diff --git a/.claude/skills/verify/skill.md b/.claude/skills/verify/skill.md index eca9c8a..7094db9 100644 --- a/.claude/skills/verify/skill.md +++ b/.claude/skills/verify/skill.md @@ -16,12 +16,18 @@ Run lint, build, and tests to verify the current state of the codebase. npm run lint ``` -**Build + Tests:** +**Build:** +```bash +npm run build +``` + +**Tests:** ```bash npm run test ``` -> `npm run test` runs `npm run build && npm run build:test && karma start test/karma.config.js` — it builds the source, builds the test bundle, and runs Karma with Mocha/Chai in Chrome and Firefox. +> `npm run test` runs Vitest in headless jsdom mode. +> `npm run build` runs Vite and produces IIFE and CommonJS bundles + TypeScript type declarations. 2. Report results in this format: @@ -35,7 +41,8 @@ npm run test ## Notes -- This is a plain JavaScript project — kit source is ES5-style; tests/tooling may use ES6. There is no TypeScript compilation step. -- Build uses Rollup and produces IIFE and CommonJS bundles. -- Tests run in real browsers (Chrome, Firefox) via Karma, not in Node/jsdom. -- `npm run test:debug` launches Chrome in non-headless mode for interactive debugging. +- TypeScript project — source is `src/Rokt-Kit.ts`, tests are `test/src/tests.spec.ts` +- Build uses Vite and produces `dist/Rokt-Kit.iife.js`, `dist/Rokt-Kit.common.js`, and `dist/Rokt-Kit.d.ts` +- Tests run in jsdom via Vitest (no browser required) +- `npm run test:watch` runs Vitest in watch mode for development +- `npm run test:coverage` generates a V8 coverage report diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index e3b384f..0000000 --- a/.eslintrc +++ /dev/null @@ -1,30 +0,0 @@ -{ - "root": true, - "env": { - "browser": true, - "node": true - }, - "globals": { - "mParticle": true, - "describe": true, - "Should": true, - "MockHttpServer": true, - "it": true, - "sinon": true, - "const": true, - "before": true, - "beforeEach": true, - "after": true, - "Leanplum": true - }, - "extends": ["plugin:prettier/recommended", "eslint:recommended"], - "plugins": ["prettier"], - "rules": { - "prettier/prettier": "error", - "no-prototype-builtins": "off", - "no-empty": "off", - "no-useless-escape": "off", - "no-unexpected-multiline": "off", - "no-unused-vars": ["error", { "argsIgnorePattern": "^_", "varsIgnorePattern": "^_" }] - } -} diff --git a/.nvmrc b/.nvmrc index 67d2ffe..a45fd52 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v20.13.1 \ No newline at end of file +24 diff --git a/.prettierrc b/.prettierrc index d84e2a6..4b9a2d9 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,5 +1,5 @@ { - "singleQuote": true, - "trailingComma": "es5", - "tabWidth": 4 -} \ No newline at end of file + "printWidth": 120, + "singleQuote": true, + "trailingComma": "all" +} diff --git a/AGENTS.md b/AGENTS.md index 75755cf..bbfd3fb 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -10,42 +10,46 @@ The Rokt web kit (`@mparticle/web-rokt-kit`) is an mParticle integration kit (fo ## Tech Stack -- **Language**: Plain JavaScript project — kit source is ES5-style; tests/tooling may use ES6. There is no TypeScript compilation step. -- **Build Tool**: Rollup (IIFE and CommonJS output) -- **Testing**: Karma + Mocha/Chai (real browser tests in Chrome and Firefox) +- **Language**: TypeScript 5.5 with `strict: true` +- **Build Tool**: Vite (library mode, IIFE + CJS output) +- **Testing**: Vitest with `jsdom` environment - **Package Manager**: npm -- **Code Quality**: ESLint +- **Code Quality**: ESLint v9 flat config + `@typescript-eslint/recommended` +- **Formatting**: Prettier (120 chars, single quotes, trailing commas) ## Project Structure ``` / src/ - Rokt-Kit.js # Single monolithic source file (~900 lines) + Rokt-Kit.ts # Single monolithic source file dist/ Rokt-Kit.iife.js # Browser bundle (IIFE) Rokt-Kit.common.js # npm bundle (CommonJS) + Rokt-Kit.d.ts # Type definitions test/ src/ - tests.js # Mocha/Chai test suite - config.js # Test mParticle configuration - karma.config.js # Karma test runner config + tests.spec.ts # Vitest test suite + vitest.setup.ts # Global test setup / mParticle mock lib/ # Test utilities end-to-end-testapp/ # E2E test app - rollup.config.js # Build configuration + vite.config.ts # Build + test configuration + tsconfig.json # TypeScript config (src only) + tsconfig.test.json # TypeScript config (src + test) + eslint.config.mjs # ESLint v9 flat config package.json ``` ## Key Commands ```bash -npm run build # Build IIFE and CommonJS bundles -npm run build:test # Build test bundle -npm run lint # ESLint check (src/ and test/src/) +npm run build # Vite build (IIFE + CJS + type defs) +npm run build:watch # Vite build in watch mode (rebuilds on change) +npm run lint # ESLint check npm run lint:fix # ESLint autofix -npm run test # Build + build tests + run Karma -npm run test:debug # Non-headless Chrome for debugging -npm run watch # Watch and rebuild on changes +npm run test # Vitest run +npm run test:watch # Vitest watch mode +npm run test:coverage # Vitest with V8 coverage ``` ## Build Artifacts — Do Not Commit @@ -54,10 +58,10 @@ The `dist/` folder, `CHANGELOG.md`, and version bumps in `package.json`/`package ## Code Conventions -- **Single source file**: All kit logic lives in `src/Rokt-Kit.js` -- **Constructor function pattern**: `var constructor = function() { ... }` with `var self = this;` -- **var declarations**: The codebase uses `var` throughout — match this style -- **No TypeScript**: No type annotations, no interfaces, no generics +- **Single source file**: All kit logic lives in `src/Rokt-Kit.ts` +- **TypeScript class pattern**: `class RoktKit { ... }` with typed public/private members +- **const/let**: Use `const` for values that don't change, `let` for reassignable variables +- **Strict TypeScript**: `strict: true` — all values must be typed, no implicit `any` - **Module registration**: Kit self-registers via `window.mParticle.addForwarder()` at load time ## Architecture @@ -69,19 +73,19 @@ The `dist/` folder, `CHANGELOG.md`, and version bumps in `package.json`/`package ## Testing Patterns -- Tests use Mocha `describe`/`it` blocks with Chai `expect` assertions -- mParticle SDK is mocked in test config -- Rokt launcher is mocked with spy functions +- Tests use Vitest `describe`/`it` blocks with `expect()` assertions +- `window.mParticle` is mocked in `test/vitest.setup.ts` +- Rokt launcher is mocked with `vi.fn()` spy functions - `beforeEach` resets kit state between tests -- Tests run in real browsers (Chrome, Firefox) via Karma +- Tests run headlessly in jsdom via Vitest ## Common Gotchas -1. **Single file**: All changes go in `src/Rokt-Kit.js` — there are no imports/modules +1. **Single file**: All changes go in `src/Rokt-Kit.ts` — there are no imports/modules 2. **Browser-only**: Code runs in browser context, `window` is always available 3. **Async launcher**: Rokt launcher loads asynchronously — events must be queued until ready -4. **var scope**: Use `var` not `let`/`const` to match existing style -5. **self reference**: Use `var self = this;` pattern for callback context +4. **Window extensions**: `window.Rokt` and `window.mParticle.Rokt` are typed via `declare global` +5. **Test isolation**: Each test resets `window.mParticle.forwarder` state in `beforeEach` ## Available Skills diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..946f580 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,73 @@ +import js from '@eslint/js'; +import typescriptEslint from '@typescript-eslint/eslint-plugin'; +import tsParser from '@typescript-eslint/parser'; +import prettier from 'eslint-plugin-prettier'; +import prettierConfig from 'eslint-config-prettier'; +import globals from 'globals'; + +const vitestGlobals = { + describe: 'readonly', + it: 'readonly', + test: 'readonly', + expect: 'readonly', + beforeEach: 'readonly', + afterEach: 'readonly', + beforeAll: 'readonly', + afterAll: 'readonly', + vi: 'readonly', + vitest: 'readonly', +}; + +const sharedRules = { + ...js.configs.recommended.rules, + ...typescriptEslint.configs.recommended.rules, + ...prettierConfig.rules, + 'prettier/prettier': 'error', + '@typescript-eslint/no-explicit-any': 'warn', + '@typescript-eslint/no-unused-vars': [ + 'error', + { + argsIgnorePattern: '^_', + varsIgnorePattern: '^_', + caughtErrorsIgnorePattern: '^_', + }, + ], + 'no-prototype-builtins': 'off', +}; + +export default [ + { ignores: ['**/node_modules/**', '**/dist/**'] }, + // Source files + { + files: ['src/**/*.ts'], + plugins: { + '@typescript-eslint': typescriptEslint, + prettier, + }, + languageOptions: { + parser: tsParser, + globals: { ...globals.browser, process: 'readonly' }, + ecmaVersion: 'latest', + sourceType: 'module', + }, + rules: sharedRules, + }, + // Test files + { + files: ['test/**/*.ts'], + plugins: { + '@typescript-eslint': typescriptEslint, + prettier, + }, + languageOptions: { + parser: tsParser, + globals: { ...globals.browser, ...vitestGlobals }, + ecmaVersion: 'latest', + sourceType: 'module', + }, + rules: { + ...sharedRules, + '@typescript-eslint/no-this-alias': 'off', + }, + }, +]; diff --git a/package-lock.json b/package-lock.json index c619878..a49e51c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,30 +12,26 @@ "@mparticle/web-sdk": "^2.56.0" }, "devDependencies": { - "@rollup/plugin-json": "^6.1.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "^9.23.0", "@semantic-release/changelog": "^6.0.3", "@semantic-release/exec": "^6.0.3", "@semantic-release/git": "^10.0.1", "@semantic-release/npm": "^13.1.2", - "chai": "^4.2.0", - "eslint": "^7.25.0", - "eslint-config-prettier": "8.3.0", - "eslint-plugin-prettier": "3.4.1", - "karma": "^5.1.0", - "karma-chai": "^0.1.0", - "karma-chrome-launcher": "^3.1.0", - "karma-firefox-launcher": "^2.1.0", - "karma-mocha": "^2.0.1", - "mocha": "^5.2.0", - "prettier": "^2.4.1", - "rollup": "^1.15.6", - "rollup-plugin-commonjs": "^10.0.0", - "rollup-plugin-node-resolve": "^5.0.3", - "rollup-plugin-replace": "^2.2.0", + "@types/node": "^20.11.5", + "@typescript-eslint/eslint-plugin": "^8.28.0", + "@typescript-eslint/parser": "^8.28.0", + "@vitest/coverage-v8": "^4.0.0", + "eslint": "^9.23.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-prettier": "^5.0.0", + "jsdom": "latest", + "prettier": "^3.0.0", "semantic-release": "^24.2.0", - "shelljs": "0.8.3", - "should": "13.2.3", - "watchify": "^3.11.0" + "typescript": "^5.5.4", + "vite": "^6.0.0", + "vite-plugin-dts": "~3.8.1", + "vitest": "^4.0.0" } }, "node_modules/@actions/core": { @@ -77,6 +73,47 @@ "dev": true, "license": "MIT" }, + "node_modules/@asamuzakjp/css-color": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-5.1.1.tgz", + "integrity": "sha512-iGWN8E45Ws0XWx3D44Q1t6vX2LqhCKcwfmwBYCDsFrYFS6m4q/Ks61L2veETaLv+ckDC6+dTETJoaAAb7VjLiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^3.1.1", + "@csstools/css-color-parser": "^4.0.2", + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0", + "lru-cache": "^11.2.7" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/dom-selector": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-7.0.4.tgz", + "integrity": "sha512-jXR6x4AcT3eIrS2fSNAwJpwirOkGcd+E7F7CP3zjdTqz9B/2huHOL8YJZBgekKwLML+u7qB/6P1LXQuMScsx0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/nwsapi": "^2.3.9", + "bidi-js": "^1.0.3", + "css-tree": "^3.2.1", + "is-potential-custom-element-name": "^1.0.1", + "lru-cache": "^11.2.7" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/nwsapi": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz", + "integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==", + "dev": true, + "license": "MIT" + }, "node_modules/@babel/code-frame": { "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", @@ -87,6 +124,16 @@ "@babel/highlight": "^7.10.4" } }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-validator-identifier": { "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", @@ -191,6 +238,22 @@ "node": ">=4" } }, + "node_modules/@babel/parser": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@babel/runtime": { "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", @@ -200,332 +263,1776 @@ "node": ">=6.9.0" } }, - "node_modules/@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", "dev": true, "license": "MIT", - "optional": true, + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, "engines": { - "node": ">=0.1.90" + "node": ">=6.9.0" } }, - "node_modules/@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "node_modules/@bcoe/v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", "dev": true, "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" - }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=18" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", - "deprecated": "Use @eslint/config-array instead", + "node_modules/@bramus/specificity": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.2.tgz", + "integrity": "sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@humanwhocodes/object-schema": "^1.2.0", - "debug": "^4.1.1", - "minimatch": "^3.0.4" + "css-tree": "^3.0.0" }, - "engines": { - "node": ">=10.10.0" + "bin": { + "specificity": "bin/cli.js" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "deprecated": "Use @eslint/object-schema instead", + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@mparticle/web-sdk": { - "version": "2.56.0", - "resolved": "https://registry.npmjs.org/@mparticle/web-sdk/-/web-sdk-2.56.0.tgz", - "integrity": "sha512-HytxaOUYEIHei5Y6OPQoQl7mmM6H2EBI1CDJ5VVB3otsvO/CQqSzyd6T1VC4hBcJ8qVJ9h7p6hIxIteVsYyXeg==", - "license": "Apache-2.0", - "dependencies": { - "@babel/runtime": "^7.23.2" + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.1.90" } }, - "node_modules/@octokit/auth-token": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-6.0.0.tgz", - "integrity": "sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w==", + "node_modules/@csstools/color-helpers": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.0.2.tgz", + "integrity": "sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==", "dev": true, - "license": "MIT", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "engines": { - "node": ">= 20" + "node": ">=20.19.0" } }, - "node_modules/@octokit/core": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-7.0.6.tgz", - "integrity": "sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q==", + "node_modules/@csstools/css-calc": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.1.1.tgz", + "integrity": "sha512-HJ26Z/vmsZQqs/o3a6bgKslXGFAungXGbinULZO3eMsOyNJHeBBZfup5FiZInOghgoM4Hwnmw+OgbJCNg1wwUQ==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "license": "MIT", - "peer": true, - "dependencies": { - "@octokit/auth-token": "^6.0.0", - "@octokit/graphql": "^9.0.3", - "@octokit/request": "^10.0.6", - "@octokit/request-error": "^7.0.2", - "@octokit/types": "^16.0.0", - "before-after-hook": "^4.0.0", - "universal-user-agent": "^7.0.0" - }, "engines": { - "node": ">= 20" + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" } }, - "node_modules/@octokit/endpoint": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-11.0.2.tgz", - "integrity": "sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ==", + "node_modules/@csstools/css-color-parser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.0.2.tgz", + "integrity": "sha512-0GEfbBLmTFf0dJlpsNU7zwxRIH0/BGEMuXLTCvFYxuL1tNhqzTbtnFICyJLTNK4a+RechKP75e7w42ClXSnJQw==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "license": "MIT", "dependencies": { - "@octokit/types": "^16.0.0", - "universal-user-agent": "^7.0.2" + "@csstools/color-helpers": "^6.0.2", + "@csstools/css-calc": "^3.1.1" }, "engines": { - "node": ">= 20" + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" } }, - "node_modules/@octokit/graphql": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-9.0.3.tgz", - "integrity": "sha512-grAEuupr/C1rALFnXTv6ZQhFuL1D8G5y8CN04RgrO4FIPMrtm+mcZzFG7dcBm+nq+1ppNixu+Jd78aeJOYxlGA==", + "node_modules/@csstools/css-parser-algorithms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz", + "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "license": "MIT", - "dependencies": { - "@octokit/request": "^10.0.6", - "@octokit/types": "^16.0.0", - "universal-user-agent": "^7.0.0" - }, "engines": { - "node": ">= 20" + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^4.0.0" } }, - "node_modules/@octokit/openapi-types": { - "version": "27.0.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-27.0.0.tgz", - "integrity": "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA==", + "node_modules/@csstools/css-syntax-patches-for-csstree": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.2.tgz", + "integrity": "sha512-5GkLzz4prTIpoyeUiIu3iV6CSG3Plo7xRVOFPKI7FVEJ3mZ0A8SwK0XU3Gl7xAkiQ+mDyam+NNp875/C5y+jSA==", "dev": true, - "license": "MIT" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peerDependencies": { + "css-tree": "^3.2.1" + }, + "peerDependenciesMeta": { + "css-tree": { + "optional": true + } + } }, - "node_modules/@octokit/plugin-paginate-rest": { - "version": "13.2.1", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-13.2.1.tgz", - "integrity": "sha512-Tj4PkZyIL6eBMYcG/76QGsedF0+dWVeLhYprTmuFVVxzDW7PQh23tM0TP0z+1MvSkxB29YFZwnUX+cXfTiSdyw==", + "node_modules/@csstools/css-tokenizer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz", + "integrity": "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "license": "MIT", - "dependencies": { - "@octokit/types": "^15.0.1" - }, "engines": { - "node": ">= 20" - }, - "peerDependencies": { - "@octokit/core": ">=6" + "node": ">=20.19.0" } }, - "node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/openapi-types": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-26.0.0.tgz", - "integrity": "sha512-7AtcfKtpo77j7Ts73b4OWhOZHTKo/gGY8bB3bNBQz4H+GRSWqx2yvj8TXRsbdTE0eRmYmXOEY66jM7mJ7LzfsA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/types": { - "version": "15.0.2", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-15.0.2.tgz", - "integrity": "sha512-rR+5VRjhYSer7sC51krfCctQhVTmjyUMAaShfPB8mscVa8tSoLyon3coxQmXu0ahJoLVWl8dSGD/3OGZlFV44Q==", + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@octokit/openapi-types": "^26.0.0" + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@octokit/plugin-retry": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-8.0.3.tgz", - "integrity": "sha512-vKGx1i3MC0za53IzYBSBXcrhmd+daQDzuZfYDd52X5S0M2otf3kVZTVP8bLA3EkU0lTvd1WEC2OlNNa4G+dohA==", + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", - "dependencies": { - "@octokit/request-error": "^7.0.2", - "@octokit/types": "^16.0.0", - "bottleneck": "^2.15.3" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">= 20" - }, - "peerDependencies": { - "@octokit/core": ">=7" + "node": ">=18" } }, - "node_modules/@octokit/plugin-throttling": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-11.0.3.tgz", - "integrity": "sha512-34eE0RkFCKycLl2D2kq7W+LovheM/ex3AwZCYN8udpi6bxsyjZidb2McXs69hZhLmJlDqTSP8cH+jSRpiaijBg==", + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@octokit/types": "^16.0.0", - "bottleneck": "^2.15.3" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">= 20" - }, - "peerDependencies": { - "@octokit/core": "^7.0.0" + "node": ">=18" } }, - "node_modules/@octokit/request": { - "version": "10.0.7", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-10.0.7.tgz", - "integrity": "sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA==", + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.5" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", + "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.14.0", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.5", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", + "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@exodus/bytes": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.15.0.tgz", + "integrity": "sha512-UY0nlA+feH81UGSHv92sLEPLCeZFjXOuHhrIo0HQydScuQc8s0A7kL/UdgwgDq8g8ilksmuoF35YVTNphV2aBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@noble/hashes": "^1.8.0 || ^2.0.0" + }, + "peerDependenciesMeta": { + "@noble/hashes": { + "optional": true + } + } + }, + "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": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@microsoft/api-extractor": { + "version": "7.43.0", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.43.0.tgz", + "integrity": "sha512-GFhTcJpB+MI6FhvXEI9b2K0snulNLWHqC/BbcJtyNYcKUiw7l3Lgis5ApsYncJ0leALX7/of4XfmXk+maT111w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@microsoft/api-extractor-model": "7.28.13", + "@microsoft/tsdoc": "0.14.2", + "@microsoft/tsdoc-config": "~0.16.1", + "@rushstack/node-core-library": "4.0.2", + "@rushstack/rig-package": "0.5.2", + "@rushstack/terminal": "0.10.0", + "@rushstack/ts-command-line": "4.19.1", + "lodash": "~4.17.15", + "minimatch": "~3.0.3", + "resolve": "~1.22.1", + "semver": "~7.5.4", + "source-map": "~0.6.1", + "typescript": "5.4.2" + }, + "bin": { + "api-extractor": "bin/api-extractor" + } + }, + "node_modules/@microsoft/api-extractor-model": { + "version": "7.28.13", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.28.13.tgz", + "integrity": "sha512-39v/JyldX4MS9uzHcdfmjjfS6cYGAoXV+io8B5a338pkHiSt+gy2eXQ0Q7cGFJ7quSa1VqqlMdlPrB6sLR/cAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@microsoft/tsdoc": "0.14.2", + "@microsoft/tsdoc-config": "~0.16.1", + "@rushstack/node-core-library": "4.0.2" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/minimatch": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", + "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/typescript": { + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", + "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/@microsoft/tsdoc": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz", + "integrity": "sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==", + "dev": true, + "license": "MIT" + }, + "node_modules/@microsoft/tsdoc-config": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.16.2.tgz", + "integrity": "sha512-OGiIzzoBLgWWR0UdRJX98oYO+XKGf7tiK4Zk6tQ/E4IJqGCe7dvkTvgDZV5cFJUzLGDOjeAXrnZoA6QkVySuxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@microsoft/tsdoc": "0.14.2", + "ajv": "~6.12.6", + "jju": "~1.4.0", + "resolve": "~1.19.0" + } + }, + "node_modules/@microsoft/tsdoc-config/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@microsoft/tsdoc-config/node_modules/resolve": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@mparticle/web-sdk": { + "version": "2.56.0", + "resolved": "https://registry.npmjs.org/@mparticle/web-sdk/-/web-sdk-2.56.0.tgz", + "integrity": "sha512-HytxaOUYEIHei5Y6OPQoQl7mmM6H2EBI1CDJ5VVB3otsvO/CQqSzyd6T1VC4hBcJ8qVJ9h7p6hIxIteVsYyXeg==", + "license": "Apache-2.0", + "dependencies": { + "@babel/runtime": "^7.23.2" + } + }, + "node_modules/@octokit/auth-token": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-6.0.0.tgz", + "integrity": "sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/core": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-7.0.6.tgz", + "integrity": "sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/auth-token": "^6.0.0", + "@octokit/graphql": "^9.0.3", + "@octokit/request": "^10.0.6", + "@octokit/request-error": "^7.0.2", + "@octokit/types": "^16.0.0", + "before-after-hook": "^4.0.0", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/endpoint": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-11.0.2.tgz", + "integrity": "sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^16.0.0", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/graphql": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-9.0.3.tgz", + "integrity": "sha512-grAEuupr/C1rALFnXTv6ZQhFuL1D8G5y8CN04RgrO4FIPMrtm+mcZzFG7dcBm+nq+1ppNixu+Jd78aeJOYxlGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/request": "^10.0.6", + "@octokit/types": "^16.0.0", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "27.0.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-27.0.0.tgz", + "integrity": "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@octokit/plugin-paginate-rest": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-13.2.1.tgz", + "integrity": "sha512-Tj4PkZyIL6eBMYcG/76QGsedF0+dWVeLhYprTmuFVVxzDW7PQh23tM0TP0z+1MvSkxB29YFZwnUX+cXfTiSdyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^15.0.1" + }, + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "@octokit/core": ">=6" + } + }, + "node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/openapi-types": { + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-26.0.0.tgz", + "integrity": "sha512-7AtcfKtpo77j7Ts73b4OWhOZHTKo/gGY8bB3bNBQz4H+GRSWqx2yvj8TXRsbdTE0eRmYmXOEY66jM7mJ7LzfsA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/types": { + "version": "15.0.2", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-15.0.2.tgz", + "integrity": "sha512-rR+5VRjhYSer7sC51krfCctQhVTmjyUMAaShfPB8mscVa8tSoLyon3coxQmXu0ahJoLVWl8dSGD/3OGZlFV44Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^26.0.0" + } + }, + "node_modules/@octokit/plugin-retry": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-8.0.3.tgz", + "integrity": "sha512-vKGx1i3MC0za53IzYBSBXcrhmd+daQDzuZfYDd52X5S0M2otf3kVZTVP8bLA3EkU0lTvd1WEC2OlNNa4G+dohA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/request-error": "^7.0.2", + "@octokit/types": "^16.0.0", + "bottleneck": "^2.15.3" + }, + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "@octokit/core": ">=7" + } + }, + "node_modules/@octokit/plugin-throttling": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-11.0.3.tgz", + "integrity": "sha512-34eE0RkFCKycLl2D2kq7W+LovheM/ex3AwZCYN8udpi6bxsyjZidb2McXs69hZhLmJlDqTSP8cH+jSRpiaijBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^16.0.0", + "bottleneck": "^2.15.3" + }, + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "@octokit/core": "^7.0.0" + } + }, + "node_modules/@octokit/request": { + "version": "10.0.7", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-10.0.7.tgz", + "integrity": "sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/endpoint": "^11.0.2", + "@octokit/request-error": "^7.0.2", + "@octokit/types": "^16.0.0", + "fast-content-type-parse": "^3.0.0", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/request-error": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-7.1.0.tgz", + "integrity": "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^16.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/types": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-16.0.0.tgz", + "integrity": "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^27.0.0" + } + }, + "node_modules/@pkgr/core": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" + } + }, + "node_modules/@pnpm/config.env-replace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", + "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", + "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "4.2.10" + }, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true, + "license": "ISC" + }, + "node_modules/@pnpm/npm-conf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-3.0.2.tgz", + "integrity": "sha512-h104Kh26rR8tm+a3Qkc5S4VLYint3FE48as7+/5oCEcKR2idC/pF1G6AhIXKI+eHPJa/3J9i5z0Al47IeGHPkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pnpm/config.env-replace": "^1.1.0", + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", + "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.1.tgz", + "integrity": "sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.1.tgz", + "integrity": "sha512-YjG/EwIDvvYI1YvYbHvDz/BYHtkY4ygUIXHnTdLhG+hKIQFBiosfWiACWortsKPKU/+dUwQQCKQM3qrDe8c9BA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.1.tgz", + "integrity": "sha512-mjCpF7GmkRtSJwon+Rq1N8+pI+8l7w5g9Z3vWj4T7abguC4Czwi3Yu/pFaLvA3TTeMVjnu3ctigusqWUfjZzvw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.1.tgz", + "integrity": "sha512-haZ7hJ1JT4e9hqkoT9R/19XW2QKqjfJVv+i5AGg57S+nLk9lQnJ1F/eZloRO3o9Scy9CM3wQ9l+dkXtcBgN5Ew==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.1.tgz", + "integrity": "sha512-czw90wpQq3ZsAVBlinZjAYTKduOjTywlG7fEeWKUA7oCmpA8xdTkxZZlwNJKWqILlq0wehoZcJYfBvOyhPTQ6w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.1.tgz", + "integrity": "sha512-KVB2rqsxTHuBtfOeySEyzEOB7ltlB/ux38iu2rBQzkjbwRVlkhAGIEDiiYnO2kFOkJp+Z7pUXKyrRRFuFUKt+g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.1.tgz", + "integrity": "sha512-L+34Qqil+v5uC0zEubW7uByo78WOCIrBvci69E7sFASRl0X7b/MB6Cqd1lky/CtcSVTydWa2WZwFuWexjS5o6g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.1.tgz", + "integrity": "sha512-n83O8rt4v34hgFzlkb1ycniJh7IR5RCIqt6mz1VRJD6pmhRi0CXdmfnLu9dIUS6buzh60IvACM842Ffb3xd6Gg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.1.tgz", + "integrity": "sha512-Nql7sTeAzhTAja3QXeAI48+/+GjBJ+QmAH13snn0AJSNL50JsDqotyudHyMbO2RbJkskbMbFJfIJKWA6R1LCJQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.1.tgz", + "integrity": "sha512-+pUymDhd0ys9GcKZPPWlFiZ67sTWV5UU6zOJat02M1+PiuSGDziyRuI/pPue3hoUwm2uGfxdL+trT6Z9rxnlMA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.1.tgz", + "integrity": "sha512-VSvgvQeIcsEvY4bKDHEDWcpW4Yw7BtlKG1GUT4FzBUlEKQK0rWHYBqQt6Fm2taXS+1bXvJT6kICu5ZwqKCnvlQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.1.tgz", + "integrity": "sha512-4LqhUomJqwe641gsPp6xLfhqWMbQV04KtPp7/dIp0nzPxAkNY1AbwL5W0MQpcalLYk07vaW9Kp1PBhdpZYYcEw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.1.tgz", + "integrity": "sha512-tLQQ9aPvkBxOc/EUT6j3pyeMD6Hb8QF2BTBnCQWP/uu1lhc9AIrIjKnLYMEroIz/JvtGYgI9dF3AxHZNaEH0rw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.1.tgz", + "integrity": "sha512-RMxFhJwc9fSXP6PqmAz4cbv3kAyvD1etJFjTx4ONqFP9DkTkXsAMU4v3Vyc5BgzC+anz7nS/9tp4obsKfqkDHg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.1.tgz", + "integrity": "sha512-QKgFl+Yc1eEk6MmOBfRHYF6lTxiiiV3/z/BRrbSiW2I7AFTXoBFvdMEyglohPj//2mZS4hDOqeB0H1ACh3sBbg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.1.tgz", + "integrity": "sha512-RAjXjP/8c6ZtzatZcA1RaQr6O1TRhzC+adn8YZDnChliZHviqIjmvFwHcxi4JKPSDAt6Uhf/7vqcBzQJy0PDJg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.1.tgz", + "integrity": "sha512-wcuocpaOlaL1COBYiA89O6yfjlp3RwKDeTIA0hM7OpmhR1Bjo9j31G1uQVpDlTvwxGn2nQs65fBFL5UFd76FcQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.1.tgz", + "integrity": "sha512-77PpsFQUCOiZR9+LQEFg9GClyfkNXj1MP6wRnzYs0EeWbPcHs02AXu4xuUbM1zhwn3wqaizle3AEYg5aeoohhg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.1.tgz", + "integrity": "sha512-5cIATbk5vynAjqqmyBjlciMJl1+R/CwX9oLk/EyiFXDWd95KpHdrOJT//rnUl4cUcskrd0jCCw3wpZnhIHdD9w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.1.tgz", + "integrity": "sha512-cl0w09WsCi17mcmWqqglez9Gk8isgeWvoUZ3WiJFYSR3zjBQc2J5/ihSjpl+VLjPqjQ/1hJRcqBfLjssREQILw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.1.tgz", + "integrity": "sha512-4Cv23ZrONRbNtbZa37mLSueXUCtN7MXccChtKpUnQNgF010rjrjfHx3QxkS2PI7LqGT5xXyYs1a7LbzAwT0iCA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.1.tgz", + "integrity": "sha512-i1okWYkA4FJICtr7KpYzFpRTHgy5jdDbZiWfvny21iIKky5YExiDXP+zbXzm3dUcFpkEeYNHgQ5fuG236JPq0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.1.tgz", + "integrity": "sha512-u09m3CuwLzShA0EYKMNiFgcjjzwqtUMLmuCJLeZWjjOYA3IT2Di09KaxGBTP9xVztWyIWjVdsB2E9goMjZvTQg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.1.tgz", + "integrity": "sha512-k+600V9Zl1CM7eZxJgMyTUzmrmhB/0XZnF4pRypKAlAgxmedUA+1v9R+XOFv56W4SlHEzfeMtzujLJD22Uz5zg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.1.tgz", + "integrity": "sha512-lWMnixq/QzxyhTV6NjQJ4SFo1J6PvOX8vUx5Wb4bBPsEb+8xZ89Bz6kOXpfXj9ak9AHTQVQzlgzBEc1SyM27xQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rushstack/node-core-library": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-4.0.2.tgz", + "integrity": "sha512-hyES82QVpkfQMeBMteQUnrhASL/KHPhd7iJ8euduwNJG4mu2GSOKybf0rOEjOm1Wz7CwJEUm9y0yD7jg2C1bfg==", "dev": true, "license": "MIT", "dependencies": { - "@octokit/endpoint": "^11.0.2", - "@octokit/request-error": "^7.0.2", - "@octokit/types": "^16.0.0", - "fast-content-type-parse": "^3.0.0", - "universal-user-agent": "^7.0.2" + "fs-extra": "~7.0.1", + "import-lazy": "~4.0.0", + "jju": "~1.4.0", + "resolve": "~1.22.1", + "semver": "~7.5.4", + "z-schema": "~5.0.2" }, - "engines": { - "node": ">= 20" + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@octokit/request-error": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-7.1.0.tgz", - "integrity": "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw==", + "node_modules/@rushstack/node-core-library/node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", "dev": true, "license": "MIT", "dependencies": { - "@octokit/types": "^16.0.0" + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" }, "engines": { - "node": ">= 20" + "node": ">=6 <7 || >=8" } }, - "node_modules/@octokit/types": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-16.0.0.tgz", - "integrity": "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg==", + "node_modules/@rushstack/node-core-library/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", "dev": true, "license": "MIT", - "dependencies": { - "@octokit/openapi-types": "^27.0.0" + "optionalDependencies": { + "graceful-fs": "^4.1.6" } }, - "node_modules/@pnpm/config.env-replace": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", - "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", + "node_modules/@rushstack/node-core-library/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, - "license": "MIT", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, "engines": { - "node": ">=12.22.0" + "node": ">=10" } }, - "node_modules/@pnpm/network.ca-file": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", - "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", + "node_modules/@rushstack/node-core-library/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "graceful-fs": "4.2.10" + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">=12.22.0" + "node": ">=10" } }, - "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "node_modules/@rushstack/node-core-library/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true, - "license": "ISC" + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } }, - "node_modules/@pnpm/npm-conf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-3.0.2.tgz", - "integrity": "sha512-h104Kh26rR8tm+a3Qkc5S4VLYint3FE48as7+/5oCEcKR2idC/pF1G6AhIXKI+eHPJa/3J9i5z0Al47IeGHPkA==", + "node_modules/@rushstack/rig-package": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.5.2.tgz", + "integrity": "sha512-mUDecIJeH3yYGZs2a48k+pbhM6JYwWlgjs2Ca5f2n1G2/kgdgP9D/07oglEGf6mRyXEnazhEENeYTSNDRCwdqA==", "dev": true, "license": "MIT", "dependencies": { - "@pnpm/config.env-replace": "^1.1.0", - "@pnpm/network.ca-file": "^1.0.1", - "config-chain": "^1.1.11" - }, - "engines": { - "node": ">=12" + "resolve": "~1.22.1", + "strip-json-comments": "~3.1.1" } }, - "node_modules/@rollup/plugin-json": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.1.0.tgz", - "integrity": "sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==", + "node_modules/@rushstack/terminal": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.10.0.tgz", + "integrity": "sha512-UbELbXnUdc7EKwfH2sb8ChqNgapUOdqcCIdQP4NGxBpTZV2sQyeekuK3zmfQSa/MN+/7b4kBogl2wq0vpkpYGw==", "dev": true, "license": "MIT", "dependencies": { - "@rollup/pluginutils": "^5.1.0" - }, - "engines": { - "node": ">=14.0.0" + "@rushstack/node-core-library": "4.0.2", + "supports-color": "~8.1.1" }, "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + "@types/node": "*" }, "peerDependenciesMeta": { - "rollup": { + "@types/node": { "optional": true } } }, - "node_modules/@rollup/pluginutils": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", - "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", + "node_modules/@rushstack/terminal/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^4.0.2" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + "node": ">=10" }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/@rushstack/ts-command-line": { + "version": "4.19.1", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.19.1.tgz", + "integrity": "sha512-J7H768dgcpG60d7skZ5uSSwyCZs/S2HrWP1Ds8d1qYAyaaeJmpmmLr9BVw97RjFzmQPOYnoXcKA4GkqDCkduQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rushstack/terminal": "0.10.0", + "@types/argparse": "1.0.38", + "argparse": "~1.0.9", + "string-argv": "~0.3.1" + } + }, + "node_modules/@rushstack/ts-command-line/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" } }, "node_modules/@sec-ant/readable-stream": { @@ -1026,999 +2533,898 @@ "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "25.2.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.0.tgz", - "integrity": "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~7.16.0" - } - }, - "node_modules/@types/normalize-package-data": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", - "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/resolve": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz", - "integrity": "sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true, - "license": "MIT", - "peer": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/acorn-node": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", - "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/argparse": { + "version": "1.0.38", + "resolved": "https://registry.npmjs.org/@types/argparse/-/argparse-1.0.38.tgz", + "integrity": "sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "acorn": "^7.0.0", - "acorn-walk": "^7.0.0", - "xtend": "^4.0.2" - } + "license": "MIT" }, - "node_modules/acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", "dev": true, "license": "MIT", - "engines": { - "node": ">=0.4.0" + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" } }, - "node_modules/after": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", - "integrity": "sha512-QbJ0NTQ/I9DI3uSJA4cbexiwQeRAfjPScqIbSjUDd9TOrcg6pTkdgziesOqxBMBzit8vFCTwrP27t13vFOORRA==", + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", "dev": true, "license": "MIT" }, - "node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14" - } + "license": "MIT" }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.19.37", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.37.tgz", + "integrity": "sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw==", "dev": true, "license": "MIT", "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" + "undici-types": "~6.21.0" } }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.58.0.tgz", + "integrity": "sha512-RLkVSiNuUP1C2ROIWfqX+YcUfLaSnxGE/8M+Y57lopVwg9VTYYfhuz15Yf1IzCKgZj6/rIbYTmJCUSqr76r0Wg==", "dev": true, "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.58.0", + "@typescript-eslint/type-utils": "8.58.0", + "@typescript-eslint/utils": "8.58.0", + "@typescript-eslint/visitor-keys": "8.58.0", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.58.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", "dev": true, "license": "MIT", "engines": { - "node": ">=6" + "node": ">= 4" } }, - "node_modules/ansi-escapes": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.2.0.tgz", - "integrity": "sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw==", + "node_modules/@typescript-eslint/parser": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.58.0.tgz", + "integrity": "sha512-rLoGZIf9afaRBYsPUMtvkDWykwXwUPL60HebR4JgTI8mxfFe2cQTu3AGitANp4b9B2QlVru6WzjgB2IzJKiCSA==", "dev": true, "license": "MIT", "dependencies": { - "environment": "^1.0.0" + "@typescript-eslint/scope-manager": "8.58.0", + "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/typescript-estree": "8.58.0", + "@typescript-eslint/visitor-keys": "8.58.0", + "debug": "^4.4.3" }, "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@typescript-eslint/project-service": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.58.0.tgz", + "integrity": "sha512-8Q/wBPWLQP1j16NxoPNIKpDZFMaxl7yWIoqXWYeWO+Bbd2mjgvoF0dxP2jKZg5+x49rgKdf7Ck473M8PC3V9lg==", "dev": true, "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "@typescript-eslint/tsconfig-utils": "^8.58.0", + "@typescript-eslint/types": "^8.58.0", + "debug": "^4.4.3" }, "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true, - "license": "MIT" - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.58.0.tgz", + "integrity": "sha512-W1Lur1oF50FxSnNdGp3Vs6P+yBRSmZiw4IIjEeYxd8UQJwhUF0gDgDD/W/Tgmh73mxgEU3qX0Bzdl/NGuSPEpQ==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" + "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/visitor-keys": "8.58.0" }, "engines": { - "node": ">= 8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/anymatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.58.0.tgz", + "integrity": "sha512-doNSZEVJsWEu4htiVC+PR6NpM+pa+a4ClH9INRWOWCUzMst/VA9c4gXq92F8GUD1rwhNvRLkgjfYtFXegXQF7A==", "dev": true, "license": "MIT", "engines": { - "node": ">=8.6" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "node_modules/@typescript-eslint/type-utils": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.58.0.tgz", + "integrity": "sha512-aGsCQImkDIqMyx1u4PrVlbi/krmDsQUs4zAcCV6M7yPcPev+RqVlndsJy9kJ8TLihW9TZ0kbDAzctpLn5o+lOg==", "dev": true, "license": "MIT", "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/argv-formatter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/argv-formatter/-/argv-formatter-1.0.0.tgz", - "integrity": "sha512-F2+Hkm9xFaRg+GkaNnbwXNDV5O6pnCFEmqyhvfC/Ic5LbgOWjJh3L+mN/s91rxVL3znE7DYVpW0GJFT+4YBgWw==", - "dev": true, - "license": "MIT" - }, - "node_modules/arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", - "dev": true, - "license": "MIT", + "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/typescript-estree": "8.58.0", + "@typescript-eslint/utils": "8.58.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, "engines": { - "node": ">=0.10.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "node_modules/@typescript-eslint/types": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.58.0.tgz", + "integrity": "sha512-O9CjxypDT89fbHxRfETNoAnHj/i6IpRK0CvbVN3qibxlLdo5p5hcLmUuCCrHMpxiWSwKyI8mCP7qRNYuOJ0Uww==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.58.0.tgz", + "integrity": "sha512-7vv5UWbHqew/dvs+D3e1RvLv1v2eeZ9txRHPnEEBUgSNLx5ghdzjHa0sgLWYVKssH+lYmV0JaWdoubo0ncGYLA==", "dev": true, "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.58.0", + "@typescript-eslint/tsconfig-utils": "8.58.0", + "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/visitor-keys": "8.58.0", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, "engines": { - "node": ">=0.10.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/array-ify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", - "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", - "dev": true, - "license": "MIT" - }, - "node_modules/array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": "18 || 20 || >=22" } }, - "node_modules/arraybuffer.slice": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", - "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==", - "dev": true, - "license": "MIT" - }, - "node_modules/asn1.js": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", - "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", "dev": true, "license": "MIT", "dependencies": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" } }, - "node_modules/asn1.js/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", - "dev": true, - "license": "MIT" - }, - "node_modules/assert": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.1.tgz", - "integrity": "sha512-zzw1uCAgLbsKwBfFc8CX78DDg+xZeBksSO3vwVIDDN5i94eOrPsSSyiVhmsSABFDM/OcpE2aagCat9dnWQLG1A==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", "dev": true, - "license": "MIT", + "license": "BlueOak-1.0.0", "dependencies": { - "object.assign": "^4.1.4", - "util": "^0.10.4" + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "node_modules/@typescript-eslint/utils": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.58.0.tgz", + "integrity": "sha512-RfeSqcFeHMHlAWzt4TBjWOAtoW9lnsAGiP3GbaX9uVgTYYrMbVnGONEfUCiSss+xMHFl+eHZiipmA8WkQ7FuNA==", "dev": true, "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.58.0", + "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/typescript-estree": "8.58.0" + }, "engines": { - "node": "*" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.58.0.tgz", + "integrity": "sha512-XJ9UD9+bbDo4a4epraTwG3TsNPeiB9aShrUneAVXy8q4LuwowN+qu89/6ByLMINqvIMeI9H9hOHQtg/ijrYXzQ==", "dev": true, "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.58.0", + "eslint-visitor-keys": "^5.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "engines": { - "node": ">=8" + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/async-each": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.6.tgz", - "integrity": "sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "license": "MIT" - }, - "node_modules/atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "node_modules/@vitest/coverage-v8": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.2.tgz", + "integrity": "sha512-sPK//PHO+kAkScb8XITeB1bf7fsk85Km7+rt4eeuRR3VS1/crD47cmV5wicisJmjNdfeokTZwjMk4Mj2d58Mgg==", "dev": true, - "license": "(MIT OR Apache-2.0)", - "bin": { - "atob": "bin/atob.js" + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^1.0.2", + "@vitest/utils": "4.1.2", + "ast-v8-to-istanbul": "^1.0.0", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.2.0", + "magicast": "^0.5.2", + "obug": "^2.1.1", + "std-env": "^4.0.0-rc.1", + "tinyrainbow": "^3.1.0" }, - "engines": { - "node": ">= 4.5.0" + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/browser": "4.1.2", + "vitest": "4.1.2" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } } }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "node_modules/@vitest/expect": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.2.tgz", + "integrity": "sha512-gbu+7B0YgUJ2nkdsRJrFFW6X7NTP44WlhiclHniUhxADQJH5Szt9mZ9hWnJPJ8YwOK5zUOSSlSvyzRf0u1DSBQ==", "dev": true, "license": "MIT", "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.2", + "@vitest/utils": "4.1.2", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://opencollective.com/vitest" } }, - "node_modules/backo2": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", - "integrity": "sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA==", - "dev": true, - "license": "MIT" - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "node_modules/@vitest/mocker": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.2.tgz", + "integrity": "sha512-Ize4iQtEALHDttPRCmN+FKqOl2vxTiNUhzobQFFt/BM1lRUTG7zRCLOykG/6Vo4E4hnUdfVLo5/eqKPukcWW7Q==", "dev": true, "license": "MIT", "dependencies": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" + "@vitest/spy": "4.1.2", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } } }, - "node_modules/base/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "node_modules/@vitest/mocker/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", "dev": true, "license": "MIT", "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" + "@types/estree": "^1.0.0" } }, - "node_modules/base/node_modules/is-descriptor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", - "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "node_modules/@vitest/mocker/node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", "dev": true, "license": "MIT", "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" + "@jridgewell/sourcemap-codec": "^1.5.5" } }, - "node_modules/base64-arraybuffer": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz", - "integrity": "sha512-a1eIFi4R9ySrbiMuyTGx5e92uRH5tQY6kArNcFaKBUleIoLjdjBg7Zxm3Mqm3Kmkf27HLR/1fnxX9q8GQ7Iavg==", + "node_modules/@vitest/pretty-format": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.2.tgz", + "integrity": "sha512-dwQga8aejqeuB+TvXCMzSQemvV9hNEtDDpgUKDzOmNQayl2OG241PSWeJwKRH3CiC+sESrmoFd49rfnq7T4RnA==", "dev": true, - "engines": { - "node": ">= 0.6.0" + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "node_modules/@vitest/runner": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.2.tgz", + "integrity": "sha512-Gr+FQan34CdiYAwpGJmQG8PgkyFVmARK8/xSijia3eTFgVfpcpztWLuP6FttGNfPLJhaZVP/euvujeNYar36OQ==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.1.2", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } }, - "node_modules/base64id": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", - "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "node_modules/@vitest/snapshot": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.2.tgz", + "integrity": "sha512-g7yfUmxYS4mNxk31qbOYsSt2F4m1E02LFqO53Xpzg3zKMhLAPZAjjfyl9e6z7HrW6LvUdTwAQR3HHfLjpko16A==", "dev": true, "license": "MIT", - "engines": { - "node": "^4.5.0 || >= 5.9" + "dependencies": { + "@vitest/pretty-format": "4.1.2", + "@vitest/utils": "4.1.2", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/before-after-hook": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-4.0.0.tgz", - "integrity": "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==", + "node_modules/@vitest/snapshot/node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", "dev": true, - "license": "Apache-2.0" + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "node_modules/@vitest/spy": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.2.tgz", + "integrity": "sha512-DU4fBnbVCJGNBwVA6xSToNXrkZNSiw59H8tcuUspVMsBDBST4nfvsPsEHDHGtWRRnqBERBQu7TrTKskmjqTXKA==", "dev": true, "license": "MIT", - "engines": { - "node": ">=8" - }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/vitest" } }, - "node_modules/bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "node_modules/@vitest/utils": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.2.tgz", + "integrity": "sha512-xw2/TiX82lQHA06cgbqRKFb5lCAy3axQ4H4SoUFhUsg+wztiet+co86IAMDtF6Vm1hc7J6j09oh/rgDn+JdKIQ==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { - "file-uri-to-path": "1.0.0" + "@vitest/pretty-format": "4.1.2", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/blob": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", - "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==", + "node_modules/@vitest/utils/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/bn.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz", - "integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==", + "node_modules/@volar/language-core": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-1.11.1.tgz", + "integrity": "sha512-dOcNn3i9GgZAcJt43wuaEykSluAuOkQgzni1cuxLxTV0nJKanQztp7FxyswdRILaKH+P2XZMPRp2S4MV/pElCw==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@volar/source-map": "1.11.1" + } }, - "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==", + "node_modules/@volar/source-map": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-1.11.1.tgz", + "integrity": "sha512-hJnOnwZ4+WT5iupLRnuzbULZ42L7BWWPMmruzwtLhJfpDVoZLjNBxHDi2sY2bgZXCKlpU5XcsMFoYrsQmPhfZg==", "dev": true, "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" + "muggle-string": "^0.3.1" } }, - "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==", + "node_modules/@volar/typescript": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-1.11.1.tgz", + "integrity": "sha512-iU+t2mas/4lYierSnoFOeRFQUhAEMgsFuQxoxvwn5EdQopw43j+J27a4lt9LMInx1gLJBC6qL14WYGlgymaSMQ==", "dev": true, "license": "MIT", "dependencies": { - "ms": "2.0.0" + "@volar/language-core": "1.11.1", + "path-browserify": "^1.0.1" } }, - "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==", + "node_modules/@volar/typescript/node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", "dev": true, "license": "MIT" }, - "node_modules/bottleneck": { - "version": "2.19.5", - "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", - "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==", + "node_modules/@vue/compiler-core": { + "version": "3.5.31", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.31.tgz", + "integrity": "sha512-k/ueL14aNIEy5Onf0OVzR8kiqF/WThgLdFhxwa4e/KF/0qe38IwIdofoSWBTvvxQOesaz6riAFAUaYjoF9fLLQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.2", + "@vue/shared": "3.5.31", + "entities": "^7.0.1", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } }, - "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/@vue/compiler-dom": { + "version": "3.5.31", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.31.tgz", + "integrity": "sha512-BMY/ozS/xxjYqRFL+tKdRpATJYDTTgWSo0+AJvJNg4ig+Hgb0dOsHPXvloHQ5hmlivUqw1Yt2pPIqp4e0v1GUw==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "@vue/compiler-core": "3.5.31", + "@vue/shared": "3.5.31" } }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "node_modules/@vue/language-core": { + "version": "1.8.27", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-1.8.27.tgz", + "integrity": "sha512-L8Kc27VdQserNaCUNiSFdDl9LWT24ly8Hpwf1ECy3aFb9m6bDhBGQYOujDm21N7EW3moKIOKEanQwe1q5BK+mA==", "dev": true, "license": "MIT", "dependencies": { - "fill-range": "^7.1.1" + "@volar/language-core": "~1.11.1", + "@volar/source-map": "~1.11.1", + "@vue/compiler-dom": "^3.3.0", + "@vue/shared": "^3.3.0", + "computeds": "^0.0.1", + "minimatch": "^9.0.3", + "muggle-string": "^0.3.1", + "path-browserify": "^1.0.1", + "vue-template-compiler": "^2.7.14" }, - "engines": { - "node": ">=8" + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", - "dev": true, - "license": "MIT" - }, - "node_modules/browser-pack": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-6.1.0.tgz", - "integrity": "sha512-erYug8XoqzU3IfcU8fUgyHqyOXqIE4tUTTQ+7mqUjQlvnXkOO6OlT9c/ZoJVHYoAaqGxr09CN53G7XIsO4KtWA==", + "node_modules/@vue/language-core/node_modules/brace-expansion": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", + "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", "dev": true, "license": "MIT", "dependencies": { - "combine-source-map": "~0.8.0", - "defined": "^1.0.0", - "JSONStream": "^1.0.3", - "safe-buffer": "^5.1.1", - "through2": "^2.0.0", - "umd": "^3.0.0" - }, - "bin": { - "browser-pack": "bin/cmd.js" + "balanced-match": "^1.0.0" } }, - "node_modules/browser-resolve": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-2.0.0.tgz", - "integrity": "sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ==", + "node_modules/@vue/language-core/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "resolve": "^1.17.0" + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "node_modules/@vue/language-core/node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", "dev": true, - "license": "ISC" + "license": "MIT" }, - "node_modules/browserify": { - "version": "16.5.2", - "resolved": "https://registry.npmjs.org/browserify/-/browserify-16.5.2.tgz", - "integrity": "sha512-TkOR1cQGdmXU9zW4YukWzWVSJwrxmNdADFbqbE3HFgQWe5wqZmOawqZ7J/8MPCwk/W8yY7Y0h+7mOtcZxLP23g==", - "dev": true, - "license": "MIT", - "dependencies": { - "assert": "^1.4.0", - "browser-pack": "^6.0.1", - "browser-resolve": "^2.0.0", - "browserify-zlib": "~0.2.0", - "buffer": "~5.2.1", - "cached-path-relative": "^1.0.0", - "concat-stream": "^1.6.0", - "console-browserify": "^1.1.0", - "constants-browserify": "~1.0.0", - "crypto-browserify": "^3.0.0", - "defined": "^1.0.0", - "deps-sort": "^2.0.0", - "domain-browser": "^1.2.0", - "duplexer2": "~0.1.2", - "events": "^2.0.0", - "glob": "^7.1.0", - "has": "^1.0.0", - "htmlescape": "^1.1.0", - "https-browserify": "^1.0.0", - "inherits": "~2.0.1", - "insert-module-globals": "^7.0.0", - "JSONStream": "^1.0.3", - "labeled-stream-splicer": "^2.0.0", - "mkdirp-classic": "^0.5.2", - "module-deps": "^6.2.3", - "os-browserify": "~0.3.0", - "parents": "^1.0.1", - "path-browserify": "~0.0.0", - "process": "~0.11.0", - "punycode": "^1.3.2", - "querystring-es3": "~0.2.0", - "read-only-stream": "^2.0.0", - "readable-stream": "^2.0.2", - "resolve": "^1.1.4", - "shasum": "^1.0.0", - "shell-quote": "^1.6.1", - "stream-browserify": "^2.0.0", - "stream-http": "^3.0.0", - "string_decoder": "^1.1.1", - "subarg": "^1.0.0", - "syntax-error": "^1.1.1", - "through2": "^2.0.0", - "timers-browserify": "^1.0.1", - "tty-browserify": "0.0.1", - "url": "~0.11.0", - "util": "~0.10.1", - "vm-browserify": "^1.0.0", - "xtend": "^4.0.0" - }, + "node_modules/@vue/shared": { + "version": "3.5.31", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.31.tgz", + "integrity": "sha512-nBxuiuS9Lj5bPkPbWogPUnjxxWpkRniX7e5UBQDWl6Fsf4roq9wwV+cR7ezQ4zXswNvPIlsdj1slcLB7XCsRAw==", + "dev": true, + "license": "MIT" + }, + "node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "license": "MIT", + "peer": true, "bin": { - "browserify": "bin/cmd.js" + "acorn": "bin/acorn" }, "engines": { - "node": ">= 0.8" + "node": ">=0.4.0" } }, - "node_modules/browserify-aes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, "license": "MIT", - "dependencies": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/browserify-cipher": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", "dev": true, "license": "MIT", - "dependencies": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" + "engines": { + "node": ">= 14" } }, - "node_modules/browserify-des": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", - "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", "dev": true, "license": "MIT", "dependencies": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/browserify-rsa": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.1.tgz", - "integrity": "sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==", + "node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "dev": true, "license": "MIT", "dependencies": { - "bn.js": "^5.2.1", - "randombytes": "^2.1.0", - "safe-buffer": "^5.2.1" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" }, - "engines": { - "node": ">= 0.10" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/browserify-rsa/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==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/browserify-sign": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.5.tgz", - "integrity": "sha512-C2AUdAJg6rlM2W5QMp2Q4KGQMVBwR1lIimTsUnutJ8bMpW5B52pGpR2gEnNBNwijumDo5FojQ0L9JrXA8m4YEw==", + "node_modules/ansi-escapes": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.2.0.tgz", + "integrity": "sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "bn.js": "^5.2.2", - "browserify-rsa": "^4.1.1", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "elliptic": "^6.6.1", - "inherits": "^2.0.4", - "parse-asn1": "^5.1.9", - "readable-stream": "^2.3.8", - "safe-buffer": "^5.2.1" + "environment": "^1.0.0" }, "engines": { - "node": ">= 0.10" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/browserify-sign/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==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/browserify-zlib": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", - "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "dev": true, "license": "MIT", - "dependencies": { - "pako": "~1.0.5" + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz", - "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==", + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4" + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/argv-formatter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/argv-formatter/-/argv-formatter-1.0.0.tgz", + "integrity": "sha512-F2+Hkm9xFaRg+GkaNnbwXNDV5O6pnCFEmqyhvfC/Ic5LbgOWjJh3L+mN/s91rxVL3znE7DYVpW0GJFT+4YBgWw==", "dev": true, "license": "MIT" }, - "node_modules/buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "node_modules/array-ify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", + "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", "dev": true, "license": "MIT" }, - "node_modules/builtin-modules": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", - "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "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": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=12" } }, - "node_modules/builtin-status-codes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", - "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "node_modules/ast-v8-to-istanbul": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.0.tgz", + "integrity": "sha512-1fSfIwuDICFA4LKkCzRPO7F0hzFf0B7+Xqrl27ynQaa+Rh0e1Es0v6kWHPott3lU10AyAr7oKHa65OppjLn3Rg==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 0.8" + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.31", + "estree-walker": "^3.0.3", + "js-tokens": "^10.0.0" } }, - "node_modules/cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "node_modules/ast-v8-to-istanbul/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", "dev": true, "license": "MIT", "dependencies": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" + "@types/estree": "^1.0.0" } }, - "node_modules/cached-path-relative": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.1.0.tgz", - "integrity": "sha512-WF0LihfemtesFcJgO7xfOoOcnWzY/QHR4qeDqV44jPU3HTI54+LnfXK3SA27AVVGCdZFgjjFFaqUA9Jx7dMJZA==", + "node_modules/ast-v8-to-istanbul/node_modules/js-tokens": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz", + "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==", "dev": true, "license": "MIT" }, - "node_modules/call-bind": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", - "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/before-after-hook": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-4.0.0.tgz", + "integrity": "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/bidi-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", + "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", "dev": true, "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.0", - "es-define-property": "^1.0.0", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "require-from-string": "^2.0.2" } }, - "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==", + "node_modules/bottleneck": { + "version": "2.19.5", + "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", + "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==", + "dev": true, + "license": "MIT" + }, + "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==", "dev": true, "license": "MIT", "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "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==", + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" + "fill-range": "^7.1.1" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, "node_modules/callsites": { @@ -2031,34 +3437,14 @@ "node": ">=6" } }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/chai": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", - "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.1.0" - }, "engines": { - "node": ">=4" + "node": ">=18" } }, "node_modules/chalk": { @@ -2088,96 +3474,6 @@ "node": ">=10" } }, - "node_modules/check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-func-name": "^2.0.2" - }, - "engines": { - "node": "*" - } - }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/cipher-base": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.7.tgz", - "integrity": "sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.4", - "safe-buffer": "^5.2.1", - "to-buffer": "^1.2.2" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/cipher-base/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==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "license": "MIT", - "dependencies": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -2288,220 +3584,67 @@ "dependencies": { "string-width": "^4.2.0" }, - "engines": { - "node": "10.* || >= 12.*" - }, - "optionalDependencies": { - "@colors/colors": "1.5.0" - } - }, - "node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "node_modules/collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", - "dev": true, - "license": "MIT", - "dependencies": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/combine-source-map": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.8.0.tgz", - "integrity": "sha512-UlxQ9Vw0b/Bt/KYwCFqdEwsQ1eL8d1gibiFb7lxQJFdvTgc2hIZi6ugsg+kyhzhPV+QEpUiEIwInIAIrgoEkrg==", - "dev": true, - "license": "MIT", - "dependencies": { - "convert-source-map": "~1.1.0", - "inline-source-map": "~0.6.0", - "lodash.memoize": "~3.0.3", - "source-map": "~0.5.3" - } - }, - "node_modules/combine-source-map/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/commander": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", - "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", - "dev": true, - "license": "MIT" - }, - "node_modules/compare-func": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", - "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-ify": "^1.0.0", - "dot-prop": "^5.1.0" - } - }, - "node_modules/component-bind": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", - "integrity": "sha512-WZveuKPeKAG9qY+FkYDeADzdHyTYdIboXS59ixDeRJL5ZhxpqUnxSOwop4FQjMsiYm3/Or8cegVbpAHNA7pHxw==", - "dev": true - }, - "node_modules/component-emitter": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", - "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/component-inherit": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", - "integrity": "sha512-w+LhYREhatpVqTESyGFg3NlP6Iu0kEKUHETY9GoZP/pQyW4mHFZuFWRUCIqVPZ36ueVLtoOEZaAqbCF2RDndaA==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, - "node_modules/concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "engines": [ - "node >= 0.8" - ], - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "node_modules/config-chain": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", - "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" } }, - "node_modules/connect": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", - "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "license": "MIT", "dependencies": { - "debug": "2.6.9", - "finalhandler": "1.1.2", - "parseurl": "~1.3.3", - "utils-merge": "1.0.1" + "color-name": "~1.1.4" }, "engines": { - "node": ">= 0.10.0" + "node": ">=7.0.0" } }, - "node_modules/connect/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", "dev": true, "license": "MIT", "dependencies": { - "ms": "2.0.0" + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" } }, - "node_modules/connect/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "node_modules/computeds": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/computeds/-/computeds-0.0.1.tgz", + "integrity": "sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==", "dev": true, "license": "MIT" }, - "node_modules/console-browserify": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", - "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", - "dev": true - }, - "node_modules/constants-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", - "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==", + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true, "license": "MIT" }, - "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==", + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 0.6" + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" } }, "node_modules/conventional-changelog-angular": { @@ -2570,460 +3713,163 @@ "license": "MIT", "engines": { "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/convert-source-map": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", - "integrity": "sha512-Y8L5rp6jo+g9VEPgvqNfEopjTR4OTYct8lXlS8iVQdmnjDvbdbzYe9rjtFCB9egC86JoNCU61WRY+ScjkZpnIg==", - "dev": true, - "license": "MIT" - }, - "node_modules/cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/cosmiconfig": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", - "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", - "dev": true, - "license": "MIT", - "dependencies": { - "env-paths": "^2.2.1", - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" - }, - "peerDependencies": { - "typescript": ">=4.9.5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/cosmiconfig/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/cosmiconfig/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==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/create-ecdh": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", - "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", - "dev": true, - "license": "MIT", - "dependencies": { - "bn.js": "^4.1.0", - "elliptic": "^6.5.3" - } - }, - "node_modules/create-ecdh/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", - "dev": true, - "license": "MIT" - }, - "node_modules/create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "node_modules/create-hmac": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/crypto-browserify": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.1.tgz", - "integrity": "sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "browserify-cipher": "^1.0.1", - "browserify-sign": "^4.2.3", - "create-ecdh": "^4.0.4", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "diffie-hellman": "^5.0.3", - "hash-base": "~3.0.4", - "inherits": "^2.0.4", - "pbkdf2": "^3.1.2", - "public-encrypt": "^4.0.3", - "randombytes": "^2.1.0", - "randomfill": "^1.0.4" - }, - "engines": { - "node": ">= 0.10" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/crypto-random-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", - "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^1.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/crypto-random-string/node_modules/type-fest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/custom-event": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", - "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==", - "dev": true, - "license": "MIT" - }, - "node_modules/dash-ast": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dash-ast/-/dash-ast-1.0.0.tgz", - "integrity": "sha512-Vy4dx7gquTeMcQR/hDkYLGUnwVil6vk4FOOct+djUnHOUWt+zJPJAaRIXaAFkPXtJjvlY7o3rfRu0/3hpnwoUA==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/date-format": { - "version": "4.0.14", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", - "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decode-uri-component": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", - "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/deep-eql": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", - "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "dev": true, "license": "MIT" }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", "dev": true, "license": "MIT", "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" }, "engines": { - "node": ">= 0.4" + "node": ">=14" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "license": "MIT", "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 8" } }, - "node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "node_modules/crypto-random-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", + "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", "dev": true, "license": "MIT", "dependencies": { - "is-descriptor": "^0.1.0" + "type-fest": "^1.0.1" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/defined": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz", - "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==", - "dev": true, - "license": "MIT", + "node": ">=12" + }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "node_modules/crypto-random-string/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", "dev": true, - "license": "MIT", + "license": "(MIT OR CC0-1.0)", "engines": { - "node": ">= 0.8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/deps-sort": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.1.tgz", - "integrity": "sha512-1orqXQr5po+3KI6kQb9A4jnXT1PBwggGl2d7Sq2xsnOeI9GPcE/tGcF9UiSZtZBM7MukY4cAh7MemS6tZYipfw==", + "node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", "dev": true, "license": "MIT", "dependencies": { - "JSONStream": "^1.0.3", - "shasum-object": "^1.0.0", - "subarg": "^1.0.0", - "through2": "^2.0.0" + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" }, - "bin": { - "deps-sort": "bin/cmd.js" + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" } }, - "node_modules/des.js": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", - "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", + "node_modules/data-urls": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-7.0.0.tgz", + "integrity": "sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==", "dev": true, "license": "MIT", "dependencies": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "node_modules/de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } + "license": "MIT" }, - "node_modules/detective": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.1.tgz", - "integrity": "sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==", + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dev": true, "license": "MIT", "dependencies": { - "acorn-node": "^1.8.2", - "defined": "^1.0.0", - "minimist": "^1.2.6" - }, - "bin": { - "detective": "bin/detective.js" + "ms": "^2.1.3" }, "engines": { - "node": ">=0.8.0" + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/di": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", - "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", "dev": true, "license": "MIT" }, - "node_modules/diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/diffie-hellman": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "dev": true, "license": "MIT", - "dependencies": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" + "engines": { + "node": ">=4.0.0" } }, - "node_modules/diffie-hellman/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true, "license": "MIT" }, @@ -3040,43 +3886,6 @@ "node": ">=8" } }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/dom-serialize": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", - "integrity": "sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "custom-event": "~1.0.0", - "ent": "~2.2.0", - "extend": "^3.0.0", - "void-elements": "^2.0.0" - } - }, - "node_modules/domain-browser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", - "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4", - "npm": ">=1.2" - } - }, "node_modules/dot-prop": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", @@ -3090,21 +3899,6 @@ "node": ">=8" } }, - "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==", - "dev": true, - "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/duplexer2": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", @@ -3115,36 +3909,6 @@ "readable-stream": "^2.0.2" } }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true, - "license": "MIT" - }, - "node_modules/elliptic": { - "version": "6.6.1", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", - "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", - "dev": true, - "license": "MIT" - }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -3159,124 +3923,17 @@ "dev": true, "license": "MIT" }, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/engine.io": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.6.2.tgz", - "integrity": "sha512-C4JjGQZLY3kWlIDx0BQNKizbrfpb7NahxDztGdN5jrPK2ghmXiNDN+E/t0JzDeNRZxPVaszxEng42Pmj27X/0w==", - "dev": true, - "license": "MIT", - "dependencies": { - "accepts": "~1.3.4", - "base64id": "2.0.0", - "cookie": "~0.4.1", - "debug": "~4.1.0", - "engine.io-parser": "~2.2.0", - "ws": "~7.5.10" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/engine.io-client": { - "version": "3.5.6", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.5.6.tgz", - "integrity": "sha512-2fDMKiXSU7bGRDCWEw9cHEdRNfoU8cpP6lt+nwJhv72tSJpO7YBsqMqYZ63eVvwX3l9prPl2k/mxhfVhY+SDWg==", - "dev": true, - "license": "MIT", - "dependencies": { - "component-emitter": "~1.3.0", - "component-inherit": "0.0.3", - "debug": "~3.1.0", - "engine.io-parser": "~2.2.0", - "has-cors": "1.1.0", - "indexof": "0.0.1", - "parseqs": "0.0.6", - "parseuri": "0.0.6", - "ws": "~7.5.10", - "xmlhttprequest-ssl": "~1.6.2", - "yeast": "0.1.2" - } - }, - "node_modules/engine.io-client/node_modules/debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/engine.io-client/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" - }, - "node_modules/engine.io-parser": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.1.tgz", - "integrity": "sha512-x+dN/fBH8Ro8TFwJ+rkB2AmuVw9Yu2mockR/p3W8f8YtExwFgDvBDi0GWyb4ZLkpahtDGZgtr3zLovanJghPqg==", - "dev": true, - "license": "MIT", - "dependencies": { - "after": "0.8.2", - "arraybuffer.slice": "~0.0.7", - "base64-arraybuffer": "0.1.4", - "blob": "0.0.5", - "has-binary2": "~1.0.2" - } - }, - "node_modules/engine.io/node_modules/debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/enquirer": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", - "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", "dev": true, - "license": "MIT", - "dependencies": { - "ansi-colors": "^4.1.1", - "strip-ansi": "^6.0.1" - }, + "license": "BSD-2-Clause", "engines": { - "node": ">=8.6" - } - }, - "node_modules/ent": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.2.tgz", - "integrity": "sha512-kKvD1tO6BM+oK9HzCPpUdRb4vKFQY/FPTFmurMvh6LlN68VMrdj77w8yp51/kDbpkFOS9J8w5W6zIzgM2H8/hw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "punycode": "^1.4.1", - "safe-regex-test": "^1.1.0" + "node": ">=0.12" }, - "engines": { - "node": ">= 0.4" + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" } }, "node_modules/env-ci": { @@ -3470,37 +4127,53 @@ "is-arrayish": "^0.2.1" } }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "dev": true, - "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==", + "node_modules/es-module-lexer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", + "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } + "license": "MIT" }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", "dev": true, + "hasInstallScript": true, "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" + "bin": { + "esbuild": "bin/esbuild" }, "engines": { - "node": ">= 0.4" + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" } }, "node_modules/escalade": { @@ -3513,13 +4186,6 @@ "node": ">=6" } }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "dev": true, - "license": "MIT" - }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -3534,69 +4200,69 @@ } }, "node_modules/eslint": { - "version": "7.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", - "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", - "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", - "ajv": "^6.10.0", + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", + "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.2", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.5", + "@eslint/js": "9.39.4", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "enquirer": "^2.3.5", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.5", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.9", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" }, - "funding": { - "url": "https://opencollective.com/eslint" + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, "node_modules/eslint-config-prettier": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", - "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.2.tgz", + "integrity": "sha512-iI1f+D2ViGn+uvv5HuHVUamg8ll4tN+JRHGc6IJi4TP9Kl976C57fzPXgseXNs8v0iA8aSJpHsTWjDb9QJamGQ==", "dev": true, "license": "MIT", "bin": { @@ -3607,114 +4273,209 @@ } }, "node_modules/eslint-plugin-prettier": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.1.tgz", - "integrity": "sha512-htg25EUYUeIhKHXjOinK4BgCcDwtLHjqaxCDsMy5nbnUMkKFvIhMVCp+5GFUXQ4Nr8lBsPqtGAqBenbpFqAA2g==", + "version": "5.5.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.5.tgz", + "integrity": "sha512-hscXkbqUZ2sPithAuLm5MXL+Wph+U7wHngPBv9OMWwlP8iaflyxpjTYZkmdgB4/vPIhemRlBEoLrH7UC1n7aUw==", "dev": true, "license": "MIT", "dependencies": { - "prettier-linter-helpers": "^1.0.0" + "prettier-linter-helpers": "^1.0.1", + "synckit": "^0.11.12" }, "engines": { - "node": ">=6.0.0" + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" }, "peerDependencies": { - "eslint": ">=5.0.0", - "prettier": ">=1.13.0" + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", + "prettier": ">=3.0.0" }, "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, "eslint-config-prettier": { "optional": true } } }, "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "estraverse": "^5.2.0" }, "engines": { - "node": ">=8.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^1.1.0" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": ">=6" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, - "license": "Apache-2.0", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, "engines": { - "node": ">=4" + "node": ">=10.13.0" } }, - "node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" + "yocto-queue": "^0.1.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "node_modules/eslint/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "license": "MIT", "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" + "acorn": "bin/acorn" }, "engines": { - "node": ">=4" + "node": ">=0.4.0" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/esquery": { @@ -3730,16 +4491,6 @@ "node": ">=0.10" } }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -3753,7 +4504,7 @@ "node": ">=4.0" } }, - "node_modules/esrecurse/node_modules/estraverse": { + "node_modules/estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", @@ -3763,16 +4514,6 @@ "node": ">=4.0" } }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, "node_modules/estree-walker": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", @@ -3790,34 +4531,6 @@ "node": ">=0.10.0" } }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true, - "license": "MIT" - }, - "node_modules/events": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/events/-/events-2.1.0.tgz", - "integrity": "sha512-3Zmiobend8P9DjmKAty0Era4jV8oJ0yGYe2nJJAxgymF9+N8F2m0hhZiMoWtcfepExzNKZumFU3ksdQbInGWCg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4.x" - } - }, - "node_modules/evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "dev": true, - "license": "MIT", - "dependencies": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -3842,107 +4555,14 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/expand-brackets/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true, - "license": "MIT" - }, - "node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/is-descriptor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", - "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", "dev": true, - "license": "MIT", - "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" - }, + "license": "Apache-2.0", "engines": { - "node": ">= 0.4" + "node": ">=12.0.0" } }, "node_modules/fast-content-type-parse": { @@ -3990,30 +4610,6 @@ "dev": true, "license": "MIT" }, - "node_modules/fast-safe-stringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, "node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", @@ -4049,86 +4645,29 @@ } }, "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "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==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "license": "MIT", "dependencies": { - "ms": "2.0.0" + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.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==", - "dev": true, - "license": "MIT" - }, - "node_modules/finalhandler/node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "license": "MIT", "dependencies": { - "ee-first": "1.1.1" + "to-regex-range": "^5.0.1" }, "engines": { - "node": ">= 0.8" + "node": ">=8" } }, "node_modules/find-up": { @@ -4175,18 +4714,17 @@ } }, "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "license": "MIT", "dependencies": { "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" + "keyv": "^4.5.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16" } }, "node_modules/flatted": { @@ -4196,66 +4734,6 @@ "dev": true, "license": "ISC" }, - "node_modules/follow-redirects": { - "version": "1.15.11", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", - "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/for-each": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", - "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-callable": "^1.2.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", - "dev": true, - "license": "MIT", - "dependencies": { - "map-cache": "^0.2.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/from2": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", @@ -4282,13 +4760,6 @@ "node": ">=14.14" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, - "license": "ISC" - }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -4327,20 +4798,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", - "dev": true, - "license": "MIT" - }, - "node_modules/get-assigned-identifiers": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz", - "integrity": "sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ==", - "dev": true, - "license": "Apache-2.0" - }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -4351,381 +4808,84 @@ "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "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==", - "dev": true, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/git-log-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/git-log-parser/-/git-log-parser-1.2.1.tgz", - "integrity": "sha512-PI+sPDvHXNPl5WNOErAK05s3j0lgwUzMN6o8cyQrDaKfT3qd7TmNJKeXX+SknI5I0QhG5fVPAEwSY4tRGDtYoQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "argv-formatter": "~1.0.0", - "spawn-error-forwarder": "~1.0.0", - "split2": "~1.0.0", - "stream-combiner2": "~1.1.1", - "through2": "~2.0.0", - "traverse": "0.6.8" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4.x" - } - }, - "node_modules/handlebars": { - "version": "4.7.8", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", - "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "minimist": "^1.2.5", - "neo-async": "^2.6.2", - "source-map": "^0.6.1", - "wordwrap": "^1.0.0" - }, - "bin": { - "handlebars": "bin/handlebars" - }, - "engines": { - "node": ">=0.4.7" - }, - "optionalDependencies": { - "uglify-js": "^3.1.4" - } - }, - "node_modules/has": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", - "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-binary2": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", - "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", - "dev": true, - "license": "MIT", - "dependencies": { - "isarray": "2.0.1" - } - }, - "node_modules/has-binary2/node_modules/isarray": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", - "integrity": "sha512-c2cu3UxbI+b6kR3fy0nRnAhodsvR9dx7U5+znCOzdj6IfP3upFURTr0Xl5BlQZNKZjEtxrmVyfSdeE3O57smoQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/has-cors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", - "integrity": "sha512-g5VNKdkFuUuVCP9gYfDJHjK2nqdQJ7aDLTnycnc2+RvsOQbuLdF5pm7vuE5J76SEBIQjs4kQY/BWq74JUmjbXA==", - "dev": true, - "license": "MIT" - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", + "node_modules/git-log-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/git-log-parser/-/git-log-parser-1.2.1.tgz", + "integrity": "sha512-PI+sPDvHXNPl5WNOErAK05s3j0lgwUzMN6o8cyQrDaKfT3qd7TmNJKeXX+SknI5I0QhG5fVPAEwSY4tRGDtYoQ==", "dev": true, "license": "MIT", "dependencies": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" + "argv-formatter": "~1.0.0", + "spawn-error-forwarder": "~1.0.0", + "split2": "~1.0.0", + "stream-combiner2": "~1.1.1", + "through2": "~2.0.0", + "traverse": "0.6.8" } }, - "node_modules/has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, "license": "MIT", - "dependencies": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", - "dev": true, - "license": "MIT", - "dependencies": { - "kind-of": "^3.0.2" + "node": ">=18" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/has-values/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true, - "license": "MIT", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } + "license": "ISC" }, - "node_modules/hash-base": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.5.tgz", - "integrity": "sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==", + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", "dev": true, "license": "MIT", "dependencies": { - "inherits": "^2.0.4", - "safe-buffer": "^5.2.1" + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" }, "engines": { - "node": ">= 0.10" + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" } }, - "node_modules/hash-base/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==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" + "engines": { + "node": ">=8" } }, "node_modules/hasown": { @@ -4741,16 +4901,6 @@ "node": ">= 0.4" } }, - "node_modules/he": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", - "integrity": "sha512-z/GDPjlRMNOa2XJiB4em8wJpuuBfrFOlYKTZxtpkdr1uPdibHI8rYA3MY0KDObpVyaes0e/aunid/t88ZI2EKA==", - "dev": true, - "license": "MIT", - "bin": { - "he": "bin/he" - } - }, "node_modules/highlight.js": { "version": "10.7.3", "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", @@ -4761,18 +4911,6 @@ "node": "*" } }, - "node_modules/hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", - "dev": true, - "license": "MIT", - "dependencies": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, "node_modules/hook-std": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/hook-std/-/hook-std-4.0.0.tgz", @@ -4799,61 +4937,25 @@ "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/htmlescape": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz", - "integrity": "sha512-eVcrzgbR4tim7c7soKQKtxa/kQM4TzjnlU83rcZ9bHU6t31ehfV7SktN6McWgwPWg+JYMA/O3qpGxBvFq1z2Jg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10" - } - }, - "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==", + "node_modules/html-encoding-sniffer": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-6.0.0.tgz", + "integrity": "sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==", "dev": true, "license": "MIT", "dependencies": { - "depd": "~2.0.0", - "inherits": "~2.0.4", - "setprototypeof": "~1.2.0", - "statuses": "~2.0.2", - "toidentifier": "~1.0.1" + "@exodus/bytes": "^1.6.0" }, "engines": { - "node": ">= 0.8" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, - "node_modules/http-errors/node_modules/statuses": { + "node_modules/html-escaper": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true, - "license": "MIT", - "dependencies": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - }, - "engines": { - "node": ">=8.0.0" - } + "license": "MIT" }, "node_modules/http-proxy-agent": { "version": "7.0.2", @@ -4869,13 +4971,6 @@ "node": ">= 14" } }, - "node_modules/https-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", - "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==", - "dev": true, - "license": "MIT" - }, "node_modules/https-proxy-agent": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", @@ -4900,44 +4995,10 @@ "node": ">=10.17.0" } }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, "node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "license": "MIT", "engines": { @@ -4975,6 +5036,16 @@ "node": ">=18.20" } }, + "node_modules/import-lazy": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", + "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/import-meta-resolve": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", @@ -5019,24 +5090,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/indexof": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", - "integrity": "sha512-i0G7hLJ1z0DE8dsqJa2rycj9dBmNKgXBvotXtZYXakU9oivfB9Uj2ZBC27qqef2U58/ZLwalxa1X/RDCdkHtVg==", - "dev": true - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -5051,195 +5104,44 @@ "dev": true, "license": "ISC" }, - "node_modules/inline-source-map": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.3.tgz", - "integrity": "sha512-1aVsPEsJWMJq/pdMU61CDlm1URcW702MTB4w9/zUjMus6H/Py8o7g68Pr9D4I6QluWGt/KdmswuRhaA05xVR1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "source-map": "~0.5.3" - } - }, - "node_modules/inline-source-map/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/insert-module-globals": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.2.1.tgz", - "integrity": "sha512-ufS5Qq9RZN+Bu899eA9QCAYThY+gGW7oRkmb0vC93Vlyu/CFGcH0OYPEjVkDXA5FEbTt1+VWzdoOD3Ny9N+8tg==", - "dev": true, - "license": "MIT", - "dependencies": { - "acorn-node": "^1.5.2", - "combine-source-map": "^0.8.0", - "concat-stream": "^1.6.1", - "is-buffer": "^1.1.0", - "JSONStream": "^1.0.3", - "path-is-absolute": "^1.0.1", - "process": "~0.11.0", - "through2": "^2.0.0", - "undeclared-identifiers": "^1.1.2", - "xtend": "^4.0.0" - }, - "bin": { - "insert-module-globals": "bin/cmd.js" - } - }, - "node_modules/interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, "node_modules/into-stream": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-7.0.0.tgz", - "integrity": "sha512-2dYz766i9HprMBasCMvHMuazJ7u4WzhJwo5kb3iPSiW/iRYV6uPari3zHoqZlnuaR7V1bEiNMxikhp37rdBXbw==", - "dev": true, - "license": "MIT", - "dependencies": { - "from2": "^2.3.0", - "p-is-promise": "^3.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-accessor-descriptor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz", - "integrity": "sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true, - "license": "MIT" - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true, - "license": "MIT" - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-data-descriptor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.1.tgz", - "integrity": "sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==", + "integrity": "sha512-2dYz766i9HprMBasCMvHMuazJ7u4WzhJwo5kb3iPSiW/iRYV6uPari3zHoqZlnuaR7V1bEiNMxikhp37rdBXbw==", "dev": true, "license": "MIT", "dependencies": { - "hasown": "^2.0.0" + "from2": "^2.3.0", + "p-is-promise": "^3.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-descriptor": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", - "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true, - "license": "MIT", - "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - } + "license": "MIT" }, - "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==", + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "dev": true, "license": "MIT", - "bin": { - "is-docker": "cli.js" + "dependencies": { + "hasown": "^2.0.2" }, "engines": { - "node": ">=8" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-extglob": { @@ -5275,13 +5177,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", - "dev": true, - "license": "MIT" - }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -5315,47 +5210,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "license": "MIT", - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-reference": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", - "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "*" - } - }, - "node_modules/is-regex": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", - "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "license": "MIT" }, "node_modules/is-stream": { "version": "2.0.1", @@ -5370,22 +5230,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", - "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "which-typed-array": "^1.1.16" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-unicode-supported": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", @@ -5399,29 +5243,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -5429,19 +5250,6 @@ "dev": true, "license": "MIT" }, - "node_modules/isbinaryfile": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", - "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/gjtorikian/" - } - }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -5449,16 +5257,6 @@ "dev": true, "license": "ISC" }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/issue-parser": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-7.0.1.tgz", @@ -5476,6 +5274,45 @@ "node": "^18.17 || >=20.6.1" } }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/java-properties": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/java-properties/-/java-properties-1.0.2.tgz", @@ -5486,6 +5323,13 @@ "node": ">= 0.6.0" } }, + "node_modules/jju": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", + "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", + "dev": true, + "license": "MIT" + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -5494,222 +5338,141 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", - "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "license": "MIT", "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-stable-stringify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz", - "integrity": "sha512-nKtD/Qxm7tWdZqJoldEC7fF0S41v0mWbeaXG3637stOWfyGxTgWTYE2wtfKmjzpvxv2MA2xzxsXOIiwUpkX6Qw==", - "dev": true, - "license": "MIT", - "dependencies": { - "jsonify": "~0.0.0" - } - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/jsonfile": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", - "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "node_modules/jsdom": { + "version": "29.0.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-29.0.1.tgz", + "integrity": "sha512-z6JOK5gRO7aMybVq/y/MlIpKh8JIi68FBKMUtKkK2KH/wMSRlCxQ682d08LB9fYXplyY/UXG8P4XXTScmdjApg==", "dev": true, "license": "MIT", "dependencies": { - "universalify": "^2.0.0" + "@asamuzakjp/css-color": "^5.0.1", + "@asamuzakjp/dom-selector": "^7.0.3", + "@bramus/specificity": "^2.4.2", + "@csstools/css-syntax-patches-for-csstree": "^1.1.1", + "@exodus/bytes": "^1.15.0", + "css-tree": "^3.2.1", + "data-urls": "^7.0.0", + "decimal.js": "^10.6.0", + "html-encoding-sniffer": "^6.0.0", + "is-potential-custom-element-name": "^1.0.1", + "lru-cache": "^11.2.7", + "parse5": "^8.0.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^6.0.1", + "undici": "^7.24.5", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^8.0.1", + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.1", + "xml-name-validator": "^5.0.0" }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24.0.0" + }, + "peerDependencies": { + "canvas": "^3.0.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } } }, - "node_modules/jsonify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz", - "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==", + "node_modules/jsdom/node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", "dev": true, - "license": "Public Domain", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", - "dev": true, - "engines": [ - "node >= 0.2.0" - ], - "license": "MIT" - }, - "node_modules/JSONStream": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", - "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "node_modules/jsdom/node_modules/parse5": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.0.tgz", + "integrity": "sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==", "dev": true, - "license": "(MIT OR Apache-2.0)", + "license": "MIT", "dependencies": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - }, - "bin": { - "JSONStream": "bin.js" + "entities": "^6.0.0" }, - "engines": { - "node": "*" + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/karma": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/karma/-/karma-5.2.3.tgz", - "integrity": "sha512-tHdyFADhVVPBorIKCX8A37iLHxc6RBRphkSoQ+MLKdAtFn1k97tD8WUGi1KlEtDZKL3hui0qhsY9HXUfSNDYPQ==", + "node_modules/jsdom/node_modules/undici": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.24.6.tgz", + "integrity": "sha512-Xi4agocCbRzt0yYMZGMA6ApD7gvtUFaxm4ZmeacWI4cZxaF6C+8I8QfofC20NAePiB/IcvZmzkJ7XPa471AEtA==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "body-parser": "^1.19.0", - "braces": "^3.0.2", - "chokidar": "^3.4.2", - "colors": "^1.4.0", - "connect": "^3.7.0", - "di": "^0.0.1", - "dom-serialize": "^2.2.1", - "glob": "^7.1.6", - "graceful-fs": "^4.2.4", - "http-proxy": "^1.18.1", - "isbinaryfile": "^4.0.6", - "lodash": "^4.17.19", - "log4js": "^6.2.1", - "mime": "^2.4.5", - "minimatch": "^3.0.4", - "qjobs": "^1.2.0", - "range-parser": "^1.2.1", - "rimraf": "^3.0.2", - "socket.io": "^2.3.0", - "source-map": "^0.6.1", - "tmp": "0.2.1", - "ua-parser-js": "0.7.22", - "yargs": "^15.3.1" - }, - "bin": { - "karma": "bin/karma" - }, "engines": { - "node": ">= 10" + "node": ">=20.18.1" } }, - "node_modules/karma-chai": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/karma-chai/-/karma-chai-0.1.0.tgz", - "integrity": "sha512-mqKCkHwzPMhgTYca10S90aCEX9+HjVjjrBFAsw36Zj7BlQNbokXXCAe6Ji04VUMsxcY5RLP7YphpfO06XOubdg==", + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true, - "license": "MIT", - "peerDependencies": { - "chai": "*", - "karma": ">=0.10.9" - } + "license": "MIT" }, - "node_modules/karma-chrome-launcher": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.2.0.tgz", - "integrity": "sha512-rE9RkUPI7I9mAxByQWkGJFXfFD6lE4gC5nPuZdobf/QdTEJI6EU4yIay/cfU/xV4ZxlM5JiTv7zWYgA64NpS5Q==", + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", "dev": true, - "license": "MIT", - "dependencies": { - "which": "^1.2.1" - } + "license": "MIT" }, - "node_modules/karma-chrome-launcher/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" }, - "node_modules/karma-firefox-launcher": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/karma-firefox-launcher/-/karma-firefox-launcher-2.1.3.tgz", - "integrity": "sha512-LMM2bseebLbYjODBOVt7TCPP9OI2vZIXCavIXhkO9m+10Uj5l7u/SKoeRmYx8FYHTVGZSpk6peX+3BMHC1WwNw==", + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true, - "license": "MIT", - "dependencies": { - "is-wsl": "^2.2.0", - "which": "^3.0.0" - } + "license": "MIT" }, - "node_modules/karma-firefox-launcher/node_modules/which": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", - "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } + "license": "MIT" }, - "node_modules/karma-mocha": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/karma-mocha/-/karma-mocha-2.0.1.tgz", - "integrity": "sha512-Tzd5HBjm8his2OA4bouAsATYEpZrp9vC7z5E5j4C5Of5Rrs1jY67RAwXNcVmd/Bnk1wgvQRou0zGVLey44G4tQ==", + "node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", "dev": true, "license": "MIT", "dependencies": { - "minimist": "^1.2.3" + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" } }, "node_modules/keyv": { @@ -5722,29 +5485,12 @@ "json-buffer": "3.0.1" } }, - "node_modules/kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/labeled-stream-splicer": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.2.tgz", - "integrity": "sha512-Ca4LSXFFZUjPScRaqOcFxneA0VpKZr4MMYCljyQr4LIewTLb3Y0IUTIsnBBsVubIeEfxeSZpSjSsRM8APEQaAw==", + "node_modules/kolorist": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", + "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==", "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.1", - "stream-splicer": "^2.0.0" - } + "license": "MIT" }, "node_modules/levn": { "version": "0.4.1", @@ -5839,6 +5585,22 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "deprecated": "This package is deprecated. Use the optional chaining (?.) operator instead.", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.isplainobject": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", @@ -5853,13 +5615,6 @@ "dev": true, "license": "MIT" }, - "node_modules/lodash.memoize": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz", - "integrity": "sha512-eDn9kqrAmVUC1wmZvlQ6Uhde44n+tXpqPrN8olQJbttgh0oKclk+SF54P47VEGE9CEiMeRwAP8BaM7UHvBkz2A==", - "dev": true, - "license": "MIT" - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -5867,13 +5622,6 @@ "dev": true, "license": "MIT" }, - "node_modules/lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", - "dev": true, - "license": "MIT" - }, "node_modules/lodash.uniqby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz", @@ -5881,51 +5629,26 @@ "dev": true, "license": "MIT" }, - "node_modules/log4js": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.9.1.tgz", - "integrity": "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "date-format": "^4.0.14", - "debug": "^4.3.4", - "flatted": "^3.2.7", - "rfdc": "^1.3.0", - "streamroller": "^3.1.5" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-func-name": "^2.0.1" - } - }, "node_modules/lru-cache": { - "version": "11.2.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.5.tgz", - "integrity": "sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw==", + "version": "11.2.7", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.7.tgz", + "integrity": "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==", "dev": true, "license": "BlueOak-1.0.0", "engines": { "node": "20 || >=22" } }, - "node_modules/magic-string": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", - "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "node_modules/magicast": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.2.tgz", + "integrity": "sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==", "dev": true, "license": "MIT", "dependencies": { - "sourcemap-codec": "^1.4.8" + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "source-map-js": "^1.2.1" } }, "node_modules/make-asynchronous": { @@ -5959,27 +5682,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, "license": "MIT", "dependencies": { - "object-visit": "^1.0.0" + "semver": "^7.5.3" }, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/marked": { @@ -5988,7 +5704,6 @@ "integrity": "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==", "dev": true, "license": "MIT", - "peer": true, "bin": { "marked": "bin/marked.js" }, @@ -6021,334 +5736,84 @@ "node_modules/marked-terminal/node_modules/chalk": { "version": "5.6.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", - "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/md5.js": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "dev": true, - "license": "MIT", - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/meow": { - "version": "13.2.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz", - "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true, - "license": "MIT" - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/miller-rabin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" - }, - "bin": { - "miller-rabin": "bin/miller-rabin" - } - }, - "node_modules/miller-rabin/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", - "dev": true, - "license": "MIT" - }, - "node_modules/mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", - "dev": true, - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "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==", - "dev": true, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true, - "license": "ISC" - }, - "node_modules/minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", - "dev": true, - "license": "MIT" - }, - "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/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "license": "MIT", - "dependencies": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mixin-deep/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", "dev": true, "license": "MIT", - "dependencies": { - "is-plain-object": "^2.0.4" - }, "engines": { - "node": ">=0.10.0" + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha512-SknJC52obPfGQPnjIkXbmA6+5H15E+fR+E4iR2oQ3zzCLbd7/ONua69R/Gw7AgkTLsRG+r5fzksYwWe1AgTyWA==", - "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", + "node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/meow": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz", + "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==", "dev": true, "license": "MIT", - "dependencies": { - "minimist": "0.0.8" + "engines": { + "node": ">=18" }, - "bin": { - "mkdirp": "bin/cmd.js" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "dev": true, - "license": "MIT" - }, - "node_modules/mkdirp/node_modules/minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha512-miQKw5Hv4NS1Psg2517mV4e4dYNaO3++hjAvLOAzKqZ61rH8NS1SK+vbfBWZ5PY/Me/bEWhUwqMghEW5Fb9T7Q==", + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true, "license": "MIT" }, - "node_modules/mocha": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", - "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "license": "MIT", "dependencies": { - "browser-stdout": "1.3.1", - "commander": "2.15.1", - "debug": "3.1.0", - "diff": "3.5.0", - "escape-string-regexp": "1.0.5", - "glob": "7.1.2", - "growl": "1.10.5", - "he": "1.1.1", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "supports-color": "5.4.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha" + "braces": "^3.0.3", + "picomatch": "^2.3.1" }, "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/mocha/node_modules/debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.0.0" + "node": ">=8.6" } }, - "node_modules/mocha/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "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==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/mocha/node_modules/glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "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": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "node": ">=8.6" }, - "engines": { - "node": "*" + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/mocha/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true, "license": "MIT", "engines": { - "node": ">=4" + "node": ">=6" } }, - "node_modules/mocha/node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "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": "ISC", "dependencies": { @@ -6358,54 +5823,14 @@ "node": "*" } }, - "node_modules/mocha/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" - }, - "node_modules/mocha/node_modules/supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/module-deps": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.2.3.tgz", - "integrity": "sha512-fg7OZaQBcL4/L+AK5f4iVqf9OMbCclXfy/znXRxTVhJSeW5AIlS9AwheYwDaXM3lVW7OBeaeUEY3gbaC6cLlSA==", + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, "license": "MIT", - "dependencies": { - "browser-resolve": "^2.0.0", - "cached-path-relative": "^1.0.2", - "concat-stream": "~1.6.0", - "defined": "^1.0.0", - "detective": "^5.2.0", - "duplexer2": "^0.1.2", - "inherits": "^2.0.1", - "JSONStream": "^1.0.3", - "parents": "^1.0.0", - "readable-stream": "^2.0.2", - "resolve": "^1.4.0", - "stream-combiner2": "^1.1.1", - "subarg": "^1.0.0", - "through2": "^2.0.0", - "xtend": "^4.0.0" - }, - "bin": { - "module-deps": "bin/cmd.js" - }, - "engines": { - "node": ">= 0.8.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/ms": { @@ -6415,6 +5840,13 @@ "dev": true, "license": "MIT" }, + "node_modules/muggle-string": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.3.1.tgz", + "integrity": "sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==", + "dev": true, + "license": "MIT" + }, "node_modules/mz": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", @@ -6427,100 +5859,23 @@ "thenify-all": "^1.0.0" } }, - "node_modules/nan": { - "version": "2.25.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.25.0.tgz", - "integrity": "sha512-0M90Ag7Xn5KMLLZ7zliPWP3rT90P6PN+IzVFS0VqmnPktBk3700xUVv8Ikm9EUaUE5SDWdp/BIxdENzVznpm1g==", - "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "license": "MIT", - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nanomatch/node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nanomatch/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nanomatch/node_modules/is-descriptor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", - "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/nanomatch/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", - "dependencies": { - "is-plain-object": "^2.0.4" + "bin": { + "nanoid": "bin/nanoid.cjs" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nanomatch/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, "node_modules/natural-compare": { @@ -6530,16 +5885,6 @@ "dev": true, "license": "MIT" }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/neo-async": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", @@ -6585,16 +5930,6 @@ "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/normalize-url": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.1.1.tgz", @@ -8591,7 +7926,6 @@ "dev": true, "inBundle": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -8715,145 +8049,35 @@ "signal-exit": "^4.0.1" }, "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", - "dev": true, - "license": "MIT", - "dependencies": { - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object.assign": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", - "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0", - "has-symbols": "^1.1.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" + "node": "^20.17.0 || >=22.9.0" } }, - "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==", + "node_modules/npm/node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "dev": true, "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, "engines": { - "node": ">= 0.8" + "node": ">=0.10.0" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "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, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT" }, "node_modules/onetime": { "version": "5.1.2", @@ -8889,23 +8113,6 @@ "node": ">= 0.8.0" } }, - "node_modules/os-browserify": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", - "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==", - "dev": true, - "license": "MIT" - }, - "node_modules/outpipe": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/outpipe/-/outpipe-1.1.1.tgz", - "integrity": "sha512-BnNY/RwnDrkmQdUa9U+OfN/Y7AWmKuUPCCd+hbRclZnnANvYpO72zp/a6Q4n829hPbdqEac31XCcsvlEvb+rtA==", - "dev": true, - "license": "MIT", - "dependencies": { - "shell-quote": "^1.4.2" - } - }, "node_modules/p-each-series": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-3.0.0.tgz", @@ -9033,13 +8240,6 @@ "node": ">=4" } }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true, - "license": "(MIT AND Zlib)" - }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -9053,54 +8253,6 @@ "node": ">=6" } }, - "node_modules/parents": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz", - "integrity": "sha512-mXKF3xkoUt5td2DoxpLmtOmZvko9VfFpwRwkKDHSNvgmpLAeBo18YDhcPbBzJq+QLCHMbGOfzia2cX4U+0v9Mg==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-platform": "~0.11.15" - } - }, - "node_modules/parse-asn1": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.9.tgz", - "integrity": "sha512-fIYNuZ/HastSb80baGOuPRo1O9cf4baWw5WsAp7dBuUzeTD/BoaG8sVTdlPFksBE2lF21dN+A1AnrpIjSWqHHg==", - "dev": true, - "license": "ISC", - "dependencies": { - "asn1.js": "^4.10.1", - "browserify-aes": "^1.2.0", - "evp_bytestokey": "^1.0.3", - "pbkdf2": "^3.1.5", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/parse-asn1/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==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", @@ -9157,54 +8309,6 @@ "dev": true, "license": "MIT" }, - "node_modules/parseqs": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz", - "integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==", - "dev": true, - "license": "MIT" - }, - "node_modules/parseuri": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz", - "integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==", - "dev": true, - "license": "MIT" - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", - "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==", - "dev": true, - "license": "MIT" - }, "node_modules/path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", @@ -9215,16 +8319,6 @@ "node": ">=4" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -9242,16 +8336,6 @@ "dev": true, "license": "MIT" }, - "node_modules/path-platform": { - "version": "0.11.15", - "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz", - "integrity": "sha512-Y30dB6rab1A/nfEKsZxmr01nUotHX0c/ZiIAsCTatEe1CmS5Pm5He7fZ195bPT7RdquoaL8lLxFCMQi/bS7IJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -9262,53 +8346,11 @@ "node": ">=8" } }, - "node_modules/pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/pbkdf2": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.5.tgz", - "integrity": "sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "ripemd160": "^2.0.3", - "safe-buffer": "^5.2.1", - "sha.js": "^2.4.12", - "to-buffer": "^1.2.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/pbkdf2/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==", + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], "license": "MIT" }, "node_modules/picocolors": { @@ -9355,227 +8397,104 @@ "node": ">=4" } }, - "node_modules/posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/possible-typed-array-names": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", - "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", - "dev": true, - "license": "MIT", - "peer": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.1.tgz", - "integrity": "sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/pretty-ms": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.0.tgz", - "integrity": "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "parse-ms": "^4.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true, - "license": "MIT" - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", - "dev": true, - "license": "ISC" - }, - "node_modules/public-encrypt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", - "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/public-encrypt/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", - "dev": true, - "license": "MIT" - }, - "node_modules/punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/qjobs": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", - "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "node_modules/postcss": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", - "engines": { - "node": ">=0.9" - } - }, - "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==", - "dev": true, - "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.1.0" + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/querystring-es3": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", - "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==", - "dev": true, - "engines": { - "node": ">=0.4.x" + "node": "^10 || ^12 || >=14" } }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, "license": "MIT", - "dependencies": { - "safe-buffer": "^5.1.0" + "engines": { + "node": ">= 0.8.0" } }, - "node_modules/randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "node_modules/prettier": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", "dev": true, "license": "MIT", - "dependencies": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "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==", + "node_modules/prettier-linter-helpers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.1.tgz", + "integrity": "sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==", "dev": true, "license": "MIT", + "dependencies": { + "fast-diff": "^1.1.2" + }, "engines": { - "node": ">= 0.6" + "node": ">=6.0.0" } }, - "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==", + "node_modules/pretty-ms": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.0.tgz", + "integrity": "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==", "dev": true, "license": "MIT", "dependencies": { - "bytes": "~3.1.2", - "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", - "unpipe": "~1.0.0" + "parse-ms": "^4.0.0" }, "engines": { - "node": ">= 0.8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "dev": true, + "license": "ISC" + }, "node_modules/rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -9602,16 +8521,6 @@ "node": ">=0.10.0" } }, - "node_modules/read-only-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz", - "integrity": "sha512-3ALe0bjBVZtkdWKIcThYpQCLbBMd/+Tbh2CDSrAIDO3UsZ4Xs+tnyjv2MjCOMMgBG+AsUOeuP1cgtY1INISc8w==", - "dev": true, - "license": "MIT", - "dependencies": { - "readable-stream": "^2.0.2" - } - }, "node_modules/read-package-up": { "version": "11.0.0", "resolved": "https://registry.npmjs.org/read-package-up/-/read-package-up-11.0.0.tgz", @@ -9842,98 +8751,6 @@ "util-deprecate": "~1.0.1" } }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/readdirp/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", - "dev": true, - "dependencies": { - "resolve": "^1.1.6" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "license": "MIT", - "dependencies": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/regex-not/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/regex-not/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, "node_modules/registry-auth-token": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.1.1.tgz", @@ -9947,33 +8764,6 @@ "node": ">=14" } }, - "node_modules/remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", - "dev": true, - "license": "ISC" - }, - "node_modules/repeat-element": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", - "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10" - } - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -9984,242 +8774,92 @@ "node": ">=0.10.0" } }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true, - "license": "ISC" - }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==", - "deprecated": "https://github.com/lydell/resolve-url#deprecated", - "dev": true, - "license": "MIT" - }, - "node_modules/ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12" - } - }, - "node_modules/rfdc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", - "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", - "dev": true, - "license": "MIT" - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/ripemd160": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.3.tgz", - "integrity": "sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==", - "dev": true, - "license": "MIT", - "dependencies": { - "hash-base": "^3.1.2", - "inherits": "^2.0.4" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/ripemd160/node_modules/hash-base": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.2.tgz", - "integrity": "sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.4", - "readable-stream": "^2.3.8", - "safe-buffer": "^5.2.1", - "to-buffer": "^1.2.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/ripemd160/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==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/rollup": { - "version": "1.32.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.32.1.tgz", - "integrity": "sha512-/2HA0Ec70TvQnXdzynFffkjA6XN+1e2pEv/uKS5Ulca40g2L7KuOE3riasHoNVHOsFD5KKZgDsMk1CP3Tw9s+A==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/estree": "*", - "@types/node": "*", - "acorn": "^7.1.0" - }, - "bin": { - "rollup": "dist/bin/rollup" - } - }, - "node_modules/rollup-plugin-commonjs": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-commonjs/-/rollup-plugin-commonjs-10.1.0.tgz", - "integrity": "sha512-jlXbjZSQg8EIeAAvepNwhJj++qJWNJw1Cl0YnOqKtP5Djx+fFGkp3WRh+W0ASCaFG5w1jhmzDxgu3SJuVxPF4Q==", - "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-commonjs.", - "dev": true, - "license": "MIT", - "dependencies": { - "estree-walker": "^0.6.1", - "is-reference": "^1.1.2", - "magic-string": "^0.25.2", - "resolve": "^1.11.0", - "rollup-pluginutils": "^2.8.1" - }, - "peerDependencies": { - "rollup": ">=1.12.0" - } - }, - "node_modules/rollup-plugin-commonjs/node_modules/estree-walker": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", - "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/rollup-plugin-node-resolve": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.2.0.tgz", - "integrity": "sha512-jUlyaDXts7TW2CqQ4GaO5VJ4PwwaV8VUGA7+km3n6k6xtOEacf61u0VXwN80phY/evMcaS+9eIeJ9MOyDxt5Zw==", - "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-node-resolve.", + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", "dev": true, "license": "MIT", "dependencies": { - "@types/resolve": "0.0.8", - "builtin-modules": "^3.1.0", - "is-module": "^1.0.0", - "resolve": "^1.11.1", - "rollup-pluginutils": "^2.8.1" + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" }, - "peerDependencies": { - "rollup": ">=1.11.0" + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/rollup-plugin-replace": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-replace/-/rollup-plugin-replace-2.2.0.tgz", - "integrity": "sha512-/5bxtUPkDHyBJAKketb4NfaeZjL5yLZdeUihSfbF2PQMz+rSTEb8ARKoOl3UBT4m7/X+QOXJo3sLTcq+yMMYTA==", - "deprecated": "This module has moved and is now available at @rollup/plugin-replace. Please update your dependencies. This version is no longer maintained.", + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, "license": "MIT", - "dependencies": { - "magic-string": "^0.25.2", - "rollup-pluginutils": "^2.6.0" + "engines": { + "node": ">=4" } }, - "node_modules/rollup-pluginutils": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", - "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", + "node_modules/rollup": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.1.tgz", + "integrity": "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==", "dev": true, "license": "MIT", "dependencies": { - "estree-walker": "^0.6.1" + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.60.1", + "@rollup/rollup-android-arm64": "4.60.1", + "@rollup/rollup-darwin-arm64": "4.60.1", + "@rollup/rollup-darwin-x64": "4.60.1", + "@rollup/rollup-freebsd-arm64": "4.60.1", + "@rollup/rollup-freebsd-x64": "4.60.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.60.1", + "@rollup/rollup-linux-arm-musleabihf": "4.60.1", + "@rollup/rollup-linux-arm64-gnu": "4.60.1", + "@rollup/rollup-linux-arm64-musl": "4.60.1", + "@rollup/rollup-linux-loong64-gnu": "4.60.1", + "@rollup/rollup-linux-loong64-musl": "4.60.1", + "@rollup/rollup-linux-ppc64-gnu": "4.60.1", + "@rollup/rollup-linux-ppc64-musl": "4.60.1", + "@rollup/rollup-linux-riscv64-gnu": "4.60.1", + "@rollup/rollup-linux-riscv64-musl": "4.60.1", + "@rollup/rollup-linux-s390x-gnu": "4.60.1", + "@rollup/rollup-linux-x64-gnu": "4.60.1", + "@rollup/rollup-linux-x64-musl": "4.60.1", + "@rollup/rollup-openbsd-x64": "4.60.1", + "@rollup/rollup-openharmony-arm64": "4.60.1", + "@rollup/rollup-win32-arm64-msvc": "4.60.1", + "@rollup/rollup-win32-ia32-msvc": "4.60.1", + "@rollup/rollup-win32-x64-gnu": "4.60.1", + "@rollup/rollup-win32-x64-msvc": "4.60.1", + "fsevents": "~2.3.2" } }, - "node_modules/rollup-pluginutils/node_modules/estree-walker": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", - "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", - "dev": true, - "license": "MIT" - }, "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -10227,48 +8867,25 @@ "dev": true, "license": "MIT" }, - "node_modules/safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ret": "~0.1.10" - } - }, - "node_modules/safe-regex-test": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", - "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-regex": "^1.2.1" + "xmlchars": "^2.2.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=v12.22.7" } }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true, - "license": "MIT" - }, "node_modules/semantic-release": { "version": "24.2.9", "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-24.2.9.tgz", "integrity": "sha512-phCkJ6pjDi9ANdhuF5ElS10GGdAKY6R1Pvt9lT3SFhOwM4T7QZE7MLpBDbNruUx/Q3gFD92/UOFringGipRqZA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@semantic-release/commit-analyzer": "^13.0.0-beta.1", "@semantic-release/error": "^4.0.0", @@ -12998,7 +11615,6 @@ "dev": true, "inBundle": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -13404,382 +12020,108 @@ "node": ">=10" } }, - "node_modules/semantic-release/node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/semantic-release/node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver-diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-5.0.0.tgz", - "integrity": "sha512-0HbGtOm+S7T6NGQ/pxJSJipJvc4DK3FcRVMRkhsIwJDJ4Jcz5DQC1cPPzB5GhzyHjwttW878HaWQq46CkL3cqg==", - "deprecated": "Deprecated as the semver package now supports this built-in.", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/semver-regex": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-4.0.5.tgz", - "integrity": "sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true, - "license": "ISC" - }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true, - "license": "ISC" - }, - "node_modules/sha.js": { - "version": "2.4.12", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz", - "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==", - "dev": true, - "license": "(MIT AND BSD-3-Clause)", - "dependencies": { - "inherits": "^2.0.4", - "safe-buffer": "^5.2.1", - "to-buffer": "^1.2.0" - }, - "bin": { - "sha.js": "bin.js" - }, - "engines": { - "node": ">= 0.10" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/sha.js/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==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/shasum": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/shasum/-/shasum-1.0.2.tgz", - "integrity": "sha512-UTzHm/+AzKfO9RgPgRpDIuMSNie1ubXRaljjlhFMNGYoG7z+rm9AHLPMf70R7887xboDH9Q+5YQbWKObFHEAtw==", - "dev": true, - "license": "MIT", - "dependencies": { - "json-stable-stringify": "~0.0.0", - "sha.js": "~2.4.4" - } - }, - "node_modules/shasum-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/shasum-object/-/shasum-object-1.0.1.tgz", - "integrity": "sha512-SsC+1tW7XKQ/94D4k1JhLmjDFpVGET/Nf54jVDtbavbALf8Zhp0Td9zTlxScjMW6nbEIrpADtPWfLk9iCXzHDQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "fast-safe-stringify": "^2.0.7" - }, - "bin": { - "shasum-object": "bin.js" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/shell-quote": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", - "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/shelljs": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.3.tgz", - "integrity": "sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - }, - "bin": { - "shjs": "bin/shjs" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/should": { - "version": "13.2.3", - "resolved": "https://registry.npmjs.org/should/-/should-13.2.3.tgz", - "integrity": "sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "should-equal": "^2.0.0", - "should-format": "^3.0.3", - "should-type": "^1.4.0", - "should-type-adaptors": "^1.0.1", - "should-util": "^1.0.0" - } - }, - "node_modules/should-equal": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz", - "integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==", - "dev": true, - "license": "MIT", - "dependencies": { - "should-type": "^1.4.0" - } - }, - "node_modules/should-format": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz", - "integrity": "sha512-hZ58adtulAk0gKtua7QxevgUaXTTXxIi8t41L3zo9AHvjXO1/7sdLECuHeIN2SRtYXpNkmhoUP2pdeWgricQ+Q==", + "node_modules/semantic-release/node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, "license": "MIT", "dependencies": { - "should-type": "^1.3.0", - "should-type-adaptors": "^1.0.1" + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" } }, - "node_modules/should-type": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", - "integrity": "sha512-MdAsTu3n25yDbIe1NeN69G4n6mUnJGtSJHygX3+oN0ZbO3DTiATnf7XnYJdGT42JCXurTb1JI0qOBR65shvhPQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/should-type-adaptors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz", - "integrity": "sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==", + "node_modules/semantic-release/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, - "license": "MIT", - "dependencies": { - "should-type": "^1.3.0", - "should-util": "^1.0.0" + "license": "ISC", + "engines": { + "node": ">=12" } }, - "node_modules/should-util": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.1.tgz", - "integrity": "sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g==", + "node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "dev": true, - "license": "MIT" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } }, - "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==", + "node_modules/semver-diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-5.0.0.tgz", + "integrity": "sha512-0HbGtOm+S7T6NGQ/pxJSJipJvc4DK3FcRVMRkhsIwJDJ4Jcz5DQC1cPPzB5GhzyHjwttW878HaWQq46CkL3cqg==", + "deprecated": "Deprecated as the semver package now supports this built-in.", "dev": true, "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" + "semver": "^7.3.5" }, "engines": { - "node": ">= 0.4" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "node_modules/semver-regex": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-4.0.5.tgz", + "integrity": "sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==", "dev": true, "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" - }, "engines": { - "node": ">= 0.4" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" + "shebang-regex": "^3.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "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==", + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, "license": "MIT", - "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": ">=8" } }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", @@ -13889,304 +12231,21 @@ "dependencies": { "has-flag": "^3.0.0" }, - "engines": { - "node": ">=4" - } - }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/skin-tone": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/skin-tone/-/skin-tone-2.0.0.tgz", - "integrity": "sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==", - "dev": true, - "license": "MIT", - "dependencies": { - "unicode-emoji-modifier-base": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "license": "MIT", - "dependencies": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/is-descriptor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", - "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "kind-of": "^3.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-util/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/snapdragon/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" - }, - "node_modules/snapdragon/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/socket.io": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.5.1.tgz", - "integrity": "sha512-eaTE4tBKRD6RFoetquMbxgvcpvoDtRyIlkIMI/SMK2bsKvbENTsDeeu4GJ/z9c90yOWxB7b/eC+yKLPbHnH6bA==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "~4.1.0", - "engine.io": "~3.6.0", - "has-binary2": "~1.0.2", - "socket.io-adapter": "~1.1.0", - "socket.io-client": "2.5.0", - "socket.io-parser": "~3.4.0" - } - }, - "node_modules/socket.io-adapter": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz", - "integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==", - "dev": true, - "license": "MIT" - }, - "node_modules/socket.io-client": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.5.0.tgz", - "integrity": "sha512-lOO9clmdgssDykiOmVQQitwBAF3I6mYcQAo7hQ7AM6Ny5X7fp8hIJ3HcQs3Rjz4SoggoxA1OgrQyY8EgTbcPYw==", - "dev": true, - "license": "MIT", - "dependencies": { - "backo2": "1.0.2", - "component-bind": "1.0.0", - "component-emitter": "~1.3.0", - "debug": "~3.1.0", - "engine.io-client": "~3.5.0", - "has-binary2": "~1.0.2", - "indexof": "0.0.1", - "parseqs": "0.0.6", - "parseuri": "0.0.6", - "socket.io-parser": "~3.3.0", - "to-array": "0.1.4" - } - }, - "node_modules/socket.io-client/node_modules/debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/socket.io-client/node_modules/isarray": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", - "integrity": "sha512-c2cu3UxbI+b6kR3fy0nRnAhodsvR9dx7U5+znCOzdj6IfP3upFURTr0Xl5BlQZNKZjEtxrmVyfSdeE3O57smoQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/socket.io-client/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" - }, - "node_modules/socket.io-client/node_modules/socket.io-parser": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.4.tgz", - "integrity": "sha512-z/pFQB3x+EZldRRzORYW1vwVO8m/3ILkswtnpoeU6Ve3cbMWkmHEWDAVJn4QJtchiiFTo5j7UG2QvwxvaA9vow==", - "dev": true, - "license": "MIT", - "dependencies": { - "component-emitter": "~1.3.0", - "debug": "~3.1.0", - "isarray": "2.0.1" - } - }, - "node_modules/socket.io-parser": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.4.3.tgz", - "integrity": "sha512-1rE4dZN3kCI/E5wixd393hmbqa78vVpkKmnEJhLeWoS/C5hbFYAbcSfnWoaVH43u9ToUVtzKjguxEZq+1XZfCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "component-emitter": "1.2.1", - "debug": "~4.1.0", - "isarray": "2.0.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/socket.io-parser/node_modules/component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha512-jPatnhd33viNplKjqXKRkGU345p263OIWzDL2wH3LGIGp5Kojo+uXizHmOADRvhGFFTnJqX3jBAKP6vvmSDKcA==", - "dev": true, - "license": "MIT" - }, - "node_modules/socket.io-parser/node_modules/debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/socket.io-parser/node_modules/isarray": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", - "integrity": "sha512-c2cu3UxbI+b6kR3fy0nRnAhodsvR9dx7U5+znCOzdj6IfP3upFURTr0Xl5BlQZNKZjEtxrmVyfSdeE3O57smoQ==", - "dev": true, - "license": "MIT" + "engines": { + "node": ">=4" + } }, - "node_modules/socket.io/node_modules/debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "node_modules/skin-tone": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/skin-tone/-/skin-tone-2.0.0.tgz", + "integrity": "sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==", "dev": true, "license": "MIT", "dependencies": { - "ms": "^2.1.1" + "unicode-emoji-modifier-base": "^1.0.0" + }, + "engines": { + "node": ">=8" } }, "node_modules/source-map": { @@ -14199,37 +12258,16 @@ "node": ">=0.10.0" } }, - "node_modules/source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, - "license": "MIT", - "dependencies": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/source-map-url": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", - "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", - "deprecated": "See https://github.com/lydell/source-map-url#deprecated", - "dev": true, - "license": "MIT" - }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "deprecated": "Please use @jridgewell/sourcemap-codec instead", - "dev": true, - "license": "MIT" - }, "node_modules/spawn-error-forwarder": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/spawn-error-forwarder/-/spawn-error-forwarder-1.0.0.tgz", @@ -14273,46 +12311,6 @@ "dev": true, "license": "CC0-1.0" }, - "node_modules/split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "license": "MIT", - "dependencies": { - "extend-shallow": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/split-string/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/split-string/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/split2": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/split2/-/split2-1.0.0.tgz", @@ -14330,40 +12328,19 @@ "dev": true, "license": "BSD-3-Clause" }, - "node_modules/static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } + "license": "MIT" }, - "node_modules/stream-browserify": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", - "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "node_modules/std-env": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.0.0.tgz", + "integrity": "sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==", "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "~2.0.1", - "readable-stream": "^2.0.2" - } + "license": "MIT" }, "node_modules/stream-combiner2": { "version": "1.1.1", @@ -14376,95 +12353,6 @@ "readable-stream": "^2.0.2" } }, - "node_modules/stream-http": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.2.0.tgz", - "integrity": "sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==", - "dev": true, - "license": "MIT", - "dependencies": { - "builtin-status-codes": "^3.0.0", - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "xtend": "^4.0.2" - } - }, - "node_modules/stream-http/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/stream-splicer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.1.tgz", - "integrity": "sha512-Xizh4/NPuYSyAXyT7g8IvdJ9HJpxIGL9PjyhtywCZvvP0OPIdqyrr4dMikeuvY8xahpdKEBlBTySe583totajg==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.2" - } - }, - "node_modules/streamroller": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz", - "integrity": "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==", - "dev": true, - "license": "MIT", - "dependencies": { - "date-format": "^4.0.14", - "debug": "^4.3.4", - "fs-extra": "^8.1.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/streamroller/node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/streamroller/node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "license": "MIT", - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/streamroller/node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -14475,6 +12363,16 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.19" + } + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -14546,16 +12444,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/subarg": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", - "integrity": "sha512-RIrIdRY0X1xojthNcVtgT9sjpOGagEUKpZdgBUi054OEPFo282yg+zE+t1Rj3+RqKq2xStL7uUHhY+AjbC4BXg==", - "dev": true, - "license": "MIT", - "dependencies": { - "minimist": "^1.1.0" - } - }, "node_modules/super-regex": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/super-regex/-/super-regex-1.1.0.tgz", @@ -14617,57 +12505,29 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/syntax-error": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz", - "integrity": "sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==", + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true, - "license": "MIT", - "dependencies": { - "acorn-node": "^1.2.0" - } + "license": "MIT" }, - "node_modules/table": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", - "integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==", + "node_modules/synckit": { + "version": "0.11.12", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz", + "integrity": "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", "dependencies": { - "ajv": "^8.0.1", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" + "@pkgr/core": "^0.2.9" }, "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/table/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" + "node": "^14.18.0 || >=16.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "url": "https://opencollective.com/synckit" } }, - "node_modules/table/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, "node_modules/tagged-tag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/tagged-tag/-/tagged-tag-1.0.0.tgz", @@ -14736,13 +12596,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true, - "license": "MIT" - }, "node_modules/thenify": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", @@ -14766,13 +12619,6 @@ "node": ">=0.8" } }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true, - "license": "MIT" - }, "node_modules/through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", @@ -14800,16 +12646,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/timers-browserify": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz", - "integrity": "sha512-PIxwAupJZiYU4JmVZYwXp9FKsHMXb5h0ZEFyuXTAn8WLHOlcij+FEcbrvDsom1o5dr1YggEtFbECvGCW2sT53Q==", + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", "dev": true, - "dependencies": { - "process": "~0.11.0" - }, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.4.tgz", + "integrity": "sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=0.6.0" + "node": ">=18" } }, "node_modules/tinyglobby": { @@ -14829,186 +12680,83 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "rimraf": "^3.0.0" - }, - "engines": { - "node": ">=8.17.0" - } - }, - "node_modules/to-array": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", - "integrity": "sha512-LhVdShQD/4Mk4zXNroIQZJC+Ap3zgLcDuwEdcmLv9CCO73NWockQDwyUnW/m8VX/EElfL6FcYx7EeutN4HJA6A==", - "dev": true - }, - "node_modules/to-buffer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz", - "integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==", - "dev": true, - "license": "MIT", - "dependencies": { - "isarray": "^2.0.5", - "safe-buffer": "^5.2.1", - "typed-array-buffer": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/to-buffer/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true, - "license": "MIT" - }, - "node_modules/to-buffer/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==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", - "dev": true, - "license": "MIT", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-object-path/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, + "node_modules/tinyrainbow": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", + "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=8.0" + "node": ">=14.0.0" } }, - "node_modules/to-regex/node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "node_modules/tldts": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.27.tgz", + "integrity": "sha512-I4FZcVFcqCRuT0ph6dCDpPuO4Xgzvh+spkcTr1gK7peIvxWauoloVO0vuy1FQnijT63ss6AsHB6+OIM4aXHbPg==", "dev": true, "license": "MIT", "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" + "tldts-core": "^7.0.27" }, - "engines": { - "node": ">=0.10.0" + "bin": { + "tldts": "bin/cli.js" } }, - "node_modules/to-regex/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "node_modules/tldts-core": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.27.tgz", + "integrity": "sha512-YQ7uPjgWUibIK6DW5lrKujGwUKhLevU4hcGbP5O6TcIUb+oTjJYJVWPS4nZsIHrEEEG6myk/oqAJUEQmpZrHsg==", + "dev": true, + "license": "MIT" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "license": "MIT", "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "is-number": "^7.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8.0" } }, - "node_modules/to-regex/node_modules/is-descriptor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", - "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "node_modules/tough-cookie": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.1.tgz", + "integrity": "sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" + "tldts": "^7.0.5" }, "engines": { - "node": ">= 0.4" + "node": ">=16" } }, - "node_modules/to-regex/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "node_modules/tr46": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-6.0.0.tgz", + "integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==", "dev": true, "license": "MIT", "dependencies": { - "is-plain-object": "^2.0.4" + "punycode": "^2.3.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=20" } }, - "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==", + "node_modules/tr46/node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.6" + "node": ">=6" } }, "node_modules/traverse": { @@ -15024,12 +12772,18 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/tty-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", - "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==", + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } }, "node_modules/tunnel": { "version": "0.0.6", @@ -15054,74 +12808,18 @@ "node": ">= 0.8.0" } }, - "node_modules/type-detect": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", - "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typed-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", - "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.14" + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" }, "engines": { - "node": ">= 0.4" - } - }, - "node_modules/typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/ua-parser-js": { - "version": "0.7.22", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.22.tgz", - "integrity": "sha512-YUxzMjJ5T71w6a8WWVcMGM6YWOTX27rCoIQgLXiWaxqXSx9D7DNjiGWn1aJIRSQ5qr0xuhra77bSIh6voR/46Q==", - "deprecated": "You are using an outdated version of ua-parser-js. Please update to ua-parser-js v0.7.33 / v1.0.33 / v2.0.0 (or later) to avoid ReDoS vulnerability [CVE-2022-25927](https://github.com/advisories/GHSA-fhg7-m89q-25r3)", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" + "node": ">=14.17" } }, "node_modules/uglify-js": { @@ -15138,33 +12836,6 @@ "node": ">=0.8.0" } }, - "node_modules/umd": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.3.tgz", - "integrity": "sha512-4IcGSufhFshvLNcMCV80UnQVlZ5pMOC8mvNPForqwA4+lzYQuetTESLDQkeLmihq8bRcnpbQa48Wb8Lh16/xow==", - "dev": true, - "license": "MIT", - "bin": { - "umd": "bin/cli.js" - } - }, - "node_modules/undeclared-identifiers": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/undeclared-identifiers/-/undeclared-identifiers-1.1.3.tgz", - "integrity": "sha512-pJOW4nxjlmfwKApE4zvxLScM/njmwj/DiUBv7EabwE4O8kRUy+HIwxQtZLBPll/jx1LJyBcqNfB3/cpv9EZwOw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "acorn-node": "^1.3.0", - "dash-ast": "^1.0.0", - "get-assigned-identifiers": "^1.2.0", - "simple-concat": "^1.0.0", - "xtend": "^4.0.1" - }, - "bin": { - "undeclared-identifiers": "bin.js" - } - }, "node_modules/undici": { "version": "6.23.0", "resolved": "https://registry.npmjs.org/undici/-/undici-6.23.0.tgz", @@ -15176,9 +12847,9 @@ } }, "node_modules/undici-types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", - "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "dev": true, "license": "MIT" }, @@ -15205,22 +12876,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dev": true, - "license": "MIT", - "dependencies": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/unique-string": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", @@ -15254,79 +12909,6 @@ "node": ">= 10.0.0" } }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", - "dev": true, - "license": "MIT", - "dependencies": { - "isarray": "1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4", - "yarn": "*" - } - }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -15347,28 +12929,6 @@ "node": ">=6" } }, - "node_modules/urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==", - "deprecated": "Please see https://github.com/lydell/urix#deprecated", - "dev": true, - "license": "MIT" - }, - "node_modules/url": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.4.tgz", - "integrity": "sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "punycode": "^1.4.1", - "qs": "^6.12.3" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/url-join": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/url-join/-/url-join-5.0.0.tgz", @@ -15379,26 +12939,6 @@ "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, - "node_modules/use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/util": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", - "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "2.0.3" - } - }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -15406,30 +12946,6 @@ "dev": true, "license": "MIT" }, - "node_modules/util/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "dev": true, - "license": "ISC" - }, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/v8-compile-cache": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz", - "integrity": "sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==", - "dev": true, - "license": "MIT" - }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -15441,346 +12957,315 @@ "spdx-expression-parse": "^3.0.0" } }, - "node_modules/vm-browserify": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", - "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/void-elements": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", - "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", + "node_modules/validator": { + "version": "13.15.26", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.26.tgz", + "integrity": "sha512-spH26xU080ydGggxRyR1Yhcbgx+j3y5jbNXk/8L+iRvdIEQ4uTRH2Sgf2dokud6Q4oAtsbNvJ1Ft+9xmm6IZcA==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 0.10" } }, - "node_modules/watchify": { - "version": "3.11.1", - "resolved": "https://registry.npmjs.org/watchify/-/watchify-3.11.1.tgz", - "integrity": "sha512-WwnUClyFNRMB2NIiHgJU9RQPQNqVeFk7OmZaWf5dC5EnNa0Mgr7imBydbaJ7tGTuPM2hz1Cb4uiBvK9NVxMfog==", + "node_modules/vite": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", + "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", "dev": true, "license": "MIT", "dependencies": { - "anymatch": "^2.0.0", - "browserify": "^16.1.0", - "chokidar": "^2.1.1", - "defined": "^1.0.0", - "outpipe": "^1.1.0", - "through2": "^2.0.0", - "xtend": "^4.0.0" + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" }, "bin": { - "watchify": "bin/cmd.js" - } - }, - "node_modules/watchify/node_modules/anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "license": "ISC", - "dependencies": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - } - }, - "node_modules/watchify/node_modules/anymatch/node_modules/normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "remove-trailing-separator": "^1.0.1" + "vite": "bin/vite.js" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchify/node_modules/binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchify/node_modules/braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "license": "MIT", - "dependencies": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchify/node_modules/chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "dev": true, - "license": "MIT", - "dependencies": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" }, "optionalDependencies": { - "fsevents": "^1.2.7" + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } } }, - "node_modules/watchify/node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "node_modules/vite-plugin-dts": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/vite-plugin-dts/-/vite-plugin-dts-3.8.3.tgz", + "integrity": "sha512-yRHiRosQw7MXdOhmcrVI+kRiB8YEShbSxnADNteK4eZGdEoyOkMHihvO5XOAVlOq8ng9sIqu8vVefDK1zcj3qw==", "dev": true, "license": "MIT", "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" + "@microsoft/api-extractor": "7.43.0", + "@rollup/pluginutils": "^5.1.0", + "@vue/language-core": "^1.8.27", + "debug": "^4.3.4", + "kolorist": "^1.8.0", + "magic-string": "^0.30.8", + "vue-tsc": "^1.8.27" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchify/node_modules/fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" + "node": "^14.18.0 || >=16.0.0" }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchify/node_modules/fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "deprecated": "Upgrade to fsevents v2 to mitigate potential security issues", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "dependencies": { - "bindings": "^1.5.0", - "nan": "^2.12.1" + "peerDependencies": { + "typescript": "*", + "vite": "*" }, - "engines": { - "node": ">= 4.0" - } - }, - "node_modules/watchify/node_modules/glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" + "peerDependenciesMeta": { + "vite": { + "optional": true + } } }, - "node_modules/watchify/node_modules/glob-parent/node_modules/is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", + "node_modules/vite-plugin-dts/node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", "dev": true, "license": "MIT", "dependencies": { - "is-extglob": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" + "@jridgewell/sourcemap-codec": "^1.5.5" } }, - "node_modules/watchify/node_modules/is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "binary-extensions": "^1.0.0" + "node_modules/vitest": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.2.tgz", + "integrity": "sha512-xjR1dMTVHlFLh98JE3i/f/WePqJsah4A0FK9cc8Ehp9Udk0AZk6ccpIZhh1qJ/yxVWRZ+Q54ocnD8TXmkhspGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.1.2", + "@vitest/mocker": "4.1.2", + "@vitest/pretty-format": "4.1.2", + "@vitest/runner": "4.1.2", + "@vitest/snapshot": "4.1.2", + "@vitest/spy": "4.1.2", + "@vitest/utils": "4.1.2", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^4.0.0-rc.1", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" }, "engines": { - "node": ">=0.10.0" + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.1.2", + "@vitest/browser-preview": "4.1.2", + "@vitest/browser-webdriverio": "4.1.2", + "@vitest/ui": "4.1.2", + "happy-dom": "*", + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "vite": { + "optional": false + } } }, - "node_modules/watchify/node_modules/is-descriptor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", - "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "node_modules/vitest/node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", "dev": true, "license": "MIT", "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" + "@jridgewell/sourcemap-codec": "^1.5.5" } }, - "node_modules/watchify/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "node_modules/vue-template-compiler": { + "version": "2.7.16", + "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz", + "integrity": "sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==", "dev": true, "license": "MIT", "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" + "de-indent": "^1.0.2", + "he": "^1.2.0" } }, - "node_modules/watchify/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "node_modules/vue-template-compiler/node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true, "license": "MIT", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" + "bin": { + "he": "bin/he" } }, - "node_modules/watchify/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "node_modules/vue-tsc": { + "version": "1.8.27", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-1.8.27.tgz", + "integrity": "sha512-WesKCAZCRAbmmhuGl3+VrdWItEvfoFIPXOvUJkjULi+x+6G/Dy69yO3TBRJDr9eUlmsNAwVmxsNZxvHKzbkKdg==", "dev": true, "license": "MIT", "dependencies": { - "is-buffer": "^1.1.5" + "@volar/typescript": "~1.11.1", + "@vue/language-core": "1.8.27", + "semver": "^7.5.4" }, - "engines": { - "node": ">=0.10.0" + "bin": { + "vue-tsc": "bin/vue-tsc.js" + }, + "peerDependencies": { + "typescript": "*" } }, - "node_modules/watchify/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", "dev": true, "license": "MIT", "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" + "xml-name-validator": "^5.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=18" } }, - "node_modules/watchify/node_modules/micromatch/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "node_modules/web-worker": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.2.0.tgz", + "integrity": "sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA==", "dev": true, - "license": "MIT", - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } + "license": "Apache-2.0" }, - "node_modules/watchify/node_modules/micromatch/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "node_modules/webidl-conversions": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", + "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "engines": { - "node": ">=0.10.0" + "node": ">=20" } }, - "node_modules/watchify/node_modules/readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "node_modules/whatwg-mimetype": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", + "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==", "dev": true, "license": "MIT", - "dependencies": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - }, "engines": { - "node": ">=0.10" + "node": ">=20" } }, - "node_modules/watchify/node_modules/to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", + "node_modules/whatwg-url": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-16.0.1.tgz", + "integrity": "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==", "dev": true, "license": "MIT", "dependencies": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" + "@exodus/bytes": "^1.11.0", + "tr46": "^6.0.0", + "webidl-conversions": "^8.0.1" }, "engines": { - "node": ">=0.10.0" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, - "node_modules/web-worker": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.2.0.tgz", - "integrity": "sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA==", - "dev": true, - "license": "Apache-2.0" - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -15797,33 +13282,21 @@ "node": ">= 8" } }, - "node_modules/which-module": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", - "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/which-typed-array": { - "version": "1.1.20", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz", - "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==", + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", "dev": true, "license": "MIT", "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "for-each": "^0.3.5", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2" + "siginfo": "^2.0.0", + "stackback": "0.0.2" }, - "engines": { - "node": ">= 0.4" + "bin": { + "why-is-node-running": "cli.js" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=8" } }, "node_modules/word-wrap": { @@ -15843,58 +13316,22 @@ "dev": true, "license": "MIT" }, - "node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/ws": { - "version": "7.5.10", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", - "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } + "node": ">=18" } }, - "node_modules/xmlhttprequest-ssl": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.6.3.tgz", - "integrity": "sha512-3XfeQE/wNkvrIktn2Kf0869fC0BN6UpydVasGIeSm2B1Llihf7/0UfZM+eCkOw3P7bP4+qPgqhm7ZoxuJtFU0Q==", + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "dev": true, - "engines": { - "node": ">=0.4.0" - } + "license": "MIT" }, "node_modules/xtend": { "version": "4.0.2", @@ -15906,144 +13343,69 @@ "node": ">=0.4" } }, - "node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true, "license": "ISC" }, - "node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/yargs/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" + "node": ">=10" }, - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/yargs/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "node_modules/yoctocolors": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", + "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", "dev": true, "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, "engines": { - "node": ">=6" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/yargs/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "node_modules/z-schema": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/z-schema/-/z-schema-5.0.5.tgz", + "integrity": "sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==", "dev": true, "license": "MIT", "dependencies": { - "p-limit": "^2.2.0" + "lodash.get": "^4.4.2", + "lodash.isequal": "^4.5.0", + "validator": "^13.7.0" + }, + "bin": { + "z-schema": "bin/z-schema" }, "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/yargs/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" + "node": ">=8.0.0" + }, + "optionalDependencies": { + "commander": "^9.4.1" } }, - "node_modules/yeast": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", - "integrity": "sha512-8HFIh676uyGYP6wP13R/j6OJ/1HwJ46snpvzE7aHAN3Ryqh2yX6Xox2B4CUmTwwOIzlG3Bs7ocsP5dZH/R1Qbg==", - "dev": true, - "license": "MIT" - }, - "node_modules/yoctocolors": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", - "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", + "node_modules/z-schema/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", "dev": true, "license": "MIT", + "optional": true, "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^12.20.0 || >=14" } } } diff --git a/package.json b/package.json index 5dc7a0a..5119309 100644 --- a/package.json +++ b/package.json @@ -3,20 +3,30 @@ "version": "1.22.0", "description": "mParticle integration kit for Rokt", "main": "dist/Rokt-Kit.common.js", + "module": "dist/Rokt-Kit.esm.js", + "types": "dist/Rokt-Kit.d.ts", + "exports": { + ".": { + "types": "./dist/Rokt-Kit.d.ts", + "import": "./dist/Rokt-Kit.esm.js", + "require": "./dist/Rokt-Kit.common.js" + } + }, "files": [ "dist/Rokt-Kit.common.js", - "dist/Rokt-Kit.iife.js" + "dist/Rokt-Kit.esm.js", + "dist/Rokt-Kit.iife.js", + "dist/Rokt-Kit.d.ts" ], "repository": "https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt", "scripts": { - "build": "rollup --config rollup.config.js", - "build:test": "rollup --config rollup.test.config.js", - "lint": "eslint src/ test/src/", - "lint:fix": "eslint src/ test/src/ --fix", - "watch": "rollup --config rollup.config.js -w", - "watch:tests": "rollup --config rollup.test.config.js -w", - "test": "npm run build && npm run build:test && karma start test/karma.config.js", - "test:debug": "npm run build && npm run build:test && DEBUG=true karma start test/karma.config.js" + "build": "vite build", + "build:watch": "vite build --watch", + "lint": "eslint \"src/**/*.ts\" \"test/**/*.ts\"", + "lint:fix": "eslint \"src/**/*.ts\" \"test/**/*.ts\" --fix", + "test": "vitest run", + "test:watch": "vitest", + "test:coverage": "vitest run --coverage" }, "publishConfig": { "access": "public", @@ -24,30 +34,26 @@ "registry": "https://registry.npmjs.org" }, "devDependencies": { - "@rollup/plugin-json": "^6.1.0", + "@eslint/js": "^9.23.0", + "@eslint/eslintrc": "^3.3.1", "@semantic-release/changelog": "^6.0.3", "@semantic-release/exec": "^6.0.3", "@semantic-release/git": "^10.0.1", "@semantic-release/npm": "^13.1.2", + "@typescript-eslint/eslint-plugin": "^8.28.0", + "@typescript-eslint/parser": "^8.28.0", + "@types/node": "^20.11.5", + "@vitest/coverage-v8": "^4.0.0", + "eslint": "^9.23.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-prettier": "^5.0.0", + "jsdom": "latest", + "prettier": "^3.0.0", "semantic-release": "^24.2.0", - "mocha": "^5.2.0", - "chai": "^4.2.0", - "eslint": "^7.25.0", - "eslint-config-prettier": "8.3.0", - "eslint-plugin-prettier": "3.4.1", - "karma": "^5.1.0", - "karma-chai": "^0.1.0", - "karma-chrome-launcher": "^3.1.0", - "karma-firefox-launcher": "^2.1.0", - "karma-mocha": "^2.0.1", - "prettier": "^2.4.1", - "rollup": "^1.15.6", - "rollup-plugin-commonjs": "^10.0.0", - "rollup-plugin-node-resolve": "^5.0.3", - "rollup-plugin-replace": "^2.2.0", - "shelljs": "0.8.3", - "should": "13.2.3", - "watchify": "^3.11.0" + "typescript": "^5.5.4", + "vite": "^6.0.0", + "vite-plugin-dts": "~3.8.1", + "vitest": "^4.0.0" }, "dependencies": { "@mparticle/web-sdk": "^2.56.0" diff --git a/rollup.config.js b/rollup.config.js deleted file mode 100644 index d427e96..0000000 --- a/rollup.config.js +++ /dev/null @@ -1,46 +0,0 @@ -import resolve from 'rollup-plugin-node-resolve'; -import commonjs from 'rollup-plugin-commonjs'; -import replace from 'rollup-plugin-replace'; -import json from '@rollup/plugin-json'; -import pkg from './package.json'; - -const kitName = 'Rokt'; - -const outputs = { - name: `${kitName}Kit`, - exports: 'named', - strict: true, -}; - -const plugins = [ - resolve({ - browser: true - }), - commonjs(), - json(), - replace({ - 'process.env.PACKAGE_VERSION': JSON.stringify(pkg.version), - preventAssignment: true - }) -]; - -export default [ - { - input: `src/${kitName}-Kit.js`, - output: { - ...outputs, - format: 'iife', - file: `dist/${kitName}-Kit.iife.js`, - }, - plugins, - }, - { - input: `src/${kitName}-Kit.js`, - output: { - ...outputs, - format: 'cjs', - file: `dist/${kitName}-Kit.common.js`, - }, - plugins, - }, -]; \ No newline at end of file diff --git a/rollup.test.config.js b/rollup.test.config.js deleted file mode 100644 index cd86478..0000000 --- a/rollup.test.config.js +++ /dev/null @@ -1,15 +0,0 @@ -const { ENVIRONMENT } = process.env; - -import resolve from 'rollup-plugin-node-resolve'; -import commonjs from 'rollup-plugin-commonjs'; -import json from '@rollup/plugin-json'; - -export default { - input: 'test/src/tests.js', - output: { - file: 'test/test-bundle.js', - format: 'iife', - name: 'mParticleTests', - }, - plugins: [resolve(), commonjs(), json()], -}; diff --git a/src/Rokt-Kit.js b/src/Rokt-Kit.js deleted file mode 100644 index e594f72..0000000 --- a/src/Rokt-Kit.js +++ /dev/null @@ -1,1264 +0,0 @@ -/* eslint-disable no-undef */ -// Copyright 2025 mParticle, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -var name = 'Rokt'; -var moduleId = 181; -var EVENT_NAME_SELECT_PLACEMENTS = 'selectPlacements'; - -var constructor = function () { - var self = this; - var PerformanceMarks = { - RoktScriptAppended: 'mp:RoktScriptAppended', - }; - - var EMAIL_SHA256_KEY = 'emailsha256'; - - // Dynamic identity type for Rokt's emailsha256 identity value which MP doesn't natively support - will be set during initialization - var mappedEmailSha256Key; - - self.name = name; - self.moduleId = moduleId; - self.isInitialized = false; - - self.launcher = null; - self.filters = {}; - self.userAttributes = {}; - self.testHelpers = null; - self.placementEventMappingLookup = {}; - self.placementEventAttributeMappingLookup = {}; - self.eventQueue = []; - self.eventStreamQueue = []; - self.integrationName = null; - - function getEventAttributeValue(event, eventAttributeKey) { - var attributes = event && event.EventAttributes; - if (!attributes) { - return null; - } - - if (typeof attributes[eventAttributeKey] === 'undefined') { - return null; - } - - return attributes[eventAttributeKey]; - } - - function doesEventAttributeConditionMatch(condition, actualValue) { - if (!condition || !isString(condition.operator)) { - return false; - } - - var operator = condition.operator.toLowerCase(); - var expectedValue = condition.attributeValue; - - if (operator === 'exists') { - return actualValue !== null; - } - - if (actualValue == null) { - return false; - } - - if (operator === 'equals') { - return String(actualValue) === String(expectedValue); - } - - if (operator === 'contains') { - return String(actualValue).indexOf(String(expectedValue)) !== -1; - } - - return false; - } - - function doesEventMatchRule(event, rule) { - if (!rule || !isString(rule.eventAttributeKey)) { - return false; - } - - var conditions = rule.conditions; - if (!Array.isArray(conditions)) { - return false; - } - - var actualValue = getEventAttributeValue(event, rule.eventAttributeKey); - - if (conditions.length === 0) { - return actualValue !== null; - } - for (var i = 0; i < conditions.length; i++) { - if (!doesEventAttributeConditionMatch(conditions[i], actualValue)) { - return false; - } - } - - return true; - } - - function generateMappedEventAttributeLookup( - placementEventAttributeMapping - ) { - var mappedAttributeKeys = {}; - if (!Array.isArray(placementEventAttributeMapping)) { - return mappedAttributeKeys; - } - for (var i = 0; i < placementEventAttributeMapping.length; i++) { - var mapping = placementEventAttributeMapping[i]; - if ( - !mapping || - !isString(mapping.value) || - !isString(mapping.map) - ) { - continue; - } - - var mappedAttributeKey = mapping.value; - var eventAttributeKey = mapping.map; - - if (!mappedAttributeKeys[mappedAttributeKey]) { - mappedAttributeKeys[mappedAttributeKey] = []; - } - - mappedAttributeKeys[mappedAttributeKey].push({ - eventAttributeKey: eventAttributeKey, - conditions: Array.isArray(mapping.conditions) - ? mapping.conditions - : [], - }); - } - return mappedAttributeKeys; - } - - function applyPlacementEventAttributeMapping(event) { - var mappedAttributeKeys = Object.keys( - self.placementEventAttributeMappingLookup - ); - for (var i = 0; i < mappedAttributeKeys.length; i++) { - var mappedAttributeKey = mappedAttributeKeys[i]; - var rulesForMappedAttributeKey = - self.placementEventAttributeMappingLookup[mappedAttributeKey]; - if (isEmpty(rulesForMappedAttributeKey)) { - continue; - } - - // Require ALL rules for the same key to match (AND). - var allMatch = true; - for (var j = 0; j < rulesForMappedAttributeKey.length; j++) { - if (!doesEventMatchRule(event, rulesForMappedAttributeKey[j])) { - allMatch = false; - break; - } - } - if (!allMatch) { - continue; - } - - window.mParticle.Rokt.setLocalSessionAttribute( - mappedAttributeKey, - true - ); - } - } - - /** - * Generates the Rokt launcher script URL with optional domain override and extensions - * @param {string} domain - The CNAME domain to use for overriding the launcher url - * @param {Array} extensions - List of extension query parameters to append - * @returns {string} The complete launcher script URL - */ - function generateLauncherScript(_domain, extensions) { - // Override domain if a customer is using a CNAME - // If a customer is using a CNAME, a domain will be passed. If not, we use the default domain. - var domain = typeof _domain !== 'undefined' ? _domain : 'apps.rokt.com'; - var protocol = 'https://'; - var launcherPath = '/wsdk/integrations/launcher.js'; - var baseUrl = [protocol, domain, launcherPath].join(''); - - if (!extensions || extensions.length === 0) { - return baseUrl; - } - return baseUrl + '?extensions=' + extensions.join(','); - } - - /** - * Checks if Rokt launcher is available and ready to attach - * @returns {boolean} True if launcher can be attached - */ - function isLauncherReadyToAttach() { - return window.Rokt && typeof window.Rokt.createLauncher === 'function'; - } - - /** - * Passes attributes to the Rokt Web SDK for client-side hashing - * @see https://docs.rokt.com/developers/integration-guides/web/library/integration-launcher#hash-attributes - * @param {Object} attributes - The attributes to be hashed - * @returns {Promise} A Promise resolving to the - * hashed attributes from the launcher, or `null` if the kit is not initialized - */ - function hashAttributes(attributes) { - if (!isKitReady()) { - console.error('Rokt Kit: Not initialized'); - return null; - } - return self.launcher.hashAttributes(attributes); - } - - function initForwarder( - settings, - _service, - testMode, - _trackerId, - filteredUserAttributes - ) { - var accountId = settings.accountId; - var roktExtensions = extractRoktExtensions(settings.roktExtensions); - self.userAttributes = filteredUserAttributes || {}; - self.onboardingExpProvider = settings.onboardingExpProvider; - - var placementEventMapping = parseSettingsString( - settings.placementEventMapping - ); - self.placementEventMappingLookup = generateMappedEventLookup( - placementEventMapping - ); - - var placementEventAttributeMapping = parseSettingsString( - settings.placementEventAttributeMapping - ); - self.placementEventAttributeMappingLookup = - generateMappedEventAttributeLookup(placementEventAttributeMapping); - - // Set dynamic OTHER_IDENTITY based on server settings - // Convert to lowercase since server sends TitleCase (e.g., 'Other' -> 'other') - if (settings.hashedEmailUserIdentityType) { - mappedEmailSha256Key = - settings.hashedEmailUserIdentityType.toLowerCase(); - } - - var domain = window.mParticle.Rokt.domain; - var launcherOptions = mergeObjects( - {}, - window.mParticle.Rokt.launcherOptions || {} - ); - self.integrationName = generateIntegrationName( - launcherOptions.integrationName - ); - launcherOptions.integrationName = self.integrationName; - - self.domain = domain; - - // Register reporting services with the core SDK - var reportingConfig = { - loggingUrl: settings.loggingUrl, - errorUrl: settings.errorUrl, - isLoggingEnabled: - settings.isLoggingEnabled === 'true' || - settings.isLoggingEnabled === true, - }; - var errorReportingService = new ErrorReportingService( - reportingConfig, - self.integrationName, - window.__rokt_li_guid__, - settings.accountId - ); - var loggingService = new LoggingService( - reportingConfig, - errorReportingService, - self.integrationName, - window.__rokt_li_guid__, - settings.accountId - ); - - self.errorReportingService = errorReportingService; - self.loggingService = loggingService; - - if ( - window.mParticle && - window.mParticle._registerErrorReportingService - ) { - window.mParticle._registerErrorReportingService( - errorReportingService - ); - } - if (window.mParticle && window.mParticle._registerLoggingService) { - window.mParticle._registerLoggingService(loggingService); - } - - if (testMode) { - self.testHelpers = { - generateLauncherScript: generateLauncherScript, - extractRoktExtensions: extractRoktExtensions, - hashEventMessage: hashEventMessage, - parseSettingsString: parseSettingsString, - generateMappedEventLookup: generateMappedEventLookup, - generateMappedEventAttributeLookup: - generateMappedEventAttributeLookup, - sendAdBlockMeasurementSignals: sendAdBlockMeasurementSignals, - createAutoRemovedIframe: createAutoRemovedIframe, - djb2: djb2, - setAllowedOriginHashes: function (hashes) { - _allowedOriginHashes = hashes; - }, - ReportingTransport: ReportingTransport, - ErrorReportingService: ErrorReportingService, - LoggingService: LoggingService, - RateLimiter: RateLimiter, - ErrorCodes: ErrorCodes, - WSDKErrorSeverity: WSDKErrorSeverity, - }; - attachLauncher(accountId, launcherOptions); - return; - } - - if (isLauncherReadyToAttach()) { - attachLauncher(accountId, launcherOptions); - } else { - var target = document.head || document.body; - var script = document.createElement('script'); - script.type = 'text/javascript'; - script.src = generateLauncherScript(domain, roktExtensions); - script.async = true; - script.crossOrigin = 'anonymous'; - script.fetchPriority = 'high'; - script.id = 'rokt-launcher'; - - script.onload = function () { - if (isLauncherReadyToAttach()) { - attachLauncher(accountId, launcherOptions); - } else { - console.error( - 'Rokt object is not available after script load.' - ); - } - }; - - script.onerror = function (error) { - console.error('Error loading Rokt launcher script:', error); - }; - - target.appendChild(script); - captureTiming(PerformanceMarks.RoktScriptAppended); - } - } - /** - * Returns the user identities from the filtered user, if any - * @param {Object} filteredUser - The filtered user object containing identities - * @returns {Object} The user identities from the filtered user - */ - function returnUserIdentities(filteredUser) { - if (!filteredUser || !filteredUser.getUserIdentities) { - return {}; - } - - var userIdentities = filteredUser.getUserIdentities().userIdentities; - - return replaceOtherIdentityWithEmailsha256(userIdentities); - } - - function returnLocalSessionAttributes() { - if ( - !window.mParticle.Rokt || - typeof window.mParticle.Rokt.getLocalSessionAttributes !== - 'function' - ) { - return {}; - } - if ( - isEmpty(self.placementEventMappingLookup) && - isEmpty(self.placementEventAttributeMappingLookup) - ) { - return {}; - } - return window.mParticle.Rokt.getLocalSessionAttributes(); - } - - function replaceOtherIdentityWithEmailsha256(userIdentities) { - var newUserIdentities = mergeObjects({}, userIdentities || {}); - if (userIdentities[mappedEmailSha256Key]) { - newUserIdentities[EMAIL_SHA256_KEY] = - userIdentities[mappedEmailSha256Key]; - } - delete newUserIdentities[mappedEmailSha256Key]; - - return newUserIdentities; - } - - /** - * Selects placements for Rokt Web SDK with merged attributes, filters, and experimentation options - * @see https://docs.rokt.com/developers/integration-guides/web/library/select-placements-options/ - * @param {Object} options - The options object for selecting placements containing: - * - identifier {string}: The placement identifier - * - attributes {Object}: Optional attributes to merge with existing attributes - * @returns {Promise} A Promise resolving to the Rokt launcher's selectPlacements method with processed attributes - */ - function selectPlacements(options) { - var attributes = (options && options.attributes) || {}; - var placementAttributes = mergeObjects(self.userAttributes, attributes); - - var filters = self.filters || {}; - var userAttributeFilters = filters.userAttributeFilters || []; - var filteredUser = filters.filteredUser || {}; - var mpid = - filteredUser && - filteredUser.getMPID && - typeof filteredUser.getMPID === 'function' - ? filteredUser.getMPID() - : null; - - var filteredAttributes; - - if (!filters) { - console.warn( - 'Rokt Kit: No filters available, using user attributes' - ); - - filteredAttributes = placementAttributes; - } else if (filters.filterUserAttributes) { - filteredAttributes = filters.filterUserAttributes( - placementAttributes, - userAttributeFilters - ); - } - - self.userAttributes = filteredAttributes; - - var optimizelyAttributes = - self.onboardingExpProvider === 'Optimizely' - ? fetchOptimizely() - : {}; - - var filteredUserIdentities = returnUserIdentities(filteredUser); - - var localSessionAttributes = returnLocalSessionAttributes(); - - var selectPlacementsAttributes = mergeObjects( - filteredUserIdentities, - filteredAttributes, - optimizelyAttributes, - localSessionAttributes, - { - mpid: mpid, - } - ); - - var selectPlacementsOptions = mergeObjects(options, { - attributes: selectPlacementsAttributes, - }); - - var selection = self.launcher.selectPlacements(selectPlacementsOptions); - - // After selection resolves, sync the Rokt session ID back to mParticle - // as an integration attribute so server-side integrations can link events. - // We log the custom event AFTER setting the attribute because - // setIntegrationAttribute alone doesn't fire a network request — - // if the user closes the page before another event fires, the server - // would never receive the session ID. - if (selection && typeof selection.then === 'function') { - selection - .then(function (sel) { - if (sel && sel.context && sel.context.sessionId) { - sel.context.sessionId - .then(function (sessionId) { - _setRoktSessionId(sessionId); - logSelectPlacementsEvent( - selectPlacementsAttributes - ); - }) - .catch(function () { - logSelectPlacementsEvent( - selectPlacementsAttributes - ); - }); - } else { - logSelectPlacementsEvent(selectPlacementsAttributes); - } - }) - .catch(function () { - logSelectPlacementsEvent(selectPlacementsAttributes); - }); - } else { - logSelectPlacementsEvent(selectPlacementsAttributes); - } - - return selection; - } - - /** - * Logs a custom event when selectPlacements is called - * This enables visibility and troubleshooting - * @param {Object} attributes - The attributes sent to Rokt - */ - function logSelectPlacementsEvent(attributes) { - if ( - !window.mParticle || - typeof window.mParticle.logEvent !== 'function' - ) { - return; - } - - if (!isObject(attributes)) { - return; - } - - var EVENT_TYPE_OTHER = window.mParticle.EventType.Other; - - window.mParticle.logEvent( - EVENT_NAME_SELECT_PLACEMENTS, - EVENT_TYPE_OTHER, - attributes - ); - } - - /** - * Enables optional Integration Launcher extensions before selecting placements - * @param {string} extensionName - Name of the extension to enable - * @returns {Promise<*>} A Promise resolving to the extension API if available - */ - function use(extensionName) { - if (!isKitReady()) { - console.error('Rokt Kit: Not initialized'); - return Promise.reject(new Error('Rokt Kit: Not initialized')); - } - if (!extensionName || !isString(extensionName)) { - return Promise.reject( - new Error('Rokt Kit: Invalid extension name') - ); - } - return self.launcher.use(extensionName); - } - - /** - * Sets extension data for Rokt Web SDK - * @param {Object} partnerExtensionData - The extension data object containing: - * - [extensionName] {string}: Name of the extension - * - [extensionName].options {Object}: Key-value pairs of options for the extension - * @returns {void} Nothing is returned - */ - function setExtensionData(partnerExtensionData) { - if (!isKitReady()) { - console.error('Rokt Kit: Not initialized'); - return; - } - - window.Rokt.setExtensionData(partnerExtensionData); - } - - function processEventQueue() { - self.eventQueue.forEach(function (event) { - processEvent(event); - }); - self.eventQueue = []; - } - - function processEvent(event) { - if (!isKitReady()) { - self.eventQueue.push(event); - return; - } - - _sendEventStream(event); - - if ( - typeof window.mParticle.Rokt.setLocalSessionAttribute !== 'function' - ) { - return; - } - - if (!isEmpty(self.placementEventAttributeMappingLookup)) { - applyPlacementEventAttributeMapping(event); - } - - if (isEmpty(self.placementEventMappingLookup)) { - return; - } - - var hashedEvent = hashEventMessage( - event.EventDataType, - event.EventCategory, - event.EventName - ); - - if (self.placementEventMappingLookup[hashedEvent]) { - var mappedValue = self.placementEventMappingLookup[hashedEvent]; - window.mParticle.Rokt.setLocalSessionAttribute(mappedValue, true); - } - } - - function _enrichEvent(event) { - return mergeObjects({}, event, { - UserAttributes: self.userAttributes, - }); - } - - function _sendEventStream(event) { - if (window.Rokt && typeof window.Rokt.__event_stream__ === 'function') { - if (self.eventStreamQueue.length) { - var queuedEvents = self.eventStreamQueue; - self.eventStreamQueue = []; - for (var i = 0; i < queuedEvents.length; i++) { - window.Rokt.__event_stream__(_enrichEvent(queuedEvents[i])); - } - } - window.Rokt.__event_stream__(_enrichEvent(event)); - } else { - self.eventStreamQueue.push(event); - } - } - - function _setRoktSessionId(sessionId) { - if (!sessionId || typeof sessionId !== 'string') { - return; - } - try { - var mpInstance = window.mParticle.getInstance(); - if ( - mpInstance && - typeof mpInstance.setIntegrationAttribute === 'function' - ) { - mpInstance.setIntegrationAttribute(moduleId, { - roktSessionId: sessionId, - }); - } - } catch (e) { - // Best effort — never let this break the partner page - } - } - - function onUserIdentified(filteredUser) { - self.filters.filteredUser = filteredUser; - self.userAttributes = filteredUser.getAllUserAttributes(); - _sendEventStream(_buildIdentityEvent('identify', filteredUser)); - } - - function _buildIdentityEvent(eventName, filteredUser) { - var mpid = - filteredUser.getMPID && typeof filteredUser.getMPID === 'function' - ? filteredUser.getMPID() - : null; - var sessionId = - window.mParticle && - window.mParticle.sessionManager && - typeof window.mParticle.sessionManager.getSession === 'function' - ? window.mParticle.sessionManager.getSession() - : null; - var userIdentities = - filteredUser.getUserIdentities && - typeof filteredUser.getUserIdentities === 'function' - ? filteredUser.getUserIdentities().userIdentities - : null; - - return { - EventName: eventName, - EventDataType: 14, // MessageType.Profile - Timestamp: Date.now(), - MPID: mpid, - SessionId: sessionId, - UserIdentities: userIdentities, - }; - } - - function onLoginComplete(filteredUser) { - self.userAttributes = filteredUser.getAllUserAttributes(); - _sendEventStream(_buildIdentityEvent('login', filteredUser)); - } - - function onLogoutComplete(filteredUser) { - self.userAttributes = filteredUser.getAllUserAttributes(); - _sendEventStream(_buildIdentityEvent('logout', filteredUser)); - } - - function onModifyComplete(filteredUser) { - self.userAttributes = filteredUser.getAllUserAttributes(); - _sendEventStream(_buildIdentityEvent('modify_user', filteredUser)); - } - - function setUserAttribute(key, value) { - self.userAttributes[key] = value; - _sendEventStream( - _buildIdentityEvent( - 'set_user_attributes', - self.filters.filteredUser || {} - ) - ); - } - - function removeUserAttribute(key) { - delete self.userAttributes[key]; - } - - function attachLauncher(accountId, launcherOptions) { - var mpSessionId = - window.mParticle && - window.mParticle.sessionManager && - typeof window.mParticle.sessionManager.getSession === 'function' - ? window.mParticle.sessionManager.getSession() - : undefined; - - var options = mergeObjects( - { - accountId: accountId, - }, - launcherOptions || {}, - mpSessionId ? { mpSessionId: mpSessionId } : {} - ); - - if (isPartnerInLocalLauncherTestGroup()) { - var localLauncher = window.Rokt.createLocalLauncher(options); - initRoktLauncher(localLauncher); - } else { - window.Rokt.createLauncher(options) - .then(initRoktLauncher) - .catch(function (err) { - console.error('Error creating Rokt launcher:', err); - }); - } - } - - function initRoktLauncher(launcher) { - // Assign the launcher to a global variable for later access - window.Rokt.currentLauncher = launcher; - // Locally cache the launcher and filters - self.launcher = launcher; - - var roktFilters = window.mParticle.Rokt.filters; - - if (!roktFilters) { - console.warn('Rokt Kit: No filters have been set.'); - } else { - self.filters = roktFilters; - if (!roktFilters.filteredUser) { - console.warn('Rokt Kit: No filtered user has been set.'); - } - } - - // Kit must be initialized before attaching to the Rokt manager - self.isInitialized = true; - - sendAdBlockMeasurementSignals(self.domain, self.integrationName); - - // Attaches the kit to the Rokt manager - window.mParticle.Rokt.attachKit(self); - processEventQueue(); - } - - // mParticle Kit Callback Methods - function fetchOptimizely() { - var forwarders = window.mParticle - ._getActiveForwarders() - .filter(function (forwarder) { - return forwarder.name === 'Optimizely'; - }); - - try { - if (forwarders.length > 0 && window.optimizely) { - // Get the state object - var optimizelyState = window.optimizely.get('state'); - if ( - !optimizelyState || - !optimizelyState.getActiveExperimentIds - ) { - return {}; - } - // Get active experiment IDs - var activeExperimentIds = - optimizelyState.getActiveExperimentIds(); - // Get variations for each active experiment - var activeExperiments = activeExperimentIds.reduce(function ( - acc, - expId - ) { - acc[ - 'rokt.custom.optimizely.experiment.' + - expId + - '.variationId' - ] = optimizelyState.getVariationMap()[expId].id; - return acc; - }, - {}); - return activeExperiments; - } - } catch (error) { - console.error('Error fetching Optimizely attributes:', error); - } - return {}; - } - - // Called by the mParticle Rokt Manager - this.selectPlacements = selectPlacements; - this.hashAttributes = hashAttributes; - this.use = use; - - // Kit Callback Methods - this.init = initForwarder; - this.process = processEvent; - this.setExtensionData = setExtensionData; - this.setUserAttribute = setUserAttribute; - this.onUserIdentified = onUserIdentified; - this.onLoginComplete = onLoginComplete; - this.onLogoutComplete = onLogoutComplete; - this.onModifyComplete = onModifyComplete; - this.removeUserAttribute = removeUserAttribute; - - /** - * Checks if the Rokt kit is ready to use. - * Both conditions must be true: - * 1. self.isInitialized - Set after successful initialization of the kit - * 2. self.launcher - The Rokt launcher instance must be available - * @returns {boolean} Whether the kit is ready for use - */ - function isKitReady() { - return !!(self.isInitialized && self.launcher); - } - - function isPartnerInLocalLauncherTestGroup() { - return ( - window.mParticle.config && - window.mParticle.config.isLocalLauncherEnabled && - _isAssignedToSampleGroup() - ); - } - - function _isAssignedToSampleGroup() { - var LOCAL_LAUNCHER_TEST_GROUP_THRESHOLD = 0.5; - return Math.random() > LOCAL_LAUNCHER_TEST_GROUP_THRESHOLD; - } - - function captureTiming(metricName) { - if ( - window && - window.mParticle && - window.mParticle.captureTiming && - metricName - ) { - window.mParticle.captureTiming(metricName); - } - } - - function createAutoRemovedIframe(src) { - var iframe = document.createElement('iframe'); - iframe.style.display = 'none'; - iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin'); - iframe.src = src; - iframe.onload = function () { - iframe.onload = null; - if (iframe.parentNode) { - iframe.parentNode.removeChild(iframe); - } - }; - var target = document.body || document.head; - if (target) { - target.appendChild(iframe); - } - } - - var ADBLOCK_CONTROL_DOMAIN = 'apps.roktecommerce.com'; - var INIT_LOG_SAMPLING_RATE = 0.1; - var _allowedOriginHashes = [-553112570, 549508659]; - - function djb2(str) { - var hash = 5381; - for (var i = 0; i < str.length; i++) { - hash = (hash << 5) + hash + str.charCodeAt(i); - hash = hash & hash; - } - return hash; - } - - function sendAdBlockMeasurementSignals(domain, version) { - var originHash = djb2(window.location.origin); - if (_allowedOriginHashes.indexOf(originHash) === -1) { - return; - } - - if (Math.random() >= INIT_LOG_SAMPLING_RATE) { - return; - } - - var guid = window.__rokt_li_guid__; - if (!guid) { - return; - } - - var pageUrl = window.location.href.split('?')[0].split('#')[0]; - var params = - 'version=' + - encodeURIComponent(version) + - '&launcherInstanceGuid=' + - encodeURIComponent(guid) + - '&pageUrl=' + - encodeURIComponent(pageUrl); - - var existingDomain = domain || 'apps.rokt.com'; - createAutoRemovedIframe( - 'https://' + existingDomain + '/v1/wsdk-init/index.html?' + params - ); - - createAutoRemovedIframe( - 'https://' + - ADBLOCK_CONTROL_DOMAIN + - '/v1/wsdk-init/index.html?' + - params + - '&isControl=true' - ); - } -}; - -function generateIntegrationName(customIntegrationName) { - var coreSdkVersion = window.mParticle.getVersion(); - var kitVersion = process.env.PACKAGE_VERSION; - var name = 'mParticle_' + 'wsdkv_' + coreSdkVersion + '_kitv_' + kitVersion; - - if (customIntegrationName) { - name += '_' + customIntegrationName; - } - return name; -} - -function getId() { - return moduleId; -} - -function register(config) { - if (!config) { - window.console.log( - 'You must pass a config object to register the kit ' + name - ); - return; - } - if (!isObject(config)) { - window.console.log( - "'config' must be an object. You passed in a " + typeof config - ); - return; - } - - if (isObject(config.kits)) { - config.kits[name] = { - constructor: constructor, - }; - } else { - config.kits = {}; - config.kits[name] = { - constructor: constructor, - }; - } - window.console.log( - 'Successfully registered ' + name + ' to your mParticle configuration' - ); -} - -function isObject(val) { - return ( - val != null && typeof val === 'object' && Array.isArray(val) === false - ); -} - -function mergeObjects() { - var resObj = {}; - for (var i = 0; i < arguments.length; i += 1) { - var obj = arguments[i], - keys = Object.keys(obj); - for (var j = 0; j < keys.length; j += 1) { - resObj[keys[j]] = obj[keys[j]]; - } - } - return resObj; -} - -function parseSettingsString(settingsString) { - if (!settingsString) { - return []; - } - try { - return JSON.parse(settingsString.replace(/"/g, '"')); - } catch (error) { - console.error('Settings string contains invalid JSON'); - } - return []; -} - -function extractRoktExtensions(settingsString) { - var settings = settingsString ? parseSettingsString(settingsString) : []; - var roktExtensions = []; - - for (var i = 0; i < settings.length; i++) { - roktExtensions.push(settings[i].value); - } - - return roktExtensions; -} - -function generateMappedEventLookup(placementEventMapping) { - if (!placementEventMapping) { - return {}; - } - - var mappedEvents = {}; - for (var i = 0; i < placementEventMapping.length; i++) { - var mapping = placementEventMapping[i]; - mappedEvents[mapping.jsmap] = mapping.value; - } - return mappedEvents; -} - -function hashEventMessage(messageType, eventType, eventName) { - return window.mParticle.generateHash( - [messageType, eventType, eventName].join('') - ); -} - -function isEmpty(value) { - return value == null || !(Object.keys(value) || value).length; -} - -function isString(value) { - return typeof value === 'string'; -} - -// --- Reporting Services --- - -var ErrorCodes = { - UNKNOWN_ERROR: 'UNKNOWN_ERROR', - UNHANDLED_EXCEPTION: 'UNHANDLED_EXCEPTION', - IDENTITY_REQUEST: 'IDENTITY_REQUEST', -}; - -var WSDKErrorSeverity = { - ERROR: 'ERROR', - INFO: 'INFO', - WARNING: 'WARNING', -}; - -var DEFAULT_LOGGING_URL = 'apps.rokt-api.com/v1/log'; -var DEFAULT_ERROR_URL = 'apps.rokt-api.com/v1/errors'; -var RATE_LIMIT_PER_SEVERITY = 10; - -function RateLimiter() { - this._logCount = {}; -} - -RateLimiter.prototype.incrementAndCheck = function (severity) { - var count = this._logCount[severity] || 0; - var newCount = count + 1; - this._logCount[severity] = newCount; - return newCount > RATE_LIMIT_PER_SEVERITY; -}; - -// --- ReportingTransport: shared transport layer for reporting services --- - -function ReportingTransport( - config, - integrationName, - launcherInstanceGuid, - accountId, - rateLimiter -) { - var self = this; - self._isLoggingEnabled = (config && config.isLoggingEnabled) || false; - self._integrationName = integrationName || ''; - self._launcherInstanceGuid = launcherInstanceGuid; - self._accountId = accountId || null; - self._rateLimiter = rateLimiter || new RateLimiter(); - self._reporter = 'mp-wsdk'; - self._isEnabled = _isReportingEnabled(self); -} - -ReportingTransport.prototype.send = function ( - url, - severity, - msg, - code, - stackTrace, - onError -) { - if (!this._isEnabled || this._rateLimiter.incrementAndCheck(severity)) { - return; - } - - try { - var logRequest = { - additionalInformation: { - message: msg, - version: this._integrationName || '', - }, - severity: severity, - code: code || ErrorCodes.UNKNOWN_ERROR, - url: _getUrl(), - deviceInfo: _getUserAgent(), - stackTrace: stackTrace, - reporter: this._reporter, - integration: this._integrationName || '', - }; - var headers = { - Accept: 'text/plain;charset=UTF-8', - 'Content-Type': 'application/json', - 'rokt-launcher-version': this._integrationName || '', - 'rokt-wsdk-version': 'joint', - }; - if (this._launcherInstanceGuid) { - headers['rokt-launcher-instance-guid'] = this._launcherInstanceGuid; - } - if (this._accountId) { - headers['rokt-account-id'] = this._accountId; - } - var payload = { - method: 'POST', - headers: headers, - body: JSON.stringify(logRequest), - }; - fetch(url, payload).catch(function (error) { - console.error('ReportingTransport: Failed to send log', error); - if (onError) { - onError(error); - } - }); - } catch (error) { - console.error('ReportingTransport: Failed to send log', error); - if (onError) { - onError(error); - } - } -}; - -function _isReportingEnabled(transport) { - return ( - _isDebugModeEnabled() || - (_isRoktDomainPresent() && transport._isLoggingEnabled) - ); -} - -function _isRoktDomainPresent() { - return typeof window !== 'undefined' && Boolean(window['ROKT_DOMAIN']); -} - -function _isDebugModeEnabled() { - return ( - typeof window !== 'undefined' && - window.location && - window.location.search && - window.location.search - .toLowerCase() - .indexOf('mp_enable_logging=true') !== -1 - ); -} - -function _getUrl() { - return typeof window !== 'undefined' && window.location - ? window.location.href - : undefined; -} - -function _getUserAgent() { - return typeof window !== 'undefined' && window.navigator - ? window.navigator.userAgent - : undefined; -} - -// --- ErrorReportingService: handles ERROR and WARNING severity --- - -function ErrorReportingService( - config, - integrationName, - launcherInstanceGuid, - accountId, - rateLimiter -) { - this._transport = new ReportingTransport( - config, - integrationName, - launcherInstanceGuid, - accountId, - rateLimiter - ); - this._errorUrl = - 'https://' + ((config && config.errorUrl) || DEFAULT_ERROR_URL); -} - -ErrorReportingService.prototype.report = function (error) { - if (!error) { - return; - } - var severity = error.severity || WSDKErrorSeverity.ERROR; - this._transport.send( - this._errorUrl, - severity, - error.message, - error.code, - error.stackTrace - ); -}; - -// --- LoggingService: handles INFO severity --- - -function LoggingService( - config, - errorReportingService, - integrationName, - launcherInstanceGuid, - accountId, - rateLimiter -) { - this._transport = new ReportingTransport( - config, - integrationName, - launcherInstanceGuid, - accountId, - rateLimiter - ); - this._loggingUrl = - 'https://' + ((config && config.loggingUrl) || DEFAULT_LOGGING_URL); - this._errorReportingService = errorReportingService; -} - -LoggingService.prototype.log = function (entry) { - if (!entry) { - return; - } - var self = this; - self._transport.send( - self._loggingUrl, - WSDKErrorSeverity.INFO, - entry.message, - entry.code, - undefined, - function (error) { - if (self._errorReportingService) { - self._errorReportingService.report({ - message: - 'LoggingService: Failed to send log: ' + error.message, - code: ErrorCodes.UNKNOWN_ERROR, - severity: WSDKErrorSeverity.ERROR, - }); - } - } - ); -}; - -if (window && window.mParticle && window.mParticle.addForwarder) { - window.mParticle.addForwarder({ - name: name, - constructor: constructor, - getId: getId, - }); -} - -module.exports = { - register: register, - ReportingTransport: ReportingTransport, - ErrorReportingService: ErrorReportingService, - LoggingService: LoggingService, - RateLimiter: RateLimiter, - ErrorCodes: ErrorCodes, - WSDKErrorSeverity: WSDKErrorSeverity, -}; diff --git a/src/Rokt-Kit.ts b/src/Rokt-Kit.ts new file mode 100644 index 0000000..5b0786d --- /dev/null +++ b/src/Rokt-Kit.ts @@ -0,0 +1,1238 @@ +// Copyright 2025 mParticle, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// ============================================================ +// Types +// ============================================================ + +interface RoktKitSettings { + accountId: string; + roktExtensions?: string; + placementEventMapping?: string; + placementEventAttributeMapping?: string; + hashedEmailUserIdentityType?: string; + onboardingExpProvider?: string; + loggingUrl?: string; + errorUrl?: string; + isLoggingEnabled?: string | boolean; +} + +interface EventAttributeCondition { + operator: string; + attributeValue: string; +} + +interface PlacementEventRule { + eventAttributeKey: string; + conditions: EventAttributeCondition[]; +} + +interface EventAttributeMapping { + value: string; + map: string; + conditions?: EventAttributeCondition[]; +} + +interface PlacementEventMappingEntry { + jsmap: string; + value: string; +} + +interface RoktExtensionEntry { + value: string; +} + +interface RoktSelection { + context?: { + sessionId?: Promise; + }; + then?: (callback: (sel: RoktSelection) => void) => Promise; + catch?: (callback: () => void) => void; +} + +interface RoktLauncher { + selectPlacements(options: Record): RoktSelection | Promise; + hashAttributes(attributes: Record): Promise>; + use(extensionName: string): Promise; +} + +interface RoktGlobal { + createLauncher(options: Record): Promise; + createLocalLauncher(options: Record): RoktLauncher; + currentLauncher?: RoktLauncher; + __event_stream__?(event: Record): void; + setExtensionData(data: Record): void; +} + +interface FilteredUser { + getMPID(): string; + getAllUserAttributes(): Record; + getUserIdentities?: () => { userIdentities: Record }; +} + +interface KitFilters { + userAttributeFilters?: string[]; + filterUserAttributes?: (attributes: Record, filters?: string[]) => Record; + filteredUser?: FilteredUser | null; +} + +interface RoktManager { + attachKit(kit: RoktKit): void | Promise; + filters?: KitFilters; + domain?: string; + launcherOptions?: Record; + getLocalSessionAttributes?(): Record; + setLocalSessionAttribute?(key: string, value: unknown): void; +} + +interface MParticleInstance { + setIntegrationAttribute(moduleId: number, attrs: Record): void; +} + +interface OptimizelyState { + getActiveExperimentIds(): string[]; + getVariationMap(): Record; +} + +interface OptimizelyGlobal { + get(key: 'state'): OptimizelyState; +} + +// Our view of the mParticle global with Rokt-specific extensions. +// We access window.mParticle via an explicit cast (see `mp()` helper below) +// rather than augmenting Window to avoid conflicts with @mparticle/web-sdk declarations. +interface MParticleExtended { + Rokt: RoktManager; + addForwarder(config: ForwarderRegistration): void; + getVersion(): string; + generateHash(value: string): string | number; + logEvent(name: string, type: number, attrs?: Record): void; + EventType: { Other: number }; + getInstance(): MParticleInstance; + sessionManager?: { getSession(): string }; + _getActiveForwarders(): Array<{ name: string }>; + config?: { isLocalLauncherEnabled?: boolean }; + captureTiming?(metricName: string): void; + forwarder?: RoktKit; + loggedEvents?: Array>; + _registerErrorReportingService?(service: ErrorReportingService): void; + _registerLoggingService?(service: LoggingService): void; +} + +interface TestHelpers { + generateLauncherScript: (domain: string | undefined, extensions: string[]) => string; + extractRoktExtensions: (settingsString?: string) => string[]; + hashEventMessage: (messageType: number, eventType: number, eventName: string) => string | number; + parseSettingsString: (settingsString?: string) => T[]; + generateMappedEventLookup: (placementEventMapping: PlacementEventMappingEntry[]) => Record; + generateMappedEventAttributeLookup: (mapping: EventAttributeMapping[]) => Record; + sendAdBlockMeasurementSignals: (domain: string | undefined, version: string | null) => void; + createAutoRemovedIframe: (src: string) => void; + djb2: (str: string) => number; + setAllowedOriginHashes: (hashes: number[]) => void; + ReportingTransport: typeof ReportingTransport; + ErrorReportingService: typeof ErrorReportingService; + LoggingService: typeof LoggingService; + RateLimiter: typeof RateLimiter; + ErrorCodes: typeof ErrorCodes; + WSDKErrorSeverity: typeof WSDKErrorSeverity; +} + +interface ForwarderRegistration { + name: string; + constructor: new () => RoktKit; + getId: () => number; +} + +interface MParticleEvent { + EventDataType: number; + EventCategory: number; + EventName?: string; + EventAttributes?: Record; + [key: string]: unknown; +} + +interface ReportingConfig { + loggingUrl?: string; + errorUrl?: string; + isLoggingEnabled?: boolean | string; +} + +interface ErrorReport { + message: string; + code?: string; + severity?: string; + stackTrace?: string; +} + +interface LogEntry { + message: string; + code?: string; +} + +declare global { + interface Window { + Rokt?: RoktGlobal; + __rokt_li_guid__?: string; + optimizely?: OptimizelyGlobal; + ROKT_DOMAIN?: string; + // mParticle is declared as any to avoid conflicts with @mparticle/web-sdk type declarations. + // We use the typed mp() accessor for all internal accesses. + // eslint-disable-next-line @typescript-eslint/no-explicit-any + mParticle: any; + } +} + +// ============================================================ +// Module-level constants +// ============================================================ + +const name = 'Rokt'; +const moduleId = 181; +const EVENT_NAME_SELECT_PLACEMENTS = 'selectPlacements'; +const ADBLOCK_CONTROL_DOMAIN = 'apps.roktecommerce.com'; +const INIT_LOG_SAMPLING_RATE = 0.1; +const MESSAGE_TYPE_PROFILE = 14; // mParticle MessageType.Profile + +// ============================================================ +// Reporting service constants +// ============================================================ + +const ErrorCodes = { + UNKNOWN_ERROR: 'UNKNOWN_ERROR', + UNHANDLED_EXCEPTION: 'UNHANDLED_EXCEPTION', + IDENTITY_REQUEST: 'IDENTITY_REQUEST', +} as const; + +const WSDKErrorSeverity = { + ERROR: 'ERROR', + INFO: 'INFO', + WARNING: 'WARNING', +} as const; + +const DEFAULT_LOGGING_URL = 'apps.rokt-api.com/v1/log'; +const DEFAULT_ERROR_URL = 'apps.rokt-api.com/v1/errors'; +const RATE_LIMIT_PER_SEVERITY = 10; + +// ============================================================ +// Helper: typed accessor for window.mParticle +// We use an explicit cast here to avoid conflicts with @mparticle/web-sdk +// type declarations while still providing full type safety for our usages. +// ============================================================ + +function mp(): MParticleExtended { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return (window as any).mParticle as MParticleExtended; +} + +// ============================================================ +// Module-level utility functions +// ============================================================ + +function generateLauncherScript(domain: string | undefined, extensions: string[]): string { + const resolvedDomain = typeof domain !== 'undefined' ? domain : 'apps.rokt.com'; + const protocol = 'https://'; + const launcherPath = '/wsdk/integrations/launcher.js'; + const baseUrl = [protocol, resolvedDomain, launcherPath].join(''); + + if (!extensions || extensions.length === 0) { + return baseUrl; + } + return baseUrl + '?extensions=' + extensions.join(','); +} + +function isObject(val: unknown): val is Record { + return val != null && typeof val === 'object' && Array.isArray(val) === false; +} + +function parseSettingsString(settingsString?: string): T[] { + if (!settingsString) { + return []; + } + try { + return JSON.parse(settingsString.replace(/"/g, '"')) as T[]; + } catch (_error) { + console.error('Settings string contains invalid JSON'); + } + return []; +} + +function extractRoktExtensions(settingsString?: string): string[] { + const settings = settingsString ? parseSettingsString(settingsString) : []; + const roktExtensions: string[] = []; + + for (let i = 0; i < settings.length; i++) { + roktExtensions.push(settings[i].value); + } + + return roktExtensions; +} + +function generateMappedEventLookup(placementEventMapping: PlacementEventMappingEntry[]): Record { + if (!placementEventMapping) { + return {}; + } + + const mappedEvents: Record = {}; + for (let i = 0; i < placementEventMapping.length; i++) { + const mapping = placementEventMapping[i]; + mappedEvents[mapping.jsmap] = mapping.value; + } + return mappedEvents; +} + +function generateMappedEventAttributeLookup( + placementEventAttributeMapping: EventAttributeMapping[], +): Record { + const mappedAttributeKeys: Record = {}; + if (!Array.isArray(placementEventAttributeMapping)) { + return mappedAttributeKeys; + } + for (let i = 0; i < placementEventAttributeMapping.length; i++) { + const mapping = placementEventAttributeMapping[i]; + if (!mapping || !isString(mapping.value) || !isString(mapping.map)) { + continue; + } + + const mappedAttributeKey = mapping.value; + const eventAttributeKey = mapping.map; + + if (!mappedAttributeKeys[mappedAttributeKey]) { + mappedAttributeKeys[mappedAttributeKey] = []; + } + + mappedAttributeKeys[mappedAttributeKey].push({ + eventAttributeKey: eventAttributeKey, + conditions: Array.isArray(mapping.conditions) ? mapping.conditions : [], + }); + } + return mappedAttributeKeys; +} + +function hashEventMessage(messageType: number, eventType: number, eventName: string): string | number { + return mp().generateHash([messageType, eventType, eventName].join('')); +} + +function isEmpty(value: unknown): boolean { + if (value == null) return true; + if (typeof value === 'object') { + return Object.keys(value as object).length === 0; + } + if (Array.isArray(value)) { + return (value as unknown[]).length === 0; + } + return false; +} + +function isString(value: unknown): value is string { + return typeof value === 'string'; +} + +function generateIntegrationName(customIntegrationName?: string): string { + const coreSdkVersion = mp().getVersion(); + const kitVersion = process.env.PACKAGE_VERSION; + let integrationName = 'mParticle_' + 'wsdkv_' + coreSdkVersion + '_kitv_' + kitVersion; + + if (customIntegrationName) { + integrationName += '_' + customIntegrationName; + } + return integrationName; +} + +function djb2(str: string): number { + let hash = 5381; + for (let i = 0; i < str.length; i++) { + hash = (hash << 5) + hash + str.charCodeAt(i); + hash = hash & hash; + } + return hash; +} + +function createAutoRemovedIframe(src: string): void { + const iframe = document.createElement('iframe'); + iframe.style.display = 'none'; + iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin'); + iframe.src = src; + iframe.onload = function () { + iframe.onload = null; + if (iframe.parentNode) { + iframe.parentNode.removeChild(iframe); + } + }; + const target = document.body || document.head; + if (target) { + target.appendChild(iframe); + } +} + +function sendAdBlockMeasurementSignals(domain: string | undefined, version: string | null): void { + const originHash = djb2(window.location.origin); + const allowedOriginHashes = RoktKit._allowedOriginHashes; + if (allowedOriginHashes.indexOf(originHash) === -1) { + return; + } + + if (Math.random() >= INIT_LOG_SAMPLING_RATE) { + return; + } + + const guid = window.__rokt_li_guid__; + if (!guid) { + return; + } + + const pageUrl = window.location.href.split('?')[0].split('#')[0]; + const params = + 'version=' + + encodeURIComponent(version ?? '') + + '&launcherInstanceGuid=' + + encodeURIComponent(guid) + + '&pageUrl=' + + encodeURIComponent(pageUrl); + + const existingDomain = domain || 'apps.rokt.com'; + createAutoRemovedIframe('https://' + existingDomain + '/v1/wsdk-init/index.html?' + params); + + createAutoRemovedIframe( + 'https://' + ADBLOCK_CONTROL_DOMAIN + '/v1/wsdk-init/index.html?' + params + '&isControl=true', + ); +} + +// ============================================================ +// Reporting helpers +// ============================================================ + +function _isRoktDomainPresent(): boolean { + return typeof window !== 'undefined' && Boolean(window.ROKT_DOMAIN); +} + +function _isDebugModeEnabled(): boolean { + return typeof window !== 'undefined' && !!window.location?.search?.toLowerCase().includes('mp_enable_logging=true'); +} + +function _getReportingUrl(): string | undefined { + return typeof window !== 'undefined' ? window.location?.href : undefined; +} + +function _getUserAgent(): string | undefined { + return typeof window !== 'undefined' ? window.navigator?.userAgent : undefined; +} + +class RateLimiter { + private _logCount: Record = {}; + + incrementAndCheck(severity: string): boolean { + const count = this._logCount[severity] || 0; + const newCount = count + 1; + this._logCount[severity] = newCount; + return newCount > RATE_LIMIT_PER_SEVERITY; + } +} + +class ReportingTransport { + private _isEnabled: boolean; + private _integrationName: string; + private _launcherInstanceGuid: string | undefined; + private _accountId: string | null; + private _rateLimiter: RateLimiter; + private readonly _reporter = 'mp-wsdk'; + + constructor( + config: ReportingConfig, + integrationName: string | null | undefined, + launcherInstanceGuid: string | undefined, + accountId: string | null | undefined, + rateLimiter?: RateLimiter, + ) { + const isLoggingEnabled = config?.isLoggingEnabled === true || config?.isLoggingEnabled === 'true'; + this._integrationName = integrationName || ''; + this._launcherInstanceGuid = launcherInstanceGuid; + this._accountId = accountId || null; + this._rateLimiter = rateLimiter || new RateLimiter(); + this._isEnabled = _isDebugModeEnabled() || (_isRoktDomainPresent() && isLoggingEnabled); + } + + send( + url: string, + severity: string, + msg: string, + code?: string, + stackTrace?: string, + onError?: (error: Error) => void, + ): void { + if (!this._isEnabled || this._rateLimiter.incrementAndCheck(severity)) { + return; + } + + try { + const logRequest = { + additionalInformation: { + message: msg, + version: this._integrationName, + }, + severity, + code: code || ErrorCodes.UNKNOWN_ERROR, + url: _getReportingUrl(), + deviceInfo: _getUserAgent(), + stackTrace, + reporter: this._reporter, + integration: this._integrationName, + }; + + const headers: Record = { + Accept: 'text/plain;charset=UTF-8', + 'Content-Type': 'application/json', + 'rokt-launcher-version': this._integrationName, + 'rokt-wsdk-version': 'joint', + }; + + if (this._launcherInstanceGuid) { + headers['rokt-launcher-instance-guid'] = this._launcherInstanceGuid; + } + if (this._accountId) { + headers['rokt-account-id'] = this._accountId; + } + + fetch(url, { + method: 'POST', + headers, + body: JSON.stringify(logRequest), + }).catch((error: Error) => { + console.error('ReportingTransport: Failed to send log', error); + if (onError) onError(error); + }); + } catch (error) { + console.error('ReportingTransport: Failed to send log', error); + if (onError) onError(error as Error); + } + } +} + +class ErrorReportingService { + private _transport: ReportingTransport; + private _errorUrl: string; + + constructor( + config: ReportingConfig, + integrationName: string | null | undefined, + launcherInstanceGuid?: string, + accountId?: string | null, + rateLimiter?: RateLimiter, + ) { + this._transport = new ReportingTransport(config, integrationName, launcherInstanceGuid, accountId, rateLimiter); + this._errorUrl = 'https://' + (config?.errorUrl || DEFAULT_ERROR_URL); + } + + report(error: ErrorReport | null | undefined): void { + if (!error) return; + const severity = error.severity || WSDKErrorSeverity.ERROR; + this._transport.send(this._errorUrl, severity, error.message, error.code, error.stackTrace); + } +} + +class LoggingService { + private _transport: ReportingTransport; + private _loggingUrl: string; + private _errorReportingService: { report: (e: ErrorReport) => void }; + + constructor( + config: ReportingConfig, + errorReportingService: { report: (e: ErrorReport) => void }, + integrationName: string | null | undefined, + launcherInstanceGuid?: string, + accountId?: string | null, + rateLimiter?: RateLimiter, + ) { + this._transport = new ReportingTransport(config, integrationName, launcherInstanceGuid, accountId, rateLimiter); + this._loggingUrl = 'https://' + (config?.loggingUrl || DEFAULT_LOGGING_URL); + this._errorReportingService = errorReportingService; + } + + log(entry: LogEntry | null | undefined): void { + if (!entry) return; + this._transport.send( + this._loggingUrl, + WSDKErrorSeverity.INFO, + entry.message, + entry.code, + undefined, + (error: Error) => { + if (this._errorReportingService) { + this._errorReportingService.report({ + message: 'LoggingService: Failed to send log: ' + error.message, + code: ErrorCodes.UNKNOWN_ERROR, + severity: WSDKErrorSeverity.ERROR, + }); + } + }, + ); + } +} + +// ============================================================ +// RoktKit class +// ============================================================ + +class RoktKit { + // Static field for allowed origin hashes (mutable by testHelpers) + public static _allowedOriginHashes: number[] = [-553112570, 549508659]; + + private static readonly PERFORMANCE_MARKS = { + RoktScriptAppended: 'mp:RoktScriptAppended', + }; + + private static readonly EMAIL_SHA256_KEY = 'emailsha256'; + + // Public fields (accessed by tests and the mParticle framework) + public name = name; + public moduleId = moduleId; + public isInitialized = false; + public launcher: RoktLauncher | null = null; + public filters: KitFilters = {}; + public userAttributes: Record = {}; + public testHelpers: TestHelpers | null = null; + public placementEventMappingLookup: Record = {}; + public placementEventAttributeMappingLookup: Record = {}; + public eventQueue: MParticleEvent[] = []; + public eventStreamQueue: MParticleEvent[] = []; + public integrationName: string | null = null; + public domain?: string; + public errorReportingService: ErrorReportingService | null = null; + public loggingService: LoggingService | null = null; + + // Private fields + private _mappedEmailSha256Key?: string; + private _onboardingExpProvider?: string; + + // ---- Private helpers ---- + + private getEventAttributeValue(event: MParticleEvent, eventAttributeKey: string): unknown { + const attributes = event && event.EventAttributes; + if (!attributes) { + return null; + } + + if (typeof attributes[eventAttributeKey] === 'undefined') { + return null; + } + + return attributes[eventAttributeKey]; + } + + private doesEventAttributeConditionMatch(condition: EventAttributeCondition, actualValue: unknown): boolean { + if (!condition || !isString(condition.operator)) { + return false; + } + + const operator = condition.operator.toLowerCase(); + const expectedValue = condition.attributeValue; + + if (operator === 'exists') { + return actualValue !== null; + } + + if (actualValue == null) { + return false; + } + + if (operator === 'equals') { + return String(actualValue) === String(expectedValue); + } + + if (operator === 'contains') { + return String(actualValue).indexOf(String(expectedValue)) !== -1; + } + + return false; + } + + private doesEventMatchRule(event: MParticleEvent, rule: PlacementEventRule): boolean { + if (!rule || !isString(rule.eventAttributeKey)) { + return false; + } + + const conditions = rule.conditions; + if (!Array.isArray(conditions)) { + return false; + } + + const actualValue = this.getEventAttributeValue(event, rule.eventAttributeKey); + + if (conditions.length === 0) { + return actualValue !== null; + } + for (let i = 0; i < conditions.length; i++) { + if (!this.doesEventAttributeConditionMatch(conditions[i], actualValue)) { + return false; + } + } + + return true; + } + + private applyPlacementEventAttributeMapping(event: MParticleEvent): void { + const mappedAttributeKeys = Object.keys(this.placementEventAttributeMappingLookup); + for (let i = 0; i < mappedAttributeKeys.length; i++) { + const mappedAttributeKey = mappedAttributeKeys[i]; + const rulesForMappedAttributeKey = this.placementEventAttributeMappingLookup[mappedAttributeKey]; + if (isEmpty(rulesForMappedAttributeKey)) { + continue; + } + + // Require ALL rules for the same key to match (AND). + let allMatch = true; + for (let j = 0; j < rulesForMappedAttributeKey.length; j++) { + if (!this.doesEventMatchRule(event, rulesForMappedAttributeKey[j])) { + allMatch = false; + break; + } + } + if (!allMatch) { + continue; + } + + mp().Rokt.setLocalSessionAttribute?.(mappedAttributeKey, true); + } + } + + private isLauncherReadyToAttach(): boolean { + return !!window.Rokt && typeof window.Rokt.createLauncher === 'function'; + } + + /** + * Returns the user identities from the filtered user, if any. + */ + private returnUserIdentities(filteredUser: FilteredUser | null | undefined): Record { + if (!filteredUser || !filteredUser.getUserIdentities) { + return {}; + } + + const userIdentities = filteredUser.getUserIdentities().userIdentities; + + return this.replaceOtherIdentityWithEmailsha256(userIdentities); + } + + private returnLocalSessionAttributes(): Record { + if (!mp().Rokt || typeof mp().Rokt.getLocalSessionAttributes !== 'function') { + return {}; + } + if (isEmpty(this.placementEventMappingLookup) && isEmpty(this.placementEventAttributeMappingLookup)) { + return {}; + } + return mp().Rokt.getLocalSessionAttributes!(); + } + + private replaceOtherIdentityWithEmailsha256(userIdentities: Record): Record { + const newUserIdentities: Record = { ...(userIdentities || {}) }; + const key = this._mappedEmailSha256Key; + if (key && userIdentities[key]) { + newUserIdentities[RoktKit.EMAIL_SHA256_KEY] = userIdentities[key]; + } + if (key) { + delete newUserIdentities[key]; + } + + return newUserIdentities; + } + + private logSelectPlacementsEvent(attributes: unknown): void { + if (!window.mParticle || typeof mp().logEvent !== 'function') { + return; + } + + if (!isObject(attributes)) { + return; + } + + const EVENT_TYPE_OTHER = mp().EventType.Other; + + mp().logEvent(EVENT_NAME_SELECT_PLACEMENTS, EVENT_TYPE_OTHER, attributes as Record); + } + + private processEventQueue(): void { + this.eventQueue.forEach((event) => { + this.process(event); + }); + this.eventQueue = []; + } + + private enrichEvent(event: MParticleEvent): Record { + return { ...(event as Record), UserAttributes: this.userAttributes }; + } + + private sendEventStream(event: MParticleEvent): void { + if (window.Rokt && typeof window.Rokt.__event_stream__ === 'function') { + if (this.eventStreamQueue.length) { + const queuedEvents = this.eventStreamQueue; + this.eventStreamQueue = []; + for (let i = 0; i < queuedEvents.length; i++) { + window.Rokt.__event_stream__(this.enrichEvent(queuedEvents[i])); + } + } + window.Rokt.__event_stream__(this.enrichEvent(event)); + } else { + this.eventStreamQueue.push(event); + } + } + + private setRoktSessionId(sessionId: string): void { + if (!sessionId || typeof sessionId !== 'string') { + return; + } + try { + const mpInstance = mp().getInstance(); + if (mpInstance && typeof mpInstance.setIntegrationAttribute === 'function') { + mpInstance.setIntegrationAttribute(moduleId, { + roktSessionId: sessionId, + }); + } + } catch (_e) { + // Best effort — never let this break the partner page + } + } + + private buildIdentityEvent(eventName: string, filteredUser: FilteredUser): MParticleEvent { + const mpid = filteredUser.getMPID && typeof filteredUser.getMPID === 'function' ? filteredUser.getMPID() : null; + const sessionId = + mp() && mp().sessionManager && typeof mp().sessionManager!.getSession === 'function' + ? mp().sessionManager!.getSession() + : null; + const userIdentities = + filteredUser.getUserIdentities && typeof filteredUser.getUserIdentities === 'function' + ? filteredUser.getUserIdentities().userIdentities + : null; + + return { + EventName: eventName, + EventDataType: MESSAGE_TYPE_PROFILE, + EventCategory: 0, + Timestamp: Date.now(), + MPID: mpid, + SessionId: sessionId, + UserIdentities: userIdentities, + }; + } + + private attachLauncher(accountId: string, launcherOptions: Record): void { + const mpSessionId = + mp() && mp().sessionManager && typeof mp().sessionManager!.getSession === 'function' + ? mp().sessionManager!.getSession() + : undefined; + + const options: Record = { + accountId, + ...(launcherOptions || {}), + ...(mpSessionId ? { mpSessionId } : {}), + }; + + if (this.isPartnerInLocalLauncherTestGroup()) { + const localLauncher = window.Rokt!.createLocalLauncher(options); + this.initRoktLauncher(localLauncher); + } else { + window + .Rokt!.createLauncher(options) + .then((launcher) => this.initRoktLauncher(launcher)) + .catch((err: unknown) => { + console.error('Error creating Rokt launcher:', err); + }); + } + } + + private initRoktLauncher(launcher: RoktLauncher): void { + // Assign the launcher to a global variable for later access + if (window.Rokt) { + window.Rokt.currentLauncher = launcher; + } + // Locally cache the launcher and filters + this.launcher = launcher; + + const roktFilters = mp().Rokt?.filters; + + if (!roktFilters) { + console.warn('Rokt Kit: No filters have been set.'); + } else { + this.filters = roktFilters; + if (!roktFilters.filteredUser) { + console.warn('Rokt Kit: No filtered user has been set.'); + } + } + + // Kit must be initialized before attaching to the Rokt manager + this.isInitialized = true; + + sendAdBlockMeasurementSignals(this.domain, this.integrationName); + + // Attaches the kit to the Rokt manager + mp().Rokt.attachKit(this); + this.processEventQueue(); + } + + private fetchOptimizely(): Record { + const forwarders = mp() + ._getActiveForwarders() + .filter((forwarder) => forwarder.name === 'Optimizely'); + + try { + if (forwarders.length > 0 && window.optimizely) { + const optimizelyState = window.optimizely.get('state'); + if (!optimizelyState || !optimizelyState.getActiveExperimentIds) { + return {}; + } + const activeExperimentIds = optimizelyState.getActiveExperimentIds(); + const activeExperiments = activeExperimentIds.reduce((acc: Record, expId: string) => { + acc['rokt.custom.optimizely.experiment.' + expId + '.variationId'] = + optimizelyState.getVariationMap()[expId].id; + return acc; + }, {}); + return activeExperiments; + } + } catch (error) { + console.error('Error fetching Optimizely attributes:', error); + } + return {}; + } + + private isKitReady(): boolean { + return !!(this.isInitialized && this.launcher); + } + + private isPartnerInLocalLauncherTestGroup(): boolean { + return !!(mp().config && mp().config!.isLocalLauncherEnabled && this.isAssignedToSampleGroup()); + } + + private isAssignedToSampleGroup(): boolean { + const LOCAL_LAUNCHER_TEST_GROUP_THRESHOLD = 0.5; + return Math.random() > LOCAL_LAUNCHER_TEST_GROUP_THRESHOLD; + } + + private captureTiming(metricName: string): void { + if (window && mp() && mp().captureTiming && metricName) { + mp().captureTiming!(metricName); + } + } + + // ---- Public methods (mParticle Kit Callbacks) ---- + + /** + * Initializes the Rokt forwarder with settings from the mParticle server. + */ + public init( + settings: RoktKitSettings, + _service: unknown, + testMode: boolean, + _trackerId: unknown, + filteredUserAttributes: Record, + ): void { + const accountId = settings.accountId; + const roktExtensions = extractRoktExtensions(settings.roktExtensions); + this.userAttributes = filteredUserAttributes || {}; + this._onboardingExpProvider = settings.onboardingExpProvider; + + const placementEventMapping = parseSettingsString(settings.placementEventMapping); + this.placementEventMappingLookup = generateMappedEventLookup(placementEventMapping); + + const placementEventAttributeMapping = parseSettingsString( + settings.placementEventAttributeMapping, + ); + this.placementEventAttributeMappingLookup = generateMappedEventAttributeLookup(placementEventAttributeMapping); + + // Set dynamic OTHER_IDENTITY based on server settings + if (settings.hashedEmailUserIdentityType) { + this._mappedEmailSha256Key = settings.hashedEmailUserIdentityType.toLowerCase(); + } + + const domain = mp().Rokt?.domain; + const launcherOptions: Record = { + ...((mp().Rokt?.launcherOptions as Record) || {}), + }; + this.integrationName = generateIntegrationName(launcherOptions.integrationName as string | undefined); + launcherOptions.integrationName = this.integrationName; + + this.domain = domain; + + const reportingConfig: ReportingConfig = { + loggingUrl: settings.loggingUrl, + errorUrl: settings.errorUrl, + isLoggingEnabled: settings.isLoggingEnabled === 'true' || settings.isLoggingEnabled === true, + }; + const errorReportingService = new ErrorReportingService( + reportingConfig, + this.integrationName, + window.__rokt_li_guid__, + settings.accountId, + ); + const loggingService = new LoggingService( + reportingConfig, + errorReportingService, + this.integrationName, + window.__rokt_li_guid__, + settings.accountId, + ); + + this.errorReportingService = errorReportingService; + this.loggingService = loggingService; + + if (mp()._registerErrorReportingService) { + mp()._registerErrorReportingService!(errorReportingService); + } + if (mp()._registerLoggingService) { + mp()._registerLoggingService!(loggingService); + } + + if (testMode) { + this.testHelpers = { + generateLauncherScript: generateLauncherScript, + extractRoktExtensions: extractRoktExtensions, + hashEventMessage: hashEventMessage, + parseSettingsString: parseSettingsString, + generateMappedEventLookup: generateMappedEventLookup, + generateMappedEventAttributeLookup: generateMappedEventAttributeLookup, + sendAdBlockMeasurementSignals: sendAdBlockMeasurementSignals, + createAutoRemovedIframe: createAutoRemovedIframe, + djb2: djb2, + setAllowedOriginHashes: (hashes: number[]) => { + RoktKit._allowedOriginHashes = hashes; + }, + ReportingTransport: ReportingTransport, + ErrorReportingService: ErrorReportingService, + LoggingService: LoggingService, + RateLimiter: RateLimiter, + ErrorCodes: ErrorCodes, + WSDKErrorSeverity: WSDKErrorSeverity, + }; + this.attachLauncher(accountId, launcherOptions); + return; + } + + if (this.isLauncherReadyToAttach()) { + this.attachLauncher(accountId, launcherOptions); + } else { + const target = document.head || document.body; + const script = document.createElement('script'); + script.type = 'text/javascript'; + script.src = generateLauncherScript(domain, roktExtensions); + script.async = true; + script.crossOrigin = 'anonymous'; + (script as HTMLScriptElement & { fetchPriority: string }).fetchPriority = 'high'; + script.id = 'rokt-launcher'; + + script.onload = () => { + if (this.isLauncherReadyToAttach()) { + this.attachLauncher(accountId, launcherOptions); + } else { + console.error('Rokt object is not available after script load.'); + } + }; + + script.onerror = (error) => { + console.error('Error loading Rokt launcher script:', error); + }; + + target.appendChild(script); + this.captureTiming(RoktKit.PERFORMANCE_MARKS.RoktScriptAppended); + } + } + + public process(event: MParticleEvent): void { + if (!this.isKitReady()) { + this.eventQueue.push(event); + return; + } + + this.sendEventStream(event); + + if (typeof mp().Rokt?.setLocalSessionAttribute !== 'function') { + return; + } + + if (!isEmpty(this.placementEventAttributeMappingLookup)) { + this.applyPlacementEventAttributeMapping(event); + } + + if (isEmpty(this.placementEventMappingLookup)) { + return; + } + + const hashedEvent = hashEventMessage(event.EventDataType, event.EventCategory, event.EventName ?? ''); + + if (this.placementEventMappingLookup[String(hashedEvent)]) { + const mappedValue = this.placementEventMappingLookup[String(hashedEvent)]; + mp().Rokt.setLocalSessionAttribute?.(mappedValue, true); + } + } + + public setExtensionData(partnerExtensionData: Record): void { + if (!this.isKitReady()) { + console.error('Rokt Kit: Not initialized'); + return; + } + + window.Rokt!.setExtensionData(partnerExtensionData); + } + + public setUserAttribute(key: string, value: unknown): void { + this.userAttributes[key] = value; + this.sendEventStream( + this.buildIdentityEvent('set_user_attributes', this.filters.filteredUser ?? ({} as FilteredUser)), + ); + } + + public removeUserAttribute(key: string): void { + delete this.userAttributes[key]; + } + + public onUserIdentified(filteredUser: FilteredUser): void { + this.filters.filteredUser = filteredUser; + this.userAttributes = filteredUser.getAllUserAttributes(); + this.sendEventStream(this.buildIdentityEvent('identify', filteredUser)); + } + + public onLoginComplete(filteredUser: FilteredUser): void { + this.userAttributes = filteredUser.getAllUserAttributes(); + this.sendEventStream(this.buildIdentityEvent('login', filteredUser)); + } + + public onLogoutComplete(filteredUser: FilteredUser): void { + this.userAttributes = filteredUser.getAllUserAttributes(); + this.sendEventStream(this.buildIdentityEvent('logout', filteredUser)); + } + + public onModifyComplete(filteredUser: FilteredUser): void { + this.userAttributes = filteredUser.getAllUserAttributes(); + this.sendEventStream(this.buildIdentityEvent('modify_user', filteredUser)); + } + + /** + * Selects placements for Rokt Web SDK with merged attributes, filters, and experimentation options. + */ + public selectPlacements(options: Record): RoktSelection | Promise | undefined { + const attributes = ((options && (options.attributes as Record)) || {}) as Record; + const placementAttributes: Record = { ...this.userAttributes, ...attributes }; + + const filters = this.filters || {}; + const userAttributeFilters = (filters.userAttributeFilters as string[]) || []; + const filteredUser = filters.filteredUser || null; + const mpid = + filteredUser && filteredUser.getMPID && typeof filteredUser.getMPID === 'function' + ? filteredUser.getMPID() + : null; + + let filteredAttributes: Record; + + if (!filters) { + console.warn('Rokt Kit: No filters available, using user attributes'); + filteredAttributes = placementAttributes; + } else if (filters.filterUserAttributes) { + filteredAttributes = filters.filterUserAttributes(placementAttributes, userAttributeFilters); + } else { + filteredAttributes = placementAttributes; + } + + this.userAttributes = filteredAttributes; + + const optimizelyAttributes = this._onboardingExpProvider === 'Optimizely' ? this.fetchOptimizely() : {}; + + const filteredUserIdentities = this.returnUserIdentities(filteredUser); + + const localSessionAttributes = this.returnLocalSessionAttributes(); + + const selectPlacementsAttributes: Record = { + ...(filteredUserIdentities as Record), + ...filteredAttributes, + ...optimizelyAttributes, + ...localSessionAttributes, + mpid, + }; + + const selectPlacementsOptions: Record = { ...options, attributes: selectPlacementsAttributes }; + + const selection = this.launcher!.selectPlacements(selectPlacementsOptions); + + // After selection resolves, sync the Rokt session ID back to mParticle, then log + const logSelection = () => this.logSelectPlacementsEvent(selectPlacementsAttributes); + + void Promise.resolve(selection) + .then((sel) => sel?.context?.sessionId?.then((sessionId) => this.setRoktSessionId(sessionId))) + .catch(() => undefined) + .finally(logSelection); + + return selection; + } + + /** + * Passes attributes to the Rokt Web SDK for client-side hashing. + */ + public hashAttributes(attributes: Record): Promise> | null { + if (!this.isKitReady()) { + console.error('Rokt Kit: Not initialized'); + return null; + } + return this.launcher!.hashAttributes(attributes); + } + + /** + * Enables optional Integration Launcher extensions before selecting placements. + */ + public use(extensionName: string): Promise { + if (!this.isKitReady()) { + console.error('Rokt Kit: Not initialized'); + return Promise.reject(new Error('Rokt Kit: Not initialized')); + } + if (!extensionName || !isString(extensionName)) { + return Promise.reject(new Error('Rokt Kit: Invalid extension name')); + } + return this.launcher!.use(extensionName); + } +} + +// ============================================================ +// Kit registration +// ============================================================ + +function getId(): number { + return moduleId; +} + +function register(config: { kits?: Record }): void { + if (!config) { + window.console.log('You must pass a config object to register the kit ' + name); + return; + } + if (!isObject(config)) { + window.console.log("'config' must be an object. You passed in a " + typeof config); + return; + } + + if (isObject(config.kits)) { + (config.kits as Record)[name] = { + constructor: RoktKit, + }; + } else { + config.kits = {}; + config.kits[name] = { + constructor: RoktKit, + }; + } + window.console.log('Successfully registered ' + name + ' to your mParticle configuration'); +} + +if (typeof window !== 'undefined' && window.mParticle && mp().addForwarder) { + mp().addForwarder({ + name: name, + constructor: RoktKit, + getId: getId, + }); +} + +export { register }; diff --git a/test/.eslintrc b/test/.eslintrc deleted file mode 100644 index d6808a8..0000000 --- a/test/.eslintrc +++ /dev/null @@ -1,13 +0,0 @@ -{ - "extends": "../.eslintrc", - "env": { - "mocha": true - }, - "parserOptions": { - "ecmaVersion": 2020, - "sourceType": "module" - }, - "rules": { - "no-unused-expressions": "off" // Allows chai's expect(...).to.be.true - } -} \ No newline at end of file diff --git a/test/config.js b/test/config.js deleted file mode 100644 index fdcd7fc..0000000 --- a/test/config.js +++ /dev/null @@ -1,3 +0,0 @@ -window.mParticle.addForwarder = function (forwarder) { - window.mParticle.forwarder = new forwarder.constructor(); -}; \ No newline at end of file diff --git a/test/index.html b/test/index.html deleted file mode 100644 index 182e8c1..0000000 --- a/test/index.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - Mocha Tests - - - -
- - - - - - - - - - - - - - - - diff --git a/test/karma.config.js b/test/karma.config.js deleted file mode 100644 index 974b5ee..0000000 --- a/test/karma.config.js +++ /dev/null @@ -1,41 +0,0 @@ -const { DEBUG } = process.env || 'false'; - -const files = [ - '../node_modules/@mparticle/web-sdk/dist/mparticle.js', - '../node_modules/mocha/mocha.js', - '../node_modules/should/should.js', - 'config.js', - - '../dist/Rokt-Kit.iife.js', - - 'lib/mockhttprequest.js', - './test-bundle.js', -]; - -let browsers = ['ChromeHeadless', 'FirefoxHeadless']; -let singleRun = true; - -if (DEBUG === 'true') { - browsers = ['Chrome']; - singleRun = false; -} - -module.exports = function (config) { - config.set({ - frameworks: ['mocha', 'chai'], - files, - reporters: ['progress'], - port: 9876, - colors: true, - logLevel: config.LOG_INFO, - browsers, - concurrency: Infinity, - customLaunchers: { - FirefoxHeadless: { - base: 'Firefox', - flags: ['-headless'], - }, - }, - singleRun, - }); -}; diff --git a/test/lib/mockhttprequest.js b/test/lib/mockhttprequest.js deleted file mode 100644 index 42f7833..0000000 --- a/test/lib/mockhttprequest.js +++ /dev/null @@ -1,472 +0,0 @@ -/* eslint-disable no-undef*/ - -/* - * Mock XMLHttpRequest (see http://www.w3.org/TR/XMLHttpRequest) - * - * Written by Philipp von Weitershausen - * Released under the MIT license. - * http://www.opensource.org/licenses/mit-license.php - * - * For test interaction it exposes the following attributes: - * - * - method, url, urlParts, async, user, password - * - requestText - * - * as well as the following methods: - * - * - getRequestHeader(header) - * - setResponseHeader(header, value) - * - receive(status, data) - * - err(exception) - * - authenticate(user, password) - * - */ -function MockHttpRequest () { - // These are internal flags and data structures - this.error = false; - this.sent = false; - this.requestHeaders = {}; - this.responseHeaders = {}; -} -MockHttpRequest.prototype = { - withCredentials: true, - - statusReasons: { - 100: 'Continue', - 101: 'Switching Protocols', - 102: 'Processing', - 200: 'OK', - 201: 'Created', - 202: 'Accepted', - 203: 'Non-Authoritative Information', - 204: 'No Content', - 205: 'Reset Content', - 206: 'Partial Content', - 207: 'Multi-Status', - 300: 'Multiple Choices', - 301: 'Moved Permanently', - 302: 'Moved Temporarily', - 303: 'See Other', - 304: 'Not Modified', - 305: 'Use Proxy', - 307: 'Temporary Redirect', - 400: 'Bad Request', - 401: 'Unauthorized', - 402: 'Payment Required', - 403: 'Forbidden', - 404: 'Not Found', - 405: 'Method Not Allowed', - 406: 'Not Acceptable', - 407: 'Proxy Authentication Required', - 408: 'Request Time-out', - 409: 'Conflict', - 410: 'Gone', - 411: 'Length Required', - 412: 'Precondition Failed', - 413: 'Request Entity Too Large', - 414: 'Request-URI Too Large', - 415: 'Unsupported Media Type', - 416: 'Requested range not satisfiable', - 417: 'Expectation Failed', - 422: 'Unprocessable Entity', - 423: 'Locked', - 424: 'Failed Dependency', - 500: 'Internal Server Error', - 501: 'Not Implemented', - 502: 'Bad Gateway', - 503: 'Service Unavailable', - 504: 'Gateway Time-out', - 505: 'HTTP Version not supported', - 507: 'Insufficient Storage' - }, - - /*** State ***/ - - UNSENT: 0, - OPENED: 1, - HEADERS_RECEIVED: 2, - LOADING: 3, - DONE: 4, - readyState: 0, - - - /*** Request ***/ - - open: function (method, url, async, user, password) { - if (typeof method !== 'string') { - throw 'INVALID_METHOD'; - } - switch (method.toUpperCase()) { - case 'CONNECT': - case 'TRACE': - case 'TRACK': - throw 'SECURITY_ERR'; - - case 'DELETE': - case 'GET': - case 'HEAD': - case 'OPTIONS': - case 'POST': - case 'PUT': - method = method.toUpperCase(); - } - this.method = method; - - if (typeof url !== 'string') { - throw 'INVALID_URL'; - } - this.url = url; - this.urlParts = this.parseUri(url); - - if (async === undefined) { - async = true; - } - this.async = async; - this.user = user; - this.password = password; - - this.readyState = this.OPENED; - this.onreadystatechange(); - }, - - setRequestHeader: function (header, value) { - header = header.toLowerCase(); - - switch (header) { - case 'accept-charset': - case 'accept-encoding': - case 'connection': - case 'content-length': - case 'cookie': - case 'cookie2': - case 'content-transfer-encoding': - case 'date': - case 'expect': - case 'host': - case 'keep-alive': - case 'referer': - case 'te': - case 'trailer': - case 'transfer-encoding': - case 'upgrade': - case 'user-agent': - case 'via': - return; - } - if ((header.substr(0, 6) === 'proxy-') - || (header.substr(0, 4) === 'sec-')) { - return; - } - - // it's the first call on this header field - if (this.requestHeaders[header] === undefined) - {this.requestHeaders[header] = value;} - else { - var prev = this.requestHeaders[header]; - this.requestHeaders[header] = prev + ', ' + value; - } - - }, - - send: function (data) { - if ((this.readyState !== this.OPENED) - || this.sent) { - throw 'INVALID_STATE_ERR'; - } - if ((this.method === 'GET') || (this.method === 'HEAD')) { - data = null; - } - - //TODO set Content-Type header? - this.error = false; - this.sent = true; - this.onreadystatechange(); - - // fake send - this.requestText = data; - this.onsend(); - }, - - abort: function () { - this.responseText = null; - this.error = true; - for (var header in this.requestHeaders) { - delete this.requestHeaders[header]; - } - delete this.requestText; - this.onreadystatechange(); - this.onabort(); - this.readyState = this.UNSENT; - }, - - - /*** Response ***/ - - status: 0, - statusText: '', - - getResponseHeader: function (header) { - if ((this.readyState === this.UNSENT) - || (this.readyState === this.OPENED) - || this.error) { - return null; - } - return this.responseHeaders[header.toLowerCase()]; - }, - - getAllResponseHeaders: function () { - var r = ''; - for (var header in this.responseHeaders) { - if ((header === 'set-cookie') || (header === 'set-cookie2')) { - continue; - } - //TODO title case header - r += header + ': ' + this.responseHeaders[header] + '\r\n'; - } - return r; - }, - - responseText: '', - responseXML: undefined, //TODO - - - /*** See http://www.w3.org/TR/progress-events/ ***/ - - onload: function () { - // Instances should override this. - }, - - onprogress: function () { - // Instances should override this. - }, - - onerror: function () { - // Instances should override this. - }, - - onabort: function () { - // Instances should override this. - }, - - onreadystatechange: function () { - // Instances should override this. - }, - - - /*** Properties and methods for test interaction ***/ - - onsend: function () { - // Instances should override this. - }, - - getRequestHeader: function (header) { - return this.requestHeaders[header.toLowerCase()]; - }, - - setResponseHeader: function (header, value) { - this.responseHeaders[header.toLowerCase()] = value; - }, - - makeXMLResponse: function (data) { - var xmlDoc; - // according to specs from point 3.7.5: - // "1. If the response entity body is null terminate these steps - // and return null. - // 2. If final MIME type is not null, text/xml, application/xml, - // and does not end in +xml terminate these steps and return null. - var mimetype = this.getResponseHeader('Content-Type'); - mimetype = mimetype && mimetype.split(';', 1)[0]; - if ((mimetype == null) || (mimetype == 'text/xml') || - (mimetype == 'application/xml') || - (mimetype && mimetype.substring(mimetype.length - 4) == '+xml')) { - // Attempt to produce an xml response - // and it will fail if not a good xml - try { - if (window.DOMParser) { - var parser = new DOMParser(); - xmlDoc = parser.parseFromString(data, 'text/xml'); - } else { // Internet Explorer - xmlDoc = new ActiveXObject('Microsoft.XMLDOM'); - xmlDoc.async = 'false'; - xmlDoc.loadXML(data); - } - } catch (e) { - // according to specs from point 3.7.5: - // "3. Let document be a cookie-free Document object that - // represents the result of parsing the response entity body - // into a document tree following the rules from the XML - // specifications. If this fails (unsupported character - // encoding, namespace well-formedness error etc.), terminate - // these steps return null." - xmlDoc = null; - } - // parse errors also yield a null. - if ((xmlDoc && xmlDoc.parseError && xmlDoc.parseError.errorCode != 0) - || (xmlDoc && xmlDoc.documentElement && xmlDoc.documentElement.nodeName == 'parsererror') - || (xmlDoc && xmlDoc.documentElement && xmlDoc.documentElement.nodeName == 'html' - && xmlDoc.documentElement.firstChild && xmlDoc.documentElement.firstChild.nodeName == 'body' - && xmlDoc.documentElement.firstChild.firstChild && xmlDoc.documentElement.firstChild.firstChild.nodeName == 'parsererror')) { - xmlDoc = null; - } - } else { - // mimetype is specified, but not xml-ish - xmlDoc = null; - } - return xmlDoc; - }, - - // Call this to simulate a server response - receive: function (status, data) { - if ((this.readyState !== this.OPENED) || (!this.sent)) { - // Can't respond to unopened request. - throw 'INVALID_STATE_ERR'; - } - - this.status = status; - this.statusText = status + ' ' + this.statusReasons[status]; - this.readyState = this.HEADERS_RECEIVED; - this.onprogress(); - this.onreadystatechange(); - - this.responseText = data; - this.responseXML = this.makeXMLResponse(data); - - this.readyState = this.LOADING; - this.onprogress(); - this.onreadystatechange(); - - this.readyState = this.DONE; - this.onreadystatechange(); - this.onprogress(); - this.onload(); - }, - - // Call this to simulate a request error (e.g. NETWORK_ERR) - err: function (exception) { - if ((this.readyState !== this.OPENED) || (!this.sent)) { - // Can't respond to unopened request. - throw 'INVALID_STATE_ERR'; - } - - this.responseText = null; - this.error = true; - for (var header in this.requestHeaders) { - delete this.requestHeaders[header]; - } - this.readyState = this.DONE; - if (!this.async) { - throw exception; - } - this.onreadystatechange(); - this.onerror(); - }, - - // Convenience method to verify HTTP credentials - authenticate: function (user, password) { - if (this.user) { - return (user === this.user) && (password === this.password); - } - - if (this.urlParts.user) { - return ((user === this.urlParts.user) - && (password === this.urlParts.password)); - } - - // Basic auth. Requires existence of the 'atob' function. - var auth = this.getRequestHeader('Authorization'); - if (auth === undefined) { - return false; - } - if (auth.substr(0, 6) !== 'Basic ') { - return false; - } - if (typeof atob !== 'function') { - return false; - } - auth = atob(auth.substr(6)); - var pieces = auth.split(':'); - var requser = pieces.shift(); - var reqpass = pieces.join(':'); - return (user === requser) && (password === reqpass); - }, - - // Parse RFC 3986 compliant URIs. - // Based on parseUri by Steven Levithan - // See http://blog.stevenlevithan.com/archives/parseuri - parseUri: function (str) { - var pattern = /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/; - var key = ['source', 'protocol', 'authority', 'userInfo', 'user', - 'password', 'host', 'port', 'relative', 'path', - 'directory', 'file', 'query', 'anchor']; - var querypattern = /(?:^|&)([^&=]*)=?([^&]*)/g; - - var match = pattern.exec(str); - var uri = {}; - var i = 14; - while (i--) { - uri[key[i]] = match[i] || ''; - } - - uri.queryKey = {}; - uri[key[12]].replace(querypattern, function ($0, $1, $2) { - if ($1) { - uri.queryKey[$1] = $2; - } - }); - - return uri; - } -}; - - -/* - * A small mock "server" that intercepts XMLHttpRequest calls and - * diverts them to your handler. - * - * Usage: - * - * 1. Initialize with either - * var server = new MockHttpServer(your_request_handler); - * or - * var server = new MockHttpServer(); - * server.handle = function (request) { ... }; - * - * 2. Call server.start() to start intercepting all XMLHttpRequests. - * - * 3. Do your tests. - * - * 4. Call server.stop() to tear down. - * - * 5. Profit! - */ -function MockHttpServer (handler) { - if (handler) { - this.handle = handler; - } -} -MockHttpServer.prototype = { - requests: [], - start: function () { - var self = this; - - function Request () { - this.onsend = function () { - self.requests.push(this); - self.handle(this); - }; - MockHttpRequest.apply(this, arguments); - } - Request.prototype = MockHttpRequest.prototype; - - window.OriginalHttpRequest = window.XMLHttpRequest; - window.XMLHttpRequest = Request; - }, - - stop: function () { - window.XMLHttpRequest = window.OriginalHttpRequest; - }, - - handle: function () { - // Instances should override this. - } -}; diff --git a/test/src/tests.js b/test/src/tests.js deleted file mode 100644 index 87e8058..0000000 --- a/test/src/tests.js +++ /dev/null @@ -1,6873 +0,0 @@ -/* eslint-env es6, mocha */ -/* eslint-parser babel-eslint */ - -const packageVersion = require('../../package.json').version; -const sdkVersion = 'mParticle_wsdkv_1.2.3'; -const kitVersion = 'kitv_' + packageVersion; - -// Reporting service classes are exposed via testHelpers after kit init - -const waitForCondition = async (conditionFn, timeout = 200, interval = 10) => { - return new Promise((resolve, reject) => { - const startTime = Date.now(); - - (function poll() { - if (conditionFn()) { - return resolve(undefined); - } else if (Date.now() - startTime > timeout) { - return reject(new Error('Timeout waiting for condition')); - } else { - setTimeout(poll, interval); - } - })(); - }); -}; - -describe('Rokt Forwarder', () => { - // Reporting service classes from testHelpers (populated after kit init) - var _ReportingTransport; - var ErrorReportingService; - var LoggingService; - var RateLimiter; - var ErrorCodes; - var WSDKErrorSeverity; - - var EventType = { - Unknown: 0, - Navigation: 1, - Location: 2, - Search: 3, - Transaction: 4, - UserContent: 5, - UserPreference: 6, - Social: 7, - Other: 8, - Media: 9, - }; - var MessageType = { - SessionStart: 1, - SessionEnd: 2, - PageView: 3, - PageEvent: 4, - CrashReport: 5, - OptOut: 6, - Commerce: 16, - }; - var ReportingService = function () { - var self = this; - - this.id = null; - this.event = null; - - this.cb = function (forwarder, event) { - self.id = forwarder.id; - self.event = event; - }; - - this.reset = function () { - this.id = null; - this.event = null; - }; - }; - var reportService = new ReportingService(); - - // -------------------DO NOT EDIT ANYTHING ABOVE THIS LINE----------------------- - // -------------------START EDITING BELOW:----------------------- - // -------------------mParticle stubs - Add any additional stubbing to our methods as needed----------------------- - mParticle.getEnvironment = function () { - return 'development'; - }; - mParticle.getVersion = function () { - return '1.2.3'; - }; - mParticle.Identity = { - getCurrentUser: function () { - return { - getMPID: function () { - return '123'; - }, - }; - }, - }; - mParticle._Store = { - localSessionAttributes: {}, - }; - mParticle.sessionManager = { - getSession: function () { - return 'test-mp-session-id'; - }, - }; - mParticle._getActiveForwarders = function () { - return []; - }; - mParticle.generateHash = function (input) { - return 'hashed-<' + input + '>-value'; - }; - // Mock for logEvent to capture custom event logging - mParticle.loggedEvents = []; - mParticle.logEvent = function (eventName, eventType, eventAttributes) { - mParticle.loggedEvents.push({ - eventName: eventName, - eventType: eventType, - eventAttributes: eventAttributes, - }); - }; - // -------------------START EDITING BELOW:----------------------- - var MockRoktForwarder = function () { - var self = this; - - this.initializeCalled = false; - this.isInitialized = false; - this.accountId = null; - this.sandbox = null; - this.integrationName = null; - this.createLauncherCalled = false; - this.createLocalLauncherCalled = false; - - this.createLauncher = function (options) { - self.accountId = options.accountId; - self.integrationName = options.integrationName; - self.noFunctional = options.noFunctional; - self.noTargeting = options.noTargeting; - self.mpSessionId = options.mpSessionId; - self.createLauncherCalled = true; - self.isInitialized = true; - self.sandbox = options.sandbox; - - return Promise.resolve({ - then: function (callback) { - callback(); - }, - }); - }; - - this.createLocalLauncher = function (options) { - self.accountId = options.accountId; - self.integrationName = options.integrationName; - self.noFunctional = options.noFunctional; - self.noTargeting = options.noTargeting; - self.mpSessionId = options.mpSessionId; - self.createLocalLauncherCalled = true; - self.isInitialized = true; - self.sandbox = options.sandbox; - - return { - selectPlacements: function () {}, - hashAttributes: function () { - throw new Error('hashAttributes not implemented'); - }, - use: function () { - throw new Error('use not implemented'); - }, - }; - }; - - this.currentLauncher = function () {}; - }; - - before(async () => { - // Run a minimal init in testMode to populate testHelpers - window.Rokt = new MockRoktForwarder(); - window.mParticle.Rokt = window.Rokt; - window.mParticle.Rokt.attachKit = async (kit) => { - window.mParticle.Rokt.kit = kit; - Promise.resolve(); - }; - window.mParticle.Rokt.filters = { - userAttributesFilters: [], - filterUserAttributes: function (attributes) { - return attributes; - }, - filteredUser: { - getMPID: function () { - return '123'; - }, - }, - }; - await mParticle.forwarder.init( - { accountId: '000000' }, - reportService.cb, - true, - null, - {} - ); - - var testHelpers = window.mParticle.forwarder.testHelpers; - _ReportingTransport = testHelpers && testHelpers.ReportingTransport; - ErrorReportingService = - testHelpers && testHelpers.ErrorReportingService; - LoggingService = testHelpers && testHelpers.LoggingService; - RateLimiter = testHelpers && testHelpers.RateLimiter; - ErrorCodes = testHelpers && testHelpers.ErrorCodes; - WSDKErrorSeverity = testHelpers && testHelpers.WSDKErrorSeverity; - }); - - beforeEach(() => { - window.Rokt = new MockRoktForwarder(); - window.mParticle.Rokt = window.Rokt; - }); - - afterEach(() => { - window.mParticle.forwarder.userAttributes = {}; - delete window.mParticle.forwarder.launcherOptions; - delete window.mParticle.Rokt.launcherOptions; - }); - - describe('#initForwarder', () => { - beforeEach(() => { - window.Rokt = new MockRoktForwarder(); - window.mParticle.Rokt = window.Rokt; - window.mParticle.Rokt.attachKitCalled = false; - window.mParticle.Rokt.attachKit = async (kit) => { - window.mParticle.Rokt.attachKitCalled = true; - window.mParticle.Rokt.kit = kit; - Promise.resolve(); - }; - window.mParticle.Rokt.filters = { - userAttributesFilters: [], - filterUserAttributes: function (attributes) { - return attributes; - }, - filteredUser: { - getMPID: function () { - return '123'; - }, - }, - }; - }); - - it('should initialize the Rokt Web SDK', async () => { - await mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true, - null, - {} - ); - - window.Rokt.accountId.should.equal('123456'); - window.Rokt.createLauncherCalled.should.equal(true); - }); - - it('should set sandbox to true if sandbox is true in launcherOptions', async () => { - window.mParticle.Rokt.launcherOptions = { - sandbox: true, - }; - - await mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true - ); - - window.Rokt.createLauncherCalled.should.equal(true); - window.Rokt.sandbox.should.equal(true); - }); - - it('should set sandbox to false if sandbox is false in launcherOptions', async () => { - window.mParticle.Rokt.launcherOptions = { - sandbox: false, - }; - - await mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true - ); - - window.Rokt.createLauncherCalled.should.equal(true); - window.Rokt.sandbox.should.equal(false); - }); - - it('should set optional settings from launcherOptions', async () => { - window.mParticle.Rokt.launcherOptions = { - integrationName: 'customName', - noFunctional: true, - noTargeting: true, - }; - - await mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true, - null, - {}, - null, - null, - null - ); - - const expectedIntegrationName = `${sdkVersion}_${kitVersion}_customName`; - - window.Rokt.createLauncherCalled.should.equal(true); - window.Rokt.accountId.should.equal('123456'); - window.Rokt.integrationName.should.equal(expectedIntegrationName); - window.Rokt.noFunctional.should.equal(true); - window.Rokt.noTargeting.should.equal(true); - }); - - it('should set the filters on the forwarder', async () => { - await mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true, - null, - {} - ); - - // Wait for initialization to complete (after launcher is created) - await waitForCondition(() => { - return window.mParticle.forwarder.isInitialized; - }); - - window.mParticle.Rokt.kit.filters.should.deepEqual({ - userAttributesFilters: [], - filterUserAttributes: function (attributes) { - return attributes; - }, - filteredUser: { - getMPID: function () { - return '123'; - }, - }, - }); - - window.mParticle.Rokt.kit.filters.filteredUser - .getMPID() - .should.equal('123'); - }); - - it('should set integrationName in the correct format', async () => { - window.Rokt = new MockRoktForwarder(); - window.mParticle.Rokt = window.Rokt; - window.mParticle.Rokt.attachKitCalled = false; - window.mParticle.Rokt.attachKit = async () => { - window.mParticle.Rokt.attachKitCalled = true; - return Promise.resolve(); - }; - - await mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true - ); - - window.Rokt.integrationName.should.equal( - `${sdkVersion}_${kitVersion}` - ); - }); - - it('should set integrationName on kit instance after attaching', async () => { - window.Rokt = new MockRoktForwarder(); - window.mParticle.Rokt = window.Rokt; - window.mParticle.Rokt.attachKitCalled = false; - - window.mParticle.Rokt.attachKit = async (kit) => { - window.mParticle.Rokt.attachKitCalled = true; - window.mParticle.Rokt.kit = kit; - return Promise.resolve(); - }; - - await mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true - ); - - // Wait for initialization to complete - await waitForCondition(() => window.mParticle.Rokt.isInitialized); - - window.mParticle.Rokt.kit.integrationName.should.equal( - `${sdkVersion}_${kitVersion}` - ); - }); - - it('should set integrationName on kit instance with custom name when provided', async () => { - const customName = 'myCustomName'; - - window.Rokt = new MockRoktForwarder(); - window.mParticle.Rokt = window.Rokt; - window.mParticle.Rokt.attachKitCalled = false; - - window.mParticle.Rokt.attachKit = async (kit) => { - window.mParticle.Rokt.attachKitCalled = true; - window.mParticle.Rokt.kit = kit; - return Promise.resolve(); - }; - - window.mParticle.Rokt.launcherOptions = { - integrationName: customName, - }; - - await mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true - ); - - // Wait for initialization to complete - await waitForCondition(() => window.mParticle.Rokt.isInitialized); - - window.mParticle.Rokt.kit.integrationName.should.equal( - `${sdkVersion}_${kitVersion}_${customName}` - ); - }); - - it('should have integrationName available on kit after initialization', async () => { - window.Rokt = new MockRoktForwarder(); - window.mParticle.Rokt = window.Rokt; - window.mParticle.Rokt.attachKitCalled = false; - - window.mParticle.Rokt.attachKit = async (kit) => { - window.mParticle.Rokt.attachKitCalled = true; - window.mParticle.Rokt.kit = kit; - return Promise.resolve(); - }; - - await mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true - ); - - // Wait for initialization to complete - await waitForCondition(() => window.mParticle.Rokt.isInitialized); - - window.mParticle.Rokt.attachKitCalled.should.equal(true); - window.mParticle.Rokt.kit.integrationName.should.be.a.String(); - window.mParticle.Rokt.kit.integrationName.should.not.be.empty(); - }); - - it('should not mutate the global launcherOptions object during initialization', async () => { - const originalIntegrationName = 'globalIntegrationName'; - - window.Rokt = new MockRoktForwarder(); - window.mParticle.Rokt = window.Rokt; - window.mParticle.Rokt.attachKitCalled = false; - window.mParticle.Rokt.attachKit = async () => { - window.mParticle.Rokt.attachKitCalled = true; - return Promise.resolve(); - }; - - // Set up the global launcherOptions with a custom integration name - window.mParticle.Rokt.launcherOptions = { - integrationName: originalIntegrationName, - sandbox: true, - }; - - // Store reference to verify it doesn't get mutated - const originalLauncherOptions = - window.mParticle.Rokt.launcherOptions; - - await mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true, - null, - {}, - null, - null, - null - ); - - originalLauncherOptions.integrationName.should.equal( - 'globalIntegrationName' - ); - originalLauncherOptions.sandbox.should.equal(true); - - // Verify the kit still gets the processed integration name - const expectedProcessedName = `${sdkVersion}_${kitVersion}_${originalIntegrationName}`; - window.Rokt.integrationName.should.equal(expectedProcessedName); - }); - - it('should initialize the kit with placement event mapping lookup from a config', async () => { - await mParticle.forwarder.init( - { - accountId: '123456', - placementEventMapping: JSON.stringify([ - { - jsmap: '-1484452948', - map: '-5208850776883573773', - maptype: 'EventClass.Id', - value: 'foo-mapped-flag', - }, - { - jsmap: '1838502119', - map: '1324617889422969328', - maptype: 'EventClass.Id', - value: 'ad_viewed_test', - }, - ]), - }, - reportService.cb, - true, - null, - {} - ); - - // Wait for initialization to complete (after launcher is created) - await waitForCondition(() => window.mParticle.Rokt.isInitialized); - - window.mParticle.forwarder.placementEventMappingLookup.should.deepEqual( - { - '-1484452948': 'foo-mapped-flag', - 1838502119: 'ad_viewed_test', - } - ); - }); - }); - - describe('#hashAttributes', () => { - beforeEach(() => { - window.Rokt = new MockRoktForwarder(); - window.mParticle.Rokt = window.Rokt; - window.mParticle.Rokt.attachKitCalled = false; - window.mParticle.Rokt.attachKit = async (kit) => { - window.mParticle.Rokt.attachKitCalled = true; - window.mParticle.Rokt.kit = kit; - Promise.resolve(); - }; - window.mParticle.forwarder.launcher = { - hashAttributes: function (attributes) { - // Mocking the hashAttributes method to show that - // the attributes will be transformed by the launcher's - // hashAttributes method. - const hashedAttributes = {}; - for (const key in attributes) { - if (attributes.hasOwnProperty(key)) { - hashedAttributes[key + '-hash'] = - 'hashed-' + attributes[key]; - } - } - window.mParticle.Rokt.hashedAttributes = hashedAttributes; - window.mParticle.Rokt.hashAttributesCalled = true; - - return Promise.resolve(hashedAttributes); - }, - }; - }); - - it('should call launcher.hashAttributes with passed through attributes when fully initialized', function () { - // Ensure both initialization conditions are met - window.mParticle.forwarder.isInitialized = true; - window.mParticle.forwarder.launcher = { - hashAttributes: function (attributes) { - window.mParticle.Rokt.hashAttributesOptions = attributes; - window.mParticle.Rokt.hashAttributesCalled = true; - return { - 'test-attribute': 'hashed-value', - }; - }, - }; - - var attributes = { - 'test-attribute': 'test-value', - }; - - window.mParticle.forwarder.hashAttributes(attributes); - - window.Rokt.hashAttributesCalled.should.equal(true); - window.Rokt.hashAttributesOptions.should.deepEqual(attributes); - }); - - it('should return null when launcher exists but kit is not initialized', function () { - // Set launcher but ensure isInitialized is false - window.mParticle.forwarder.isInitialized = false; - window.mParticle.forwarder.launcher = { - hashAttributes: function () {}, - }; - - var result = window.mParticle.forwarder.hashAttributes({ - 'test-attribute': 'test-value', - }); - - (result === null).should.equal(true); - }); - - it('should log an error when called before initialization', function () { - var errorLogged = false; - var errorMessage = null; - window.console.error = function (message) { - errorLogged = true; - errorMessage = message; - }; - - // Ensure kit is not initialized - window.mParticle.forwarder.isInitialized = false; - window.mParticle.forwarder.launcher = null; - - window.mParticle.forwarder.hashAttributes({ - 'test-attribute': 'test-value', - }); - - errorLogged.should.equal(true); - errorMessage.should.equal('Rokt Kit: Not initialized'); - }); - - it('should return null when kit is initialized but launcher is missing', function () { - // Mock isInitialized but remove launcher - window.mParticle.forwarder.isInitialized = true; - window.mParticle.forwarder.launcher = null; - - var result = window.mParticle.forwarder.hashAttributes({ - 'test-attribute': 'test-value', - }); - - (result === null).should.equal(true); - }); - - it('should log an error when kit is initialized but launcher is missing', function () { - var errorLogged = false; - var errorMessage = null; - window.console.error = function (message) { - errorLogged = true; - errorMessage = message; - }; - - window.mParticle.forwarder.isInitialized = true; - window.mParticle.forwarder.launcher = null; - - window.mParticle.forwarder.hashAttributes({ - 'test-attribute': 'test-value', - }); - - errorLogged.should.equal(true); - errorMessage.should.equal('Rokt Kit: Not initialized'); - }); - - it('should return hashed attributes from launcher', async () => { - await window.mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true, - null, - {} - ); - - const result = await window.mParticle.forwarder.hashAttributes({ - 'test-attribute': 'test-value', - }); - - result.should.deepEqual({ - 'test-attribute-hash': 'hashed-test-value', - }); - }); - }); - - describe('#attachLauncher', () => { - let mockMessageQueue; - - beforeEach(() => { - mockMessageQueue = []; - - // Reset forwarder state between tests - window.mParticle.forwarder.isInitialized = false; - - window.Rokt = new MockRoktForwarder(); - window.mParticle.Rokt = window.Rokt; - window.mParticle.Rokt.attachKitCalled = false; - - // Ensure currentLauncher is undefined to trigger script appending - window.Rokt.currentLauncher = undefined; - - // Set attachKit as async to allow for await calls in the test - // This is necessary to simiulate a race condition between the - // core sdk and the Rokt forwarder - window.mParticle.Rokt.attachKit = async (kit) => { - window.mParticle.Rokt.attachKitCalled = true; - window.mParticle.Rokt.kit = kit; - - // Call queued messages - mockMessageQueue.forEach((message) => message()); - mockMessageQueue = []; - - return Promise.resolve(); - }; - window.mParticle.Rokt.filters = { - userAttributesFilters: [], - filterUserAttributes: function (attributes) { - return attributes; - }, - filteredUser: { - getMPID: function () { - return '123'; - }, - }, - }; - window.mParticle.config = undefined; - Math.random = () => 1; - - window.mParticle.captureTiming = function (metricName) { - window.mParticle.Rokt.capturedPerformanceMetric = metricName; - }; - }); - - it('should add a performance marker when the script is appended', async () => { - var savedRokt = window.mParticle.Rokt; - window.Rokt = undefined; - window.mParticle.Rokt = { - domain: 'apps.rokt.com', - attachKit: async () => Promise.resolve(), - filters: savedRokt.filters, - }; - - await window.mParticle.forwarder.init( - { accountId: '123456' }, - reportService.cb, - false, - null, - {} - ); - - window.mParticle.Rokt.capturedPerformanceMetric.should.equal( - 'mp:RoktScriptAppended' - ); - }); - - it('should create a remote launcher if the partner is not in the local launcher test group', async () => { - await window.mParticle.forwarder.init( - { accountId: '123456' }, - reportService.cb, - true, - null, - {} - ); - - window.mParticle.Rokt.createLauncherCalled.should.equal(true); - window.mParticle.Rokt.createLocalLauncherCalled.should.equal(false); - }); - - it('should create a local launcher if the partner is in the local launcher test group', async () => { - window.mParticle.config = { - isLocalLauncherEnabled: true, - }; - - await window.mParticle.forwarder.init( - { accountId: '123456' }, - reportService.cb, - true, - null, - {} - ); - - window.mParticle.Rokt.createLauncherCalled.should.equal(false); - window.mParticle.Rokt.createLocalLauncherCalled.should.equal(true); - }); - - it('should create a remote launcher if the partner is in the local launcher test group but the random number is below the thresholds', async () => { - window.mParticle.config = { - isLocalLauncherEnabled: true, - }; - - Math.random = () => 0; - - await window.mParticle.forwarder.init( - { accountId: '123456' }, - reportService.cb, - true, - null, - {} - ); - - window.mParticle.Rokt.createLauncherCalled.should.equal(true); - window.mParticle.Rokt.createLocalLauncherCalled.should.equal(false); - }); - - it('should create a local launcher if the partner is in the local launcher test group but the random number is above the thresholds', async () => { - window.mParticle.config = { - isLocalLauncherEnabled: true, - }; - - Math.random = () => 1; - - await window.mParticle.forwarder.init( - { accountId: '123456' }, - reportService.cb, - true, - null, - {} - ); - - window.mParticle.Rokt.createLauncherCalled.should.equal(false); - window.mParticle.Rokt.createLocalLauncherCalled.should.equal(true); - }); - - it('should call attachKit', async () => { - await window.mParticle.forwarder.init( - { accountId: '123456' }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition(() => window.mParticle.Rokt.attachKitCalled); - - window.mParticle.Rokt.attachKitCalled.should.equal(true); - }); - - it('should set isInitialized to true', async () => { - await window.mParticle.forwarder.init( - { accountId: '123456' }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition(() => window.mParticle.Rokt.attachKitCalled); - - window.mParticle.forwarder.isInitialized.should.equal(true); - }); - - // This test is to ensure the kit is initialized before attaching to the Rokt manager - // so we can ensure that the Rokt Manager's message queue is processed and that - // all the isReady() checks are properly handled in by the Rokt Manager. - // This is to validate in case a bug that was found in the Rokt Manager's - // queueing logic regresses. - it('should initialize the kit before calling queued messages', async () => { - let queuedMessageCalled = false; - let wasKitInitializedFirst = false; - - const queuedMessage = () => { - wasKitInitializedFirst = - window.mParticle.Rokt.kit && - window.mParticle.Rokt.kit.isInitialized; - queuedMessageCalled = true; - }; - - mockMessageQueue.push(queuedMessage); - - await window.mParticle.forwarder.init( - { accountId: '123456' }, - reportService.cb, - true, - null, - {} - ); - - window.mParticle.forwarder.isInitialized.should.equal(false); - queuedMessageCalled.should.equal(false); - - await waitForCondition(() => window.mParticle.Rokt.attachKitCalled); - - window.mParticle.forwarder.isInitialized.should.equal(true); - queuedMessageCalled.should.equal(true); - - wasKitInitializedFirst.should.equal(true); - - mockMessageQueue.length.should.equal(0); - }); - - it('should call createLauncher when launcher is embedded and not yet initialized', async () => { - await window.mParticle.forwarder.init( - { accountId: '123456' }, - reportService.cb, - false, - null, - {} - ); - - await waitForCondition(() => window.mParticle.Rokt.attachKitCalled); - - window.mParticle.Rokt.createLauncherCalled.should.equal(true); - }); - - it('should pass mpSessionId from mParticle sessionManager to createLauncher', async () => { - window.mParticle.sessionManager = { - getSession: function () { - return 'my-mp-session-123'; - }, - }; - - await window.mParticle.forwarder.init( - { accountId: '123456' }, - reportService.cb, - true, - null, - {} - ); - - window.mParticle.Rokt.mpSessionId.should.equal('my-mp-session-123'); - }); - - it('should not pass mpSessionId when sessionManager is unavailable', async () => { - delete window.mParticle.sessionManager; - - await window.mParticle.forwarder.init( - { accountId: '123456' }, - reportService.cb, - true, - null, - {} - ); - - (window.mParticle.Rokt.mpSessionId === undefined).should.equal( - true - ); - }); - }); - - describe('#selectPlacements', () => { - beforeEach(() => { - window.Rokt = new MockRoktForwarder(); - window.mParticle.Rokt = window.Rokt; - window.mParticle.Rokt.attachKit = async () => { - window.mParticle.Rokt.attachKitCalled = true; - return Promise.resolve(); - }; - mParticle.loggedEvents = []; - window.mParticle.Rokt.setLocalSessionAttribute = function ( - key, - value - ) { - mParticle._Store.localSessionAttributes[key] = value; - }; - window.mParticle.Rokt.getLocalSessionAttributes = function () { - return mParticle._Store.localSessionAttributes; - }; - window.mParticle.Rokt.store = window.mParticle._Store; - window.mParticle.Rokt.store.localSessionAttributes = {}; - window.mParticle.forwarder.launcher = { - selectPlacements: function (options) { - window.mParticle.Rokt.selectPlacementsOptions = options; - window.mParticle.Rokt.selectPlacementsCalled = true; - }, - }; - window.mParticle.forwarder.filters = { - userAttributesFilters: [], - filterUserAttributes: function (attributes) { - return attributes; - }, - filteredUser: { - getMPID: function () { - return '123'; - }, - }, - }; - }); - - describe('Default initialization', () => { - it('should call launcher.selectPlacements with all passed through options', async () => { - await window.mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true, - null, - {} - ); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: { - test: 'test', - }, - }); - - window.Rokt.selectPlacementsCalled.should.equal(true); - window.Rokt.selectPlacementsOptions.should.deepEqual({ - identifier: 'test-placement', - attributes: { - test: 'test', - mpid: '123', - }, - }); - }); - - it('should collect mpid and send to launcher.selectPlacements', async () => { - await window.mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true, - null, - { - 'user-attribute': 'user-attribute-value', - } - ); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: { - 'user-attribute': 'user-attribute-value', - }, - }); - - window.Rokt.selectPlacementsCalled.should.equal(true); - window.Rokt.selectPlacementsOptions.should.deepEqual({ - identifier: 'test-placement', - attributes: { - 'user-attribute': 'user-attribute-value', - mpid: '123', - }, - }); - }); - - it('should collect local session attributes and send to launcher.selectPlacements', async () => { - window.mParticle.Rokt.store.localSessionAttributes = { - 'custom-local-attribute': true, - 'secondary-local-attribute': true, - }; - - await window.mParticle.forwarder.init( - { - accountId: '123456', - placementEventMapping: JSON.stringify([ - { - jsmap: 'test-event-hash', - map: 'test-event-map', - maptype: 'EventClass.Id', - value: 'test-mapped-flag', - }, - ]), - }, - reportService.cb, - true - ); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: { - 'test-attribute': 'test-value', - }, - }); - - window.Rokt.selectPlacementsCalled.should.equal(true); - window.Rokt.selectPlacementsOptions.should.deepEqual({ - identifier: 'test-placement', - attributes: { - mpid: '123', - 'test-attribute': 'test-value', - 'custom-local-attribute': true, - 'secondary-local-attribute': true, - }, - }); - }); - - it('should not throw an error if getLocalSessionAttributes is not available', async () => { - let errorLogged = false; - const originalConsoleError = console.error; - console.error = function (message) { - if ( - message && - message.indexOf && - message.indexOf( - 'Error getting local session attributes' - ) !== -1 - ) { - errorLogged = true; - } - originalConsoleError.apply(console, arguments); - }; - - delete window.mParticle.Rokt.getLocalSessionAttributes; - - await window.mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true - ); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: { - 'test-attribute': 'test-value', - }, - }); - - errorLogged.should.equal(false); - - console.error = originalConsoleError; - }); - }); - - describe('User Attributes', () => { - it('should call launcher.selectPlacements with filtered user attributes', async () => { - window.mParticle.forwarder.filters.filterUserAttributes = - function () { - return { - 'user-attribute': 'user-attribute-value', - 'unfiltered-attribute': 'unfiltered-value', - }; - }; - - await window.mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true, - null, - {} - ); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: { - 'unfiltered-attribute': 'unfiltered-value', - 'filtered-attribute': 'filtered-value', - }, - }); - - window.Rokt.selectPlacementsCalled.should.equal(true); - window.Rokt.selectPlacementsOptions.should.deepEqual({ - identifier: 'test-placement', - attributes: { - 'user-attribute': 'user-attribute-value', - 'unfiltered-attribute': 'unfiltered-value', - mpid: '123', - }, - }); - }); - - it('should filter user attributes through filterUserAttributes function before sending to selectPlacements', async () => { - // Mocked filterUserAttributes function will return filtered attributes - // based on the config passed in the init method and will ultimately - // remove any attributes from the init method that are filtered. - // Also, any initial attributes from the init call that have updated - // durring runtime should be returned by the filterUserAttribute method. - window.mParticle.forwarder.filters.filterUserAttributes = - function () { - return { - 'user-attribute': 'user-attribute-value', - 'unfiltered-attribute': 'unfiltered-value', - 'changed-attribute': 'new-value', - }; - }; - - await window.mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true, - null, - { - // These should be filtered out - 'blocked-attribute': 'blocked-value', - 'initial-user-attribute': - 'initial-user-attribute-value', - - // This should be updated - 'changed-attribute': 'old-value', - } - ); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: { - // This should pass through - 'unfiltered-attribute': 'unfiltered-value', - - // This should be filtered out - 'filtered-attribute': 'filtered-value', - }, - }); - - window.Rokt.selectPlacementsCalled.should.equal(true); - window.Rokt.selectPlacementsOptions.should.deepEqual({ - identifier: 'test-placement', - attributes: { - 'user-attribute': 'user-attribute-value', - 'unfiltered-attribute': 'unfiltered-value', - 'changed-attribute': 'new-value', - mpid: '123', - }, - }); - }); - }); - - describe('Identity handling', () => { - beforeEach(() => { - window.Rokt = new MockRoktForwarder(); - window.mParticle.Rokt = window.Rokt; - window.mParticle.Rokt.attachKitCalled = false; - window.mParticle.Rokt.attachKit = async (kit) => { - window.mParticle.Rokt.attachKitCalled = true; - window.mParticle.Rokt.kit = kit; - Promise.resolve(); - }; - window.mParticle.Rokt.setLocalSessionAttribute = function ( - key, - value - ) { - mParticle._Store.localSessionAttributes[key] = value; - }; - window.mParticle.Rokt.getLocalSessionAttributes = function () { - return mParticle._Store.localSessionAttributes; - }; - window.mParticle.forwarder.launcher = { - selectPlacements: function (options) { - window.mParticle.Rokt.selectPlacementsOptions = options; - window.mParticle.Rokt.selectPlacementsCalled = true; - }, - }; - }); - - it('should send userAttributes if userIdentities is null but userAttributes exists', async () => { - window.mParticle.Rokt.filters = { - userAttributeFilters: [], - filterUserAttributes: function (attributes) { - return attributes; - }, - filteredUser: { - getMPID: function () { - return 'abc'; - }, - getUserIdentities: function () { - return { userIdentities: {} }; - }, - }, - }; - - // Set up the createLauncher to properly resolve asynchronously - window.Rokt.createLauncher = async function () { - return Promise.resolve({ - selectPlacements: function (options) { - window.mParticle.Rokt.selectPlacementsOptions = - options; - window.mParticle.Rokt.selectPlacementsCalled = true; - }, - }); - }; - - await window.mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true, - null, - { - 'test-attribute': 'test-value', - } - ); - - // Wait for initialization to complete (after launcher is created) - await waitForCondition(() => { - return window.mParticle.forwarder.isInitialized; - }); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: {}, - }); - - window.Rokt.selectPlacementsOptions.attributes.should.deepEqual( - { - 'test-attribute': 'test-value', - mpid: 'abc', - } - ); - }); - - it('should send userIdentities when userAttributes is null but userIdentities exists', async () => { - window.mParticle.Rokt.filters = { - userAttributeFilters: [], - filterUserAttributes: function () { - return {}; - }, - filteredUser: { - getMPID: function () { - return '234'; - }, - getUserIdentities: function () { - return { - userIdentities: { - customerid: 'customer123', - email: 'test@example.com', - }, - }; - }, - }, - }; - - // Set up the createLauncher to properly resolve asynchronously - window.Rokt.createLauncher = async function () { - return Promise.resolve({ - selectPlacements: function (options) { - window.mParticle.Rokt.selectPlacementsOptions = - options; - window.mParticle.Rokt.selectPlacementsCalled = true; - }, - }); - }; - await window.mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true, - null, - {} - ); - // Wait for initialization to complete (after launcher is created) - await waitForCondition(() => { - return window.mParticle.forwarder.isInitialized; - }); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: {}, - }); - - window.Rokt.selectPlacementsOptions.attributes.should.deepEqual( - { - customerid: 'customer123', - email: 'test@example.com', - mpid: '234', - } - ); - }); - - it('should send userAttributes and userIdentities if both exist', async () => { - window.mParticle.Rokt.filters = { - userAttributeFilters: [], - filterUserAttributes: function (attributes) { - return attributes; - }, - filteredUser: { - getMPID: function () { - return '123'; - }, - getUserIdentities: function () { - return { - userIdentities: { - customerid: 'customer123', - email: 'test@example.com', - }, - }; - }, - }, - }; - - // Set up the createLauncher to properly resolve asynchronously - window.Rokt.createLauncher = async function () { - return Promise.resolve({ - selectPlacements: function (options) { - window.mParticle.Rokt.selectPlacementsOptions = - options; - window.mParticle.Rokt.selectPlacementsCalled = true; - }, - }); - }; - - await window.mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true, - null, - { - 'test-attribute': 'test-value', - } - ); - - // Wait for initialization to complete (after launcher is created) - await waitForCondition(() => { - return window.mParticle.forwarder.isInitialized; - }); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: {}, - }); - - window.Rokt.selectPlacementsOptions.attributes.should.deepEqual( - { - 'test-attribute': 'test-value', - customerid: 'customer123', - email: 'test@example.com', - mpid: '123', - } - ); - }); - - it('should not send userIdentities if filteredUser is null', async () => { - window.mParticle.Rokt.filters = { - userAttributeFilters: [], - filterUserAttributes: function (attributes) { - return attributes; - }, - filteredUser: null, - }; - - // Set up the createLauncher to properly resolve asynchronously - window.Rokt.createLauncher = async function () { - return Promise.resolve({ - selectPlacements: function (options) { - window.mParticle.Rokt.selectPlacementsOptions = - options; - window.mParticle.Rokt.selectPlacementsCalled = true; - }, - }); - }; - - await window.mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true, - null, - { - 'test-attribute': 'test-value', - } - ); - - // Wait for initialization to complete (after launcher is created) - await waitForCondition(() => { - return window.mParticle.forwarder.isInitialized; - }); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: {}, - }); - - window.Rokt.selectPlacementsOptions.attributes.should.deepEqual( - { - 'test-attribute': 'test-value', - mpid: null, - } - ); - }); - - it('should not send userIdentities if getUserIdentities function does not exist', async () => { - window.mParticle.Rokt.filters = { - userAttributeFilters: [], - filterUserAttributes: function (attributes) { - return attributes; - }, - filteredUser: { - getMPID: function () { - return '123'; - }, - // getUserIdentities is intentionally missing - }, - }; - - window.Rokt.createLauncher = async function () { - return Promise.resolve({ - selectPlacements: function (options) { - window.mParticle.Rokt.selectPlacementsOptions = - options; - window.mParticle.Rokt.selectPlacementsCalled = true; - }, - }); - }; - - await window.mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true, - null, - { - 'test-attribute': 'test-value', - } - ); - - // Wait for initialization to complete (after launcher is created) - await waitForCondition(() => { - return window.mParticle.forwarder.isInitialized; - }); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: {}, - }); - - window.Rokt.selectPlacementsOptions.attributes.should.deepEqual( - { - 'test-attribute': 'test-value', - mpid: '123', - } - ); - }); - - it('should map other userIdentities to emailsha256', async () => { - window.mParticle.Rokt.filters = { - userAttributeFilters: [], - filterUserAttributes: function () { - return {}; - }, - filteredUser: { - getMPID: function () { - return '234'; - }, - getUserIdentities: function () { - return { - userIdentities: { - customerid: 'customer123', - other: 'sha256-test@gmail.com', - }, - }; - }, - }, - }; - - // Set up the createLauncher to properly resolve asynchronously - window.Rokt.createLauncher = async function () { - return Promise.resolve({ - selectPlacements: function (options) { - window.mParticle.Rokt.selectPlacementsOptions = - options; - window.mParticle.Rokt.selectPlacementsCalled = true; - }, - }); - }; - await window.mParticle.forwarder.init( - { - accountId: '123456', - hashedEmailUserIdentityType: 'Other', - }, - reportService.cb, - true, - null, - {} - ); - // Wait for initialization to complete (after launcher is created) - await waitForCondition(() => { - return window.mParticle.forwarder.isInitialized; - }); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: {}, - }); - - window.Rokt.selectPlacementsOptions.attributes.should.deepEqual( - { - customerid: 'customer123', - emailsha256: 'sha256-test@gmail.com', - mpid: '234', - } - ); - }); - - it('should map other to emailsha256 when other is passed through selectPlacements', async () => { - window.mParticle.Rokt.filters = { - userAttributeFilters: [], - filterUserAttributes: function (attributes) { - return attributes; - }, - filteredUser: { - getMPID: function () { - return '123'; - }, - getUserIdentities: function () { - return { - userIdentities: { - customerid: 'customer123', - }, - }; - }, - }, - }; - - // Set up the createLauncher to properly resolve asynchronously - window.Rokt.createLauncher = async function () { - return Promise.resolve({ - selectPlacements: function (options) { - window.mParticle.Rokt.selectPlacementsOptions = - options; - window.mParticle.Rokt.selectPlacementsCalled = true; - }, - }); - }; - - await window.mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true, - null, - { - 'test-attribute': 'test-value', - } - ); - - // Wait for initialization to complete (after launcher is created) - await waitForCondition(() => { - return window.mParticle.forwarder.isInitialized; - }); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: { - other: 'other-attribute', - }, - }); - - window.Rokt.selectPlacementsOptions.attributes.should.deepEqual( - { - 'test-attribute': 'test-value', - customerid: 'customer123', - other: 'other-attribute', - mpid: '123', - } - ); - }); - - it('should pass the attribute `other` in selectPlacements directly to Rokt', async () => { - window.mParticle.Rokt.filters = { - userAttributeFilters: [], - filterUserAttributes: function (attributes) { - return attributes; - }, - filteredUser: { - getMPID: function () { - return '123'; - }, - getUserIdentities: function () { - return { - userIdentities: { - customerid: 'customer123', - other: 'other-id', - }, - }; - }, - }, - }; - - // Set up the createLauncher to properly resolve asynchronously - window.Rokt.createLauncher = async function () { - return Promise.resolve({ - selectPlacements: function (options) { - window.mParticle.Rokt.selectPlacementsOptions = - options; - window.mParticle.Rokt.selectPlacementsCalled = true; - }, - }); - }; - - await window.mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true, - null, - { - 'test-attribute': 'test-value', - } - ); - - // Wait for initialization to complete (after launcher is created) - await waitForCondition(() => { - return window.mParticle.forwarder.isInitialized; - }); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: { - other: 'continues-to-exist', - }, - }); - - window.Rokt.selectPlacementsOptions.attributes.should.deepEqual( - { - 'test-attribute': 'test-value', - customerid: 'customer123', - other: 'continues-to-exist', - emailsha256: 'other-id', - mpid: '123', - } - ); - }); - - it('should use custom hashedEmailUserIdentityType when provided in settings', async () => { - window.mParticle.Rokt.filters = { - userAttributeFilters: [], - filterUserAttributes: function (attributes) { - return attributes; - }, - filteredUser: { - getMPID: function () { - return '789'; - }, - getUserIdentities: function () { - return { - userIdentities: { - // Using 'customerid' as the identity type instead of 'other' - other5: 'hashed-customer-id-value', - }, - }; - }, - }, - }; - - // Set up the createLauncher to properly resolve asynchronously - window.Rokt.createLauncher = async function () { - return Promise.resolve({ - selectPlacements: function (options) { - window.mParticle.Rokt.selectPlacementsOptions = - options; - window.mParticle.Rokt.selectPlacementsCalled = true; - }, - }); - }; - - await window.mParticle.forwarder.init( - { - accountId: '123456', - hashedEmailUserIdentityType: 'Other5', // TitleCase from server - }, - reportService.cb, - true, - null, - {} - ); - - // Wait for initialization to complete (after launcher is created) - await waitForCondition(() => { - return window.mParticle.forwarder.isInitialized; - }); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: { - 'test-attribute': 'test-value', - }, - }); - - // Should map customerid from userIdentities to emailsha256 since hashedEmailUserIdentityType was set to 'CustomerID' - window.Rokt.selectPlacementsOptions.attributes.should.deepEqual( - { - 'test-attribute': 'test-value', - emailsha256: 'hashed-customer-id-value', // mapped from customerid in userIdentities - mpid: '789', - } - ); - }); - - it('should NOT set emailsha256 on final select placements attributes when hashedEmailUserIdentityType is Unassigned', async () => { - window.mParticle.Rokt.filters = { - userAttributeFilters: [], - filterUserAttributes: function (attributes) { - return attributes; - }, - filteredUser: { - getMPID: function () { - return '999'; - }, - getUserIdentities: function () { - return { - userIdentities: { - // Using lowercase identity name that matches the converted OTHER_IDENTITY - other: 'hashed-custom-identity-value', - }, - }; - }, - }, - }; - - // Set up the createLauncher to properly resolve asynchronously - window.Rokt.createLauncher = async function () { - return Promise.resolve({ - selectPlacements: function (options) { - window.mParticle.Rokt.selectPlacementsOptions = - options; - window.mParticle.Rokt.selectPlacementsCalled = true; - }, - }); - }; - - await window.mParticle.forwarder.init( - { - accountId: '123456', - hashedEmailUserIdentityType: 'Unassigned', // Mixed case from server - }, - reportService.cb, - true, - null, - {} - ); - - // Wait for initialization to complete (after launcher is created) - await waitForCondition(() => { - return window.mParticle.forwarder.isInitialized; - }); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: { - 'test-attr': 'test-value', - }, - }); - - // Should map customidentity from userIdentities to emailsha256 (TitleCase converted to lowercase) - window.Rokt.selectPlacementsOptions.attributes.should.deepEqual( - { - 'test-attr': 'test-value', - other: 'hashed-custom-identity-value', - mpid: '999', - } - ); - }); - - it('should keep both email and emailsha256 when emailsha256 is passed through selectPlacements and email exists in userIdentities', async () => { - window.mParticle.Rokt.filters = { - userAttributeFilters: [], - filterUserAttributes: function (attributes) { - return attributes; - }, - filteredUser: { - getMPID: function () { - return '456'; - }, - getUserIdentities: function () { - return { - userIdentities: { - email: 'test@example.com', - }, - }; - }, - }, - }; - - // Set up the createLauncher to properly resolve asynchronously - window.Rokt.createLauncher = async function () { - return Promise.resolve({ - selectPlacements: function (options) { - window.mParticle.Rokt.selectPlacementsOptions = - options; - window.mParticle.Rokt.selectPlacementsCalled = true; - }, - }); - }; - - await window.mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true, - null, - {} - ); - - // Wait for initialization to complete (after launcher is created) - await waitForCondition(() => { - return window.mParticle.forwarder.isInitialized; - }); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: { - emailsha256: 'hashed-email-value', - }, - }); - - // Should keep both email from userIdentities and emailsha256 from selectPlacements - window.Rokt.selectPlacementsOptions.attributes.should.deepEqual( - { - email: 'test@example.com', - emailsha256: 'hashed-email-value', - mpid: '456', - } - ); - }); - - it('should keep both email and emailsha256 when both are passed through selectPlacements', async () => { - window.mParticle.Rokt.filters = { - userAttributeFilters: [], - filterUserAttributes: function (attributes) { - return attributes; - }, - filteredUser: { - getMPID: function () { - return '789'; - }, - getUserIdentities: function () { - return { - userIdentities: { - email: 'identity-email@example.com', - }, - }; - }, - }, - }; - - // Set up the createLauncher to properly resolve asynchronously - window.Rokt.createLauncher = async function () { - return Promise.resolve({ - selectPlacements: function (options) { - window.mParticle.Rokt.selectPlacementsOptions = - options; - window.mParticle.Rokt.selectPlacementsCalled = true; - }, - }); - }; - - await window.mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true, - null, - {} - ); - - // Wait for initialization to complete (after launcher is created) - await waitForCondition(() => { - return window.mParticle.forwarder.isInitialized; - }); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: { - email: 'developer-email@example.com', - emailsha256: 'hashed-email-value', - }, - }); - - // Should keep both email and emailsha256 since developer explicitly passed both - window.Rokt.selectPlacementsOptions.attributes.should.deepEqual( - { - email: 'developer-email@example.com', - emailsha256: 'hashed-email-value', - mpid: '789', - } - ); - }); - - it('should include email in kit.selectPlacements call if not passed, and email exists in userIdentities', async () => { - window.mParticle.Rokt.filters = { - userAttributeFilters: [], - filterUserAttributes: function (attributes) { - return attributes; - }, - filteredUser: { - getMPID: function () { - return '901'; - }, - getUserIdentities: function () { - return { - userIdentities: { - email: 'identity-email@example.com', - customerid: 'customer456', - }, - }; - }, - }, - }; - - // Set up the createLauncher to properly resolve asynchronously - window.Rokt.createLauncher = async function () { - return Promise.resolve({ - selectPlacements: function (options) { - window.mParticle.Rokt.selectPlacementsOptions = - options; - window.mParticle.Rokt.selectPlacementsCalled = true; - }, - }); - }; - - await window.mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true, - null, - {} - ); - - // Wait for initialization to complete (after launcher is created) - await waitForCondition(() => { - return window.mParticle.forwarder.isInitialized; - }); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: { - someAttribute: 'someValue', - }, - }); - - // Should keep email from userIdentities since emailsha256 does not exist - window.Rokt.selectPlacementsOptions.attributes.should.deepEqual( - { - email: 'identity-email@example.com', - customerid: 'customer456', - someAttribute: 'someValue', - mpid: '901', - } - ); - }); - - it('should have both email and emailsha256 in kit.selectPlacements call if both exist on userIdentities, and neither is passed through selectPlacements', async () => { - window.mParticle.Rokt.filters = { - userAttributeFilters: [], - filterUserAttributes: function (attributes) { - return attributes; - }, - filteredUser: { - getMPID: function () { - return '912'; - }, - getUserIdentities: function () { - return { - userIdentities: { - email: 'identity-email@example.com', - other: 'hashed-from-other', - customerid: 'customer789', - }, - }; - }, - }, - }; - - // Set up the createLauncher to properly resolve asynchronously - window.Rokt.createLauncher = async function () { - return Promise.resolve({ - selectPlacements: function (options) { - window.mParticle.Rokt.selectPlacementsOptions = - options; - window.mParticle.Rokt.selectPlacementsCalled = true; - }, - }); - }; - - await window.mParticle.forwarder.init( - { - accountId: '123456', - hashedEmailUserIdentityType: 'Other', - }, - reportService.cb, - true, - null, - {} - ); - - // Wait for initialization to complete (after launcher is created) - await waitForCondition(() => { - return window.mParticle.forwarder.isInitialized; - }); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: {}, - }); - - // Should keep both email and emailsha256 since emailsha256 was mapped from other identity (not explicitly passed) - window.Rokt.selectPlacementsOptions.attributes.should.deepEqual( - { - email: 'identity-email@example.com', - emailsha256: 'hashed-from-other', - customerid: 'customer789', - mpid: '912', - } - ); - }); - - it('should keep only email from selectPlacements when no emailsha256 exists', async () => { - window.mParticle.Rokt.filters = { - userAttributeFilters: [], - filterUserAttributes: function (attributes) { - return attributes; - }, - filteredUser: { - getMPID: function () { - return '934'; - }, - getUserIdentities: function () { - return { - userIdentities: { - customerid: 'customer202', - }, - }; - }, - }, - }; - - // Set up the createLauncher to properly resolve asynchronously - window.Rokt.createLauncher = async function () { - return Promise.resolve({ - selectPlacements: function (options) { - window.mParticle.Rokt.selectPlacementsOptions = - options; - window.mParticle.Rokt.selectPlacementsCalled = true; - }, - }); - }; - - await window.mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true, - null, - {} - ); - - // Wait for initialization to complete (after launcher is created) - await waitForCondition(() => { - return window.mParticle.forwarder.isInitialized; - }); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: { - email: 'developer-email@example.com', - }, - }); - - // Should keep email from selectPlacements since no emailsha256 exists - window.Rokt.selectPlacementsOptions.attributes.should.deepEqual( - { - email: 'developer-email@example.com', - customerid: 'customer202', - mpid: '934', - } - ); - }); - - it('should keep only emailsha256 from selectPlacements when no email exists in userIdentities', async () => { - window.mParticle.Rokt.filters = { - userAttributeFilters: [], - filterUserAttributes: function (attributes) { - return attributes; - }, - filteredUser: { - getMPID: function () { - return '945'; - }, - getUserIdentities: function () { - return { - userIdentities: { - customerid: 'customer303', - }, - }; - }, - }, - }; - - window.Rokt.createLauncher = async function () { - return Promise.resolve({ - selectPlacements: function (options) { - window.mParticle.Rokt.selectPlacementsOptions = - options; - window.mParticle.Rokt.selectPlacementsCalled = true; - }, - }); - }; - - await window.mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition(() => { - return window.mParticle.forwarder.isInitialized; - }); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: { - emailsha256: 'developer-hashed-email', - }, - }); - - window.Rokt.selectPlacementsOptions.attributes.should.deepEqual( - { - emailsha256: 'developer-hashed-email', - customerid: 'customer303', - mpid: '945', - } - ); - }); - - it('should have nothing when neither email nor emailsha256 exist anywhere', async () => { - window.mParticle.Rokt.filters = { - userAttributeFilters: [], - filterUserAttributes: function (attributes) { - return attributes; - }, - filteredUser: { - getMPID: function () { - return '967'; - }, - getUserIdentities: function () { - return { - userIdentities: { - customerid: 'customer505', - }, - }; - }, - }, - }; - - window.Rokt.createLauncher = async function () { - return Promise.resolve({ - selectPlacements: function (options) { - window.mParticle.Rokt.selectPlacementsOptions = - options; - window.mParticle.Rokt.selectPlacementsCalled = true; - }, - }); - }; - - await window.mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition(() => { - return window.mParticle.forwarder.isInitialized; - }); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: {}, - }); - - window.Rokt.selectPlacementsOptions.attributes.should.deepEqual( - { - customerid: 'customer505', - mpid: '967', - } - ); - }); - - it('should keep only emailsha256 from userIdentities when email is not in userIdentities and developer passes nothing', async () => { - window.mParticle.Rokt.filters = { - userAttributeFilters: [], - filterUserAttributes: function (attributes) { - return attributes; - }, - filteredUser: { - getMPID: function () { - return '978'; - }, - getUserIdentities: function () { - return { - userIdentities: { - other: 'hashed-from-useridentities', - customerid: 'customer606', - }, - }; - }, - }, - }; - - window.Rokt.createLauncher = async function () { - return Promise.resolve({ - selectPlacements: function (options) { - window.mParticle.Rokt.selectPlacementsOptions = - options; - window.mParticle.Rokt.selectPlacementsCalled = true; - }, - }); - }; - - await window.mParticle.forwarder.init( - { - accountId: '123456', - hashedEmailUserIdentityType: 'Other', - }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition(() => { - return window.mParticle.forwarder.isInitialized; - }); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: {}, - }); - - window.Rokt.selectPlacementsOptions.attributes.should.deepEqual( - { - emailsha256: 'hashed-from-useridentities', - customerid: 'customer606', - mpid: '978', - } - ); - }); - - it('should keep both when developer passes both and both exist in userIdentities', async () => { - window.mParticle.Rokt.filters = { - userAttributeFilters: [], - filterUserAttributes: function (attributes) { - return attributes; - }, - filteredUser: { - getMPID: function () { - return '992'; - }, - getUserIdentities: function () { - return { - userIdentities: { - email: 'useridentity-email@example.com', - other: 'hashed-from-useridentities', - customerid: 'customer909', - }, - }; - }, - }, - }; - - window.Rokt.createLauncher = async function () { - return Promise.resolve({ - selectPlacements: function (options) { - window.mParticle.Rokt.selectPlacementsOptions = - options; - window.mParticle.Rokt.selectPlacementsCalled = true; - }, - }); - }; - - await window.mParticle.forwarder.init( - { - accountId: '123456', - hashedEmailUserIdentityType: 'Other', - }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition(() => { - return window.mParticle.forwarder.isInitialized; - }); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: { - email: 'developer-email@example.com', - emailsha256: 'developer-hashed-email', - }, - }); - - // Should use developer-passed values for both - window.Rokt.selectPlacementsOptions.attributes.should.deepEqual( - { - email: 'developer-email@example.com', - emailsha256: 'developer-hashed-email', - customerid: 'customer909', - mpid: '992', - } - ); - }); - - it('should NOT map other userIdentities to emailsha256 when the value is an empty string', async () => { - window.mParticle.Rokt.filters = { - userAttributeFilters: [], - filterUserAttributes: function () { - return {}; - }, - filteredUser: { - getMPID: function () { - return '234'; - }, - getUserIdentities: function () { - return { - userIdentities: { - email: 'test@gmail.com', - other: '', // Empty string - }, - }; - }, - }, - }; - - // Set up the createLauncher to properly resolve asynchronously - window.Rokt.createLauncher = async function () { - return Promise.resolve({ - selectPlacements: function (options) { - window.mParticle.Rokt.selectPlacementsOptions = - options; - window.mParticle.Rokt.selectPlacementsCalled = true; - }, - }); - }; - await window.mParticle.forwarder.init( - { - accountId: '123456', - hashedEmailUserIdentityType: 'Other', - }, - reportService.cb, - true, - null, - {} - ); - // Wait for initialization to complete (after launcher is created) - await waitForCondition(() => { - return window.mParticle.forwarder.isInitialized; - }); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: {}, - }); - - // Should NOT include emailsha256 since the other identity value was empty - window.Rokt.selectPlacementsOptions.attributes.should.deepEqual( - { - email: 'test@gmail.com', - mpid: '234', - } - ); - }); - - it('should NOT map other userIdentities to emailsha256 when the value is null', async () => { - window.mParticle.Rokt.filters = { - userAttributeFilters: [], - filterUserAttributes: function () { - return {}; - }, - filteredUser: { - getMPID: function () { - return '345'; - }, - getUserIdentities: function () { - return { - userIdentities: { - email: 'test@gmail.com', - other: null, // Null value - }, - }; - }, - }, - }; - - // Set up the createLauncher to properly resolve asynchronously - window.Rokt.createLauncher = async function () { - return Promise.resolve({ - selectPlacements: function (options) { - window.mParticle.Rokt.selectPlacementsOptions = - options; - window.mParticle.Rokt.selectPlacementsCalled = true; - }, - }); - }; - await window.mParticle.forwarder.init( - { - accountId: '123456', - hashedEmailUserIdentityType: 'Other', - }, - reportService.cb, - true, - null, - {} - ); - // Wait for initialization to complete (after launcher is created) - await waitForCondition(() => { - return window.mParticle.forwarder.isInitialized; - }); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: {}, - }); - - // Should NOT include emailsha256 since the other identity value was null - window.Rokt.selectPlacementsOptions.attributes.should.deepEqual( - { - email: 'test@gmail.com', - mpid: '345', - } - ); - }); - - it('should NOT map other userIdentities to emailsha256 when the value is undefined', async () => { - window.mParticle.Rokt.filters = { - userAttributeFilters: [], - filterUserAttributes: function () { - return {}; - }, - filteredUser: { - getMPID: function () { - return '456'; - }, - getUserIdentities: function () { - return { - userIdentities: { - email: 'test@gmail.com', - other: undefined, // Undefined value - }, - }; - }, - }, - }; - - // Set up the createLauncher to properly resolve asynchronously - window.Rokt.createLauncher = async function () { - return Promise.resolve({ - selectPlacements: function (options) { - window.mParticle.Rokt.selectPlacementsOptions = - options; - window.mParticle.Rokt.selectPlacementsCalled = true; - }, - }); - }; - await window.mParticle.forwarder.init( - { - accountId: '123456', - hashedEmailUserIdentityType: 'Other', - }, - reportService.cb, - true, - null, - {} - ); - // Wait for initialization to complete (after launcher is created) - await waitForCondition(() => { - return window.mParticle.forwarder.isInitialized; - }); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: {}, - }); - - // Should NOT include emailsha256 since the other identity value was undefined - window.Rokt.selectPlacementsOptions.attributes.should.deepEqual( - { - email: 'test@gmail.com', - mpid: '456', - } - ); - }); - - it('should NOT map other userIdentities to emailsha256 when the value is 0', async () => { - window.mParticle.Rokt.filters = { - userAttributeFilters: [], - filterUserAttributes: function () { - return {}; - }, - filteredUser: { - getMPID: function () { - return '567'; - }, - getUserIdentities: function () { - return { - userIdentities: { - email: 'test@gmail.com', - other: 0, // Zero value - }, - }; - }, - }, - }; - - // Set up the createLauncher to properly resolve asynchronously - window.Rokt.createLauncher = async function () { - return Promise.resolve({ - selectPlacements: function (options) { - window.mParticle.Rokt.selectPlacementsOptions = - options; - window.mParticle.Rokt.selectPlacementsCalled = true; - }, - }); - }; - await window.mParticle.forwarder.init( - { - accountId: '123456', - hashedEmailUserIdentityType: 'Other', - }, - reportService.cb, - true, - null, - {} - ); - // Wait for initialization to complete (after launcher is created) - await waitForCondition(() => { - return window.mParticle.forwarder.isInitialized; - }); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: {}, - }); - - // Should NOT include emailsha256 since the other identity value was 0 - window.Rokt.selectPlacementsOptions.attributes.should.deepEqual( - { - email: 'test@gmail.com', - mpid: '567', - } - ); - }); - - it('should NOT map other userIdentities to emailsha256 when the value is false', async () => { - window.mParticle.Rokt.filters = { - userAttributeFilters: [], - filterUserAttributes: function () { - return {}; - }, - filteredUser: { - getMPID: function () { - return '678'; - }, - getUserIdentities: function () { - return { - userIdentities: { - email: 'test@gmail.com', - other: false, // False value - }, - }; - }, - }, - }; - - // Set up the createLauncher to properly resolve asynchronously - window.Rokt.createLauncher = async function () { - return Promise.resolve({ - selectPlacements: function (options) { - window.mParticle.Rokt.selectPlacementsOptions = - options; - window.mParticle.Rokt.selectPlacementsCalled = true; - }, - }); - }; - await window.mParticle.forwarder.init( - { - accountId: '123456', - hashedEmailUserIdentityType: 'Other', - }, - reportService.cb, - true, - null, - {} - ); - // Wait for initialization to complete (after launcher is created) - await waitForCondition(() => { - return window.mParticle.forwarder.isInitialized; - }); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: {}, - }); - - // Should NOT include emailsha256 since the other identity value was false - window.Rokt.selectPlacementsOptions.attributes.should.deepEqual( - { - email: 'test@gmail.com', - mpid: '678', - } - ); - }); - }); - - describe('#logSelectPlacementsEvent', () => { - it('should log a custom event', async () => { - window.Rokt.createLauncher = async function () { - return Promise.resolve({ - selectPlacements: function () { - return Promise.resolve({ - context: { - sessionId: - Promise.resolve('rokt-session-abc'), - }, - }); - }, - }); - }; - - await window.mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true, - null, - { - 'cached-user-attr': 'cached-value', - } - ); - - await waitForCondition( - () => window.mParticle.forwarder.isInitialized - ); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: { - 'new-attr': 'new-value', - }, - }); - - await waitForCondition(() => mParticle.loggedEvents.length > 0); - - mParticle.loggedEvents.length.should.equal(1); - mParticle.loggedEvents[0].eventName.should.equal( - 'selectPlacements' - ); - mParticle.loggedEvents[0].eventType.should.equal(8); // EventType.Other - - const eventAttributes = - mParticle.loggedEvents[0].eventAttributes; - eventAttributes.should.have.property('mpid'); - }); - - it('should include merged user attributes, identities, and mpid', async () => { - window.Rokt.createLauncher = async function () { - return Promise.resolve({ - selectPlacements: function () { - return Promise.resolve({ - context: { - sessionId: - Promise.resolve('rokt-session-abc'), - }, - }); - }, - }); - }; - - await window.mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true, - null, - { - 'cached-user-attr': 'cached-value', - } - ); - - await waitForCondition( - () => window.mParticle.forwarder.isInitialized - ); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: { - 'new-attr': 'new-value', - }, - }); - - await waitForCondition(() => mParticle.loggedEvents.length > 0); - - const eventAttributes = - mParticle.loggedEvents[0].eventAttributes; - - // eventAttributes should include merged attributes and mpid directly - eventAttributes.should.have.property('mpid', '123'); - eventAttributes.should.have.property('new-attr', 'new-value'); - eventAttributes.should.have.property( - 'cached-user-attr', - 'cached-value' - ); - }); - - it('should log event when sessionId promise rejects', async () => { - window.Rokt.createLauncher = async function () { - return Promise.resolve({ - selectPlacements: function () { - return Promise.resolve({ - context: { - sessionId: Promise.reject( - new Error('session id failed') - ), - }, - }); - }, - }); - }; - - await window.mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true, - null, - { - 'cached-user-attr': 'cached-value', - } - ); - - await waitForCondition( - () => window.mParticle.forwarder.isInitialized - ); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: { - 'new-attr': 'new-value', - }, - }); - - await waitForCondition(() => mParticle.loggedEvents.length > 0); - - mParticle.loggedEvents.length.should.equal(1); - mParticle.loggedEvents[0].eventName.should.equal( - 'selectPlacements' - ); - }); - - it('should log event when selection has no sessionId', async () => { - window.Rokt.createLauncher = async function () { - return Promise.resolve({ - selectPlacements: function () { - return Promise.resolve({ - context: {}, - }); - }, - }); - }; - - await window.mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true, - null, - { - 'cached-user-attr': 'cached-value', - } - ); - - await waitForCondition( - () => window.mParticle.forwarder.isInitialized - ); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: { - 'new-attr': 'new-value', - }, - }); - - await waitForCondition(() => mParticle.loggedEvents.length > 0); - - mParticle.loggedEvents.length.should.equal(1); - mParticle.loggedEvents[0].eventName.should.equal( - 'selectPlacements' - ); - }); - - it('should log event when selectPlacements promise rejects', async () => { - window.Rokt.createLauncher = async function () { - return Promise.resolve({ - selectPlacements: function () { - return Promise.reject( - new Error('selection failed') - ); - }, - }); - }; - - await window.mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true, - null, - { - 'cached-user-attr': 'cached-value', - } - ); - - await waitForCondition( - () => window.mParticle.forwarder.isInitialized - ); - - try { - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: { - 'new-attr': 'new-value', - }, - }); - } catch (e) { - // Expected rejection from selectPlacements - } - - await waitForCondition(() => mParticle.loggedEvents.length > 0); - - mParticle.loggedEvents.length.should.equal(1); - mParticle.loggedEvents[0].eventName.should.equal( - 'selectPlacements' - ); - }); - - it('should log event when selectPlacements returns a non-thenable value', async () => { - window.Rokt.createLauncher = async function () { - return Promise.resolve({ - selectPlacements: function () { - // Returns a non-thenable (no .then method) - return undefined; - }, - }); - }; - - await window.mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true, - null, - { - 'cached-user-attr': 'cached-value', - } - ); - - await waitForCondition( - () => window.mParticle.forwarder.isInitialized - ); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: { - 'new-attr': 'new-value', - }, - }); - - await waitForCondition(() => mParticle.loggedEvents.length > 0); - - mParticle.loggedEvents.length.should.equal(1); - mParticle.loggedEvents[0].eventName.should.equal( - 'selectPlacements' - ); - }); - - it('should skip logging when mParticle.logEvent is not available', async () => { - var originalLogEvent = window.mParticle.logEvent; - window.mParticle.logEvent = undefined; - - await window.mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true, - null, - {} - ); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: { - attr: 'value', - }, - }); - - window.Rokt.selectPlacementsCalled.should.equal(true); - mParticle.loggedEvents.length.should.equal(0); - window.mParticle.logEvent = originalLogEvent; - }); - }); - }); - - describe('#use', () => { - beforeEach(() => { - window.Rokt = new MockRoktForwarder(); - window.mParticle.Rokt = window.Rokt; - window.mParticle.Rokt.attachKitCalled = false; - window.mParticle.Rokt.attachKit = async (kit) => { - window.mParticle.Rokt.attachKitCalled = true; - window.mParticle.Rokt.kit = kit; - Promise.resolve(); - }; - }); - - it('should call launcher.use with the provided extension name when fully initialized', async () => { - window.mParticle.forwarder.isInitialized = true; - window.mParticle.forwarder.launcher = { - use: function (name) { - window.Rokt.useCalled = true; - window.Rokt.useName = name; - return Promise.resolve({}); - }, - }; - - await window.mParticle.forwarder.use('ThankYouPageJourney'); - - window.Rokt.useCalled.should.equal(true); - window.Rokt.useName.should.equal('ThankYouPageJourney'); - }); - - it('should reject when called before initialization', async () => { - window.mParticle.forwarder.isInitialized = false; - - try { - await window.mParticle.forwarder.use('ThankYouPageJourney'); - } catch (error) { - error.message.should.equal('Rokt Kit: Not initialized'); - } - }); - - it('should log an error when called before initialization', async () => { - const originalConsoleError = window.console.error; - let errorLogged = false; - let errorMessage = null; - window.console.error = function (message) { - errorLogged = true; - errorMessage = message; - }; - - window.mParticle.forwarder.isInitialized = false; - window.mParticle.forwarder.launcher = null; - - try { - await window.mParticle.forwarder.use('ThankYouPageJourney'); - throw new Error('Expected promise to reject'); - } catch (error) { - error.message.should.equal('Rokt Kit: Not initialized'); - } finally { - window.console.error = originalConsoleError; - } - - errorLogged.should.equal(true); - errorMessage.should.equal('Rokt Kit: Not initialized'); - }); - - it('should reject when extension name is invalid', async () => { - window.mParticle.forwarder.isInitialized = true; - window.mParticle.forwarder.launcher = { - use: function () { - return Promise.resolve({}); - }, - }; - - try { - await window.mParticle.forwarder.use(123); - } catch (error) { - error.message.should.equal('Rokt Kit: Invalid extension name'); - } - }); - - it('should log an error when kit is initialized but launcher is missing', async () => { - const originalConsoleError = window.console.error; - let errorLogged = false; - let errorMessage = null; - window.console.error = function (message) { - errorLogged = true; - errorMessage = message; - }; - - window.mParticle.forwarder.isInitialized = true; - window.mParticle.forwarder.launcher = null; - - try { - await window.mParticle.forwarder.use('ThankYouPageJourney'); - throw new Error('Expected promise to reject'); - } catch (error) { - error.message.should.equal('Rokt Kit: Not initialized'); - } finally { - window.console.error = originalConsoleError; - } - errorLogged.should.equal(true); - errorMessage.should.equal('Rokt Kit: Not initialized'); - }); - - it('should call launcher.use after init (test mode) and attach', async () => { - window.mParticle.Rokt.attachKitCalled = false; - window.mParticle.Rokt.attachKit = async (kit) => { - window.mParticle.Rokt.attachKitCalled = true; - window.mParticle.Rokt.kit = kit; - Promise.resolve(); - }; - - window.Rokt.createLauncher = async function () { - return Promise.resolve({ - use: function (name) { - window.Rokt.useCalled = true; - window.Rokt.useName = name; - return Promise.resolve({}); - }, - }); - }; - - await window.mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition(() => window.mParticle.Rokt.attachKitCalled); - - await window.mParticle.forwarder.use('ThankYouPageJourney'); - - window.Rokt.useCalled.should.equal(true); - window.Rokt.useName.should.equal('ThankYouPageJourney'); - }); - }); - - describe('#setUserAttribute', () => { - it('should set the user attribute', async () => { - window.mParticle.forwarder.setUserAttribute( - 'test-attribute', - 'test-value' - ); - - window.mParticle.forwarder.userAttributes.should.deepEqual({ - 'test-attribute': 'test-value', - }); - }); - - describe('event stream', () => { - beforeEach(() => { - window.mParticle.forwarder.eventStreamQueue = []; - window.mParticle.sessionManager = { - getSession: function () { - return 'test-mp-session-id'; - }, - }; - }); - - afterEach(() => { - delete window.Rokt.__event_stream__; - window.mParticle.forwarder.eventStreamQueue = []; - }); - - it('should send a set_user_attributes event to window.Rokt.__event_stream__', () => { - var receivedEvents = []; - window.Rokt.__event_stream__ = function (event) { - receivedEvents.push(event); - }; - - window.mParticle.forwarder.setUserAttribute( - 'test-attribute', - 'test-value' - ); - - receivedEvents.length.should.equal(1); - receivedEvents[0].EventName.should.equal('set_user_attributes'); - receivedEvents[0].EventDataType.should.equal(14); - }); - - it('should include updated UserAttributes in the event', () => { - var receivedEvents = []; - window.Rokt.__event_stream__ = function (event) { - receivedEvents.push(event); - }; - - window.mParticle.forwarder.setUserAttribute( - 'new-attr', - 'new-value' - ); - - receivedEvents[0].UserAttributes.should.deepEqual({ - 'new-attr': 'new-value', - }); - }); - - it('should include MPID from filteredUser and SessionId from sessionManager', () => { - var receivedEvents = []; - window.Rokt.__event_stream__ = function (event) { - receivedEvents.push(event); - }; - - window.mParticle.forwarder.filters.filteredUser = { - getMPID: function () { - return 'attr-mpid-123'; - }, - getUserIdentities: function () { - return { - userIdentities: { email: 'user@example.com' }, - }; - }, - }; - - window.mParticle.forwarder.setUserAttribute('k', 'v'); - - receivedEvents[0].MPID.should.equal('attr-mpid-123'); - receivedEvents[0].SessionId.should.equal('test-mp-session-id'); - receivedEvents[0].UserIdentities.should.deepEqual({ - email: 'user@example.com', - }); - }); - - it('should include null MPID and null UserIdentities when filteredUser is not set', () => { - var receivedEvents = []; - window.Rokt.__event_stream__ = function (event) { - receivedEvents.push(event); - }; - - window.mParticle.forwarder.filters.filteredUser = null; - window.mParticle.forwarder.setUserAttribute('k', 'v'); - - (receivedEvents[0].MPID === null).should.be.true(); - (receivedEvents[0].UserIdentities === null).should.be.true(); - }); - - it('should queue event when window.Rokt.__event_stream__ is not available', () => { - window.mParticle.forwarder.setUserAttribute( - 'queued-attr', - 'queued-value' - ); - - window.mParticle.forwarder.eventStreamQueue.length.should.equal( - 1 - ); - window.mParticle.forwarder.eventStreamQueue[0].EventName.should.equal( - 'set_user_attributes' - ); - window.mParticle.forwarder.eventStreamQueue[0].EventDataType.should.equal( - 14 - ); - }); - - it('should not throw when window.Rokt is undefined', () => { - var savedRokt = window.Rokt; - window.Rokt = undefined; - - (function () { - window.mParticle.forwarder.setUserAttribute('k', 'v'); - }).should.not.throw(); - - window.mParticle.forwarder.eventStreamQueue.length.should.equal( - 1 - ); - window.mParticle.forwarder.eventStreamQueue[0].EventName.should.equal( - 'set_user_attributes' - ); - - window.Rokt = savedRokt; - }); - }); - }); - - describe('#removeUserAttribute', () => { - it('should remove the user attribute', async () => { - window.mParticle.forwarder.setUserAttribute( - 'test-attribute', - 'test-value' - ); - - window.mParticle.forwarder.removeUserAttribute('test-attribute'); - - window.mParticle.forwarder.userAttributes.should.deepEqual({}); - }); - }); - - describe('#onUserIdentified', () => { - beforeEach(() => { - window.mParticle.sessionManager = { - getSession: function () { - return 'test-mp-session-id'; - }, - }; - }); - afterEach(() => { - delete window.Rokt.__event_stream__; - window.mParticle.forwarder.eventStreamQueue = []; - }); - - it('should set the filtered user and userAttributes', () => { - window.mParticle.forwarder.onUserIdentified({ - getAllUserAttributes: function () { - return { 'test-attribute': 'test-value' }; - }, - getMPID: function () { - return '123'; - }, - getUserIdentities: function () { - return { userIdentities: {} }; - }, - }); - - window.mParticle.forwarder.userAttributes.should.deepEqual({ - 'test-attribute': 'test-value', - }); - window.mParticle.forwarder.filters.filteredUser - .getMPID() - .should.equal('123'); - }); - - it('should send a User Identified event to window.Rokt.__event_stream__', () => { - var receivedEvents = []; - window.Rokt.__event_stream__ = function (event) { - receivedEvents.push(event); - }; - - window.mParticle.forwarder.onUserIdentified({ - getAllUserAttributes: function () { - return { 'user-attr': 'user-value' }; - }, - getMPID: function () { - return 'identified-mpid-123'; - }, - getUserIdentities: function () { - return { userIdentities: { email: 'jenny@example.com' } }; - }, - }); - - receivedEvents.length.should.equal(1); - receivedEvents[0].EventName.should.equal('identify'); - receivedEvents[0].EventDataType.should.equal(14); - receivedEvents[0].MPID.should.equal('identified-mpid-123'); - receivedEvents[0].SessionId.should.equal('test-mp-session-id'); - receivedEvents[0].UserAttributes.should.deepEqual({ - 'user-attr': 'user-value', - }); - receivedEvents[0].UserIdentities.should.deepEqual({ - email: 'jenny@example.com', - }); - }); - - it('should queue event when window.Rokt.__event_stream__ is not available', () => { - window.mParticle.forwarder.onUserIdentified({ - getAllUserAttributes: function () { - return {}; - }, - getMPID: function () { - return '123'; - }, - getUserIdentities: function () { - return { userIdentities: {} }; - }, - }); - - window.mParticle.forwarder.eventStreamQueue.length.should.equal(1); - window.mParticle.forwarder.eventStreamQueue[0].EventName.should.equal( - 'identify' - ); - }); - }); - - describe('#onLoginComplete', () => { - beforeEach(() => { - window.mParticle.sessionManager = { - getSession: function () { - return 'test-mp-session-id'; - }, - }; - }); - afterEach(() => { - delete window.Rokt.__event_stream__; - window.mParticle.forwarder.eventStreamQueue = []; - }); - - it('should update userAttributes from the filtered user', () => { - window.mParticle.forwarder.onLoginComplete({ - getAllUserAttributes: function () { - return { 'user-attr': 'user-value' }; - }, - }); - - window.mParticle.forwarder.userAttributes.should.deepEqual({ - 'user-attr': 'user-value', - }); - }); - - it('should send a User Login event to window.Rokt.__event_stream__', () => { - var receivedEvents = []; - window.Rokt.__event_stream__ = function (event) { - receivedEvents.push(event); - }; - - window.mParticle.forwarder.onLoginComplete({ - getAllUserAttributes: function () { - return { 'user-attr': 'user-value' }; - }, - getMPID: function () { - return 'login-mpid-123'; - }, - getUserIdentities: function () { - return { - userIdentities: { email: 'jenny@example.com' }, - }; - }, - }); - - receivedEvents.length.should.equal(1); - receivedEvents[0].EventName.should.equal('login'); - receivedEvents[0].EventDataType.should.equal(14); - receivedEvents[0].UserAttributes.should.deepEqual({ - 'user-attr': 'user-value', - }); - receivedEvents[0].MPID.should.equal('login-mpid-123'); - receivedEvents[0].SessionId.should.equal('test-mp-session-id'); - receivedEvents[0].UserIdentities.should.deepEqual({ - email: 'jenny@example.com', - }); - }); - - it('should include null MPID and null UserIdentities when filteredUser has no getMPID or getUserIdentities', () => { - var receivedEvents = []; - window.Rokt.__event_stream__ = function (event) { - receivedEvents.push(event); - }; - - window.mParticle.forwarder.onLoginComplete({ - getAllUserAttributes: function () { - return {}; - }, - }); - - receivedEvents.length.should.equal(1); - (receivedEvents[0].MPID === null).should.be.true(); - (receivedEvents[0].UserIdentities === null).should.be.true(); - }); - - it('should include null SessionId when sessionManager is unavailable', () => { - delete window.mParticle.sessionManager; - - var receivedEvents = []; - window.Rokt.__event_stream__ = function (event) { - receivedEvents.push(event); - }; - - window.mParticle.forwarder.onLoginComplete({ - getAllUserAttributes: function () { - return {}; - }, - getMPID: function () { - return 'some-mpid'; - }, - }); - - receivedEvents.length.should.equal(1); - (receivedEvents[0].SessionId === null).should.be.true(); - }); - - it('should queue event when window.Rokt.__event_stream__ is not available', () => { - window.mParticle.forwarder.onLoginComplete({ - getAllUserAttributes: function () { - return {}; - }, - }); - - window.mParticle.forwarder.eventStreamQueue.length.should.equal(1); - window.mParticle.forwarder.eventStreamQueue[0].EventName.should.equal( - 'login' - ); - window.mParticle.forwarder.eventStreamQueue[0].EventDataType.should.equal( - 14 - ); - }); - - it('should queue event when window.Rokt is undefined', () => { - var savedRokt = window.Rokt; - window.Rokt = undefined; - - (function () { - window.mParticle.forwarder.onLoginComplete({ - getAllUserAttributes: function () { - return {}; - }, - }); - }).should.not.throw(); - - window.mParticle.forwarder.eventStreamQueue.length.should.equal(1); - window.mParticle.forwarder.eventStreamQueue[0].EventName.should.equal( - 'login' - ); - - window.Rokt = savedRokt; - }); - }); - - describe('#onLogoutComplete', () => { - beforeEach(() => { - window.mParticle.sessionManager = { - getSession: function () { - return 'test-mp-session-id'; - }, - }; - }); - afterEach(() => { - delete window.Rokt.__event_stream__; - window.mParticle.forwarder.eventStreamQueue = []; - }); - - it('should update userAttributes from the filtered user', () => { - window.mParticle.forwarder.onLogoutComplete({ - getAllUserAttributes: function () { - return { 'remaining-attr': 'some-value' }; - }, - }); - - window.mParticle.forwarder.userAttributes.should.deepEqual({ - 'remaining-attr': 'some-value', - }); - }); - - it('should send a User Logout event to window.Rokt.__event_stream__', () => { - var receivedEvents = []; - window.Rokt.__event_stream__ = function (event) { - receivedEvents.push(event); - }; - - window.mParticle.forwarder.onLogoutComplete({ - getAllUserAttributes: function () { - return {}; - }, - getMPID: function () { - return 'logout-mpid-456'; - }, - getUserIdentities: function () { - return { - userIdentities: { customerid: 'cust-789' }, - }; - }, - }); - - receivedEvents.length.should.equal(1); - receivedEvents[0].EventName.should.equal('logout'); - receivedEvents[0].EventDataType.should.equal(14); - receivedEvents[0].UserAttributes.should.deepEqual({}); - receivedEvents[0].MPID.should.equal('logout-mpid-456'); - receivedEvents[0].SessionId.should.equal('test-mp-session-id'); - receivedEvents[0].UserIdentities.should.deepEqual({ - customerid: 'cust-789', - }); - }); - - it('should queue event when window.Rokt.__event_stream__ is not available', () => { - window.mParticle.forwarder.onLogoutComplete({ - getAllUserAttributes: function () { - return {}; - }, - }); - - window.mParticle.forwarder.eventStreamQueue.length.should.equal(1); - window.mParticle.forwarder.eventStreamQueue[0].EventName.should.equal( - 'logout' - ); - window.mParticle.forwarder.eventStreamQueue[0].EventDataType.should.equal( - 14 - ); - }); - - it('should queue event when window.Rokt is undefined', () => { - var savedRokt = window.Rokt; - window.Rokt = undefined; - - (function () { - window.mParticle.forwarder.onLogoutComplete({ - getAllUserAttributes: function () { - return {}; - }, - }); - }).should.not.throw(); - - window.mParticle.forwarder.eventStreamQueue.length.should.equal(1); - window.mParticle.forwarder.eventStreamQueue[0].EventName.should.equal( - 'logout' - ); - - window.Rokt = savedRokt; - }); - }); - - describe('#onModifyComplete', () => { - beforeEach(() => { - window.mParticle.sessionManager = { - getSession: function () { - return 'test-mp-session-id'; - }, - }; - }); - afterEach(() => { - delete window.Rokt.__event_stream__; - window.mParticle.forwarder.eventStreamQueue = []; - }); - - it('should update userAttributes from the filtered user', () => { - window.mParticle.forwarder.onModifyComplete({ - getAllUserAttributes: function () { - return { 'modified-attr': 'modified-value' }; - }, - getMPID: function () { - return '123'; - }, - getUserIdentities: function () { - return { userIdentities: {} }; - }, - }); - - window.mParticle.forwarder.userAttributes.should.deepEqual({ - 'modified-attr': 'modified-value', - }); - }); - - it('should send a User Modified event to window.Rokt.__event_stream__', () => { - var receivedEvents = []; - window.Rokt.__event_stream__ = function (event) { - receivedEvents.push(event); - }; - - window.mParticle.forwarder.onModifyComplete({ - getAllUserAttributes: function () { - return { 'modified-attr': 'modified-value' }; - }, - getMPID: function () { - return 'modify-mpid-789'; - }, - getUserIdentities: function () { - return { - userIdentities: { email: 'modified@example.com' }, - }; - }, - }); - - receivedEvents.length.should.equal(1); - receivedEvents[0].EventName.should.equal('modify_user'); - receivedEvents[0].EventDataType.should.equal(14); - receivedEvents[0].MPID.should.equal('modify-mpid-789'); - receivedEvents[0].SessionId.should.equal('test-mp-session-id'); - receivedEvents[0].UserAttributes.should.deepEqual({ - 'modified-attr': 'modified-value', - }); - receivedEvents[0].UserIdentities.should.deepEqual({ - email: 'modified@example.com', - }); - }); - - it('should queue event when window.Rokt.__event_stream__ is not available', () => { - window.mParticle.forwarder.onModifyComplete({ - getAllUserAttributes: function () { - return {}; - }, - getMPID: function () { - return '123'; - }, - getUserIdentities: function () { - return { userIdentities: {} }; - }, - }); - - window.mParticle.forwarder.eventStreamQueue.length.should.equal(1); - window.mParticle.forwarder.eventStreamQueue[0].EventName.should.equal( - 'modify_user' - ); - window.mParticle.forwarder.eventStreamQueue[0].EventDataType.should.equal( - 14 - ); - }); - - it('should queue event when window.Rokt is undefined', () => { - var savedRokt = window.Rokt; - window.Rokt = undefined; - - (function () { - window.mParticle.forwarder.onModifyComplete({ - getAllUserAttributes: function () { - return {}; - }, - getMPID: function () { - return '123'; - }, - getUserIdentities: function () { - return { userIdentities: {} }; - }, - }); - }).should.not.throw(); - - window.mParticle.forwarder.eventStreamQueue.length.should.equal(1); - window.mParticle.forwarder.eventStreamQueue[0].EventName.should.equal( - 'modify_user' - ); - - window.Rokt = savedRokt; - }); - }); - - describe('#fetchOptimizely', () => { - // Helper functions for setting up Optimizely mocks - function setupValidOptimizelyMock(experiments) { - window.optimizely = { - get: function (key) { - if (key === 'state') { - return { - getActiveExperimentIds: function () { - return Object.keys(experiments); - }, - getVariationMap: function () { - return experiments; - }, - }; - } - }, - }; - } - - function setupInvalidOptimizelyMock(stateObject) { - window.optimizely = { - get: function (key) { - if (key === 'state') { - return stateObject; - } - }, - }; - } - - // Common test setup - async function initAndSelectPlacements(settings = {}) { - await window.mParticle.forwarder.init( - { - accountId: '123456', - ...settings, - }, - reportService.cb, - true, - null, - {} - ); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: { - test: 'test', - }, - }); - } - - beforeEach(() => { - window.Rokt = new MockRoktForwarder(); - window.mParticle.Rokt = window.Rokt; - window.mParticle.Rokt.attachKitCalled = false; - window.mParticle.Rokt.attachKit = async (kit) => { - window.mParticle.Rokt.attachKitCalled = true; - window.mParticle.Rokt.kit = kit; - Promise.resolve(); - }; - window.mParticle.Rokt.setLocalSessionAttribute = function ( - key, - value - ) { - mParticle._Store.localSessionAttributes[key] = value; - }; - window.mParticle.Rokt.getLocalSessionAttributes = function () { - return mParticle._Store.localSessionAttributes; - }; - window.mParticle.forwarder.launcher = { - selectPlacements: function (options) { - window.mParticle.Rokt.selectPlacementsOptions = options; - window.mParticle.Rokt.selectPlacementsCalled = true; - }, - }; - window.mParticle.Rokt.filters = { - userAttributesFilters: [], - filterUserAttributes: function (attributes) { - return attributes; - }, - filteredUser: { - getMPID: function () { - return '123'; - }, - }, - }; - window.mParticle._getActiveForwarders = function () { - return [{ name: 'Optimizely' }]; - }; - }); - - afterEach(() => { - delete window.optimizely; - }); - - describe('when Optimizely is properly configured', () => { - it('should fetch experiment data for single experiment', async () => { - setupValidOptimizelyMock({ - exp1: { id: 'var1' }, - }); - - await initAndSelectPlacements({ - onboardingExpProvider: 'Optimizely', - }); - - window.Rokt.selectPlacementsOptions.attributes.should.have.property( - 'rokt.custom.optimizely.experiment.exp1.variationId', - 'var1' - ); - }); - - it('should fetch experiment data for multiple experiments', async () => { - setupValidOptimizelyMock({ - exp1: { id: 'var1' }, - exp2: { id: 'var2' }, - }); - - await initAndSelectPlacements({ - onboardingExpProvider: 'Optimizely', - }); - - const attributes = - window.Rokt.selectPlacementsOptions.attributes; - attributes.should.have.property( - 'rokt.custom.optimizely.experiment.exp1.variationId', - 'var1' - ); - attributes.should.have.property( - 'rokt.custom.optimizely.experiment.exp2.variationId', - 'var2' - ); - }); - }); - - describe('when Optimizely is not properly configured', () => { - it('should return empty object when Optimizely is not available', async () => { - delete window.optimizely; - - await initAndSelectPlacements({ - onboardingExpProvider: 'Optimizely', - }); - - window.Rokt.selectPlacementsOptions.attributes.should.not.have.property( - 'rokt.custom.optimizely' - ); - }); - - it('should return empty object when Optimizely state is undefined', async () => { - setupInvalidOptimizelyMock(undefined); - - await initAndSelectPlacements({ - onboardingExpProvider: 'Optimizely', - }); - - window.Rokt.selectPlacementsOptions.attributes.should.not.have.property( - 'rokt.custom.optimizely' - ); - }); - - it('should return empty object when Optimizely state has invalid format', async () => { - setupInvalidOptimizelyMock({ - someOtherProperty: 'value', - invalidFunction: function () { - return null; - }, - }); - - await initAndSelectPlacements({ - onboardingExpProvider: 'Optimizely', - }); - - window.Rokt.selectPlacementsOptions.attributes.should.not.have.property( - 'rokt.custom.optimizely' - ); - }); - - it('should return empty object when Optimizely state is missing required methods', async () => { - setupInvalidOptimizelyMock({ - getVariationMap: function () { - return {}; - }, - // Mocking a scenario for when getActiveExperimentIds() method is missing - }); - - await initAndSelectPlacements({ - onboardingExpProvider: 'Optimizely', - }); - - window.Rokt.selectPlacementsOptions.attributes.should.not.have.property( - 'rokt.custom.optimizely' - ); - }); - }); - - describe('when Optimizely is not the provider', () => { - it('should not fetch Optimizely data', async () => { - setupValidOptimizelyMock({ - exp1: { id: 'var1' }, - }); - - await initAndSelectPlacements({ - onboardingExpProvider: 'NotOptimizely', - }); - - window.Rokt.selectPlacementsOptions.attributes.should.not.have.property( - 'rokt.custom.optimizely' - ); - }); - }); - }); - - describe('#generateLauncherScript', () => { - const baseUrl = 'https://apps.rokt.com/wsdk/integrations/launcher.js'; - - beforeEach(() => { - window.mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true - ); - }); - - it('should return base URL when no domain is passed', () => { - const url = - window.mParticle.forwarder.testHelpers.generateLauncherScript(); - url.should.equal(baseUrl); - }); - - it('should return an updated base URL with CNAME when domain is passed', () => { - window.mParticle.forwarder.testHelpers - .generateLauncherScript('cname.rokt.com') - .should.equal( - 'https://cname.rokt.com/wsdk/integrations/launcher.js' - ); - }); - - it('should return base URL when no extensions are provided', () => { - const url = - window.mParticle.forwarder.testHelpers.generateLauncherScript(); - url.should.equal(baseUrl); - }); - - it('should return base URL when extensions is null or undefined', () => { - window.mParticle.forwarder.testHelpers - .generateLauncherScript(undefined, null) - .should.equal(baseUrl); - - window.mParticle.forwarder.testHelpers - .generateLauncherScript(undefined, undefined) - .should.equal(baseUrl); - }); - - it('should correctly append a single extension', () => { - const url = - window.mParticle.forwarder.testHelpers.generateLauncherScript( - undefined, - ['cos-extension-detection'] - ); - url.should.equal(baseUrl + '?extensions=cos-extension-detection'); - }); - - it('should correctly append multiple extensions', () => { - const url = - window.mParticle.forwarder.testHelpers.generateLauncherScript( - undefined, - [ - 'cos-extension-detection', - 'experiment-monitoring', - 'sponsored-payments-apple-pay', - ] - ); - url.should.equal( - baseUrl + - '?extensions=cos-extension-detection,' + - 'experiment-monitoring,' + - 'sponsored-payments-apple-pay' - ); - }); - }); - - describe('#roktExtensions', () => { - beforeEach(async () => { - window.Rokt = new MockRoktForwarder(); - window.mParticle.Rokt = window.Rokt; - - await window.mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true - ); - }); - - describe('extractRoktExtensions', () => { - it('should correctly map known extension names to their query parameters', async () => { - const settingsString = - '[{"jsmap":null,"map":null,"maptype":"StaticList","value":"cos-extension-detection"},{"jsmap":null,"map":null,"maptype":"StaticList","value":"experiment-monitoring"}]'; - const expectedExtensions = [ - 'cos-extension-detection', - 'experiment-monitoring', - ]; - - window.mParticle.forwarder.testHelpers - .extractRoktExtensions(settingsString) - .should.deepEqual(expectedExtensions); - }); - }); - - it('should handle invalid setting strings', () => { - window.mParticle.forwarder.testHelpers - .extractRoktExtensions('NONE') - .should.deepEqual([]); - - window.mParticle.forwarder.testHelpers - .extractRoktExtensions(undefined) - .should.deepEqual([]); - - window.mParticle.forwarder.testHelpers - .extractRoktExtensions(null) - .should.deepEqual([]); - }); - }); - - describe('#generateMappedEventLookup', () => { - beforeEach(async () => { - window.Rokt = new MockRoktForwarder(); - window.mParticle.Rokt = window.Rokt; - - await window.mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true - ); - }); - - it('should generate a lookup table from a placement event mapping', () => { - const placementEventMapping = [ - { - jsmap: '-1484452948', - map: '-5208850776883573773', - maptype: 'EventClass.Id', - value: 'foo-mapped-flag', - }, - { - jsmap: '1838502119', - map: '1324617889422969328', - maptype: 'EventClass.Id', - value: 'ad_viewed_test', - }, - ]; - - window.mParticle.forwarder.testHelpers - .generateMappedEventLookup(placementEventMapping) - .should.deepEqual({ - '-1484452948': 'foo-mapped-flag', - 1838502119: 'ad_viewed_test', - }); - }); - - it('should return an empty object if the placement event mapping is null', () => { - window.mParticle.forwarder.testHelpers - .generateMappedEventLookup(null) - .should.deepEqual({}); - }); - }); - - describe('#generateMappedEventAttributeLookup', () => { - beforeEach(async () => { - window.Rokt = new MockRoktForwarder(); - window.mParticle.Rokt = window.Rokt; - - await window.mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true - ); - }); - - it('should generate a lookup table from placementEventAttributeMapping', () => { - const placementEventAttributeMapping = [ - { - jsmap: null, - map: 'number_of_products', - maptype: 'EventAttributeClass.Name', - value: 'tof_products_2', - conditions: [ - { - operator: 'equals', - attributeValue: 2, - }, - ], - }, - { - jsmap: null, - map: 'URL', - maptype: 'EventAttributeClass.Name', - value: 'saleSeeker', - conditions: [ - { - operator: 'contains', - attributeValue: 'sale', - }, - ], - }, - ]; - - window.mParticle.forwarder.testHelpers - .generateMappedEventAttributeLookup( - placementEventAttributeMapping - ) - .should.deepEqual({ - tof_products_2: [ - { - eventAttributeKey: 'number_of_products', - conditions: [ - { - operator: 'equals', - attributeValue: 2, - }, - ], - }, - ], - saleSeeker: [ - { - eventAttributeKey: 'URL', - conditions: [ - { - operator: 'contains', - attributeValue: 'sale', - }, - ], - }, - ], - }); - }); - - it('should default conditions to an empty array when missing', () => { - const placementEventAttributeMapping = [ - { - jsmap: null, - map: 'URL', - maptype: 'EventAttributeClass.Name', - value: 'hasUrl', - }, - ]; - - window.mParticle.forwarder.testHelpers - .generateMappedEventAttributeLookup( - placementEventAttributeMapping - ) - .should.deepEqual({ - hasUrl: [ - { - eventAttributeKey: 'URL', - conditions: [], - }, - ], - }); - }); - - it('should return an empty object when placementEventAttributeMapping is null', () => { - window.mParticle.forwarder.testHelpers - .generateMappedEventAttributeLookup(null) - .should.deepEqual({}); - }); - - it('should ignore invalid mappings (non-string map/value)', () => { - const placementEventAttributeMapping = [ - { - jsmap: null, - map: null, - maptype: 'EventAttributeClass.Name', - value: 'bad', - conditions: [], - }, - { - jsmap: null, - map: 'URL', - maptype: 'EventAttributeClass.Name', - value: null, - conditions: [], - }, - { - jsmap: null, - map: 'URL', - maptype: 'EventAttributeClass.Name', - value: 'good', - conditions: [], - }, - ]; - - window.mParticle.forwarder.testHelpers - .generateMappedEventAttributeLookup( - placementEventAttributeMapping - ) - .should.deepEqual({ - good: [ - { - eventAttributeKey: 'URL', - conditions: [], - }, - ], - }); - }); - }); - - describe('#processEvent', () => { - beforeEach(() => { - window.Rokt = new MockRoktForwarder(); - window.Rokt.createLauncher = async function () { - return Promise.resolve({ - selectPlacements: function (options) { - window.mParticle.Rokt.selectPlacementsOptions = options; - window.mParticle.Rokt.selectPlacementsCalled = true; - }, - }); - }; - window.mParticle.Rokt = window.Rokt; - window.mParticle.Rokt.attachKitCalled = false; - window.mParticle.Rokt.attachKit = async (kit) => { - window.mParticle.Rokt.attachKitCalled = true; - window.mParticle.Rokt.kit = kit; - Promise.resolve(); - }; - window.mParticle.Rokt.setLocalSessionAttribute = function ( - key, - value - ) { - window.mParticle._Store.localSessionAttributes[key] = value; - }; - window.mParticle.Rokt.getLocalSessionAttributes = function () { - return window.mParticle._Store.localSessionAttributes; - }; - window.mParticle.forwarder.launcher = { - selectPlacements: function (options) { - window.mParticle.Rokt.selectPlacementsOptions = options; - window.mParticle.Rokt.selectPlacementsCalled = true; - }, - }; - window.mParticle.Rokt.filters = { - userAttributesFilters: [], - filterUserAttributes: function (attributes) { - return attributes; - }, - filteredUser: { - getMPID: function () { - return '123'; - }, - }, - }; - }); - - afterEach(() => { - window.mParticle.forwarder.eventQueue = []; - window.mParticle.forwarder.isInitialized = false; - window.mParticle.Rokt.attachKitCalled = false; - }); - - it('set a local session selection attribute if the event is a mapped placement event', async () => { - // Mocks hashed values for testing - const placementEventMapping = JSON.stringify([ - { - jsmap: 'hashed-<48Video Watched>-value', - map: '123466', - maptype: 'EventClass.Id', - value: 'foo-mapped-flag', - }, - { - jsmap: 'hashed-<29Other Value>-value', - map: '1279898989', - maptype: 'EventClass.Id', - value: 'ad_viewed_test', - }, - ]); - - await window.mParticle.forwarder.init( - { - accountId: '123456', - placementEventMapping, - }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition(() => window.mParticle.Rokt.attachKitCalled); - - window.mParticle.forwarder.process({ - EventName: 'Video Watched', - EventCategory: EventType.Other, - EventDataType: MessageType.PageEvent, - }); - - window.mParticle._Store.localSessionAttributes.should.deepEqual({ - 'foo-mapped-flag': true, - }); - }); - - it('should set local session attribute only when placementEventAttributeMapping conditions match (URL contains)', async () => { - const placementEventAttributeMapping = JSON.stringify([ - { - jsmap: null, - map: 'URL', - maptype: 'EventAttributeClass.Name', - value: 'saleSeeker', - conditions: [ - { - operator: 'contains', - attributeValue: 'sale', - }, - ], - }, - ]); - - await window.mParticle.forwarder.init( - { - accountId: '123456', - placementEventAttributeMapping, - }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition(() => window.mParticle.Rokt.attachKitCalled); - - window.mParticle._Store.localSessionAttributes = {}; - window.mParticle.forwarder.process({ - EventName: 'Browse', - EventCategory: EventType.Unknown, - EventDataType: MessageType.PageView, - EventAttributes: { - URL: 'https://example.com/home', - }, - }); - window.mParticle._Store.localSessionAttributes.should.deepEqual({}); - - window.mParticle._Store.localSessionAttributes = {}; - window.mParticle.forwarder.process({ - EventName: 'Browse', - EventCategory: EventType.Unknown, - EventDataType: MessageType.PageView, - EventAttributes: { - URL: 'https://example.com/sale/items', - }, - }); - window.mParticle._Store.localSessionAttributes.should.deepEqual({ - saleSeeker: true, - }); - }); - it('should support event attribute mapping when conditions are not defined', async () => { - const placementEventAttributeMapping = JSON.stringify([ - { - jsmap: null, - map: 'URL', - maptype: 'EventAttributeClass.Name', - value: 'hasUrl', - }, - ]); - - await window.mParticle.forwarder.init( - { - accountId: '123456', - placementEventAttributeMapping, - }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition(() => window.mParticle.Rokt.attachKitCalled); - - window.mParticle._Store.localSessionAttributes = {}; - window.mParticle.forwarder.process({ - EventName: 'Browse', - EventCategory: EventType.Unknown, - EventDataType: MessageType.PageView, - EventAttributes: { - URL: 'https://example.com/anything', - }, - }); - - window.mParticle._Store.localSessionAttributes.should.deepEqual({ - hasUrl: true, - }); - }); - - it('should not set local session attribute when mapped attribute key is missing from event and no conditions have been defined', async () => { - const placementEventAttributeMapping = JSON.stringify([ - { - jsmap: null, - map: 'URL', - maptype: 'EventAttributeClass.Name', - value: 'hasUrl', - }, - ]); - - await window.mParticle.forwarder.init( - { - accountId: '123456', - placementEventAttributeMapping, - }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition(() => window.mParticle.Rokt.attachKitCalled); - - window.mParticle._Store.localSessionAttributes = {}; - window.mParticle.forwarder.process({ - EventName: 'Browse', - EventCategory: EventType.Unknown, - EventDataType: MessageType.PageView, - EventAttributes: { - someOtherAttribute: 'value', - }, - }); - - window.mParticle._Store.localSessionAttributes.should.deepEqual({}); - }); - - it('should support exists operator for placementEventAttributeMapping conditions', async () => { - const placementEventAttributeMapping = JSON.stringify([ - { - jsmap: null, - map: 'URL', - maptype: 'EventAttributeClass.Name', - value: 'hasUrl', - conditions: [{ operator: 'exists' }], - }, - ]); - - await window.mParticle.forwarder.init( - { - accountId: '123456', - placementEventAttributeMapping, - }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition(() => window.mParticle.Rokt.attachKitCalled); - - window.mParticle._Store.localSessionAttributes = {}; - window.mParticle.forwarder.process({ - EventName: 'Browse', - EventCategory: EventType.Unknown, - EventDataType: MessageType.PageView, - EventAttributes: { - URL: 'https://example.com/anything', - }, - }); - - window.mParticle._Store.localSessionAttributes.should.deepEqual({ - hasUrl: true, - }); - - window.mParticle._Store.localSessionAttributes = {}; - window.mParticle.forwarder.process({ - EventName: 'Browse', - EventCategory: EventType.Unknown, - EventDataType: MessageType.PageView, - EventAttributes: { - someOtherAttribute: 'value', - }, - }); - - window.mParticle._Store.localSessionAttributes.should.deepEqual({}); - }); - - it('should evaluate equals for placementEventAttributeMapping conditions', async () => { - const placementEventAttributeMapping = JSON.stringify([ - { - jsmap: null, - map: 'number_of_products', - maptype: 'EventAttributeClass.Name', - value: 'multipleproducts', - conditions: [ - { - operator: 'equals', - attributeValue: 2, - }, - ], - }, - ]); - - await window.mParticle.forwarder.init( - { - accountId: '123456', - placementEventAttributeMapping, - }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition(() => window.mParticle.Rokt.attachKitCalled); - - window.mParticle._Store.localSessionAttributes = {}; - window.mParticle.forwarder.process({ - EventName: 'Browse', - EventCategory: EventType.Unknown, - EventDataType: MessageType.PageView, - EventAttributes: { - number_of_products: 2, - }, - }); - window.mParticle._Store.localSessionAttributes.should.deepEqual({ - multipleproducts: true, - }); - - window.mParticle._Store.localSessionAttributes = {}; - window.mParticle.forwarder.process({ - EventName: 'Browse', - EventCategory: EventType.Unknown, - EventDataType: MessageType.PageView, - EventAttributes: { - number_of_products: '2', - }, - }); - window.mParticle._Store.localSessionAttributes.should.deepEqual({ - multipleproducts: true, - }); - }); - - it('should evaluate contains for placementEventAttributeMapping conditions', async () => { - const placementEventAttributeMapping = JSON.stringify([ - { - jsmap: null, - map: 'number_of_products', - maptype: 'EventAttributeClass.Name', - value: 'containsNumber', - conditions: [ - { - operator: 'contains', - attributeValue: '2', - }, - ], - }, - ]); - - await window.mParticle.forwarder.init( - { - accountId: '123456', - placementEventAttributeMapping, - }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition(() => window.mParticle.Rokt.attachKitCalled); - - window.mParticle._Store.localSessionAttributes = {}; - window.mParticle.forwarder.process({ - EventName: 'Browse', - EventCategory: EventType.Unknown, - EventDataType: MessageType.PageView, - EventAttributes: { - number_of_products: 2, - }, - }); - window.mParticle._Store.localSessionAttributes.should.deepEqual({ - containsNumber: true, - }); - }); - - it('should correctly match attribute values for different type cases', async () => { - const placementEventAttributeMapping = JSON.stringify([ - { - jsmap: null, - map: 'boolAttr', - maptype: 'EventAttributeClass.Name', - value: 'lowerCaseMatches', - conditions: [ - { - operator: 'equals', - attributeValue: 'true', - }, - ], - }, - { - jsmap: null, - map: 'boolAttr', - maptype: 'EventAttributeClass.Name', - value: 'titleCaseMatches', - conditions: [ - { - operator: 'equals', - attributeValue: 'True', - }, - ], - }, - { - jsmap: null, - map: 'boolAttr', - maptype: 'EventAttributeClass.Name', - value: 'upperCaseMatches', - conditions: [ - { - operator: 'equals', - attributeValue: 'TRUE', - }, - ], - }, - { - jsmap: null, - map: 'zeroAttr', - maptype: 'EventAttributeClass.Name', - value: 'falseMatches', - conditions: [ - { - operator: 'equals', - attributeValue: false, - }, - ], - }, - { - jsmap: null, - map: 'zeroAttr', - maptype: 'EventAttributeClass.Name', - value: 'emptyMatches', - conditions: [ - { - operator: 'equals', - attributeValue: '', - }, - ], - }, - { - jsmap: null, - map: 'zeroAttr', - maptype: 'EventAttributeClass.Name', - value: 'zeroMatches', - conditions: [ - { - operator: 'equals', - attributeValue: '0', - }, - ], - }, - { - jsmap: null, - map: 'numAttr', - maptype: 'EventAttributeClass.Name', - value: 'digitMatches', - conditions: [ - { - operator: 'contains', - attributeValue: '2', - }, - ], - }, - ]); - - await window.mParticle.forwarder.init( - { - accountId: '123456', - placementEventAttributeMapping, - }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition(() => window.mParticle.Rokt.attachKitCalled); - - window.mParticle._Store.localSessionAttributes = {}; - window.mParticle.forwarder.process({ - EventName: 'Test', - EventCategory: EventType.Unknown, - EventDataType: MessageType.PageView, - EventAttributes: { - boolAttr: true, - zeroAttr: 0, - numAttr: 123, - }, - }); - - window.mParticle._Store.localSessionAttributes.should.deepEqual({ - lowerCaseMatches: true, - zeroMatches: true, - digitMatches: true, - }); - }); - - it('should not match when attribute key is missing or EventAttributes is absent', async () => { - const placementEventAttributeMapping = JSON.stringify([ - { - jsmap: null, - map: 'missingAttr', - maptype: 'EventAttributeClass.Name', - value: 'shouldNotMatch', - conditions: [ - { - operator: 'equals', - attributeValue: 'testValue', - }, - ], - }, - ]); - - await window.mParticle.forwarder.init( - { - accountId: '123456', - placementEventAttributeMapping, - }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition(() => window.mParticle.Rokt.attachKitCalled); - - window.mParticle._Store.localSessionAttributes = {}; - window.mParticle.forwarder.process({ - EventName: 'Test', - EventCategory: EventType.Unknown, - EventDataType: MessageType.PageView, - EventAttributes: { - otherAttr: 'value', - }, - }); - - window.mParticle._Store.localSessionAttributes.should.deepEqual({}); - - window.mParticle._Store.localSessionAttributes = {}; - window.mParticle.forwarder.process({ - EventName: 'Test', - EventCategory: EventType.Unknown, - EventDataType: MessageType.PageView, - }); - - window.mParticle._Store.localSessionAttributes.should.deepEqual({}); - }); - - it('should require ALL rules for the same mapped key to match (AND across rules)', async () => { - const placementEventAttributeMapping = JSON.stringify([ - { - jsmap: null, - map: 'URL', - maptype: 'EventAttributeClass.Name', - value: 'saleSeeker', - conditions: [ - { - operator: 'contains', - attributeValue: 'sale', - }, - { - operator: 'exists', - }, - ], - }, - { - jsmap: null, - map: 'URL', - maptype: 'EventAttributeClass.Name', - value: 'saleSeeker', - conditions: [ - { - operator: 'contains', - attributeValue: 'items', - }, - ], - }, - ]); - - await window.mParticle.forwarder.init( - { - accountId: '123456', - placementEventAttributeMapping, - }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition(() => window.mParticle.Rokt.attachKitCalled); - - window.mParticle._Store.localSessionAttributes = {}; - window.mParticle.forwarder.process({ - EventName: 'Browse', - EventCategory: EventType.Unknown, - EventDataType: MessageType.PageView, - EventAttributes: { - URL: 'https://example.com/sale', - }, - }); - window.mParticle._Store.localSessionAttributes.should.deepEqual({}); - - window.mParticle._Store.localSessionAttributes = {}; - window.mParticle.forwarder.process({ - EventName: 'Browse', - EventCategory: EventType.Unknown, - EventDataType: MessageType.PageView, - EventAttributes: { - URL: 'https://example.com/sale/items', - }, - }); - window.mParticle._Store.localSessionAttributes.should.deepEqual({ - saleSeeker: true, - }); - }); - it('should set multiple local session attributes for the same event attribute key', async () => { - const placementEventAttributeMapping = JSON.stringify([ - { - jsmap: null, - map: 'URL', - maptype: 'EventAttributeClass.Name', - value: 'saleSeeker', - conditions: [ - { - operator: 'contains', - attributeValue: 'sale', - }, - ], - }, - { - jsmap: null, - map: 'URL', - maptype: 'EventAttributeClass.Name', - value: 'saleSeeker1', - conditions: [ - { - operator: 'contains', - attributeValue: 'items', - }, - ], - }, - ]); - - await window.mParticle.forwarder.init( - { - accountId: '123456', - placementEventAttributeMapping, - }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition(() => window.mParticle.Rokt.attachKitCalled); - - window.mParticle._Store.localSessionAttributes = {}; - window.mParticle.forwarder.process({ - EventName: 'Browse', - EventCategory: EventType.Unknown, - EventDataType: MessageType.PageView, - EventAttributes: { - URL: 'https://example.com/sale', - }, - }); - window.mParticle._Store.localSessionAttributes.should.deepEqual({ - saleSeeker: true, - }); - - window.mParticle._Store.localSessionAttributes = {}; - window.mParticle.forwarder.process({ - EventName: 'Browse', - EventCategory: EventType.Unknown, - EventDataType: MessageType.PageView, - EventAttributes: { - URL: 'https://example.com/sale/items', - }, - }); - window.mParticle._Store.localSessionAttributes.should.deepEqual({ - saleSeeker: true, - saleSeeker1: true, - }); - }); - it('should treat falsy attribute values as existing', async () => { - const placementEventAttributeMapping = JSON.stringify([ - { - jsmap: null, - map: 'zeroProp', - maptype: 'EventAttributeClass.Name', - value: 'zeroExists', - conditions: [{ operator: 'exists' }], - }, - { - jsmap: null, - map: 'falseProp', - maptype: 'EventAttributeClass.Name', - value: 'falseExists', - conditions: [{ operator: 'exists' }], - }, - { - jsmap: null, - map: 'emptyStringProp', - maptype: 'EventAttributeClass.Name', - value: 'emptyStringExists', - conditions: [{ operator: 'exists' }], - }, - ]); - - await window.mParticle.forwarder.init( - { - accountId: '123456', - placementEventAttributeMapping, - }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition(() => window.mParticle.Rokt.attachKitCalled); - - window.mParticle._Store.localSessionAttributes = {}; - window.mParticle.forwarder.process({ - EventName: 'Test', - EventCategory: EventType.Unknown, - EventDataType: MessageType.PageView, - EventAttributes: { - zeroProp: 0, - falseProp: false, - emptyStringProp: '', - }, - }); - - window.mParticle._Store.localSessionAttributes.should.deepEqual({ - zeroExists: true, - falseExists: true, - emptyStringExists: true, - }); - }); - - it('should not match when condition has an unrecognized operator', async () => { - const placementEventAttributeMapping = JSON.stringify([ - { - jsmap: null, - map: 'URL', - maptype: 'EventAttributeClass.Name', - value: 'shouldNotMatch', - conditions: [ - { - operator: 'testOperator', - attributeValue: 'https', - }, - ], - }, - ]); - - await window.mParticle.forwarder.init( - { - accountId: '123456', - placementEventAttributeMapping, - }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition(() => window.mParticle.Rokt.attachKitCalled); - - window.mParticle._Store.localSessionAttributes = {}; - window.mParticle.forwarder.process({ - EventName: 'Browse', - EventCategory: EventType.Unknown, - EventDataType: MessageType.PageView, - EventAttributes: { - URL: 'https://example.com', - }, - }); - - window.mParticle._Store.localSessionAttributes.should.deepEqual({}); - }); - - it('should support both placementEventMapping and placementEventAttributeMapping together', async () => { - const placementEventMapping = JSON.stringify([ - { - jsmap: 'hashed-<48Video Watched>-value', - map: '123466', - maptype: 'EventClass.Id', - value: 'foo-mapped-flag', - }, - ]); - - const placementEventAttributeMapping = JSON.stringify([ - { - jsmap: null, - map: 'URL', - maptype: 'EventAttributeClass.Name', - value: 'hasUrl', - conditions: [{ operator: 'exists' }], - }, - ]); - - await window.mParticle.forwarder.init( - { - accountId: '123456', - placementEventMapping, - placementEventAttributeMapping, - }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition(() => window.mParticle.Rokt.attachKitCalled); - - window.mParticle._Store.localSessionAttributes = {}; - window.mParticle.forwarder.process({ - EventName: 'Browse', - EventCategory: EventType.Unknown, - EventDataType: MessageType.PageView, - EventAttributes: { - URL: 'https://example.com/anything', - }, - }); - - window.mParticle._Store.localSessionAttributes.should.deepEqual({ - hasUrl: true, - }); - - window.mParticle._Store.localSessionAttributes = {}; - window.mParticle.forwarder.process({ - EventName: 'Video Watched', - EventCategory: EventType.Other, - EventDataType: MessageType.PageEvent, - EventAttributes: { - URL: 'https://example.com/video', - }, - }); - - window.mParticle._Store.localSessionAttributes.should.deepEqual({ - hasUrl: true, - 'foo-mapped-flag': true, - }); - - window.mParticle._Store.localSessionAttributes = {}; - window.mParticle.forwarder.process({ - EventName: 'Video Watched', - EventCategory: EventType.Other, - EventDataType: MessageType.PageEvent, - }); - - window.mParticle._Store.localSessionAttributes.should.deepEqual({ - 'foo-mapped-flag': true, - }); - }); - - it('should add the event to the event queue if the kit is not initialized', async () => { - await window.mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true, - null, - {} - ); - - window.mParticle.forwarder.process({ - EventName: 'Video Watched A', - EventCategory: EventType.Other, - EventDataType: MessageType.PageEvent, - }); - - window.mParticle.forwarder.eventQueue.should.deepEqual([ - { - EventName: 'Video Watched A', - EventCategory: EventType.Other, - EventDataType: MessageType.PageEvent, - }, - ]); - }); - - it('should process queued events once the kit is ready', async () => { - await window.mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true, - null, - {} - ); - - window.mParticle.forwarder.process({ - EventName: 'Video Watched B', - EventCategory: EventType.Other, - EventDataType: MessageType.PageEvent, - }); - - window.mParticle.forwarder.eventQueue.should.deepEqual([ - { - EventName: 'Video Watched B', - EventCategory: EventType.Other, - EventDataType: MessageType.PageEvent, - }, - ]); - - await waitForCondition(() => window.mParticle.Rokt.attachKitCalled); - - window.mParticle.forwarder.eventQueue.should.deepEqual([]); - }); - }); - - describe('#_sendEventStream', () => { - beforeEach(() => { - window.mParticle.forwarder.eventStreamQueue = []; - window.Rokt = new MockRoktForwarder(); - window.Rokt.createLauncher = async function () { - return Promise.resolve({ - selectPlacements: function (options) { - window.mParticle.Rokt.selectPlacementsOptions = options; - window.mParticle.Rokt.selectPlacementsCalled = true; - }, - }); - }; - window.mParticle.Rokt = window.Rokt; - window.mParticle.Rokt.attachKitCalled = false; - window.mParticle.Rokt.attachKit = async (kit) => { - window.mParticle.Rokt.attachKitCalled = true; - window.mParticle.Rokt.kit = kit; - Promise.resolve(); - }; - window.mParticle.Rokt.setLocalSessionAttribute = function ( - key, - value - ) { - window.mParticle._Store.localSessionAttributes[key] = value; - }; - window.mParticle.Rokt.getLocalSessionAttributes = function () { - return window.mParticle._Store.localSessionAttributes; - }; - window.mParticle.forwarder.launcher = { - selectPlacements: function (options) { - window.mParticle.Rokt.selectPlacementsOptions = options; - window.mParticle.Rokt.selectPlacementsCalled = true; - }, - }; - window.mParticle.Rokt.filters = { - userAttributesFilters: [], - filterUserAttributes: function (attributes) { - return attributes; - }, - filteredUser: { - getMPID: function () { - return '123'; - }, - }, - }; - }); - - afterEach(() => { - delete window.Rokt.__event_stream__; - window.mParticle.forwarder.eventQueue = []; - window.mParticle.forwarder.eventStreamQueue = []; - window.mParticle.forwarder.isInitialized = false; - window.mParticle.Rokt.attachKitCalled = false; - }); - - it('should forward event to window.Rokt.__event_stream__ when available', async () => { - var receivedEvents = []; - window.Rokt.__event_stream__ = function (event) { - receivedEvents.push(event); - }; - - await window.mParticle.forwarder.init( - { accountId: '123456' }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition(() => window.mParticle.Rokt.attachKitCalled); - - var testEvent = { - EventName: 'Test Event', - EventCategory: EventType.Other, - EventDataType: MessageType.PageEvent, - }; - - window.mParticle.forwarder.process(testEvent); - - receivedEvents.length.should.equal(1); - receivedEvents[0].EventName.should.equal('Test Event'); - receivedEvents[0].EventCategory.should.equal(EventType.Other); - receivedEvents[0].EventDataType.should.equal(MessageType.PageEvent); - receivedEvents[0].UserAttributes.should.deepEqual({}); - }); - - it('should queue event when window.Rokt.__event_stream__ is not defined', async () => { - await window.mParticle.forwarder.init( - { accountId: '123456' }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition(() => window.mParticle.Rokt.attachKitCalled); - - var testEvent = { - EventName: 'Test Event', - EventCategory: EventType.Other, - EventDataType: MessageType.PageEvent, - }; - - (function () { - window.mParticle.forwarder.process(testEvent); - }).should.not.throw(); - - window.mParticle.forwarder.eventStreamQueue.length.should.equal(1); - window.mParticle.forwarder.eventStreamQueue[0].should.deepEqual( - testEvent - ); - }); - - it('should queue event when window.Rokt is undefined', async () => { - await window.mParticle.forwarder.init( - { accountId: '123456' }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition(() => window.mParticle.Rokt.attachKitCalled); - - var savedRokt = window.Rokt; - window.Rokt = undefined; - - var testEvent = { - EventName: 'Test Event', - EventCategory: EventType.Other, - EventDataType: MessageType.PageEvent, - }; - - (function () { - window.mParticle.forwarder.process(testEvent); - }).should.not.throw(); - - window.mParticle.forwarder.eventStreamQueue.length.should.equal(1); - window.mParticle.forwarder.eventStreamQueue[0].should.deepEqual( - testEvent - ); - - window.Rokt = savedRokt; - }); - - it('should forward event with attributes to the event stream', async () => { - var receivedEvents = []; - window.Rokt.__event_stream__ = function (event) { - receivedEvents.push(event); - }; - - await window.mParticle.forwarder.init( - { accountId: '123456' }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition(() => window.mParticle.Rokt.attachKitCalled); - - var testEvent = { - EventName: 'Purchase', - EventCategory: EventType.Transaction, - EventDataType: MessageType.PageEvent, - EventAttributes: { - product: 'shoes', - price: '49.99', - }, - }; - - window.mParticle.forwarder.process(testEvent); - - receivedEvents.length.should.equal(1); - receivedEvents[0].EventAttributes.should.deepEqual({ - product: 'shoes', - price: '49.99', - }); - }); - - it('should forward multiple events to the event stream', async () => { - var receivedEvents = []; - window.Rokt.__event_stream__ = function (event) { - receivedEvents.push(event); - }; - - await window.mParticle.forwarder.init( - { accountId: '123456' }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition(() => window.mParticle.Rokt.attachKitCalled); - - window.mParticle.forwarder.process({ - EventName: 'Event A', - EventCategory: EventType.Other, - EventDataType: MessageType.PageEvent, - }); - - window.mParticle.forwarder.process({ - EventName: 'Event B', - EventCategory: EventType.Navigation, - EventDataType: MessageType.PageView, - }); - - receivedEvents.length.should.equal(2); - receivedEvents[0].EventName.should.equal('Event A'); - receivedEvents[1].EventName.should.equal('Event B'); - }); - - it('should forward queued events to the event stream after init', async () => { - var receivedEvents = []; - window.Rokt.__event_stream__ = function (event) { - receivedEvents.push(event); - }; - - window.mParticle.forwarder.process({ - EventName: 'Queued Event', - EventCategory: EventType.Other, - EventDataType: MessageType.PageEvent, - }); - - receivedEvents.length.should.equal(0); - window.mParticle.forwarder.eventQueue.length.should.equal(1); - - await window.mParticle.forwarder.init( - { accountId: '123456' }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition(() => window.mParticle.Rokt.attachKitCalled); - - receivedEvents.length.should.equal(1); - receivedEvents[0].EventName.should.equal('Queued Event'); - }); - - it('should still process placement event mapping alongside event stream', async () => { - var receivedEvents = []; - window.Rokt.__event_stream__ = function (event) { - receivedEvents.push(event); - }; - - var placementEventMapping = JSON.stringify([ - { - jsmap: 'hashed-<48Video Watched>-value', - map: '123466', - maptype: 'EventClass.Id', - value: 'foo-mapped-flag', - }, - ]); - - await window.mParticle.forwarder.init( - { - accountId: '123456', - placementEventMapping: placementEventMapping, - }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition(() => window.mParticle.Rokt.attachKitCalled); - - window.mParticle.forwarder.process({ - EventName: 'Video Watched', - EventCategory: EventType.Other, - EventDataType: MessageType.PageEvent, - }); - - receivedEvents.length.should.equal(1); - receivedEvents[0].EventName.should.equal('Video Watched'); - - window.mParticle._Store.localSessionAttributes.should.deepEqual({ - 'foo-mapped-flag': true, - }); - }); - - it('should enrich event with Kit userAttributes before sending to event stream', async () => { - var receivedEvents = []; - window.Rokt.__event_stream__ = function (event) { - receivedEvents.push(event); - }; - - await window.mParticle.forwarder.init( - { accountId: '123456' }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition(() => window.mParticle.Rokt.attachKitCalled); - - window.mParticle.forwarder.userAttributes = { - firstName: 'John', - lastName: 'Doe', - }; - - window.mParticle.forwarder.process({ - EventName: 'Test Event', - EventCategory: EventType.Other, - EventDataType: MessageType.PageEvent, - }); - - receivedEvents.length.should.equal(1); - receivedEvents[0].UserAttributes.should.deepEqual({ - firstName: 'John', - lastName: 'Doe', - }); - }); - - it('should override event UserAttributes with Kit userAttributes', async () => { - var receivedEvents = []; - window.Rokt.__event_stream__ = function (event) { - receivedEvents.push(event); - }; - - await window.mParticle.forwarder.init( - { accountId: '123456' }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition(() => window.mParticle.Rokt.attachKitCalled); - - window.mParticle.forwarder.userAttributes = { - firstName: 'Jane', - }; - - window.mParticle.forwarder.process({ - EventName: 'Test Event', - EventCategory: EventType.Other, - EventDataType: MessageType.PageEvent, - UserAttributes: { - firstName: 'Stale', - obsoleteAttr: 'should-not-appear', - }, - }); - - receivedEvents.length.should.equal(1); - receivedEvents[0].UserAttributes.should.deepEqual({ - firstName: 'Jane', - }); - }); - - it('should not mutate the original event when enriching with userAttributes', async () => { - var receivedEvents = []; - window.Rokt.__event_stream__ = function (event) { - receivedEvents.push(event); - }; - - await window.mParticle.forwarder.init( - { accountId: '123456' }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition(() => window.mParticle.Rokt.attachKitCalled); - - window.mParticle.forwarder.userAttributes = { - firstName: 'John', - }; - - var originalEvent = { - EventName: 'Test Event', - EventCategory: EventType.Other, - EventDataType: MessageType.PageEvent, - }; - - window.mParticle.forwarder.process(originalEvent); - - originalEvent.should.not.have.property('UserAttributes'); - receivedEvents[0].UserAttributes.should.deepEqual({ - firstName: 'John', - }); - }); - - it('should send empty UserAttributes when Kit has no userAttributes', async () => { - var receivedEvents = []; - window.Rokt.__event_stream__ = function (event) { - receivedEvents.push(event); - }; - - await window.mParticle.forwarder.init( - { accountId: '123456' }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition(() => window.mParticle.Rokt.attachKitCalled); - - window.mParticle.forwarder.userAttributes = {}; - - window.mParticle.forwarder.process({ - EventName: 'Test Event', - EventCategory: EventType.Other, - EventDataType: MessageType.PageEvent, - }); - - receivedEvents.length.should.equal(1); - receivedEvents[0].UserAttributes.should.deepEqual({}); - }); - - it('should flush queued events in FIFO order when __event_stream__ becomes available', async () => { - await window.mParticle.forwarder.init( - { accountId: '123456' }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition(() => window.mParticle.Rokt.attachKitCalled); - - window.mParticle.forwarder.process({ - EventName: 'Event A', - EventCategory: EventType.Other, - EventDataType: MessageType.PageEvent, - }); - window.mParticle.forwarder.process({ - EventName: 'Event B', - EventCategory: EventType.Other, - EventDataType: MessageType.PageEvent, - }); - - window.mParticle.forwarder.eventStreamQueue.length.should.equal(2); - - var receivedEvents = []; - window.Rokt.__event_stream__ = function (event) { - receivedEvents.push(event); - }; - - window.mParticle.forwarder.process({ - EventName: 'Event C', - EventCategory: EventType.Other, - EventDataType: MessageType.PageEvent, - }); - - receivedEvents.length.should.equal(3); - receivedEvents[0].EventName.should.equal('Event A'); - receivedEvents[1].EventName.should.equal('Event B'); - receivedEvents[2].EventName.should.equal('Event C'); - window.mParticle.forwarder.eventStreamQueue.length.should.equal(0); - }); - }); - - describe('#_setRoktSessionId', () => { - var setIntegrationAttributeCalls; - - beforeEach(() => { - setIntegrationAttributeCalls = []; - window.Rokt = new MockRoktForwarder(); - window.mParticle.Rokt = window.Rokt; - window.mParticle.Rokt.attachKitCalled = false; - window.mParticle.Rokt.attachKit = async (kit) => { - window.mParticle.Rokt.attachKitCalled = true; - window.mParticle.Rokt.kit = kit; - Promise.resolve(); - }; - window.mParticle.Rokt.setLocalSessionAttribute = function ( - key, - value - ) { - window.mParticle._Store.localSessionAttributes[key] = value; - }; - window.mParticle.Rokt.getLocalSessionAttributes = function () { - return window.mParticle._Store.localSessionAttributes; - }; - window.mParticle.Rokt.filters = { - userAttributeFilters: [], - filterUserAttributes: function (attributes) { - return attributes; - }, - filteredUser: { - getMPID: function () { - return '123'; - }, - }, - }; - window.mParticle.getInstance = function () { - return { - setIntegrationAttribute: function (id, attrs) { - setIntegrationAttributeCalls.push({ - id: id, - attrs: attrs, - }); - }, - }; - }; - }); - - afterEach(() => { - delete window.mParticle.getInstance; - window.mParticle.forwarder.isInitialized = false; - window.mParticle.Rokt.attachKitCalled = false; - }); - - function createMockSelection(sessionId) { - return { - context: { - sessionId: sessionId - ? Promise.resolve(sessionId) - : Promise.resolve(''), - }, - }; - } - - function setupLauncherWithSelection(mockSelection) { - window.Rokt.createLauncher = async function (_options) { - return Promise.resolve({ - selectPlacements: function () { - return Promise.resolve(mockSelection); - }, - }); - }; - } - - it('should set integration attribute when session ID is available via context', async () => { - var mockSelection = createMockSelection('rokt-session-abc'); - setupLauncherWithSelection(mockSelection); - - await window.mParticle.forwarder.init( - { accountId: '123456' }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition( - () => window.mParticle.forwarder.isInitialized - ); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: {}, - }); - - await waitForCondition( - () => setIntegrationAttributeCalls.length > 0 - ); - - setIntegrationAttributeCalls.length.should.equal(1); - setIntegrationAttributeCalls[0].id.should.equal(181); - setIntegrationAttributeCalls[0].attrs.should.deepEqual({ - roktSessionId: 'rokt-session-abc', - }); - }); - - it('should not set integration attribute when session ID is empty', async () => { - var mockSelection = createMockSelection(''); - setupLauncherWithSelection(mockSelection); - - await window.mParticle.forwarder.init( - { accountId: '123456' }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition( - () => window.mParticle.forwarder.isInitialized - ); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: {}, - }); - - // Give time for any async operations to settle - await new Promise((resolve) => setTimeout(resolve, 50)); - - setIntegrationAttributeCalls.length.should.equal(0); - }); - - it('should not throw when mParticle.getInstance is unavailable', async () => { - var mockSelection = createMockSelection('rokt-session-abc'); - setupLauncherWithSelection(mockSelection); - delete window.mParticle.getInstance; - - await window.mParticle.forwarder.init( - { accountId: '123456' }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition( - () => window.mParticle.forwarder.isInitialized - ); - - // Should not throw - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: {}, - }); - - // Give time for async operations - await new Promise((resolve) => setTimeout(resolve, 50)); - - setIntegrationAttributeCalls.length.should.equal(0); - }); - - it('should return the selection promise to callers', async () => { - var mockSelection = createMockSelection('rokt-session-abc'); - setupLauncherWithSelection(mockSelection); - - await window.mParticle.forwarder.init( - { accountId: '123456' }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition( - () => window.mParticle.forwarder.isInitialized - ); - - var result = await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: {}, - }); - - result.should.equal(mockSelection); - }); - }); - - describe('#parseSettingsString', () => { - it('should parse null values in a settings string appropriately', () => { - const settingsString = - '[{"jsmap":null,"map":"f.name","maptype":"UserAttributeClass.Name","value":"firstname"},{"jsmap":null,"map":"last_name","maptype":"UserAttributeClass.Name","value":"lastname"}]'; - - window.mParticle.forwarder.testHelpers - .parseSettingsString(settingsString) - .should.deepEqual([ - { - jsmap: null, - map: 'f.name', - maptype: 'UserAttributeClass.Name', - value: 'firstname', - }, - { - jsmap: null, - map: 'last_name', - maptype: 'UserAttributeClass.Name', - value: 'lastname', - }, - ]); - }); - - it('should convert jmap and map number values to stringified numbers when parsed', () => { - const settingsString = - '[{"jsmap":"-1484452948","map":"-5208850776883573773","maptype":"EventClass.Id","value":"abc"},{"jsmap":"1838502119","map":"1324617889422969328","maptype":"EventClass.Id","value":"bcd"},{"jsmap":"-355458063","map":"5878452521714063084","maptype":"EventClass.Id","value":"card_viewed_test"}]'; - - window.mParticle.forwarder.testHelpers - .parseSettingsString(settingsString) - .should.deepEqual([ - { - jsmap: '-1484452948', - map: '-5208850776883573773', - maptype: 'EventClass.Id', - value: 'abc', - }, - { - jsmap: '1838502119', - map: '1324617889422969328', - maptype: 'EventClass.Id', - value: 'bcd', - }, - { - jsmap: '-355458063', - map: '5878452521714063084', - maptype: 'EventClass.Id', - value: 'card_viewed_test', - }, - ]); - }); - - it('returns an empty array if the settings string is empty', () => { - const settingsString = ''; - - window.mParticle.forwarder.testHelpers - .parseSettingsString(settingsString) - .should.deepEqual([]); - }); - - it('returns an empty array if the settings string is not a valid JSON', () => { - const settingsString = 'not a valid JSON'; - - window.mParticle.forwarder.testHelpers - .parseSettingsString(settingsString) - .should.deepEqual([]); - }); - }); - - describe('#hashEventMessage', () => { - it('should hash event message using generateHash in the proper order', () => { - const eventName = 'Test Event'; - const eventType = EventType.Other; - const messageType = MessageType.PageEvent; - const resultHash = - window.mParticle.forwarder.testHelpers.hashEventMessage( - messageType, - eventType, - eventName - ); - - // Order should be messageType (4), eventType (8), eventName (Test Event) - resultHash.should.equal('hashed-<48Test Event>-value'); - }); - }); - - describe('#createAutoRemovedIframe', () => { - beforeEach(() => { - window.mParticle.forwarder.init( - { accountId: '123456' }, - reportService.cb, - true - ); - }); - - it('should create a hidden iframe with the given src and append it to the document', () => { - const src = 'https://example.com/test'; - window.mParticle.forwarder.testHelpers.createAutoRemovedIframe(src); - - const iframe = document.querySelector('iframe[src="' + src + '"]'); - iframe.should.be.ok(); - iframe.style.display.should.equal('none'); - iframe - .getAttribute('sandbox') - .should.equal('allow-scripts allow-same-origin'); - }); - - it('should remove the iframe from the DOM after it loads', (done) => { - const src = 'https://example.com/auto-remove-test'; - window.mParticle.forwarder.testHelpers.createAutoRemovedIframe(src); - - const iframe = document.querySelector('iframe[src="' + src + '"]'); - iframe.should.be.ok(); - - // Simulate load event - iframe.onload(); - - // iframe should be removed - const removed = document.querySelector('iframe[src="' + src + '"]'); - (removed === null).should.be.true(); - done(); - }); - }); - - describe('#sendAdBlockMeasurementSignals', () => { - let originalRandom; - - beforeEach(() => { - originalRandom = Math.random; - window.mParticle.forwarder.init( - { accountId: '123456' }, - reportService.cb, - true - ); - // Set allowed origin hash to match the test environment origin - const testOriginHash = window.mParticle.forwarder.testHelpers.djb2( - window.location.origin - ); - window.mParticle.forwarder.testHelpers.setAllowedOriginHashes([ - testOriginHash, - ]); - // Clean up any iframes from previous tests - document.querySelectorAll('iframe').forEach((iframe) => { - if (iframe.parentNode) { - iframe.parentNode.removeChild(iframe); - } - }); - }); - - afterEach(() => { - Math.random = originalRandom; - delete window.__rokt_li_guid__; - // Clean up iframes - document.querySelectorAll('iframe').forEach((iframe) => { - if (iframe.parentNode) { - iframe.parentNode.removeChild(iframe); - } - }); - }); - - it('should create two iframes with correct URLs when sampled in and guid is set', () => { - Math.random = () => 0.05; // Below 0.1 threshold - window.__rokt_li_guid__ = 'test-guid-123'; - - window.mParticle.forwarder.testHelpers.sendAdBlockMeasurementSignals( - 'custom.rokt.com', - 'test-version' - ); - - const iframes = document.querySelectorAll('iframe'); - const srcs = Array.prototype.map.call( - iframes, - (iframe) => iframe.src - ); - - srcs.length.should.be.aboveOrEqual(2); - - const existingDomainIframe = srcs.find( - (src) => - src.indexOf('custom.rokt.com/v1/wsdk-init/index.html') !== - -1 - ); - const controlDomainIframe = srcs.find( - (src) => - src.indexOf( - 'apps.roktecommerce.com/v1/wsdk-init/index.html' - ) !== -1 - ); - - existingDomainIframe.should.be.ok(); - controlDomainIframe.should.be.ok(); - - existingDomainIframe.should.containEql('version=test-version'); - existingDomainIframe.should.containEql( - 'launcherInstanceGuid=test-guid-123' - ); - existingDomainIframe.should.not.containEql('isControl'); - - controlDomainIframe.should.containEql('version=test-version'); - controlDomainIframe.should.containEql( - 'launcherInstanceGuid=test-guid-123' - ); - controlDomainIframe.should.containEql('isControl=true'); - }); - - it('should use apps.rokt.com as the default domain when no domain is provided', () => { - Math.random = () => 0.05; - window.__rokt_li_guid__ = 'test-guid-123'; - - window.mParticle.forwarder.testHelpers.sendAdBlockMeasurementSignals( - undefined, - 'test-version' - ); - - const iframes = document.querySelectorAll('iframe'); - const srcs = Array.prototype.map.call( - iframes, - (iframe) => iframe.src - ); - - const defaultDomainIframe = srcs.find( - (src) => - src.indexOf('apps.rokt.com/v1/wsdk-init/index.html') !== - -1 && src.indexOf('apps.roktecommerce.com') === -1 - ); - - defaultDomainIframe.should.be.ok(); - }); - - it('should not create iframes when sampled out', () => { - Math.random = () => 0.5; // Above 0.1 threshold - window.__rokt_li_guid__ = 'test-guid-123'; - - const iframeCountBefore = - document.querySelectorAll('iframe').length; - - window.mParticle.forwarder.testHelpers.sendAdBlockMeasurementSignals( - 'apps.rokt.com', - 'test-version' - ); - - const iframeCountAfter = document.querySelectorAll('iframe').length; - iframeCountAfter.should.equal(iframeCountBefore); - }); - - it('should not create iframes when __rokt_li_guid__ is not set', () => { - Math.random = () => 0.05; - delete window.__rokt_li_guid__; - - const iframeCountBefore = - document.querySelectorAll('iframe').length; - - window.mParticle.forwarder.testHelpers.sendAdBlockMeasurementSignals( - 'apps.rokt.com', - 'test-version' - ); - - const iframeCountAfter = document.querySelectorAll('iframe').length; - iframeCountAfter.should.equal(iframeCountBefore); - }); - - it('should not create iframes when origin does not match allowed hash', () => { - Math.random = () => 0.05; - window.__rokt_li_guid__ = 'test-guid-123'; - - // Set to a hash that won't match any real origin - window.mParticle.forwarder.testHelpers.setAllowedOriginHashes([0]); - - const iframeCountBefore = - document.querySelectorAll('iframe').length; - - window.mParticle.forwarder.testHelpers.sendAdBlockMeasurementSignals( - 'apps.rokt.com', - 'test-version' - ); - - const iframeCountAfter = document.querySelectorAll('iframe').length; - iframeCountAfter.should.equal(iframeCountBefore); - }); - - it('should strip hash fragments from pageUrl', () => { - Math.random = () => 0.05; - window.__rokt_li_guid__ = 'test-guid-123'; - - // window.location.href in test env won't have a fragment, - // but we can verify the pageUrl param does not contain '#' - window.mParticle.forwarder.testHelpers.sendAdBlockMeasurementSignals( - 'apps.rokt.com', - 'test-version' - ); - - const iframes = document.querySelectorAll('iframe'); - const srcs = Array.prototype.map.call( - iframes, - (iframe) => iframe.src - ); - - srcs.forEach((src) => { - src.should.containEql('pageUrl='); - // Extract the pageUrl param value - const match = src.match(/pageUrl=([^&]*)/); - match.should.be.ok(); - const decodedPageUrl = decodeURIComponent(match[1]); - decodedPageUrl.should.not.containEql('#'); - decodedPageUrl.should.not.containEql('?'); - }); - }); - - it('should fire measurement signals during initRoktLauncher when guid exists', async () => { - Math.random = () => 0.05; - window.__rokt_li_guid__ = 'init-test-guid'; - // Ensure origin hash matches test environment - const testOriginHash = window.mParticle.forwarder.testHelpers.djb2( - window.location.origin - ); - window.mParticle.forwarder.testHelpers.setAllowedOriginHashes([ - testOriginHash, - ]); - - window.Rokt = new MockRoktForwarder(); - window.mParticle.Rokt = window.Rokt; - window.mParticle.Rokt.attachKitCalled = false; - window.mParticle.Rokt.attachKit = async (kit) => { - window.mParticle.Rokt.attachKitCalled = true; - window.mParticle.Rokt.kit = kit; - Promise.resolve(); - }; - window.mParticle.Rokt.filters = { - userAttributesFilters: [], - filterUserAttributes: function (attributes) { - return attributes; - }, - filteredUser: { - getMPID: function () { - return '123'; - }, - }, - }; - - await mParticle.forwarder.init( - { accountId: '123456' }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition( - () => window.mParticle.forwarder.isInitialized - ); - - const iframes = document.querySelectorAll('iframe'); - const srcs = Array.prototype.map.call( - iframes, - (iframe) => iframe.src - ); - - const controlIframe = srcs.find( - (src) => - src.indexOf( - 'apps.roktecommerce.com/v1/wsdk-init/index.html' - ) !== -1 - ); - - controlIframe.should.be.ok(); - controlIframe.should.containEql( - 'launcherInstanceGuid=init-test-guid' - ); - }); - - it('should not fire measurement signals during init when guid is absent', async () => { - Math.random = () => 0.05; - delete window.__rokt_li_guid__; - // Ensure origin hash matches test environment - const testOriginHash = window.mParticle.forwarder.testHelpers.djb2( - window.location.origin - ); - window.mParticle.forwarder.testHelpers.setAllowedOriginHashes([ - testOriginHash, - ]); - - window.Rokt = new MockRoktForwarder(); - window.mParticle.Rokt = window.Rokt; - window.mParticle.Rokt.attachKitCalled = false; - window.mParticle.Rokt.attachKit = async (kit) => { - window.mParticle.Rokt.attachKitCalled = true; - window.mParticle.Rokt.kit = kit; - Promise.resolve(); - }; - window.mParticle.Rokt.filters = { - userAttributesFilters: [], - filterUserAttributes: function (attributes) { - return attributes; - }, - filteredUser: { - getMPID: function () { - return '123'; - }, - }, - }; - - await mParticle.forwarder.init( - { accountId: '123456' }, - reportService.cb, - true, - null, - {} - ); - - await waitForCondition( - () => window.mParticle.forwarder.isInitialized - ); - - const iframes = document.querySelectorAll('iframe'); - const srcs = Array.prototype.map.call( - iframes, - (iframe) => iframe.src - ); - - const controlIframe = srcs.find( - (src) => - src.indexOf( - 'apps.roktecommerce.com/v1/wsdk-init/index.html' - ) !== -1 - ); - - (controlIframe === undefined).should.be.true(); - }); - }); - - describe('ErrorReportingService', () => { - var originalFetch; - var mockFetch; - var fetchCalls; - var originalROKT_DOMAIN; - var originalLocation; - var originalNavigator; - - beforeEach(() => { - fetchCalls = []; - mockFetch = function (url, options) { - fetchCalls.push({ url: url, options: options }); - return Promise.resolve({ ok: true }); - }; - originalFetch = window.fetch; - window.fetch = mockFetch; - - originalROKT_DOMAIN = window.ROKT_DOMAIN; - window.ROKT_DOMAIN = 'set'; - - originalLocation = window.location; - originalNavigator = window.navigator; - }); - - afterEach(() => { - window.fetch = originalFetch; - window.ROKT_DOMAIN = originalROKT_DOMAIN; - try { - Object.defineProperty(window, 'location', { - writable: true, - value: originalLocation, - }); - } catch (_e) {} - try { - Object.defineProperty(window, 'navigator', { - writable: true, - value: originalNavigator, - }); - } catch (_e) {} - }); - - it('should send error reports to the errors endpoint', () => { - var service = new ErrorReportingService( - { - errorUrl: 'test.com/v1/errors', - isLoggingEnabled: true, - }, - '1.0.0', - 'test-guid' - ); - - service.report({ - message: 'test error', - code: ErrorCodes.UNHANDLED_EXCEPTION, - severity: WSDKErrorSeverity.ERROR, - stackTrace: 'stack', - }); - - fetchCalls.length.should.equal(1); - fetchCalls[0].url.should.equal('https://test.com/v1/errors'); - var body = JSON.parse(fetchCalls[0].options.body); - body.severity.should.equal('ERROR'); - body.code.should.equal('UNHANDLED_EXCEPTION'); - body.stackTrace.should.equal('stack'); - body.reporter.should.equal('mp-wsdk'); - }); - - it('should send warning reports to the errors endpoint', () => { - var service = new ErrorReportingService( - { - errorUrl: 'test.com/v1/errors', - isLoggingEnabled: true, - }, - '1.0.0', - 'test-guid' - ); - - service.report({ - message: 'test warning', - code: ErrorCodes.UNHANDLED_EXCEPTION, - severity: WSDKErrorSeverity.WARNING, - }); - - fetchCalls.length.should.equal(1); - fetchCalls[0].url.should.equal('https://test.com/v1/errors'); - var body = JSON.parse(fetchCalls[0].options.body); - body.severity.should.equal('WARNING'); - }); - - it('should send info reports to the error endpoint (error service only handles error url)', () => { - var service = new ErrorReportingService( - { - errorUrl: 'test.com/v1/errors', - isLoggingEnabled: true, - }, - '1.0.0', - 'test-guid' - ); - - service.report({ - message: 'info message', - code: ErrorCodes.UNHANDLED_EXCEPTION, - severity: WSDKErrorSeverity.INFO, - }); - - fetchCalls.length.should.equal(1); - fetchCalls[0].url.should.equal('https://test.com/v1/errors'); - var body = JSON.parse(fetchCalls[0].options.body); - body.severity.should.equal('INFO'); - }); - - it('should not send when ROKT_DOMAIN is missing and feature flag is off', () => { - window.ROKT_DOMAIN = undefined; - var service = new ErrorReportingService( - { isLoggingEnabled: false }, - '1.0.0', - 'test-guid' - ); - - service.report({ - message: 'should not send', - severity: WSDKErrorSeverity.ERROR, - }); - - fetchCalls.length.should.equal(0); - }); - - it('should not send when feature flag is off and debug mode is off', () => { - var service = new ErrorReportingService( - { isLoggingEnabled: false }, - '1.0.0', - 'test-guid' - ); - - service.report({ - message: 'should not send', - severity: WSDKErrorSeverity.ERROR, - }); - - fetchCalls.length.should.equal(0); - }); - - it('should send when debug mode is enabled even without ROKT_DOMAIN', () => { - window.ROKT_DOMAIN = undefined; - // Set debug mode via location search using history.pushState - var originalSearch = window.location.search; - window.history.pushState( - {}, - '', - window.location.pathname + '?mp_enable_logging=true' - ); - - var service = new ErrorReportingService( - { isLoggingEnabled: false }, - '1.0.0', - 'test-guid' - ); - - service.report({ - message: 'debug message', - severity: WSDKErrorSeverity.ERROR, - }); - - fetchCalls.length.should.equal(1); - - // Restore original URL - window.history.pushState( - {}, - '', - window.location.pathname + originalSearch - ); - }); - - it('should include correct headers', () => { - var service = new ErrorReportingService( - { isLoggingEnabled: true }, - '1.0.0', - 'test-guid' - ); - - service.report({ - message: 'test', - severity: WSDKErrorSeverity.ERROR, - }); - - fetchCalls.length.should.equal(1); - var headers = fetchCalls[0].options.headers; - headers['Accept'].should.equal('text/plain;charset=UTF-8'); - headers['Content-Type'].should.equal('application/json'); - headers['rokt-launcher-instance-guid'].should.equal('test-guid'); - headers['rokt-wsdk-version'].should.equal('joint'); - }); - - it('should omit rokt-launcher-instance-guid header when guid is undefined', () => { - var service = new ErrorReportingService( - { isLoggingEnabled: true }, - '1.0.0', - undefined - ); - - service.report({ - message: 'test', - severity: WSDKErrorSeverity.ERROR, - }); - - fetchCalls.length.should.equal(1); - var headers = fetchCalls[0].options.headers; - ( - headers['rokt-launcher-instance-guid'] === undefined - ).should.be.true(); - }); - - it('should include rokt-account-id header when accountId is provided', () => { - var service = new ErrorReportingService( - { isLoggingEnabled: true }, - 'test-integration', - 'test-guid', - '1234567890' - ); - - service.report({ - message: 'test', - severity: WSDKErrorSeverity.WARNING, - }); - - fetchCalls.length.should.equal(1); - fetchCalls[0].options.headers['rokt-account-id'].should.equal( - '1234567890' - ); - }); - - it('should not include rokt-account-id header when accountId is not provided', () => { - var service = new ErrorReportingService( - { isLoggingEnabled: true }, - 'test-integration', - 'test-guid' - ); - - service.report({ - message: 'test', - severity: WSDKErrorSeverity.ERROR, - }); - - fetchCalls.length.should.equal(1); - ( - fetchCalls[0].options.headers['rokt-account-id'] === undefined - ).should.be.true(); - }); - - it('should use default UNKNOWN_ERROR code when code is not provided', () => { - var service = new ErrorReportingService( - { isLoggingEnabled: true }, - '1.0.0', - 'test-guid' - ); - - service.report({ - message: 'test', - severity: WSDKErrorSeverity.ERROR, - }); - - var body = JSON.parse(fetchCalls[0].options.body); - body.code.should.equal('UNKNOWN_ERROR'); - }); - - it('should use default Rokt error URL when not configured', () => { - var service = new ErrorReportingService( - { isLoggingEnabled: true }, - '1.0.0', - 'test-guid' - ); - - service.report({ - message: 'test error', - severity: WSDKErrorSeverity.ERROR, - }); - - fetchCalls[0].url.should.equal( - 'https://apps.rokt-api.com/v1/errors' - ); - }); - - it('should include all required fields in the log request body', () => { - var service = new ErrorReportingService( - { isLoggingEnabled: true }, - 'test-integration', - 'test-guid' - ); - - service.report({ - message: 'error message', - code: ErrorCodes.IDENTITY_REQUEST, - severity: WSDKErrorSeverity.ERROR, - stackTrace: 'stack trace here', - }); - - var body = JSON.parse(fetchCalls[0].options.body); - body.additionalInformation.message.should.equal('error message'); - body.additionalInformation.version.should.equal('test-integration'); - body.severity.should.equal('ERROR'); - body.code.should.equal('IDENTITY_REQUEST'); - body.stackTrace.should.equal('stack trace here'); - body.reporter.should.equal('mp-wsdk'); - body.integration.should.equal('test-integration'); - }); - - it('should use empty integration values when no integration name is provided', () => { - var service = new ErrorReportingService( - { isLoggingEnabled: true }, - '', - 'test-guid' - ); - - service.report({ - message: 'test', - severity: WSDKErrorSeverity.ERROR, - }); - - var body = JSON.parse(fetchCalls[0].options.body); - body.reporter.should.equal('mp-wsdk'); - body.integration.should.equal(''); - body.additionalInformation.version.should.equal(''); - }); - - it('should not throw when fetch fails', (done) => { - window.fetch = function () { - return Promise.reject(new Error('Network failure')); - }; - var consoleErrors = []; - var originalConsoleError = console.error; - console.error = function () { - consoleErrors.push(Array.prototype.slice.call(arguments)); - }; - - var service = new ErrorReportingService( - { isLoggingEnabled: true }, - '1.0.0', - 'test-guid' - ); - - service.report({ - message: 'test', - severity: WSDKErrorSeverity.ERROR, - }); - - // Wait for the promise rejection to be handled - setTimeout(function () { - consoleErrors.length.should.be.above(0); - consoleErrors[0][0].should.equal( - 'ReportingTransport: Failed to send log' - ); - console.error = originalConsoleError; - done(); - }, 50); - }); - - it('should not send when report is called with null', () => { - var service = new ErrorReportingService( - { isLoggingEnabled: true }, - '1.0.0', - 'test-guid' - ); - - service.report(null); - fetchCalls.length.should.equal(0); - }); - }); - - describe('LoggingService', () => { - var originalFetch; - var mockFetch; - var fetchCalls; - var originalROKT_DOMAIN; - - beforeEach(() => { - fetchCalls = []; - mockFetch = function (url, options) { - fetchCalls.push({ url: url, options: options }); - return Promise.resolve({ ok: true }); - }; - originalFetch = window.fetch; - window.fetch = mockFetch; - - originalROKT_DOMAIN = window.ROKT_DOMAIN; - window.ROKT_DOMAIN = 'set'; - }); - - afterEach(() => { - window.fetch = originalFetch; - window.ROKT_DOMAIN = originalROKT_DOMAIN; - }); - - it('should always send to the logging endpoint with severity INFO', () => { - var errorService = new ErrorReportingService( - { isLoggingEnabled: true }, - '1.0.0', - 'test-guid' - ); - var service = new LoggingService( - { loggingUrl: 'test.com/v1/log', isLoggingEnabled: true }, - errorService, - '1.0.0', - 'test-guid' - ); - - service.log({ - message: 'log entry', - code: ErrorCodes.UNKNOWN_ERROR, - }); - - fetchCalls.length.should.equal(1); - fetchCalls[0].url.should.equal('https://test.com/v1/log'); - var body = JSON.parse(fetchCalls[0].options.body); - body.severity.should.equal('INFO'); - body.additionalInformation.message.should.equal('log entry'); - }); - - it('should report failure through ErrorReportingService on fetch error', (done) => { - var errorReports = []; - var errorService = { - report: function (error) { - errorReports.push(error); - }, - }; - window.fetch = function () { - return Promise.reject(new Error('Network failure')); - }; - var originalConsoleError = console.error; - console.error = function () {}; - - var service = new LoggingService( - { isLoggingEnabled: true }, - errorService, - '1.0.0', - 'test-guid' - ); - - service.log({ message: 'test' }); - - setTimeout(function () { - errorReports.length.should.be.above(0); - errorReports[0].severity.should.equal('ERROR'); - errorReports[0].message.should.containEql('Failed to send log'); - console.error = originalConsoleError; - done(); - }, 50); - }); - - it('should not send when log is called with null', () => { - var errorService = new ErrorReportingService( - { isLoggingEnabled: true }, - '1.0.0', - 'test-guid' - ); - var service = new LoggingService( - { isLoggingEnabled: true }, - errorService, - '1.0.0', - 'test-guid' - ); - - service.log(null); - fetchCalls.length.should.equal(0); - }); - }); - - describe('RateLimiter', () => { - it('should allow up to 10 logs per severity then rate limit', () => { - var limiter = new RateLimiter(); - for (var i = 0; i < 10; i++) { - limiter.incrementAndCheck('ERROR').should.be.false(); - } - limiter.incrementAndCheck('ERROR').should.be.true(); - limiter.incrementAndCheck('ERROR').should.be.true(); - }); - - it('should allow up to 10 warning logs then rate limit', () => { - var limiter = new RateLimiter(); - for (var i = 0; i < 10; i++) { - limiter.incrementAndCheck('WARNING').should.be.false(); - } - limiter.incrementAndCheck('WARNING').should.be.true(); - }); - - it('should allow up to 10 info logs then rate limit', () => { - var limiter = new RateLimiter(); - for (var i = 0; i < 10; i++) { - limiter.incrementAndCheck('INFO').should.be.false(); - } - limiter.incrementAndCheck('INFO').should.be.true(); - }); - - it('should track rate limits independently per severity', () => { - var limiter = new RateLimiter(); - for (var i = 0; i < 10; i++) { - limiter.incrementAndCheck('ERROR'); - } - limiter.incrementAndCheck('ERROR').should.be.true(); - limiter.incrementAndCheck('WARNING').should.be.false(); - }); - }); - - describe('ErrorReportingService rate limiting', () => { - var originalFetch; - var fetchCalls; - var originalROKT_DOMAIN; - - beforeEach(() => { - fetchCalls = []; - originalFetch = window.fetch; - window.fetch = function (url, options) { - fetchCalls.push({ url: url, options: options }); - return Promise.resolve({ ok: true }); - }; - - originalROKT_DOMAIN = window.ROKT_DOMAIN; - window.ROKT_DOMAIN = 'set'; - }); - - afterEach(() => { - window.fetch = originalFetch; - window.ROKT_DOMAIN = originalROKT_DOMAIN; - }); - - it('should rate limit after 10 errors', () => { - var service = new ErrorReportingService( - { isLoggingEnabled: true }, - '1.0.0', - 'test-guid' - ); - - for (var i = 0; i < 15; i++) { - service.report({ - message: 'error ' + i, - severity: WSDKErrorSeverity.ERROR, - }); - } - - fetchCalls.length.should.equal(10); - }); - - it('should rate limit with custom rate limiter', () => { - var count = 0; - var customLimiter = { - incrementAndCheck: function () { - return ++count > 3; - }, - }; - - var service = new ErrorReportingService( - { isLoggingEnabled: true }, - 'test-integration', - 'test-guid', - null, - customLimiter - ); - - for (var i = 0; i < 5; i++) { - service.report({ - message: 'error ' + i, - severity: WSDKErrorSeverity.ERROR, - }); - } - - fetchCalls.length.should.equal(3); - }); - }); - - describe('Reporting service registration', () => { - it('should register services with mParticle if methods exist', async () => { - var registeredErrorService = null; - var registeredLoggingService = null; - - window.mParticle._registerErrorReportingService = function ( - service - ) { - registeredErrorService = service; - }; - window.mParticle._registerLoggingService = function (service) { - registeredLoggingService = service; - }; - - window.Rokt = new MockRoktForwarder(); - window.mParticle.Rokt = window.Rokt; - window.mParticle.Rokt.attachKitCalled = false; - window.mParticle.Rokt.attachKit = async (kit) => { - window.mParticle.Rokt.attachKitCalled = true; - window.mParticle.Rokt.kit = kit; - Promise.resolve(); - }; - window.mParticle.Rokt.filters = { - userAttributesFilters: [], - filterUserAttributes: function (attributes) { - return attributes; - }, - filteredUser: { - getMPID: function () { - return '123'; - }, - }, - }; - - await mParticle.forwarder.init( - { - accountId: '123456', - isLoggingEnabled: 'true', - }, - reportService.cb, - true, - null, - {} - ); - - (registeredErrorService !== null).should.be.true(); - (registeredLoggingService !== null).should.be.true(); - (typeof registeredErrorService.report).should.equal('function'); - (typeof registeredLoggingService.log).should.equal('function'); - - // Cleanup - delete window.mParticle._registerErrorReportingService; - delete window.mParticle._registerLoggingService; - }); - - it('should not throw when registration methods do not exist', async () => { - delete window.mParticle._registerErrorReportingService; - delete window.mParticle._registerLoggingService; - - window.Rokt = new MockRoktForwarder(); - window.mParticle.Rokt = window.Rokt; - window.mParticle.Rokt.attachKitCalled = false; - window.mParticle.Rokt.attachKit = async (kit) => { - window.mParticle.Rokt.attachKitCalled = true; - window.mParticle.Rokt.kit = kit; - Promise.resolve(); - }; - window.mParticle.Rokt.filters = { - userAttributesFilters: [], - filterUserAttributes: function (attributes) { - return attributes; - }, - filteredUser: { - getMPID: function () { - return '123'; - }, - }, - }; - - // Should not throw - await mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true, - null, - {} - ); - - window.mParticle.forwarder.isInitialized.should.not.be.undefined(); - }); - }); -}); diff --git a/test/src/tests.spec.ts b/test/src/tests.spec.ts new file mode 100644 index 0000000..58569a5 --- /dev/null +++ b/test/src/tests.spec.ts @@ -0,0 +1,6026 @@ +import packageJson from '../../package.json'; +const packageVersion = packageJson.version; +import '../../src/Rokt-Kit'; + +/* eslint-disable @typescript-eslint/no-explicit-any */ + +declare const mParticle: any; + +const sdkVersion = 'mParticle_wsdkv_1.2.3'; +const kitVersion = 'kitv_' + packageVersion; + +const waitForCondition = async (conditionFn: () => boolean, timeout = 200, interval = 10) => { + return new Promise((resolve, reject) => { + const startTime = Date.now(); + + (function poll() { + if (conditionFn()) { + return resolve(undefined); + } else if (Date.now() - startTime > timeout) { + return reject(new Error('Timeout waiting for condition')); + } else { + setTimeout(poll, interval); + } + })(); + }); +}; + +describe('Rokt Forwarder', () => { + // Reporting service classes from testHelpers (populated after kit init) + let _ReportingTransportClass: any; + let ErrorReportingServiceClass: any; + let LoggingServiceClass: any; + let RateLimiterClass: any; + let ErrorCodesConst: any; + let WSDKErrorSeverityConst: any; + + const EventType = { + Unknown: 0, + Navigation: 1, + Location: 2, + Search: 3, + Transaction: 4, + UserContent: 5, + UserPreference: 6, + Social: 7, + Other: 8, + Media: 9, + }; + const MessageType = { + SessionStart: 1, + SessionEnd: 2, + PageView: 3, + PageEvent: 4, + CrashReport: 5, + OptOut: 6, + Commerce: 16, + }; + const ReportingService = function (this: any) { + const self = this; + + this.id = null; + this.event = null; + + this.cb = function (forwarder: any, event: any) { + self.id = forwarder.id; + self.event = event; + }; + + this.reset = function () { + this.id = null; + this.event = null; + }; + }; + const reportService = new (ReportingService as any)(); + + // -------------------DO NOT EDIT ANYTHING ABOVE THIS LINE----------------------- + // -------------------START EDITING BELOW:----------------------- + // -------------------mParticle stubs - Add any additional stubbing to our methods as needed----------------------- + mParticle.getEnvironment = function () { + return 'development'; + }; + mParticle.getVersion = function () { + return '1.2.3'; + }; + mParticle.Identity = { + getCurrentUser: function () { + return { + getMPID: function () { + return '123'; + }, + }; + }, + }; + mParticle._Store = { + localSessionAttributes: {}, + }; + mParticle.sessionManager = { + getSession: function () { + return 'test-mp-session-id'; + }, + }; + mParticle._getActiveForwarders = function () { + return []; + }; + mParticle.generateHash = function (input: any) { + return 'hashed-<' + input + '>-value'; + }; + // Mock for logEvent to capture custom event logging + mParticle.loggedEvents = []; + mParticle.logEvent = function (eventName: any, eventType: any, eventAttributes: any) { + mParticle.loggedEvents.push({ + eventName: eventName, + eventType: eventType, + eventAttributes: eventAttributes, + }); + }; + // -------------------START EDITING BELOW:----------------------- + const MockRoktForwarder = function (this: any) { + const self = this; + + this.initializeCalled = false; + this.isInitialized = false; + this.accountId = null; + this.sandbox = null; + this.integrationName = null; + this.createLauncherCalled = false; + this.createLocalLauncherCalled = false; + + this.createLauncher = function (options: any) { + self.accountId = options.accountId; + self.integrationName = options.integrationName; + self.noFunctional = options.noFunctional; + self.noTargeting = options.noTargeting; + self.mpSessionId = options.mpSessionId; + self.createLauncherCalled = true; + self.isInitialized = true; + self.sandbox = options.sandbox; + + return Promise.resolve({ + then: function (callback: any) { + callback(); + }, + }); + }; + + this.createLocalLauncher = function (options: any) { + self.accountId = options.accountId; + self.integrationName = options.integrationName; + self.noFunctional = options.noFunctional; + self.noTargeting = options.noTargeting; + self.mpSessionId = options.mpSessionId; + self.createLocalLauncherCalled = true; + self.isInitialized = true; + self.sandbox = options.sandbox; + + return { + selectPlacements: function () {}, + hashAttributes: function () { + throw new Error('hashAttributes not implemented'); + }, + use: function () { + throw new Error('use not implemented'); + }, + }; + }; + + this.currentLauncher = function () {}; + }; + + beforeAll(async () => { + (window as any).Rokt = new (MockRoktForwarder as any)(); + (window as any).mParticle.Rokt = (window as any).Rokt; + (window as any).mParticle.Rokt.attachKit = async (kit: any) => { + (window as any).mParticle.Rokt.kit = kit; + }; + (window as any).mParticle.Rokt.filters = { + userAttributesFilters: [], + filterUserAttributes: function (attributes: any) { + return attributes; + }, + filteredUser: { + getMPID: function () { + return '123'; + }, + }, + }; + await mParticle.forwarder.init({ accountId: '000000' }, reportService.cb, true, null, {}); + + const testHelpers = (window as any).mParticle.forwarder.testHelpers; + _ReportingTransportClass = testHelpers?.ReportingTransport; + ErrorReportingServiceClass = testHelpers?.ErrorReportingService; + LoggingServiceClass = testHelpers?.LoggingService; + RateLimiterClass = testHelpers?.RateLimiter; + ErrorCodesConst = testHelpers?.ErrorCodes; + WSDKErrorSeverityConst = testHelpers?.WSDKErrorSeverity; + }); + + beforeEach(() => { + (window as any).Rokt = new (MockRoktForwarder as any)(); + (window as any).mParticle.Rokt = (window as any).Rokt; + }); + + afterEach(() => { + (window as any).mParticle.forwarder.userAttributes = {}; + delete (window as any).mParticle.forwarder.launcherOptions; + delete (window as any).mParticle.Rokt.launcherOptions; + }); + + describe('#initForwarder', () => { + beforeEach(() => { + (window as any).Rokt = new (MockRoktForwarder as any)(); + (window as any).mParticle.Rokt = (window as any).Rokt; + (window as any).mParticle.Rokt.attachKitCalled = false; + (window as any).mParticle.Rokt.attachKit = async (kit: any) => { + (window as any).mParticle.Rokt.attachKitCalled = true; + (window as any).mParticle.Rokt.kit = kit; + Promise.resolve(); + }; + (window as any).mParticle.Rokt.filters = { + userAttributesFilters: [], + filterUserAttributes: function (attributes: any) { + return attributes; + }, + filteredUser: { + getMPID: function () { + return '123'; + }, + }, + }; + }); + + it('should initialize the Rokt Web SDK', async () => { + await mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + {}, + ); + + expect((window as any).Rokt.accountId).toBe('123456'); + expect((window as any).Rokt.createLauncherCalled).toBe(true); + }); + + it('should set sandbox to true if sandbox is true in launcherOptions', async () => { + (window as any).mParticle.Rokt.launcherOptions = { + sandbox: true, + }; + + await mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + ); + + expect((window as any).Rokt.createLauncherCalled).toBe(true); + expect((window as any).Rokt.sandbox).toBe(true); + }); + + it('should set sandbox to false if sandbox is false in launcherOptions', async () => { + (window as any).mParticle.Rokt.launcherOptions = { + sandbox: false, + }; + + await mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + ); + + expect((window as any).Rokt.createLauncherCalled).toBe(true); + expect((window as any).Rokt.sandbox).toBe(false); + }); + + it('should set optional settings from launcherOptions', async () => { + (window as any).mParticle.Rokt.launcherOptions = { + integrationName: 'customName', + noFunctional: true, + noTargeting: true, + }; + + await mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + {}, + null, + null, + null, + ); + + const expectedIntegrationName = `${sdkVersion}_${kitVersion}_customName`; + + expect((window as any).Rokt.createLauncherCalled).toBe(true); + expect((window as any).Rokt.accountId).toBe('123456'); + expect((window as any).Rokt.integrationName).toBe(expectedIntegrationName); + expect((window as any).Rokt.noFunctional).toBe(true); + expect((window as any).Rokt.noTargeting).toBe(true); + }); + + it('should set the filters on the forwarder', async () => { + await mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + {}, + ); + + // Wait for initialization to complete (after launcher is created) + await waitForCondition(() => { + return (window as any).mParticle.forwarder.isInitialized; + }); + + // kit.filters is the same reference as window.mParticle.Rokt.filters + expect((window as any).mParticle.Rokt.kit.filters).toBe((window as any).mParticle.Rokt.filters); + + expect((window as any).mParticle.Rokt.kit.filters.filteredUser.getMPID()).toBe('123'); + }); + + it('should set integrationName in the correct format', async () => { + (window as any).Rokt = new (MockRoktForwarder as any)(); + (window as any).mParticle.Rokt = (window as any).Rokt; + (window as any).mParticle.Rokt.attachKitCalled = false; + (window as any).mParticle.Rokt.attachKit = async () => { + (window as any).mParticle.Rokt.attachKitCalled = true; + return Promise.resolve(); + }; + + await mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + ); + + expect((window as any).Rokt.integrationName).toBe(`${sdkVersion}_${kitVersion}`); + }); + + it('should set integrationName on kit instance after attaching', async () => { + (window as any).Rokt = new (MockRoktForwarder as any)(); + (window as any).mParticle.Rokt = (window as any).Rokt; + (window as any).mParticle.Rokt.attachKitCalled = false; + + (window as any).mParticle.Rokt.attachKit = async (kit: any) => { + (window as any).mParticle.Rokt.attachKitCalled = true; + (window as any).mParticle.Rokt.kit = kit; + return Promise.resolve(); + }; + + await mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + ); + + // Wait for initialization to complete + await waitForCondition(() => (window as any).mParticle.Rokt.isInitialized); + + expect((window as any).mParticle.Rokt.kit.integrationName).toBe(`${sdkVersion}_${kitVersion}`); + }); + + it('should set integrationName on kit instance with custom name when provided', async () => { + const customName = 'myCustomName'; + + (window as any).Rokt = new (MockRoktForwarder as any)(); + (window as any).mParticle.Rokt = (window as any).Rokt; + (window as any).mParticle.Rokt.attachKitCalled = false; + + (window as any).mParticle.Rokt.attachKit = async (kit: any) => { + (window as any).mParticle.Rokt.attachKitCalled = true; + (window as any).mParticle.Rokt.kit = kit; + return Promise.resolve(); + }; + + (window as any).mParticle.Rokt.launcherOptions = { + integrationName: customName, + }; + + await mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + ); + + // Wait for initialization to complete + await waitForCondition(() => (window as any).mParticle.Rokt.isInitialized); + + expect((window as any).mParticle.Rokt.kit.integrationName).toBe(`${sdkVersion}_${kitVersion}_${customName}`); + }); + + it('should have integrationName available on kit after initialization', async () => { + (window as any).Rokt = new (MockRoktForwarder as any)(); + (window as any).mParticle.Rokt = (window as any).Rokt; + (window as any).mParticle.Rokt.attachKitCalled = false; + + (window as any).mParticle.Rokt.attachKit = async (kit: any) => { + (window as any).mParticle.Rokt.attachKitCalled = true; + (window as any).mParticle.Rokt.kit = kit; + return Promise.resolve(); + }; + + await mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + ); + + // Wait for initialization to complete + await waitForCondition(() => (window as any).mParticle.Rokt.isInitialized); + + expect((window as any).mParticle.Rokt.attachKitCalled).toBe(true); + expect(typeof (window as any).mParticle.Rokt.kit.integrationName).toBe('string'); + expect((window as any).mParticle.Rokt.kit.integrationName).toBeTruthy(); + }); + + it('should not mutate the global launcherOptions object during initialization', async () => { + const originalIntegrationName = 'globalIntegrationName'; + + (window as any).Rokt = new (MockRoktForwarder as any)(); + (window as any).mParticle.Rokt = (window as any).Rokt; + (window as any).mParticle.Rokt.attachKitCalled = false; + (window as any).mParticle.Rokt.attachKit = async () => { + (window as any).mParticle.Rokt.attachKitCalled = true; + return Promise.resolve(); + }; + + // Set up the global launcherOptions with a custom integration name + (window as any).mParticle.Rokt.launcherOptions = { + integrationName: originalIntegrationName, + sandbox: true, + }; + + // Store reference to verify it doesn't get mutated + const originalLauncherOptions = (window as any).mParticle.Rokt.launcherOptions; + + await mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + {}, + null, + null, + null, + ); + + expect(originalLauncherOptions.integrationName).toBe('globalIntegrationName'); + expect(originalLauncherOptions.sandbox).toBe(true); + + // Verify the kit still gets the processed integration name + const expectedProcessedName = `${sdkVersion}_${kitVersion}_${originalIntegrationName}`; + expect((window as any).Rokt.integrationName).toBe(expectedProcessedName); + }); + + it('should initialize the kit with placement event mapping lookup from a config', async () => { + await mParticle.forwarder.init( + { + accountId: '123456', + placementEventMapping: JSON.stringify([ + { + jsmap: '-1484452948', + map: '-5208850776883573773', + maptype: 'EventClass.Id', + value: 'foo-mapped-flag', + }, + { + jsmap: '1838502119', + map: '1324617889422969328', + maptype: 'EventClass.Id', + value: 'ad_viewed_test', + }, + ]), + }, + reportService.cb, + true, + null, + {}, + ); + + // Wait for initialization to complete (after launcher is created) + await waitForCondition(() => (window as any).mParticle.Rokt.isInitialized); + + expect((window as any).mParticle.forwarder.placementEventMappingLookup).toEqual({ + '-1484452948': 'foo-mapped-flag', + 1838502119: 'ad_viewed_test', + }); + }); + }); + + describe('#hashAttributes', () => { + beforeEach(() => { + (window as any).Rokt = new (MockRoktForwarder as any)(); + (window as any).mParticle.Rokt = (window as any).Rokt; + (window as any).mParticle.Rokt.attachKitCalled = false; + (window as any).mParticle.Rokt.attachKit = async (kit: any) => { + (window as any).mParticle.Rokt.attachKitCalled = true; + (window as any).mParticle.Rokt.kit = kit; + Promise.resolve(); + }; + (window as any).mParticle.forwarder.launcher = { + hashAttributes: function (attributes: any) { + // Mocking the hashAttributes method to show that + // the attributes will be transformed by the launcher's + // hashAttributes method. + const hashedAttributes: any = {}; + for (const key in attributes) { + if (attributes.hasOwnProperty(key)) { + hashedAttributes[key + '-hash'] = 'hashed-' + attributes[key]; + } + } + (window as any).mParticle.Rokt.hashedAttributes = hashedAttributes; + (window as any).mParticle.Rokt.hashAttributesCalled = true; + + return Promise.resolve(hashedAttributes); + }, + }; + }); + + it('should call launcher.hashAttributes with passed through attributes when fully initialized', function () { + // Ensure both initialization conditions are met + (window as any).mParticle.forwarder.isInitialized = true; + (window as any).mParticle.forwarder.launcher = { + hashAttributes: function (attributes: any) { + (window as any).mParticle.Rokt.hashAttributesOptions = attributes; + (window as any).mParticle.Rokt.hashAttributesCalled = true; + return { + 'test-attribute': 'hashed-value', + }; + }, + }; + + const attributes = { + 'test-attribute': 'test-value', + }; + + (window as any).mParticle.forwarder.hashAttributes(attributes); + + expect((window as any).Rokt.hashAttributesCalled).toBe(true); + expect((window as any).Rokt.hashAttributesOptions).toEqual(attributes); + }); + + it('should return null when launcher exists but kit is not initialized', function () { + // Set launcher but ensure isInitialized is false + (window as any).mParticle.forwarder.isInitialized = false; + (window as any).mParticle.forwarder.launcher = { + hashAttributes: function () {}, + }; + + const result = (window as any).mParticle.forwarder.hashAttributes({ + 'test-attribute': 'test-value', + }); + + expect(result).toBeNull(); + }); + + it('should log an error when called before initialization', function () { + let errorLogged = false; + let errorMessage = null; + window.console.error = function (message: any) { + errorLogged = true; + errorMessage = message; + }; + + // Ensure kit is not initialized + (window as any).mParticle.forwarder.isInitialized = false; + (window as any).mParticle.forwarder.launcher = null; + + (window as any).mParticle.forwarder.hashAttributes({ + 'test-attribute': 'test-value', + }); + + expect(errorLogged).toBe(true); + expect(errorMessage).toBe('Rokt Kit: Not initialized'); + }); + + it('should return null when kit is initialized but launcher is missing', function () { + // Mock isInitialized but remove launcher + (window as any).mParticle.forwarder.isInitialized = true; + (window as any).mParticle.forwarder.launcher = null; + + const result = (window as any).mParticle.forwarder.hashAttributes({ + 'test-attribute': 'test-value', + }); + + expect(result).toBeNull(); + }); + + it('should log an error when kit is initialized but launcher is missing', function () { + let errorLogged = false; + let errorMessage = null; + window.console.error = function (message: any) { + errorLogged = true; + errorMessage = message; + }; + + (window as any).mParticle.forwarder.isInitialized = true; + (window as any).mParticle.forwarder.launcher = null; + + (window as any).mParticle.forwarder.hashAttributes({ + 'test-attribute': 'test-value', + }); + + expect(errorLogged).toBe(true); + expect(errorMessage).toBe('Rokt Kit: Not initialized'); + }); + + it('should return hashed attributes from launcher', async () => { + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + {}, + ); + + const result = await (window as any).mParticle.forwarder.hashAttributes({ + 'test-attribute': 'test-value', + }); + + expect(result).toEqual({ + 'test-attribute-hash': 'hashed-test-value', + }); + }); + }); + + describe('#attachLauncher', () => { + let mockMessageQueue: any[]; + + beforeEach(() => { + mockMessageQueue = []; + + // Reset forwarder state between tests + (window as any).mParticle.forwarder.isInitialized = false; + + (window as any).Rokt = new (MockRoktForwarder as any)(); + (window as any).mParticle.Rokt = (window as any).Rokt; + (window as any).mParticle.Rokt.attachKitCalled = false; + + // Ensure currentLauncher is undefined to trigger script appending + (window as any).Rokt.currentLauncher = undefined; + + // Set attachKit as async to allow for await calls in the test + // This is necessary to simiulate a race condition between the + // core sdk and the Rokt forwarder + (window as any).mParticle.Rokt.attachKit = async (kit: any) => { + (window as any).mParticle.Rokt.attachKitCalled = true; + (window as any).mParticle.Rokt.kit = kit; + + // Call queued messages + mockMessageQueue.forEach((message) => message()); + mockMessageQueue = []; + + return Promise.resolve(); + }; + (window as any).mParticle.Rokt.filters = { + userAttributesFilters: [], + filterUserAttributes: function (attributes: any) { + return attributes; + }, + filteredUser: { + getMPID: function () { + return '123'; + }, + }, + }; + (window as any).mParticle.config = undefined; + Math.random = () => 1; + + (window as any).mParticle.captureTiming = function (metricName: any) { + (window as any).mParticle.Rokt.capturedPerformanceMetric = metricName; + }; + }); + + it('should add a performance marker when the script is appended', async () => { + const savedRokt = (window as any).mParticle.Rokt; + (window as any).Rokt = undefined; + (window as any).mParticle.Rokt = { + domain: 'apps.rokt.com', + attachKit: async () => Promise.resolve(), + filters: savedRokt.filters, + }; + + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, false, null, {}); + + expect((window as any).mParticle.Rokt.capturedPerformanceMetric).toBe('mp:RoktScriptAppended'); + }); + + it('should create a remote launcher if the partner is not in the local launcher test group', async () => { + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + expect((window as any).mParticle.Rokt.createLauncherCalled).toBe(true); + expect((window as any).mParticle.Rokt.createLocalLauncherCalled).toBe(false); + }); + + it('should create a local launcher if the partner is in the local launcher test group', async () => { + (window as any).mParticle.config = { + isLocalLauncherEnabled: true, + }; + + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + expect((window as any).mParticle.Rokt.createLauncherCalled).toBe(false); + expect((window as any).mParticle.Rokt.createLocalLauncherCalled).toBe(true); + }); + + it('should create a remote launcher if the partner is in the local launcher test group but the random number is below the thresholds', async () => { + (window as any).mParticle.config = { + isLocalLauncherEnabled: true, + }; + + Math.random = () => 0; + + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + expect((window as any).mParticle.Rokt.createLauncherCalled).toBe(true); + expect((window as any).mParticle.Rokt.createLocalLauncherCalled).toBe(false); + }); + + it('should create a local launcher if the partner is in the local launcher test group but the random number is above the thresholds', async () => { + (window as any).mParticle.config = { + isLocalLauncherEnabled: true, + }; + + Math.random = () => 1; + + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + expect((window as any).mParticle.Rokt.createLauncherCalled).toBe(false); + expect((window as any).mParticle.Rokt.createLocalLauncherCalled).toBe(true); + }); + + it('should call attachKit', async () => { + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + expect((window as any).mParticle.Rokt.attachKitCalled).toBe(true); + }); + + it('should set isInitialized to true', async () => { + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + expect((window as any).mParticle.forwarder.isInitialized).toBe(true); + }); + + // This test is to ensure the kit is initialized before attaching to the Rokt manager + // so we can ensure that the Rokt Manager's message queue is processed and that + // all the isReady() checks are properly handled in by the Rokt Manager. + // This is to validate in case a bug that was found in the Rokt Manager's + // queueing logic regresses. + it('should initialize the kit before calling queued messages', async () => { + let queuedMessageCalled = false; + let wasKitInitializedFirst = false; + + const queuedMessage = () => { + wasKitInitializedFirst = (window as any).mParticle.Rokt.kit && (window as any).mParticle.Rokt.kit.isInitialized; + queuedMessageCalled = true; + }; + + mockMessageQueue.push(queuedMessage); + + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + expect((window as any).mParticle.forwarder.isInitialized).toBe(false); + expect(queuedMessageCalled).toBe(false); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + expect((window as any).mParticle.forwarder.isInitialized).toBe(true); + expect(queuedMessageCalled).toBe(true); + + expect(wasKitInitializedFirst).toBe(true); + + expect(mockMessageQueue.length).toBe(0); + }); + + it('should call createLauncher when launcher is embedded and not yet initialized', async () => { + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, false, null, {}); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + expect((window as any).mParticle.Rokt.createLauncherCalled).toBe(true); + }); + + it('should pass mpSessionId from mParticle sessionManager to createLauncher', async () => { + (window as any).mParticle.sessionManager = { + getSession: function () { + return 'my-mp-session-123'; + }, + }; + + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + expect((window as any).mParticle.Rokt.mpSessionId).toBe('my-mp-session-123'); + }); + + it('should not pass mpSessionId when sessionManager is unavailable', async () => { + delete (window as any).mParticle.sessionManager; + + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + expect((window as any).mParticle.Rokt.mpSessionId).toBeUndefined(); + }); + }); + + describe('#selectPlacements', () => { + beforeEach(() => { + (window as any).Rokt = new (MockRoktForwarder as any)(); + (window as any).mParticle.Rokt = (window as any).Rokt; + (window as any).mParticle.Rokt.attachKit = async () => { + (window as any).mParticle.Rokt.attachKitCalled = true; + return Promise.resolve(); + }; + mParticle.loggedEvents = []; + (window as any).mParticle.Rokt.setLocalSessionAttribute = function (key: any, value: any) { + mParticle._Store.localSessionAttributes[key] = value; + }; + (window as any).mParticle.Rokt.getLocalSessionAttributes = function () { + return mParticle._Store.localSessionAttributes; + }; + (window as any).mParticle.Rokt.store = (window as any).mParticle._Store; + (window as any).mParticle.Rokt.store.localSessionAttributes = {}; + (window as any).mParticle.forwarder.launcher = { + selectPlacements: function (options: any) { + (window as any).mParticle.Rokt.selectPlacementsOptions = options; + (window as any).mParticle.Rokt.selectPlacementsCalled = true; + }, + }; + (window as any).mParticle.forwarder.filters = { + userAttributesFilters: [], + filterUserAttributes: function (attributes: any) { + return attributes; + }, + filteredUser: { + getMPID: function () { + return '123'; + }, + }, + }; + }); + + describe('Default initialization', () => { + it('should call launcher.selectPlacements with all passed through options', async () => { + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + {}, + ); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: { + test: 'test', + }, + }); + + expect((window as any).Rokt.selectPlacementsCalled).toBe(true); + expect((window as any).Rokt.selectPlacementsOptions).toEqual({ + identifier: 'test-placement', + attributes: { + test: 'test', + mpid: '123', + }, + }); + }); + + it('should collect mpid and send to launcher.selectPlacements', async () => { + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + { + 'user-attribute': 'user-attribute-value', + }, + ); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: { + 'user-attribute': 'user-attribute-value', + }, + }); + + expect((window as any).Rokt.selectPlacementsCalled).toBe(true); + expect((window as any).Rokt.selectPlacementsOptions).toEqual({ + identifier: 'test-placement', + attributes: { + 'user-attribute': 'user-attribute-value', + mpid: '123', + }, + }); + }); + + it('should collect local session attributes and send to launcher.selectPlacements', async () => { + (window as any).mParticle.Rokt.store.localSessionAttributes = { + 'custom-local-attribute': true, + 'secondary-local-attribute': true, + }; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + placementEventMapping: JSON.stringify([ + { + jsmap: 'test-event-hash', + map: 'test-event-map', + maptype: 'EventClass.Id', + value: 'test-mapped-flag', + }, + ]), + }, + reportService.cb, + true, + ); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: { + 'test-attribute': 'test-value', + }, + }); + + expect((window as any).Rokt.selectPlacementsCalled).toBe(true); + expect((window as any).Rokt.selectPlacementsOptions).toEqual({ + identifier: 'test-placement', + attributes: { + mpid: '123', + 'test-attribute': 'test-value', + 'custom-local-attribute': true, + 'secondary-local-attribute': true, + }, + }); + }); + + it('should not throw an error if getLocalSessionAttributes is not available', async () => { + let errorLogged = false; + const originalConsoleError = console.error; + console.error = function (message: any) { + if (message && message.indexOf && message.indexOf('Error getting local session attributes') !== -1) { + errorLogged = true; + } + originalConsoleError.apply(console, arguments as any); + }; + + delete (window as any).mParticle.Rokt.getLocalSessionAttributes; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + ); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: { + 'test-attribute': 'test-value', + }, + }); + + expect(errorLogged).toBe(false); + + console.error = originalConsoleError; + }); + }); + + describe('User Attributes', () => { + it('should call launcher.selectPlacements with filtered user attributes', async () => { + (window as any).mParticle.forwarder.filters.filterUserAttributes = function () { + return { + 'user-attribute': 'user-attribute-value', + 'unfiltered-attribute': 'unfiltered-value', + }; + }; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + {}, + ); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: { + 'unfiltered-attribute': 'unfiltered-value', + 'filtered-attribute': 'filtered-value', + }, + }); + + expect((window as any).Rokt.selectPlacementsCalled).toBe(true); + expect((window as any).Rokt.selectPlacementsOptions).toEqual({ + identifier: 'test-placement', + attributes: { + 'user-attribute': 'user-attribute-value', + 'unfiltered-attribute': 'unfiltered-value', + mpid: '123', + }, + }); + }); + + it('should filter user attributes through filterUserAttributes function before sending to selectPlacements', async () => { + // Mocked filterUserAttributes function will return filtered attributes + // based on the config passed in the init method and will ultimately + // remove any attributes from the init method that are filtered. + // Also, any initial attributes from the init call that have updated + // durring runtime should be returned by the filterUserAttribute method. + (window as any).mParticle.forwarder.filters.filterUserAttributes = function () { + return { + 'user-attribute': 'user-attribute-value', + 'unfiltered-attribute': 'unfiltered-value', + 'changed-attribute': 'new-value', + }; + }; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + { + // These should be filtered out + 'blocked-attribute': 'blocked-value', + 'initial-user-attribute': 'initial-user-attribute-value', + + // This should be updated + 'changed-attribute': 'old-value', + }, + ); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: { + // This should pass through + 'unfiltered-attribute': 'unfiltered-value', + + // This should be filtered out + 'filtered-attribute': 'filtered-value', + }, + }); + + expect((window as any).Rokt.selectPlacementsCalled).toBe(true); + expect((window as any).Rokt.selectPlacementsOptions).toEqual({ + identifier: 'test-placement', + attributes: { + 'user-attribute': 'user-attribute-value', + 'unfiltered-attribute': 'unfiltered-value', + 'changed-attribute': 'new-value', + mpid: '123', + }, + }); + }); + }); + + describe('Identity handling', () => { + beforeEach(() => { + (window as any).Rokt = new (MockRoktForwarder as any)(); + (window as any).mParticle.Rokt = (window as any).Rokt; + (window as any).mParticle.Rokt.attachKitCalled = false; + (window as any).mParticle.Rokt.attachKit = async (kit: any) => { + (window as any).mParticle.Rokt.attachKitCalled = true; + (window as any).mParticle.Rokt.kit = kit; + Promise.resolve(); + }; + (window as any).mParticle.Rokt.setLocalSessionAttribute = function (key: any, value: any) { + mParticle._Store.localSessionAttributes[key] = value; + }; + (window as any).mParticle.Rokt.getLocalSessionAttributes = function () { + return mParticle._Store.localSessionAttributes; + }; + (window as any).mParticle.forwarder.launcher = { + selectPlacements: function (options: any) { + (window as any).mParticle.Rokt.selectPlacementsOptions = options; + (window as any).mParticle.Rokt.selectPlacementsCalled = true; + }, + }; + }); + + it('should send userAttributes if userIdentities is null but userAttributes exists', async () => { + (window as any).mParticle.Rokt.filters = { + userAttributeFilters: [], + filterUserAttributes: function (attributes: any) { + return attributes; + }, + filteredUser: { + getMPID: function () { + return 'abc'; + }, + getUserIdentities: function () { + return { userIdentities: {} }; + }, + }, + }; + + // Set up the createLauncher to properly resolve asynchronously + (window as any).Rokt.createLauncher = async function () { + return Promise.resolve({ + selectPlacements: function (options: any) { + (window as any).mParticle.Rokt.selectPlacementsOptions = options; + (window as any).mParticle.Rokt.selectPlacementsCalled = true; + }, + }); + }; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + { + 'test-attribute': 'test-value', + }, + ); + + // Wait for initialization to complete (after launcher is created) + await waitForCondition(() => { + return (window as any).mParticle.forwarder.isInitialized; + }); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: {}, + }); + + expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ + 'test-attribute': 'test-value', + mpid: 'abc', + }); + }); + + it('should send userIdentities when userAttributes is null but userIdentities exists', async () => { + (window as any).mParticle.Rokt.filters = { + userAttributeFilters: [], + filterUserAttributes: function () { + return {}; + }, + filteredUser: { + getMPID: function () { + return '234'; + }, + getUserIdentities: function () { + return { + userIdentities: { + customerid: 'customer123', + email: 'test@example.com', + }, + }; + }, + }, + }; + + // Set up the createLauncher to properly resolve asynchronously + (window as any).Rokt.createLauncher = async function () { + return Promise.resolve({ + selectPlacements: function (options: any) { + (window as any).mParticle.Rokt.selectPlacementsOptions = options; + (window as any).mParticle.Rokt.selectPlacementsCalled = true; + }, + }); + }; + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + {}, + ); + // Wait for initialization to complete (after launcher is created) + await waitForCondition(() => { + return (window as any).mParticle.forwarder.isInitialized; + }); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: {}, + }); + + expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ + customerid: 'customer123', + email: 'test@example.com', + mpid: '234', + }); + }); + + it('should send userAttributes and userIdentities if both exist', async () => { + (window as any).mParticle.Rokt.filters = { + userAttributeFilters: [], + filterUserAttributes: function (attributes: any) { + return attributes; + }, + filteredUser: { + getMPID: function () { + return '123'; + }, + getUserIdentities: function () { + return { + userIdentities: { + customerid: 'customer123', + email: 'test@example.com', + }, + }; + }, + }, + }; + + // Set up the createLauncher to properly resolve asynchronously + (window as any).Rokt.createLauncher = async function () { + return Promise.resolve({ + selectPlacements: function (options: any) { + (window as any).mParticle.Rokt.selectPlacementsOptions = options; + (window as any).mParticle.Rokt.selectPlacementsCalled = true; + }, + }); + }; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + { + 'test-attribute': 'test-value', + }, + ); + + // Wait for initialization to complete (after launcher is created) + await waitForCondition(() => { + return (window as any).mParticle.forwarder.isInitialized; + }); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: {}, + }); + + expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ + 'test-attribute': 'test-value', + customerid: 'customer123', + email: 'test@example.com', + mpid: '123', + }); + }); + + it('should not send userIdentities if filteredUser is null', async () => { + (window as any).mParticle.Rokt.filters = { + userAttributeFilters: [], + filterUserAttributes: function (attributes: any) { + return attributes; + }, + filteredUser: null, + }; + + // Set up the createLauncher to properly resolve asynchronously + (window as any).Rokt.createLauncher = async function () { + return Promise.resolve({ + selectPlacements: function (options: any) { + (window as any).mParticle.Rokt.selectPlacementsOptions = options; + (window as any).mParticle.Rokt.selectPlacementsCalled = true; + }, + }); + }; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + { + 'test-attribute': 'test-value', + }, + ); + + // Wait for initialization to complete (after launcher is created) + await waitForCondition(() => { + return (window as any).mParticle.forwarder.isInitialized; + }); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: {}, + }); + + expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ + 'test-attribute': 'test-value', + mpid: null, + }); + }); + + it('should not send userIdentities if getUserIdentities function does not exist', async () => { + (window as any).mParticle.Rokt.filters = { + userAttributeFilters: [], + filterUserAttributes: function (attributes: any) { + return attributes; + }, + filteredUser: { + getMPID: function () { + return '123'; + }, + // getUserIdentities is intentionally missing + }, + }; + + (window as any).Rokt.createLauncher = async function () { + return Promise.resolve({ + selectPlacements: function (options: any) { + (window as any).mParticle.Rokt.selectPlacementsOptions = options; + (window as any).mParticle.Rokt.selectPlacementsCalled = true; + }, + }); + }; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + { + 'test-attribute': 'test-value', + }, + ); + + // Wait for initialization to complete (after launcher is created) + await waitForCondition(() => { + return (window as any).mParticle.forwarder.isInitialized; + }); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: {}, + }); + + expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ + 'test-attribute': 'test-value', + mpid: '123', + }); + }); + + it('should map other userIdentities to emailsha256', async () => { + (window as any).mParticle.Rokt.filters = { + userAttributeFilters: [], + filterUserAttributes: function () { + return {}; + }, + filteredUser: { + getMPID: function () { + return '234'; + }, + getUserIdentities: function () { + return { + userIdentities: { + customerid: 'customer123', + other: 'sha256-test@gmail.com', + }, + }; + }, + }, + }; + + // Set up the createLauncher to properly resolve asynchronously + (window as any).Rokt.createLauncher = async function () { + return Promise.resolve({ + selectPlacements: function (options: any) { + (window as any).mParticle.Rokt.selectPlacementsOptions = options; + (window as any).mParticle.Rokt.selectPlacementsCalled = true; + }, + }); + }; + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + hashedEmailUserIdentityType: 'Other', + }, + reportService.cb, + true, + null, + {}, + ); + // Wait for initialization to complete (after launcher is created) + await waitForCondition(() => { + return (window as any).mParticle.forwarder.isInitialized; + }); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: {}, + }); + + expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ + customerid: 'customer123', + emailsha256: 'sha256-test@gmail.com', + mpid: '234', + }); + }); + + it('should map other to emailsha256 when other is passed through selectPlacements', async () => { + (window as any).mParticle.Rokt.filters = { + userAttributeFilters: [], + filterUserAttributes: function (attributes: any) { + return attributes; + }, + filteredUser: { + getMPID: function () { + return '123'; + }, + getUserIdentities: function () { + return { + userIdentities: { + customerid: 'customer123', + }, + }; + }, + }, + }; + + // Set up the createLauncher to properly resolve asynchronously + (window as any).Rokt.createLauncher = async function () { + return Promise.resolve({ + selectPlacements: function (options: any) { + (window as any).mParticle.Rokt.selectPlacementsOptions = options; + (window as any).mParticle.Rokt.selectPlacementsCalled = true; + }, + }); + }; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + { + 'test-attribute': 'test-value', + }, + ); + + // Wait for initialization to complete (after launcher is created) + await waitForCondition(() => { + return (window as any).mParticle.forwarder.isInitialized; + }); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: { + other: 'other-attribute', + }, + }); + + expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ + 'test-attribute': 'test-value', + customerid: 'customer123', + other: 'other-attribute', + mpid: '123', + }); + }); + + it('should pass the attribute `other` in selectPlacements directly to Rokt', async () => { + (window as any).mParticle.Rokt.filters = { + userAttributeFilters: [], + filterUserAttributes: function (attributes: any) { + return attributes; + }, + filteredUser: { + getMPID: function () { + return '123'; + }, + getUserIdentities: function () { + return { + userIdentities: { + customerid: 'customer123', + other: 'other-id', + }, + }; + }, + }, + }; + + // Set up the createLauncher to properly resolve asynchronously + (window as any).Rokt.createLauncher = async function () { + return Promise.resolve({ + selectPlacements: function (options: any) { + (window as any).mParticle.Rokt.selectPlacementsOptions = options; + (window as any).mParticle.Rokt.selectPlacementsCalled = true; + }, + }); + }; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + { + 'test-attribute': 'test-value', + }, + ); + + // Wait for initialization to complete (after launcher is created) + await waitForCondition(() => { + return (window as any).mParticle.forwarder.isInitialized; + }); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: { + other: 'continues-to-exist', + }, + }); + + expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ + 'test-attribute': 'test-value', + customerid: 'customer123', + other: 'continues-to-exist', + emailsha256: 'other-id', + mpid: '123', + }); + }); + + it('should use custom hashedEmailUserIdentityType when provided in settings', async () => { + (window as any).mParticle.Rokt.filters = { + userAttributeFilters: [], + filterUserAttributes: function (attributes: any) { + return attributes; + }, + filteredUser: { + getMPID: function () { + return '789'; + }, + getUserIdentities: function () { + return { + userIdentities: { + // Using 'customerid' as the identity type instead of 'other' + other5: 'hashed-customer-id-value', + }, + }; + }, + }, + }; + + // Set up the createLauncher to properly resolve asynchronously + (window as any).Rokt.createLauncher = async function () { + return Promise.resolve({ + selectPlacements: function (options: any) { + (window as any).mParticle.Rokt.selectPlacementsOptions = options; + (window as any).mParticle.Rokt.selectPlacementsCalled = true; + }, + }); + }; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + hashedEmailUserIdentityType: 'Other5', // TitleCase from server + }, + reportService.cb, + true, + null, + {}, + ); + + // Wait for initialization to complete (after launcher is created) + await waitForCondition(() => { + return (window as any).mParticle.forwarder.isInitialized; + }); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: { + 'test-attribute': 'test-value', + }, + }); + + // Should map customerid from userIdentities to emailsha256 since hashedEmailUserIdentityType was set to 'CustomerID' + expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ + 'test-attribute': 'test-value', + emailsha256: 'hashed-customer-id-value', // mapped from customerid in userIdentities + mpid: '789', + }); + }); + + it('should NOT set emailsha256 on final select placements attributes when hashedEmailUserIdentityType is Unassigned', async () => { + (window as any).mParticle.Rokt.filters = { + userAttributeFilters: [], + filterUserAttributes: function (attributes: any) { + return attributes; + }, + filteredUser: { + getMPID: function () { + return '999'; + }, + getUserIdentities: function () { + return { + userIdentities: { + // Using lowercase identity name that matches the converted OTHER_IDENTITY + other: 'hashed-custom-identity-value', + }, + }; + }, + }, + }; + + // Set up the createLauncher to properly resolve asynchronously + (window as any).Rokt.createLauncher = async function () { + return Promise.resolve({ + selectPlacements: function (options: any) { + (window as any).mParticle.Rokt.selectPlacementsOptions = options; + (window as any).mParticle.Rokt.selectPlacementsCalled = true; + }, + }); + }; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + hashedEmailUserIdentityType: 'Unassigned', // Mixed case from server + }, + reportService.cb, + true, + null, + {}, + ); + + // Wait for initialization to complete (after launcher is created) + await waitForCondition(() => { + return (window as any).mParticle.forwarder.isInitialized; + }); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: { + 'test-attr': 'test-value', + }, + }); + + // Should map customidentity from userIdentities to emailsha256 (TitleCase converted to lowercase) + expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ + 'test-attr': 'test-value', + other: 'hashed-custom-identity-value', + mpid: '999', + }); + }); + + it('should keep both email and emailsha256 when emailsha256 is passed through selectPlacements and email exists in userIdentities', async () => { + (window as any).mParticle.Rokt.filters = { + userAttributeFilters: [], + filterUserAttributes: function (attributes: any) { + return attributes; + }, + filteredUser: { + getMPID: function () { + return '456'; + }, + getUserIdentities: function () { + return { + userIdentities: { + email: 'test@example.com', + }, + }; + }, + }, + }; + + // Set up the createLauncher to properly resolve asynchronously + (window as any).Rokt.createLauncher = async function () { + return Promise.resolve({ + selectPlacements: function (options: any) { + (window as any).mParticle.Rokt.selectPlacementsOptions = options; + (window as any).mParticle.Rokt.selectPlacementsCalled = true; + }, + }); + }; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + {}, + ); + + // Wait for initialization to complete (after launcher is created) + await waitForCondition(() => { + return (window as any).mParticle.forwarder.isInitialized; + }); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: { + emailsha256: 'hashed-email-value', + }, + }); + + // Should keep both email from userIdentities and emailsha256 from selectPlacements + expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ + email: 'test@example.com', + emailsha256: 'hashed-email-value', + mpid: '456', + }); + }); + + it('should keep both email and emailsha256 when both are passed through selectPlacements', async () => { + (window as any).mParticle.Rokt.filters = { + userAttributeFilters: [], + filterUserAttributes: function (attributes: any) { + return attributes; + }, + filteredUser: { + getMPID: function () { + return '789'; + }, + getUserIdentities: function () { + return { + userIdentities: { + email: 'identity-email@example.com', + }, + }; + }, + }, + }; + + // Set up the createLauncher to properly resolve asynchronously + (window as any).Rokt.createLauncher = async function () { + return Promise.resolve({ + selectPlacements: function (options: any) { + (window as any).mParticle.Rokt.selectPlacementsOptions = options; + (window as any).mParticle.Rokt.selectPlacementsCalled = true; + }, + }); + }; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + {}, + ); + + // Wait for initialization to complete (after launcher is created) + await waitForCondition(() => { + return (window as any).mParticle.forwarder.isInitialized; + }); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: { + email: 'developer-email@example.com', + emailsha256: 'hashed-email-value', + }, + }); + + // Should keep both email and emailsha256 since developer explicitly passed both + expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ + email: 'developer-email@example.com', + emailsha256: 'hashed-email-value', + mpid: '789', + }); + }); + + it('should include email in kit.selectPlacements call if not passed, and email exists in userIdentities', async () => { + (window as any).mParticle.Rokt.filters = { + userAttributeFilters: [], + filterUserAttributes: function (attributes: any) { + return attributes; + }, + filteredUser: { + getMPID: function () { + return '901'; + }, + getUserIdentities: function () { + return { + userIdentities: { + email: 'identity-email@example.com', + customerid: 'customer456', + }, + }; + }, + }, + }; + + // Set up the createLauncher to properly resolve asynchronously + (window as any).Rokt.createLauncher = async function () { + return Promise.resolve({ + selectPlacements: function (options: any) { + (window as any).mParticle.Rokt.selectPlacementsOptions = options; + (window as any).mParticle.Rokt.selectPlacementsCalled = true; + }, + }); + }; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + {}, + ); + + // Wait for initialization to complete (after launcher is created) + await waitForCondition(() => { + return (window as any).mParticle.forwarder.isInitialized; + }); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: { + someAttribute: 'someValue', + }, + }); + + // Should keep email from userIdentities since emailsha256 does not exist + expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ + email: 'identity-email@example.com', + customerid: 'customer456', + someAttribute: 'someValue', + mpid: '901', + }); + }); + + it('should have both email and emailsha256 in kit.selectPlacements call if both exist on userIdentities, and neither is passed through selectPlacements', async () => { + (window as any).mParticle.Rokt.filters = { + userAttributeFilters: [], + filterUserAttributes: function (attributes: any) { + return attributes; + }, + filteredUser: { + getMPID: function () { + return '912'; + }, + getUserIdentities: function () { + return { + userIdentities: { + email: 'identity-email@example.com', + other: 'hashed-from-other', + customerid: 'customer789', + }, + }; + }, + }, + }; + + // Set up the createLauncher to properly resolve asynchronously + (window as any).Rokt.createLauncher = async function () { + return Promise.resolve({ + selectPlacements: function (options: any) { + (window as any).mParticle.Rokt.selectPlacementsOptions = options; + (window as any).mParticle.Rokt.selectPlacementsCalled = true; + }, + }); + }; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + hashedEmailUserIdentityType: 'Other', + }, + reportService.cb, + true, + null, + {}, + ); + + // Wait for initialization to complete (after launcher is created) + await waitForCondition(() => { + return (window as any).mParticle.forwarder.isInitialized; + }); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: {}, + }); + + // Should keep both email and emailsha256 since emailsha256 was mapped from other identity (not explicitly passed) + expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ + email: 'identity-email@example.com', + emailsha256: 'hashed-from-other', + customerid: 'customer789', + mpid: '912', + }); + }); + + it('should keep only email from selectPlacements when no emailsha256 exists', async () => { + (window as any).mParticle.Rokt.filters = { + userAttributeFilters: [], + filterUserAttributes: function (attributes: any) { + return attributes; + }, + filteredUser: { + getMPID: function () { + return '934'; + }, + getUserIdentities: function () { + return { + userIdentities: { + customerid: 'customer202', + }, + }; + }, + }, + }; + + // Set up the createLauncher to properly resolve asynchronously + (window as any).Rokt.createLauncher = async function () { + return Promise.resolve({ + selectPlacements: function (options: any) { + (window as any).mParticle.Rokt.selectPlacementsOptions = options; + (window as any).mParticle.Rokt.selectPlacementsCalled = true; + }, + }); + }; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + {}, + ); + + // Wait for initialization to complete (after launcher is created) + await waitForCondition(() => { + return (window as any).mParticle.forwarder.isInitialized; + }); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: { + email: 'developer-email@example.com', + }, + }); + + // Should keep email from selectPlacements since no emailsha256 exists + expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ + email: 'developer-email@example.com', + customerid: 'customer202', + mpid: '934', + }); + }); + + it('should keep only emailsha256 from selectPlacements when no email exists in userIdentities', async () => { + (window as any).mParticle.Rokt.filters = { + userAttributeFilters: [], + filterUserAttributes: function (attributes: any) { + return attributes; + }, + filteredUser: { + getMPID: function () { + return '945'; + }, + getUserIdentities: function () { + return { + userIdentities: { + customerid: 'customer303', + }, + }; + }, + }, + }; + + (window as any).Rokt.createLauncher = async function () { + return Promise.resolve({ + selectPlacements: function (options: any) { + (window as any).mParticle.Rokt.selectPlacementsOptions = options; + (window as any).mParticle.Rokt.selectPlacementsCalled = true; + }, + }); + }; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + {}, + ); + + await waitForCondition(() => { + return (window as any).mParticle.forwarder.isInitialized; + }); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: { + emailsha256: 'developer-hashed-email', + }, + }); + + expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ + emailsha256: 'developer-hashed-email', + customerid: 'customer303', + mpid: '945', + }); + }); + + it('should have nothing when neither email nor emailsha256 exist anywhere', async () => { + (window as any).mParticle.Rokt.filters = { + userAttributeFilters: [], + filterUserAttributes: function (attributes: any) { + return attributes; + }, + filteredUser: { + getMPID: function () { + return '967'; + }, + getUserIdentities: function () { + return { + userIdentities: { + customerid: 'customer505', + }, + }; + }, + }, + }; + + (window as any).Rokt.createLauncher = async function () { + return Promise.resolve({ + selectPlacements: function (options: any) { + (window as any).mParticle.Rokt.selectPlacementsOptions = options; + (window as any).mParticle.Rokt.selectPlacementsCalled = true; + }, + }); + }; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + {}, + ); + + await waitForCondition(() => { + return (window as any).mParticle.forwarder.isInitialized; + }); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: {}, + }); + + expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ + customerid: 'customer505', + mpid: '967', + }); + }); + + it('should keep only emailsha256 from userIdentities when email is not in userIdentities and developer passes nothing', async () => { + (window as any).mParticle.Rokt.filters = { + userAttributeFilters: [], + filterUserAttributes: function (attributes: any) { + return attributes; + }, + filteredUser: { + getMPID: function () { + return '978'; + }, + getUserIdentities: function () { + return { + userIdentities: { + other: 'hashed-from-useridentities', + customerid: 'customer606', + }, + }; + }, + }, + }; + + (window as any).Rokt.createLauncher = async function () { + return Promise.resolve({ + selectPlacements: function (options: any) { + (window as any).mParticle.Rokt.selectPlacementsOptions = options; + (window as any).mParticle.Rokt.selectPlacementsCalled = true; + }, + }); + }; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + hashedEmailUserIdentityType: 'Other', + }, + reportService.cb, + true, + null, + {}, + ); + + await waitForCondition(() => { + return (window as any).mParticle.forwarder.isInitialized; + }); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: {}, + }); + + expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ + emailsha256: 'hashed-from-useridentities', + customerid: 'customer606', + mpid: '978', + }); + }); + + it('should keep both when developer passes both and both exist in userIdentities', async () => { + (window as any).mParticle.Rokt.filters = { + userAttributeFilters: [], + filterUserAttributes: function (attributes: any) { + return attributes; + }, + filteredUser: { + getMPID: function () { + return '992'; + }, + getUserIdentities: function () { + return { + userIdentities: { + email: 'useridentity-email@example.com', + other: 'hashed-from-useridentities', + customerid: 'customer909', + }, + }; + }, + }, + }; + + (window as any).Rokt.createLauncher = async function () { + return Promise.resolve({ + selectPlacements: function (options: any) { + (window as any).mParticle.Rokt.selectPlacementsOptions = options; + (window as any).mParticle.Rokt.selectPlacementsCalled = true; + }, + }); + }; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + hashedEmailUserIdentityType: 'Other', + }, + reportService.cb, + true, + null, + {}, + ); + + await waitForCondition(() => { + return (window as any).mParticle.forwarder.isInitialized; + }); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: { + email: 'developer-email@example.com', + emailsha256: 'developer-hashed-email', + }, + }); + + // Should use developer-passed values for both + expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ + email: 'developer-email@example.com', + emailsha256: 'developer-hashed-email', + customerid: 'customer909', + mpid: '992', + }); + }); + + it('should NOT map other userIdentities to emailsha256 when the value is an empty string', async () => { + (window as any).mParticle.Rokt.filters = { + userAttributeFilters: [], + filterUserAttributes: function () { + return {}; + }, + filteredUser: { + getMPID: function () { + return '234'; + }, + getUserIdentities: function () { + return { + userIdentities: { + email: 'test@gmail.com', + other: '', // Empty string + }, + }; + }, + }, + }; + + // Set up the createLauncher to properly resolve asynchronously + (window as any).Rokt.createLauncher = async function () { + return Promise.resolve({ + selectPlacements: function (options: any) { + (window as any).mParticle.Rokt.selectPlacementsOptions = options; + (window as any).mParticle.Rokt.selectPlacementsCalled = true; + }, + }); + }; + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + hashedEmailUserIdentityType: 'Other', + }, + reportService.cb, + true, + null, + {}, + ); + // Wait for initialization to complete (after launcher is created) + await waitForCondition(() => { + return (window as any).mParticle.forwarder.isInitialized; + }); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: {}, + }); + + // Should NOT include emailsha256 since the other identity value was empty + expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ + email: 'test@gmail.com', + mpid: '234', + }); + }); + + it('should NOT map other userIdentities to emailsha256 when the value is null', async () => { + (window as any).mParticle.Rokt.filters = { + userAttributeFilters: [], + filterUserAttributes: function () { + return {}; + }, + filteredUser: { + getMPID: function () { + return '345'; + }, + getUserIdentities: function () { + return { + userIdentities: { + email: 'test@gmail.com', + other: null, // Null value + }, + }; + }, + }, + }; + + // Set up the createLauncher to properly resolve asynchronously + (window as any).Rokt.createLauncher = async function () { + return Promise.resolve({ + selectPlacements: function (options: any) { + (window as any).mParticle.Rokt.selectPlacementsOptions = options; + (window as any).mParticle.Rokt.selectPlacementsCalled = true; + }, + }); + }; + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + hashedEmailUserIdentityType: 'Other', + }, + reportService.cb, + true, + null, + {}, + ); + // Wait for initialization to complete (after launcher is created) + await waitForCondition(() => { + return (window as any).mParticle.forwarder.isInitialized; + }); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: {}, + }); + + // Should NOT include emailsha256 since the other identity value was null + expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ + email: 'test@gmail.com', + mpid: '345', + }); + }); + + it('should NOT map other userIdentities to emailsha256 when the value is undefined', async () => { + (window as any).mParticle.Rokt.filters = { + userAttributeFilters: [], + filterUserAttributes: function () { + return {}; + }, + filteredUser: { + getMPID: function () { + return '456'; + }, + getUserIdentities: function () { + return { + userIdentities: { + email: 'test@gmail.com', + other: undefined, // Undefined value + }, + }; + }, + }, + }; + + // Set up the createLauncher to properly resolve asynchronously + (window as any).Rokt.createLauncher = async function () { + return Promise.resolve({ + selectPlacements: function (options: any) { + (window as any).mParticle.Rokt.selectPlacementsOptions = options; + (window as any).mParticle.Rokt.selectPlacementsCalled = true; + }, + }); + }; + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + hashedEmailUserIdentityType: 'Other', + }, + reportService.cb, + true, + null, + {}, + ); + // Wait for initialization to complete (after launcher is created) + await waitForCondition(() => { + return (window as any).mParticle.forwarder.isInitialized; + }); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: {}, + }); + + // Should NOT include emailsha256 since the other identity value was undefined + expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ + email: 'test@gmail.com', + mpid: '456', + }); + }); + + it('should NOT map other userIdentities to emailsha256 when the value is 0', async () => { + (window as any).mParticle.Rokt.filters = { + userAttributeFilters: [], + filterUserAttributes: function () { + return {}; + }, + filteredUser: { + getMPID: function () { + return '567'; + }, + getUserIdentities: function () { + return { + userIdentities: { + email: 'test@gmail.com', + other: 0, // Zero value + }, + }; + }, + }, + }; + + // Set up the createLauncher to properly resolve asynchronously + (window as any).Rokt.createLauncher = async function () { + return Promise.resolve({ + selectPlacements: function (options: any) { + (window as any).mParticle.Rokt.selectPlacementsOptions = options; + (window as any).mParticle.Rokt.selectPlacementsCalled = true; + }, + }); + }; + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + hashedEmailUserIdentityType: 'Other', + }, + reportService.cb, + true, + null, + {}, + ); + // Wait for initialization to complete (after launcher is created) + await waitForCondition(() => { + return (window as any).mParticle.forwarder.isInitialized; + }); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: {}, + }); + + // Should NOT include emailsha256 since the other identity value was 0 + expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ + email: 'test@gmail.com', + mpid: '567', + }); + }); + + it('should NOT map other userIdentities to emailsha256 when the value is false', async () => { + (window as any).mParticle.Rokt.filters = { + userAttributeFilters: [], + filterUserAttributes: function () { + return {}; + }, + filteredUser: { + getMPID: function () { + return '678'; + }, + getUserIdentities: function () { + return { + userIdentities: { + email: 'test@gmail.com', + other: false, // False value + }, + }; + }, + }, + }; + + // Set up the createLauncher to properly resolve asynchronously + (window as any).Rokt.createLauncher = async function () { + return Promise.resolve({ + selectPlacements: function (options: any) { + (window as any).mParticle.Rokt.selectPlacementsOptions = options; + (window as any).mParticle.Rokt.selectPlacementsCalled = true; + }, + }); + }; + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + hashedEmailUserIdentityType: 'Other', + }, + reportService.cb, + true, + null, + {}, + ); + // Wait for initialization to complete (after launcher is created) + await waitForCondition(() => { + return (window as any).mParticle.forwarder.isInitialized; + }); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: {}, + }); + + // Should NOT include emailsha256 since the other identity value was false + expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ + email: 'test@gmail.com', + mpid: '678', + }); + }); + }); + + describe('#logSelectPlacementsEvent', () => { + it('should log a custom event', async () => { + (window as any).Rokt.createLauncher = async function () { + return Promise.resolve({ + selectPlacements: function () { + return Promise.resolve({ + context: { + sessionId: Promise.resolve('rokt-session-abc'), + }, + }); + }, + }); + }; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + { + 'cached-user-attr': 'cached-value', + }, + ); + + await waitForCondition(() => (window as any).mParticle.forwarder.isInitialized); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: { + 'new-attr': 'new-value', + }, + }); + + await waitForCondition(() => mParticle.loggedEvents.length > 0); + + expect(mParticle.loggedEvents.length).toBe(1); + expect(mParticle.loggedEvents[0].eventName).toBe('selectPlacements'); + expect(mParticle.loggedEvents[0].eventType).toBe(8); // EventType.Other + + const eventAttributes = mParticle.loggedEvents[0].eventAttributes; + expect(eventAttributes).toHaveProperty('mpid'); + }); + + it('should include merged user attributes, identities, and mpid', async () => { + (window as any).Rokt.createLauncher = async function () { + return Promise.resolve({ + selectPlacements: function () { + return Promise.resolve({ + context: { + sessionId: Promise.resolve('rokt-session-abc'), + }, + }); + }, + }); + }; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + { + 'cached-user-attr': 'cached-value', + }, + ); + + await waitForCondition(() => (window as any).mParticle.forwarder.isInitialized); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: { + 'new-attr': 'new-value', + }, + }); + + await waitForCondition(() => mParticle.loggedEvents.length > 0); + + const eventAttributes = mParticle.loggedEvents[0].eventAttributes; + + // eventAttributes should include merged attributes and mpid directly + expect(eventAttributes).toHaveProperty('mpid', '123'); + expect(eventAttributes).toHaveProperty('new-attr', 'new-value'); + expect(eventAttributes).toHaveProperty('cached-user-attr', 'cached-value'); + }); + + it('should log event when sessionId promise rejects', async () => { + (window as any).Rokt.createLauncher = async function () { + return Promise.resolve({ + selectPlacements: function () { + return Promise.resolve({ + context: { + sessionId: Promise.reject(new Error('session id failed')), + }, + }); + }, + }); + }; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + { + 'cached-user-attr': 'cached-value', + }, + ); + + await waitForCondition(() => (window as any).mParticle.forwarder.isInitialized); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: { + 'new-attr': 'new-value', + }, + }); + + await waitForCondition(() => mParticle.loggedEvents.length > 0); + + expect(mParticle.loggedEvents.length).toBe(1); + expect(mParticle.loggedEvents[0].eventName).toBe('selectPlacements'); + }); + + it('should log event when selection has no sessionId', async () => { + (window as any).Rokt.createLauncher = async function () { + return Promise.resolve({ + selectPlacements: function () { + return Promise.resolve({ + context: {}, + }); + }, + }); + }; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + { + 'cached-user-attr': 'cached-value', + }, + ); + + await waitForCondition(() => (window as any).mParticle.forwarder.isInitialized); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: { + 'new-attr': 'new-value', + }, + }); + + await waitForCondition(() => mParticle.loggedEvents.length > 0); + + expect(mParticle.loggedEvents.length).toBe(1); + expect(mParticle.loggedEvents[0].eventName).toBe('selectPlacements'); + }); + + it('should log event when selectPlacements promise rejects', async () => { + (window as any).Rokt.createLauncher = async function () { + return Promise.resolve({ + selectPlacements: function () { + return Promise.reject(new Error('selection failed')); + }, + }); + }; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + { + 'cached-user-attr': 'cached-value', + }, + ); + + await waitForCondition(() => (window as any).mParticle.forwarder.isInitialized); + + try { + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: { + 'new-attr': 'new-value', + }, + }); + } catch (_e) { + // Expected rejection from selectPlacements + } + + await waitForCondition(() => mParticle.loggedEvents.length > 0); + + expect(mParticle.loggedEvents.length).toBe(1); + expect(mParticle.loggedEvents[0].eventName).toBe('selectPlacements'); + }); + + it('should log event when selectPlacements returns a non-thenable value', async () => { + (window as any).Rokt.createLauncher = async function () { + return Promise.resolve({ + selectPlacements: function () { + // Returns a non-thenable (no .then method) + return undefined; + }, + }); + }; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + { + 'cached-user-attr': 'cached-value', + }, + ); + + await waitForCondition(() => (window as any).mParticle.forwarder.isInitialized); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: { + 'new-attr': 'new-value', + }, + }); + + await waitForCondition(() => mParticle.loggedEvents.length > 0); + + expect(mParticle.loggedEvents.length).toBe(1); + expect(mParticle.loggedEvents[0].eventName).toBe('selectPlacements'); + }); + + it('should skip logging when mParticle.logEvent is not available', async () => { + const originalLogEvent = (window as any).mParticle.logEvent; + (window as any).mParticle.logEvent = undefined; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + {}, + ); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: { + attr: 'value', + }, + }); + + expect((window as any).Rokt.selectPlacementsCalled).toBe(true); + expect(mParticle.loggedEvents.length).toBe(0); + (window as any).mParticle.logEvent = originalLogEvent; + }); + }); + }); + + describe('#use', () => { + beforeEach(() => { + (window as any).Rokt = new (MockRoktForwarder as any)(); + (window as any).mParticle.Rokt = (window as any).Rokt; + (window as any).mParticle.Rokt.attachKitCalled = false; + (window as any).mParticle.Rokt.attachKit = async (kit: any) => { + (window as any).mParticle.Rokt.attachKitCalled = true; + (window as any).mParticle.Rokt.kit = kit; + Promise.resolve(); + }; + }); + + it('should call launcher.use with the provided extension name when fully initialized', async () => { + (window as any).mParticle.forwarder.isInitialized = true; + (window as any).mParticle.forwarder.launcher = { + use: function (name: any) { + (window as any).Rokt.useCalled = true; + (window as any).Rokt.useName = name; + return Promise.resolve({}); + }, + }; + + await (window as any).mParticle.forwarder.use('ThankYouPageJourney'); + + expect((window as any).Rokt.useCalled).toBe(true); + expect((window as any).Rokt.useName).toBe('ThankYouPageJourney'); + }); + + it('should reject when called before initialization', async () => { + (window as any).mParticle.forwarder.isInitialized = false; + + try { + await (window as any).mParticle.forwarder.use('ThankYouPageJourney'); + } catch (error: any) { + expect(error.message).toBe('Rokt Kit: Not initialized'); + } + }); + + it('should log an error when called before initialization', async () => { + const originalConsoleError = window.console.error; + let errorLogged = false; + let errorMessage = null; + window.console.error = function (message: any) { + errorLogged = true; + errorMessage = message; + }; + + (window as any).mParticle.forwarder.isInitialized = false; + (window as any).mParticle.forwarder.launcher = null; + + try { + await (window as any).mParticle.forwarder.use('ThankYouPageJourney'); + throw new Error('Expected promise to reject'); + } catch (error: any) { + expect(error.message).toBe('Rokt Kit: Not initialized'); + } finally { + window.console.error = originalConsoleError; + } + + expect(errorLogged).toBe(true); + expect(errorMessage).toBe('Rokt Kit: Not initialized'); + }); + + it('should reject when extension name is invalid', async () => { + (window as any).mParticle.forwarder.isInitialized = true; + (window as any).mParticle.forwarder.launcher = { + use: function () { + return Promise.resolve({}); + }, + }; + + try { + await (window as any).mParticle.forwarder.use(123); + } catch (error: any) { + expect(error.message).toBe('Rokt Kit: Invalid extension name'); + } + }); + + it('should log an error when kit is initialized but launcher is missing', async () => { + const originalConsoleError = window.console.error; + let errorLogged = false; + let errorMessage = null; + window.console.error = function (message: any) { + errorLogged = true; + errorMessage = message; + }; + + (window as any).mParticle.forwarder.isInitialized = true; + (window as any).mParticle.forwarder.launcher = null; + + try { + await (window as any).mParticle.forwarder.use('ThankYouPageJourney'); + throw new Error('Expected promise to reject'); + } catch (error: any) { + expect(error.message).toBe('Rokt Kit: Not initialized'); + } finally { + window.console.error = originalConsoleError; + } + expect(errorLogged).toBe(true); + expect(errorMessage).toBe('Rokt Kit: Not initialized'); + }); + + it('should call launcher.use after init (test mode) and attach', async () => { + (window as any).mParticle.Rokt.attachKitCalled = false; + (window as any).mParticle.Rokt.attachKit = async (kit: any) => { + (window as any).mParticle.Rokt.attachKitCalled = true; + (window as any).mParticle.Rokt.kit = kit; + Promise.resolve(); + }; + + (window as any).Rokt.createLauncher = async function () { + return Promise.resolve({ + use: function (name: any) { + (window as any).Rokt.useCalled = true; + (window as any).Rokt.useName = name; + return Promise.resolve({}); + }, + }); + }; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + {}, + ); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + await (window as any).mParticle.forwarder.use('ThankYouPageJourney'); + + expect((window as any).Rokt.useCalled).toBe(true); + expect((window as any).Rokt.useName).toBe('ThankYouPageJourney'); + }); + }); + + describe('#setUserAttribute', () => { + beforeEach(() => { + (window as any).mParticle.sessionManager = { + getSession: function () { + return 'test-mp-session-id'; + }, + }; + }); + afterEach(() => { + delete (window as any).Rokt.__event_stream__; + (window as any).mParticle.forwarder.eventStreamQueue = []; + }); + + it('should set the user attribute', async () => { + (window as any).mParticle.forwarder.setUserAttribute('test-attribute', 'test-value'); + + expect((window as any).mParticle.forwarder.userAttributes).toEqual({ + 'test-attribute': 'test-value', + }); + }); + + it('should send a set_user_attributes event to window.Rokt.__event_stream__', () => { + const receivedEvents: any[] = []; + (window as any).Rokt.__event_stream__ = function (event: any) { + receivedEvents.push(event); + }; + + (window as any).mParticle.forwarder.onUserIdentified({ + getAllUserAttributes: function () { + return { 'user-attr': 'user-value' }; + }, + getMPID: function () { + return 'test-mpid'; + }, + getUserIdentities: function () { + return { userIdentities: { email: 'test@example.com' } }; + }, + }); + + receivedEvents.length = 0; // clear the identify event + + (window as any).mParticle.forwarder.setUserAttribute('new-attr', 'new-value'); + + expect(receivedEvents.length).toBe(1); + expect(receivedEvents[0].EventName).toBe('set_user_attributes'); + expect(receivedEvents[0].EventDataType).toBe(14); + expect(receivedEvents[0].MPID).toBe('test-mpid'); + expect(receivedEvents[0].SessionId).toBe('test-mp-session-id'); + }); + + it('should queue event when window.Rokt.__event_stream__ is not available', () => { + (window as any).mParticle.forwarder.setUserAttribute('queued-attr', 'queued-value'); + + expect((window as any).mParticle.forwarder.eventStreamQueue.length).toBe(1); + expect((window as any).mParticle.forwarder.eventStreamQueue[0].EventName).toBe('set_user_attributes'); + }); + }); + + describe('#removeUserAttribute', () => { + it('should remove the user attribute', async () => { + (window as any).mParticle.forwarder.setUserAttribute('test-attribute', 'test-value'); + + (window as any).mParticle.forwarder.removeUserAttribute('test-attribute'); + + expect((window as any).mParticle.forwarder.userAttributes).toEqual({}); + }); + }); + + describe('#onUserIdentified', () => { + beforeEach(() => { + (window as any).mParticle.sessionManager = { + getSession: function () { + return 'test-mp-session-id'; + }, + }; + }); + afterEach(() => { + delete (window as any).Rokt.__event_stream__; + (window as any).mParticle.forwarder.eventStreamQueue = []; + }); + + it('should set the filtered user and userAttributes', () => { + (window as any).mParticle.forwarder.onUserIdentified({ + getAllUserAttributes: function () { + return { 'test-attribute': 'test-value' }; + }, + getMPID: function () { + return '123'; + }, + getUserIdentities: function () { + return { userIdentities: {} }; + }, + }); + + expect((window as any).mParticle.forwarder.userAttributes).toEqual({ + 'test-attribute': 'test-value', + }); + expect((window as any).mParticle.forwarder.filters.filteredUser.getMPID()).toBe('123'); + }); + + it('should send a User Identified event to window.Rokt.__event_stream__', () => { + const receivedEvents: any[] = []; + (window as any).Rokt.__event_stream__ = function (event: any) { + receivedEvents.push(event); + }; + + (window as any).mParticle.forwarder.onUserIdentified({ + getAllUserAttributes: function () { + return { 'user-attr': 'user-value' }; + }, + getMPID: function () { + return 'identified-mpid-123'; + }, + getUserIdentities: function () { + return { userIdentities: { email: 'jenny@example.com' } }; + }, + }); + + expect(receivedEvents.length).toBe(1); + expect(receivedEvents[0].EventName).toBe('identify'); + expect(receivedEvents[0].EventDataType).toBe(14); + expect(receivedEvents[0].MPID).toBe('identified-mpid-123'); + expect(receivedEvents[0].SessionId).toBe('test-mp-session-id'); + expect(receivedEvents[0].UserAttributes).toEqual({ + 'user-attr': 'user-value', + }); + expect(receivedEvents[0].UserIdentities).toEqual({ + email: 'jenny@example.com', + }); + }); + + it('should queue event when window.Rokt.__event_stream__ is not available', () => { + (window as any).mParticle.forwarder.onUserIdentified({ + getAllUserAttributes: function () { + return {}; + }, + getMPID: function () { + return '123'; + }, + getUserIdentities: function () { + return { userIdentities: {} }; + }, + }); + + expect((window as any).mParticle.forwarder.eventStreamQueue.length).toBe(1); + expect((window as any).mParticle.forwarder.eventStreamQueue[0].EventName).toBe('identify'); + }); + }); + + describe('#onLoginComplete', () => { + beforeEach(() => { + (window as any).mParticle.sessionManager = { + getSession: function () { + return 'test-mp-session-id'; + }, + }; + }); + afterEach(() => { + delete (window as any).Rokt.__event_stream__; + (window as any).mParticle.forwarder.eventStreamQueue = []; + }); + + it('should update userAttributes from the filtered user', () => { + (window as any).mParticle.forwarder.onLoginComplete({ + getAllUserAttributes: function () { + return { 'user-attr': 'user-value' }; + }, + }); + + expect((window as any).mParticle.forwarder.userAttributes).toEqual({ + 'user-attr': 'user-value', + }); + }); + + it('should send a User Login event to window.Rokt.__event_stream__', () => { + const receivedEvents: any[] = []; + (window as any).Rokt.__event_stream__ = function (event: any) { + receivedEvents.push(event); + }; + + (window as any).mParticle.forwarder.onLoginComplete({ + getAllUserAttributes: function () { + return { 'user-attr': 'user-value' }; + }, + getMPID: function () { + return 'login-mpid-123'; + }, + getUserIdentities: function () { + return { + userIdentities: { email: 'jenny@example.com' }, + }; + }, + }); + + expect(receivedEvents.length).toBe(1); + expect(receivedEvents[0].EventName).toBe('login'); + expect(receivedEvents[0].EventDataType).toBe(14); + expect(receivedEvents[0].UserAttributes).toEqual({ + 'user-attr': 'user-value', + }); + expect(receivedEvents[0].MPID).toBe('login-mpid-123'); + expect(receivedEvents[0].SessionId).toBe('test-mp-session-id'); + expect(receivedEvents[0].UserIdentities).toEqual({ + email: 'jenny@example.com', + }); + }); + + it('should include null MPID and null UserIdentities when filteredUser has no getMPID or getUserIdentities', () => { + const receivedEvents: any[] = []; + (window as any).Rokt.__event_stream__ = function (event: any) { + receivedEvents.push(event); + }; + + (window as any).mParticle.forwarder.onLoginComplete({ + getAllUserAttributes: function () { + return {}; + }, + }); + + expect(receivedEvents.length).toBe(1); + expect(receivedEvents[0].MPID).toBeNull(); + expect(receivedEvents[0].UserIdentities).toBeNull(); + }); + + it('should include null SessionId when sessionManager is unavailable', () => { + delete (window as any).mParticle.sessionManager; + + const receivedEvents: any[] = []; + (window as any).Rokt.__event_stream__ = function (event: any) { + receivedEvents.push(event); + }; + + (window as any).mParticle.forwarder.onLoginComplete({ + getAllUserAttributes: function () { + return {}; + }, + getMPID: function () { + return 'some-mpid'; + }, + }); + + expect(receivedEvents.length).toBe(1); + expect(receivedEvents[0].SessionId).toBeNull(); + }); + + it('should queue event when window.Rokt.__event_stream__ is not available', () => { + (window as any).mParticle.forwarder.onLoginComplete({ + getAllUserAttributes: function () { + return {}; + }, + }); + + expect((window as any).mParticle.forwarder.eventStreamQueue.length).toBe(1); + expect((window as any).mParticle.forwarder.eventStreamQueue[0].EventName).toBe('login'); + expect((window as any).mParticle.forwarder.eventStreamQueue[0].EventDataType).toBe(14); + }); + + it('should queue event when window.Rokt is undefined', () => { + const savedRokt = (window as any).Rokt; + (window as any).Rokt = undefined; + + expect(() => { + (window as any).mParticle.forwarder.onLoginComplete({ + getAllUserAttributes: function () { + return {}; + }, + }); + }).not.toThrow(); + + expect((window as any).mParticle.forwarder.eventStreamQueue.length).toBe(1); + expect((window as any).mParticle.forwarder.eventStreamQueue[0].EventName).toBe('login'); + + (window as any).Rokt = savedRokt; + }); + }); + + describe('#onLogoutComplete', () => { + beforeEach(() => { + (window as any).mParticle.sessionManager = { + getSession: function () { + return 'test-mp-session-id'; + }, + }; + }); + afterEach(() => { + delete (window as any).Rokt.__event_stream__; + (window as any).mParticle.forwarder.eventStreamQueue = []; + }); + + it('should update userAttributes from the filtered user', () => { + (window as any).mParticle.forwarder.onLogoutComplete({ + getAllUserAttributes: function () { + return { 'remaining-attr': 'some-value' }; + }, + }); + + expect((window as any).mParticle.forwarder.userAttributes).toEqual({ + 'remaining-attr': 'some-value', + }); + }); + + it('should send a User Logout event to window.Rokt.__event_stream__', () => { + const receivedEvents: any[] = []; + (window as any).Rokt.__event_stream__ = function (event: any) { + receivedEvents.push(event); + }; + + (window as any).mParticle.forwarder.onLogoutComplete({ + getAllUserAttributes: function () { + return {}; + }, + getMPID: function () { + return 'logout-mpid-456'; + }, + getUserIdentities: function () { + return { + userIdentities: { customerid: 'cust-789' }, + }; + }, + }); + + expect(receivedEvents.length).toBe(1); + expect(receivedEvents[0].EventName).toBe('logout'); + expect(receivedEvents[0].EventDataType).toBe(14); + expect(receivedEvents[0].UserAttributes).toEqual({}); + expect(receivedEvents[0].MPID).toBe('logout-mpid-456'); + expect(receivedEvents[0].SessionId).toBe('test-mp-session-id'); + expect(receivedEvents[0].UserIdentities).toEqual({ + customerid: 'cust-789', + }); + }); + + it('should queue event when window.Rokt.__event_stream__ is not available', () => { + (window as any).mParticle.forwarder.onLogoutComplete({ + getAllUserAttributes: function () { + return {}; + }, + }); + + expect((window as any).mParticle.forwarder.eventStreamQueue.length).toBe(1); + expect((window as any).mParticle.forwarder.eventStreamQueue[0].EventName).toBe('logout'); + expect((window as any).mParticle.forwarder.eventStreamQueue[0].EventDataType).toBe(14); + }); + + it('should queue event when window.Rokt is undefined', () => { + const savedRokt = (window as any).Rokt; + (window as any).Rokt = undefined; + + expect(() => { + (window as any).mParticle.forwarder.onLogoutComplete({ + getAllUserAttributes: function () { + return {}; + }, + }); + }).not.toThrow(); + + expect((window as any).mParticle.forwarder.eventStreamQueue.length).toBe(1); + expect((window as any).mParticle.forwarder.eventStreamQueue[0].EventName).toBe('logout'); + + (window as any).Rokt = savedRokt; + }); + }); + + describe('#onModifyComplete', () => { + beforeEach(() => { + (window as any).mParticle.sessionManager = { + getSession: function () { + return 'test-mp-session-id'; + }, + }; + }); + afterEach(() => { + delete (window as any).Rokt.__event_stream__; + (window as any).mParticle.forwarder.eventStreamQueue = []; + }); + + it('should update userAttributes from the filtered user', () => { + (window as any).mParticle.forwarder.onModifyComplete({ + getAllUserAttributes: function () { + return { 'modified-attr': 'modified-value' }; + }, + getMPID: function () { + return '123'; + }, + getUserIdentities: function () { + return { userIdentities: {} }; + }, + }); + + expect((window as any).mParticle.forwarder.userAttributes).toEqual({ + 'modified-attr': 'modified-value', + }); + }); + + it('should send a User Modified event to window.Rokt.__event_stream__', () => { + const receivedEvents: any[] = []; + (window as any).Rokt.__event_stream__ = function (event: any) { + receivedEvents.push(event); + }; + + (window as any).mParticle.forwarder.onModifyComplete({ + getAllUserAttributes: function () { + return { 'modified-attr': 'modified-value' }; + }, + getMPID: function () { + return 'modify-mpid-789'; + }, + getUserIdentities: function () { + return { + userIdentities: { email: 'modified@example.com' }, + }; + }, + }); + + expect(receivedEvents.length).toBe(1); + expect(receivedEvents[0].EventName).toBe('modify_user'); + expect(receivedEvents[0].EventDataType).toBe(14); + expect(receivedEvents[0].MPID).toBe('modify-mpid-789'); + expect(receivedEvents[0].SessionId).toBe('test-mp-session-id'); + expect(receivedEvents[0].UserAttributes).toEqual({ + 'modified-attr': 'modified-value', + }); + expect(receivedEvents[0].UserIdentities).toEqual({ + email: 'modified@example.com', + }); + }); + + it('should queue event when window.Rokt.__event_stream__ is not available', () => { + (window as any).mParticle.forwarder.onModifyComplete({ + getAllUserAttributes: function () { + return {}; + }, + getMPID: function () { + return '123'; + }, + getUserIdentities: function () { + return { userIdentities: {} }; + }, + }); + + expect((window as any).mParticle.forwarder.eventStreamQueue.length).toBe(1); + expect((window as any).mParticle.forwarder.eventStreamQueue[0].EventName).toBe('modify_user'); + expect((window as any).mParticle.forwarder.eventStreamQueue[0].EventDataType).toBe(14); + }); + + it('should queue event when window.Rokt is undefined', () => { + const savedRokt = (window as any).Rokt; + (window as any).Rokt = undefined; + + expect(() => { + (window as any).mParticle.forwarder.onModifyComplete({ + getAllUserAttributes: function () { + return {}; + }, + getMPID: function () { + return '123'; + }, + getUserIdentities: function () { + return { userIdentities: {} }; + }, + }); + }).not.toThrow(); + + expect((window as any).mParticle.forwarder.eventStreamQueue.length).toBe(1); + expect((window as any).mParticle.forwarder.eventStreamQueue[0].EventName).toBe('modify_user'); + + (window as any).Rokt = savedRokt; + }); + }); + + describe('#fetchOptimizely', () => { + // Helper functions for setting up Optimizely mocks + function setupValidOptimizelyMock(experiments: any) { + (window as any).optimizely = { + get: function (key: any) { + if (key === 'state') { + return { + getActiveExperimentIds: function () { + return Object.keys(experiments); + }, + getVariationMap: function () { + return experiments; + }, + }; + } + }, + }; + } + + function setupInvalidOptimizelyMock(stateObject: any) { + (window as any).optimizely = { + get: function (key: any) { + if (key === 'state') { + return stateObject; + } + }, + }; + } + + // Common test setup + async function initAndSelectPlacements(settings: any = {}) { + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + ...settings, + }, + reportService.cb, + true, + null, + {}, + ); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: { + test: 'test', + }, + }); + } + + beforeEach(() => { + (window as any).Rokt = new (MockRoktForwarder as any)(); + (window as any).mParticle.Rokt = (window as any).Rokt; + (window as any).mParticle.Rokt.attachKitCalled = false; + (window as any).mParticle.Rokt.attachKit = async (kit: any) => { + (window as any).mParticle.Rokt.attachKitCalled = true; + (window as any).mParticle.Rokt.kit = kit; + Promise.resolve(); + }; + (window as any).mParticle.Rokt.setLocalSessionAttribute = function (key: any, value: any) { + mParticle._Store.localSessionAttributes[key] = value; + }; + (window as any).mParticle.Rokt.getLocalSessionAttributes = function () { + return mParticle._Store.localSessionAttributes; + }; + (window as any).mParticle.forwarder.launcher = { + selectPlacements: function (options: any) { + (window as any).mParticle.Rokt.selectPlacementsOptions = options; + (window as any).mParticle.Rokt.selectPlacementsCalled = true; + }, + }; + (window as any).mParticle.Rokt.filters = { + userAttributesFilters: [], + filterUserAttributes: function (attributes: any) { + return attributes; + }, + filteredUser: { + getMPID: function () { + return '123'; + }, + }, + }; + (window as any).mParticle._getActiveForwarders = function () { + return [{ name: 'Optimizely' }]; + }; + }); + + afterEach(() => { + delete (window as any).optimizely; + }); + + describe('when Optimizely is properly configured', () => { + it('should fetch experiment data for single experiment', async () => { + setupValidOptimizelyMock({ + exp1: { id: 'var1' }, + }); + + await initAndSelectPlacements({ + onboardingExpProvider: 'Optimizely', + }); + + expect((window as any).Rokt.selectPlacementsOptions.attributes).toHaveProperty( + 'rokt.custom.optimizely.experiment.exp1.variationId', + 'var1', + ); + }); + + it('should fetch experiment data for multiple experiments', async () => { + setupValidOptimizelyMock({ + exp1: { id: 'var1' }, + exp2: { id: 'var2' }, + }); + + await initAndSelectPlacements({ + onboardingExpProvider: 'Optimizely', + }); + + const attributes = (window as any).Rokt.selectPlacementsOptions.attributes; + expect(attributes).toHaveProperty('rokt.custom.optimizely.experiment.exp1.variationId', 'var1'); + expect(attributes).toHaveProperty('rokt.custom.optimizely.experiment.exp2.variationId', 'var2'); + }); + }); + + describe('when Optimizely is not properly configured', () => { + it('should return empty object when Optimizely is not available', async () => { + delete (window as any).optimizely; + + await initAndSelectPlacements({ + onboardingExpProvider: 'Optimizely', + }); + + expect((window as any).Rokt.selectPlacementsOptions.attributes).not.toHaveProperty('rokt.custom.optimizely'); + }); + + it('should return empty object when Optimizely state is undefined', async () => { + setupInvalidOptimizelyMock(undefined); + + await initAndSelectPlacements({ + onboardingExpProvider: 'Optimizely', + }); + + expect((window as any).Rokt.selectPlacementsOptions.attributes).not.toHaveProperty('rokt.custom.optimizely'); + }); + + it('should return empty object when Optimizely state has invalid format', async () => { + setupInvalidOptimizelyMock({ + someOtherProperty: 'value', + invalidFunction: function () { + return null; + }, + }); + + await initAndSelectPlacements({ + onboardingExpProvider: 'Optimizely', + }); + + expect((window as any).Rokt.selectPlacementsOptions.attributes).not.toHaveProperty('rokt.custom.optimizely'); + }); + + it('should return empty object when Optimizely state is missing required methods', async () => { + setupInvalidOptimizelyMock({ + getVariationMap: function () { + return {}; + }, + // Mocking a scenario for when getActiveExperimentIds() method is missing + }); + + await initAndSelectPlacements({ + onboardingExpProvider: 'Optimizely', + }); + + expect((window as any).Rokt.selectPlacementsOptions.attributes).not.toHaveProperty('rokt.custom.optimizely'); + }); + }); + + describe('when Optimizely is not the provider', () => { + it('should not fetch Optimizely data', async () => { + setupValidOptimizelyMock({ + exp1: { id: 'var1' }, + }); + + await initAndSelectPlacements({ + onboardingExpProvider: 'NotOptimizely', + }); + + expect((window as any).Rokt.selectPlacementsOptions.attributes).not.toHaveProperty('rokt.custom.optimizely'); + }); + }); + }); + + describe('#generateLauncherScript', () => { + const baseUrl = 'https://apps.rokt.com/wsdk/integrations/launcher.js'; + + beforeEach(() => { + (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + ); + }); + + it('should return base URL when no domain is passed', () => { + const url = (window as any).mParticle.forwarder.testHelpers.generateLauncherScript(); + expect(url).toBe(baseUrl); + }); + + it('should return an updated base URL with CNAME when domain is passed', () => { + expect((window as any).mParticle.forwarder.testHelpers.generateLauncherScript('cname.rokt.com')).toBe( + 'https://cname.rokt.com/wsdk/integrations/launcher.js', + ); + }); + + it('should return base URL when no extensions are provided', () => { + const url = (window as any).mParticle.forwarder.testHelpers.generateLauncherScript(); + expect(url).toBe(baseUrl); + }); + + it('should return base URL when extensions is null or undefined', () => { + expect((window as any).mParticle.forwarder.testHelpers.generateLauncherScript(undefined, null)).toBe(baseUrl); + + expect((window as any).mParticle.forwarder.testHelpers.generateLauncherScript(undefined, undefined)).toBe( + baseUrl, + ); + }); + + it('should correctly append a single extension', () => { + const url = (window as any).mParticle.forwarder.testHelpers.generateLauncherScript(undefined, [ + 'cos-extension-detection', + ]); + expect(url).toBe(baseUrl + '?extensions=cos-extension-detection'); + }); + + it('should correctly append multiple extensions', () => { + const url = (window as any).mParticle.forwarder.testHelpers.generateLauncherScript(undefined, [ + 'cos-extension-detection', + 'experiment-monitoring', + 'sponsored-payments-apple-pay', + ]); + expect(url).toBe( + baseUrl + '?extensions=cos-extension-detection,' + 'experiment-monitoring,' + 'sponsored-payments-apple-pay', + ); + }); + }); + + describe('#roktExtensions', () => { + beforeEach(async () => { + (window as any).Rokt = new (MockRoktForwarder as any)(); + (window as any).mParticle.Rokt = (window as any).Rokt; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + ); + }); + + describe('extractRoktExtensions', () => { + it('should correctly map known extension names to their query parameters', async () => { + const settingsString = + '[{"jsmap":null,"map":null,"maptype":"StaticList","value":"cos-extension-detection"},{"jsmap":null,"map":null,"maptype":"StaticList","value":"experiment-monitoring"}]'; + const expectedExtensions = ['cos-extension-detection', 'experiment-monitoring']; + + expect((window as any).mParticle.forwarder.testHelpers.extractRoktExtensions(settingsString)).toEqual( + expectedExtensions, + ); + }); + }); + + it('should handle invalid setting strings', () => { + expect((window as any).mParticle.forwarder.testHelpers.extractRoktExtensions('NONE')).toEqual([]); + + expect((window as any).mParticle.forwarder.testHelpers.extractRoktExtensions(undefined)).toEqual([]); + + expect((window as any).mParticle.forwarder.testHelpers.extractRoktExtensions(null)).toEqual([]); + }); + }); + + describe('#generateMappedEventLookup', () => { + beforeEach(async () => { + (window as any).Rokt = new (MockRoktForwarder as any)(); + (window as any).mParticle.Rokt = (window as any).Rokt; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + ); + }); + + it('should generate a lookup table from a placement event mapping', () => { + const placementEventMapping = [ + { + jsmap: '-1484452948', + map: '-5208850776883573773', + maptype: 'EventClass.Id', + value: 'foo-mapped-flag', + }, + { + jsmap: '1838502119', + map: '1324617889422969328', + maptype: 'EventClass.Id', + value: 'ad_viewed_test', + }, + ]; + + expect((window as any).mParticle.forwarder.testHelpers.generateMappedEventLookup(placementEventMapping)).toEqual({ + '-1484452948': 'foo-mapped-flag', + 1838502119: 'ad_viewed_test', + }); + }); + + it('should return an empty object if the placement event mapping is null', () => { + expect((window as any).mParticle.forwarder.testHelpers.generateMappedEventLookup(null)).toEqual({}); + }); + }); + + describe('#generateMappedEventAttributeLookup', () => { + beforeEach(async () => { + (window as any).Rokt = new (MockRoktForwarder as any)(); + (window as any).mParticle.Rokt = (window as any).Rokt; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + ); + }); + + it('should generate a lookup table from placementEventAttributeMapping', () => { + const placementEventAttributeMapping = [ + { + jsmap: null, + map: 'number_of_products', + maptype: 'EventAttributeClass.Name', + value: 'tof_products_2', + conditions: [ + { + operator: 'equals', + attributeValue: 2, + }, + ], + }, + { + jsmap: null, + map: 'URL', + maptype: 'EventAttributeClass.Name', + value: 'saleSeeker', + conditions: [ + { + operator: 'contains', + attributeValue: 'sale', + }, + ], + }, + ]; + + expect( + (window as any).mParticle.forwarder.testHelpers.generateMappedEventAttributeLookup( + placementEventAttributeMapping, + ), + ).toEqual({ + tof_products_2: [ + { + eventAttributeKey: 'number_of_products', + conditions: [ + { + operator: 'equals', + attributeValue: 2, + }, + ], + }, + ], + saleSeeker: [ + { + eventAttributeKey: 'URL', + conditions: [ + { + operator: 'contains', + attributeValue: 'sale', + }, + ], + }, + ], + }); + }); + + it('should default conditions to an empty array when missing', () => { + const placementEventAttributeMapping = [ + { + jsmap: null, + map: 'URL', + maptype: 'EventAttributeClass.Name', + value: 'hasUrl', + }, + ]; + + expect( + (window as any).mParticle.forwarder.testHelpers.generateMappedEventAttributeLookup( + placementEventAttributeMapping, + ), + ).toEqual({ + hasUrl: [ + { + eventAttributeKey: 'URL', + conditions: [], + }, + ], + }); + }); + + it('should return an empty object when placementEventAttributeMapping is null', () => { + expect((window as any).mParticle.forwarder.testHelpers.generateMappedEventAttributeLookup(null)).toEqual({}); + }); + + it('should ignore invalid mappings (non-string map/value)', () => { + const placementEventAttributeMapping = [ + { + jsmap: null, + map: null, + maptype: 'EventAttributeClass.Name', + value: 'bad', + conditions: [], + }, + { + jsmap: null, + map: 'URL', + maptype: 'EventAttributeClass.Name', + value: null, + conditions: [], + }, + { + jsmap: null, + map: 'URL', + maptype: 'EventAttributeClass.Name', + value: 'good', + conditions: [], + }, + ]; + + expect( + (window as any).mParticle.forwarder.testHelpers.generateMappedEventAttributeLookup( + placementEventAttributeMapping, + ), + ).toEqual({ + good: [ + { + eventAttributeKey: 'URL', + conditions: [], + }, + ], + }); + }); + }); + + describe('#processEvent', () => { + beforeEach(() => { + (window as any).Rokt = new (MockRoktForwarder as any)(); + (window as any).Rokt.createLauncher = async function () { + return Promise.resolve({ + selectPlacements: function (options: any) { + (window as any).mParticle.Rokt.selectPlacementsOptions = options; + (window as any).mParticle.Rokt.selectPlacementsCalled = true; + }, + }); + }; + (window as any).mParticle.Rokt = (window as any).Rokt; + (window as any).mParticle.Rokt.attachKitCalled = false; + (window as any).mParticle.Rokt.attachKit = async (kit: any) => { + (window as any).mParticle.Rokt.attachKitCalled = true; + (window as any).mParticle.Rokt.kit = kit; + Promise.resolve(); + }; + (window as any).mParticle.Rokt.setLocalSessionAttribute = function (key: any, value: any) { + (window as any).mParticle._Store.localSessionAttributes[key] = value; + }; + (window as any).mParticle.Rokt.getLocalSessionAttributes = function () { + return (window as any).mParticle._Store.localSessionAttributes; + }; + (window as any).mParticle.forwarder.launcher = { + selectPlacements: function (options: any) { + (window as any).mParticle.Rokt.selectPlacementsOptions = options; + (window as any).mParticle.Rokt.selectPlacementsCalled = true; + }, + }; + (window as any).mParticle.Rokt.filters = { + userAttributesFilters: [], + filterUserAttributes: function (attributes: any) { + return attributes; + }, + filteredUser: { + getMPID: function () { + return '123'; + }, + }, + }; + }); + + afterEach(() => { + (window as any).mParticle.forwarder.eventQueue = []; + (window as any).mParticle.forwarder.isInitialized = false; + (window as any).mParticle.Rokt.attachKitCalled = false; + }); + + it('set a local session selection attribute if the event is a mapped placement event', async () => { + // Mocks hashed values for testing + const placementEventMapping = JSON.stringify([ + { + jsmap: 'hashed-<48Video Watched>-value', + map: '123466', + maptype: 'EventClass.Id', + value: 'foo-mapped-flag', + }, + { + jsmap: 'hashed-<29Other Value>-value', + map: '1279898989', + maptype: 'EventClass.Id', + value: 'ad_viewed_test', + }, + ]); + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + placementEventMapping, + }, + reportService.cb, + true, + null, + {}, + ); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + (window as any).mParticle.forwarder.process({ + EventName: 'Video Watched', + EventCategory: EventType.Other, + EventDataType: MessageType.PageEvent, + }); + + expect((window as any).mParticle._Store.localSessionAttributes).toEqual({ + 'foo-mapped-flag': true, + }); + }); + + it('should set local session attribute only when placementEventAttributeMapping conditions match (URL contains)', async () => { + const placementEventAttributeMapping = JSON.stringify([ + { + jsmap: null, + map: 'URL', + maptype: 'EventAttributeClass.Name', + value: 'saleSeeker', + conditions: [ + { + operator: 'contains', + attributeValue: 'sale', + }, + ], + }, + ]); + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + placementEventAttributeMapping, + }, + reportService.cb, + true, + null, + {}, + ); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + (window as any).mParticle._Store.localSessionAttributes = {}; + (window as any).mParticle.forwarder.process({ + EventName: 'Browse', + EventCategory: EventType.Unknown, + EventDataType: MessageType.PageView, + EventAttributes: { + URL: 'https://example.com/home', + }, + }); + expect((window as any).mParticle._Store.localSessionAttributes).toEqual({}); + + (window as any).mParticle._Store.localSessionAttributes = {}; + (window as any).mParticle.forwarder.process({ + EventName: 'Browse', + EventCategory: EventType.Unknown, + EventDataType: MessageType.PageView, + EventAttributes: { + URL: 'https://example.com/sale/items', + }, + }); + expect((window as any).mParticle._Store.localSessionAttributes).toEqual({ + saleSeeker: true, + }); + }); + + it('should support event attribute mapping when conditions are not defined', async () => { + const placementEventAttributeMapping = JSON.stringify([ + { + jsmap: null, + map: 'URL', + maptype: 'EventAttributeClass.Name', + value: 'hasUrl', + }, + ]); + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + placementEventAttributeMapping, + }, + reportService.cb, + true, + null, + {}, + ); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + (window as any).mParticle._Store.localSessionAttributes = {}; + (window as any).mParticle.forwarder.process({ + EventName: 'Browse', + EventCategory: EventType.Unknown, + EventDataType: MessageType.PageView, + EventAttributes: { + URL: 'https://example.com/anything', + }, + }); + + expect((window as any).mParticle._Store.localSessionAttributes).toEqual({ + hasUrl: true, + }); + }); + + it('should not set local session attribute when mapped attribute key is missing from event and no conditions have been defined', async () => { + const placementEventAttributeMapping = JSON.stringify([ + { + jsmap: null, + map: 'URL', + maptype: 'EventAttributeClass.Name', + value: 'hasUrl', + }, + ]); + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + placementEventAttributeMapping, + }, + reportService.cb, + true, + null, + {}, + ); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + (window as any).mParticle._Store.localSessionAttributes = {}; + (window as any).mParticle.forwarder.process({ + EventName: 'Browse', + EventCategory: EventType.Unknown, + EventDataType: MessageType.PageView, + EventAttributes: { + someOtherAttribute: 'value', + }, + }); + + expect((window as any).mParticle._Store.localSessionAttributes).toEqual({}); + }); + + it('should support exists operator for placementEventAttributeMapping conditions', async () => { + const placementEventAttributeMapping = JSON.stringify([ + { + jsmap: null, + map: 'URL', + maptype: 'EventAttributeClass.Name', + value: 'hasUrl', + conditions: [{ operator: 'exists' }], + }, + ]); + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + placementEventAttributeMapping, + }, + reportService.cb, + true, + null, + {}, + ); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + (window as any).mParticle._Store.localSessionAttributes = {}; + (window as any).mParticle.forwarder.process({ + EventName: 'Browse', + EventCategory: EventType.Unknown, + EventDataType: MessageType.PageView, + EventAttributes: { + URL: 'https://example.com/anything', + }, + }); + + expect((window as any).mParticle._Store.localSessionAttributes).toEqual({ + hasUrl: true, + }); + + (window as any).mParticle._Store.localSessionAttributes = {}; + (window as any).mParticle.forwarder.process({ + EventName: 'Browse', + EventCategory: EventType.Unknown, + EventDataType: MessageType.PageView, + EventAttributes: { + someOtherAttribute: 'value', + }, + }); + + expect((window as any).mParticle._Store.localSessionAttributes).toEqual({}); + }); + + it('should evaluate equals for placementEventAttributeMapping conditions', async () => { + const placementEventAttributeMapping = JSON.stringify([ + { + jsmap: null, + map: 'number_of_products', + maptype: 'EventAttributeClass.Name', + value: 'multipleproducts', + conditions: [ + { + operator: 'equals', + attributeValue: 2, + }, + ], + }, + ]); + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + placementEventAttributeMapping, + }, + reportService.cb, + true, + null, + {}, + ); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + (window as any).mParticle._Store.localSessionAttributes = {}; + (window as any).mParticle.forwarder.process({ + EventName: 'Browse', + EventCategory: EventType.Unknown, + EventDataType: MessageType.PageView, + EventAttributes: { + number_of_products: 2, + }, + }); + expect((window as any).mParticle._Store.localSessionAttributes).toEqual({ + multipleproducts: true, + }); + + (window as any).mParticle._Store.localSessionAttributes = {}; + (window as any).mParticle.forwarder.process({ + EventName: 'Browse', + EventCategory: EventType.Unknown, + EventDataType: MessageType.PageView, + EventAttributes: { + number_of_products: '2', + }, + }); + expect((window as any).mParticle._Store.localSessionAttributes).toEqual({ + multipleproducts: true, + }); + }); + + it('should evaluate contains for placementEventAttributeMapping conditions', async () => { + const placementEventAttributeMapping = JSON.stringify([ + { + jsmap: null, + map: 'number_of_products', + maptype: 'EventAttributeClass.Name', + value: 'containsNumber', + conditions: [ + { + operator: 'contains', + attributeValue: '2', + }, + ], + }, + ]); + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + placementEventAttributeMapping, + }, + reportService.cb, + true, + null, + {}, + ); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + (window as any).mParticle._Store.localSessionAttributes = {}; + (window as any).mParticle.forwarder.process({ + EventName: 'Browse', + EventCategory: EventType.Unknown, + EventDataType: MessageType.PageView, + EventAttributes: { + number_of_products: 2, + }, + }); + expect((window as any).mParticle._Store.localSessionAttributes).toEqual({ + containsNumber: true, + }); + }); + + it('should correctly match attribute values for different type cases', async () => { + const placementEventAttributeMapping = JSON.stringify([ + { + jsmap: null, + map: 'boolAttr', + maptype: 'EventAttributeClass.Name', + value: 'lowerCaseMatches', + conditions: [ + { + operator: 'equals', + attributeValue: 'true', + }, + ], + }, + { + jsmap: null, + map: 'boolAttr', + maptype: 'EventAttributeClass.Name', + value: 'titleCaseMatches', + conditions: [ + { + operator: 'equals', + attributeValue: 'True', + }, + ], + }, + { + jsmap: null, + map: 'boolAttr', + maptype: 'EventAttributeClass.Name', + value: 'upperCaseMatches', + conditions: [ + { + operator: 'equals', + attributeValue: 'TRUE', + }, + ], + }, + { + jsmap: null, + map: 'zeroAttr', + maptype: 'EventAttributeClass.Name', + value: 'falseMatches', + conditions: [ + { + operator: 'equals', + attributeValue: false, + }, + ], + }, + { + jsmap: null, + map: 'zeroAttr', + maptype: 'EventAttributeClass.Name', + value: 'emptyMatches', + conditions: [ + { + operator: 'equals', + attributeValue: '', + }, + ], + }, + { + jsmap: null, + map: 'zeroAttr', + maptype: 'EventAttributeClass.Name', + value: 'zeroMatches', + conditions: [ + { + operator: 'equals', + attributeValue: '0', + }, + ], + }, + { + jsmap: null, + map: 'numAttr', + maptype: 'EventAttributeClass.Name', + value: 'digitMatches', + conditions: [ + { + operator: 'contains', + attributeValue: '2', + }, + ], + }, + ]); + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + placementEventAttributeMapping, + }, + reportService.cb, + true, + null, + {}, + ); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + (window as any).mParticle._Store.localSessionAttributes = {}; + (window as any).mParticle.forwarder.process({ + EventName: 'Test', + EventCategory: EventType.Unknown, + EventDataType: MessageType.PageView, + EventAttributes: { + boolAttr: true, + zeroAttr: 0, + numAttr: 123, + }, + }); + + expect((window as any).mParticle._Store.localSessionAttributes).toEqual({ + lowerCaseMatches: true, + zeroMatches: true, + digitMatches: true, + }); + }); + + it('should not match when attribute key is missing or EventAttributes is absent', async () => { + const placementEventAttributeMapping = JSON.stringify([ + { + jsmap: null, + map: 'missingAttr', + maptype: 'EventAttributeClass.Name', + value: 'shouldNotMatch', + conditions: [ + { + operator: 'equals', + attributeValue: 'testValue', + }, + ], + }, + ]); + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + placementEventAttributeMapping, + }, + reportService.cb, + true, + null, + {}, + ); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + (window as any).mParticle._Store.localSessionAttributes = {}; + (window as any).mParticle.forwarder.process({ + EventName: 'Test', + EventCategory: EventType.Unknown, + EventDataType: MessageType.PageView, + EventAttributes: { + otherAttr: 'value', + }, + }); + + expect((window as any).mParticle._Store.localSessionAttributes).toEqual({}); + + (window as any).mParticle._Store.localSessionAttributes = {}; + (window as any).mParticle.forwarder.process({ + EventName: 'Test', + EventCategory: EventType.Unknown, + EventDataType: MessageType.PageView, + }); + + expect((window as any).mParticle._Store.localSessionAttributes).toEqual({}); + }); + + it('should require ALL rules for the same mapped key to match (AND across rules)', async () => { + const placementEventAttributeMapping = JSON.stringify([ + { + jsmap: null, + map: 'URL', + maptype: 'EventAttributeClass.Name', + value: 'saleSeeker', + conditions: [ + { + operator: 'contains', + attributeValue: 'sale', + }, + { + operator: 'exists', + }, + ], + }, + { + jsmap: null, + map: 'URL', + maptype: 'EventAttributeClass.Name', + value: 'saleSeeker', + conditions: [ + { + operator: 'contains', + attributeValue: 'items', + }, + ], + }, + ]); + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + placementEventAttributeMapping, + }, + reportService.cb, + true, + null, + {}, + ); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + (window as any).mParticle._Store.localSessionAttributes = {}; + (window as any).mParticle.forwarder.process({ + EventName: 'Browse', + EventCategory: EventType.Unknown, + EventDataType: MessageType.PageView, + EventAttributes: { + URL: 'https://example.com/sale', + }, + }); + expect((window as any).mParticle._Store.localSessionAttributes).toEqual({}); + + (window as any).mParticle._Store.localSessionAttributes = {}; + (window as any).mParticle.forwarder.process({ + EventName: 'Browse', + EventCategory: EventType.Unknown, + EventDataType: MessageType.PageView, + EventAttributes: { + URL: 'https://example.com/sale/items', + }, + }); + expect((window as any).mParticle._Store.localSessionAttributes).toEqual({ + saleSeeker: true, + }); + }); + + it('should set multiple local session attributes for the same event attribute key', async () => { + const placementEventAttributeMapping = JSON.stringify([ + { + jsmap: null, + map: 'URL', + maptype: 'EventAttributeClass.Name', + value: 'saleSeeker', + conditions: [ + { + operator: 'contains', + attributeValue: 'sale', + }, + ], + }, + { + jsmap: null, + map: 'URL', + maptype: 'EventAttributeClass.Name', + value: 'saleSeeker1', + conditions: [ + { + operator: 'contains', + attributeValue: 'items', + }, + ], + }, + ]); + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + placementEventAttributeMapping, + }, + reportService.cb, + true, + null, + {}, + ); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + (window as any).mParticle._Store.localSessionAttributes = {}; + (window as any).mParticle.forwarder.process({ + EventName: 'Browse', + EventCategory: EventType.Unknown, + EventDataType: MessageType.PageView, + EventAttributes: { + URL: 'https://example.com/sale', + }, + }); + expect((window as any).mParticle._Store.localSessionAttributes).toEqual({ + saleSeeker: true, + }); + + (window as any).mParticle._Store.localSessionAttributes = {}; + (window as any).mParticle.forwarder.process({ + EventName: 'Browse', + EventCategory: EventType.Unknown, + EventDataType: MessageType.PageView, + EventAttributes: { + URL: 'https://example.com/sale/items', + }, + }); + expect((window as any).mParticle._Store.localSessionAttributes).toEqual({ + saleSeeker: true, + saleSeeker1: true, + }); + }); + + it('should treat falsy attribute values as existing', async () => { + const placementEventAttributeMapping = JSON.stringify([ + { + jsmap: null, + map: 'zeroProp', + maptype: 'EventAttributeClass.Name', + value: 'zeroExists', + conditions: [{ operator: 'exists' }], + }, + { + jsmap: null, + map: 'falseProp', + maptype: 'EventAttributeClass.Name', + value: 'falseExists', + conditions: [{ operator: 'exists' }], + }, + { + jsmap: null, + map: 'emptyStringProp', + maptype: 'EventAttributeClass.Name', + value: 'emptyStringExists', + conditions: [{ operator: 'exists' }], + }, + ]); + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + placementEventAttributeMapping, + }, + reportService.cb, + true, + null, + {}, + ); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + (window as any).mParticle._Store.localSessionAttributes = {}; + (window as any).mParticle.forwarder.process({ + EventName: 'Test', + EventCategory: EventType.Unknown, + EventDataType: MessageType.PageView, + EventAttributes: { + zeroProp: 0, + falseProp: false, + emptyStringProp: '', + }, + }); + + expect((window as any).mParticle._Store.localSessionAttributes).toEqual({ + zeroExists: true, + falseExists: true, + emptyStringExists: true, + }); + }); + + it('should not match when condition has an unrecognized operator', async () => { + const placementEventAttributeMapping = JSON.stringify([ + { + jsmap: null, + map: 'URL', + maptype: 'EventAttributeClass.Name', + value: 'shouldNotMatch', + conditions: [ + { + operator: 'testOperator', + attributeValue: 'https', + }, + ], + }, + ]); + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + placementEventAttributeMapping, + }, + reportService.cb, + true, + null, + {}, + ); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + (window as any).mParticle._Store.localSessionAttributes = {}; + (window as any).mParticle.forwarder.process({ + EventName: 'Browse', + EventCategory: EventType.Unknown, + EventDataType: MessageType.PageView, + EventAttributes: { + URL: 'https://example.com', + }, + }); + + expect((window as any).mParticle._Store.localSessionAttributes).toEqual({}); + }); + + it('should support both placementEventMapping and placementEventAttributeMapping together', async () => { + const placementEventMapping = JSON.stringify([ + { + jsmap: 'hashed-<48Video Watched>-value', + map: '123466', + maptype: 'EventClass.Id', + value: 'foo-mapped-flag', + }, + ]); + + const placementEventAttributeMapping = JSON.stringify([ + { + jsmap: null, + map: 'URL', + maptype: 'EventAttributeClass.Name', + value: 'hasUrl', + conditions: [{ operator: 'exists' }], + }, + ]); + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + placementEventMapping, + placementEventAttributeMapping, + }, + reportService.cb, + true, + null, + {}, + ); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + (window as any).mParticle._Store.localSessionAttributes = {}; + (window as any).mParticle.forwarder.process({ + EventName: 'Browse', + EventCategory: EventType.Unknown, + EventDataType: MessageType.PageView, + EventAttributes: { + URL: 'https://example.com/anything', + }, + }); + + expect((window as any).mParticle._Store.localSessionAttributes).toEqual({ + hasUrl: true, + }); + + (window as any).mParticle._Store.localSessionAttributes = {}; + (window as any).mParticle.forwarder.process({ + EventName: 'Video Watched', + EventCategory: EventType.Other, + EventDataType: MessageType.PageEvent, + EventAttributes: { + URL: 'https://example.com/video', + }, + }); + + expect((window as any).mParticle._Store.localSessionAttributes).toEqual({ + hasUrl: true, + 'foo-mapped-flag': true, + }); + + (window as any).mParticle._Store.localSessionAttributes = {}; + (window as any).mParticle.forwarder.process({ + EventName: 'Video Watched', + EventCategory: EventType.Other, + EventDataType: MessageType.PageEvent, + }); + + expect((window as any).mParticle._Store.localSessionAttributes).toEqual({ + 'foo-mapped-flag': true, + }); + }); + + it('should add the event to the event queue if the kit is not initialized', async () => { + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + {}, + ); + + (window as any).mParticle.forwarder.process({ + EventName: 'Video Watched A', + EventCategory: EventType.Other, + EventDataType: MessageType.PageEvent, + }); + + expect((window as any).mParticle.forwarder.eventQueue).toEqual([ + { + EventName: 'Video Watched A', + EventCategory: EventType.Other, + EventDataType: MessageType.PageEvent, + }, + ]); + }); + + it('should process queued events once the kit is ready', async () => { + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + {}, + ); + + (window as any).mParticle.forwarder.process({ + EventName: 'Video Watched B', + EventCategory: EventType.Other, + EventDataType: MessageType.PageEvent, + }); + + expect((window as any).mParticle.forwarder.eventQueue).toEqual([ + { + EventName: 'Video Watched B', + EventCategory: EventType.Other, + EventDataType: MessageType.PageEvent, + }, + ]); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + expect((window as any).mParticle.forwarder.eventQueue).toEqual([]); + }); + }); + + describe('#_sendEventStream', () => { + beforeEach(() => { + (window as any).mParticle.forwarder.eventStreamQueue = []; + (window as any).Rokt = new (MockRoktForwarder as any)(); + (window as any).Rokt.createLauncher = async function () { + return Promise.resolve({ + selectPlacements: function (options: any) { + (window as any).mParticle.Rokt.selectPlacementsOptions = options; + (window as any).mParticle.Rokt.selectPlacementsCalled = true; + }, + }); + }; + (window as any).mParticle.Rokt = (window as any).Rokt; + (window as any).mParticle.Rokt.attachKitCalled = false; + (window as any).mParticle.Rokt.attachKit = async (kit: any) => { + (window as any).mParticle.Rokt.attachKitCalled = true; + (window as any).mParticle.Rokt.kit = kit; + Promise.resolve(); + }; + (window as any).mParticle.Rokt.setLocalSessionAttribute = function (key: any, value: any) { + (window as any).mParticle._Store.localSessionAttributes[key] = value; + }; + (window as any).mParticle.Rokt.getLocalSessionAttributes = function () { + return (window as any).mParticle._Store.localSessionAttributes; + }; + (window as any).mParticle.forwarder.launcher = { + selectPlacements: function (options: any) { + (window as any).mParticle.Rokt.selectPlacementsOptions = options; + (window as any).mParticle.Rokt.selectPlacementsCalled = true; + }, + }; + (window as any).mParticle.Rokt.filters = { + userAttributesFilters: [], + filterUserAttributes: function (attributes: any) { + return attributes; + }, + filteredUser: { + getMPID: function () { + return '123'; + }, + }, + }; + }); + + afterEach(() => { + delete (window as any).Rokt.__event_stream__; + (window as any).mParticle.forwarder.eventQueue = []; + (window as any).mParticle.forwarder.eventStreamQueue = []; + (window as any).mParticle.forwarder.isInitialized = false; + (window as any).mParticle.Rokt.attachKitCalled = false; + }); + + it('should forward event to window.Rokt.__event_stream__ when available', async () => { + const receivedEvents: any[] = []; + (window as any).Rokt.__event_stream__ = function (event: any) { + receivedEvents.push(event); + }; + + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + const testEvent = { + EventName: 'Test Event', + EventCategory: EventType.Other, + EventDataType: MessageType.PageEvent, + }; + + (window as any).mParticle.forwarder.process(testEvent); + + expect(receivedEvents.length).toBe(1); + expect(receivedEvents[0].EventName).toBe('Test Event'); + expect(receivedEvents[0].EventCategory).toBe(EventType.Other); + expect(receivedEvents[0].EventDataType).toBe(MessageType.PageEvent); + expect(receivedEvents[0].UserAttributes).toEqual({}); + }); + + it('should queue event when window.Rokt.__event_stream__ is not defined', async () => { + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + const testEvent = { + EventName: 'Test Event', + EventCategory: EventType.Other, + EventDataType: MessageType.PageEvent, + }; + + expect(() => { + (window as any).mParticle.forwarder.process(testEvent); + }).not.toThrow(); + + expect((window as any).mParticle.forwarder.eventStreamQueue.length).toBe(1); + expect((window as any).mParticle.forwarder.eventStreamQueue[0]).toEqual(testEvent); + }); + + it('should queue event when window.Rokt is undefined', async () => { + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + const savedRokt = (window as any).Rokt; + (window as any).Rokt = undefined; + + const testEvent = { + EventName: 'Test Event', + EventCategory: EventType.Other, + EventDataType: MessageType.PageEvent, + }; + + expect(() => { + (window as any).mParticle.forwarder.process(testEvent); + }).not.toThrow(); + + expect((window as any).mParticle.forwarder.eventStreamQueue.length).toBe(1); + expect((window as any).mParticle.forwarder.eventStreamQueue[0]).toEqual(testEvent); + + (window as any).Rokt = savedRokt; + }); + + it('should forward event with attributes to the event stream', async () => { + const receivedEvents: any[] = []; + (window as any).Rokt.__event_stream__ = function (event: any) { + receivedEvents.push(event); + }; + + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + const testEvent = { + EventName: 'Purchase', + EventCategory: EventType.Transaction, + EventDataType: MessageType.PageEvent, + EventAttributes: { + product: 'shoes', + price: '49.99', + }, + }; + + (window as any).mParticle.forwarder.process(testEvent); + + expect(receivedEvents.length).toBe(1); + expect(receivedEvents[0].EventAttributes).toEqual({ + product: 'shoes', + price: '49.99', + }); + }); + + it('should forward multiple events to the event stream', async () => { + const receivedEvents: any[] = []; + (window as any).Rokt.__event_stream__ = function (event: any) { + receivedEvents.push(event); + }; + + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + (window as any).mParticle.forwarder.process({ + EventName: 'Event A', + EventCategory: EventType.Other, + EventDataType: MessageType.PageEvent, + }); + + (window as any).mParticle.forwarder.process({ + EventName: 'Event B', + EventCategory: EventType.Navigation, + EventDataType: MessageType.PageView, + }); + + expect(receivedEvents.length).toBe(2); + expect(receivedEvents[0].EventName).toBe('Event A'); + expect(receivedEvents[1].EventName).toBe('Event B'); + }); + + it('should forward queued events to the event stream after init', async () => { + const receivedEvents: any[] = []; + (window as any).Rokt.__event_stream__ = function (event: any) { + receivedEvents.push(event); + }; + + (window as any).mParticle.forwarder.process({ + EventName: 'Queued Event', + EventCategory: EventType.Other, + EventDataType: MessageType.PageEvent, + }); + + expect(receivedEvents.length).toBe(0); + expect((window as any).mParticle.forwarder.eventQueue.length).toBe(1); + + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + expect(receivedEvents.length).toBe(1); + expect(receivedEvents[0].EventName).toBe('Queued Event'); + }); + + it('should still process placement event mapping alongside event stream', async () => { + const receivedEvents: any[] = []; + (window as any).Rokt.__event_stream__ = function (event: any) { + receivedEvents.push(event); + }; + + const placementEventMapping = JSON.stringify([ + { + jsmap: 'hashed-<48Video Watched>-value', + map: '123466', + maptype: 'EventClass.Id', + value: 'foo-mapped-flag', + }, + ]); + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + placementEventMapping: placementEventMapping, + }, + reportService.cb, + true, + null, + {}, + ); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + (window as any).mParticle.forwarder.process({ + EventName: 'Video Watched', + EventCategory: EventType.Other, + EventDataType: MessageType.PageEvent, + }); + + expect(receivedEvents.length).toBe(1); + expect(receivedEvents[0].EventName).toBe('Video Watched'); + + expect((window as any).mParticle._Store.localSessionAttributes).toEqual({ + 'foo-mapped-flag': true, + }); + }); + + it('should enrich event with Kit userAttributes before sending to event stream', async () => { + const receivedEvents: any[] = []; + (window as any).Rokt.__event_stream__ = function (event: any) { + receivedEvents.push(event); + }; + + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + (window as any).mParticle.forwarder.userAttributes = { + firstName: 'John', + lastName: 'Doe', + }; + + (window as any).mParticle.forwarder.process({ + EventName: 'Test Event', + EventCategory: EventType.Other, + EventDataType: MessageType.PageEvent, + }); + + expect(receivedEvents.length).toBe(1); + expect(receivedEvents[0].UserAttributes).toEqual({ + firstName: 'John', + lastName: 'Doe', + }); + }); + + it('should override event UserAttributes with Kit userAttributes', async () => { + const receivedEvents: any[] = []; + (window as any).Rokt.__event_stream__ = function (event: any) { + receivedEvents.push(event); + }; + + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + (window as any).mParticle.forwarder.userAttributes = { + firstName: 'Jane', + }; + + (window as any).mParticle.forwarder.process({ + EventName: 'Test Event', + EventCategory: EventType.Other, + EventDataType: MessageType.PageEvent, + UserAttributes: { + firstName: 'Stale', + obsoleteAttr: 'should-not-appear', + }, + }); + + expect(receivedEvents.length).toBe(1); + expect(receivedEvents[0].UserAttributes).toEqual({ + firstName: 'Jane', + }); + }); + + it('should not mutate the original event when enriching with userAttributes', async () => { + const receivedEvents: any[] = []; + (window as any).Rokt.__event_stream__ = function (event: any) { + receivedEvents.push(event); + }; + + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + (window as any).mParticle.forwarder.userAttributes = { + firstName: 'John', + }; + + const originalEvent = { + EventName: 'Test Event', + EventCategory: EventType.Other, + EventDataType: MessageType.PageEvent, + }; + + (window as any).mParticle.forwarder.process(originalEvent); + + expect(originalEvent).not.toHaveProperty('UserAttributes'); + expect(receivedEvents[0].UserAttributes).toEqual({ + firstName: 'John', + }); + }); + + it('should send empty UserAttributes when Kit has no userAttributes', async () => { + const receivedEvents: any[] = []; + (window as any).Rokt.__event_stream__ = function (event: any) { + receivedEvents.push(event); + }; + + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + (window as any).mParticle.forwarder.userAttributes = {}; + + (window as any).mParticle.forwarder.process({ + EventName: 'Test Event', + EventCategory: EventType.Other, + EventDataType: MessageType.PageEvent, + }); + + expect(receivedEvents.length).toBe(1); + expect(receivedEvents[0].UserAttributes).toEqual({}); + }); + + it('should flush queued events in FIFO order when __event_stream__ becomes available', async () => { + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + (window as any).mParticle.forwarder.process({ + EventName: 'Event A', + EventCategory: EventType.Other, + EventDataType: MessageType.PageEvent, + }); + (window as any).mParticle.forwarder.process({ + EventName: 'Event B', + EventCategory: EventType.Other, + EventDataType: MessageType.PageEvent, + }); + + expect((window as any).mParticle.forwarder.eventStreamQueue.length).toBe(2); + + const receivedEvents: any[] = []; + (window as any).Rokt.__event_stream__ = function (event: any) { + receivedEvents.push(event); + }; + + (window as any).mParticle.forwarder.process({ + EventName: 'Event C', + EventCategory: EventType.Other, + EventDataType: MessageType.PageEvent, + }); + + expect(receivedEvents.length).toBe(3); + expect(receivedEvents[0].EventName).toBe('Event A'); + expect(receivedEvents[1].EventName).toBe('Event B'); + expect(receivedEvents[2].EventName).toBe('Event C'); + expect((window as any).mParticle.forwarder.eventStreamQueue.length).toBe(0); + }); + }); + + describe('#_setRoktSessionId', () => { + let setIntegrationAttributeCalls: any[]; + + beforeEach(() => { + setIntegrationAttributeCalls = []; + (window as any).Rokt = new (MockRoktForwarder as any)(); + (window as any).mParticle.Rokt = (window as any).Rokt; + (window as any).mParticle.Rokt.attachKitCalled = false; + (window as any).mParticle.Rokt.attachKit = async (kit: any) => { + (window as any).mParticle.Rokt.attachKitCalled = true; + (window as any).mParticle.Rokt.kit = kit; + Promise.resolve(); + }; + (window as any).mParticle.Rokt.setLocalSessionAttribute = function (key: any, value: any) { + (window as any).mParticle._Store.localSessionAttributes[key] = value; + }; + (window as any).mParticle.Rokt.getLocalSessionAttributes = function () { + return (window as any).mParticle._Store.localSessionAttributes; + }; + (window as any).mParticle.Rokt.filters = { + userAttributeFilters: [], + filterUserAttributes: function (attributes: any) { + return attributes; + }, + filteredUser: { + getMPID: function () { + return '123'; + }, + }, + }; + (window as any).mParticle.getInstance = function () { + return { + setIntegrationAttribute: function (id: any, attrs: any) { + setIntegrationAttributeCalls.push({ + id: id, + attrs: attrs, + }); + }, + }; + }; + }); + + afterEach(() => { + delete (window as any).mParticle.getInstance; + (window as any).mParticle.forwarder.isInitialized = false; + (window as any).mParticle.Rokt.attachKitCalled = false; + }); + + function createMockSelection(sessionId: any) { + return { + context: { + sessionId: sessionId ? Promise.resolve(sessionId) : Promise.resolve(''), + }, + }; + } + + function setupLauncherWithSelection(mockSelection: any) { + (window as any).Rokt.createLauncher = async function (_options: any) { + return Promise.resolve({ + selectPlacements: function () { + return Promise.resolve(mockSelection); + }, + }); + }; + } + + it('should set integration attribute when session ID is available via context', async () => { + const mockSelection = createMockSelection('rokt-session-abc'); + setupLauncherWithSelection(mockSelection); + + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + await waitForCondition(() => (window as any).mParticle.forwarder.isInitialized); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: {}, + }); + + await waitForCondition(() => setIntegrationAttributeCalls.length > 0); + + expect(setIntegrationAttributeCalls.length).toBe(1); + expect(setIntegrationAttributeCalls[0].id).toBe(181); + expect(setIntegrationAttributeCalls[0].attrs).toEqual({ + roktSessionId: 'rokt-session-abc', + }); + }); + + it('should not set integration attribute when session ID is empty', async () => { + const mockSelection = createMockSelection(''); + setupLauncherWithSelection(mockSelection); + + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + await waitForCondition(() => (window as any).mParticle.forwarder.isInitialized); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: {}, + }); + + // Give time for any async operations to settle + await new Promise((resolve) => setTimeout(resolve, 50)); + + expect(setIntegrationAttributeCalls.length).toBe(0); + }); + + it('should not throw when mParticle.getInstance is unavailable', async () => { + const mockSelection = createMockSelection('rokt-session-abc'); + setupLauncherWithSelection(mockSelection); + delete (window as any).mParticle.getInstance; + + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + await waitForCondition(() => (window as any).mParticle.forwarder.isInitialized); + + // Should not throw + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: {}, + }); + + // Give time for async operations + await new Promise((resolve) => setTimeout(resolve, 50)); + + expect(setIntegrationAttributeCalls.length).toBe(0); + }); + + it('should return the selection promise to callers', async () => { + const mockSelection = createMockSelection('rokt-session-abc'); + setupLauncherWithSelection(mockSelection); + + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + await waitForCondition(() => (window as any).mParticle.forwarder.isInitialized); + + const result = await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: {}, + }); + + expect(result).toBe(mockSelection); + }); + }); + + describe('#parseSettingsString', () => { + it('should parse null values in a settings string appropriately', () => { + const settingsString = + '[{"jsmap":null,"map":"f.name","maptype":"UserAttributeClass.Name","value":"firstname"},{"jsmap":null,"map":"last_name","maptype":"UserAttributeClass.Name","value":"lastname"}]'; + + expect((window as any).mParticle.forwarder.testHelpers.parseSettingsString(settingsString)).toEqual([ + { + jsmap: null, + map: 'f.name', + maptype: 'UserAttributeClass.Name', + value: 'firstname', + }, + { + jsmap: null, + map: 'last_name', + maptype: 'UserAttributeClass.Name', + value: 'lastname', + }, + ]); + }); + + it('should convert jmap and map number values to stringified numbers when parsed', () => { + const settingsString = + '[{"jsmap":"-1484452948","map":"-5208850776883573773","maptype":"EventClass.Id","value":"abc"},{"jsmap":"1838502119","map":"1324617889422969328","maptype":"EventClass.Id","value":"bcd"},{"jsmap":"-355458063","map":"5878452521714063084","maptype":"EventClass.Id","value":"card_viewed_test"}]'; + + expect((window as any).mParticle.forwarder.testHelpers.parseSettingsString(settingsString)).toEqual([ + { + jsmap: '-1484452948', + map: '-5208850776883573773', + maptype: 'EventClass.Id', + value: 'abc', + }, + { + jsmap: '1838502119', + map: '1324617889422969328', + maptype: 'EventClass.Id', + value: 'bcd', + }, + { + jsmap: '-355458063', + map: '5878452521714063084', + maptype: 'EventClass.Id', + value: 'card_viewed_test', + }, + ]); + }); + + it('returns an empty array if the settings string is empty', () => { + const settingsString = ''; + + expect((window as any).mParticle.forwarder.testHelpers.parseSettingsString(settingsString)).toEqual([]); + }); + + it('returns an empty array if the settings string is not a valid JSON', () => { + const settingsString = 'not a valid JSON'; + + expect((window as any).mParticle.forwarder.testHelpers.parseSettingsString(settingsString)).toEqual([]); + }); + }); + + describe('#hashEventMessage', () => { + it('should hash event message using generateHash in the proper order', () => { + const eventName = 'Test Event'; + const eventType = EventType.Other; + const messageType = MessageType.PageEvent; + const resultHash = (window as any).mParticle.forwarder.testHelpers.hashEventMessage( + messageType, + eventType, + eventName, + ); + + // Order should be messageType (4), eventType (8), eventName (Test Event) + expect(resultHash).toBe('hashed-<48Test Event>-value'); + }); + }); + + describe('#createAutoRemovedIframe', () => { + beforeEach(() => { + (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true); + }); + + it('should create a hidden iframe with the given src and append it to the document', () => { + const src = 'https://example.com/test'; + (window as any).mParticle.forwarder.testHelpers.createAutoRemovedIframe(src); + + const iframe = document.querySelector('iframe[src="' + src + '"]') as HTMLIFrameElement; + expect(iframe).toBeTruthy(); + expect(iframe.style.display).toBe('none'); + expect(iframe.getAttribute('sandbox')).toBe('allow-scripts allow-same-origin'); + }); + + it('should remove the iframe from the DOM after it loads', () => { + const src = 'https://example.com/auto-remove-test'; + (window as any).mParticle.forwarder.testHelpers.createAutoRemovedIframe(src); + + const iframe = document.querySelector('iframe[src="' + src + '"]') as any; + expect(iframe).toBeTruthy(); + + // Simulate load event + iframe.onload(); + + // iframe should be removed + const removed = document.querySelector('iframe[src="' + src + '"]'); + expect(removed).toBeNull(); + }); + }); + + describe('#sendAdBlockMeasurementSignals', () => { + let originalRandom: () => number; + + beforeEach(() => { + originalRandom = Math.random; + (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true); + // Set allowed origin hash to match the test environment origin + const testOriginHash = (window as any).mParticle.forwarder.testHelpers.djb2(window.location.origin); + (window as any).mParticle.forwarder.testHelpers.setAllowedOriginHashes([testOriginHash]); + // Clean up any iframes from previous tests + document.querySelectorAll('iframe').forEach((iframe) => { + if (iframe.parentNode) { + iframe.parentNode.removeChild(iframe); + } + }); + }); + + afterEach(() => { + Math.random = originalRandom; + delete (window as any).__rokt_li_guid__; + // Clean up iframes + document.querySelectorAll('iframe').forEach((iframe) => { + if (iframe.parentNode) { + iframe.parentNode.removeChild(iframe); + } + }); + }); + + it('should create two iframes with correct URLs when sampled in and guid is set', () => { + Math.random = () => 0.05; // Below 0.1 threshold + (window as any).__rokt_li_guid__ = 'test-guid-123'; + + (window as any).mParticle.forwarder.testHelpers.sendAdBlockMeasurementSignals('custom.rokt.com', 'test-version'); + + const iframes = document.querySelectorAll('iframe'); + const srcs = Array.prototype.map.call(iframes, (iframe: any) => iframe.src) as string[]; + + expect(srcs.length).toBeGreaterThanOrEqual(2); + + const existingDomainIframe = srcs.find((src) => src.indexOf('custom.rokt.com/v1/wsdk-init/index.html') !== -1); + const controlDomainIframe = srcs.find( + (src) => src.indexOf('apps.roktecommerce.com/v1/wsdk-init/index.html') !== -1, + ); + + expect(existingDomainIframe).toBeTruthy(); + expect(controlDomainIframe).toBeTruthy(); + + expect(existingDomainIframe).toContain('version=test-version'); + expect(existingDomainIframe).toContain('launcherInstanceGuid=test-guid-123'); + expect(existingDomainIframe).not.toContain('isControl'); + + expect(controlDomainIframe).toContain('version=test-version'); + expect(controlDomainIframe).toContain('launcherInstanceGuid=test-guid-123'); + expect(controlDomainIframe).toContain('isControl=true'); + }); + + it('should use apps.rokt.com as the default domain when no domain is provided', () => { + Math.random = () => 0.05; + (window as any).__rokt_li_guid__ = 'test-guid-123'; + + (window as any).mParticle.forwarder.testHelpers.sendAdBlockMeasurementSignals(undefined, 'test-version'); + + const iframes = document.querySelectorAll('iframe'); + const srcs = Array.prototype.map.call(iframes, (iframe: any) => iframe.src) as string[]; + + const defaultDomainIframe = srcs.find( + (src) => + src.indexOf('apps.rokt.com/v1/wsdk-init/index.html') !== -1 && src.indexOf('apps.roktecommerce.com') === -1, + ); + + expect(defaultDomainIframe).toBeTruthy(); + }); + + it('should not create iframes when sampled out', () => { + Math.random = () => 0.5; // Above 0.1 threshold + (window as any).__rokt_li_guid__ = 'test-guid-123'; + + const iframeCountBefore = document.querySelectorAll('iframe').length; + + (window as any).mParticle.forwarder.testHelpers.sendAdBlockMeasurementSignals('apps.rokt.com', 'test-version'); + + const iframeCountAfter = document.querySelectorAll('iframe').length; + expect(iframeCountAfter).toBe(iframeCountBefore); + }); + + it('should not create iframes when __rokt_li_guid__ is not set', () => { + Math.random = () => 0.05; + delete (window as any).__rokt_li_guid__; + + const iframeCountBefore = document.querySelectorAll('iframe').length; + + (window as any).mParticle.forwarder.testHelpers.sendAdBlockMeasurementSignals('apps.rokt.com', 'test-version'); + + const iframeCountAfter = document.querySelectorAll('iframe').length; + expect(iframeCountAfter).toBe(iframeCountBefore); + }); + + it('should not create iframes when origin does not match allowed hash', () => { + Math.random = () => 0.05; + (window as any).__rokt_li_guid__ = 'test-guid-123'; + + // Set to a hash that won't match any real origin + (window as any).mParticle.forwarder.testHelpers.setAllowedOriginHashes([0]); + + const iframeCountBefore = document.querySelectorAll('iframe').length; + + (window as any).mParticle.forwarder.testHelpers.sendAdBlockMeasurementSignals('apps.rokt.com', 'test-version'); + + const iframeCountAfter = document.querySelectorAll('iframe').length; + expect(iframeCountAfter).toBe(iframeCountBefore); + }); + + it('should strip hash fragments from pageUrl', () => { + Math.random = () => 0.05; + (window as any).__rokt_li_guid__ = 'test-guid-123'; + + // window.location.href in test env won't have a fragment, + // but we can verify the pageUrl param does not contain '#' + (window as any).mParticle.forwarder.testHelpers.sendAdBlockMeasurementSignals('apps.rokt.com', 'test-version'); + + const iframes = document.querySelectorAll('iframe'); + const srcs = Array.prototype.map.call(iframes, (iframe: any) => iframe.src) as string[]; + + srcs.forEach((src) => { + expect(src).toContain('pageUrl='); + // Extract the pageUrl param value + const match = src.match(/pageUrl=([^&]*)/); + expect(match).toBeTruthy(); + const decodedPageUrl = decodeURIComponent(match![1]); + expect(decodedPageUrl).not.toContain('#'); + expect(decodedPageUrl).not.toContain('?'); + }); + }); + + it('should fire measurement signals during initRoktLauncher when guid exists', async () => { + Math.random = () => 0.05; + (window as any).__rokt_li_guid__ = 'init-test-guid'; + // Ensure origin hash matches test environment + const testOriginHash = (window as any).mParticle.forwarder.testHelpers.djb2(window.location.origin); + (window as any).mParticle.forwarder.testHelpers.setAllowedOriginHashes([testOriginHash]); + + (window as any).Rokt = new (MockRoktForwarder as any)(); + (window as any).mParticle.Rokt = (window as any).Rokt; + (window as any).mParticle.Rokt.attachKitCalled = false; + (window as any).mParticle.Rokt.attachKit = async (kit: any) => { + (window as any).mParticle.Rokt.attachKitCalled = true; + (window as any).mParticle.Rokt.kit = kit; + Promise.resolve(); + }; + (window as any).mParticle.Rokt.filters = { + userAttributesFilters: [], + filterUserAttributes: function (attributes: any) { + return attributes; + }, + filteredUser: { + getMPID: function () { + return '123'; + }, + }, + }; + + await mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + await waitForCondition(() => (window as any).mParticle.forwarder.isInitialized); + + const iframes = document.querySelectorAll('iframe'); + const srcs = Array.prototype.map.call(iframes, (iframe: any) => iframe.src) as string[]; + + const controlIframe = srcs.find((src) => src.indexOf('apps.roktecommerce.com/v1/wsdk-init/index.html') !== -1); + + expect(controlIframe).toBeTruthy(); + expect(controlIframe).toContain('launcherInstanceGuid=init-test-guid'); + }); + + it('should not fire measurement signals during init when guid is absent', async () => { + Math.random = () => 0.05; + delete (window as any).__rokt_li_guid__; + // Ensure origin hash matches test environment + const testOriginHash = (window as any).mParticle.forwarder.testHelpers.djb2(window.location.origin); + (window as any).mParticle.forwarder.testHelpers.setAllowedOriginHashes([testOriginHash]); + + (window as any).Rokt = new (MockRoktForwarder as any)(); + (window as any).mParticle.Rokt = (window as any).Rokt; + (window as any).mParticle.Rokt.attachKitCalled = false; + (window as any).mParticle.Rokt.attachKit = async (kit: any) => { + (window as any).mParticle.Rokt.attachKitCalled = true; + (window as any).mParticle.Rokt.kit = kit; + Promise.resolve(); + }; + (window as any).mParticle.Rokt.filters = { + userAttributesFilters: [], + filterUserAttributes: function (attributes: any) { + return attributes; + }, + filteredUser: { + getMPID: function () { + return '123'; + }, + }, + }; + + await mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + await waitForCondition(() => (window as any).mParticle.forwarder.isInitialized); + + const iframes = document.querySelectorAll('iframe'); + const srcs = Array.prototype.map.call(iframes, (iframe: any) => iframe.src) as string[]; + + const controlIframe = srcs.find((src) => src.indexOf('apps.roktecommerce.com/v1/wsdk-init/index.html') !== -1); + + expect(controlIframe).toBeUndefined(); + }); + }); + + describe('ErrorReportingService', () => { + let originalFetch: typeof window.fetch; + let fetchCalls: Array<{ url: string; options: any }>; + const originalROKT_DOMAIN_ref = { value: (window as any).ROKT_DOMAIN }; + + beforeEach(() => { + fetchCalls = []; + originalFetch = window.fetch; + (window as any).fetch = (url: string, options: any) => { + fetchCalls.push({ url, options }); + return Promise.resolve({ ok: true }); + }; + originalROKT_DOMAIN_ref.value = (window as any).ROKT_DOMAIN; + (window as any).ROKT_DOMAIN = 'set'; + }); + + afterEach(() => { + window.fetch = originalFetch; + (window as any).ROKT_DOMAIN = originalROKT_DOMAIN_ref.value; + }); + + it('should send error reports to the errors endpoint', () => { + const service = new ErrorReportingServiceClass( + { errorUrl: 'test.com/v1/errors', isLoggingEnabled: true }, + '1.0.0', + 'test-guid', + ); + service.report({ + message: 'test error', + code: ErrorCodesConst.UNHANDLED_EXCEPTION, + severity: WSDKErrorSeverityConst.ERROR, + stackTrace: 'stack', + }); + expect(fetchCalls.length).toBe(1); + expect(fetchCalls[0].url).toBe('https://test.com/v1/errors'); + const body = JSON.parse(fetchCalls[0].options.body); + expect(body.severity).toBe('ERROR'); + expect(body.code).toBe('UNHANDLED_EXCEPTION'); + expect(body.stackTrace).toBe('stack'); + expect(body.reporter).toBe('mp-wsdk'); + }); + + it('should send warning reports to the errors endpoint', () => { + const service = new ErrorReportingServiceClass( + { errorUrl: 'test.com/v1/errors', isLoggingEnabled: true }, + '1.0.0', + 'test-guid', + ); + service.report({ + message: 'test warning', + code: ErrorCodesConst.UNHANDLED_EXCEPTION, + severity: WSDKErrorSeverityConst.WARNING, + }); + expect(fetchCalls.length).toBe(1); + const body = JSON.parse(fetchCalls[0].options.body); + expect(body.severity).toBe('WARNING'); + }); + + it('should send info reports to the errors endpoint', () => { + const service = new ErrorReportingServiceClass( + { errorUrl: 'test.com/v1/errors', isLoggingEnabled: true }, + '1.0.0', + 'test-guid', + ); + service.report({ + message: 'info message', + code: ErrorCodesConst.UNHANDLED_EXCEPTION, + severity: WSDKErrorSeverityConst.INFO, + }); + expect(fetchCalls.length).toBe(1); + const body = JSON.parse(fetchCalls[0].options.body); + expect(body.severity).toBe('INFO'); + }); + + it('should not send when ROKT_DOMAIN is missing and feature flag is off', () => { + (window as any).ROKT_DOMAIN = undefined; + const service = new ErrorReportingServiceClass({ isLoggingEnabled: false }, '1.0.0', 'test-guid'); + service.report({ message: 'should not send', severity: WSDKErrorSeverityConst.ERROR }); + expect(fetchCalls.length).toBe(0); + }); + + it('should not send when feature flag is off and debug mode is off', () => { + const service = new ErrorReportingServiceClass({ isLoggingEnabled: false }, '1.0.0', 'test-guid'); + service.report({ message: 'should not send', severity: WSDKErrorSeverityConst.ERROR }); + expect(fetchCalls.length).toBe(0); + }); + + it('should send when debug mode is enabled even without ROKT_DOMAIN', () => { + (window as any).ROKT_DOMAIN = undefined; + const originalSearch = window.location.search; + window.history.pushState({}, '', window.location.pathname + '?mp_enable_logging=true'); + const service = new ErrorReportingServiceClass({ isLoggingEnabled: false }, '1.0.0', 'test-guid'); + service.report({ message: 'debug message', severity: WSDKErrorSeverityConst.ERROR }); + expect(fetchCalls.length).toBe(1); + window.history.pushState({}, '', window.location.pathname + originalSearch); + }); + + it('should include correct headers', () => { + const service = new ErrorReportingServiceClass({ isLoggingEnabled: true }, '1.0.0', 'test-guid'); + service.report({ message: 'test', severity: WSDKErrorSeverityConst.ERROR }); + expect(fetchCalls.length).toBe(1); + const headers = fetchCalls[0].options.headers; + expect(headers['Accept']).toBe('text/plain;charset=UTF-8'); + expect(headers['Content-Type']).toBe('application/json'); + expect(headers['rokt-launcher-instance-guid']).toBe('test-guid'); + expect(headers['rokt-wsdk-version']).toBe('joint'); + }); + + it('should omit rokt-launcher-instance-guid header when guid is undefined', () => { + const service = new ErrorReportingServiceClass({ isLoggingEnabled: true }, '1.0.0', undefined); + service.report({ message: 'test', severity: WSDKErrorSeverityConst.ERROR }); + expect(fetchCalls.length).toBe(1); + expect(fetchCalls[0].options.headers['rokt-launcher-instance-guid']).toBeUndefined(); + }); + + it('should include rokt-account-id header when accountId is provided', () => { + const service = new ErrorReportingServiceClass( + { isLoggingEnabled: true }, + 'test-integration', + 'test-guid', + '1234567890', + ); + service.report({ message: 'test', severity: WSDKErrorSeverityConst.WARNING }); + expect(fetchCalls.length).toBe(1); + expect(fetchCalls[0].options.headers['rokt-account-id']).toBe('1234567890'); + }); + + it('should not include rokt-account-id header when accountId is not provided', () => { + const service = new ErrorReportingServiceClass({ isLoggingEnabled: true }, 'test-integration', 'test-guid'); + service.report({ message: 'test', severity: WSDKErrorSeverityConst.ERROR }); + expect(fetchCalls.length).toBe(1); + expect(fetchCalls[0].options.headers['rokt-account-id']).toBeUndefined(); + }); + + it('should use default UNKNOWN_ERROR code when code is not provided', () => { + const service = new ErrorReportingServiceClass({ isLoggingEnabled: true }, '1.0.0', 'test-guid'); + service.report({ message: 'test', severity: WSDKErrorSeverityConst.ERROR }); + const body = JSON.parse(fetchCalls[0].options.body); + expect(body.code).toBe('UNKNOWN_ERROR'); + }); + + it('should use default Rokt error URL when not configured', () => { + const service = new ErrorReportingServiceClass({ isLoggingEnabled: true }, '1.0.0', 'test-guid'); + service.report({ message: 'test error', severity: WSDKErrorSeverityConst.ERROR }); + expect(fetchCalls[0].url).toBe('https://apps.rokt-api.com/v1/errors'); + }); + + it('should include all required fields in the log request body', () => { + const service = new ErrorReportingServiceClass({ isLoggingEnabled: true }, 'test-integration', 'test-guid'); + service.report({ + message: 'error message', + code: ErrorCodesConst.IDENTITY_REQUEST, + severity: WSDKErrorSeverityConst.ERROR, + stackTrace: 'stack trace here', + }); + const body = JSON.parse(fetchCalls[0].options.body); + expect(body.additionalInformation.message).toBe('error message'); + expect(body.additionalInformation.version).toBe('test-integration'); + expect(body.severity).toBe('ERROR'); + expect(body.code).toBe('IDENTITY_REQUEST'); + expect(body.stackTrace).toBe('stack trace here'); + expect(body.reporter).toBe('mp-wsdk'); + expect(body.integration).toBe('test-integration'); + }); + + it('should use empty integration values when no integration name is provided', () => { + const service = new ErrorReportingServiceClass({ isLoggingEnabled: true }, '', 'test-guid'); + service.report({ message: 'test', severity: WSDKErrorSeverityConst.ERROR }); + const body = JSON.parse(fetchCalls[0].options.body); + expect(body.reporter).toBe('mp-wsdk'); + expect(body.integration).toBe(''); + expect(body.additionalInformation.version).toBe(''); + }); + + it('should not throw when fetch fails', async () => { + (window as any).fetch = () => Promise.reject(new Error('Network failure')); + const consoleErrors: any[][] = []; + const originalConsoleError = console.error; + console.error = (...args: any[]) => { + consoleErrors.push(args); + }; + + const service = new ErrorReportingServiceClass({ isLoggingEnabled: true }, '1.0.0', 'test-guid'); + service.report({ message: 'test', severity: WSDKErrorSeverityConst.ERROR }); + + await new Promise((resolve) => setTimeout(resolve, 50)); + expect(consoleErrors.length).toBeGreaterThan(0); + expect(consoleErrors[0][0]).toBe('ReportingTransport: Failed to send log'); + console.error = originalConsoleError; + }); + + it('should not send when report is called with null', () => { + const service = new ErrorReportingServiceClass({ isLoggingEnabled: true }, '1.0.0', 'test-guid'); + service.report(null); + expect(fetchCalls.length).toBe(0); + }); + }); + + describe('LoggingService', () => { + let originalFetch: typeof window.fetch; + let fetchCalls: Array<{ url: string; options: any }>; + const originalROKT_DOMAIN_ref = { value: (window as any).ROKT_DOMAIN }; + + beforeEach(() => { + fetchCalls = []; + originalFetch = window.fetch; + (window as any).fetch = (url: string, options: any) => { + fetchCalls.push({ url, options }); + return Promise.resolve({ ok: true }); + }; + originalROKT_DOMAIN_ref.value = (window as any).ROKT_DOMAIN; + (window as any).ROKT_DOMAIN = 'set'; + }); + + afterEach(() => { + window.fetch = originalFetch; + (window as any).ROKT_DOMAIN = originalROKT_DOMAIN_ref.value; + }); + + it('should always send to the logging endpoint with severity INFO', () => { + const errorService = new ErrorReportingServiceClass({ isLoggingEnabled: true }, '1.0.0', 'test-guid'); + const service = new LoggingServiceClass( + { loggingUrl: 'test.com/v1/log', isLoggingEnabled: true }, + errorService, + '1.0.0', + 'test-guid', + ); + service.log({ message: 'log entry', code: ErrorCodesConst.UNKNOWN_ERROR }); + expect(fetchCalls.length).toBe(1); + expect(fetchCalls[0].url).toBe('https://test.com/v1/log'); + const body = JSON.parse(fetchCalls[0].options.body); + expect(body.severity).toBe('INFO'); + expect(body.additionalInformation.message).toBe('log entry'); + }); + + it('should report failure through ErrorReportingService on fetch error', async () => { + const errorReports: any[] = []; + const errorService = { + report: (error: any) => { + errorReports.push(error); + }, + }; + (window as any).fetch = () => Promise.reject(new Error('Network failure')); + const originalConsoleError = console.error; + console.error = () => {}; + + const service = new LoggingServiceClass({ isLoggingEnabled: true }, errorService, '1.0.0', 'test-guid'); + service.log({ message: 'test' }); + + await new Promise((resolve) => setTimeout(resolve, 50)); + expect(errorReports.length).toBeGreaterThan(0); + expect(errorReports[0].severity).toBe('ERROR'); + expect(errorReports[0].message).toContain('Failed to send log'); + console.error = originalConsoleError; + }); + + it('should not send when log is called with null', () => { + const errorService = new ErrorReportingServiceClass({ isLoggingEnabled: true }, '1.0.0', 'test-guid'); + const service = new LoggingServiceClass({ isLoggingEnabled: true }, errorService, '1.0.0', 'test-guid'); + service.log(null); + expect(fetchCalls.length).toBe(0); + }); + }); + + describe('RateLimiter', () => { + it('should allow up to 10 logs per severity then rate limit', () => { + const limiter = new RateLimiterClass(); + for (let i = 0; i < 10; i++) { + expect(limiter.incrementAndCheck('ERROR')).toBe(false); + } + expect(limiter.incrementAndCheck('ERROR')).toBe(true); + expect(limiter.incrementAndCheck('ERROR')).toBe(true); + }); + + it('should allow up to 10 warning logs then rate limit', () => { + const limiter = new RateLimiterClass(); + for (let i = 0; i < 10; i++) { + expect(limiter.incrementAndCheck('WARNING')).toBe(false); + } + expect(limiter.incrementAndCheck('WARNING')).toBe(true); + }); + + it('should allow up to 10 info logs then rate limit', () => { + const limiter = new RateLimiterClass(); + for (let i = 0; i < 10; i++) { + expect(limiter.incrementAndCheck('INFO')).toBe(false); + } + expect(limiter.incrementAndCheck('INFO')).toBe(true); + }); + + it('should track rate limits independently per severity', () => { + const limiter = new RateLimiterClass(); + for (let i = 0; i < 10; i++) { + limiter.incrementAndCheck('ERROR'); + } + expect(limiter.incrementAndCheck('ERROR')).toBe(true); + expect(limiter.incrementAndCheck('WARNING')).toBe(false); + }); + }); + + describe('ErrorReportingService rate limiting', () => { + let originalFetch: typeof window.fetch; + let fetchCalls: Array<{ url: string; options: any }>; + const originalROKT_DOMAIN_ref = { value: (window as any).ROKT_DOMAIN }; + + beforeEach(() => { + fetchCalls = []; + originalFetch = window.fetch; + (window as any).fetch = (url: string, options: any) => { + fetchCalls.push({ url, options }); + return Promise.resolve({ ok: true }); + }; + originalROKT_DOMAIN_ref.value = (window as any).ROKT_DOMAIN; + (window as any).ROKT_DOMAIN = 'set'; + }); + + afterEach(() => { + window.fetch = originalFetch; + (window as any).ROKT_DOMAIN = originalROKT_DOMAIN_ref.value; + }); + + it('should rate limit after 10 errors', () => { + const service = new ErrorReportingServiceClass({ isLoggingEnabled: true }, '1.0.0', 'test-guid'); + for (let i = 0; i < 15; i++) { + service.report({ message: `error ${i}`, severity: WSDKErrorSeverityConst.ERROR }); + } + expect(fetchCalls.length).toBe(10); + }); + + it('should rate limit with custom rate limiter', () => { + let count = 0; + const customLimiter = { incrementAndCheck: () => ++count > 3 }; + const service = new ErrorReportingServiceClass( + { isLoggingEnabled: true }, + 'test-integration', + 'test-guid', + null, + customLimiter, + ); + for (let i = 0; i < 5; i++) { + service.report({ message: `error ${i}`, severity: WSDKErrorSeverityConst.ERROR }); + } + expect(fetchCalls.length).toBe(3); + }); + }); + + describe('Reporting service registration', () => { + it('should register services with mParticle if methods exist', async () => { + let registeredErrorService: any = null; + let registeredLoggingService: any = null; + + (window as any).mParticle._registerErrorReportingService = (service: any) => { + registeredErrorService = service; + }; + (window as any).mParticle._registerLoggingService = (service: any) => { + registeredLoggingService = service; + }; + + (window as any).Rokt = new (MockRoktForwarder as any)(); + (window as any).mParticle.Rokt = (window as any).Rokt; + (window as any).mParticle.Rokt.attachKitCalled = false; + (window as any).mParticle.Rokt.attachKit = async (kit: any) => { + (window as any).mParticle.Rokt.attachKitCalled = true; + (window as any).mParticle.Rokt.kit = kit; + }; + (window as any).mParticle.Rokt.filters = { + userAttributesFilters: [], + filterUserAttributes: (attributes: any) => attributes, + filteredUser: { getMPID: () => '123' }, + }; + + await mParticle.forwarder.init( + { accountId: '123456', isLoggingEnabled: 'true' }, + reportService.cb, + true, + null, + {}, + ); + + expect(registeredErrorService).not.toBeNull(); + expect(registeredLoggingService).not.toBeNull(); + expect(typeof registeredErrorService.report).toBe('function'); + expect(typeof registeredLoggingService.log).toBe('function'); + + delete (window as any).mParticle._registerErrorReportingService; + delete (window as any).mParticle._registerLoggingService; + }); + + it('should not throw when registration methods do not exist', async () => { + delete (window as any).mParticle._registerErrorReportingService; + delete (window as any).mParticle._registerLoggingService; + + (window as any).Rokt = new (MockRoktForwarder as any)(); + (window as any).mParticle.Rokt = (window as any).Rokt; + (window as any).mParticle.Rokt.attachKit = async (kit: any) => { + (window as any).mParticle.Rokt.kit = kit; + }; + (window as any).mParticle.Rokt.filters = { + userAttributesFilters: [], + filterUserAttributes: (attributes: any) => attributes, + filteredUser: { getMPID: () => '123' }, + }; + + await mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + expect((window as any).mParticle.forwarder.isInitialized).toBeDefined(); + }); + }); +}); diff --git a/test/vitest.setup.ts b/test/vitest.setup.ts new file mode 100644 index 0000000..a2c92be --- /dev/null +++ b/test/vitest.setup.ts @@ -0,0 +1,37 @@ +// Global test setup for Vitest. +// This file runs before each test file. +// It sets up the window.mParticle mock so the kit can self-register when imported. + +// Set up global mParticle mock before any test files load. +// The kit self-registers via window.mParticle.addForwarder() at module load time. +// eslint-disable-next-line @typescript-eslint/no-explicit-any +(globalThis as any).mParticle = { + addForwarder: function (forwarder: { name: string; constructor: new () => unknown }) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (globalThis as any).mParticle.forwarder = new forwarder.constructor(); + }, + Rokt: {}, + EventType: { Other: 8 }, + getEnvironment: () => 'development', + getVersion: () => '1.2.3', + Identity: { + getCurrentUser: () => ({ + getMPID: () => '123', + }), + }, + _Store: { localSessionAttributes: {} }, + sessionManager: { + getSession: () => 'test-mp-session-id', + }, + _getActiveForwarders: () => [], + generateHash: (input: string) => 'hashed-<' + input + '>-value', + loggedEvents: [] as unknown[], + logEvent: function (eventName: string, eventType: unknown, eventAttributes: unknown) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (globalThis as any).mParticle.loggedEvents.push({ eventName, eventType, eventAttributes }); + }, + getInstance: () => ({ + setIntegrationAttribute: () => {}, + }), + captureTiming: () => {}, +}; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..ee3c6d1 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "module": "ESNext", + "moduleResolution": "bundler", + "target": "ES2017", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "lib": ["DOM", "ESNext"], + "declaration": true, + "skipLibCheck": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "test"] +} diff --git a/tsconfig.test.json b/tsconfig.test.json new file mode 100644 index 0000000..8541679 --- /dev/null +++ b/tsconfig.test.json @@ -0,0 +1,7 @@ +{ + "extends": "./tsconfig.json", + "include": ["src/**/*", "test/**/*"], + "compilerOptions": { + "types": ["vitest/globals"] + } +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..0f36f5a --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,41 @@ +/// +import { defineConfig } from 'vite'; +import dts from 'vite-plugin-dts'; +import { resolve } from 'path'; + +export default defineConfig({ + build: { + target: 'es2020', + lib: { + entry: resolve(__dirname, 'src/Rokt-Kit.ts'), + name: 'RoktKit', + formats: ['iife', 'cjs', 'es'], + fileName: (format) => { + if (format === 'iife') return 'Rokt-Kit.iife.js'; + if (format === 'es') return 'Rokt-Kit.esm.js'; + return 'Rokt-Kit.common.js'; + }, + }, + outDir: 'dist', + sourcemap: true, + rollupOptions: { + output: { + exports: 'named', + }, + }, + }, + define: { + 'process.env.PACKAGE_VERSION': JSON.stringify(process.env.npm_package_version), + }, + plugins: [dts({ rollupTypes: true })], + test: { + environment: 'jsdom', + globals: true, + setupFiles: ['./test/vitest.setup.ts'], + include: ['test/src/**/*.spec.ts', 'src/**/*.spec.ts'], + coverage: { + provider: 'v8', + include: ['src/**/*.ts'], + }, + }, +});