diff --git a/kits/rokt/.gitignore b/kits/rokt/.gitignore new file mode 100644 index 000000000..6a135610c --- /dev/null +++ b/kits/rokt/.gitignore @@ -0,0 +1,5 @@ +node_modules/ +test/test-bundle.js +.DS_Store +test/end-to-end-testapp/build/compilation.js +dist/* diff --git a/kits/rokt/.nvmrc b/kits/rokt/.nvmrc new file mode 100644 index 000000000..a45fd52cc --- /dev/null +++ b/kits/rokt/.nvmrc @@ -0,0 +1 @@ +24 diff --git a/kits/rokt/.prettierrc b/kits/rokt/.prettierrc new file mode 100644 index 000000000..4b9a2d97d --- /dev/null +++ b/kits/rokt/.prettierrc @@ -0,0 +1,5 @@ +{ + "printWidth": 120, + "singleQuote": true, + "trailingComma": "all" +} diff --git a/kits/rokt/CHANGELOG.md b/kits/rokt/CHANGELOG.md index 0e8329536..e325ef191 100644 --- a/kits/rokt/CHANGELOG.md +++ b/kits/rokt/CHANGELOG.md @@ -1,3 +1,121 @@ +## [1.26.1](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/compare/v1.26.0...v1.26.1) (2026-05-12) + + +### Bug Fixes + +* search workspace for cached Rokt users ([#94](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/issues/94)) ([00f3f73](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/commit/00f3f734e57a1a232841482287f84bdeb37ab634)) + +# [1.26.0](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/compare/v1.25.1...v1.26.0) (2026-05-05) + + +### Bug Fixes + +* Support more identities in search ([#93](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/issues/93)) ([1526325](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/commit/1526325de752804d811d74ed9a1b95d7171f3383)) + + +### Features + +* Add Workspace IDSync search on user identification ([#92](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/issues/92)) ([f742616](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/commit/f742616704ff5fea12d1043c8d45762e065f4a6b)) + +## [1.25.1](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/compare/v1.25.0...v1.25.1) (2026-04-27) + + +### Bug Fixes + +* Enable Thank You Element Partner Event listening before RoktKit is ready ([#91](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/issues/91)) ([bced30e](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/commit/bced30e278c6f9a906a45a3734c0d2af67cfee69)) + +# [1.25.0](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/compare/v1.24.1...v1.25.0) (2026-04-23) + + +### Features + +* Embed Thank You Element in Joint SDK ([#90](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/issues/90)) ([035f0f9](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/commit/035f0f9d5b7aba345b636839e9ab982128658dbf)) + +## [1.24.1](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/compare/v1.24.0...v1.24.1) (2026-04-16) + + +### Bug Fixes + +* align identity events with mParticle batch schema ([#88](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/issues/88)) ([ddcfa61](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/commit/ddcfa61084ea6f392071cb85feecb42703bc3093)) + +# [1.24.0](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/compare/v1.23.0...v1.24.0) (2026-04-09) + + +### Features + +* add batch stream wrapper function ([#86](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/issues/86)) ([c361fa2](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/commit/c361fa2aba7d13b55d3cc0918ee0e4f0e4db5106)) + +# [1.23.0](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/compare/v1.22.0...v1.23.0) (2026-04-08) + + +### Features + +* migrate toolchain to TypeScript 5.5, Vite, Vitest, and ESLint v9 ([#84](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/issues/84)) ([58f6b41](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/commit/58f6b418c0ee898f4264de14abfd0a9c11b1ca37)) + +# [1.22.0](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/compare/v1.21.0...v1.22.0) (2026-04-07) + + +### Features + +* implement Rokt reporting service in kit ([#70](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/issues/70)) ([efb8905](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/commit/efb8905155db9a9fb580f15c4b196cdd51aecd2c)) + +# [1.21.0](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/compare/v1.20.0...v1.21.0) (2026-04-03) + + +### Features + +* send set_user_attributes event ([#82](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/issues/82)) ([9995f09](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/commit/9995f09a008a5acc6355306e109a683f8d80cd91)) + +# [1.20.0](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/compare/v1.19.0...v1.20.0) (2026-03-30) + + +### Features + +* support sending login, logout, identify, and modify_user events ([#81](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/issues/81)) ([78061a5](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/commit/78061a54a85feb25c3e27dff445eae7f6c855b90)) + +# [1.19.0](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/compare/v1.18.1...v1.19.0) (2026-03-25) + + +### Bug Fixes + +* Update adblock measurement target origin ([#68](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/issues/68)) ([8a524c2](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/commit/8a524c21c82a48d756d35ef294ad9342ab7ac4ba)) + + +### Features + +* add /verify skill and AGENTS.md for agent guidance ([#69](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/issues/69)) ([21134b0](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/commit/21134b05eae9868c08d412fc1f95bd62f3583cee)), closes [hi#level](https://github.com/hi/issues/level) +* add defensive queue to _sendEventStream to prevent event loss ([#78](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/issues/78)) ([82b8dfc](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/commit/82b8dfc4248d05795be0bad117a16de0f6a4f694)) +* enrich event stream with Kit userAttributes ([#79](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/issues/79)) ([7c27cd3](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/commit/7c27cd30a22328a2b117d9c39e5f256784f0e1af)) + +## [1.18.1](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/compare/v1.18.0...v1.18.1) (2026-03-24) + + +### Bug Fixes + +* Add logSelectPlacementsEvent to falsey selection value ([#76](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/issues/76)) ([8a0d0b1](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/commit/8a0d0b1f41e4c0c45622ef2754464ff6b4ef6ddd)) + +# [1.18.0](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/compare/v1.17.0...v1.18.0) (2026-03-24) + + +### Bug Fixes + +* **ci:** add contents read permission for pr-notify workflow ([#73](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/issues/73)) ([7c84013](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/commit/7c84013f3b8e1b26eae4d298e624abea4d2eea1d)) +* **ci:** add id-token permission for pr-notify workflow ([#72](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/issues/72)) ([fa278ff](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/commit/fa278ff2f3cdd2def3f370151627abddeb1ba73e)) + + +### Features + +* pass mParticle session ID to Rokt SDK on launcher creation ([#74](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/issues/74)) ([1a5b591](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/commit/1a5b59199caa15ac5261b9bec77b13f66d9e5d0f)) +* sync Rokt session ID to mParticle via setIntegrationAttribute ([#67](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/issues/67)) ([021b2a5](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/commit/021b2a544e2db4eece85190b0f98231445d27a50)) + +# [1.17.0](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/compare/v1.16.0...v1.17.0) (2026-03-12) + + +### Features + +* Add Event Stream function ([#64](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/issues/64)) ([1fea071](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/commit/1fea071e4ded678e11afcf54046dbcfc6c1c3df2)) +* Improve observability through additional init signals ([#61](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/issues/61)) ([83bdc6d](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/commit/83bdc6df254f3060587aaa57443d4154c20a666b)) + # [1.16.0](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/compare/v1.15.0...v1.16.0) (2026-02-24) diff --git a/kits/rokt/eslint.config.mjs b/kits/rokt/eslint.config.mjs new file mode 100644 index 000000000..946f580e4 --- /dev/null +++ b/kits/rokt/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/kits/rokt/package-lock.json b/kits/rokt/package-lock.json index b56dc3105..a0471c5e0 100644 --- a/kits/rokt/package-lock.json +++ b/kits/rokt/package-lock.json @@ -1,41 +1,38 @@ { "name": "@mparticle/web-rokt-kit", - "version": "1.16.0", + "version": "1.26.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@mparticle/web-rokt-kit", - "version": "1.16.0", + "version": "1.26.1", "license": "Apache-2.0", "dependencies": { - "@mparticle/web-sdk": "^2.56.0" + "@mparticle/web-sdk": "^2.62.0" }, "devDependencies": { - "@rollup/plugin-json": "^6.1.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "^9.23.0", + "@mparticle/event-models": "^1.1.9", "@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": "^24.1.3", + "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 +74,27 @@ "dev": true, "license": "MIT" }, + "node_modules/@asamuzakjp/css-color": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz", + "integrity": "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^2.1.3", + "@csstools/css-color-parser": "^3.0.9", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "lru-cache": "^10.4.3" + } + }, + "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, "node_modules/@babel/code-frame": { "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", @@ -87,6 +105,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 +219,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,6 +244,30 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/@colors/colors": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", @@ -211,184 +279,1059 @@ "node": ">=0.1.90" } }, - "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/@csstools/color-helpers": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", + "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/css-calc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", + "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "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" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" } }, - "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/@csstools/css-color-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", + "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", "dev": true, - "license": "Apache-2.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", "dependencies": { - "@humanwhocodes/object-schema": "^1.2.0", - "debug": "^4.1.1", - "minimatch": "^3.0.4" + "@csstools/color-helpers": "^5.1.0", + "@csstools/css-calc": "^2.1.4" }, "engines": { - "node": ">=10.10.0" + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" } }, - "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/@csstools/css-parser-algorithms": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", + "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", "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" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.4" } }, - "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/css-tokenizer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", + "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "license": "MIT", "engines": { - "node": ">= 20" + "node": ">=18" } }, - "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/@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", - "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" - }, + "optional": true, + "os": [ + "aix" + ], "engines": { - "node": ">= 20" + "node": ">=18" } }, - "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/@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/types": "^16.0.0", - "universal-user-agent": "^7.0.2" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">= 20" + "node": ">=18" } }, - "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/@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/request": "^10.0.6", - "@octokit/types": "^16.0.0", - "universal-user-agent": "^7.0.0" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">= 20" + "node": ">=18" } }, - "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/@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" + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } }, - "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/@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", - "dependencies": { - "@octokit/types": "^15.0.1" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">= 20" - }, - "peerDependencies": { - "@octokit/core": ">=6" + "node": ">=18" } }, - "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==", + "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" + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } }, - "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/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", - "dependencies": { - "@octokit/openapi-types": "^26.0.0" + "optional": true, + "os": [ + "freebsd" + ], + "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/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", - "dependencies": { - "@octokit/request-error": "^7.0.2", - "@octokit/types": "^16.0.0", - "bottleneck": "^2.15.3" - }, + "optional": true, + "os": [ + "freebsd" + ], "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/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", - "dependencies": { + "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/@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/event-models": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@mparticle/event-models/-/event-models-1.1.9.tgz", + "integrity": "sha512-2ucTwTKKA4xZjcSMlkim3rvr6d8uyi9yWDqOW8b9RDah2ak+dI0PkWANHkMJqteQprEg9mOkSvxc17kv5adIIA==", + "license": "Apache-2.0" + }, + "node_modules/@mparticle/web-sdk": { + "version": "2.62.0", + "resolved": "https://registry.npmjs.org/@mparticle/web-sdk/-/web-sdk-2.62.0.tgz", + "integrity": "sha512-JJV61ValoRNnS4hq3hMe1U9SVkI6EQC+b8Jg/11mq/yMO7xoqvfC274BjNd8I2sYtr5LgD3zGnHOz8gcBn7+Xw==", + "license": "Apache-2.0", + "dependencies": { + "@babel/runtime": "^7.23.2" + }, + "peerDependencies": { + "@mparticle/event-models": "^1.1.9" + } + }, + "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" }, @@ -439,6 +1382,19 @@ "@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", @@ -484,14 +1440,16 @@ "node": ">=12" } }, - "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/@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": { - "@rollup/pluginutils": "^5.1.0" + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" }, "engines": { "node": ">=14.0.0" @@ -505,29 +1463,512 @@ } } }, - "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/@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": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^4.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" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "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": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" }, "engines": { - "node": ">=14.0.0" + "node": ">=6 <7 || >=8" + } + }, + "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", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "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": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "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": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "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": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "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": { + "resolve": "~1.22.1", + "strip-json-comments": "~3.1.1" + } + }, + "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": { + "@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/@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": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "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": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", @@ -1026,13 +2467,45 @@ "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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": "MIT" + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" } }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -1040,14 +2513,21 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/node": { - "version": "25.2.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.0.tgz", - "integrity": "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w==", + "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": { - "undici-types": "~7.16.0" + "undici-types": "~6.21.0" } }, "node_modules/@types/normalize-package-data": { @@ -1057,937 +2537,825 @@ "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==", + "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": { - "@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" + "@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": ">= 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" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "license": "MIT", "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/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==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "acorn": "^7.0.0", - "acorn-walk": "^7.0.0", - "xtend": "^4.0.2" - } - }, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4.0" + "@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/after": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", - "integrity": "sha512-QbJ0NTQ/I9DI3uSJA4cbexiwQeRAfjPScqIbSjUDd9TOrcg6pTkdgziesOqxBMBzit8vFCTwrP27t13vFOORRA==", - "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/@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": ">= 14" + "node": ">= 4" } }, - "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/@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": { - "clean-stack": "^2.0.0", - "indent-string": "^4.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": ">=8" - } - }, - "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" + "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": { + "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/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": { + "@typescript-eslint/tsconfig-utils": "^8.58.0", + "@typescript-eslint/types": "^8.58.0", + "debug": "^4.4.3" + }, "engines": { - "node": ">=6" + "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/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/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": "MIT", "dependencies": { - "environment": "^1.0.0" + "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/visitor-keys": "8.58.0" }, "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "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": ">=12" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "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/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": { - "color-convert": "^2.0.1" + "@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": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "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==", - "dev": true, - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" }, - "engines": { - "node": ">= 8" + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "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/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": ">=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" } }, - "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/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": { - "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/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/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/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/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/node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", "dev": true, "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, "engines": { - "node": ">=0.10.0" + "node": "18 || 20 || >=22" } }, - "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/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": { + "brace-expansion": "^5.0.5" + }, "engines": { - "node": ">=0.10.0" + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "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/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": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" + "@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": "^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/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/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": { - "object.assign": "^4.1.4", - "util": "^0.10.4" - } - }, - "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==", - "dev": true, - "license": "MIT", + "@typescript-eslint/types": "8.58.0", + "eslint-visitor-keys": "^5.0.0" + }, "engines": { - "node": "*" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "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/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": ">=0.10.0" + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/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/@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", - "engines": { - "node": ">=8" - } - }, - "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" + "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" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/browser": "4.1.2", + "vitest": "4.1.2" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } + } }, - "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/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 OR Apache-2.0)", - "bin": { - "atob": "bin/atob.js" + "license": "MIT", + "dependencies": { + "@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" }, - "engines": { - "node": ">= 4.5.0" + "funding": { + "url": "https://opencollective.com/vitest" } }, - "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/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": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" + "@vitest/spy": "4.1.2", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "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/backo2": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", - "integrity": "sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA==", + "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" + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } }, - "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==", + "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" + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } }, - "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/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, "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" + "tinyrainbow": "^3.1.0" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "url": "https://opencollective.com/vitest" } }, - "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/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, "license": "MIT", "dependencies": { - "is-descriptor": "^1.0.0" + "@vitest/utils": "4.1.2", + "pathe": "^2.0.3" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "url": "https://opencollective.com/vitest" } }, - "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/snapshot": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.2.tgz", + "integrity": "sha512-g7yfUmxYS4mNxk31qbOYsSt2F4m1E02LFqO53Xpzg3zKMhLAPZAjjfyl9e6z7HrW6LvUdTwAQR3HHfLjpko16A==", "dev": true, "license": "MIT", "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" + "@vitest/pretty-format": "4.1.2", + "@vitest/utils": "4.1.2", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" }, - "engines": { - "node": ">= 0.4" + "funding": { + "url": "https://opencollective.com/vitest" } }, - "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/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, - "engines": { - "node": ">= 0.6.0" + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" } }, - "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/spy": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.2.tgz", + "integrity": "sha512-DU4fBnbVCJGNBwVA6xSToNXrkZNSiw59H8tcuUspVMsBDBST4nfvsPsEHDHGtWRRnqBERBQu7TrTKskmjqTXKA==", "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", + "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/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", - "engines": { - "node": "^4.5.0 || >= 5.9" + "dependencies": { + "@vitest/pretty-format": "4.1.2", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" + }, + "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/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": "Apache-2.0" + "license": "MIT" }, - "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/@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", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "dependencies": { + "@volar/source-map": "1.11.1" } }, - "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/@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", - "optional": true, "dependencies": { - "file-uri-to-path": "1.0.0" + "muggle-string": "^0.3.1" } }, - "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/@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" + "license": "MIT", + "dependencies": { + "@volar/language-core": "1.11.1", + "path-browserify": "^1.0.1" + } }, - "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/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/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/@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", "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" + "@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/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/@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": { - "ms": "2.0.0" + "@vue/compiler-core": "3.5.31", + "@vue/shared": "3.5.31" } }, - "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==", - "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/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" + "license": "MIT", + "dependencies": { + "@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" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } }, - "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/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": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, - "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/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": { - "fill-range": "^7.1.1" + "brace-expansion": "^2.0.2" }, "engines": { - "node": ">=8" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "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": "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/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", - "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" - }, + "peer": true, "bin": { - "browser-pack": "bin/cmd.js" + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.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/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": { - "resolve": "^1.17.0" + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "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/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": "ISC" + "license": "MIT", + "engines": { + "node": ">= 14" + } }, - "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" - }, - "bin": { - "browserify": "bin/cmd.js" + "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": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" }, "engines": { - "node": ">= 0.8" + "node": ">=8" } }, - "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/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": { - "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" + "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/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/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": "MIT", "dependencies": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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/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": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "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/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": { - "bn.js": "^5.2.1", - "randombytes": "^2.1.0", - "safe-buffer": "^5.2.1" + "color-convert": "^2.0.1" }, "engines": { - "node": ">= 0.10" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "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==", + "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/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, - "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/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": "ISC", - "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" - }, + "license": "MIT", "engines": { - "node": ">= 0.10" + "node": ">=12" } }, - "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/ast-v8-to-istanbul": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.0.tgz", + "integrity": "sha512-1fSfIwuDICFA4LKkCzRPO7F0hzFf0B7+Xqrl27ynQaa+Rh0e1Es0v6kWHPott3lU10AyAr7oKHa65OppjLn3Rg==", "dev": true, "license": "MIT", "dependencies": { - "pako": "~1.0.5" + "@jridgewell/trace-mapping": "^0.3.31", + "estree-walker": "^3.0.3", + "js-tokens": "^10.0.0" } }, - "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/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": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4" + "@types/estree": "^1.0.0" } }, - "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/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/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/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "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/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", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "license": "MIT" }, - "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==", + "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": "MIT" + "license": "Apache-2.0" }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "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", - "engines": { - "node": ">= 0.8" - } + "license": "MIT" }, - "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/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": { - "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" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "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==", - "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/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.0", - "es-define-property": "^1.0.0", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.2" + "fill-range": "^7.1.1" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, "node_modules/call-bind-apply-helpers": { @@ -2004,23 +3372,6 @@ "node": ">= 0.4" } }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -2031,34 +3382,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 +3419,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", @@ -2295,32 +3536,6 @@ "@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", @@ -2341,46 +3556,19 @@ "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==", + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "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", + "delayed-stream": "~1.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.8" } }, - "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", @@ -2388,120 +3576,33 @@ "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" - } - }, - "node_modules/connect": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", - "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "finalhandler": "1.1.2", - "parseurl": "~1.3.3", - "utils-merge": "1.0.1" - }, - "engines": { - "node": ">= 0.10.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==", - "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": { @@ -2575,33 +3676,6 @@ "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", @@ -2636,73 +3710,6 @@ } } }, - "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", @@ -2718,33 +3725,6 @@ "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", @@ -2774,30 +3754,48 @@ "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==", + "node_modules/cssstyle": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.6.0.tgz", + "integrity": "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^3.2.0", + "rrweb-cssom": "^0.8.0" + }, + "engines": { + "node": ">=18" + } }, - "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==", + "node_modules/cssstyle/node_modules/rrweb-cssom": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", + "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", "dev": true, - "license": "Apache-2.0" + "license": "MIT" }, - "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==", + "node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", "dev": true, "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, "engines": { - "node": ">=4.0" + "node": ">=18" } }, + "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" + }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -2816,38 +3814,12 @@ } } }, - "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==", + "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", - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=6" - } + "license": "MIT" }, "node_modules/deep-extend": { "version": "0.6.0", @@ -2866,215 +3838,27 @@ "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "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", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "JSONStream": "^1.0.3", - "shasum-object": "^1.0.0", - "subarg": "^1.0.0", - "through2": "^2.0.0" - }, - "bin": { - "deps-sort": "bin/cmd.js" - } - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/detective": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.1.tgz", - "integrity": "sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==", - "dev": true, - "license": "MIT", - "dependencies": { - "acorn-node": "^1.8.2", - "defined": "^1.0.0", - "minimist": "^1.2.6" - }, - "bin": { - "detective": "bin/detective.js" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/di": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", - "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.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==", - "dev": true, - "license": "MIT" - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/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==", + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true, "license": "MIT", - "dependencies": { - "custom-event": "~1.0.0", - "ent": "~2.2.0", - "extend": "^3.0.0", - "void-elements": "^2.0.0" + "engines": { + "node": ">=0.4.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==", + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, "engines": { - "node": ">=0.4", - "npm": ">=1.2" + "node": ">=8" } }, "node_modules/dot-prop": { @@ -3115,36 +3899,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 +3913,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": { @@ -3490,6 +4137,13 @@ "node": ">= 0.4" } }, + "node_modules/es-module-lexer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", + "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", + "dev": true, + "license": "MIT" + }, "node_modules/es-object-atoms": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", @@ -3503,6 +4157,64 @@ "node": ">= 0.4" } }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -3513,13 +4225,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 +4239,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://opencollective.com/eslint" + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "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 +4312,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 +4530,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,20 +4543,10 @@ "node": ">=4.0" } }, - "node_modules/esrecurse/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/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "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": { @@ -3790,34 +4570,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 +4594,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 +4649,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,26 +4684,18 @@ } }, "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==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "license": "MIT", "dependencies": { - "flat-cache": "^3.0.4" + "flat-cache": "^4.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16.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", @@ -4082,55 +4709,6 @@ "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/find-up": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", @@ -4175,18 +4753,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,64 +4773,21 @@ "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==", + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", "dev": true, "license": "MIT", "dependencies": { - "map-cache": "^0.2.2" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" }, "engines": { - "node": ">=0.10.0" + "node": ">= 6" } }, "node_modules/from2": { @@ -4282,13 +4816,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 +4854,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,16 +4864,6 @@ "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", @@ -4413,16 +4916,6 @@ "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", @@ -4438,52 +4931,14 @@ "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==", + "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": { - "type-fest": "^0.20.2" - }, "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -4509,16 +4964,6 @@ "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", @@ -4541,61 +4986,14 @@ "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" + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" } }, "node_modules/has-symbols": { @@ -4627,107 +5025,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "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==", - "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" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.4", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -4741,16 +5038,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 +5048,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 +5074,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": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", "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" + "whatwg-encoding": "^3.1.1" }, "engines": { - "node": ">= 0.8" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "node": ">=18" } }, - "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 +5108,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", @@ -4901,43 +5133,22 @@ } }, "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==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "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 +5186,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 +5240,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 +5254,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==", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "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/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", - "bin": { - "is-docker": "cli.js" + "dependencies": { + "from2": "^2.3.0", + "p-is-promise": "^3.0.0" }, "engines": { - "node": ">=8" + "node": ">=12" }, "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==", + "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-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.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-extglob": { @@ -5275,13 +5327,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 +5360,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 +5380,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 +5393,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 +5400,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 +5407,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 +5424,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 +5473,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 +5488,131 @@ "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" + "node_modules/jsdom": { + "version": "24.1.3", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-24.1.3.tgz", + "integrity": "sha512-MyL55p3Ut3cXbeBEG7Hcv0mVM8pp8PBNWxRqchZnSfAiES1v1mRnMeFfaHWIPULpwsYfvO+ZmMZz5tGCnjzDUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssstyle": "^4.0.1", + "data-urls": "^5.0.0", + "decimal.js": "^10.4.3", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.5", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.12", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.7.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.4", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/jsonify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz", - "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==", - "dev": true, - "license": "Public Domain", - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^2.11.2" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } } }, - "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/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", "dev": true, - "license": "(MIT OR Apache-2.0)", - "dependencies": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - }, - "bin": { - "JSONStream": "bin.js" - }, + "license": "BSD-2-Clause", "engines": { - "node": "*" + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?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/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", "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" + "entities": "^6.0.0" }, - "bin": { - "karma": "bin/karma" - }, - "engines": { - "node": ">= 10" + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=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 +5625,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 +5725,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 +5755,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 +5762,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 +5769,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 +5822,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 +5844,6 @@ "integrity": "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==", "dev": true, "license": "MIT", - "peer": true, "bin": { "marked": "bin/marked.js" }, @@ -6034,321 +5889,97 @@ "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-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "dev": true, "license": "MIT", - "dependencies": { - "is-plain-object": "^2.0.4" - }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" } }, - "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/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": ">=8.6" } }, - "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==", + "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", - "dependencies": { - "ms": "2.0.0" + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "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/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.8.0" + "node": ">= 0.6" } }, - "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", + "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": "ISC", + "license": "MIT", "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" + "mime-db": "1.52.0" }, "engines": { - "node": "*" + "node": ">= 0.6" } }, - "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 +5989,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 +6006,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 +6025,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 +6051,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 +6096,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 +8092,6 @@ "dev": true, "inBundle": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -8681,179 +8181,76 @@ "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/npm/node_modules/walk-up-path": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/npm/node_modules/which": { - "version": "6.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/write-file-atomic": { - "version": "7.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4", - "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==", + "node_modules/npm/node_modules/walk-up-path": { + "version": "4.0.0", "dev": true, - "license": "MIT", + "inBundle": true, + "license": "ISC", "engines": { - "node": ">= 0.4" + "node": "20 || >=22" } }, - "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==", + "node_modules/npm/node_modules/which": { + "version": "6.0.0", "dev": true, - "license": "MIT", + "inBundle": true, + "license": "ISC", "dependencies": { - "isobject": "^3.0.0" + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" }, "engines": { - "node": ">=0.10.0" + "node": "^20.17.0 || >=22.9.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==", + "node_modules/npm/node_modules/write-file-atomic": { + "version": "7.0.0", "dev": true, - "license": "MIT", + "inBundle": true, + "license": "ISC", "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" + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^20.17.0 || >=22.9.0" } }, - "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==", + "node_modules/npm/node_modules/yallist": { + "version": "4.0.0", "dev": true, - "license": "MIT", - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } + "inBundle": true, + "license": "ISC" }, - "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/nwsapi": { + "version": "2.2.23", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.23.tgz", + "integrity": "sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==", + "dev": true, + "license": "MIT" + }, + "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 +8286,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 +8413,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 +8426,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 +8482,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 +8492,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 +8509,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 +8519,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,24 +8570,33 @@ "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==", + "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", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, "engines": { - "node": ">= 0.4" + "node": "^10 || ^12 || >=14" } }, "node_modules/prelude-ls": { @@ -9386,17 +8610,16 @@ } }, "node_modules/prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "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", - "peer": true, "bin": { - "prettier": "bin-prettier.js" + "prettier": "bin/prettier.cjs" }, "engines": { - "node": ">=10.13.0" + "node": ">=14" }, "funding": { "url": "https://github.com/prettier/prettier?sponsor=1" @@ -9410,171 +8633,70 @@ "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==", - "dev": true, - "license": "MIT", + }, "engines": { - "node": ">=0.9" + "node": ">=6.0.0" } }, - "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==", + "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": "BSD-3-Clause", + "license": "MIT", "dependencies": { - "side-channel": "^1.1.0" + "parse-ms": "^4.0.0" }, "engines": { - "node": ">=0.6" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "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, - "engines": { - "node": ">=0.4.x" - } + "license": "MIT" }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "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": "MIT", - "dependencies": { - "safe-buffer": "^5.1.0" - } + "license": "ISC" }, - "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/psl": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", + "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", "dev": true, "license": "MIT", "dependencies": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" + "punycode": "^2.3.1" + }, + "funding": { + "url": "https://github.com/sponsors/lupomontero" } }, - "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/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/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/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", "dev": true, - "license": "MIT", - "dependencies": { - "bytes": "~3.1.2", - "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } + "license": "MIT" }, "node_modules/rc": { "version": "1.2.8", @@ -9602,16 +8724,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 +8954,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,276 +8967,103 @@ "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", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "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.", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, "license": "MIT", - "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" + "engines": { + "node": ">=0.10.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/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/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==", + "node_modules/rrweb-cssom": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", + "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==", "dev": true, "license": "MIT" }, @@ -10227,48 +9074,32 @@ "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==", + "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", - "dependencies": { - "ret": "~0.1.10" - } + "license": "MIT" }, - "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 +11829,6 @@ "dev": true, "inBundle": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -13411,375 +12241,101 @@ "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" + "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-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-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-type-adaptors": "^1.0.1" + "license": "ISC", + "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/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", - "dependencies": { - "should-type": "^1.3.0", - "should-util": "^1.0.0" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, - "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==", - "dev": true, - "license": "MIT" - }, - "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", @@ -13880,313 +12436,30 @@ "node": ">=4" } }, - "node_modules/signale/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "license": "MIT", - "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)", + "node_modules/signale/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "license": "MIT", "dependencies": { - "ms": "^2.1.1" + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" } }, - "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" - }, - "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 +12472,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 +12525,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 +12542,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 +12567,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 +12577,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 +12658,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 +12719,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 +12810,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 +12833,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 +12860,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,108 +12894,14 @@ "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==", + "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", - "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": ">=14.0.0" } }, "node_modules/to-regex-range": { @@ -14946,69 +12917,43 @@ "node": ">=8.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==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "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/tough-cookie": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" }, "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "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/node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", "dev": true, "license": "MIT", - "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" - }, "engines": { - "node": ">= 0.4" + "node": ">= 4.0.0" } }, - "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": "5.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", + "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", "dev": true, "license": "MIT", "dependencies": { - "is-plain-object": "^2.0.4" + "punycode": "^2.3.1" }, "engines": { - "node": ">=0.10.0" - } - }, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6" + "node": ">=18" } }, "node_modules/traverse": { @@ -15024,12 +12969,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 +13005,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 +13033,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 +13044,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 +13073,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 +13106,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", @@ -15337,38 +13116,6 @@ "punycode": "^2.1.0" } }, - "node_modules/uri-js/node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/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,24 +13126,15 @@ "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==", + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", "dev": true, "license": "MIT", "dependencies": { - "inherits": "2.0.3" + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" } }, "node_modules/util-deprecate": { @@ -15406,30 +13144,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 +13155,328 @@ "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": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "typescript": "*", + "vite": "*" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } } }, - "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==", + "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": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" + "@jridgewell/sourcemap-codec": "^1.5.5" } }, - "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" + "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": ">= 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" + "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/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/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-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==", + "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": { - "binary-extensions": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" + "de-indent": "^1.0.2", + "he": "^1.2.0" } }, - "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/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": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" + "bin": { + "he": "bin/he" } }, - "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-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-plain-object": "^2.0.4" + "@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/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/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": { - "kind-of": "^3.0.2" + "xml-name-validator": "^5.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=18" } }, - "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/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": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } + "license": "Apache-2.0" }, - "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/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", "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" - }, + "license": "BSD-2-Clause", "engines": { - "node": ">=0.10.0" + "node": ">=12" } }, - "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/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", "dev": true, "license": "MIT", "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "iconv-lite": "0.6.3" }, "engines": { - "node": ">=0.10.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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" + "node": ">=18" } }, - "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": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", "dev": true, "license": "MIT", - "dependencies": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - }, "engines": { - "node": ">=0.10" + "node": ">=18" } }, - "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": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", "dev": true, "license": "MIT", "dependencies": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" + "tr46": "^5.1.0", + "webidl-conversions": "^7.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=18" } }, - "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 +13493,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,40 +13527,18 @@ "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==", + "version": "8.20.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz", + "integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==", "dev": true, "license": "MIT", "engines": { - "node": ">=8.3.0" + "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -15887,15 +13549,23 @@ } } }, - "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/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": "Apache-2.0", "engines": { - "node": ">=0.4.0" + "node": ">=18" } }, + "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, + "license": "MIT" + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -15906,144 +13576,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/kits/rokt/package.json b/kits/rokt/package.json index 0c4d82957..3ca574976 100644 --- a/kits/rokt/package.json +++ b/kits/rokt/package.json @@ -1,22 +1,38 @@ { "name": "@mparticle/web-rokt-kit", - "version": "1.16.0", + "version": "1.26.1", "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", + "repository": { + "type": "git", + "url": "https://github.com/mParticle/mparticle-web-sdk.git", + "directory": "kits/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:core-types": "npm --prefix ../.. run build:types", + "prebuild": "npm run build:core-types", + "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,33 +40,30 @@ "registry": "https://registry.npmjs.org" }, "devDependencies": { - "@rollup/plugin-json": "^6.1.0", + "@eslint/js": "^9.23.0", + "@eslint/eslintrc": "^3.3.1", + "@mparticle/event-models": "^1.1.9", "@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": "^24.1.3", + "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" + "@mparticle/web-sdk": "^2.62.0" }, "license": "Apache-2.0" } diff --git a/kits/rokt/release.config.js b/kits/rokt/release.config.js new file mode 100644 index 000000000..3638e2c69 --- /dev/null +++ b/kits/rokt/release.config.js @@ -0,0 +1,65 @@ +module.exports = { + branches: ['main'], + tagFormat: 'v${version}', + repositoryUrl: + 'https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt', + plugins: [ + [ + '@semantic-release/commit-analyzer', + { + preset: 'angular', + releaseRules: [ + { type: 'feat', release: 'minor' }, + { type: 'ci', release: 'patch' }, + { type: 'fix', release: 'patch' }, + { type: 'docs', release: 'patch' }, + { type: 'test', release: 'patch' }, + { type: 'refactor', release: 'patch' }, + { type: 'style', release: 'patch' }, + { type: 'build', release: 'patch' }, + { type: 'chore', release: 'patch' }, + { type: 'revert', release: 'patch' }, + ], + }, + ], + [ + '@semantic-release/release-notes-generator', + { + preset: 'angular', + }, + ], + [ + '@semantic-release/changelog', + { + changelogFile: 'CHANGELOG.md', + }, + ], + [ + '@semantic-release/npm', + { + npmPublish: false, // Disable npm publish here; we use exec with OIDC instead + }, + ], + [ + '@semantic-release/exec', + { + prepareCmd: 'sh ./scripts/release.sh', + publishCmd: 'npm publish', + }, + ], + [ + '@semantic-release/github', + { + assets: ['dist/Rokt-Kit.common.js', 'dist/Rokt-Kit.iife.js'], + }, + ], + [ + '@semantic-release/git', + { + assets: ['package.json', 'package-lock.json', 'CHANGELOG.md'], + message: + 'chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}', + }, + ], + ], +}; diff --git a/kits/rokt/rollup.config.js b/kits/rokt/rollup.config.js deleted file mode 100644 index 25c25164c..000000000 --- a/kits/rokt/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, - }, -]; diff --git a/kits/rokt/rollup.test.config.js b/kits/rokt/rollup.test.config.js deleted file mode 100644 index cd86478ca..000000000 --- a/kits/rokt/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/kits/rokt/scripts/release.sh b/kits/rokt/scripts/release.sh new file mode 100644 index 000000000..4111e663b --- /dev/null +++ b/kits/rokt/scripts/release.sh @@ -0,0 +1,3 @@ +npm run build +git add dist -f +git commit -m 'chore(build): Generate latest bundle [skip ci]' \ No newline at end of file diff --git a/kits/rokt/src/Rokt-Kit.js b/kits/rokt/src/Rokt-Kit.js deleted file mode 100644 index 704b3521e..000000000 --- a/kits/rokt/src/Rokt-Kit.js +++ /dev/null @@ -1,780 +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.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; - - if (testMode) { - self.testHelpers = { - generateLauncherScript: generateLauncherScript, - extractRoktExtensions: extractRoktExtensions, - hashEventMessage: hashEventMessage, - parseSettingsString: parseSettingsString, - generateMappedEventLookup: generateMappedEventLookup, - generateMappedEventAttributeLookup: generateMappedEventAttributeLookup, - }; - 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, - }); - - // Log custom event for selectPlacements call - logSelectPlacementsEvent(selectPlacementsAttributes); - - return self.launcher.selectPlacements(selectPlacementsOptions); - } - - /** - * 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; - } - - 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 onUserIdentified(filteredUser) { - self.filters.filteredUser = filteredUser; - self.userAttributes = filteredUser.getAllUserAttributes(); - } - - function setUserAttribute(key, value) { - self.userAttributes[key] = value; - } - - function removeUserAttribute(key) { - delete self.userAttributes[key]; - } - - function attachLauncher(accountId, launcherOptions) { - var options = mergeObjects( - { - accountId: accountId, - }, - launcherOptions || {} - ); - - 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; - // 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.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 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'; -} - -if (window && window.mParticle && window.mParticle.addForwarder) { - window.mParticle.addForwarder({ - name: name, - constructor: constructor, - getId: getId, - }); -} - -module.exports = { - register: register, -}; diff --git a/kits/rokt/src/Rokt-Kit.ts b/kits/rokt/src/Rokt-Kit.ts new file mode 100644 index 000000000..64a462d6a --- /dev/null +++ b/kits/rokt/src/Rokt-Kit.ts @@ -0,0 +1,1498 @@ +// 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 +// ============================================================ + +import type { + IIdentitySearchResult, + RoktAttributes, + RoktSelection, + SDKIdentityApi, + UserIdentities, +} from '@mparticle/web-sdk'; +import type { Batch, KitInterface, IMParticleUser, SDKEvent } from '@mparticle/web-sdk/internal'; + +// BaseEvent not re-exported from @mparticle/web-sdk/internal, so we import directly from @mparticle/event-models. +import { BaseEvent } from '@mparticle/event-models'; + +interface RoktKitSettings { + accountId: string; + roktExtensions?: string; + placementEventMapping?: string; + placementEventAttributeMapping?: string; + hashedEmailUserIdentityType?: string; + onboardingExpProvider?: string; + loggingUrl?: string; + errorUrl?: string; + isLoggingEnabled?: string | boolean; + workspaceIdSyncApiKey?: string; +} + +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 RoktLauncher { + selectPlacements(options: Record): RoktSelection | Promise; + hashAttributes(attributes: RoktAttributes): Promise>; + use(extensionName: string): Promise; +} + +interface RoktGlobal { + createLauncher(options: Record): Promise; + createLocalLauncher(options: Record): RoktLauncher; + currentLauncher?: RoktLauncher; + __batch_stream__?(batch: Batch): void; + setExtensionData(data: Record): void; +} + +// FilteredUser is the IMParticleUser shape we receive after kit filtering. +// `getMPID` and `getUserIdentities` are inherited from the SDK's `User` base type. +type FilteredUser = IMParticleUser; + +interface KitFilters { + userAttributeFilters?: string[]; + filterUserAttributes?: (attributes: Record, filters?: string[]) => Record; + filteredUser?: FilteredUser | null; +} + +interface RoktManager { + attachKit(kit: RoktKit): void | Promise; + flushOnShoppableAdsReadyMessageQueue?(kit: RoktKit): void; + 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; + Identity?: Pick; +} + +interface TestHelpers { + generateLauncherScript: (domain: string | undefined, extensions: string[]) => string; + generateThankYouElementScript: (domain: string | undefined) => string; + extractRoktExtensionConfig: (settingsString?: string) => RoktExtensionConfig; + 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 ReportingConfig { + loggingUrl?: string; + errorUrl?: string; + isLoggingEnabled?: boolean | string; +} + +interface ErrorReport { + message: string; + code?: string; + severity?: string; + stackTrace?: string; +} + +interface LogEntry { + message: string; + code?: string; +} + +interface RoktExtensionConfig { + roktExtensionsQueryParams: string[]; + legacyRoktExtensions: string[]; + loadThankYouElement: boolean; +} + +declare global { + interface Window { + Rokt?: RoktGlobal; + __rokt_li_guid__?: string; + optimizely?: OptimizelyGlobal; + ROKT_DOMAIN?: string; + } +} + +// ============================================================ +// 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 ROKT_IDENTITY_EVENT_TYPE = { + LOGIN: 'login', + LOGOUT: 'logout', + MODIFY_USER: 'modify_user', + IDENTIFY: 'identify', +} as const; +const ROKT_THANK_YOU_JOURNEY_EXTENSION = 'ThankYouPageJourney'; +const ROKT_INTEGRATION_SCRIPT_ID = 'rokt-launcher'; +const ROKT_THANK_YOU_ELEMENT_SCRIPT_ID = 'rokt-thank-you-element'; +const USER_IDENTIFIED_IN_WORKSPACE_KEY = 'userIdentifiedInWorkspace'; + +// Bound on how long selectPlacements will wait for an in-flight Workspace +// IDSync search before proceeding without the userIdentifiedInWorkspace flag. +// Long enough to cover the typical /v1/search round-trip (~50ms); short enough that a +// stalled search never blocks placement rendering on a thank-you page. +const WORKSPACE_SEARCH_SELECT_TIMEOUT_MS = 500; + +type RoktIdentityEventType = (typeof ROKT_IDENTITY_EVENT_TYPE)[keyof typeof ROKT_IDENTITY_EVENT_TYPE]; + +// ============================================================ +// 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 launcherPath = '/wsdk/integrations/launcher.js'; + const baseUrl = [generateBaseUrl(domain), launcherPath].join(''); + + if (!extensions || extensions.length === 0) { + return baseUrl; + } + return baseUrl + '?extensions=' + extensions.join(','); +} + +function generateThankYouElementScript(domain: string | undefined) { + const thankYouElementPath = '/rokt-elements/rokt-element-thank-you.js'; + return [generateBaseUrl(domain), thankYouElementPath].join(''); +} + +function generateBaseUrl(domain: string | undefined) { + const resolvedDomain = typeof domain !== 'undefined' ? domain : 'apps.rokt-api.com'; + const protocol = 'https://'; + + return [protocol, resolvedDomain].join(''); +} + +function loadRoktScript( + scriptId: string, + source: string, + handlers?: { onLoad?: () => void; onError?: (e: Event | string) => void }, +): void { + if (document.getElementById(scriptId)) return; // resolves the preexisting script issue + + const target = document.head || document.body; + const script = document.createElement('script'); + script.id = scriptId; + script.type = 'text/javascript'; + script.src = source; + script.async = true; + script.crossOrigin = 'anonymous'; + (script as HTMLScriptElement & { fetchPriority: string }).fetchPriority = 'high'; + if (handlers?.onLoad) script.onload = handlers.onLoad; + if (handlers?.onError) script.onerror = handlers.onError; + target.appendChild(script); +} + +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 extractRoktExtensionConfig(settingsString?: string): RoktExtensionConfig { + const settings = settingsString ? parseSettingsString(settingsString) : []; + const roktExtensionsQueryParams: string[] = []; + const legacyRoktExtensions: string[] = []; + let loadThankYouElement = false; + + for (let i = 0; i < settings.length; i++) { + const extensionName = settings[i].value; + if (extensionName === 'thank-you-journey') { + loadThankYouElement = true; + legacyRoktExtensions.push(ROKT_THANK_YOU_JOURNEY_EXTENSION); + } else { + roktExtensionsQueryParams.push(extensionName); + } + } + + return { + roktExtensionsQueryParams, + legacyRoktExtensions, + loadThankYouElement, + }; +} + +async function registerLegacyExtensions(legacyExtensions: string[], launcher: RoktLauncher | null) { + const extensions: Promise[] = []; + if (launcher) { + for (const extension of legacyExtensions) { + extensions.push(launcher.use(extension)); + } + } + + return Promise.all(extensions); +} + +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 implements KitInterface { + // 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 id = moduleId; + public moduleId = moduleId; + public isInitialized = false; + public launcher: RoktLauncher | null = null; + public filters: KitFilters = {}; + public userAttributes: Record = {}; + // Flag set by the Workspace IDSync flow on a 200 response. Stored on the + // kit instance and merged into placement attributes inside selectPlacements. + public userIdentifiedInWorkspace = false; + public testHelpers: TestHelpers | null = null; + public placementEventMappingLookup: Record = {}; + public placementEventAttributeMappingLookup: Record = {}; + public batchQueue: Batch[] = []; + public batchStreamQueue: Batch[] = []; + public pendingIdentityEvents: BaseEvent[] = []; + 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 _thankYouElementOnLoadCallback: (() => void) | null = null; + private _isThankYouElementLoaded = false; + private _workspaceIdSyncApiKey?: string; + + // Held during a search dispatch so the next selectPlacements call; + // can wait for the HTTP response before reading userIdentifiedInWorkspace; + // — otherwise the first placement call ships without the flag. + private _workspaceSearchInFlightPromise: Promise | null = null; + // Stable serialization of the identifier set sent in the most recent + // successful search dispatch. If a subsequent identification arrives with + // an identical set, we skip the network call (the flag is still correct + // from the prior search). Keyed over the full UserIdentities map — not + // just email — so partners passing hashed email through `other`/`other2-10` + // or any other identifier benefit from the same dedupe. Cleared on logout + // so a re-login re-evaluates fresh. + private _workspaceLastSearchedIdentitiesKey?: string; + + // ---- Private helpers ---- + + private getEventAttributeValue(event: SDKEvent, 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: SDKEvent, 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: SDKEvent): 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: 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: UserIdentities): Record { + const newUserIdentities: Record = {}; + for (const identityKey of Object.keys(userIdentities || {}) as Array) { + const identityValue = userIdentities[identityKey]; + if (isString(identityValue)) { + newUserIdentities[identityKey] = identityValue; + } + } + + const key = this._mappedEmailSha256Key; + if (key && userIdentities[key as keyof UserIdentities]) { + newUserIdentities[RoktKit.EMAIL_SHA256_KEY] = userIdentities[key as keyof UserIdentities] as string; + } + 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 buildIdentityEvent(eventType: RoktIdentityEventType, filteredUser: FilteredUser): BaseEvent { + const mpid = filteredUser.getMPID(); + const sessionUuid = + mp() && mp().sessionManager && typeof mp().sessionManager!.getSession === 'function' + ? mp().sessionManager!.getSession() + : undefined; + + return { + event_type: eventType, + data: { + timestamp_unixtime_ms: Date.now(), + session_uuid: sessionUuid ?? undefined, + mpid, + }, + } as unknown as BaseEvent; + } + + private mergePendingIdentityEvents(batch: Batch): Batch { + if (this.pendingIdentityEvents.length === 0) { + return batch; + } + const merged: Batch = { + ...batch, + events: [...(batch.events ?? []), ...this.pendingIdentityEvents], + }; + this.pendingIdentityEvents = []; + return merged; + } + + private drainBatchQueue(): void { + this.batchQueue.forEach((batch) => { + this.processBatch(batch); + }); + this.batchQueue = []; + } + + public processBatch(batch: Batch): string { + if (!this.isKitReady()) { + this.batchQueue.push(batch); + return 'Batch queued for forwarder: ' + name; + } + this.sendBatchStream(this.mergePendingIdentityEvents(batch)); + return 'Successfully sent batch to forwarder: ' + name; + } + + private sendBatchStream(batch: Batch): void { + if (window.Rokt && typeof window.Rokt.__batch_stream__ === 'function') { + if (this.batchStreamQueue.length) { + const queuedBatches = this.batchStreamQueue; + this.batchStreamQueue = []; + for (let i = 0; i < queuedBatches.length; i++) { + window.Rokt.__batch_stream__(queuedBatches[i]); + } + } + window.Rokt.__batch_stream__(batch); + } else { + this.batchStreamQueue.push(batch); + } + } + + 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 attachLauncher( + accountId: string, + launcherOptions: Record, + legacyRoktExtensions: string[] = [], + ): void { + const mpSessionId = + mp() && mp().sessionManager && typeof mp().sessionManager!.getSession === 'function' + ? mp().sessionManager!.getSession() + : undefined; + + const options: Record = { + accountId, + ...(launcherOptions || {}), + ...(mpSessionId ? { mpSessionId } : {}), + }; + + let launcherPromise: Promise; + if (this.isPartnerInLocalLauncherTestGroup()) { + launcherPromise = Promise.resolve(window.Rokt!.createLocalLauncher(options)); + } else { + launcherPromise = window.Rokt!.createLauncher(options); + } + + launcherPromise + .then(async (launcher) => { + await registerLegacyExtensions(legacyRoktExtensions, 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.'); + } else { + this._workspaceSearchInFlightPromise = this.search(roktFilters.filteredUser); + } + } + + // 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.drainBatchQueue(); + } + + 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: Record, + _service: unknown, + testMode: boolean, + _trackerId: unknown, + filteredUserAttributes?: Record, + ): string { + const kitSettings = settings as unknown as RoktKitSettings; + const accountId = kitSettings.accountId; + this.userAttributes = filteredUserAttributes || {}; + this._onboardingExpProvider = kitSettings.onboardingExpProvider; + + const placementEventMapping = parseSettingsString(kitSettings.placementEventMapping); + this.placementEventMappingLookup = generateMappedEventLookup(placementEventMapping); + + const placementEventAttributeMapping = parseSettingsString( + kitSettings.placementEventAttributeMapping, + ); + this.placementEventAttributeMappingLookup = generateMappedEventAttributeLookup(placementEventAttributeMapping); + + // Set dynamic OTHER_IDENTITY based on server settings + if (kitSettings.hashedEmailUserIdentityType) { + this._mappedEmailSha256Key = kitSettings.hashedEmailUserIdentityType.toLowerCase(); + } + + this._workspaceIdSyncApiKey = isString(kitSettings.workspaceIdSyncApiKey) + ? kitSettings.workspaceIdSyncApiKey + : undefined; + + const domain = mp().Rokt?.domain; + const { roktExtensionsQueryParams, legacyRoktExtensions, loadThankYouElement } = extractRoktExtensionConfig( + kitSettings.roktExtensions, + ); + 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: kitSettings.loggingUrl, + errorUrl: kitSettings.errorUrl, + isLoggingEnabled: kitSettings.isLoggingEnabled === 'true' || kitSettings.isLoggingEnabled === true, + }; + const errorReportingService = new ErrorReportingService( + reportingConfig, + this.integrationName, + window.__rokt_li_guid__, + kitSettings.accountId, + ); + const loggingService = new LoggingService( + reportingConfig, + errorReportingService, + this.integrationName, + window.__rokt_li_guid__, + kitSettings.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, + generateThankYouElementScript: generateThankYouElementScript, + extractRoktExtensionConfig: extractRoktExtensionConfig, + 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 'Successfully initialized: ' + name; + } + + if (loadThankYouElement) { + mp().Rokt.flushOnShoppableAdsReadyMessageQueue?.(this); + loadRoktScript(ROKT_THANK_YOU_ELEMENT_SCRIPT_ID, generateThankYouElementScript(domain), { + onLoad: () => { + this._isThankYouElementLoaded = true; + if (this._thankYouElementOnLoadCallback) { + this._thankYouElementOnLoadCallback(); + } + }, + onError: (error) => { + console.error('Error loading Rokt Thank You Element script:', error); + }, + }); + } + + if (this.isLauncherReadyToAttach()) { + this.attachLauncher(accountId, launcherOptions, legacyRoktExtensions); + } else { + loadRoktScript(ROKT_INTEGRATION_SCRIPT_ID, generateLauncherScript(domain, roktExtensionsQueryParams), { + onLoad: () => { + if (this.isLauncherReadyToAttach()) { + this.attachLauncher(accountId, launcherOptions, legacyRoktExtensions); + } else { + console.error('Rokt object is not available after script load.'); + } + }, + onError: (error) => { + console.error('Error loading Rokt launcher script:', error); + }, + }); + + this.captureTiming(RoktKit.PERFORMANCE_MARKS.RoktScriptAppended); + } + + return 'Successfully initialized: ' + name; + } + + public process(event: SDKEvent): string { + if (!this.isKitReady()) { + return 'Kit not ready for forwarder: ' + name; + } + if (typeof mp().Rokt?.setLocalSessionAttribute === 'function') { + if (!isEmpty(this.placementEventAttributeMappingLookup)) { + this.applyPlacementEventAttributeMapping(event); + } + + if (!isEmpty(this.placementEventMappingLookup)) { + const hashedEvent = hashEventMessage(event.EventDataType, event.EventCategory, event.EventName ?? ''); + if (this.placementEventMappingLookup[String(hashedEvent)]) { + mp().Rokt.setLocalSessionAttribute?.(this.placementEventMappingLookup[String(hashedEvent)], true); + } + } + } + + return 'Successfully sent to forwarder: ' + name; + } + + 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): string { + this.userAttributes[key] = value; + return 'Successfully set user attribute for forwarder: ' + name; + } + + public removeUserAttribute(key: string): string { + delete this.userAttributes[key]; + return 'Successfully removed user attribute for forwarder: ' + name; + } + + private handleIdentityComplete(user: IMParticleUser, eventType: RoktIdentityEventType, callbackName: string): string { + const filteredUser = user as FilteredUser; + this.userAttributes = user.getAllUserAttributes(); + this.pendingIdentityEvents.push(this.buildIdentityEvent(eventType, filteredUser)); + return 'Successfully called ' + callbackName + ' for forwarder: ' + name; + } + + public onUserIdentified(user: IMParticleUser): string { + const filteredUser = user as FilteredUser; + this.filters.filteredUser = filteredUser; + this._workspaceSearchInFlightPromise = this.search(filteredUser); + return this.handleIdentityComplete(user, ROKT_IDENTITY_EVENT_TYPE.IDENTIFY, 'onUserIdentified'); + } + + private search(filteredUser: FilteredUser): Promise { + const apiKey = this._workspaceIdSyncApiKey; + if (!apiKey) { + this.userIdentifiedInWorkspace = false; + this._workspaceLastSearchedIdentitiesKey = undefined; + return Promise.resolve(); + } + const search = mp().Identity?.search; + if (typeof search !== 'function') { + this.userIdentifiedInWorkspace = false; + this._workspaceLastSearchedIdentitiesKey = undefined; + return Promise.resolve(); + } + + const userIdentities: UserIdentities | null = filteredUser.getUserIdentities + ? filteredUser.getUserIdentities().userIdentities + : null; + + // Forward every non-empty string identifier the user has — email, + // customerid, other/other2-10 (commonly used for hashed email), + // mobile_number, facebook, etc. The host SDK's Identity.search accepts + // the full UserIdentities surface and the server validates it. + const knownIdentities: Record = {}; + if (userIdentities) { + for (const key of Object.keys(userIdentities) as Array) { + const value = userIdentities[key]; + if (isString(value) && value.length > 0) { + knownIdentities[key] = value; + } + } + } + + const identityKeys = Object.keys(knownIdentities); + if (identityKeys.length === 0) { + this.userIdentifiedInWorkspace = false; + this._workspaceLastSearchedIdentitiesKey = undefined; + return Promise.resolve(); + } + + // Stable cache key: sort keys so insertion-order differences don't + // cause false misses. The values are partner-supplied strings; no + // hashing needed — equality on this serialization is sufficient. + const identitiesKey = identityKeys + .sort() + .map((k) => `${k}=${knownIdentities[k]}`) + .join('&'); + + // Same identifier set as the last successful dispatch → skip the + // network call. The current flag value still reflects the correct + // match status. + if (identitiesKey === this._workspaceLastSearchedIdentitiesKey) { + return this._workspaceSearchInFlightPromise || Promise.resolve(); + } + + // New / different identifier set → reset and re-search. Cache the key + // up front so a second concurrent invocation with the same set also + // dedupes. + this.userIdentifiedInWorkspace = false; + this._workspaceLastSearchedIdentitiesKey = identitiesKey; + + return new Promise((resolve) => { + try { + search(apiKey, knownIdentities as UserIdentities, (result: IIdentitySearchResult) => { + if (result?.httpCode === 200) { + this.userIdentifiedInWorkspace = true; + } + resolve(); + }); + } catch (err) { + console.error('Rokt Kit: Workspace IDSync search failed', err); + // Dispatch failed — clear the cache so the same identifier set + // can retry on the next identification rather than being stuck + // behind a poisoned entry that short-circuits future searches. + this._workspaceLastSearchedIdentitiesKey = undefined; + resolve(); + } + }); + } + + public onLoginComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string { + return this.handleIdentityComplete(user, ROKT_IDENTITY_EVENT_TYPE.LOGIN, 'onLoginComplete'); + } + + public onLogoutComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string { + // Anonymous sessions must not carry the previous user's match forward. + // Clear the flag explicitly here. Also clear the identities cache so a + // re-login (possibly with the same identifiers) dispatches a fresh + // search rather than reusing a stale answer. + this.userIdentifiedInWorkspace = false; + this._workspaceSearchInFlightPromise = null; + this._workspaceLastSearchedIdentitiesKey = undefined; + return this.handleIdentityComplete(user, ROKT_IDENTITY_EVENT_TYPE.LOGOUT, 'onLogoutComplete'); + } + + public onModifyComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string { + return this.handleIdentityComplete(user, ROKT_IDENTITY_EVENT_TYPE.MODIFY_USER, 'onModifyComplete'); + } + + /** + * Selects placements for Rokt Web SDK with merged attributes, filters, and experimentation options. + * + * If a Workspace IDSync search is in flight from a recent onUserIdentified + * call, this method waits up to `WORKSPACE_SEARCH_SELECT_TIMEOUT_MS` for it + * to settle so the first placement call can include the + * `userIdentifiedInWorkspace` flag without racing the network response. + * The timeout protects against a stalled or slow search blocking placement + * rendering — if it fires, selectPlacements proceeds without the flag. + * + * Implementation note: this method stays non-async deliberately. First, + * the public return type is `RoktSelection | Promise | + * undefined` — a superset of the `RoktSelection | Promise` + * shape declared for `RoktLauncher.selectPlacements` above (line ~70). + * Marking this `async` would narrow it to `Promise` and silently change the contract for callers that read + * the result synchronously. Second, `RoktSelection` has an optional + * `then?` member, so TS treats it as ambiguously promise-like and + * rejects it as the awaited return of an async function (TS1058) — + * working around that would require a cast or wrapping every return in + * `Promise.resolve(...)`. The inner work runs in `_dispatchPlacements`; + * this wrapper just gates it on the in-flight search via `Promise.race`. + */ + public selectPlacements(options: Record): RoktSelection | Promise | undefined { + if (this._workspaceSearchInFlightPromise) { + const inFlight = this._workspaceSearchInFlightPromise; + return Promise.race([ + inFlight, + new Promise((resolve) => setTimeout(resolve, WORKSPACE_SEARCH_SELECT_TIMEOUT_MS)), + ]).then(() => this._dispatchPlacements(options)) as Promise; + } + return this._dispatchPlacements(options); + } + + private _dispatchPlacements(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() : 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, + ...(this.userIdentifiedInWorkspace ? { [USER_IDENTIFIED_IN_WORKSPACE_KEY]: true } : {}), + 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: RoktAttributes): 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. + * + * @deprecated This functionality has been internalized and will be removed in a future release. + */ + 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); + } + + /** + * Registers a callback to be invoked once rokt-thank-you-element.js becomes available. + */ + public onShoppableAdsReady(callback: () => void) { + if (this._isThankYouElementLoaded) { + callback(); + } else { + this._thankYouElementOnLoadCallback = callback; + } + } +} + +// ============================================================ +// 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/kits/rokt/test/.eslintrc b/kits/rokt/test/.eslintrc deleted file mode 100644 index d6808a82f..000000000 --- a/kits/rokt/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/kits/rokt/test/config.js b/kits/rokt/test/config.js deleted file mode 100644 index fdcd7fcae..000000000 --- a/kits/rokt/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/kits/rokt/test/index.html b/kits/rokt/test/index.html deleted file mode 100644 index 182e8c1a4..000000000 --- a/kits/rokt/test/index.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - Mocha Tests - - - -
- - - - - - - - - - - - - - - - diff --git a/kits/rokt/test/karma.config.js b/kits/rokt/test/karma.config.js deleted file mode 100644 index 974b5ee2f..000000000 --- a/kits/rokt/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/kits/rokt/test/lib/mockhttprequest.js b/kits/rokt/test/lib/mockhttprequest.js deleted file mode 100644 index 42f783335..000000000 --- a/kits/rokt/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/kits/rokt/test/src/tests.js b/kits/rokt/test/src/tests.js deleted file mode 100644 index d1bebee51..000000000 --- a/kits/rokt/test/src/tests.js +++ /dev/null @@ -1,4402 +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; - -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', () => { - 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._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.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.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(() => {}); - - 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); - }); - }); - - 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 () => { - await window.mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true, - null, - { - 'cached-user-attr': 'cached-value', - } - ); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: { - 'new-attr': 'new-value', - }, - }); - - 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 () => { - await window.mParticle.forwarder.init( - { - accountId: '123456', - }, - reportService.cb, - true, - null, - { - 'cached-user-attr': 'cached-value', - } - ); - - await window.mParticle.forwarder.selectPlacements({ - identifier: 'test-placement', - attributes: { - 'new-attr': 'new-value', - }, - }); - - 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 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('#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', () => { - it('should set the filtered user', async () => { - window.mParticle.forwarder.onUserIdentified({ - getAllUserAttributes: function () { - return { - 'test-attribute': 'test-value', - }; - }, - getMPID: function () { - return '123'; - }, - }); - - window.mParticle.forwarder.userAttributes.should.deepEqual({ - 'test-attribute': 'test-value', - }); - - window.mParticle.forwarder.filters.filteredUser - .getMPID() - .should.equal('123'); - }); - }); - - 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('#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'); - }); - }); -}); diff --git a/kits/rokt/test/src/tests.spec.ts b/kits/rokt/test/src/tests.spec.ts new file mode 100644 index 000000000..15ae27a71 --- /dev/null +++ b/kits/rokt/test/src/tests.spec.ts @@ -0,0 +1,6635 @@ +import packageJson from '../../package.json'; +const packageVersion = packageJson.version; +import '../../src/Rokt-Kit'; +import { Batch } from '@mparticle/web-sdk/internal'; + +/* 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({ + selectPlacements: function (opts: any) { + self.selectPlacementsOptions = opts; + self.selectPlacementsCalled = true; + }, + hashAttributes: function () { + throw new Error('hashAttributes not implemented'); + }, + use: function () { + return Promise.resolve(); + }, + onShoppableAdsReady: function () {}, + }); + }; + + 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; + (window as any).mParticle.Rokt.flushOnShoppableAdsReadyMessageQueue = () => {}; + }); + + 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 attachKit to complete (fires after the full async launcher chain) + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + 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 attachKit to complete (fires after the full async launcher chain) + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + 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 attachKit to complete (fires after the full async launcher chain) + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + 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 attachKit to complete (fires after the full async launcher chain) + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + 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 attachKit to complete (fires after the full async launcher chain) + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + 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 attachKit to complete (fires after the full async launcher chain) + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + 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 not set emailsha256 when the mapped source identity is null', async () => { + // hashedEmailUserIdentityType points at `other`, but `other` is null — + // the kit must not forward `emailsha256: null` (or any synthesized + // null value) to the placements payload. + (window as any).mParticle.Rokt.filters = { + userAttributeFilters: [], + filterUserAttributes: function () { + return {}; + }, + filteredUser: { + getMPID: function () { + return '234'; + }, + getUserIdentities: function () { + return { + userIdentities: { + customerid: 'customer123', + other: null, + }, + }; + }, + }, + }; + + (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(() => (window as any).mParticle.Rokt.attachKitCalled); + + await (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: {}, + }); + + const attrs = (window as any).Rokt.selectPlacementsOptions.attributes; + expect(attrs).toEqual({ + customerid: 'customer123', + mpid: '234', + }); + expect(attrs).not.toHaveProperty('emailsha256'); + expect(attrs).not.toHaveProperty('other'); + }); + + 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 attachKit to complete (fires after the full async launcher chain) + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + 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 attachKit to complete (fires after the full async launcher chain) + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + 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 attachKit to complete (fires after the full async launcher chain) + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + 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 attachKit to complete (fires after the full async launcher chain) + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + 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 attachKit to complete (fires after the full async launcher chain) + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + 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 attachKit to complete (fires after the full async launcher chain) + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + 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 attachKit to complete (fires after the full async launcher chain) + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + 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 attachKit to complete (fires after the full async launcher chain) + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + 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 attachKit to complete (fires after the full async launcher chain) + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + 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(() => (window as any).mParticle.Rokt.attachKitCalled); + + 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(() => (window as any).mParticle.Rokt.attachKitCalled); + + 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(() => (window as any).mParticle.Rokt.attachKitCalled); + + 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(() => (window as any).mParticle.Rokt.attachKitCalled); + + 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 attachKit to complete (fires after the full async launcher chain) + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + 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 attachKit to complete (fires after the full async launcher chain) + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + 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 attachKit to complete (fires after the full async launcher chain) + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + 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 attachKit to complete (fires after the full async launcher chain) + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + 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 attachKit to complete (fires after the full async launcher chain) + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + 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'; + }, + }; + }); + 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', + }); + }); + }); + + 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', () => { + 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'); + }); + }); + + describe('#workspaceIdSync', () => { + const WORKSPACE_API_KEY = 'workspace-key-abc123'; + + function makeUser(overrides: any = {}) { + return { + getAllUserAttributes: () => ({}), + getMPID: () => '123', + getUserIdentities: () => ({ userIdentities: { email: 'test@example.com' } }), + ...overrides, + }; + } + + let originalIdentity: any; + + beforeEach(() => { + originalIdentity = (window as any).mParticle.Identity; + }); + + afterEach(() => { + (window as any).mParticle.Identity = originalIdentity; + (window as any).mParticle.forwarder.userAttributes = {}; + // The kit's `init()` only runs once per instance in production, so it + // does NOT reset workspace-search state. In tests, multiple cases + // share a single forwarder instance and call init repeatedly, so we + // have to clear search state here to keep tests independent — + // otherwise the identities-cache hit would suppress a search the + // next test expects. + (window as any).mParticle.forwarder.userIdentifiedInWorkspace = false; + (window as any).mParticle.forwarder._workspaceSearchInFlightPromise = null; + (window as any).mParticle.forwarder._workspaceLastSearchedIdentitiesKey = undefined; + }); + + it('should call Identity.search with the configured api key and set userIdentifiedInWorkspace when 200 returned', async () => { + let receivedApiKey: any = null; + let receivedKnownIdentities: any = null; + (window as any).mParticle.Identity = { + search: (apiKey: any, knownIdentities: any, cb: any) => { + receivedApiKey = apiKey; + receivedKnownIdentities = knownIdentities; + cb({ httpCode: 200, body: { mpid: '999' } }); + }, + }; + + await (window as any).mParticle.forwarder.init( + { accountId: '123456', workspaceIdSyncApiKey: WORKSPACE_API_KEY }, + reportService.cb, + true, + null, + {}, + ); + + (window as any).mParticle.forwarder.onUserIdentified(makeUser()); + + expect(receivedApiKey).toBe(WORKSPACE_API_KEY); + expect(receivedKnownIdentities).toEqual({ email: 'test@example.com' }); + expect((window as any).mParticle.forwarder.userIdentifiedInWorkspace).toBe(true); + }); + + it('should search cached filtered user identities when the launcher initializes', async () => { + let receivedApiKey: any = null; + let receivedKnownIdentities: any = null; + let searchCallCount = 0; + (window as any).mParticle.Identity = { + search: (apiKey: any, knownIdentities: any, cb: any) => { + searchCallCount += 1; + receivedApiKey = apiKey; + receivedKnownIdentities = knownIdentities; + cb({ httpCode: 200, body: { mpid: '999' } }); + }, + }; + (window as any).mParticle.Rokt.attachKit = async () => {}; + (window as any).mParticle.Rokt.filters = { + userAttributeFilters: [], + filterUserAttributes: (attributes: any) => attributes, + filteredUser: makeUser(), + }; + + await (window as any).mParticle.forwarder.init( + { accountId: '123456', workspaceIdSyncApiKey: WORKSPACE_API_KEY }, + reportService.cb, + true, + null, + {}, + ); + + await waitForCondition(() => searchCallCount === 1); + + expect(receivedApiKey).toBe(WORKSPACE_API_KEY); + expect(receivedKnownIdentities).toEqual({ email: 'test@example.com' }); + expect((window as any).mParticle.forwarder.userIdentifiedInWorkspace).toBe(true); + }); + + it('should not search cached filtered user identities when workspaceIdSyncApiKey is missing', async () => { + let searchCalled = false; + (window as any).mParticle.Identity = { + search: () => { + searchCalled = true; + }, + }; + (window as any).mParticle.Rokt.attachKit = async () => {}; + (window as any).mParticle.Rokt.filters = { + userAttributeFilters: [], + filterUserAttributes: (attributes: any) => attributes, + filteredUser: makeUser(), + }; + + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + await waitForCondition(() => (window as any).mParticle.forwarder.isInitialized); + + expect(searchCalled).toBe(false); + expect((window as any).mParticle.forwarder.userIdentifiedInWorkspace).toBe(false); + }); + + it('should not search cached filtered user when it has no usable identifiers', async () => { + let searchCalled = false; + (window as any).mParticle.Identity = { + search: () => { + searchCalled = true; + }, + }; + (window as any).mParticle.Rokt.attachKit = async () => {}; + (window as any).mParticle.Rokt.filters = { + userAttributeFilters: [], + filterUserAttributes: (attributes: any) => attributes, + filteredUser: makeUser({ getUserIdentities: () => ({ userIdentities: {} }) }), + }; + + await (window as any).mParticle.forwarder.init( + { accountId: '123456', workspaceIdSyncApiKey: WORKSPACE_API_KEY }, + reportService.cb, + true, + null, + {}, + ); + await waitForCondition(() => (window as any).mParticle.forwarder.isInitialized); + + expect(searchCalled).toBe(false); + expect((window as any).mParticle.forwarder.userIdentifiedInWorkspace).toBe(false); + }); + + it('should not set userIdentifiedInWorkspace when search returns 404', async () => { + (window as any).mParticle.Identity = { + search: (_apiKey: any, _knownIdentities: any, cb: any) => { + cb({ httpCode: 404 }); + }, + }; + + await (window as any).mParticle.forwarder.init( + { accountId: '123456', workspaceIdSyncApiKey: WORKSPACE_API_KEY }, + reportService.cb, + true, + null, + {}, + ); + + (window as any).mParticle.forwarder.onUserIdentified(makeUser()); + + expect((window as any).mParticle.forwarder.userIdentifiedInWorkspace).toBe(false); + }); + + it('should not call search when workspaceIdSyncApiKey is missing', async () => { + let searchCalled = false; + (window as any).mParticle.Identity = { + search: () => { + searchCalled = true; + }, + }; + + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + (window as any).mParticle.forwarder.onUserIdentified(makeUser()); + + expect(searchCalled).toBe(false); + expect((window as any).mParticle.forwarder.userIdentifiedInWorkspace).toBe(false); + }); + + it('should not call search when workspaceIdSyncApiKey is an empty string', async () => { + let searchCalled = false; + (window as any).mParticle.Identity = { + search: () => { + searchCalled = true; + }, + }; + + await (window as any).mParticle.forwarder.init( + { accountId: '123456', workspaceIdSyncApiKey: '' }, + reportService.cb, + true, + null, + {}, + ); + + (window as any).mParticle.forwarder.onUserIdentified(makeUser()); + + expect(searchCalled).toBe(false); + expect((window as any).mParticle.forwarder.userIdentifiedInWorkspace).toBe(false); + }); + + it('should not call search when the user has no usable identifiers', async () => { + let searchCalled = false; + (window as any).mParticle.Identity = { + search: () => { + searchCalled = true; + }, + }; + + await (window as any).mParticle.forwarder.init( + { accountId: '123456', workspaceIdSyncApiKey: WORKSPACE_API_KEY }, + reportService.cb, + true, + null, + {}, + ); + + (window as any).mParticle.forwarder.onUserIdentified( + makeUser({ getUserIdentities: () => ({ userIdentities: {} }) }), + ); + + expect(searchCalled).toBe(false); + expect((window as any).mParticle.forwarder.userIdentifiedInWorkspace).toBe(false); + }); + + it('should call search and forward non-email identifiers (e.g. hashed email in `other`)', async () => { + let receivedKnownIdentities: any = null; + (window as any).mParticle.Identity = { + search: (_apiKey: any, knownIdentities: any, cb: any) => { + receivedKnownIdentities = knownIdentities; + cb({ httpCode: 200, body: { mpid: '999' } }); + }, + }; + + await (window as any).mParticle.forwarder.init( + { accountId: '123456', workspaceIdSyncApiKey: WORKSPACE_API_KEY }, + reportService.cb, + true, + null, + {}, + ); + + (window as any).mParticle.forwarder.onUserIdentified( + makeUser({ + getUserIdentities: () => ({ + userIdentities: { other: 'sha256:abc123', customerid: 'cust-1' }, + }), + }), + ); + + expect(receivedKnownIdentities).toEqual({ other: 'sha256:abc123', customerid: 'cust-1' }); + expect((window as any).mParticle.forwarder.userIdentifiedInWorkspace).toBe(true); + }); + + it('should forward all non-empty string identifiers and drop empty/null entries', async () => { + let receivedKnownIdentities: any = null; + (window as any).mParticle.Identity = { + search: (_apiKey: any, knownIdentities: any, cb: any) => { + receivedKnownIdentities = knownIdentities; + cb({ httpCode: 200 }); + }, + }; + + await (window as any).mParticle.forwarder.init( + { accountId: '123456', workspaceIdSyncApiKey: WORKSPACE_API_KEY }, + reportService.cb, + true, + null, + {}, + ); + + (window as any).mParticle.forwarder.onUserIdentified( + makeUser({ + getUserIdentities: () => ({ + userIdentities: { + email: 'user@example.com', + other: 'sha256:abc', + customerid: '', + mobile_number: null, + facebook: 'fb-id', + }, + }), + }), + ); + + expect(receivedKnownIdentities).toEqual({ + email: 'user@example.com', + other: 'sha256:abc', + facebook: 'fb-id', + }); + }); + + it('should not throw when Identity.search is unavailable', async () => { + (window as any).mParticle.Identity = {}; + + await (window as any).mParticle.forwarder.init( + { accountId: '123456', workspaceIdSyncApiKey: WORKSPACE_API_KEY }, + reportService.cb, + true, + null, + {}, + ); + + expect(() => { + (window as any).mParticle.forwarder.onUserIdentified(makeUser()); + }).not.toThrow(); + expect((window as any).mParticle.forwarder.userIdentifiedInWorkspace).toBe(false); + }); + + it('should swallow errors thrown by search', async () => { + (window as any).mParticle.Identity = { + search: () => { + throw new Error('boom'); + }, + }; + + await (window as any).mParticle.forwarder.init( + { accountId: '123456', workspaceIdSyncApiKey: WORKSPACE_API_KEY }, + reportService.cb, + true, + null, + {}, + ); + + expect(() => { + (window as any).mParticle.forwarder.onUserIdentified(makeUser()); + }).not.toThrow(); + expect((window as any).mParticle.forwarder.userIdentifiedInWorkspace).toBe(false); + }); + + it('should wait for an in-flight search before selectPlacements builds attributes', async () => { + // Race regression: previously, onUserIdentified fired search + // synchronously and returned. Partners doing + // `Identity.login(...).then(() => Rokt.selectPlacements(...))` would + // read the flag before the HTTP response landed, missing the flag for + // the most important placement call. Now selectPlacements awaits the + // in-flight search (with a timeout) before building attributes. + let triggerSearchResponse: () => void = () => undefined; + (window as any).mParticle.Identity = { + search: (_apiKey: any, _knownIdentities: any, cb: any) => { + // Defer the callback to simulate a real network round-trip. + triggerSearchResponse = () => cb({ httpCode: 200, body: { mpid: '999' } }); + }, + }; + + await (window as any).mParticle.forwarder.init( + { accountId: '123456', workspaceIdSyncApiKey: WORKSPACE_API_KEY }, + reportService.cb, + true, + null, + {}, + ); + + // Stub launcher + filters so selectPlacements can dispatch. + let launcherCalledWithAttributes: any = null; + (window as any).mParticle.forwarder.launcher = { + selectPlacements: (opts: any) => { + launcherCalledWithAttributes = opts.attributes; + return { context: { sessionId: Promise.resolve('test-session') } }; + }, + }; + (window as any).mParticle.forwarder.filters = { + userAttributesFilters: [], + filterUserAttributes: (attributes: any) => attributes, + filteredUser: { getMPID: () => '123' }, + }; + + // Identification kicks off the search; callback NOT yet fired. + (window as any).mParticle.forwarder.onUserIdentified(makeUser()); + + // selectPlacements is invoked while the search is still in flight. + const placementPromise = (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: {}, + }); + + // Resolve the search; selectPlacements should now proceed and merge the flag. + triggerSearchResponse(); + await placementPromise; + + expect(launcherCalledWithAttributes.userIdentifiedInWorkspace).toBe(true); + }); + + it('should preserve an in-flight cached-user search when the same identity re-identifies', async () => { + let triggerSearchResponse: () => void = () => undefined; + let searchCallCount = 0; + (window as any).mParticle.Identity = { + search: (_apiKey: any, _knownIdentities: any, cb: any) => { + searchCallCount += 1; + triggerSearchResponse = () => cb({ httpCode: 200, body: { mpid: '999' } }); + }, + }; + (window as any).mParticle.Rokt.attachKit = async () => {}; + (window as any).mParticle.Rokt.filters = { + userAttributeFilters: [], + filterUserAttributes: (attributes: any) => attributes, + filteredUser: makeUser(), + }; + + await (window as any).mParticle.forwarder.init( + { accountId: '123456', workspaceIdSyncApiKey: WORKSPACE_API_KEY }, + reportService.cb, + true, + null, + {}, + ); + await waitForCondition(() => searchCallCount === 1); + + // A same-identity onUserIdentified while the cached-user search is + // still in flight should dedupe the network call without replacing the + // promise selectPlacements needs to wait on. + (window as any).mParticle.forwarder.onUserIdentified(makeUser()); + expect(searchCallCount).toBe(1); + + let launcherCalledWithAttributes: any = null; + (window as any).mParticle.forwarder.launcher = { + selectPlacements: (opts: any) => { + launcherCalledWithAttributes = opts.attributes; + return { context: { sessionId: Promise.resolve('test-session') } }; + }, + }; + + const placementPromise = (window as any).mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: {}, + }); + + triggerSearchResponse(); + await placementPromise; + + expect(launcherCalledWithAttributes.userIdentifiedInWorkspace).toBe(true); + }); + + it('should reset userIdentifiedInWorkspace on onLogoutComplete', async () => { + (window as any).mParticle.Identity = { + search: (_apiKey: any, _knownIdentities: any, cb: any) => { + cb({ httpCode: 200 }); + }, + }; + + await (window as any).mParticle.forwarder.init( + { accountId: '123456', workspaceIdSyncApiKey: WORKSPACE_API_KEY }, + reportService.cb, + true, + null, + {}, + ); + + (window as any).mParticle.forwarder.onUserIdentified(makeUser()); + expect((window as any).mParticle.forwarder.userIdentifiedInWorkspace).toBe(true); + + // onLogoutComplete must clear the flag so anonymous sessions don't + // carry the previous user's match forward — search is only + // fired from onUserIdentified, so logout has no re-evaluation path. + (window as any).mParticle.forwarder.onLogoutComplete({ + getAllUserAttributes: () => ({}), + getMPID: () => '999', + }); + + expect((window as any).mParticle.forwarder.userIdentifiedInWorkspace).toBe(false); + }); + + it('should reset userIdentifiedInWorkspace when re-identifying via a short-circuit path', async () => { + // A previous identification matched (flag=true). The new user has no + // email, so search short-circuits without dispatching. The + // flag must reset to false rather than leak from the previous user. + (window as any).mParticle.Identity = { + search: (_apiKey: any, _knownIdentities: any, cb: any) => { + cb({ httpCode: 200 }); + }, + }; + + await (window as any).mParticle.forwarder.init( + { accountId: '123456', workspaceIdSyncApiKey: WORKSPACE_API_KEY }, + reportService.cb, + true, + null, + {}, + ); + + (window as any).mParticle.forwarder.onUserIdentified(makeUser()); + expect((window as any).mParticle.forwarder.userIdentifiedInWorkspace).toBe(true); + + (window as any).mParticle.forwarder.onUserIdentified( + makeUser({ getUserIdentities: () => ({ userIdentities: {} }) }), + ); + + expect((window as any).mParticle.forwarder.userIdentifiedInWorkspace).toBe(false); + }); + + it('should not re-call Identity.search when the same identifier set re-identifies', async () => { + let searchCallCount = 0; + (window as any).mParticle.Identity = { + search: (_apiKey: any, _knownIdentities: any, cb: any) => { + searchCallCount += 1; + cb({ httpCode: 200 }); + }, + }; + + await (window as any).mParticle.forwarder.init( + { accountId: '123456', workspaceIdSyncApiKey: WORKSPACE_API_KEY }, + reportService.cb, + true, + null, + {}, + ); + + // Two identifications with the same identifier set. Should dispatch + // only once; the cached identities key skips the second network call. + (window as any).mParticle.forwarder.onUserIdentified(makeUser()); + (window as any).mParticle.forwarder.onUserIdentified(makeUser()); + + expect(searchCallCount).toBe(1); + // Flag from the first match still correct after the second identify. + expect((window as any).mParticle.forwarder.userIdentifiedInWorkspace).toBe(true); + }); + + it('should not re-call Identity.search when the same identifier set arrives with different key insertion order', async () => { + let searchCallCount = 0; + (window as any).mParticle.Identity = { + search: (_apiKey: any, _knownIdentities: any, cb: any) => { + searchCallCount += 1; + cb({ httpCode: 200 }); + }, + }; + + await (window as any).mParticle.forwarder.init( + { accountId: '123456', workspaceIdSyncApiKey: WORKSPACE_API_KEY }, + reportService.cb, + true, + null, + {}, + ); + + (window as any).mParticle.forwarder.onUserIdentified( + makeUser({ + getUserIdentities: () => ({ + userIdentities: { email: 'a@example.com', other: 'sha256:abc' }, + }), + }), + ); + (window as any).mParticle.forwarder.onUserIdentified( + makeUser({ + getUserIdentities: () => ({ + userIdentities: { other: 'sha256:abc', email: 'a@example.com' }, + }), + }), + ); + + expect(searchCallCount).toBe(1); + }); + + it('should re-call Identity.search when a non-email identifier changes', async () => { + let searchCallCount = 0; + const observedHashes: string[] = []; + (window as any).mParticle.Identity = { + search: (_apiKey: any, knownIdentities: any, cb: any) => { + searchCallCount += 1; + observedHashes.push(knownIdentities.other); + cb({ httpCode: 200 }); + }, + }; + + await (window as any).mParticle.forwarder.init( + { accountId: '123456', workspaceIdSyncApiKey: WORKSPACE_API_KEY }, + reportService.cb, + true, + null, + {}, + ); + + (window as any).mParticle.forwarder.onUserIdentified( + makeUser({ getUserIdentities: () => ({ userIdentities: { other: 'sha256:aaa' } }) }), + ); + (window as any).mParticle.forwarder.onUserIdentified( + makeUser({ getUserIdentities: () => ({ userIdentities: { other: 'sha256:bbb' } }) }), + ); + + expect(searchCallCount).toBe(2); + expect(observedHashes).toEqual(['sha256:aaa', 'sha256:bbb']); + }); + + it('should re-call Identity.search when the email changes', async () => { + let searchCallCount = 0; + const observedEmails: string[] = []; + (window as any).mParticle.Identity = { + search: (_apiKey: any, knownIdentities: any, cb: any) => { + searchCallCount += 1; + observedEmails.push(knownIdentities.email); + cb({ httpCode: 200 }); + }, + }; + + await (window as any).mParticle.forwarder.init( + { accountId: '123456', workspaceIdSyncApiKey: WORKSPACE_API_KEY }, + reportService.cb, + true, + null, + {}, + ); + + (window as any).mParticle.forwarder.onUserIdentified( + makeUser({ getUserIdentities: () => ({ userIdentities: { email: 'a@example.com' } }) }), + ); + (window as any).mParticle.forwarder.onUserIdentified( + makeUser({ getUserIdentities: () => ({ userIdentities: { email: 'b@example.com' } }) }), + ); + + expect(searchCallCount).toBe(2); + expect(observedEmails).toEqual(['a@example.com', 'b@example.com']); + }); + + it('should re-call Identity.search after logout even with the same identifiers', async () => { + let searchCallCount = 0; + (window as any).mParticle.Identity = { + search: (_apiKey: any, _knownIdentities: any, cb: any) => { + searchCallCount += 1; + cb({ httpCode: 200 }); + }, + }; + + await (window as any).mParticle.forwarder.init( + { accountId: '123456', workspaceIdSyncApiKey: WORKSPACE_API_KEY }, + reportService.cb, + true, + null, + {}, + ); + + (window as any).mParticle.forwarder.onUserIdentified(makeUser()); + // Logout clears the identities cache so a re-login re-evaluates. + (window as any).mParticle.forwarder.onLogoutComplete({ + getAllUserAttributes: () => ({}), + getMPID: () => '999', + }); + (window as any).mParticle.forwarder.onUserIdentified(makeUser()); + + expect(searchCallCount).toBe(2); + }); + }); + + describe('#onLoginComplete', () => { + it('should update userAttributes from the filtered user', () => { + (window as any).mParticle.forwarder.onLoginComplete({ + getAllUserAttributes: function () { + return { 'user-attr': 'user-value' }; + }, + getMPID: function () { + return '123'; + }, + }); + + expect((window as any).mParticle.forwarder.userAttributes).toEqual({ + 'user-attr': 'user-value', + }); + }); + }); + + describe('#onLogoutComplete', () => { + it('should update userAttributes from the filtered user', () => { + (window as any).mParticle.forwarder.onLogoutComplete({ + getAllUserAttributes: function () { + return { 'remaining-attr': 'some-value' }; + }, + getMPID: function () { + return '123'; + }, + }); + + expect((window as any).mParticle.forwarder.userAttributes).toEqual({ + 'remaining-attr': 'some-value', + }); + }); + }); + + describe('#onModifyComplete', () => { + 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', + }); + }); + }); + + 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-api.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('#generateThankYouElementScript', () => { + const baseUrl = 'https://apps.rokt-api.com/rokt-elements/rokt-element-thank-you.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.generateThankYouElementScript(undefined); + expect(url).toBe(baseUrl); + }); + + it('should return an updated base URL with CNAME when domain is passed', () => { + const url = (window as any).mParticle.forwarder.testHelpers.generateThankYouElementScript('cname.rokt.com'); + expect(url).toBe('https://cname.rokt.com/rokt-elements/rokt-element-thank-you.js'); + }); + }); + + describe('#roktExtensions', () => { + beforeEach(() => { + (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true); + }); + + describe('extractRoktExtensionConfig', () => { + it('should correctly map known extension names to their query parameters', () => { + const settingsString = + '[{"jsmap":null,"map":null,"maptype":"StaticList","value":"cos-extension-detection"},{"jsmap":null,"map":null,"maptype":"StaticList","value":"experiment-monitoring"}]'; + + const result = (window as any).mParticle.forwarder.testHelpers.extractRoktExtensionConfig(settingsString); + expect(result.roktExtensionsQueryParams).toEqual(['cos-extension-detection', 'experiment-monitoring']); + expect(result.legacyRoktExtensions).toEqual([]); + expect(result.loadThankYouElement).toBe(false); + }); + + it('should separate thank-you-journey into legacyRoktExtensions and set loadThankYouElement', () => { + const settingsString = + '[{"jsmap":null,"map":null,"maptype":"StaticList","value":"thank-you-journey"},{"jsmap":null,"map":null,"maptype":"StaticList","value":"instant-purchase"}]'; + + const result = (window as any).mParticle.forwarder.testHelpers.extractRoktExtensionConfig(settingsString); + expect(result.roktExtensionsQueryParams).toEqual(['instant-purchase']); + expect(result.legacyRoktExtensions).toEqual(['ThankYouPageJourney']); + expect(result.loadThankYouElement).toBe(true); + }); + }); + + it('should fetch thank you element resource when thank you element extension is provided', async () => { + document.getElementById('rokt-thank-you-element')?.remove(); + document.getElementById('rokt-launcher')?.remove(); + + (window as any).Rokt = undefined; + (window as any).mParticle.Rokt = { + attachKit: async (kit: any) => { + (window as any).mParticle.Rokt.kit = kit; + }, + filters: { + userAttributesFilters: [], + filterUserAttributes: (attrs: any) => attrs, + filteredUser: { getMPID: () => '123' }, + }, + use: () => Promise.resolve(), + flushOnShoppableAdsReadyMessageQueue: () => {}, + }; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + roktExtensions: '[{"jsmap":null,"map":null,"maptype":"StaticList","value":"thank-you-journey"}]', + }, + reportService.cb, + false, + ); + + const tyeScript = document.getElementById('rokt-thank-you-element') as HTMLScriptElement; + expect(tyeScript).not.toBeNull(); + expect(tyeScript.src).toContain('/rokt-elements/rokt-element-thank-you.js'); + }); + + it('should call launcher.use with ThankYouPageJourney when thank-you-journey extension is provided', async () => { + document.getElementById('rokt-thank-you-element')?.remove(); + document.getElementById('rokt-launcher')?.remove(); + + const useCalls: string[] = []; + const mockLauncher = { + selectPlacements: () => {}, + hashAttributes: () => {}, + use: (name: string) => { + useCalls.push(name); + }, + }; + + (window as any).Rokt = undefined; + (window as any).mParticle.Rokt = { + attachKit: async (kit: any) => { + (window as any).mParticle.Rokt.kit = kit; + }, + filters: { + userAttributesFilters: [], + filterUserAttributes: (attrs: any) => attrs, + filteredUser: { getMPID: () => '123' }, + }, + flushOnShoppableAdsReadyMessageQueue: () => {}, + }; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + roktExtensions: '[{"jsmap":null,"map":null,"maptype":"StaticList","value":"thank-you-journey"}]', + }, + reportService.cb, + false, + ); + + // Use a synchronous thenable so this.launcher is set before registerLegacyExtensions runs + (window as any).Rokt = new (MockRoktForwarder as any)(); + (window as any).Rokt.createLauncher = () => ({ + then: (onFulfilled: (launcher: typeof mockLauncher) => void) => { + onFulfilled(mockLauncher); + return { catch: () => {} }; + }, + }); + + const launcherScript = document.getElementById('rokt-launcher') as HTMLScriptElement; + launcherScript.onload!(new Event('load')); + + expect(useCalls).toContain('ThankYouPageJourney'); + }); + + it('should fetch thank you element resource when thank you element extension is provided', async () => { + document.getElementById('rokt-thank-you-element')?.remove(); + document.getElementById('rokt-launcher')?.remove(); + + (window as any).Rokt = undefined; + (window as any).mParticle.Rokt = { + attachKit: async (kit: any) => { + (window as any).mParticle.Rokt.kit = kit; + }, + filters: { + userAttributesFilters: [], + filterUserAttributes: (attrs: any) => attrs, + filteredUser: { getMPID: () => '123' }, + }, + use: () => Promise.resolve(), + flushOnShoppableAdsReadyMessageQueue: () => {}, + }; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + roktExtensions: '[{"jsmap":null,"map":null,"maptype":"StaticList","value":"thank-you-journey"}]', + }, + reportService.cb, + false, + ); + + const tyeScript = document.getElementById('rokt-thank-you-element') as HTMLScriptElement; + expect(tyeScript).not.toBeNull(); + expect(tyeScript.src).toContain('/rokt-elements/rokt-element-thank-you.js'); + }); + + it('should call launcher.use with ThankYouPageJourney when thank-you-journey extension is provided', async () => { + document.getElementById('rokt-thank-you-element')?.remove(); + document.getElementById('rokt-launcher')?.remove(); + + const useCalls: string[] = []; + + (window as any).Rokt = undefined; + (window as any).mParticle.Rokt = { + attachKit: async (kit: any) => { + (window as any).mParticle.Rokt.kit = kit; + }, + filters: { + userAttributesFilters: [], + filterUserAttributes: (attrs: any) => attrs, + filteredUser: { getMPID: () => '123' }, + }, + flushOnShoppableAdsReadyMessageQueue: () => {}, + }; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + roktExtensions: '[{"jsmap":null,"map":null,"maptype":"StaticList","value":"thank-you-journey"}]', + }, + reportService.cb, + false, + ); + + const mockLauncher = { + selectPlacements: () => {}, + hashAttributes: () => {}, + use: (name: string) => { + useCalls.push(name); + }, + }; + + // Use a synchronous thenable so this.launcher is set before registerLegacyExtensions runs + (window as any).Rokt = new (MockRoktForwarder as any)(); + (window as any).Rokt.createLauncher = () => ({ + then: (onFulfilled: (launcher: typeof mockLauncher) => void) => { + onFulfilled(mockLauncher); + return { catch: () => {} }; + }, + }); + + const launcherScript = document.getElementById('rokt-launcher') as HTMLScriptElement; + launcherScript.onload!(new Event('load')); + + expect(useCalls).toContain('ThankYouPageJourney'); + }); + + it('should handle invalid setting strings', () => { + expect((window as any).mParticle.forwarder.testHelpers.extractRoktExtensionConfig('NONE')).toEqual({ + roktExtensionsQueryParams: [], + legacyRoktExtensions: [], + loadThankYouElement: false, + }); + expect((window as any).mParticle.forwarder.testHelpers.extractRoktExtensionConfig(undefined)).toEqual({ + roktExtensionsQueryParams: [], + legacyRoktExtensions: [], + loadThankYouElement: false, + }); + expect((window as any).mParticle.forwarder.testHelpers.extractRoktExtensionConfig(null)).toEqual({ + roktExtensionsQueryParams: [], + legacyRoktExtensions: [], + loadThankYouElement: false, + }); + }); + }); + + describe('#onShoppableAdsReady', () => { + let flushOnShoppableAdsReadyMessageQueueCalled: boolean; + let flushedKit: any; + + beforeEach(() => { + document.getElementById('rokt-thank-you-element')?.remove(); + document.getElementById('rokt-launcher')?.remove(); + + // Reset TYE load state so tests are independent of execution order. + (window as any).mParticle.forwarder._isThankYouElementLoaded = false; + (window as any).mParticle.forwarder._thankYouElementOnLoadCallback = null; + + flushOnShoppableAdsReadyMessageQueueCalled = false; + flushedKit = null; + + (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.flushOnShoppableAdsReadyMessageQueue = (kit: any) => { + flushOnShoppableAdsReadyMessageQueueCalled = true; + flushedKit = kit; + }; + (window as any).mParticle.Rokt.filters = { + userAttributesFilters: [], + filterUserAttributes: (attrs: any) => attrs, + filteredUser: { getMPID: () => '123' }, + }; + }); + + it('should call flushOnShoppableAdsReadyMessageQueue with the kit when thank-you-journey extension is configured', async () => { + (window as any).Rokt = undefined; + (window as any).mParticle.Rokt.flushOnShoppableAdsReadyMessageQueue = (kit: any) => { + flushOnShoppableAdsReadyMessageQueueCalled = true; + flushedKit = kit; + }; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + roktExtensions: '[{"jsmap":null,"map":null,"maptype":"StaticList","value":"thank-you-journey"}]', + }, + reportService.cb, + false, + ); + + expect(flushOnShoppableAdsReadyMessageQueueCalled).toBe(true); + expect(flushedKit).toBe((window as any).mParticle.forwarder); + }); + + it('should NOT call flushOnShoppableAdsReadyMessageQueue when thank-you-journey is not configured', async () => { + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true); + + expect(flushOnShoppableAdsReadyMessageQueueCalled).toBe(false); + }); + + it('should store the onShoppableAdsReady callback and invoke it when the TYE script loads', async () => { + (window as any).Rokt = undefined; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + roktExtensions: '[{"jsmap":null,"map":null,"maptype":"StaticList","value":"thank-you-journey"}]', + }, + reportService.cb, + false, + ); + + let callbackInvoked = false; + (window as any).mParticle.forwarder.onShoppableAdsReady(() => { + callbackInvoked = true; + }); + + // Simulate TYE script onload firing + const tyeScript = document.getElementById('rokt-thank-you-element') as HTMLScriptElement; + expect(tyeScript).not.toBeNull(); + tyeScript.onload!(new Event('load')); + + expect(callbackInvoked).toBe(true); + }); + + it('should overwrite a previously registered onShoppableAdsReady callback', async () => { + (window as any).Rokt = undefined; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + roktExtensions: '[{"jsmap":null,"map":null,"maptype":"StaticList","value":"thank-you-journey"}]', + }, + reportService.cb, + false, + ); + + let firstCallbackInvoked = false; + let secondCallbackInvoked = false; + + (window as any).mParticle.forwarder.onShoppableAdsReady(() => { + firstCallbackInvoked = true; + }); + (window as any).mParticle.forwarder.onShoppableAdsReady(() => { + secondCallbackInvoked = true; + }); + + const tyeScript = document.getElementById('rokt-thank-you-element') as HTMLScriptElement; + tyeScript.onload!(new Event('load')); + + expect(firstCallbackInvoked).toBe(false); + expect(secondCallbackInvoked).toBe(true); + }); + + it('should invoke the callback immediately when registered after the TYE script has already loaded', async () => { + (window as any).Rokt = undefined; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + roktExtensions: '[{"jsmap":null,"map":null,"maptype":"StaticList","value":"thank-you-journey"}]', + }, + reportService.cb, + false, + ); + + // Simulate TYE script loading before the callback is registered + const tyeScript = document.getElementById('rokt-thank-you-element') as HTMLScriptElement; + expect(tyeScript).not.toBeNull(); + tyeScript.onload!(new Event('load')); + + // Register the callback late — after the TYE script has already loaded + let callbackInvoked = false; + (window as any).mParticle.forwarder.onShoppableAdsReady(() => { + callbackInvoked = true; + }); + + expect(callbackInvoked).toBe(true); + }); + + it('should not invoke the callback if the TYE script fails to load', async () => { + (window as any).Rokt = undefined; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + roktExtensions: '[{"jsmap":null,"map":null,"maptype":"StaticList","value":"thank-you-journey"}]', + }, + reportService.cb, + false, + ); + + let callbackInvoked = false; + (window as any).mParticle.forwarder.onShoppableAdsReady(() => { + callbackInvoked = true; + }); + + const tyeScript = document.getElementById('rokt-thank-you-element') as HTMLScriptElement; + tyeScript.onerror!(new Event('error')); + + expect(callbackInvoked).toBe(false); + }); + }); + + describe('#registerLegacyExtensions', () => { + beforeEach(() => { + document.getElementById('rokt-thank-you-element')?.remove(); + document.getElementById('rokt-launcher')?.remove(); + + (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.flushOnShoppableAdsReadyMessageQueue = () => {}; + (window as any).mParticle.Rokt.filters = { + userAttributesFilters: [], + filterUserAttributes: (attrs: any) => attrs, + filteredUser: { getMPID: () => '123' }, + }; + }); + + it('should await all launcher.use() promises before calling initRoktLauncher', async () => { + const useCallOrder: string[] = []; + let initCalledAfterUse = false; + + const mockLauncher = { + selectPlacements: () => {}, + hashAttributes: () => {}, + onShoppableAdsReady: () => {}, + use: (name: string) => { + return new Promise((resolve) => { + setTimeout(() => { + useCallOrder.push(name); + resolve(); + }, 0); + }); + }, + }; + + (window as any).Rokt = undefined; + (window as any).mParticle.Rokt.attachKit = async (kit: any) => { + initCalledAfterUse = useCallOrder.includes('ThankYouPageJourney'); + (window as any).mParticle.Rokt.kit = kit; + }; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + roktExtensions: '[{"jsmap":null,"map":null,"maptype":"StaticList","value":"thank-you-journey"}]', + }, + reportService.cb, + false, + ); + + (window as any).Rokt = new (MockRoktForwarder as any)(); + (window as any).Rokt.createLauncher = () => Promise.resolve(mockLauncher); + + const launcherScript = document.getElementById('rokt-launcher') as HTMLScriptElement; + launcherScript.onload!(new Event('load')); + + await waitForCondition(() => initCalledAfterUse); + + expect(useCallOrder).toContain('ThankYouPageJourney'); + expect(initCalledAfterUse).toBe(true); + }); + + it('should not throw if launcher.use() rejects', async () => { + const mockLauncher = { + selectPlacements: () => {}, + hashAttributes: () => {}, + onShoppableAdsReady: () => {}, + use: () => Promise.reject(new Error('extension load failed')), + }; + + (window as any).Rokt = undefined; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + roktExtensions: '[{"jsmap":null,"map":null,"maptype":"StaticList","value":"thank-you-journey"}]', + }, + reportService.cb, + false, + ); + + (window as any).Rokt = new (MockRoktForwarder as any)(); + (window as any).Rokt.createLauncher = () => Promise.resolve(mockLauncher); + + const launcherScript = document.getElementById('rokt-launcher') as HTMLScriptElement; + + // Should not throw + await expect( + new Promise((resolve) => { + launcherScript.onload!(new Event('load')); + setTimeout(resolve, 50); + }), + ).resolves.not.toThrow(); + }); + }); + + 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, + }); + }); + }); + + describe('#processBatch', () => { + let mockBatch: Batch; + + beforeEach(() => { + (window as any).mParticle.forwarder.batchQueue = []; + (window as any).mParticle.forwarder.batchStreamQueue = []; + (window as any).mParticle.forwarder.pendingIdentityEvents = []; + (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'; + }, + }, + }; + + mockBatch = { + mpid: 'test-mpid-123', + user_attributes: { 'user-attr': 'user-value' }, + user_identities: { email: 'test@example.com' }, + events: [ + { + event_type: 'custom_event', + data: { event_name: 'Test Event', custom_event_type: 'other' }, + }, + ], + }; + }); + + afterEach(() => { + delete (window as any).Rokt.__batch_stream__; + (window as any).mParticle.forwarder.batchQueue = []; + (window as any).mParticle.forwarder.batchStreamQueue = []; + (window as any).mParticle.forwarder.pendingIdentityEvents = []; + (window as any).mParticle.forwarder.isInitialized = false; + (window as any).mParticle.Rokt.attachKitCalled = false; + }); + + it('should send batch to window.Rokt.__batch_stream__ when kit is ready', async () => { + const receivedBatches: any[] = []; + (window as any).Rokt.__batch_stream__ = function (payload: any) { + receivedBatches.push(payload); + }; + + 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.processBatch(mockBatch); + + expect(receivedBatches.length).toBe(1); + expect(receivedBatches[0].mpid).toBe('test-mpid-123'); + expect(receivedBatches[0].user_attributes).toEqual({ 'user-attr': 'user-value' }); + expect(receivedBatches[0].user_identities).toEqual({ email: 'test@example.com' }); + expect(receivedBatches[0].events.length).toBe(1); + }); + + it('should not add extra events when pendingIdentityEvents is empty', async () => { + const receivedBatches: any[] = []; + (window as any).Rokt.__batch_stream__ = function (payload: any) { + receivedBatches.push(payload); + }; + + 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.pendingIdentityEvents.length).toBe(0); + + (window as any).mParticle.forwarder.processBatch(mockBatch); + + expect(receivedBatches.length).toBe(1); + expect(receivedBatches[0].events.length).toBe(1); + expect(receivedBatches[0].events[0].event_type).toBe('custom_event'); + }); + + it('should queue batch in batchQueue when kit is not initialized', () => { + (window as any).mParticle.forwarder.isInitialized = false; + (window as any).mParticle.forwarder.launcher = null; + + expect(() => { + (window as any).mParticle.forwarder.processBatch(mockBatch); + }).not.toThrow(); + + expect((window as any).mParticle.forwarder.batchQueue.length).toBe(1); + expect((window as any).mParticle.forwarder.batchQueue[0]).toEqual(mockBatch); + }); + + it('should flush batchQueue when kit becomes ready', async () => { + const receivedBatches: any[] = []; + (window as any).Rokt.__batch_stream__ = function (payload: any) { + receivedBatches.push(payload); + }; + + (window as any).mParticle.forwarder.isInitialized = false; + (window as any).mParticle.forwarder.launcher = null; + (window as any).mParticle.forwarder.processBatch(mockBatch); + + expect((window as any).mParticle.forwarder.batchQueue.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(receivedBatches.length).toBe(1); + expect(receivedBatches[0].mpid).toBe('test-mpid-123'); + expect((window as any).mParticle.forwarder.batchQueue.length).toBe(0); + }); + + it('should queue batch in batchStreamQueue when window.Rokt.__batch_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); + + expect(() => { + (window as any).mParticle.forwarder.processBatch(mockBatch); + }).not.toThrow(); + + expect((window as any).mParticle.forwarder.batchStreamQueue.length).toBe(1); + expect((window as any).mParticle.forwarder.batchStreamQueue[0]).toEqual(mockBatch); + }); + + it('should queue batch in batchStreamQueue 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; + delete (window as any).Rokt; + + expect(() => { + (window as any).mParticle.forwarder.processBatch(mockBatch); + }).not.toThrow(); + + expect((window as any).mParticle.forwarder.batchStreamQueue.length).toBe(1); + expect((window as any).mParticle.forwarder.batchStreamQueue[0]).toEqual(mockBatch); + + (window as any).Rokt = savedRokt; + }); + + it('should flush batchStreamQueue before sending the next batch', async () => { + const receivedBatches: any[] = []; + + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + const batchA = { mpid: 'mpid-A', events: [], user_attributes: {} }; + const batchB = { mpid: 'mpid-B', events: [], user_attributes: {} }; + const batchC = { mpid: 'mpid-C', events: [], user_attributes: {} }; + + (window as any).mParticle.forwarder.processBatch(batchA); + (window as any).mParticle.forwarder.processBatch(batchB); + + expect((window as any).mParticle.forwarder.batchStreamQueue.length).toBe(2); + + (window as any).Rokt.__batch_stream__ = function (payload: any) { + receivedBatches.push(payload); + }; + + (window as any).mParticle.forwarder.processBatch(batchC); + + expect(receivedBatches.length).toBe(3); + expect(receivedBatches[0].mpid).toBe('mpid-A'); + expect(receivedBatches[1].mpid).toBe('mpid-B'); + expect(receivedBatches[2].mpid).toBe('mpid-C'); + expect((window as any).mParticle.forwarder.batchStreamQueue.length).toBe(0); + }); + + it('should add an identity event to pendingIdentityEvents on onLoginComplete', () => { + const mockUser = { + getMPID: () => '123', + getAllUserAttributes: () => ({}), + getUserIdentities: () => ({ userIdentities: {} }), + }; + + (window as any).mParticle.forwarder.onLoginComplete(mockUser, null); + + const pending = (window as any).mParticle.forwarder.pendingIdentityEvents; + expect(pending.length).toBe(1); + expect(pending[0].event_type).toBe('login'); + expect(pending[0].data.timestamp_unixtime_ms).toBeTypeOf('number'); + }); + + it('should add an identity event to pendingIdentityEvents on onLogoutComplete', () => { + const mockUser = { + getMPID: () => '123', + getAllUserAttributes: () => ({}), + getUserIdentities: () => ({ userIdentities: {} }), + }; + + (window as any).mParticle.forwarder.onLogoutComplete(mockUser, null); + + const pending = (window as any).mParticle.forwarder.pendingIdentityEvents; + expect(pending.length).toBe(1); + expect(pending[0].event_type).toBe('logout'); + expect(pending[0].data.timestamp_unixtime_ms).toBeTypeOf('number'); + }); + + it('should add identity events to pendingIdentityEvents on onModifyComplete and onUserIdentified', () => { + const mockUser = { + getMPID: () => '42', + getAllUserAttributes: () => ({}), + getUserIdentities: () => ({ userIdentities: {} }), + }; + + (window as any).mParticle.forwarder.onModifyComplete(mockUser, null); + (window as any).mParticle.forwarder.onUserIdentified(mockUser); + + const pending = (window as any).mParticle.forwarder.pendingIdentityEvents; + expect(pending.length).toBe(2); + expect(pending[0].event_type).toBe('modify_user'); + expect(pending[1].event_type).toBe('identify'); + }); + + it('should merge pendingIdentityEvents into the outgoing batch and clear the queue', async () => { + const receivedBatches: any[] = []; + (window as any).Rokt.__batch_stream__ = function (payload: any) { + receivedBatches.push(payload); + }; + + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + const mockUser = { + getMPID: () => '123', + getAllUserAttributes: () => ({}), + getUserIdentities: () => ({ userIdentities: {} }), + }; + + (window as any).mParticle.forwarder.onLoginComplete(mockUser, null); + expect((window as any).mParticle.forwarder.pendingIdentityEvents.length).toBe(1); + + (window as any).mParticle.forwarder.processBatch(mockBatch); + + expect(receivedBatches.length).toBe(1); + // Original 1 custom_event + 1 identity event from onLoginComplete + expect(receivedBatches[0].events.length).toBe(2); + expect(receivedBatches[0].events[1].event_type).toBe('login'); + expect(receivedBatches[0].events[1].data.timestamp_unixtime_ms).toBeTypeOf('number'); + // Queue should be cleared after flush + expect((window as any).mParticle.forwarder.pendingIdentityEvents.length).toBe(0); + }); + + it('should merge pendingIdentityEvents into the first queued batch when kit becomes ready', async () => { + const receivedBatches: any[] = []; + (window as any).Rokt.__batch_stream__ = function (payload: any) { + receivedBatches.push(payload); + }; + + // Queue a batch before the kit initialises + (window as any).mParticle.forwarder.isInitialized = false; + (window as any).mParticle.forwarder.launcher = null; + + const mockUser = { + getMPID: () => '123', + getAllUserAttributes: () => ({}), + getUserIdentities: () => ({ userIdentities: {} }), + }; + + // Identity callback fires before kit is ready + (window as any).mParticle.forwarder.onLoginComplete(mockUser, null); + (window as any).mParticle.forwarder.processBatch(mockBatch); + + expect((window as any).mParticle.forwarder.batchQueue.length).toBe(1); + expect((window as any).mParticle.forwarder.pendingIdentityEvents.length).toBe(1); + + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + // The queued batch should have the pending identity event merged in + expect(receivedBatches.length).toBe(1); + expect(receivedBatches[0].events.length).toBe(2); + expect(receivedBatches[0].events[1].event_type).toBe('login'); + expect((window as any).mParticle.forwarder.pendingIdentityEvents.length).toBe(0); + expect((window as any).mParticle.forwarder.batchQueue.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/kits/rokt/test/vitest.setup.ts b/kits/rokt/test/vitest.setup.ts new file mode 100644 index 000000000..a2c92bebb --- /dev/null +++ b/kits/rokt/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/kits/rokt/tsconfig.json b/kits/rokt/tsconfig.json new file mode 100644 index 000000000..15793be04 --- /dev/null +++ b/kits/rokt/tsconfig.json @@ -0,0 +1,24 @@ +{ + "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, + "baseUrl": ".", + "paths": { + "@mparticle/web-sdk": ["../../dist/types/src/public-types.d.ts"], + "@mparticle/web-sdk/internal": ["../../dist/types/src/internal-types.d.ts"] + } + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "test"] +} diff --git a/kits/rokt/tsconfig.test.json b/kits/rokt/tsconfig.test.json new file mode 100644 index 000000000..8541679d0 --- /dev/null +++ b/kits/rokt/tsconfig.test.json @@ -0,0 +1,7 @@ +{ + "extends": "./tsconfig.json", + "include": ["src/**/*", "test/**/*"], + "compilerOptions": { + "types": ["vitest/globals"] + } +} diff --git a/kits/rokt/vite.config.ts b/kits/rokt/vite.config.ts new file mode 100644 index 000000000..0f36f5aa5 --- /dev/null +++ b/kits/rokt/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'], + }, + }, +});