From 13b34ed5ad04db7f246b26a3585187294bd76cd4 Mon Sep 17 00:00:00 2001 From: Ed Dorsey Date: Wed, 13 May 2026 21:10:29 -0400 Subject: [PATCH 01/13] Migrate integration from v1 to v2 - Convert integration.js to TypeScript (src/integration.ts) - Replace postman-request with polarity-integration-utils - Convert Ember/Handlebars component to Lit web component (web-components/details.ts) - Update config.json (runtimeVersion 2, dataTypes, webComponents) - Fix credential leakage in error logging (security review) - Sanitize parseErrorToReadableJSON to strip auth from serialized errors - Remove v1 files (integration.js, config/config.js, components/, templates/, styles/) - Version 4.0.0 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/release-current-version.yml | 6 +- .github/workflows/run-int-dev-checklist.yml | 27 +- .gitignore | 3 +- .npmrc | 1 + .prettierignore | 4 + .prettierrc | 22 +- LICENSE | 22 +- README.md | 2 +- components/block.js | 74 - config/config.js | 65 - config/config.json | 57 +- {assets => docs}/Host List Detections.png | Bin {assets => docs}/KnowledgeBase Record.png | Bin .../hostDetectionsFullExample.png | Bin {assets => docs}/knowledgeBaseFullExample.png | Bin eslint.config.mjs | 22 + integration.js | 62 - package-lock.json | 4312 ++++++++++++++++- package.json | 39 +- src/associateDataWithEntities.js | 39 - src/associateDataWithEntities.ts | 47 + src/{constants.js => constants.ts} | 61 +- src/createLookupResults.js | 57 - src/createLookupResults.ts | 46 + src/createRequestWithDefaults.js | 115 - src/dataTransformations.js | 216 - src/dataTransformations.ts | 211 + src/getDisplayResults.js | 40 - src/getDisplayResults.ts | 48 + src/getLookupResults.js | 67 - src/getLookupResults.ts | 53 + src/integration.ts | 78 + src/querying/queryAssetsForAllEntities.js | 72 - src/querying/queryAssetsForAllEntities.ts | 60 + .../queryHostDetectionListForAllEntities.js | 140 - .../queryHostDetectionListForAllEntities.ts | 129 + .../queryVulnerabilitiesForAllEntities.js | 71 - .../queryVulnerabilitiesForAllEntities.ts | 61 + src/validateOptions.js | 45 - src/validateOptions.ts | 45 + styles/styles.less | 112 - templates/block.hbs | 274 -- test/integration.test.ts | 7 + test/web-components/details.test.ts | 7 + tsconfig.json | 21 + tsconfig.web.json | 12 + vite.config.js | 36 + vitest.config.ts | 28 + web-components/details.ts | 628 +++ 49 files changed, 5824 insertions(+), 1720 deletions(-) create mode 100644 .npmrc create mode 100644 .prettierignore delete mode 100644 components/block.js delete mode 100644 config/config.js rename {assets => docs}/Host List Detections.png (100%) rename {assets => docs}/KnowledgeBase Record.png (100%) rename {assets => docs}/hostDetectionsFullExample.png (100%) rename {assets => docs}/knowledgeBaseFullExample.png (100%) create mode 100644 eslint.config.mjs delete mode 100644 integration.js delete mode 100644 src/associateDataWithEntities.js create mode 100644 src/associateDataWithEntities.ts rename src/{constants.js => constants.ts} (67%) delete mode 100644 src/createLookupResults.js create mode 100644 src/createLookupResults.ts delete mode 100644 src/createRequestWithDefaults.js delete mode 100644 src/dataTransformations.js create mode 100644 src/dataTransformations.ts delete mode 100644 src/getDisplayResults.js create mode 100644 src/getDisplayResults.ts delete mode 100644 src/getLookupResults.js create mode 100644 src/getLookupResults.ts create mode 100644 src/integration.ts delete mode 100644 src/querying/queryAssetsForAllEntities.js create mode 100644 src/querying/queryAssetsForAllEntities.ts delete mode 100644 src/querying/queryHostDetectionListForAllEntities.js create mode 100644 src/querying/queryHostDetectionListForAllEntities.ts delete mode 100644 src/querying/queryVulnerabilitiesForAllEntities.js create mode 100644 src/querying/queryVulnerabilitiesForAllEntities.ts delete mode 100644 src/validateOptions.js create mode 100644 src/validateOptions.ts delete mode 100644 styles/styles.less delete mode 100644 templates/block.hbs create mode 100644 test/integration.test.ts create mode 100644 test/web-components/details.test.ts create mode 100644 tsconfig.json create mode 100644 tsconfig.web.json create mode 100644 vite.config.js create mode 100644 vitest.config.ts create mode 100644 web-components/details.ts diff --git a/.github/workflows/release-current-version.yml b/.github/workflows/release-current-version.yml index 6d6faae..641a3b7 100644 --- a/.github/workflows/release-current-version.yml +++ b/.github/workflows/release-current-version.yml @@ -2,10 +2,8 @@ name: Release Current Version on: push: - branches: [ master, main ] + branches: [ master, main, support/v1 ] jobs: Run: - uses: polarityio/polarity-github-actions/.github/workflows/release-server-versions-for-int-store.yml@master - # with: - # use-integration-development-checklist: false + uses: polarityio/polarity-github-actions/.github/workflows/release-integration.yml@master diff --git a/.github/workflows/run-int-dev-checklist.yml b/.github/workflows/run-int-dev-checklist.yml index ffa86d7..12eba68 100644 --- a/.github/workflows/run-int-dev-checklist.yml +++ b/.github/workflows/run-int-dev-checklist.yml @@ -2,22 +2,23 @@ name: Run Integration Development Checklist on: pull_request: - branches: [ master, main, develop ] + branches: [ master, main, develop, support/v1 ] jobs: run-integration-development-checklist: runs-on: ubuntu-latest - container: 'centos:7' steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v1 - - name: Test NPM Install - id: test-npm-install - run: | - npm ci - - name: Polarity Integration Development Checklist - id: int-dev-checklist - uses: polarityio/polarity-integration-development-checklist@main - with: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - uses: actions/checkout@v6 + - uses: actions/setup-node@v4 + with: + node-version: '18' + - name: Test NPM Install + id: test-npm-install + run: | + npm ci + - name: Polarity Integration Development Checklist + id: int-dev-checklist + uses: polarityio/polarity-integration-development-checklist@main + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index f7fe565..6b8cdd1 100644 --- a/.gitignore +++ b/.gitignore @@ -33,4 +33,5 @@ test-runner.js .polarity.conf -data/ \ No newline at end of file +data/ +dist/ diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..521a9f7 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +legacy-peer-deps=true diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..55a10aa --- /dev/null +++ b/.prettierignore @@ -0,0 +1,4 @@ +dist/ +node_modules/ +mocks/ +package-lock.json diff --git a/.prettierrc b/.prettierrc index 8dff95d..e98ecea 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,11 +1,11 @@ -{ - "arrowParens": "always", - "bracketSpacing": true, - "printWidth": 90, - "proseWrap": "preserve", - "semi": true, - "singleQuote": true, - "tabWidth": 2, - "trailingComma": "none", - "useTabs": false -} \ No newline at end of file +{ + "arrowParens": "always", + "bracketSpacing": true, + "printWidth": 100, + "proseWrap": "preserve", + "semi": true, + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "none", + "useTabs": false +} diff --git a/LICENSE b/LICENSE index 6af51a9..5ed68de 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1 @@ -MIT License - -Copyright (c) 2022 Polarity.io, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file +Copyright 2026 Dataminr, Inc. All rights reserved. diff --git a/README.md b/README.md index e257c9b..837bac5 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ * List of all detections associated with Host
- Host List Detections + Host List Detections
## About Qualys diff --git a/components/block.js b/components/block.js deleted file mode 100644 index fd19836..0000000 --- a/components/block.js +++ /dev/null @@ -1,74 +0,0 @@ -polarity.export = PolarityComponent.extend({ - details: Ember.computed.alias('block.data.details'), - summary: Ember.computed.alias('block.data.summary'), - tabKeys: Ember.computed.alias('details.tabKeys'), - timezone: Ember.computed('Intl', function () { - return Intl.DateTimeFormat().resolvedOptions().timeZone; - }), - expandableTitleStates: {}, - copiedStates: {}, - isRunningStates: {}, - messageStates: {}, - errorMessageStates: {}, - hostDetectionsFound: false, - activeTab: '', - init() { - const details = this.get('details'); - this.set( - 'activeTab', - this.get('tabKeys').find((tabKey) => details[tabKey] && details[tabKey].length) - ); - - this._super(...arguments); - }, - actions: { - changeTab: function (tabName) { - this.set('activeTab', tabName); - }, - toggleExpandableTitle: function ( - displayFieldIndex, - itemDisplayFieldsIndex, - fieldName - ) { - const modifiedExpandableTitleStates = Object.assign( - {}, - this.get('expandableTitleStates'), - { - [`${displayFieldIndex}${itemDisplayFieldsIndex}${fieldName}`]: !this.get( - 'expandableTitleStates' - )[`${displayFieldIndex}${itemDisplayFieldsIndex}${fieldName}`] - } - ); - - this.set(`expandableTitleStates`, modifiedExpandableTitleStates); - }, - copyField: function ( - displayFieldValue, - displayFieldIndex, - displayFieldLabel, - subIndex, - shouldCopyFieldLabel - ) { - navigator.clipboard.writeText( - `${shouldCopyFieldLabel ? `${displayFieldLabel}: ` : ''}${displayFieldValue}` - ); - - this.set( - `copiedStates`, - Object.assign({}, this.get('copiedStates'), { - [`${displayFieldIndex}${displayFieldLabel}${subIndex}`]: true - }) - ); - this.get('block').notifyPropertyChange('data'); - setTimeout(() => { - this.set( - `copiedStates`, - Object.assign({}, this.get('copiedStates'), { - [`${displayFieldIndex}${displayFieldLabel}${subIndex}`]: false - }) - ); - this.get('block').notifyPropertyChange('data'); - }, 3000); - } - } -}); diff --git a/config/config.js b/config/config.js deleted file mode 100644 index c13ad36..0000000 --- a/config/config.js +++ /dev/null @@ -1,65 +0,0 @@ -module.exports = { - name: 'Qualys', - acronym: 'QLS', - description: - "The Polarity Qualys Integration queries the Qualys Cloud Platform's Host Detection List and KnowledgeBase for IP Addresses, Domains, CVEs and QIDs.", - entityTypes: ['IPv4', 'IPv6'], - customTypes: [ - { - key: 'qid', - regex: /(?:QID|qid):\s*\d{1,8}/ - } - ], - defaultColor: 'light-purple', - styles: ['./styles/styles.less'], - onDemandOnly: true, - block: { - component: { - file: './components/block.js' - }, - template: { - file: './templates/block.hbs' - } - }, - request: { - cert: '', - key: '', - passphrase: '', - ca: '', - proxy: "" - }, - logging: { - level: 'info' //trace, debug, info, warn, error, fatal - }, - - options: [ - { - key: 'url', - name: 'Qualys URL', - description: - 'The URL of the Qualys you would like to connect to (including http:// or https://)', - default: '', - type: 'text', - userCanEdit: false, - adminOnly: true - }, - { - key: 'username', - name: 'Qualys Username', - description: 'The Username for your Qualys Account', - default: '', - type: 'text', - userCanEdit: false, - adminOnly: true - }, - { - key: 'password', - name: 'Qualys Password', - description: 'The Password associated with the Qualys Account', - default: '', - type: 'password', - userCanEdit: false, - adminOnly: true - } - ] -}; diff --git a/config/config.json b/config/config.json index 8806fd1..a6d8692 100644 --- a/config/config.json +++ b/config/config.json @@ -3,39 +3,31 @@ "name": "Qualys", "acronym": "QLS", "description": "The Polarity Qualys Integration queries the Qualys Cloud Platform's Host Detection List and KnowledgeBase for IP Addresses, Domains, CVEs and QIDs.", - "entityTypes": [ + "runtimeVersion": 2, + "defaultColor": "light-purple", + "onDemandOnly": true, + "dataTypes": [ "IPv4", "IPv6" ], - "customTypes": [ - { - "key": "qid", - "regex": "(?:QID|qid):\\s*\\d{1,8}" - } - ], - "defaultColor": "light-purple", - "styles": [ - "./styles/styles.less" - ], - "onDemandOnly": true, - "block": { - "component": { - "file": "./components/block.js" - }, - "template": { - "file": "./templates/block.hbs" - } - }, - "request": { - "cert": "", - "key": "", - "passphrase": "", - "ca": "", - "proxy": "" - }, "logging": { "level": "info" }, + "webComponents": { + "id": "512a1044-4cd2-4184-b120-48de15680389", + "moduleFilename": "web-components.mjs", + "components": [ + { + "type": "details", + "element": "px-int-4szfuj42ymklnvnabm9q4yt1l-qls-details-v4-0-0" + } + ] + }, + "reducer": { + "details": { + "file": "./reducers/details.json" + } + }, "options": [ { "key": "url", @@ -65,9 +57,10 @@ "adminOnly": true } ], - "reducer": { - "details": { - "file": "./reducers/details.json" + "customTypes": [ + { + "key": "qid", + "regex": "(?:QID|qid):\\s*\\d{1,8}" } - } -} \ No newline at end of file + ] +} diff --git a/assets/Host List Detections.png b/docs/Host List Detections.png similarity index 100% rename from assets/Host List Detections.png rename to docs/Host List Detections.png diff --git a/assets/KnowledgeBase Record.png b/docs/KnowledgeBase Record.png similarity index 100% rename from assets/KnowledgeBase Record.png rename to docs/KnowledgeBase Record.png diff --git a/assets/hostDetectionsFullExample.png b/docs/hostDetectionsFullExample.png similarity index 100% rename from assets/hostDetectionsFullExample.png rename to docs/hostDetectionsFullExample.png diff --git a/assets/knowledgeBaseFullExample.png b/docs/knowledgeBaseFullExample.png similarity index 100% rename from assets/knowledgeBaseFullExample.png rename to docs/knowledgeBaseFullExample.png diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..8040144 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,22 @@ +import eslint from '@eslint/js'; +import tseslint from 'typescript-eslint'; +import eslintConfigPrettier from 'eslint-config-prettier'; + +export default tseslint.config( + eslint.configs.recommended, + ...tseslint.configs.recommended, + eslintConfigPrettier, + { + ignores: ['dist/', 'node_modules/', 'mocks/', 'vite.config.js'] + }, + { + files: ['src/**/*.ts', 'web-components/**/*.ts'], + rules: { + '@typescript-eslint/no-explicit-any': 'warn', + '@typescript-eslint/no-unused-vars': [ + 'warn', + { argsIgnorePattern: '^_', varsIgnorePattern: '^_', caughtErrorsIgnorePattern: '^_' } + ] + } + } +); diff --git a/integration.js b/integration.js deleted file mode 100644 index 275ab19..0000000 --- a/integration.js +++ /dev/null @@ -1,62 +0,0 @@ -const createRequestWithDefaults = require('./src/createRequestWithDefaults'); -const { validateStringOptions, validateUrlOption } = require('./src/validateOptions'); -const { parseErrorToReadableJSON } = require('./src/dataTransformations'); -const { getLookupResults } = require('./src/getLookupResults'); - -let Logger; -let requestWithDefaults; - -const startup = async (logger) => { - Logger = logger; - requestWithDefaults = createRequestWithDefaults(Logger); -}; - -const doLookup = async (entities, options, cb) => { - Logger.debug({ entities }, 'Entities'); - - let lookupResults = []; - try { - lookupResults = await getLookupResults( - entities, - options, - requestWithDefaults, - Logger - ); - } catch (error) { - const err = parseErrorToReadableJSON(error); - Logger.error({ error, formattedError: err }, 'Get Lookup Results Failed'); - - return cb({ - detail: error.message ? error.message : 'Searching Failed', - err - }); - } - - Logger.trace({ lookupResults }, 'Lookup Results'); - cb(null, lookupResults); -}; - -const validateOptions = async (options, callback) => { - const stringOptionsErrorMessages = { - url: 'You must provide a valid Qualys URL.', - username: 'You must provide a valid Qualys Username', - password: 'You must provide a valid Qualys Password' - }; - - const stringValidationErrors = validateStringOptions( - stringOptionsErrorMessages, - options - ); - - const urlValidationErrors = validateUrlOption(options.url.value); - - const errors = stringValidationErrors.concat(urlValidationErrors); - - callback(null, errors); -}; - -module.exports = { - startup, - validateOptions, - doLookup -}; diff --git a/package-lock.json b/package-lock.json index c288ba4..f82fe96 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,343 +1,3929 @@ { "name": "qualys", - "version": "3.2.1", - "lockfileVersion": 1, + "version": "4.0.0", + "lockfileVersion": 3, "requires": true, - "dependencies": { - "@postman/form-data": { + "packages": { + "": { + "name": "qualys", + "version": "4.0.0", + "license": "UNLICENSED", + "dependencies": { + "lodash": "^4.17.21", + "polarity-integration-utils": "^4.1.0", + "xml2js": "^0.6.2" + }, + "devDependencies": { + "@eslint/js": "^10.0.1", + "@polarityio/integration-types": "^1.1.0", + "@polarityio/pi-components": "^1.9.3", + "@polarityio/vite-plugin-icl": "^1.0.1", + "@types/lodash": "^4.17.24", + "@types/xml2js": "^0.4.14", + "@vitest/browser": "^4.1.4", + "@vitest/browser-playwright": "^4.1.4", + "eslint": "^10.2.0", + "eslint-config-prettier": "^10.1.8", + "lit": "^3.3.2", + "playwright": "^1.59.1", + "prettier": "^3.8.3", + "typescript": "^5.9.3", + "typescript-eslint": "^8.58.2", + "vite": "^7.3.2", + "vitest": "^4.1.4" + } + }, + "node_modules/@blazediff/core": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@blazediff/core/-/core-1.9.1.tgz", + "integrity": "sha512-ehg3jIkYKulZh+8om/O25vkvSsXXwC+skXmyA87FFx6A/45eqOkZsBltMw/TVteb0mloiGT8oGRTcjRAz66zaA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", + "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.23.5", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz", + "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^3.0.5", + "debug": "^4.3.1", + "minimatch": "^10.2.4" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.5.tgz", + "integrity": "sha512-eIJYKTCECbP/nsKaaruF6LW967mtbQbsw4JTtSVkUQc9MneSkbrgPJAbKl9nWr0ZeowV8BfsarBmPpBzGelA2w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/core": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", + "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/js": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", + "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "eslint": "^10.0.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/@eslint/object-schema": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", + "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.1.tgz", + "integrity": "sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1", + "levn": "^0.4.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz", + "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", + "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.5", + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz", + "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@fortawesome/fontawesome-common-types": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-7.2.0.tgz", + "integrity": "sha512-IpR0bER9FY25p+e7BmFH25MZKEwFHTfRAfhOyJubgiDnoJNsSvJ7nigLraHtp4VOG/cy8D7uiV0dLkHOne5Fhw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/fontawesome-svg-core": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-7.2.0.tgz", + "integrity": "sha512-6639htZMjEkwskf3J+e6/iar+4cTNM9qhoWuRfj9F3eJD6r7iCzV1SWnQr2Mdv0QT0suuqU8BoJCZUyCtP9R4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@fortawesome/fontawesome-common-types": "7.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-solid-svg-icons": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-7.2.0.tgz", + "integrity": "sha512-YTVITFGN0/24PxzXrwqCgnyd7njDuzp5ZvaCx5nq/jg55kUYd94Nj8UTchBdBofi/L0nwRfjGOg0E41d2u9T1w==", + "dev": true, + "license": "(CC-BY-4.0 AND MIT)", + "dependencies": { + "@fortawesome/fontawesome-common-types": "7.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@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/@lit-labs/ssr-dom-shim": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.5.1.tgz", + "integrity": "sha512-Aou5UdlSpr5whQe8AA/bZG0jMj96CoJIWbGfZ91qieWu5AWUMKw8VR/pAkQkJYvBNhmCcWnZlyyk5oze8JIqYA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@lit/reactive-element": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.1.2.tgz", + "integrity": "sha512-pbCDiVMnne1lYUIaYNN5wrwQXDtHaYtg7YEFPeW+hws6U47WeFvISGUWekPGKWOP1ygrs0ef0o1VJMk1exos5A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.5.0" + } + }, + "node_modules/@polarityio/integration-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@polarityio/integration-types/-/integration-types-1.1.0.tgz", + "integrity": "sha512-AEsWN3N5z92Ld8kuLC9sQUJFshlN76vjWYvQS1xoUFsybx55vErPYGOrZl8FZnUkUuxr+phIpv0vp5XtCJ7Gzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@polarityio/pi-button": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@polarityio/pi-button/-/pi-button-1.0.4.tgz", + "integrity": "sha512-l6kPPQTXDw5pRQ3xQ5CIz4AKiwrvSrXmKYCXP/nR4rYagQJDs/vykzcPRfoeZi7loRclagzqNi3WWh23Np2tzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@fortawesome/fontawesome-svg-core": "^7.0.0", + "@fortawesome/free-solid-svg-icons": "^7.0.0", + "@polarityio/pi-shared": "1.0.3", + "@polarityio/pi-tooltip": "1.0.4" + }, + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-button/node_modules/@polarityio/pi-shared": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@polarityio/pi-shared/-/pi-shared-1.0.3.tgz", + "integrity": "sha512-emX5IT4sn1fNJBqABSDeXF+jv/RhTr8b+27jSTnnJ4Jas/APi4rWnZ203dqBI99PhYTV8cvePLabI5KOuKFg/g==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-button/node_modules/@polarityio/pi-tooltip": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@polarityio/pi-tooltip/-/pi-tooltip-1.0.4.tgz", + "integrity": "sha512-/q2b3wobIcmmE+EWzZAH995fmbsRZ7k3Usp/k0xadDXO/dU7kwgKdwat+P1rJ4ZNtvV/I9i9mDPsdimuQO6Tow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.6", + "@polarityio/pi-shared": "1.0.3" + }, + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-card": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@polarityio/pi-card/-/pi-card-1.2.3.tgz", + "integrity": "sha512-wsuUPNxqvQYSozt1XJ8j9I+Fiu9XfVNEaBSafSLyMn5BISdP9XGWkPomi9GqkzpMMBdXaWPk0q+GjYHEGFu5Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@fortawesome/fontawesome-svg-core": "^7.0.0", + "@fortawesome/free-solid-svg-icons": "^7.0.0", + "@polarityio/pi-icon": "1.0.3", + "@polarityio/pi-shared": "1.3.1" + }, + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-checkbox": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@polarityio/pi-checkbox/-/pi-checkbox-1.0.4.tgz", + "integrity": "sha512-QhuEoVNOHVG/zSRjG7s6iFNfcYhFqsbhFYSvnv9DD4DO1AmhZ83dmvxLkokKS+399jT/Nv5d2cYr9rmRsHj3rw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polarityio/pi-shared": "1.2.1" + }, + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-checkbox/node_modules/@polarityio/pi-shared": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@polarityio/pi-shared/-/pi-shared-1.2.1.tgz", + "integrity": "sha512-kNemzBeJKcN7QFHdnf1j1L+ImRjIYtRxBDJrlZEvRVKybNlnZwGPjAGyOTRsyAeMJ16HiOECnY/cNMeknEC9/w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-components": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@polarityio/pi-components/-/pi-components-1.9.3.tgz", + "integrity": "sha512-srGOiNZ7Ql+unJok+pZH2UExhrVg73941ospcFiHvsrCcLuM0tvCDW9LJ1QT+TfZwBaOSnEbEKbSoIeuPm7VOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polarityio/pi-button": "1.0.4", + "@polarityio/pi-card": "1.2.3", + "@polarityio/pi-checkbox": "1.0.4", + "@polarityio/pi-copy-button": "1.1.0", + "@polarityio/pi-error": "1.1.3", + "@polarityio/pi-external-link": "1.0.4", + "@polarityio/pi-icon": "1.0.3", + "@polarityio/pi-input": "1.0.5", + "@polarityio/pi-key-value": "1.2.3", + "@polarityio/pi-object-table": "1.0.5", + "@polarityio/pi-radio": "1.0.4", + "@polarityio/pi-retry-button": "1.0.1", + "@polarityio/pi-scroller": "1.0.2", + "@polarityio/pi-section-header": "1.0.5", + "@polarityio/pi-select": "1.0.4", + "@polarityio/pi-shared": "1.3.1", + "@polarityio/pi-show-more": "1.1.3", + "@polarityio/pi-spinner": "1.0.4", + "@polarityio/pi-summary-tag": "1.1.0", + "@polarityio/pi-tab": "1.2.2", + "@polarityio/pi-tag": "1.0.6", + "@polarityio/pi-tooltip": "1.0.5" + }, + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-copy-button": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@polarityio/pi-copy-button/-/pi-copy-button-1.1.0.tgz", + "integrity": "sha512-EmNUq1DnzrwBqhf9clzuY5cRr0wzuJj8ZWfYaoLrGWGlzhke52XVR3/sRShB4DzH8GkdpYgb7duLM5epyvvQMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@fortawesome/fontawesome-svg-core": "^7.2.0", + "@fortawesome/free-solid-svg-icons": "^7.0.0", + "@polarityio/pi-button": "1.0.4", + "@polarityio/pi-shared": "1.2.1", + "@polarityio/pi-tooltip": "1.0.5" + }, + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-copy-button/node_modules/@polarityio/pi-shared": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@polarityio/pi-shared/-/pi-shared-1.2.1.tgz", + "integrity": "sha512-kNemzBeJKcN7QFHdnf1j1L+ImRjIYtRxBDJrlZEvRVKybNlnZwGPjAGyOTRsyAeMJ16HiOECnY/cNMeknEC9/w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-error": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@polarityio/pi-error/-/pi-error-1.1.3.tgz", + "integrity": "sha512-aB7lqiD15axYvGBtUyjhhMduSQG1Myxnb/4K940NfcBS7prfEJbVjXsfJDexGJe1iUGKh5cCfEHeQ2fiQyp/5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@fortawesome/fontawesome-svg-core": "^7.0.0", + "@fortawesome/free-solid-svg-icons": "^7.0.0", + "@polarityio/pi-button": "1.0.4", + "@polarityio/pi-copy-button": "1.1.0", + "@polarityio/pi-icon": "1.0.3", + "@polarityio/pi-shared": "1.3.1" + }, + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-external-link": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@polarityio/pi-external-link/-/pi-external-link-1.0.4.tgz", + "integrity": "sha512-uKlNFq5V0UVnJ5zXI5DqZFvVtjjRMFFa2xaYRRpnOjX5vASlrIEXw/WBc7XM5QmOfEJ4t9yAIveA6d5OGy7I7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@fortawesome/free-solid-svg-icons": "^7.0.0", + "@polarityio/pi-icon": "1.0.3", + "@polarityio/pi-shared": "1.2.1", + "@polarityio/pi-tooltip": "1.0.5" + }, + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-external-link/node_modules/@polarityio/pi-shared": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@polarityio/pi-shared/-/pi-shared-1.2.1.tgz", + "integrity": "sha512-kNemzBeJKcN7QFHdnf1j1L+ImRjIYtRxBDJrlZEvRVKybNlnZwGPjAGyOTRsyAeMJ16HiOECnY/cNMeknEC9/w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-icon": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@polarityio/pi-icon/-/pi-icon-1.0.3.tgz", + "integrity": "sha512-NWQurGNSZvOST2lehdaqsc9T5X0mddMNlFPQOgI2YaZJVBwSAahq+j8sL5gUgnLiX/YH4hB/UxuWiWkuOuiPxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@fortawesome/fontawesome-svg-core": "^7.0.0", + "@fortawesome/free-solid-svg-icons": "^7.0.0", + "@polarityio/pi-shared": "1.0.3" + }, + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-icon/node_modules/@polarityio/pi-shared": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@polarityio/pi-shared/-/pi-shared-1.0.3.tgz", + "integrity": "sha512-emX5IT4sn1fNJBqABSDeXF+jv/RhTr8b+27jSTnnJ4Jas/APi4rWnZ203dqBI99PhYTV8cvePLabI5KOuKFg/g==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-input": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@polarityio/pi-input/-/pi-input-1.0.5.tgz", + "integrity": "sha512-AzKNCwUFuYQz9wfngkIqAFuHUEZF4jWHRLFxCOmRig6I0zx/nI5SQUQorZZPmyDxAnue5ilL/WaWHhXbiAGi9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polarityio/pi-shared": "1.2.1" + }, + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-input/node_modules/@polarityio/pi-shared": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@polarityio/pi-shared/-/pi-shared-1.2.1.tgz", + "integrity": "sha512-kNemzBeJKcN7QFHdnf1j1L+ImRjIYtRxBDJrlZEvRVKybNlnZwGPjAGyOTRsyAeMJ16HiOECnY/cNMeknEC9/w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-key-value": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@polarityio/pi-key-value/-/pi-key-value-1.2.3.tgz", + "integrity": "sha512-IEIbYMfTKzXcVWDpPJznECfJc1c6kAG5IJeB2HTrrX7X82wQopXX6wzeWJVZ97EYWWbGwO0+wt+IyaHDXAIUIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@fortawesome/free-solid-svg-icons": "^7.0.0", + "@polarityio/pi-icon": "1.0.3", + "@polarityio/pi-shared": "1.2.1", + "@polarityio/pi-tooltip": "1.0.5", + "date-fns": "^4.0.0" + }, + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-key-value/node_modules/@polarityio/pi-shared": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@polarityio/pi-shared/-/pi-shared-1.2.1.tgz", + "integrity": "sha512-kNemzBeJKcN7QFHdnf1j1L+ImRjIYtRxBDJrlZEvRVKybNlnZwGPjAGyOTRsyAeMJ16HiOECnY/cNMeknEC9/w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-object-table": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@polarityio/pi-object-table/-/pi-object-table-1.0.5.tgz", + "integrity": "sha512-NzYSXJL/SiGgAdn7SJJU2V/J8l2CbQEMu93pqywGF35MOnZ5bfWvLm4JkIHK7OjjCcFOo6vMLKMtSBrLfw7unw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polarityio/pi-shared": "1.3.1" + }, + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-radio": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@polarityio/pi-radio/-/pi-radio-1.0.4.tgz", + "integrity": "sha512-qhw7s0hJVdwcBH83LnCR02r6mheriI6kCFxVrJHx97/MLSvF70M7gmbDEU3skfGogzHueQ/TUw+o0jWAJRyInA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polarityio/pi-shared": "1.2.1" + }, + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-radio/node_modules/@polarityio/pi-shared": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@polarityio/pi-shared/-/pi-shared-1.2.1.tgz", + "integrity": "sha512-kNemzBeJKcN7QFHdnf1j1L+ImRjIYtRxBDJrlZEvRVKybNlnZwGPjAGyOTRsyAeMJ16HiOECnY/cNMeknEC9/w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-retry-button": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@polarityio/pi-retry-button/-/pi-retry-button-1.0.1.tgz", + "integrity": "sha512-z8DnVCTlmiUyDSFo6jP72qTeZgLPcIPLwKxZTtNZBFYC+BuRP8hXe4GVWXd7kSyymoJze0oHMD8Zl0nAAExmcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@fortawesome/fontawesome-svg-core": "^7.0.0", + "@fortawesome/free-solid-svg-icons": "^7.0.0", + "@polarityio/pi-button": "1.0.4", + "@polarityio/pi-shared": "1.2.0", + "@polarityio/pi-spinner": "1.0.3", + "@polarityio/pi-tooltip": "1.0.4" + }, + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-retry-button/node_modules/@polarityio/pi-shared": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@polarityio/pi-shared/-/pi-shared-1.2.0.tgz", + "integrity": "sha512-esRx4+jP9jmKdmXk1ZSyOMbiJ/IxjL+FKUw3iwn3HmX3LaNCBfgIAap/81+tA8Ocgvyr2EjWa1j+FN7ikr+sMg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-retry-button/node_modules/@polarityio/pi-spinner": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@polarityio/pi-spinner/-/pi-spinner-1.0.3.tgz", + "integrity": "sha512-TLwb+zzoLiS5sb858RZgcWJXtgZ/AnQ/W5hncPrvuHJLwltGZlkOX+juyQPeqtucWD/p7PexDTKoxHfCOyfbiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polarityio/pi-shared": "1.0.3" + }, + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-retry-button/node_modules/@polarityio/pi-spinner/node_modules/@polarityio/pi-shared": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@polarityio/pi-shared/-/pi-shared-1.0.3.tgz", + "integrity": "sha512-emX5IT4sn1fNJBqABSDeXF+jv/RhTr8b+27jSTnnJ4Jas/APi4rWnZ203dqBI99PhYTV8cvePLabI5KOuKFg/g==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-retry-button/node_modules/@polarityio/pi-tooltip": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@polarityio/pi-tooltip/-/pi-tooltip-1.0.4.tgz", + "integrity": "sha512-/q2b3wobIcmmE+EWzZAH995fmbsRZ7k3Usp/k0xadDXO/dU7kwgKdwat+P1rJ4ZNtvV/I9i9mDPsdimuQO6Tow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.6", + "@polarityio/pi-shared": "1.0.3" + }, + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-retry-button/node_modules/@polarityio/pi-tooltip/node_modules/@polarityio/pi-shared": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@polarityio/pi-shared/-/pi-shared-1.0.3.tgz", + "integrity": "sha512-emX5IT4sn1fNJBqABSDeXF+jv/RhTr8b+27jSTnnJ4Jas/APi4rWnZ203dqBI99PhYTV8cvePLabI5KOuKFg/g==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-scroller": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@polarityio/pi-scroller/-/pi-scroller-1.0.2.tgz", + "integrity": "sha512-d93nkdLxpiTcxMlaqO9VtqLiRsSor3JzYzIj7g8+5tiYWyR60q9TVHYiBrhSkgthp3MrfSqmbaYKtvraDR8HsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polarityio/pi-shared": "1.3.1" + }, + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-section-header": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@polarityio/pi-section-header/-/pi-section-header-1.0.5.tgz", + "integrity": "sha512-pjYHqnISsEchARTfjC72G9WnTHN4mdxW0u6X3dRiX+1EC82G8zFuNc4XoLgxb015hEYSn5xZGlsKkKJ5EfohLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@fortawesome/fontawesome-svg-core": "^7.0.0", + "@fortawesome/free-solid-svg-icons": "^7.0.0", + "@polarityio/pi-shared": "1.3.1" + }, + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-select": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@polarityio/pi-select/-/pi-select-1.0.4.tgz", + "integrity": "sha512-Frl7QLWDgQqUs83LABiEiKzyFjEVtrBRLJjMD1CotC1KcNluIi3yChi1KRZhBLfZr+pa9K0iTQsX6/AGP7/+xg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.6", + "@polarityio/pi-shared": "1.0.3" + }, + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-select/node_modules/@polarityio/pi-shared": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@polarityio/pi-shared/-/pi-shared-1.0.3.tgz", + "integrity": "sha512-emX5IT4sn1fNJBqABSDeXF+jv/RhTr8b+27jSTnnJ4Jas/APi4rWnZ203dqBI99PhYTV8cvePLabI5KOuKFg/g==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-shared": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@polarityio/pi-shared/-/pi-shared-1.3.1.tgz", + "integrity": "sha512-TXvKZBmFj9rqqZtSMImYLNVFtaYTCVJ69rPxrYBbOSOkoUvPWscCKP9zvT9xJHMaD7tjocI0gv7BvDc3H7grmg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-show-more": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@polarityio/pi-show-more/-/pi-show-more-1.1.3.tgz", + "integrity": "sha512-fZhwYRaw03tBEM3u+R/Y7wOcwnaq48ectu2GhE5ygpXNLx5dfyHg5huYKD9KX+JF6cUuOMPE4ogcGvGNaWcIWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polarityio/pi-button": "1.0.4", + "@polarityio/pi-shared": "1.3.1" + }, + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-spinner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@polarityio/pi-spinner/-/pi-spinner-1.0.4.tgz", + "integrity": "sha512-HsaWqOkzTMe6ZqaBZ3XBkv27BJ5dn5PJrgtOwShmVFQDDx0AY0Ijk8w2rVk6DaaYnBotCeTtw53gUZIR6X0Gow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polarityio/pi-shared": "1.2.1" + }, + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-spinner/node_modules/@polarityio/pi-shared": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@polarityio/pi-shared/-/pi-shared-1.2.1.tgz", + "integrity": "sha512-kNemzBeJKcN7QFHdnf1j1L+ImRjIYtRxBDJrlZEvRVKybNlnZwGPjAGyOTRsyAeMJ16HiOECnY/cNMeknEC9/w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-summary-tag": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@polarityio/pi-summary-tag/-/pi-summary-tag-1.1.0.tgz", + "integrity": "sha512-aR+AgZ9Vcro7u+TQYvM0qwhWxEXSGrkAXEmdZJaZPiAfVd8TXnwjWwZnyF/jF3ttuU0RPXXsgdhk6t8ijy3iKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@fortawesome/fontawesome-svg-core": "^7.0.0", + "@fortawesome/free-solid-svg-icons": "^7.0.0", + "@polarityio/pi-shared": "1.2.1" + }, + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-summary-tag/node_modules/@polarityio/pi-shared": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@polarityio/pi-shared/-/pi-shared-1.2.1.tgz", + "integrity": "sha512-kNemzBeJKcN7QFHdnf1j1L+ImRjIYtRxBDJrlZEvRVKybNlnZwGPjAGyOTRsyAeMJ16HiOECnY/cNMeknEC9/w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-tab": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@polarityio/pi-tab/-/pi-tab-1.2.2.tgz", + "integrity": "sha512-tqLT0kXTPmz/e0HWw9S3ogQ5KvN+4NZX5AYY0oW3hI4qtMRTJi/nilHCpgqrrsPPJlYRCWO8UkvBLMgrzDRMcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polarityio/pi-shared": "1.3.1" + }, + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-tag": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@polarityio/pi-tag/-/pi-tag-1.0.6.tgz", + "integrity": "sha512-H/Td6m/n1MOtafmskWgCDhdak2BsuTubpWYzS6OhvxcJcDTQ/b8g2bKG9F/6kFqQ0vYG0rG8mQzHm5E3pFVBrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@fortawesome/fontawesome-svg-core": "^7.0.0", + "@fortawesome/free-solid-svg-icons": "^7.0.0", + "@polarityio/pi-icon": "1.0.3", + "@polarityio/pi-shared": "1.3.1" + }, + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-tooltip": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@polarityio/pi-tooltip/-/pi-tooltip-1.0.5.tgz", + "integrity": "sha512-Ii0Y+j4ji0LGPKBSHZAfdhD5gvrvs++8RStaY591nan9cLDzSC9H3v8PTtUE2pKXsoVyjAk5xmbpLP539VAGKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.6", + "@polarityio/pi-shared": "1.2.1" + }, + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/pi-tooltip/node_modules/@polarityio/pi-shared": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@polarityio/pi-shared/-/pi-shared-1.2.1.tgz", + "integrity": "sha512-kNemzBeJKcN7QFHdnf1j1L+ImRjIYtRxBDJrlZEvRVKybNlnZwGPjAGyOTRsyAeMJ16HiOECnY/cNMeknEC9/w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@polarityio/vite-plugin-icl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@polarityio/vite-plugin-icl/-/vite-plugin-icl-1.0.1.tgz", + "integrity": "sha512-jKYwWlhENNOj4aQYqMcvnT/txKN/UdLW8F+tudjHTpm83TYE24JnpUVn7y6KwJ5a2w38cuPloGooymFCQs5u/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=24" + }, + "peerDependencies": { + "vite": ">=5" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "dev": true, + "license": "MIT" + }, + "node_modules/@postman/form-data": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/@postman/form-data/-/form-data-3.1.1.tgz", "integrity": "sha512-vjh8Q2a8S6UCm/KKs31XFJqEEgmbjBmpPNVV2eVav6905wyFAwaUOBGA1NPBI4ERH9MMZc6w0umFgM6WbEPMdg==", - "requires": { + "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" } }, - "@postman/tough-cookie": { + "node_modules/@postman/tough-cookie": { "version": "4.1.3-postman.1", "resolved": "https://registry.npmjs.org/@postman/tough-cookie/-/tough-cookie-4.1.3-postman.1.tgz", "integrity": "sha512-txpgUqZOnWYnUHZpHjkfb0IwVH4qJmyq77pPnJLlfhMtdCLMFTEeQHlzQiK906aaNCe4NEB5fGJHo9uzGbFMeA==", - "requires": { + "dependencies": { "psl": "^1.1.33", "punycode": "^2.1.1", "universalify": "^0.2.0", "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" } }, - "@postman/tunnel-agent": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@postman/tunnel-agent/-/tunnel-agent-0.6.3.tgz", - "integrity": "sha512-k57fzmAZ2PJGxfOA4SGR05ejorHbVAa/84Hxh/2nAztjNXc4ZjOm9NUIk6/Z6LCrBvJZqjRZbN8e/nROVUPVdg==", - "requires": { + "node_modules/@postman/tunnel-agent": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@postman/tunnel-agent/-/tunnel-agent-0.6.8.tgz", + "integrity": "sha512-2U42SmZW5G+suEcS++zB94sBWNO4qD4bvETGFRFDTqSpYl5ksfjcPqzYpgQgXgUmb6dfz+fAGbkcRamounGm0w==", + "license": "Apache-2.0", + "dependencies": { "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.3.tgz", + "integrity": "sha512-x35CNW/ANXG3hE/EZpRU8MXX1JDN86hBb2wMGAtltkz7pc6cxgjpy1OMMfDosOQ+2hWqIkag/fGok1Yady9nGw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.3.tgz", + "integrity": "sha512-xw3xtkDApIOGayehp2+Rz4zimfkaX65r4t47iy+ymQB2G4iJCBBfj0ogVg5jpvjpn8UWn/+q9tprxleYeNp3Hw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.3.tgz", + "integrity": "sha512-vo6Y5Qfpx7/5EaamIwi0WqW2+zfiusVihKatLvtN1VFVy3D13uERk/6gZLU1UiHRL6fDXqj/ELIeVRGnvcTE1g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.3.tgz", + "integrity": "sha512-D+0QGcZhBzTN82weOnsSlY7V7+RMmPuF1CkbxyMAGE8+ZHeUjyb76ZiWmBlCu//AQQONvxcqRbwZTajZKqjuOw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.3.tgz", + "integrity": "sha512-6HnvHCT7fDyj6R0Ph7A6x8dQS/S38MClRWeDLqc0MdfWkxjiu1HSDYrdPhqSILzjTIC/pnXbbJbo+ft+gy/9hQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.3.tgz", + "integrity": "sha512-KHLgC3WKlUYW3ShFKnnosZDOJ0xjg9zp7au3sIm2bs/tGBeC2ipmvRh/N7JKi0t9Ue20C0dpEshi8WUubg+cnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.3.tgz", + "integrity": "sha512-DV6fJoxEYWJOvaZIsok7KrYl0tPvga5OZ2yvKHNNYyk/2roMLqQAbGhr78EQ5YhHpnhLKJD3S1WFusAkmUuV5g==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.3.tgz", + "integrity": "sha512-mQKoJAzvuOs6F+TZybQO4GOTSMUu7v0WdxEk24krQ/uUxXoPTtHjuaUuPmFhtBcM4K0ons8nrE3JyhTuCFtT/w==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.3.tgz", + "integrity": "sha512-Whjj2qoiJ6+OOJMGptTYazaJvjOJm+iKHpXQM1P3LzGjt7Ff++Tp7nH4N8J/BUA7R9IHfDyx4DJIflifwnbmIA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.3.tgz", + "integrity": "sha512-4YTNHKqGng5+yiZt3mg77nmyuCfmNfX4fPmyUapBcIk+BdwSwmCWGXOUxhXbBEkFHtoN5boLj/5NON+u5QC9tg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.3.tgz", + "integrity": "sha512-SU3kNlhkpI4UqlUc2VXPGK9o886ZsSeGfMAX2ba2b8DKmMXq4AL7KUrkSWVbb7koVqx41Yczx6dx5PNargIrEA==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.3.tgz", + "integrity": "sha512-6lDLl5h4TXpB1mTf2rQWnAk/LcXrx9vBfu/DT5TIPhvMhRWaZ5MxkIc8u4lJAmBo6klTe1ywXIUHFjylW505sg==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.3.tgz", + "integrity": "sha512-BMo8bOw8evlup/8G+cj5xWtPyp93xPdyoSN16Zy90Q2QZ0ZYRhCt6ZJSwbrRzG9HApFabjwj2p25TUPDWrhzqQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.3.tgz", + "integrity": "sha512-E0L8X1dZN1/Rph+5VPF6Xj2G7JJvMACVXtamTJIDrVI44Y3K+G8gQaMEAavbqCGTa16InptiVrX6eM6pmJ+7qA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.3.tgz", + "integrity": "sha512-oZJ/WHaVfHUiRAtmTAeo3DcevNsVvH8mbvodjZy7D5QKvCefO371SiKRpxoDcCxB3PTRTLayWBkvmDQKTcX/sw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.3.tgz", + "integrity": "sha512-Dhbyh7j9FybM3YaTgaHmVALwA8AkUwTPccyCQ79TG9AJUsMQqgN1DDEZNr4+QUfwiWvLDumW5vdwzoeUF+TNxQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.3.tgz", + "integrity": "sha512-cJd1X5XhHHlltkaypz1UcWLA8AcoIi1aWhsvaWDskD1oz2eKCypnqvTQ8ykMNI0RSmm7NkTdSqSSD7zM0xa6Ig==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.3.tgz", + "integrity": "sha512-DAZDBHQfG2oQuhY7mc6I3/qB4LU2fQCjRvxbDwd/Jdvb9fypP4IJ4qmtu6lNjes6B531AI8cg1aKC2di97bUxA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.3.tgz", + "integrity": "sha512-cRxsE8c13mZOh3vP+wLDxpQBRrOHDIGOWyDL93Sy0Ga8y515fBcC2pjUfFwUe5T7tqvTvWbCpg1URM/AXdWIXA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.3.tgz", + "integrity": "sha512-QaWcIgRxqEdQdhJqW4DJctsH6HCmo5vHxY0krHSX4jMtOqfzC+dqDGuHM87bu4H8JBeibWx7jFz+h6/4C8wA5Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.3.tgz", + "integrity": "sha512-AaXwSvUi3QIPtroAUw1t5yHGIyqKEXwH54WUocFolZhpGDruJcs8c+xPNDRn4XiQsS7MEwnYsHW2l0MBLDMkWg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.3.tgz", + "integrity": "sha512-65LAKM/bAWDqKNEelHlcHvm2V+Vfb8C6INFxQXRHCvaVN1rJfwr4NvdP4FyzUaLqWfaCGaadf6UbTm8xJeYfEg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.3.tgz", + "integrity": "sha512-EEM2gyhBF5MFnI6vMKdX1LAosE627RGBzIoGMdLloPZkXrUN0Ckqgr2Qi8+J3zip/8NVVro3/FjB+tjhZUgUHA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.3.tgz", + "integrity": "sha512-E5Eb5H/DpxaoXH++Qkv28RcUJboMopmdDUALBczvHMf7hNIxaDZqwY5lK12UK1BHacSmvupoEWGu+n993Z0y1A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.3.tgz", + "integrity": "sha512-hPt/bgL5cE+Qp+/TPHBqptcAgPzgj46mPcg/16zNUmbQk0j+mOEQV/+Lqu8QRtDV3Ek95Q6FeFITpuhl6OTsAA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "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/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/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/lodash": { + "version": "4.17.24", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.24.tgz", + "integrity": "sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.7.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.7.0.tgz", + "integrity": "sha512-z+pdZyxE+RTQE9AcboAZCb4otwcrvgHD+GlBpPgn0emDVt0ohrTMhAwlr2Wd9nZ+nihhYFxO2pThz3C5qSu2Eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.21.0" + } + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/xml2js": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.4.14.tgz", + "integrity": "sha512-4YnrRemBShWRO2QjvUin8ESA41rH+9nQGLUGZV/1IDhi3SL9OhdpNC/MrulTWuptXKwhx/aDxE7toV0f/ypIXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.59.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.59.3.tgz", + "integrity": "sha512-PwFvSKsXGShKGW6n5bZOhGHEcCZXM8HofLK9fNsEwZXzFRjoY+XT1Vsf1zgyXdwTr0ZYz1/2tkZ0DBTT9jZjhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.59.3", + "@typescript-eslint/type-utils": "8.59.3", + "@typescript-eslint/utils": "8.59.3", + "@typescript-eslint/visitor-keys": "8.59.3", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.59.3", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.59.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.59.3.tgz", + "integrity": "sha512-HPwA+hVkfcriajbNvTmZv4VRauibay+cWArYUYq7u7W7PmGShMxbPxLvrwDme55a6d5alG3nrYfhyJ/G28XlLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.59.3", + "@typescript-eslint/types": "8.59.3", + "@typescript-eslint/typescript-estree": "8.59.3", + "@typescript-eslint/visitor-keys": "8.59.3", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.59.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.59.3.tgz", + "integrity": "sha512-ECiUWa/KYRGDFUqTNehaRgzDshnJfkTABJxVemHk4ko22gcr0ukloKjWvyQ64g8YCV/UI47kN1dbmjf/GaQYng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.59.3", + "@typescript-eslint/types": "^8.59.3", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.59.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.59.3.tgz", + "integrity": "sha512-t2LvZnoEfzKtnPjgeEu41xw5gxq9mQVfYy4OoZ4Vlt0sk3JwxmhCca/AR7DwOiHrjWgjAj6as4AhRLKSDfvZIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.59.3", + "@typescript-eslint/visitor-keys": "8.59.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.59.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.59.3.tgz", + "integrity": "sha512-PcIJHjmaREXLgIAIzLnSY9VucEzz8FKXsRgFa1DmdGCK/5tJpW03TKJF01Q6VZd1lLdz2sIKPWaDUZN9dp//dw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.59.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.59.3.tgz", + "integrity": "sha512-g71d8QD8UaiHGvrJwyIS1hCX5r63w6Jll+4VEYhEAHXTDIqX1JgxhTAbEHtKntL9kuc4jRo7/GWw5xfCepSccQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.59.3", + "@typescript-eslint/typescript-estree": "8.59.3", + "@typescript-eslint/utils": "8.59.3", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.59.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.59.3.tgz", + "integrity": "sha512-ePFoH0g4ludssdRFqqDxQePCxU4WQyRa9+XVwjm7yLn0FKhMeoetC+qBEEI1Eyb1pGSDveTIT09Bvw2WhlGayg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.59.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.59.3.tgz", + "integrity": "sha512-CbRjVRAf7Lr9Kr8RopKcbY45p2VfmmHrm0ygOCYFi7oU8q19m0Fs/6iHS7kNOmwpp+ob07ZVcAqlxUod9lYdmg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.59.3", + "@typescript-eslint/tsconfig-utils": "8.59.3", + "@typescript-eslint/types": "8.59.3", + "@typescript-eslint/visitor-keys": "8.59.3", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.59.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.59.3.tgz", + "integrity": "sha512-JAvT14goBzRzzzZyqq3P9BLArIxTtQURUtFgQ/V7FO+eU+Gg6ES+5ymOPP1wRxXcxAYeivCk4uS3jCKWI1K8Zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.59.3", + "@typescript-eslint/types": "8.59.3", + "@typescript-eslint/typescript-estree": "8.59.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.59.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.59.3.tgz", + "integrity": "sha512-f1UQF7ggd42YiwI5wGrRaPsa+P0CINBlrkLPmGfpq/u/I/oVtecoEIfFR9ag/oa1sLOsRNZ6xehf6qMZhQGBDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.59.3", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vitest/browser": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@vitest/browser/-/browser-4.1.6.tgz", + "integrity": "sha512-ynsspTubXGSpa58JFJ24xIQt4z4A25epSbugEyaTmmrV1//Wec9EgE/LtoaC6yxUrXi5P7erGHRrkdZIHaVQuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@blazediff/core": "1.9.1", + "@vitest/mocker": "4.1.6", + "@vitest/utils": "4.1.6", + "magic-string": "^0.30.21", + "pngjs": "^7.0.0", + "sirv": "^3.0.2", + "tinyrainbow": "^3.1.0", + "ws": "^8.19.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "vitest": "4.1.6" + } + }, + "node_modules/@vitest/browser-playwright": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@vitest/browser-playwright/-/browser-playwright-4.1.6.tgz", + "integrity": "sha512-4csoeyl/qwHyxU2zNL0++WaoDr8YJDXOQPwWPNJoTZ+QzcdO3INYKgF5Zfz730Io7zbkuv914aZmfQ+QE+1Hvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/browser": "4.1.6", + "@vitest/mocker": "4.1.6", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "playwright": "*", + "vitest": "4.1.6" + }, + "peerDependenciesMeta": { + "playwright": { + "optional": false + } + } + }, + "node_modules/@vitest/expect": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.6.tgz", + "integrity": "sha512-7EHDquPthALSV0jhhjgEW8FXaviMx7rSqu8W6oqCoAuOhKov814P99QDV1pxMA3QPv21YudvJngIhjrNI4opLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.6", + "@vitest/utils": "4.1.6", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.6.tgz", + "integrity": "sha512-MCFc63czMjEInOlcY2cpQCvCN+KgbAn+60xu9cMgP4sKaLC5JNAKw7JH8QdAnoAC88hW1IiSNZ+GgVXlN1UcMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.1.6", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.6.tgz", + "integrity": "sha512-h5SxD/IzNhZYnrSZRsUZQIC+vD0GY8cUvq0iwsmkFKixRCKLLWqCXa/FIQ4S1R+sI+PGoojkHsdNrbZiM9Qpgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.6.tgz", + "integrity": "sha512-nOPCmn2+yD0ZNmKdsXGv/UxMMWbMuKeD6GyYncNwdkYDxpQvrPSKYj2rWuDjC2Y4b6w6hjip5dBKFzEUuZe3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.1.6", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.6.tgz", + "integrity": "sha512-YhsdE6xAVfTDmzjxL2ZDUvjj+ZsgyOKe+TdQzqkD72wIOmHka8NuGQ6NpTNZv9D2Z63fbwWKJPeVpEw4EQgYxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.6", + "@vitest/utils": "4.1.6", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.6.tgz", + "integrity": "sha512-JFKxMx6udhwKh/Ldo270e17QX710vgunMkuPAvXjHSvC6oqLWAHhVhjg/I71q0u0CBSErIODV1Kjv0FQNSWjdg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.6.tgz", + "integrity": "sha512-FxIY+U81R3LGKCxaHHFRQ5+g6/iRgGLmeHWdp2Amj4ljQRrEIWHmZyDfDYBRZlpyqA7qKxtS9DD1dhk8RnRIVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.6", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "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": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" } }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "requires": { + "node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "asn1": { + "node_modules/asn1": { "version": "0.2.6", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "requires": { + "license": "MIT", + "dependencies": { "safer-buffer": "~2.1.0" } }, - "assert-plus": { + "node_modules/assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==" + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "license": "MIT", + "engines": { + "node": ">=0.8" + } }, - "asynckit": { + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, - "aws-sign2": { + "node_modules/aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==" + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "engines": { + "node": "*" + } }, - "aws4": { + "node_modules/aws4": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==" }, - "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/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } }, - "bcrypt-pbkdf": { + "node_modules/bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "requires": { + "license": "BSD-3-Clause", + "dependencies": { "tweetnacl": "^0.14.3" } }, - "bluebird": { + "node_modules/bluebird": { "version": "2.11.0", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", "integrity": "sha512-UfFSr22dmHPQqPP9XWHRhq+gWnHCYguQGkXQlbyPtW5qTnhFWA8/iXg765tH0cAjy7l/zPJ1aBTO0g5XgA7kvQ==" }, - "brotli": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz", - "integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==", - "requires": { - "base64-js": "^1.1.2" + "node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "caseless": { + "node_modules/caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" }, - "combined-stream": { + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "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==", - "requires": { + "dependencies": { "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" } }, - "core-util-is": { + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } }, - "dashdash": { + "node_modules/dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", - "requires": { + "license": "MIT", + "dependencies": { "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" } }, - "delayed-stream": { + "node_modules/date-fns": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } }, - "ecc-jsbn": { + "node_modules/ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "requires": { + "license": "MIT", + "dependencies": { "jsbn": "~0.1.0", "safer-buffer": "^2.1.0" } }, - "extend": { + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", + "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.3.0.tgz", + "integrity": "sha512-XbEXaRva5cF0ZQB8w6MluHA0kZZfV2DuCMJ3ozyEOHLwDpZX2Lmm/7Pp0xdJmI0GL1W05VH5VwIFHEm1Vcw2gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.5", + "@eslint/config-helpers": "^0.5.5", + "@eslint/core": "^1.2.1", + "@eslint/plugin-kit": "^0.7.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", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^9.1.2", + "eslint-visitor-keys": "^5.0.1", + "espree": "^11.2.0", + "esquery": "^1.7.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "minimatch": "^10.2.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-config-prettier": { + "version": "10.1.8", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", + "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "funding": { + "url": "https://opencollective.com/eslint-config-prettier" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, - "extsprintf": { + "node_modules/extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==" + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "engines": [ + "node >=0.6.0" + ], + "license": "MIT" }, - "fast-deep-equal": { + "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true }, - "fast-json-stable-stringify": { + "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } }, - "forever-agent": { + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true, + "license": "ISC" + }, + "node_modules/forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==" + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "engines": { + "node": "*" + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } }, - "getpass": { + "node_modules/getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "requires": { + "license": "MIT", + "dependencies": { "assert-plus": "^1.0.0" } }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==" - }, - "har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "requires": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - } - }, - "http-signature": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", - "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==", - "requires": { + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", + "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-signature": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.4.0.tgz", + "integrity": "sha512-G5akfn7eKbpDN+8nPS/cb57YeA1jLTVxjpCj7tmm3QKPdyDy7T+qSC40e9ptydSWvkwjSXw1VbkpyEm39ukeAg==", + "license": "MIT", + "dependencies": { "assert-plus": "^1.0.0", "jsprim": "^2.0.2", - "sshpk": "^1.14.1" + "sshpk": "^1.18.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/ip-address": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", + "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", + "license": "MIT", + "engines": { + "node": ">= 12" } }, - "is-typedarray": { + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" }, - "isstream": { + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" }, - "jsbn": { + "node_modules/jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==" + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "license": "MIT" }, - "json-schema": { + "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-schema": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "license": "(AFL-2.1 OR BSD-3-Clause)" }, - "json-schema-traverse": { + "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==" + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "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" }, - "json-stringify-safe": { + "node_modules/json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" }, - "jsprim": { + "node_modules/jsprim": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==", - "requires": { + "engines": [ + "node >=0.6.0" + ], + "license": "MIT", + "dependencies": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", "json-schema": "0.4.0", "verror": "1.10.0" } }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lit": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/lit/-/lit-3.3.2.tgz", + "integrity": "sha512-NF9zbsP79l4ao2SNrH3NkfmFgN/hBYSQo90saIVI1o5GpjAdCPVstVzO1MrLOakHoEhYkrtRjPK6Ob521aoYWQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@lit/reactive-element": "^2.1.0", + "lit-element": "^4.2.0", + "lit-html": "^3.3.0" + } + }, + "node_modules/lit-element": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-4.2.2.tgz", + "integrity": "sha512-aFKhNToWxoyhkNDmWZwEva2SlQia+jfG0fjIWV//YeTaWrVnOxD89dPKfigCUspXFmjzOEUQpOkejH5Ly6sG0w==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.5.0", + "@lit/reactive-element": "^2.1.0", + "lit-html": "^3.3.0" + } + }, + "node_modules/lit-html": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.3.2.tgz", + "integrity": "sha512-Qy9hU88zcmaxBXcc10ZpdK7cOLXvXpRoBxERdtqV9QOrfpMZZ6pSYP91LhpPtap3sFMUiL7Tw2RImbe0Al2/kw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@types/trusted-types": "^2.0.2" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "license": "MIT" + }, + "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": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } }, - "mime-db": { + "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==" + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } }, - "mime-types": { + "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==", - "requires": { + "dependencies": { "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "oauth-sign": { + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "engines": { + "node": "*" + } }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" - }, - "postman-request": { - "version": "2.88.1-postman.33", - "resolved": "https://registry.npmjs.org/postman-request/-/postman-request-2.88.1-postman.33.tgz", - "integrity": "sha512-uL9sCML4gPH6Z4hreDWbeinKU0p0Ke261nU7OvII95NU22HN6Dk7T/SaVPaj6T4TsQqGKIFw6/woLZnH7ugFNA==", - "requires": { + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obug": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT" + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/playwright": { + "version": "1.60.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.60.0.tgz", + "integrity": "sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.60.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.60.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.60.0.tgz", + "integrity": "sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/pngjs": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz", + "integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.19.0" + } + }, + "node_modules/polarity-integration-utils": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/polarity-integration-utils/-/polarity-integration-utils-4.1.0.tgz", + "integrity": "sha512-WcrOJ8CQ/FPcfk5C37QeagOVdzEDE/CumxwVeBoDkCKsOtByDe4u2zcQGwP+o0Ws4xnlfbNVa5lOKgL6KZgpWw==", + "license": "MIT", + "dependencies": { + "lodash": "^4.18.1", + "postman-request": "^2.88.1-postman.48" + }, + "peerDependencies": { + "@polarityio/integration-types": ">=1.1.0" + } + }, + "node_modules/postcss": { + "version": "8.5.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz", + "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postman-request": { + "version": "2.88.1-postman.48", + "resolved": "https://registry.npmjs.org/postman-request/-/postman-request-2.88.1-postman.48.tgz", + "integrity": "sha512-E32FGh8ig2KDvzo4Byi7Ibr+wK2gNKPSqXoNsvjdCHgDBxSK4sCUwv+aa3zOBUwfiibPImHMy0WdlDSSCTqTuw==", + "license": "Apache-2.0", + "dependencies": { "@postman/form-data": "~3.1.1", "@postman/tough-cookie": "~4.1.3-postman.1", - "@postman/tunnel-agent": "^0.6.3", + "@postman/tunnel-agent": "^0.6.8", "aws-sign2": "~0.7.0", "aws4": "^1.12.0", - "brotli": "^1.3.3", "caseless": "~0.12.0", "combined-stream": "~1.0.6", "extend": "~3.0.2", "forever-agent": "~0.6.1", - "har-validator": "~5.1.3", - "http-signature": "~1.3.1", + "http-signature": "~1.4.0", "is-typedarray": "~1.0.0", "isstream": "~0.1.2", "json-stringify-safe": "~5.0.1", "mime-types": "^2.1.35", "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.3", + "qs": "~6.14.1", "safe-buffer": "^5.1.2", + "socks-proxy-agent": "^8.0.5", "stream-length": "^1.0.2", "uuid": "^8.3.2" + }, + "engines": { + "node": ">= 16" } }, - "psl": { + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz", + "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" }, - "punycode": { + "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==" + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "engines": { + "node": ">=6" + } }, - "qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==" + "node_modules/qs": { + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", + "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "querystringify": { + "node_modules/querystringify": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" }, - "requires-port": { + "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==" }, - "safe-buffer": { + "node_modules/rollup": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.3.tgz", + "integrity": "sha512-pAQK9HalE84QSm4Po3EmWIZPd3FnjkShVkiMlz1iligWYkWQ7wHYd1PF/T7QZ5TVSD6uSTon5gBVMSM4JfBV+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@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.3", + "@rollup/rollup-android-arm64": "4.60.3", + "@rollup/rollup-darwin-arm64": "4.60.3", + "@rollup/rollup-darwin-x64": "4.60.3", + "@rollup/rollup-freebsd-arm64": "4.60.3", + "@rollup/rollup-freebsd-x64": "4.60.3", + "@rollup/rollup-linux-arm-gnueabihf": "4.60.3", + "@rollup/rollup-linux-arm-musleabihf": "4.60.3", + "@rollup/rollup-linux-arm64-gnu": "4.60.3", + "@rollup/rollup-linux-arm64-musl": "4.60.3", + "@rollup/rollup-linux-loong64-gnu": "4.60.3", + "@rollup/rollup-linux-loong64-musl": "4.60.3", + "@rollup/rollup-linux-ppc64-gnu": "4.60.3", + "@rollup/rollup-linux-ppc64-musl": "4.60.3", + "@rollup/rollup-linux-riscv64-gnu": "4.60.3", + "@rollup/rollup-linux-riscv64-musl": "4.60.3", + "@rollup/rollup-linux-s390x-gnu": "4.60.3", + "@rollup/rollup-linux-x64-gnu": "4.60.3", + "@rollup/rollup-linux-x64-musl": "4.60.3", + "@rollup/rollup-openbsd-x64": "4.60.3", + "@rollup/rollup-openharmony-arm64": "4.60.3", + "@rollup/rollup-win32-arm64-msvc": "4.60.3", + "@rollup/rollup-win32-ia32-msvc": "4.60.3", + "@rollup/rollup-win32-x64-gnu": "4.60.3", + "@rollup/rollup-win32-x64-msvc": "4.60.3", + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup/node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/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==" + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" }, - "safer-buffer": { + "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" }, - "sax": { + "node_modules/sax": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==" }, - "sshpk": { + "node_modules/semver": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "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/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/sirv": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", + "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.9.tgz", + "integrity": "sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==", + "license": "MIT", + "dependencies": { + "ip-address": "^10.1.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sshpk": { "version": "1.18.0", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", - "requires": { + "license": "MIT", + "dependencies": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", "bcrypt-pbkdf": "^1.0.0", @@ -347,71 +3933,495 @@ "jsbn": "~0.1.0", "safer-buffer": "^2.0.2", "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" } }, - "stream-length": { + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz", + "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/stream-length": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/stream-length/-/stream-length-1.0.2.tgz", "integrity": "sha512-aI+qKFiwoDV4rsXiS7WRoCt+v2RX1nUj17+KJC5r2gfh5xoSJIfP6Y3Do/HtvesFcTSWthIuJ3l1cvKQY/+nZg==", - "requires": { + "dependencies": { "bluebird": "^2.6.2" } }, - "tweetnacl": { + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.2.tgz", + "integrity": "sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyrainbow": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", + "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==" + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "license": "Unlicense" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.59.3", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.59.3.tgz", + "integrity": "sha512-KgusgyDgG4LI8Ih/sWaCtZ06tckLAS5CvT5A4D1Q7bYVoAAyzwiZvE4BmwDHkhRVkvhRBepKeASoFzQetha7Fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.59.3", + "@typescript-eslint/parser": "8.59.3", + "@typescript-eslint/typescript-estree": "8.59.3", + "@typescript-eslint/utils": "8.59.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/undici-types": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.21.0.tgz", + "integrity": "sha512-w9IMgQrz4O0YN1LtB7K5P63vhlIOvC7opSmouCJ+ZywlPAlO9gIkJ+otk6LvGpAs2wg4econaCz3TvQ9xPoyuQ==", + "dev": true, + "license": "MIT" }, - "universalify": { + "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==" + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "engines": { + "node": ">= 4.0.0" + } }, - "uri-js": { + "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "requires": { + "dev": true, + "dependencies": { "punycode": "^2.1.0" } }, - "url-parse": { + "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==", - "requires": { + "dependencies": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" } }, - "uuid": { + "node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", + "bin": { + "uuid": "dist/bin/uuid" + } }, - "verror": { + "node_modules/verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", - "requires": { + "engines": [ + "node >=0.6.0" + ], + "license": "MIT", + "dependencies": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", "extsprintf": "^1.2.0" } }, - "xml2js": { + "node_modules/vite": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.3.tgz", + "integrity": "sha512-/4XH147Ui7OGTjg3HbdWe5arnZQSbfuRzdr9Ec7TQi5I7R+ir0Rlc9GIvD4v0XZurELqA035KVXJXpR61xhiTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/vitest": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.6.tgz", + "integrity": "sha512-6lvjbS3p9b4CrdCmguzbh2/4uoXhGE2q71R4OX5sqF9R1bo9Xd6fGrMAfvp5wnCzlBnFVdCOp6onuTQVbo8iUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.1.6", + "@vitest/mocker": "4.1.6", + "@vitest/pretty-format": "4.1.6", + "@vitest/runner": "4.1.6", + "@vitest/snapshot": "4.1.6", + "@vitest/spy": "4.1.6", + "@vitest/utils": "4.1.6", + "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": "^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.6", + "@vitest/browser-preview": "4.1.6", + "@vitest/browser-webdriverio": "4.1.6", + "@vitest/coverage-istanbul": "4.1.6", + "@vitest/coverage-v8": "4.1.6", + "@vitest/ui": "4.1.6", + "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/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "vite": { + "optional": false + } + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ws": { + "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": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml2js": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", - "requires": { + "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" } }, - "xmlbuilder": { + "node_modules/xmlbuilder": { "version": "11.0.1", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/package.json b/package.json index 029b409..4a1f6c5 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,44 @@ { "name": "qualys", - "version": "3.2.1", - "main": "./integration.js", + "version": "4.0.0", + "main": "./dist/integration.js", "private": true, - "license": "MIT", + "license": "UNLICENSED", "author": "Polarity", "dependencies": { "lodash": "^4.17.21", - "postman-request": "^2.88.1-postman.33", + "polarity-integration-utils": "^4.1.0", "xml2js": "^0.6.2" + }, + "devDependencies": { + "@eslint/js": "^10.0.1", + "@polarityio/integration-types": "^1.1.0", + "@polarityio/pi-components": "^1.9.3", + "@polarityio/vite-plugin-icl": "^1.0.1", + "@types/lodash": "^4.17.24", + "@types/xml2js": "^0.4.14", + "@vitest/browser": "^4.1.4", + "@vitest/browser-playwright": "^4.1.4", + "eslint": "^10.2.0", + "eslint-config-prettier": "^10.1.8", + "lit": "^3.3.2", + "playwright": "^1.59.1", + "prettier": "^3.8.3", + "typescript": "^5.9.3", + "typescript-eslint": "^8.58.2", + "vite": "^7.3.2", + "vitest": "^4.1.4" + }, + "scripts": { + "build": "tsc && vite build", + "typecheck": "tsc --noEmit && tsc -p tsconfig.web.json", + "lint": "eslint src/ web-components/", + "lint:fix": "eslint src/ web-components/ --fix", + "format": "prettier --write 'src/**/*.ts' 'web-components/**/*.ts'", + "format:check": "prettier --check 'src/**/*.ts' 'web-components/**/*.ts'", + "test": "vitest run", + "test:server": "vitest run --project server", + "test:browser": "vitest run --project browser", + "test:watch": "vitest" } } diff --git a/src/associateDataWithEntities.js b/src/associateDataWithEntities.js deleted file mode 100644 index 89b6631..0000000 --- a/src/associateDataWithEntities.js +++ /dev/null @@ -1,39 +0,0 @@ -const { map, toLower, filter, flow, replace, includes, get, concat, uniqBy, flatMap } = require('lodash/fp'); - -const associateDataWithEntities = ( - entities, - { allHostDetections, allFoundKnowledgeBaseRecords }, - Logger -) => - map((entity) => { - const knowledgeBaseRecords = getObjectsContainingString( - entity.value, - allFoundKnowledgeBaseRecords - ); - const hostDetections = flow( - flatMap(({ qid }) => getObjectsContainingString(qid, allHostDetections)), - concat(getObjectsContainingString(entity.value, allHostDetections)), - uniqBy('id') - )(knowledgeBaseRecords); - - return { - entity, - results: { - hostDetections, - knowledgeBaseRecords - } - }; - }, entities); - -const getObjectsContainingString = (string, objs) => - filter( - flow( - JSON.stringify, - replace(/[^\w]/g, ''), - toLower, - includes(flow(replace(/[^\w]/g, ''), toLower)(string)) - ), - objs - ); - -module.exports = associateDataWithEntities; diff --git a/src/associateDataWithEntities.ts b/src/associateDataWithEntities.ts new file mode 100644 index 0000000..e695f80 --- /dev/null +++ b/src/associateDataWithEntities.ts @@ -0,0 +1,47 @@ +import { map, toLower, filter, flow, replace, includes, concat, uniqBy, flatMap } from 'lodash/fp'; +import type { Entity } from '@polarityio/integration-types'; + +/* eslint-disable @typescript-eslint/no-explicit-any */ + +export interface EntityData { + allHostDetections: any[]; + allFoundKnowledgeBaseRecords: any[] | undefined; +} + +export interface EntityWithResults { + entity: Entity; + results: { + hostDetections: any[]; + knowledgeBaseRecords: any[]; + }; +} + +const associateDataWithEntities = ( + entities: Entity[], + { allHostDetections, allFoundKnowledgeBaseRecords }: EntityData +): EntityWithResults[] => + map((entity: Entity) => { + const knowledgeBaseRecords = getObjectsContainingString( + entity.value, + allFoundKnowledgeBaseRecords || [] + ); + const hostDetections = flow( + flatMap(({ qid }: any) => getObjectsContainingString(qid, allHostDetections)), + concat(getObjectsContainingString(entity.value, allHostDetections)), + uniqBy('id') + )(knowledgeBaseRecords); + return { entity, results: { hostDetections, knowledgeBaseRecords } }; + }, entities); + +const getObjectsContainingString = (string: string, objs: any[]): any[] => + filter( + flow( + JSON.stringify, + replace(/[^\w]/g, ''), + toLower, + includes(flow(replace(/[^\w]/g, ''), toLower)(string)) + ), + objs + ); + +export default associateDataWithEntities; diff --git a/src/constants.js b/src/constants.ts similarity index 67% rename from src/constants.js rename to src/constants.ts index 8672634..2c130ca 100644 --- a/src/constants.js +++ b/src/constants.ts @@ -1,12 +1,9 @@ -const IGNORED_IPS = new Set(['127.0.0.1', '255.255.255.255', '0.0.0.0']); +export const IGNORED_IPS = new Set(['127.0.0.1', '255.255.255.255', '0.0.0.0']); -const QUERY_PATHS_BY_TYPE = { +export const QUERY_PATHS_BY_TYPE: Record> = { qid: { assets: ['name'], - vulnerabilities: [ - 'vulnerabilities.vulnerability.qid', - 'vulnerabilities.vulnerability.title' - ] + vulnerabilities: ['vulnerabilities.vulnerability.qid', 'vulnerabilities.vulnerability.title'] }, cve: { assets: ['name'], @@ -14,38 +11,44 @@ const QUERY_PATHS_BY_TYPE = { }, domain: { assets: ['name', 'interfaces.hostname'], - vulnerabilities: [ - 'vulnerabilities.hostAssetName', - 'vulnerabilities.vulnerability.title' - ] + vulnerabilities: ['vulnerabilities.hostAssetName', 'vulnerabilities.vulnerability.title'] }, IPv4: { - assets: [ - 'interfaces.address', - 'name', - 'interfaces.dnsAddress', - 'interfaces.gatewayAddress' - ], + assets: ['interfaces.address', 'name', 'interfaces.dnsAddress', 'interfaces.gatewayAddress'], vulnerabilities: ['vulnerabilities.vulnerability.title'] }, IPv6: { - assets: [ - 'interfaces.address', - 'name', - 'interfaces.dnsAddress', - 'interfaces.gatewayAddress' - ], + assets: ['interfaces.address', 'name', 'interfaces.dnsAddress', 'interfaces.gatewayAddress'], vulnerabilities: ['vulnerabilities.vulnerability.title'] } }; -const SEARCH_COLUMN_NAMES_BY_TYPE = { +export const SEARCH_COLUMN_NAMES_BY_TYPE: Record = { cve: ['title', 'category', 'diagnosis', 'solution', 'cves', 'vender_references'], qid: ['qid'], default: ['title', 'diagnosis', 'solution', 'vender_references'] }; -const HOST_DETECTION_DISPLAY_FORMAT = { +export interface DisplayFormatEntry { + label?: string; + isTitle?: boolean; + isDate?: boolean; + isList?: boolean; + isListOfLinks?: boolean; + isHtml?: boolean; + isNewSectionLineBreak?: boolean; + indent?: number; + collapsibleListItems?: boolean; + showLabelAndValue?: boolean; + fieldIsCopyable?: boolean; + shouldCopyFieldLabel?: boolean; + itemDisplayFormat?: DisplayFormat; +} + +export type DisplayFormatValue = string | DisplayFormatEntry; +export type DisplayFormat = Record; + +export const HOST_DETECTION_DISPLAY_FORMAT: DisplayFormat = { ip: { label: 'IP Address', isTitle: true, showLabelAndValue: true }, id: 'Host Detection ID', asset_id: 'Asset Id', @@ -82,7 +85,7 @@ const HOST_DETECTION_DISPLAY_FORMAT = { newSectionLineBreak: { isNewSectionLineBreak: true } }; -const KNOWLEDGE_BASE_RECORD_DISPLAY_FORMAT = { +export const KNOWLEDGE_BASE_RECORD_DISPLAY_FORMAT: DisplayFormat = { title: { isTitle: true }, qid: { label: 'QID', fieldIsCopyable: true, shouldCopyFieldLabel: true }, severity: 'Severity', @@ -101,11 +104,3 @@ const KNOWLEDGE_BASE_RECORD_DISPLAY_FORMAT = { solution: { label: 'Solution', isHtml: true }, newSectionLineBreak: { isNewSectionLineBreak: true } }; - -module.exports = { - IGNORED_IPS, - QUERY_PATHS_BY_TYPE, - SEARCH_COLUMN_NAMES_BY_TYPE, - KNOWLEDGE_BASE_RECORD_DISPLAY_FORMAT, - HOST_DETECTION_DISPLAY_FORMAT -}; diff --git a/src/createLookupResults.js b/src/createLookupResults.js deleted file mode 100644 index 8696fb9..0000000 --- a/src/createLookupResults.js +++ /dev/null @@ -1,57 +0,0 @@ -const { - flow, - get, - map, - size, - mapValues, - some, - identity, - keys, - assign, - eq -} = require('lodash/fp'); - -const { HOST_DETECTION_DISPLAY_FORMAT } = require('./constants'); -const getDisplayResults = require('./getDisplayResults'); - -const createLookupResults = (foundEntities, Logger) => - map(({ entity, results }) => { - const formattedQueryResult = formatQueryResult(results); - - const lookupResult = { - entity, - displayValue: entity.type === 'qid' ? `QID: ${entity.value}` : entity.value, - data: !!formattedQueryResult - ? { - summary: createSummary(entity, results, Logger), - details: flow(keys, (keys) => - assign(formattedQueryResult, { - tabKeys: keys - }) - )(formattedQueryResult) - } - : null - }; - - return lookupResult; - }, foundEntities); - -const createSummary = (entity, { hostDetections, knowledgeBaseRecords }, Logger) => - [].concat(size(hostDetections) ? `Host Detections: ${size(hostDetections)}` : []); - -const formatQueryResult = (result) => { - const resultNotEmpty = flow(mapValues(size), some(identity))(result); - - if (resultNotEmpty) { - const hostDetections = getDisplayResults( - HOST_DETECTION_DISPLAY_FORMAT, - result.hostDetections - ); - - return { - hostDetections - }; - } -}; - -module.exports = createLookupResults; diff --git a/src/createLookupResults.ts b/src/createLookupResults.ts new file mode 100644 index 0000000..c8170d5 --- /dev/null +++ b/src/createLookupResults.ts @@ -0,0 +1,46 @@ +import { flow, map, size, mapValues, some, identity, keys, assign } from 'lodash/fp'; +import type { Entity } from '@polarityio/integration-types'; +import type { LookupResult } from '@polarityio/integration-types'; + +import { HOST_DETECTION_DISPLAY_FORMAT } from './constants'; +import getDisplayResults from './getDisplayResults'; +import type { EntityWithResults } from './associateDataWithEntities'; + +/* eslint-disable @typescript-eslint/no-explicit-any */ + +const createLookupResults = (foundEntities: EntityWithResults[]): LookupResult[] => + map(({ entity, results }: EntityWithResults) => { + const formattedQueryResult = formatQueryResult(results); + const lookupResult: LookupResult = { + entity, + displayValue: (entity.type as string) === 'qid' ? `QID: ${entity.value}` : entity.value, + data: formattedQueryResult + ? { + summary: createSummary(entity, results), + details: flow(keys, (k: string[]) => assign(formattedQueryResult, { tabKeys: k }))( + formattedQueryResult + ) + } + : null + }; + return lookupResult; + }, foundEntities); + +const createSummary = ( + _entity: Entity, + { hostDetections }: { hostDetections: any[]; knowledgeBaseRecords: any[] } +): string[] => + ([] as string[]).concat(size(hostDetections) ? `Host Detections: ${size(hostDetections)}` : []); + +const formatQueryResult = (result: { + hostDetections: any[]; + knowledgeBaseRecords: any[]; +}): Record | undefined => { + const resultNotEmpty = flow(mapValues(size), some(identity))(result); + if (resultNotEmpty) { + const hostDetections = getDisplayResults(HOST_DETECTION_DISPLAY_FORMAT, result.hostDetections); + return { hostDetections }; + } +}; + +export default createLookupResults; diff --git a/src/createRequestWithDefaults.js b/src/createRequestWithDefaults.js deleted file mode 100644 index 21aa6dd..0000000 --- a/src/createRequestWithDefaults.js +++ /dev/null @@ -1,115 +0,0 @@ -const fs = require('fs'); -const { identity, omit } = require('lodash/fp'); -const request = require('postman-request'); -const config = require('../config/config'); -const { parseErrorToReadableJSON } = require('./dataTransformations'); - -const SUCCESSFUL_ROUNDED_REQUEST_STATUS_CODES = [200]; - -const _configFieldIsValid = (field) => typeof field === 'string' && field.length > 0; - -const createRequestWithDefaults = (Logger) => { - const { - request: { ca, cert, key, passphrase, rejectUnauthorized, proxy } - } = config; - - const defaults = { - ...(_configFieldIsValid(ca) && { ca: fs.readFileSync(ca) }), - ...(_configFieldIsValid(cert) && { cert: fs.readFileSync(cert) }), - ...(_configFieldIsValid(key) && { key: fs.readFileSync(key) }), - ...(_configFieldIsValid(passphrase) && { passphrase }), - ...(_configFieldIsValid(proxy) && { proxy }), - ...(typeof rejectUnauthorized === 'boolean' && { rejectUnauthorized }), - json: true - }; - - const requestWithDefaults = ( - preRequestFunction = async () => ({}), - postRequestSuccessFunction = async (x) => x, - postRequestFailureFunction = async (e) => { - throw e; - } - ) => { - const defaultsRequest = request.defaults(defaults); - - const _requestWithDefault = (requestOptions) => - new Promise((resolve, reject) => { - defaultsRequest(requestOptions, (err, res, body) => { - if (err) return reject(err); - resolve({ ...res, body }); - }); - }); - - return async (requestOptions) => { - const preRequestFunctionResults = await preRequestFunction(requestOptions); - const _requestOptions = { - ...requestOptions, - ...preRequestFunctionResults - }; - - let postRequestFunctionResults; - try { - const result = await _requestWithDefault(_requestOptions); - checkForStatusError(result, _requestOptions); - - postRequestFunctionResults = await postRequestSuccessFunction( - result, - _requestOptions - ); - } catch (error) { - postRequestFunctionResults = await postRequestFailureFunction( - error, - _requestOptions - ); - } - return postRequestFunctionResults; - }; - }; - - const handleAuth = async ({ options, ...requestOptions }) => ({ - ...requestOptions, - auth: { - username: options.username, - password: options.password, - } - }); - - const checkForStatusError = ({ statusCode, body }, requestOptions) => { - Logger.trace({ - requestOptions: { - ...requestOptions, - auth: '************', - options: '************' - }, - statusCode, - body - }); - - const roundedStatus = Math.round(statusCode / 100) * 100; - if (!SUCCESSFUL_ROUNDED_REQUEST_STATUS_CODES.includes(roundedStatus)) { - const requestError = Error('Request Error'); - requestError.status = statusCode; - requestError.description = JSON.stringify(body); - requestError.requestOptions = JSON.stringify(requestOptions); - throw requestError; - } - }; - - const requestDefaultsWithInterceptors = requestWithDefaults(handleAuth, identity, (error) => { - const err = parseErrorToReadableJSON(error); - if (err.requestOptions && ['{', '['].includes(err.requestOptions[0])) - err.requestOptions = omit(['options', 'auth'], JSON.parse(err.requestOptions)); - - Logger.error({ err }); - let newError = new Error(err.message) - newError.status = err.status; - newError.requestOptions = JSON.stringify(err.requestOptions); - newError.description = err.description; - newError.stack = err.stack; - throw newError; - }); - - return requestDefaultsWithInterceptors; -}; - -module.exports = createRequestWithDefaults; diff --git a/src/dataTransformations.js b/src/dataTransformations.js deleted file mode 100644 index 0937448..0000000 --- a/src/dataTransformations.js +++ /dev/null @@ -1,216 +0,0 @@ -const _ = require('lodash'); -const { - flow, - keys, - values, - zipObject, - map, - first, - omit, - reduce, - size, - negate, - curry, - filter, - eq, - isEmpty, - getOr, - join, - get, - isArray, - identity -} = require('lodash/fp'); - -const { IGNORED_IPS, QUERY_PATHS_BY_TYPE } = require('./constants'); - -const getKeys = (keys, items) => - Array.isArray(items) - ? items.map((item) => _.pickBy(item, (v, key) => keys.includes(key))) - : _.pickBy(items, (v, key) => keys.includes(key)); - -const groupEntities = (entities) => - _.chain(entities) - .groupBy(({ isIP, isDomain, type }) => - isIP - ? 'ip' - : isDomain - ? 'domain' - : type === 'MAC' - ? 'mac' - : type === 'MD5' - ? 'md5' - : type === 'SHA1' - ? 'sha1' - : type === 'SHA256' - ? 'sha256' - : 'unknown' - ) - .omit('unknown') - .value(); - -const splitOutIgnoredIps = (_entitiesPartition) => { - const { ignoredIPs, entitiesPartition } = _.groupBy( - _entitiesPartition, - ({ isIP, value }) => - !isIP || (isIP && !IGNORED_IPS.has(value)) ? 'entitiesPartition' : 'ignoredIPs' - ); - - return { - entitiesPartition, - ignoredIpLookupResults: _.map(ignoredIPs, (entity) => ({ - entity, - data: null - })) - }; -}; - -const objectPromiseAll = async (obj = { fn1: async () => {} }) => { - const labels = keys(obj); - const functions = values(obj); - const executedFunctions = await Promise.all(map((func) => func(), functions)); - - return zipObject(labels, executedFunctions); -}; - -const asyncObjectReduce = async (func, initAgg, obj) => { - const nextKey = flow(keys, first)(obj); - - if (!nextKey) return initAgg; - - const newAgg = await func(initAgg, obj[nextKey], nextKey); - - return await asyncObjectReduce(func, newAgg, omit(nextKey, obj)); -}; - -const transpose2DArray = reduce( - (agg, [key, value]) => [ - [...agg[0], key], - [...agg[1], value] - ], - [[], []] -); - -const or = - (...[func, ...funcs]) => - (x) => - func(x) || (funcs.length && or(...funcs)(x)); - -const and = - (...[func, ...funcs]) => - (x) => - func(x) && (funcs.length ? and(...funcs)(x) : true); - -// func: (value, key) => [newKey, newValue], obj: { key1:value1, key2:value2 } -// return { newKey1: newValue1, newKey2: newValue2 } -const mapObject = curry((func, obj) => - flow( - Object.entries, - map(([key, value]) => func(value, key)), - filter(and(negate(isEmpty), flow(size, eq(2)))), - transpose2DArray, - ([keys, values]) => zipObject(keys, values) - )(obj) -); - -const mapObjectAsync = async (func, obj) => { - // func: (value, key) => [newKey, newValue], obj: { key1:value1, key2:value2 } - // return { newKey1: newValue1, newKey2: newValue2 } - const unzippedResults = await Promise.all( - map(async ([key, value]) => await func(value, key), Object.entries(obj)) - ); - - return flow( - filter(and(negate(isEmpty), flow(size, eq(2)))), - transpose2DArray, - ([keys, values]) => zipObject(keys, values) - )(unzippedResults); -}; - -const parseErrorToReadableJSON = (error) => - JSON.parse(JSON.stringify(error, Object.getOwnPropertyNames(error))); - -const buildQueryByQueryType = (queryType, entities) => - flow( - map((entity) => - flow( - getOr([], [entity.type, queryType]), - map((queryPath) => `${queryPath}: "${entity.value}"`), - join(' OR ') - )(QUERY_PATHS_BY_TYPE) - ), - join(' OR ') - )(entities); - -const millisToHoursMinutesAndSeconds = (millis) => { - let remainingMillis = millis; - - const seconds = Math.floor((remainingMillis / 1000) % 60); - remainingMillis -= seconds * 1000; - - const minutes = Math.floor((remainingMillis / 60000) % 60); - remainingMillis -= minutes * 60000; - - const hours = Math.floor(remainingMillis / 3600000); - - return ( - (hours ? `${hours} hours, ` : '') + - (minutes ? `${minutes} minutes, ` : '') + - (seconds ? `${seconds} seconds` : '') + - (!hours && !minutes && !seconds ? `${millis}ms` : '') - ); -}; - -const processResultWithProcessingFormat = (processingFormat) => (result) => - mapObject( - (value, key) => [ - key, - typeof value === 'string' - ? get(value, result) - : flow(get(value.path), value.process)(result) - ], - processingFormat - ); - -const processPossibleList = - (shouldStringify = true) => - (arrayOrObject) => - arrayOrObject && - (shouldStringify ? JSON.stringify : identity)( - isArray(arrayOrObject) ? arrayOrObject : [arrayOrObject] - ); - -const xml2js = require('xml2js'); - -const xmlToJson = async (xml, Logger) => { - try { - const parser = new xml2js.Parser({ - normalizeTags: true, - explicitArray: false, - charkey: 'value', - attrkey: 'attributes' - }); - return await parser.parseStringPromise(xml); - } catch (e) { - const err = parseErrorToReadableJSON(e); - Logger.error({ MESSAGE: 'Failed to Parse XML', xml, err }); - } -}; - -module.exports = { - getKeys, - groupEntities, - splitOutIgnoredIps, - objectPromiseAll, - asyncObjectReduce, - mapObject, - mapObjectAsync, - transpose2DArray, - parseErrorToReadableJSON, - buildQueryByQueryType, - millisToHoursMinutesAndSeconds, - processResultWithProcessingFormat, - processPossibleList, - xmlToJson, - and, - or -}; diff --git a/src/dataTransformations.ts b/src/dataTransformations.ts new file mode 100644 index 0000000..c022dc7 --- /dev/null +++ b/src/dataTransformations.ts @@ -0,0 +1,211 @@ +import _ from 'lodash'; +import { + flow, + keys, + values, + zipObject, + map, + first, + omit, + reduce, + size, + curry, + filter, + eq, + isEmpty, + getOr, + join, + get, + isArray, + identity +} from 'lodash/fp'; +import * as xml2js from 'xml2js'; +import type { Logger } from '@polarityio/integration-types'; +import type { Entity } from '@polarityio/integration-types'; + +import { IGNORED_IPS, QUERY_PATHS_BY_TYPE } from './constants'; + +/* eslint-disable @typescript-eslint/no-explicit-any */ + +export const getKeys = (keyList: string[], items: any): any => + Array.isArray(items) + ? items.map((item: any) => _.pickBy(item, (_v: any, key: string) => keyList.includes(key))) + : _.pickBy(items, (_v: any, key: string) => keyList.includes(key)); + +export const groupEntities = (entities: Entity[]): Record => + _.chain(entities) + .groupBy(({ isIP, isDomain, type }: any) => + isIP + ? 'ip' + : isDomain + ? 'domain' + : type === 'MAC' + ? 'mac' + : type === 'MD5' + ? 'md5' + : type === 'SHA1' + ? 'sha1' + : type === 'SHA256' + ? 'sha256' + : 'unknown' + ) + .omit('unknown') + .value(); + +export const splitOutIgnoredIps = ( + _entitiesPartition: Entity[] +): { entitiesPartition: Entity[]; ignoredIpLookupResults: any[] } => { + const grouped = _.groupBy(_entitiesPartition, ({ isIP, value }: any) => + !isIP || (isIP && !IGNORED_IPS.has(value)) ? 'entitiesPartition' : 'ignoredIPs' + ); + + return { + entitiesPartition: grouped.entitiesPartition || [], + ignoredIpLookupResults: _.map(grouped.ignoredIPs, (entity: Entity) => ({ + entity, + data: null + })) + }; +}; + +export const objectPromiseAll = async ( + obj: Record Promise> +): Promise> => { + const labels = keys(obj); + const functions = values(obj); + const executedFunctions = await Promise.all(map((func: () => Promise) => func(), functions)); + return zipObject(labels, executedFunctions); +}; + +export const asyncObjectReduce = async ( + func: (agg: any, value: any, key: string) => Promise, + initAgg: any, + obj: Record +): Promise => { + const nextKey = flow(keys, first)(obj) as string | undefined; + if (!nextKey) return initAgg; + const newAgg = await func(initAgg, obj[nextKey], nextKey); + return await asyncObjectReduce(func, newAgg, omit(nextKey, obj) as Record); +}; + +export const transpose2DArray = reduce( + (agg: [any[], any[]], [key, value]: [any, any]) => + [ + [...agg[0], key], + [...agg[1], value] + ] as [any[], any[]], + [[], []] as [any[], any[]] +); + +export const or = + (...[func, ...funcs]: Array<(x: any) => boolean>) => + (x: any): boolean => + func(x) || (funcs.length > 0 && or(...funcs)(x)); + +export const and = + (...[func, ...funcs]: Array<(x: any) => boolean>) => + (x: any): boolean => + func(x) && (funcs.length > 0 ? and(...funcs)(x) : true); + +const negate = + (fn: (x: any) => boolean) => + (x: any): boolean => + !fn(x); + +export const mapObject = curry( + (func: (value: any, key: string) => any, obj: Record): Record => + flow( + Object.entries, + map(([key, value]: [string, any]) => func(value, key)), + filter(and(negate(isEmpty), flow(size, eq(2)))), + transpose2DArray, + ([k, v]: [string[], any[]]) => zipObject(k, v) + )(obj) +); + +export const mapObjectAsync = async ( + func: (value: any, key: string) => Promise, + obj: Record +): Promise> => { + const unzippedResults = await Promise.all( + map(async ([key, value]: [string, any]) => await func(value, key), Object.entries(obj)) + ); + return flow( + filter(and(negate(isEmpty), flow(size, eq(2)))), + transpose2DArray, + ([k, v]: [string[], any[]]) => zipObject(k, v) + )(unzippedResults); +}; + +export const parseErrorToReadableJSON = (error: unknown): Record => { + const serialized = JSON.parse(JSON.stringify(error, Object.getOwnPropertyNames(error as object))); + delete serialized.config; + delete serialized.request; + delete serialized.options; + delete serialized.auth; + return serialized; +}; + +export const buildQueryByQueryType = (queryType: string, entities: Entity[]): string => + flow( + map((entity: Entity) => + flow( + getOr([], [entity.type, queryType]), + map((queryPath: string) => `${queryPath}: "${entity.value}"`), + join(' OR ') + )(QUERY_PATHS_BY_TYPE as any) + ), + join(' OR ') + )(entities); + +export const millisToHoursMinutesAndSeconds = (millis: number): string => { + let remainingMillis = millis; + const seconds = Math.floor((remainingMillis / 1000) % 60); + remainingMillis -= seconds * 1000; + const minutes = Math.floor((remainingMillis / 60000) % 60); + remainingMillis -= minutes * 60000; + const hours = Math.floor(remainingMillis / 3600000); + return ( + (hours ? `${hours} hours, ` : '') + + (minutes ? `${minutes} minutes, ` : '') + + (seconds ? `${seconds} seconds` : '') + + (!hours && !minutes && !seconds ? `${millis}ms` : '') + ); +}; + +export const processResultWithProcessingFormat = + (processingFormat: Record) => + (result: any): Record => + mapObject( + (value: any, key: string) => [ + key, + typeof value === 'string' + ? get(value, result) + : flow(get(value.path), value.process)(result) + ], + processingFormat + ); + +export const processPossibleList = + (shouldStringify = true) => + (arrayOrObject: any): any => + arrayOrObject && + (shouldStringify ? JSON.stringify : identity)( + isArray(arrayOrObject) ? arrayOrObject : [arrayOrObject] + ); + +export const xmlToJson = async (xml: string, Logger: Logger): Promise => { + try { + const parser = new xml2js.Parser({ + normalizeTags: true, + explicitArray: false, + charkey: 'value', + attrkey: 'attributes' + }); + return await parser.parseStringPromise(xml); + } catch (e) { + const err = parseErrorToReadableJSON(e); + Logger.error({ MESSAGE: 'Failed to Parse XML', err }, 'XML Parse Failed'); + Logger.trace({ xml }, 'Raw XML that failed to parse'); + } +}; diff --git a/src/getDisplayResults.js b/src/getDisplayResults.js deleted file mode 100644 index 0fc256c..0000000 --- a/src/getDisplayResults.js +++ /dev/null @@ -1,40 +0,0 @@ -const { flow, get, map, values, assign, flatMap } = require('lodash/fp'); - -const { mapObject } = require('./dataTransformations'); - -const getDisplayResults = (displayFormat, results, dontFlatten) => - (dontFlatten ? map : flatMap)((record) => { - const displayResultsAsObject = mapObject( - (contentInfo, columnName) => - (get(columnName, record) || - get('isTitle', contentInfo) || - get('isNewSectionLineBreak', contentInfo)) && [ - columnName, - buildDisplayValue(contentInfo, columnName, record) - ], - displayFormat - ); - - const displayResults = values(displayResultsAsObject); - - return displayResults; - }, results); - -const buildDisplayValue = (contentInfo, columnName, record) => - typeof contentInfo === 'string' - ? { label: contentInfo, value: get(columnName, record) } - : assign(contentInfo, { - value: flow(get(columnName), (value) => - contentInfo.isListOfLinks - ? JSON.parse(value) - : contentInfo.isList - ? getDisplayResults( - contentInfo.itemDisplayFormat, - get(columnName, record), - true - ) - : value - )(record) - }); - -module.exports = getDisplayResults; diff --git a/src/getDisplayResults.ts b/src/getDisplayResults.ts new file mode 100644 index 0000000..fb17b34 --- /dev/null +++ b/src/getDisplayResults.ts @@ -0,0 +1,48 @@ +import { flow, get, map, values, assign, flatMap } from 'lodash/fp'; +import { mapObject } from './dataTransformations'; +import type { DisplayFormat, DisplayFormatEntry } from './constants'; + +/* eslint-disable @typescript-eslint/no-explicit-any */ + +const getDisplayResults = ( + displayFormat: DisplayFormat, + results: any[], + dontFlatten?: boolean +): any[] => + (dontFlatten ? map : (flatMap as any))((record: any) => { + const displayResultsAsObject = mapObject( + (contentInfo: any, columnName: string) => + (get(columnName, record) || + get('isTitle', contentInfo) || + get('isNewSectionLineBreak', contentInfo)) && [ + columnName, + buildDisplayValue(contentInfo, columnName, record) + ], + displayFormat + ); + const displayResults = values(displayResultsAsObject); + return displayResults; + }, results); + +const buildDisplayValue = ( + contentInfo: string | DisplayFormatEntry, + columnName: string, + record: any +): any => + typeof contentInfo === 'string' + ? { label: contentInfo, value: get(columnName, record) } + : assign(contentInfo, { + value: flow(get(columnName), (value: any) => + (contentInfo as DisplayFormatEntry).isListOfLinks + ? JSON.parse(value) + : (contentInfo as DisplayFormatEntry).isList + ? getDisplayResults( + (contentInfo as DisplayFormatEntry).itemDisplayFormat!, + get(columnName, record), + true + ) + : value + )(record) + }); + +export default getDisplayResults; diff --git a/src/getLookupResults.js b/src/getLookupResults.js deleted file mode 100644 index 190270f..0000000 --- a/src/getLookupResults.js +++ /dev/null @@ -1,67 +0,0 @@ -const { flow, map, split, first, last, trim, concat, get, uniqBy } = require('lodash/fp'); - -const { splitOutIgnoredIps } = require('./dataTransformations'); -const createLookupResults = require('./createLookupResults'); -const queryHostDetectionListForAllEntities = require('./querying/queryHostDetectionListForAllEntities'); -const associateDataWithEntities = require('./associateDataWithEntities'); - -const getLookupResults = async ( - entities, - options, - requestWithDefaults, - Logger -) => { - const entitiesWithCustomTypesSpecified = map(({ type, types, value, ...entity }) => { - type = type === 'custom' ? flow(first, split('.'), last)(types) : type; - - return { - ...entity, - type, - value: type === 'qid' ? flow(split(':'), last, trim)(value) : value - }; - }, entities); - - const { entitiesPartition, ignoredIpLookupResults } = splitOutIgnoredIps( - entitiesWithCustomTypesSpecified - ); - - const data = await getData( - entitiesPartition, - options, - requestWithDefaults, - Logger - ); - - const foundEntities = associateDataWithEntities(entitiesPartition, data, Logger); - const lookupResults = createLookupResults(foundEntities, Logger); - - return lookupResults.concat(ignoredIpLookupResults); -}; - -const getData = async ( - entitiesPartition, - options, - requestWithDefaults, - Logger -) => { - const [initialHostDetections, allFoundKnowledgeBaseRecords] = await Promise.all([ - queryHostDetectionListForAllEntities( - entitiesPartition, - options, - requestWithDefaults, - Logger - ) - ]); - - const allHostDetections = flow( - uniqBy('id') - )(initialHostDetections); - - Logger.trace({ allHostDetections }, 'All Host Detections'); - - return { allHostDetections, allFoundKnowledgeBaseRecords }; -}; - -module.exports = { - getLookupResults -}; diff --git a/src/getLookupResults.ts b/src/getLookupResults.ts new file mode 100644 index 0000000..9ca66eb --- /dev/null +++ b/src/getLookupResults.ts @@ -0,0 +1,53 @@ +import { flow, map, split, first, last, trim, uniqBy } from 'lodash/fp'; +import type { Entity, Logger } from '@polarityio/integration-types'; +import type { PolarityRequest } from 'polarity-integration-utils'; + +import { splitOutIgnoredIps } from './dataTransformations'; +import createLookupResults from './createLookupResults'; +import queryHostDetectionListForAllEntities from './querying/queryHostDetectionListForAllEntities'; +import associateDataWithEntities from './associateDataWithEntities'; + +/* eslint-disable @typescript-eslint/no-explicit-any */ + +export const getLookupResults = async ( + entities: Entity[], + options: Record, + request: PolarityRequest, + Logger: Logger +): Promise => { + const entitiesWithCustomTypesSpecified: Entity[] = map((entity: Entity) => { + const type: string = + entity.type === 'custom' + ? (flow(first, split('.'), last)(entity.types) as string) + : entity.type; + const value = + type === 'qid' ? (flow(split(':'), last, trim)(entity.value) as string) : entity.value; + + return { ...entity, type, value } as Entity; + }, entities); + + const { entitiesPartition, ignoredIpLookupResults } = splitOutIgnoredIps( + entitiesWithCustomTypesSpecified + ); + + const data = await getData(entitiesPartition, options, request, Logger); + const foundEntities = associateDataWithEntities(entitiesPartition, data); + const lookupResults = createLookupResults(foundEntities); + return lookupResults.concat(ignoredIpLookupResults); +}; + +const getData = async ( + entitiesPartition: Entity[], + options: Record, + request: PolarityRequest, + Logger: Logger +): Promise => { + const [initialHostDetections] = await Promise.all([ + queryHostDetectionListForAllEntities(entitiesPartition, options, request, Logger) + ]); + + const allHostDetections = flow(uniqBy('id'))(initialHostDetections); + Logger.trace({ allHostDetections }, 'All Host Detections'); + + return { allHostDetections, allFoundKnowledgeBaseRecords: undefined }; +}; diff --git a/src/integration.ts b/src/integration.ts new file mode 100644 index 0000000..696a04d --- /dev/null +++ b/src/integration.ts @@ -0,0 +1,78 @@ +import { PolarityRequest, setLogger } from 'polarity-integration-utils'; +import { IntegrationError } from 'polarity-integration-utils'; +import type { + Entity, + DoLookupUserOptions, + DoLookupResult, + Logger, + IntegrationContext, + ValidateOptionsUserOptions, + ValidationError +} from '@polarityio/integration-types'; +import type { BeforeRequestHook } from 'polarity-integration-utils'; + +import { parseErrorToReadableJSON } from './dataTransformations'; +import { getLookupResults } from './getLookupResults'; +import { validateStringOptions, validateUrlOption } from './validateOptions'; + +let request: PolarityRequest; + +const addAuth: BeforeRequestHook = async (requestOptions, userOptions) => ({ + ...requestOptions, + auth: { + username: userOptions.username as string, + password: userOptions.password as string + } +}); + +function startup(logger: Logger): void { + setLogger(logger); + request = new PolarityRequest({ + roundedSuccessStatusCodes: [200], + hooks: { beforeRequest: [addAuth] } + }); +} + +async function doLookup( + entities: Entity[], + options: DoLookupUserOptions, + context: IntegrationContext +): Promise { + const Logger = context.logger; + Logger.debug({ entities }, 'Entities'); + + request.userOptions = options; + + try { + const lookupResults = await getLookupResults(entities, options, request, Logger); + Logger.trace({ lookupResults }, 'Lookup Results'); + return lookupResults; + } catch (error) { + const err = parseErrorToReadableJSON(error); + Logger.error({ formattedError: err }, 'Get Lookup Results Failed'); + + throw new IntegrationError( + (error as Error).message ? (error as Error).message : 'Searching Failed', + { cause: error, meta: { formattedError: err } } + ); + } +} + +function validateOptions( + options: ValidateOptionsUserOptions, + _context: IntegrationContext +): ValidationError[] { + const stringOptionsErrorMessages: Record = { + url: 'You must provide a valid Qualys URL.', + username: 'You must provide a valid Qualys Username', + password: 'You must provide a valid Qualys Password' + }; + + const stringValidationErrors = validateStringOptions(stringOptionsErrorMessages, options); + + const urlValidationErrors = validateUrlOption(options.url.value as string); + + return stringValidationErrors.concat(urlValidationErrors); +} + +export { startup, doLookup, validateOptions }; diff --git a/src/querying/queryAssetsForAllEntities.js b/src/querying/queryAssetsForAllEntities.js deleted file mode 100644 index 811dcdf..0000000 --- a/src/querying/queryAssetsForAllEntities.js +++ /dev/null @@ -1,72 +0,0 @@ -const { getOr, size, flow, concat, uniqBy } = require('lodash/fp'); -const { - parseErrorToReadableJSON, - buildQueryByQueryType -} = require('../dataTransformations'); - -const ASSET_QUERY_FIELDS = - 'id,name,host,createdAt,tags,sourceInfo,activationModules,activationModulesPending,' + - 'activationModulesNoProfileFound,activationModulesQueuedManifestGen,updatedAt,' + - 'criticalityScore,isDefaultCriticalityScore,criticalityScoreUpdated,lastVmScanDate,' + - 'lastComplianceScanDate'; - -const limit = 200; - -const queryAssetsForAllEntities = async ( - entities, - options, - requestWithDefaults, - Logger, - offset = 0, - allAssets = [] -) => { - try { - const assetQuery = buildQueryByQueryType('assets', entities); - - const assetsData = getOr( - [], - 'body', - await requestWithDefaults({ - uri: `${options.url}/portal-front/rest/assetview/1.0/assets`, - qs: { - havingQuery: assetQuery, - fields: ASSET_QUERY_FIELDS, - order: '-updatedAt', - includeAssets: true, - limit, - offset - }, - options - }) - ); - - const foundAssets = flow(concat(assetsData), uniqBy('id'))(allAssets); - - if (size(assetsData) === 200) { - return await queryAssetsForAllEntities( - entities, - options, - requestWithDefaults, - Logger, - offset + limit, - foundAssets - ); - } - - return foundAssets; - } catch (error) { - const err = parseErrorToReadableJSON(error); - Logger.error( - { - detail: 'Failed to Query Assets', - options, - formattedError: err - }, - 'Query Assets Failed' - ); - - throw error; - } -}; - -module.exports = queryAssetsForAllEntities; diff --git a/src/querying/queryAssetsForAllEntities.ts b/src/querying/queryAssetsForAllEntities.ts new file mode 100644 index 0000000..0adc08d --- /dev/null +++ b/src/querying/queryAssetsForAllEntities.ts @@ -0,0 +1,60 @@ +import { size, flow, concat, uniqBy } from 'lodash/fp'; +import type { Entity, Logger } from '@polarityio/integration-types'; +import type { PolarityRequest } from 'polarity-integration-utils'; + +import { parseErrorToReadableJSON, buildQueryByQueryType } from '../dataTransformations'; + +/* eslint-disable @typescript-eslint/no-explicit-any */ + +const ASSET_QUERY_FIELDS = 'id,name,host,createdAt,tags,sourceInfo,activationModules,...'; +const limit = 200; + +const queryAssetsForAllEntities = async ( + entities: Entity[], + options: Record, + request: PolarityRequest, + Logger: Logger, + offset = 0, + allAssets: any[] = [] +): Promise => { + try { + const assetQuery = buildQueryByQueryType('assets', entities); + + const response = await request.run({ + url: `${options.url}/portal-front/rest/assetview/1.0/assets`, + qs: { + havingQuery: assetQuery, + fields: ASSET_QUERY_FIELDS, + order: '-updatedAt', + includeAssets: true, + limit, + offset + } + }); + + const assetsData = (response!.body as any[]) || []; + const foundAssets = flow(concat(assetsData), uniqBy('id'))(allAssets); + + if (size(assetsData) === 200) { + return await queryAssetsForAllEntities( + entities, + options, + request, + Logger, + offset + limit, + foundAssets + ); + } + + return foundAssets; + } catch (error) { + const err = parseErrorToReadableJSON(error); + Logger.error( + { detail: 'Failed to Query Assets', url: options.url, formattedError: err }, + 'Query Assets Failed' + ); + throw error; + } +}; + +export default queryAssetsForAllEntities; diff --git a/src/querying/queryHostDetectionListForAllEntities.js b/src/querying/queryHostDetectionListForAllEntities.js deleted file mode 100644 index 23e9665..0000000 --- a/src/querying/queryHostDetectionListForAllEntities.js +++ /dev/null @@ -1,140 +0,0 @@ -const { identity } = require('lodash'); -const { - get, - getOr, - map, - flow, - filter, - eq, - uniqBy, - join, - cond, - size -} = require('lodash/fp'); - -const { - parseErrorToReadableJSON, - processResultWithProcessingFormat, - processPossibleList, - xmlToJson, - or -} = require('../dataTransformations'); - -const queryHostDetectionListForAllEntities = async ( - entities, - options, - requestWithDefaults, - Logger -) => { - const allHostDetectionResultForIpAddresses = await flow( - filter(flow(get('type'), or(eq('IPv4'), eq('IPv6')))), - map(get('value')), - cond([[size, queryHostDetectionList('ips', options, requestWithDefaults, Logger)]]) - )(entities); - - const allHostDetectionResultForQids = await flow( - filter(flow(get('type'), eq('qid'))), - map(get('value')), - cond([[size, queryHostDetectionList('qids', options, requestWithDefaults, Logger)]]) - )(entities); - - return uniqBy('id', allHostDetectionResultForIpAddresses).concat( - uniqBy('id', allHostDetectionResultForQids) - ); -}; - -const queryHostDetectionList = - (type, options, requestWithDefaults, Logger) => async (entityValues) => { - try { - const responseXml = getOr( - '', - 'body', - await requestWithDefaults({ - method: 'GET', - url: `${options.url}/api/2.0/fo/asset/host/vm/detection/`, - qs: { - action: 'list', - [type]: join(',', entityValues), - show_asset_id: 1, - show_results: 1 - }, - headers: { 'X-Requested-With': 'Polarity' }, - options - }) - ); - - const hostDetections = flow( - get('host_list_vm_detection_output.response.host_list.host'), - processPossibleList(false) - )(await xmlToJson(responseXml, Logger)); - - const processedJson = map( - processResultWithProcessingFormat(HOST_DETECTIONS_LIST_FORMAT), - hostDetections - ); - - return processedJson; - } catch (error) { - const err = parseErrorToReadableJSON(error); - Logger.error( - { - detail: 'Failed to Query Host Detection List', - formattedError: err - }, - 'Querying Host Detection List Failed' - ); - - throw error; - } - }; - -const HOST_DETECTIONS_LIST_ITEM_FORMAT = { - qid: 'qid', - type: 'type', - severity: 'severity', - port: 'port', - protocol: 'protocol', - ssl: { - path: 'ssl', - process: (ssl) => (ssl == 1 ? 'Yes' : 'No') - }, - results: 'results', - status: 'status', - first_found_datetime: 'first_found_datetime', - last_found_datetime: 'last_found_datetime', - times_found: 'times_found', - last_test_datetime: 'last_test_datetime', - last_update_datetime: 'last_update_datetime', - is_ignored: { - path: 'is_ignored', - process: (is_ignored) => (is_ignored == 1 ? 'Yes' : 'No') - }, - is_disabled: { - path: 'is_disabled', - process: (is_disabled) => (is_disabled == 1 ? 'Yes' : 'No') - }, - last_processed_datetime: 'last_processed_datetime' -}; - -const HOST_DETECTIONS_LIST_FORMAT = { - id: 'id', - asset_id: 'asset_id', - ip: 'ip', - os: 'os', - dns: 'dns', - last_scan_datetime: 'last_scan_datetime', - last_vm_scanned_date: 'last_vm_scanned_date', - last_vm_scanned_duration: 'last_vm_scanned_duration', - category: 'category', - detection_list: { - path: 'detection_list', - process: flow( - get('detection'), - processPossibleList(false), - map(processResultWithProcessingFormat(HOST_DETECTIONS_LIST_ITEM_FORMAT)), - uniqBy('qid') - ) - } -}; - -module.exports = queryHostDetectionListForAllEntities; diff --git a/src/querying/queryHostDetectionListForAllEntities.ts b/src/querying/queryHostDetectionListForAllEntities.ts new file mode 100644 index 0000000..9c35db6 --- /dev/null +++ b/src/querying/queryHostDetectionListForAllEntities.ts @@ -0,0 +1,129 @@ +import { get, map, flow, filter, eq, uniqBy, join, size } from 'lodash/fp'; +import type { Entity, Logger } from '@polarityio/integration-types'; +import type { PolarityRequest } from 'polarity-integration-utils'; + +import { + parseErrorToReadableJSON, + processResultWithProcessingFormat, + processPossibleList, + xmlToJson, + or +} from '../dataTransformations'; + +/* eslint-disable @typescript-eslint/no-explicit-any */ + +const queryHostDetectionListForAllEntities = async ( + entities: Entity[], + options: Record, + request: PolarityRequest, + Logger: Logger +): Promise => { + const ipEntities = filter(flow(get('type'), or(eq('IPv4'), eq('IPv6'))), entities); + const ipValues = map(get('value'), ipEntities) as string[]; + + const qidEntities = filter(flow(get('type'), eq('qid')), entities); + const qidValues = map(get('value'), qidEntities) as string[]; + + const allHostDetectionResultForIpAddresses = size(ipValues) + ? await queryHostDetectionList('ips', options, request, Logger)(ipValues) + : []; + + const allHostDetectionResultForQids = size(qidValues) + ? await queryHostDetectionList('qids', options, request, Logger)(qidValues) + : []; + + return uniqBy('id', allHostDetectionResultForIpAddresses).concat( + uniqBy('id', allHostDetectionResultForQids) + ); +}; + +const queryHostDetectionList = + (type: string, options: Record, request: PolarityRequest, Logger: Logger) => + async (entityValues: string[]): Promise => { + try { + const response = await request.run({ + method: 'GET', + url: `${options.url}/api/2.0/fo/asset/host/vm/detection/`, + qs: { + action: 'list', + [type]: join(',', entityValues), + show_asset_id: 1, + show_results: 1 + }, + headers: { 'X-Requested-With': 'Polarity' }, + json: false + }); + + const responseXml = (response!.body as string) || ''; + + const hostDetections = flow( + get('host_list_vm_detection_output.response.host_list.host'), + processPossibleList(false) + )(await xmlToJson(responseXml, Logger)); + + const processedJson = map( + processResultWithProcessingFormat(HOST_DETECTIONS_LIST_FORMAT), + hostDetections + ); + + return processedJson; + } catch (error) { + const err = parseErrorToReadableJSON(error); + Logger.error( + { + detail: 'Failed to Query Host Detection List', + formattedError: err + }, + 'Querying Host Detection List Failed' + ); + throw error; + } + }; + +const HOST_DETECTIONS_LIST_ITEM_FORMAT: Record = { + qid: 'qid', + type: 'type', + severity: 'severity', + port: 'port', + protocol: 'protocol', + ssl: { path: 'ssl', process: (ssl: any) => (ssl == 1 ? 'Yes' : 'No') }, + results: 'results', + status: 'status', + first_found_datetime: 'first_found_datetime', + last_found_datetime: 'last_found_datetime', + times_found: 'times_found', + last_test_datetime: 'last_test_datetime', + last_update_datetime: 'last_update_datetime', + is_ignored: { + path: 'is_ignored', + process: (is_ignored: any) => (is_ignored == 1 ? 'Yes' : 'No') + }, + is_disabled: { + path: 'is_disabled', + process: (is_disabled: any) => (is_disabled == 1 ? 'Yes' : 'No') + }, + last_processed_datetime: 'last_processed_datetime' +}; + +const HOST_DETECTIONS_LIST_FORMAT: Record = { + id: 'id', + asset_id: 'asset_id', + ip: 'ip', + os: 'os', + dns: 'dns', + last_scan_datetime: 'last_scan_datetime', + last_vm_scanned_date: 'last_vm_scanned_date', + last_vm_scanned_duration: 'last_vm_scanned_duration', + category: 'category', + detection_list: { + path: 'detection_list', + process: flow( + get('detection'), + processPossibleList(false), + map(processResultWithProcessingFormat(HOST_DETECTIONS_LIST_ITEM_FORMAT)), + uniqBy('qid') + ) + } +}; + +export default queryHostDetectionListForAllEntities; diff --git a/src/querying/queryVulnerabilitiesForAllEntities.js b/src/querying/queryVulnerabilitiesForAllEntities.js deleted file mode 100644 index fd93307..0000000 --- a/src/querying/queryVulnerabilitiesForAllEntities.js +++ /dev/null @@ -1,71 +0,0 @@ -const { getOr, size, flow, concat, uniqBy, orderBy } = require('lodash/fp'); -const { - parseErrorToReadableJSON, - buildQueryByQueryType -} = require('../dataTransformations'); - -const VULNERABILITIES_QUERY_FIELDS = - 'title,id,qid,title,port,age,typeDetected,assetId,assetName,assetUUID,lastDetected,' + - 'firstDetected,fqdn,ssl,severity,assetCount,cveids,vulnStatus,ignored,disabled,' + - 'isQualysPatchable,missingPatchCount,patchLicenseType,patchPlatform'; - -const limit = 200; - -const queryVulnerabilitiesForAllEntities = async ( - entities, - options, - requestWithDefaults, - Logger, - offset = 0, - allVulnerabilities = [] -) => { - try { - const vulnerabilitiesQuery = buildQueryByQueryType('vulnerabilities', entities); - - const vulnerabilitiesData = getOr( - [], - 'body', - await requestWithDefaults({ - uri: `${options.url}/portal-front/rest/assetview/1.0/assets`, - qs: { - havingQuery: vulnerabilitiesQuery, - fields: VULNERABILITIES_QUERY_FIELDS, - limit, - offset - }, - options - }) - ); - - const foundVulnerabilities = flow( - concat(vulnerabilitiesData), - uniqBy('id') - )(allVulnerabilities); - - if (size(vulnerabilitiesData) === 200) { - return await queryVulnerabilitiesForAllEntities( - entities, - options, - requestWithDefaults, - Logger, - offset + limit, - foundVulnerabilities - ); - } - - return orderBy('lastDetected.iMillis', 'desc')(foundVulnerabilities); - } catch (error) { - const err = parseErrorToReadableJSON(error); - Logger.error( - { - detail: 'Failed to Query Vulnerabilities', - formattedError: err - }, - 'Query Vulnerabilities Failed' - ); - - throw error; - } -}; - -module.exports = queryVulnerabilitiesForAllEntities; diff --git a/src/querying/queryVulnerabilitiesForAllEntities.ts b/src/querying/queryVulnerabilitiesForAllEntities.ts new file mode 100644 index 0000000..f19069e --- /dev/null +++ b/src/querying/queryVulnerabilitiesForAllEntities.ts @@ -0,0 +1,61 @@ +import { size, flow, concat, uniqBy, orderBy } from 'lodash/fp'; +import type { Entity, Logger } from '@polarityio/integration-types'; +import type { PolarityRequest } from 'polarity-integration-utils'; + +import { parseErrorToReadableJSON, buildQueryByQueryType } from '../dataTransformations'; + +/* eslint-disable @typescript-eslint/no-explicit-any */ + +const VULNERABILITIES_QUERY_FIELDS = 'title,id,qid,...'; +const limit = 200; + +const queryVulnerabilitiesForAllEntities = async ( + entities: Entity[], + options: Record, + request: PolarityRequest, + Logger: Logger, + offset = 0, + allVulnerabilities: any[] = [] +): Promise => { + try { + const vulnerabilitiesQuery = buildQueryByQueryType('vulnerabilities', entities); + + const response = await request.run({ + url: `${options.url}/portal-front/rest/assetview/1.0/assets`, + qs: { + havingQuery: vulnerabilitiesQuery, + fields: VULNERABILITIES_QUERY_FIELDS, + limit, + offset + } + }); + + const vulnerabilitiesData = (response!.body as any[]) || []; + const foundVulnerabilities = flow( + concat(vulnerabilitiesData), + uniqBy('id') + )(allVulnerabilities); + + if (size(vulnerabilitiesData) === 200) { + return await queryVulnerabilitiesForAllEntities( + entities, + options, + request, + Logger, + offset + limit, + foundVulnerabilities + ); + } + + return orderBy('lastDetected.iMillis', 'desc')(foundVulnerabilities); + } catch (error) { + const err = parseErrorToReadableJSON(error); + Logger.error( + { detail: 'Failed to Query Vulnerabilities', formattedError: err }, + 'Query Vulnerabilities Failed' + ); + throw error; + } +}; + +export default queryVulnerabilitiesForAllEntities; diff --git a/src/validateOptions.js b/src/validateOptions.js deleted file mode 100644 index 9eeb158..0000000 --- a/src/validateOptions.js +++ /dev/null @@ -1,45 +0,0 @@ -const fp = require('lodash/fp'); -const reduce = require('lodash/fp/reduce').convert({ cap: false }); - - -const validateStringOptions = (stringOptionsErrorMessages, options, otherErrors = []) => - reduce((agg, message, optionName) => { - const isString = typeof options[optionName].value === 'string'; - const isEmptyString = isString && fp.isEmpty(options[optionName].value); - - return !isString || isEmptyString - ? agg.concat({ - key: optionName, - message - }) - : agg; - }, otherErrors)(stringOptionsErrorMessages); - -const validateUrlOption = (url, otherErrors = []) => { - const endWithError = - url && url.endsWith('/') - ? otherErrors.concat({ - key: 'url', - message: - 'Your URL must not end with a /' - }) - : otherErrors; - if (endWithError.length) return endWithError; - - if (url) { - try { - new URL(url); - } catch (_) { - return otherErrors.concat({ - key: 'url', - message: - 'This URL is invalid. You must provide a valid URL.' - }); - } - } - - return otherErrors; -}; - - -module.exports = { validateStringOptions, validateUrlOption }; diff --git a/src/validateOptions.ts b/src/validateOptions.ts new file mode 100644 index 0000000..422d72b --- /dev/null +++ b/src/validateOptions.ts @@ -0,0 +1,45 @@ +import fp from 'lodash/fp'; +import reduce from 'lodash/fp/reduce'; +import type { ValidationError, ValidateOptionsUserOptions } from '@polarityio/integration-types'; + +const uncappedReduce = (reduce as any).convert({ cap: false }); + +export const validateStringOptions = ( + stringOptionsErrorMessages: Record, + options: ValidateOptionsUserOptions, + otherErrors: ValidationError[] = [] +): ValidationError[] => + uncappedReduce((agg: ValidationError[], message: string, optionName: string) => { + const isString = typeof options[optionName].value === 'string'; + const isEmptyString = isString && fp.isEmpty(options[optionName].value as string); + + return !isString || isEmptyString ? agg.concat({ key: optionName, message }) : agg; + }, otherErrors)(stringOptionsErrorMessages); + +export const validateUrlOption = ( + url: string, + otherErrors: ValidationError[] = [] +): ValidationError[] => { + const endWithError = + url && url.endsWith('/') + ? otherErrors.concat({ + key: 'url', + message: 'Your URL must not end with a /' + }) + : otherErrors; + + if (endWithError.length) return endWithError; + + if (url) { + try { + new URL(url); + } catch { + return otherErrors.concat({ + key: 'url', + message: 'This URL is invalid. You must provide a valid URL.' + }); + } + } + + return otherErrors; +}; diff --git a/styles/styles.less b/styles/styles.less deleted file mode 100644 index 38d0270..0000000 --- a/styles/styles.less +++ /dev/null @@ -1,112 +0,0 @@ -.block { - margin-bottom: 5px; -} - -hr { - display: block; - margin-top: 0.5em; - margin-bottom: 0.5em; - margin-left: auto; - margin-right: auto; - border-style: inset; - border-width: 1px; -} - -.expandable-title { - display: block; - color: #5ccd18 !important; - font-weight: 600; - line-height: 16px; - margin-bottom: 5px; - .text { - color: #5ccd18 !important; - border-bottom: 1px solid #5ccd18; - .desc { - color: black !important; - font-weight: 400 !important; - } - } -} - -.p-title { - font-size: 14px !important; - font-weight: 500; - text-decoration: underline; -} - -hr { - margin-top: 13px; -} - -.load-more { - margin-top: 10px; - font-size: 14px; - color: darkgray !important; - &:hover { - color: rgb(119, 119, 119) !important; - } -} - -.loading { - font-size: 14px; - margin-top: 10px; - color: darkgray !important; -} - -.no-style-button { - cursor: pointer; - font-size: 100%; - font-family: inherit; - border: 0; - padding: 0; - background-color: transparent; - - &:hover, - &:focus { - background: inherit; - } - - &:focus { - outline: none; - } - - &:active { - transform: none; - } -} - -.copy-button { - width: 15px; - border-radius: 3px; - &:hover, - &:focus { - background: inherit; - background-color: rgba(153, 153, 153, 0.2); - border-color: rgba(153, 153, 153, 0.2); - cursor: pointer; - } - - &:focus { - outline: none; - } - - &:active { - cursor: pointer; - .header-button-icon { - color: #fff; - } - background-color: rgba(100, 100, 100, 0.4);; - border-color: rgba(100, 100, 100, 0.4);; - transform: none; - } -} - -.copied-label { - color: lightgray; -} - - - -.operation-button-icon { - color: #9e9e9e; -} diff --git a/templates/block.hbs b/templates/block.hbs deleted file mode 100644 index f30ead5..0000000 --- a/templates/block.hbs +++ /dev/null @@ -1,274 +0,0 @@ - -{{#each tabKeys as |tabKey|}} - {{#if (eq activeTab tabKey)}} - {{#each (get details tabKey) as |displayField displayFieldIndex|}} - {{#if displayField.isTitle}} - {{#if (and displayField.displayLink (or displayField.value displayField.label))}} -

- {{#if displayField.icon}} - {{fa-icon displayField.icon fixedWidth=true}} - {{/if}} - - {{#if displayField.capitalize}} - {{capitalize (or displayField.label displayField.value)}} - {{else}} - {{or displayField.label displayField.value}} - {{/if}} - - {{fa-icon "external-link" class="p-link ml-1"}} -

- {{else if displayField.showLabelAndValue}} -

- {{#if displayField.displayLink}} - - {{displayField.label}}: {{displayField.value}} - - {{else}} - {{displayField.label}}: {{displayField.value}} - {{/if}} - {{#if - (and - displayField.pathIsLinkToMoreData (not displayField.moreDataIsPopulated) - ) - }} - {{fa-icon "spinner-third" fixedWidth=true spin=true}} - {{/if}} -

- {{else}} -

- {{#if displayField.displayLink}} - - {{or displayField.label displayField.value}} - - {{else}} - {{or displayField.label displayField.value}} - {{/if}} - {{#if - (and - displayField.pathIsLinkToMoreData (not displayField.moreDataIsPopulated) - ) - }} - {{fa-icon "spinner-third" fixedWidth=true spin=true}} - {{/if}} -

- {{/if}} - {{else if displayField.isTextBlock}} -
- {{#if displayField.capitalize}} - {{capitalize displayField.value}} - {{else}} - {{displayField.value}} - {{/if}} -
- {{else if displayField.isListOfLinks}} -
- {{displayField.label}}: - - {{#each displayField.value as |content contentIndex|}} - {{#if content.capitalize}}{{capitalize content.id}}{{else}}{{content.id}}{{/if}}{{#if (not (eq contentIndex (sub displayField.value.length 1)))}}, {{/if}} - {{/each}} - -
- {{else if displayField.isHtml}} -
- {{#if (get expandableTitleStates (concat displayFieldIndex 0 displayField.label))}} - - {{displayField.label}} {{fa-icon "angle-up"}} - -
- {{html-safe displayField.value}} -
- {{else}} - - {{displayField.label}} {{fa-icon "angle-down"}} - - {{/if}} -
- {{else if displayField.isList}} -

- {{displayField.label}} -

-
- {{#each displayField.value as |itemDisplayFields itemDisplayFieldsIndex|}} - {{#if displayField.collapsibleListItems}} - {{#if (get expandableTitleStates (concat displayFieldIndex itemDisplayFieldsIndex displayField.label))}} - - {{itemDisplayFields.0.value}} {{fa-icon "angle-up"}} - - {{#each itemDisplayFields as |itemDisplayField itemDisplayFieldIndex|}} - {{#if (not (eq itemDisplayFieldIndex 0))}} -
- {{itemDisplayField.label}}: - - {{#if itemDisplayField.isDate}} - {{moment-format - itemDisplayField.value - "MM/DD/YYYY HH:mm:ss" - timeZone=timezone - }} - {{else}} - {{itemDisplayField.value}} - {{/if}} - - {{#if itemDisplayField.fieldIsCopyable}} - - {{#if (get copiedStates (concat displayFieldIndex itemDisplayField.label itemDisplayFieldIndex))}} - Copied - {{/if}} - {{/if}} -
- {{/if}} - {{/each}} - {{else}} - - {{itemDisplayFields.0.value}} {{fa-icon "angle-down"}} - - {{/if}} - {{else}} - {{#each itemDisplayFields as |itemDisplayField itemDisplayFieldIndex|}} -
- {{itemDisplayField.label}}: - - {{#if itemDisplayField.isDate}} - {{moment-format - itemDisplayField.value - "MM/DD/YYYY HH:mm:ss" - timeZone=timezone - }} - {{else}} - {{itemDisplayField.value}} - {{/if}} - - {{#if itemDisplayField.fieldIsCopyable}} - - {{#if (get copiedStates (concat displayFieldIndex itemDisplayField.label itemDisplayFieldIndex))}} - Copied - {{/if}} - {{/if}} -
- {{/each}} - {{/if}} - {{/each}} -
- {{else if displayField.isNewSectionLineBreak}} -
- {{else if displayField.fieldIsCopyable}} -
- {{displayField.label}}: - - {{#if displayField.isDate}} - {{moment-format - displayField.value - "MM/DD/YYYY HH:mm:ss" - timeZone=timezone - }} - {{else if displayField.capitalize}} - {{capitalize displayField.value}} - {{else}} - {{displayField.value}} - {{/if}} - - - {{#if (get copiedStates (concat displayFieldIndex displayField.label 0))}} - Copied - {{/if}} -
- {{else}} -
- {{displayField.label}}: - - {{#if displayField.pathToOnePropertyFromMoreDataToDisplay}} - {{fa-icon "spinner-third" fixedWidth=true spin=true}} - {{else}} - {{#if displayField.isDate}} - {{moment-format - displayField.value - "MM/DD/YYYY HH:mm:ss" - timeZone=timezone - }} - {{else if displayField.displayLink}} - - {{#if displayField.capitalize}} - {{capitalize displayField.value}} - {{else}} - {{displayField.value}} - {{/if}} - - {{else if displayField.capitalize}} - {{capitalize displayField.value}} - {{else}} - {{displayField.value}} - {{/if}} - {{/if}} - -
- {{/if}} - {{/each}} - {{/if}} -{{/each}} \ No newline at end of file diff --git a/test/integration.test.ts b/test/integration.test.ts new file mode 100644 index 0000000..ecd0631 --- /dev/null +++ b/test/integration.test.ts @@ -0,0 +1,7 @@ +import { describe, it, expect } from 'vitest'; + +describe('Qualys integration', () => { + it('should be implemented', () => { + expect(true).toBe(true); + }); +}); diff --git a/test/web-components/details.test.ts b/test/web-components/details.test.ts new file mode 100644 index 0000000..c89ee41 --- /dev/null +++ b/test/web-components/details.test.ts @@ -0,0 +1,7 @@ +import { describe, it, expect } from 'vitest'; + +describe('Qualys DetailsComponent', () => { + it('should be implemented', () => { + expect(true).toBe(true); + }); +}); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..7bee2dc --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "CommonJS", + "moduleResolution": "node", + "outDir": "./dist", + "rootDir": "./src", + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "declaration": true, + "sourceMap": true, + "experimentalDecorators": true, + "useDefineForClassFields": false + }, + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "dist", "web-components"] +} diff --git a/tsconfig.web.json b/tsconfig.web.json new file mode 100644 index 0000000..ce44f5f --- /dev/null +++ b/tsconfig.web.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "bundler", + "experimentalDecorators": true, + "useDefineForClassFields": false, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "noEmit": true + }, + "include": ["web-components/**/*.ts"] +} diff --git a/vite.config.js b/vite.config.js new file mode 100644 index 0000000..1d275b4 --- /dev/null +++ b/vite.config.js @@ -0,0 +1,36 @@ +import config from './config/config.json' with { type: 'json' }; +import { defineConfig } from 'vite'; +import { transformComponentNames, VIRTUAL_COMPONENTS_ID } from '@polarityio/vite-plugin-icl'; +import { resolve } from 'node:path'; + +export default defineConfig({ + plugins: [ + transformComponentNames({ + componentsDir: resolve(__dirname, 'web-components'), + componentRegistries: [ + '@polarityio/pi-components/component-registry.json', + ], + }), + ], + build: { + outDir: 'dist', + emptyOutDir: false, + lib: { + entry: VIRTUAL_COMPONENTS_ID, + name: 'qualys-v2_build', + fileName: () => { + const webComponentsConfig = config.webComponents; + return webComponentsConfig.moduleFilename; + }, + formats: ['es'], + }, + minify: false, + rollupOptions: { + output: { + globals: { + lit: 'lit', + }, + }, + }, + }, +}); diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..fb62fc3 --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,28 @@ +import { defineConfig } from 'vitest/config'; +import { playwright } from '@vitest/browser-playwright'; + +export default defineConfig({ + test: { + projects: [ + { + test: { + name: 'server', + environment: 'node', + include: ['test/**/*.test.ts'], + exclude: ['test/web-components/**'] + } + }, + { + test: { + name: 'browser', + include: ['test/web-components/**/*.test.ts'], + browser: { + enabled: true, + provider: playwright(), + instances: [{ browser: 'chromium' }] + } + } + } + ] + } +}); diff --git a/web-components/details.ts b/web-components/details.ts new file mode 100644 index 0000000..8412501 --- /dev/null +++ b/web-components/details.ts @@ -0,0 +1,628 @@ +import { css, html, nothing, unsafeCSS } from 'lit'; +import { property, state } from 'lit/decorators.js'; +import { unsafeHTML } from 'lit/directives/unsafe-html.js'; +import { IntegrationComponentBase, IBlock, typographyCSS } from '@polarityio/pi-components'; +import { faAngleUp, faAngleDown, faCopy } from '@polarityio/pi-icon'; + +interface DisplayField { + label?: string; + value?: any; + isTitle?: boolean; + isDate?: boolean; + isList?: boolean; + isListOfLinks?: boolean; + isHtml?: boolean; + isTextBlock?: boolean; + isNewSectionLineBreak?: boolean; + indent?: number; + collapsibleListItems?: boolean; + showLabelAndValue?: boolean; + fieldIsCopyable?: boolean; + shouldCopyFieldLabel?: boolean; + displayLink?: string; + icon?: string; + capitalize?: boolean; +} + +interface Details { + tabKeys: string[]; + [key: string]: DisplayField[] | string[] | any; +} + +/** + * Converts a camelCase or PascalCase key like "hostDetections" + * to a title-cased, spaced label like "Host Detections". + */ +function humanizeTabKey(key: string): string { + return key + .replace(/([a-z])([A-Z])/g, '$1 $2') + .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2') + .replace(/^./, (c) => c.toUpperCase()); +} + +/** + * Formats an ISO 8601 date string using Intl.DateTimeFormat (Chrome 90 safe). + */ +function formatDate(value: string): string { + try { + const date = new Date(value); + if (isNaN(date.getTime())) return value; + const tz = Intl.DateTimeFormat().resolvedOptions().timeZone; + return new Intl.DateTimeFormat('en-US', { + month: '2-digit', + day: '2-digit', + year: 'numeric', + hour: '2-digit', + minute: '2-digit', + second: '2-digit', + hour12: false, + timeZone: tz + }).format(date); + } catch { + return String(value); + } +} + +function capitalizeStr(str: string): string { + if (!str) return ''; + return str.charAt(0).toUpperCase() + str.slice(1); +} + +export class DetailsComponent extends IntegrationComponentBase { + @property({ type: Object }) block: IBlock = { + integrationId: '', + acronym: '', + data: { details: {} as any, summary: [] } + }; + + @state() private _activeTab = ''; + @state() private _expandedStates: Record = {}; + @state() private _copiedStates: Record = {}; + + private _copyContentId = `copy-content-${Array.from( + crypto.getRandomValues(new Uint8Array(16)), + (b) => b.toString(16).padStart(2, '0') + ).join('')}`; + + static styles = [ + unsafeCSS(typographyCSS), + css` + :host { + display: block; + font-family: var(--pi-font-family-base, 'NotoSans', sans-serif); + font-size: var(--pi-size-font-base, 0.8125rem); + color: var(--pi-color-font-primary, #fafaff); + line-height: var(--pi-line-height-base, 1.4); + } + + .copy-btn-container { + position: absolute; + right: 10px; + top: 7px; + z-index: 1; + } + + .content-wrapper { + position: relative; + } + + .tab-content { + display: flex; + flex-direction: column; + gap: var(--pi-size-spacing-xxs, 2px); + padding-top: var(--pi-size-spacing-xs, 4px); + } + + .field-row { + display: flex; + align-items: baseline; + gap: var(--pi-size-spacing-xs, 4px); + flex-wrap: wrap; + } + + .text-block { + margin-bottom: var(--pi-size-spacing-xs, 4px); + color: var(--pi-color-font-secondary, #cdced6); + } + + .section-break { + border: none; + border-top: 1px solid var(--pi-color-border-container, #606470); + margin: var(--pi-size-spacing-sm, 8px) 0; + } + + .expandable-title { + display: flex; + align-items: center; + gap: var(--pi-size-spacing-xs, 4px); + cursor: pointer; + background: none; + border: none; + padding: var(--pi-size-spacing-xxs, 2px) 0; + font-family: inherit; + font-size: inherit; + color: var(--pi-color-font-info, #33b2ff); + font-weight: var(--pi-font-weight-semibold, 600); + line-height: 1.2; + margin-bottom: var(--pi-size-spacing-xs, 4px); + } + + .expandable-title:hover { + opacity: 0.8; + } + + .expandable-title-text { + border-bottom: 1px solid var(--pi-color-font-info, #33b2ff); + } + + .list-section { + margin-bottom: var(--pi-size-spacing-xs, 4px); + } + + .list-items { + padding-left: var(--pi-size-spacing-sm, 8px); + display: flex; + flex-direction: column; + gap: var(--pi-size-spacing-xxs, 2px); + } + + .list-item-fields { + padding-left: var(--pi-size-spacing-md, 12px); + display: flex; + flex-direction: column; + gap: var(--pi-size-spacing-xxs, 2px); + } + + .copyable-field { + display: inline-flex; + align-items: center; + gap: var(--pi-size-spacing-xs, 4px); + } + + .copy-inline-btn { + cursor: pointer; + background: none; + border: none; + padding: 0; + display: inline-flex; + align-items: center; + color: var(--pi-color-font-secondary, #cdced6); + } + + .copy-inline-btn:hover { + color: var(--pi-color-font-primary, #fafaff); + } + + .copied-label { + font-size: var(--pi-size-font-xs, 0.75rem); + color: var(--pi-color-font-secondary, #cdced6); + } + + .html-content { + padding-left: var(--pi-size-spacing-md, 12px); + margin-bottom: var(--pi-size-spacing-xs, 4px); + color: var(--pi-color-font-primary, #fafaff); + } + + .link-list { + display: inline; + } + + .kv-key { + color: var(--pi-color-font-secondary, #cdced6); + font-weight: var(--pi-font-weight-semibold, 600); + white-space: nowrap; + } + + .link-separator { + color: var(--pi-color-font-secondary, #cdced6); + } + + .indent-0 { + padding-left: 0; + } + .indent-1 { + padding-left: var(--pi-size-spacing-sm, 8px); + } + .indent-2 { + padding-left: var(--pi-size-spacing-lg, 16px); + } + .indent-3 { + padding-left: var(--pi-size-spacing-xl, 24px); + } + ` + ]; + + connectedCallback() { + super.connectedCallback(); + this._initActiveTab(); + } + + updated(changedProperties: Map) { + super.updated(changedProperties); + if (changedProperties.has('block')) { + this._initActiveTab(); + } + } + + private _initActiveTab() { + const d = this.block.data?.details as Details | undefined; + if (!d?.tabKeys) return; + + // Restore persisted tab from componentState, or pick first non-empty + const persisted = (this.block as any).componentState?.activeTab; + if (persisted && d.tabKeys.includes(persisted) && d[persisted]?.length) { + this._activeTab = persisted; + } else if (!this._activeTab || !d.tabKeys.includes(this._activeTab)) { + this._activeTab = + d.tabKeys.find((key) => d[key] && Array.isArray(d[key]) && d[key].length) || + d.tabKeys[0] || + ''; + } + } + + private _onTabChange(e: CustomEvent) { + const d = this.block.data?.details as Details; + if (!d?.tabKeys) return; + const tabIndex = e.detail?.tabIndex ?? 0; + const tabKey = d.tabKeys.filter((k) => d[k] && Array.isArray(d[k]) && d[k].length)[tabIndex]; + if (tabKey) { + this._activeTab = tabKey; + // Persist active tab in componentState + if (this.block) { + (this.block as any).componentState = { + ...((this.block as any).componentState || {}), + activeTab: tabKey + }; + } + } + } + + private _toggleExpanded(key: string) { + this._expandedStates = { + ...this._expandedStates, + [key]: !this._expandedStates[key] + }; + } + + private _copyField(value: string, label: string, shouldCopyLabel: boolean, stateKey: string) { + const text = shouldCopyLabel ? `${label}: ${value}` : value; + navigator.clipboard.writeText(text); + this._copiedStates = { ...this._copiedStates, [stateKey]: true }; + setTimeout(() => { + this._copiedStates = { ...this._copiedStates, [stateKey]: false }; + }, 3000); + } + + private _beforeCopy = async () => { + this.shadowRoot?.querySelectorAll('[data-pi-card]').forEach((card: any) => { + if (typeof card.expanded !== 'undefined') { + card.expanded = true; + } + }); + await this.updateComplete; + }; + + private _afterCopy = async () => { + // No-op: cards remain expanded after copy + }; + + render() { + const d = this.block.data?.details as Details | undefined; + if (!d?.tabKeys?.length) return nothing; + + const visibleTabs = d.tabKeys.filter((key) => d[key] && Array.isArray(d[key]) && d[key].length); + + if (!visibleTabs.length) return nothing; + + const activeIndex = Math.max(0, visibleTabs.indexOf(this._activeTab)); + + return html` +
+
+ +
+
+ ${visibleTabs.length === 1 + ? this._renderTabContent(d[visibleTabs[0]] as DisplayField[]) + : html` + + ${visibleTabs.map( + (tabKey, idx) => html` + + ${humanizeTabKey(tabKey)} + + ` + )} + ${visibleTabs.map( + (tabKey, idx) => html` + + ${this._renderTabContent(d[tabKey] as DisplayField[])} + + ` + )} + + `} +
+
+ `; + } + + private _renderTabContent(fields: DisplayField[]) { + if (!fields?.length) return nothing; + return html` +
+ ${fields.map((field, idx) => this._renderDisplayField(field, idx))} +
+ `; + } + + private _renderDisplayField(field: DisplayField, fieldIndex: number) { + if (field.isTitle) { + return this._renderTitle(field); + } + if (field.isTextBlock) { + return this._renderTextBlock(field); + } + if (field.isListOfLinks) { + return this._renderListOfLinks(field); + } + if (field.isHtml) { + return this._renderHtmlField(field, fieldIndex); + } + if (field.isList) { + return this._renderList(field, fieldIndex); + } + if (field.isNewSectionLineBreak) { + return html`
`; + } + if (field.fieldIsCopyable) { + return this._renderCopyableField(field, fieldIndex, 0); + } + return this._renderKeyValue(field); + } + + private _renderTitle(field: DisplayField) { + const indentClass = `indent-${field.indent || 0}`; + const labelText = field.capitalize + ? capitalizeStr(field.label || field.value || '') + : field.label || field.value || ''; + + if (field.displayLink && (field.value || field.label)) { + if (field.showLabelAndValue) { + return html` +

+ +

+ `; + } + return html` +

+ +

+ `; + } + + if (field.showLabelAndValue) { + return html`

${field.label}: ${field.value}

`; + } + + return html`

${labelText}

`; + } + + private _renderTextBlock(field: DisplayField) { + const indentClass = `indent-${field.indent || 0}`; + const text = field.capitalize ? capitalizeStr(field.value) : field.value; + return html`
${text}
`; + } + + private _renderListOfLinks(field: DisplayField) { + const indentClass = `indent-${field.indent || 0}`; + const links = field.value as Array<{ url: string; id: string; capitalize?: boolean }>; + return html` +
+ ${field.label}: + + ${links.map( + (link, i) => html` + ${i < links.length - 1 ? html`, ` : nothing} + ` + )} + +
+ `; + } + + private _renderHtmlField(field: DisplayField, fieldIndex: number) { + const stateKey = `${fieldIndex}-0-${field.label}`; + const isExpanded = !!this._expandedStates[stateKey]; + return html` +
+ + ${isExpanded ? html`
${unsafeHTML(field.value)}
` : nothing} +
+ `; + } + + private _renderList(field: DisplayField, fieldIndex: number) { + const items = field.value as DisplayField[][]; + if (!items?.length) return nothing; + + return html` +
+

${field.label}

+
+ ${items.map((itemFields, itemIdx) => + field.collapsibleListItems + ? this._renderCollapsibleListItem(field, fieldIndex, itemFields, itemIdx) + : this._renderFlatListItem(itemFields, fieldIndex, itemIdx) + )} +
+
+ `; + } + + private _renderCollapsibleListItem( + parentField: DisplayField, + fieldIndex: number, + itemFields: DisplayField[], + itemIdx: number + ) { + const stateKey = `${fieldIndex}-${itemIdx}-${parentField.label}`; + const isExpanded = !!this._expandedStates[stateKey]; + const headerValue = itemFields[0]?.value ?? ''; + + return html` +
+ + ${isExpanded + ? html` +
+ ${itemFields + .slice(1) + .map((itemField, subIdx) => + this._renderListItemField(itemField, fieldIndex, subIdx + 1) + )} +
+ ` + : nothing} +
+ `; + } + + private _renderFlatListItem(itemFields: DisplayField[], fieldIndex: number, _itemIdx: number) { + return html` +
+ ${itemFields.map((itemField, subIdx) => + this._renderListItemField(itemField, fieldIndex, subIdx) + )} +
+ `; + } + + private _renderListItemField(field: DisplayField, fieldIndex: number, subIndex: number) { + const value = field.isDate ? formatDate(field.value) : field.value; + const copyStateKey = `${fieldIndex}-${field.label}-${subIndex}`; + + if (field.fieldIsCopyable) { + return html` +
+ + + ${this._copiedStates[copyStateKey] + ? html`Copied` + : nothing} +
+ `; + } + + return html` `; + } + + private _renderCopyableField(field: DisplayField, fieldIndex: number, subIndex: number) { + const indentClass = `indent-${field.indent || 0}`; + const value = field.isDate + ? formatDate(field.value) + : field.capitalize + ? capitalizeStr(field.value) + : field.value; + const copyStateKey = `${fieldIndex}-${field.label}-${subIndex}`; + + return html` +
+ + + ${this._copiedStates[copyStateKey] + ? html`Copied` + : nothing} +
+ `; + } + + private _renderKeyValue(field: DisplayField) { + const indentClass = `indent-${field.indent || 0}`; + + if (field.isDate) { + return html` +
+ +
+ `; + } + + if (field.displayLink) { + const displayText = field.capitalize ? capitalizeStr(field.value) : field.value; + return html` +
+ ${field.label}: + +
+ `; + } + + const value = field.capitalize ? capitalizeStr(field.value) : field.value; + return html` +
+ +
+ `; + } +} From fba77a15d3ff943bf6a79eec7a839c7275d76da7 Mon Sep 17 00:00:00 2001 From: Ed Dorsey Date: Wed, 13 May 2026 21:23:24 -0400 Subject: [PATCH 02/13] Fix stray > character after pi-external-link tags in details component The closing tag to render after each external link in link lists. Restructure the template so the closing bracket stays on the same line as the tag name, and add a prettier-ignore comment to prevent reformatting. Addresses PR review feedback for #18 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- web-components/details.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/web-components/details.ts b/web-components/details.ts index 8412501..63938c5 100644 --- a/web-components/details.ts +++ b/web-components/details.ts @@ -439,14 +439,14 @@ export class DetailsComponent extends IntegrationComponentBase { ${field.label}: ${links.map( - (link, i) => html` - html`${i < links.length - 1 ? html`, ` : nothing} - ` + >${i < links.length - 1 + ? html`, ` + : nothing}` )} From 874106c7812a0ecb83fd3c6d38a7f4cdd5763ecb Mon Sep 17 00:00:00 2001 From: Ed Dorsey Date: Sun, 31 May 2026 06:14:25 -0400 Subject: [PATCH 03/13] Implement comprehensive server and web component tests Server tests (17): - startup initialization - doLookup with valid host detection results - doLookup returning null for empty/miss results - Multiple entity handling - Ignored IP filtering (127.0.0.1, etc.) - Request options verification - Error propagation (API errors, non-Error throws) - QID custom type entity support - validateOptions for all fields and URL validation Web component tests (16): - Renders host detection data correctly - Handles empty/undefined details gracefully - Key-value pair rendering - Title fields with showLabelAndValue - Date formatting - Collapsible list items (collapsed by default) - HTML content in expandable sections - Copy button presence - Section breaks - Single tab vs multi-tab rendering - Empty tab filtering - Copyable fields with copy button - External links via pi-external-link - List of links rendering Also adds resolve aliases to vitest.config.ts to fix polarity-integration-utils ESM resolution. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- test/integration.test.ts | 466 +++++++++++++++++++++++++++- test/web-components/details.test.ts | 318 ++++++++++++++++++- vitest.config.ts | 26 ++ 3 files changed, 803 insertions(+), 7 deletions(-) diff --git a/test/integration.test.ts b/test/integration.test.ts index ecd0631..0c813ef 100644 --- a/test/integration.test.ts +++ b/test/integration.test.ts @@ -1,7 +1,465 @@ -import { describe, it, expect } from 'vitest'; +import { vi, describe, it, expect, beforeEach } from 'vitest'; +import type { + Entity, + DoLookupUserOptions, + IntegrationContext +} from '@polarityio/integration-types'; +import type { HttpRequestResponse } from 'polarity-integration-utils'; -describe('Qualys integration', () => { - it('should be implemented', () => { - expect(true).toBe(true); +function createEntity(type: string, value: string): Entity { + const isDomain = /^[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9](?:\.[a-zA-Z]{2,})+$/.test(value); + const isIPv4 = /^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/.test(value); + const isIPv6 = /^[\da-fA-F:]+$/.test(value) && value.includes(':'); + const typeId = type === 'IP' ? 'IPv4' : type.startsWith('custom.') ? 'custom' : type; + return { + value, + rawValue: value, + displayValue: value, + type: typeId, + types: [type], + isDomain, + isIPv4, + isIP: isIPv4 || isIPv6, + isIPv6, + isEmail: false, + isHash: false, + isHex: false, + isHTMLTag: false, + isMD5: false, + isPrivateIP: false, + isSHA1: false, + isSHA256: false, + isSHA512: false, + isURL: false, + channels: [], + requestContext: { requestType: 'OnDemand', isUserInitiated: true } + } as unknown as Entity; +} + +function createMockIntegrationContext() { + const createCacheScope = () => ({ get: vi.fn(), set: vi.fn(), delete: vi.fn() }); + const logger = { + child: vi.fn().mockReturnThis(), + info: vi.fn(), + debug: vi.fn(), + trace: vi.fn(), + warn: vi.fn(), + error: vi.fn(), + fatal: vi.fn() + }; + (logger.child as any).mockReturnValue(logger); + return { + cache: { + global: createCacheScope(), + integration: createCacheScope(), + user: createCacheScope() + }, + integrationId: 'test-integration', + userId: 1, + logger, + startPolling: vi.fn(), + stopPolling: vi.fn() + }; +} + +const { mockRun, mockSetLogger } = vi.hoisted(() => ({ + mockRun: vi.fn(), + mockSetLogger: vi.fn() +})); + +vi.mock('polarity-integration-utils', () => { + class MockIntegrationError extends Error { + cause: unknown; + meta: unknown; + constructor(message: string, props?: any) { + super(message); + this.name = 'IntegrationError'; + this.cause = props?.cause; + this.meta = props?.meta; + } + } + + class MockPolarityRequest { + run = mockRun; + runInParallel = vi.fn(); + userOptions: any = null; + network: any = null; + limiter: any = null; + hooks = { beforeRequest: [], afterResponse: [], onApiError: [], onNetworkError: [] }; + constructor(_opts?: any) {} + } + + return { + PolarityRequest: MockPolarityRequest, + setLogger: mockSetLogger, + IntegrationError: MockIntegrationError, + ApiRequestError: class extends Error { + constructor(m: string) { + super(m); + this.name = 'ApiRequestError'; + } + }, + NetworkError: class extends Error { + constructor(m: string) { + super(m); + this.name = 'NetworkError'; + } + } + }; +}); + +import { doLookup, startup, validateOptions } from '../src/integration'; + +const createMockContext = () => createMockIntegrationContext(); + +const createOptions = (overrides: Partial> = {}): DoLookupUserOptions => + ({ + url: 'https://qualysapi.qualys.com', + username: 'testuser', + password: 'testpass', + ...overrides + }) as unknown as DoLookupUserOptions; + +const HOST_DETECTION_XML = ` + + + + + 12345 + 67890 + 192.168.1.1 + Linux 4.15 + host.example.com + 2024-01-15T10:30:00Z + 2024-01-15T10:30:00Z + 120 + Confirmed + + + 38623 + Confirmed + 3 + 443 + tcp + 1 + SSL Certificate - Subject + Active + 2024-01-10T08:00:00Z + 2024-01-15T10:30:00Z + 5 + 2024-01-15T10:30:00Z + 2024-01-15T10:30:00Z + 0 + 0 + 2024-01-15T10:30:00Z + + + + + +`; + +const EMPTY_HOST_DETECTION_XML = ` + + + +`; + +describe('Qualys Integration', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + describe('startup', () => { + it('should initialize without error', () => { + const mockLogger = { + info: vi.fn(), + debug: vi.fn(), + trace: vi.fn(), + warn: vi.fn(), + error: vi.fn(), + fatal: vi.fn(), + child: vi.fn() + }; + expect(() => startup(mockLogger as any)).not.toThrow(); + }); + }); + + describe('doLookup', () => { + beforeEach(() => { + const mockLogger = { + info: vi.fn(), + debug: vi.fn(), + trace: vi.fn(), + warn: vi.fn(), + error: vi.fn(), + fatal: vi.fn(), + child: vi.fn() + }; + startup(mockLogger as any); + }); + + it('should return lookup results with data for an IPv4 entity with host detections', async () => { + mockRun.mockResolvedValue({ + statusCode: 200, + body: HOST_DETECTION_XML, + headers: {} + } as HttpRequestResponse); + + const entities: Entity[] = [createEntity('IPv4', '192.168.1.1')]; + const options = createOptions(); + const context = createMockContext(); + + const results = await doLookup(entities, options, context as unknown as IntegrationContext); + + expect(results).toHaveLength(1); + expect(results![0].entity.value).toBe('192.168.1.1'); + expect(results![0].data).not.toBeNull(); + expect(results![0].data!.summary).toContain('Host Detections: 1'); + expect(results![0].data!.details).toHaveProperty('tabKeys'); + }); + + it('should return data: null for an entity with no results', async () => { + mockRun.mockResolvedValue({ + statusCode: 200, + body: EMPTY_HOST_DETECTION_XML, + headers: {} + } as HttpRequestResponse); + + const entities: Entity[] = [createEntity('IPv4', '10.0.0.1')]; + const options = createOptions(); + const context = createMockContext(); + + const results = await doLookup(entities, options, context as unknown as IntegrationContext); + + expect(results).toHaveLength(1); + expect(results![0].data).toBeNull(); + }); + + it('should handle multiple entities', async () => { + mockRun.mockResolvedValue({ + statusCode: 200, + body: EMPTY_HOST_DETECTION_XML, + headers: {} + } as HttpRequestResponse); + + const entities: Entity[] = [ + createEntity('IPv4', '192.168.1.1'), + createEntity('IPv4', '192.168.1.2') + ]; + const options = createOptions(); + const context = createMockContext(); + + const results = await doLookup(entities, options, context as unknown as IntegrationContext); + + expect(results).toHaveLength(2); + }); + + it('should return data: null for ignored IPs (127.0.0.1)', async () => { + mockRun.mockResolvedValue({ + statusCode: 200, + body: EMPTY_HOST_DETECTION_XML, + headers: {} + } as HttpRequestResponse); + + const entities: Entity[] = [createEntity('IPv4', '127.0.0.1')]; + const options = createOptions(); + const context = createMockContext(); + + const results = await doLookup(entities, options, context as unknown as IntegrationContext); + + expect(results).toHaveLength(1); + expect(results![0].data).toBeNull(); + }); + + it('should pass correct request options to the API', async () => { + mockRun.mockResolvedValue({ + statusCode: 200, + body: EMPTY_HOST_DETECTION_XML, + headers: {} + } as HttpRequestResponse); + + const entities: Entity[] = [createEntity('IPv4', '10.20.30.40')]; + const options = createOptions({ url: 'https://qualysapi.example.com' }); + const context = createMockContext(); + + await doLookup(entities, options, context as unknown as IntegrationContext); + + expect(mockRun).toHaveBeenCalledWith( + expect.objectContaining({ + method: 'GET', + url: 'https://qualysapi.example.com/api/2.0/fo/asset/host/vm/detection/', + qs: expect.objectContaining({ + action: 'list', + ips: '10.20.30.40', + show_asset_id: 1, + show_results: 1 + }), + headers: { 'X-Requested-With': 'Polarity' }, + json: false + }) + ); + }); + + it('should throw IntegrationError when API request fails', async () => { + const apiError = new Error('API request failed'); + mockRun.mockRejectedValue(apiError); + + const entities: Entity[] = [createEntity('IPv4', '192.168.1.1')]; + const options = createOptions(); + const context = createMockContext(); + + await expect( + doLookup(entities, options, context as unknown as IntegrationContext) + ).rejects.toThrow('API request failed'); + }); + + it('should throw IntegrationError with default message for non-Error objects', async () => { + mockRun.mockRejectedValue('string error'); + + const entities: Entity[] = [createEntity('IPv4', '192.168.1.1')]; + const options = createOptions(); + const context = createMockContext(); + + await expect( + doLookup(entities, options, context as unknown as IntegrationContext) + ).rejects.toThrow('Searching Failed'); + }); + + it('should not make API calls when only ignored IPs are provided', async () => { + const entities: Entity[] = [ + createEntity('IPv4', '127.0.0.1'), + createEntity('IPv4', '255.255.255.255'), + createEntity('IPv4', '0.0.0.0') + ]; + const options = createOptions(); + const context = createMockContext(); + + const results = await doLookup(entities, options, context as unknown as IntegrationContext); + + expect(mockRun).not.toHaveBeenCalled(); + expect(results).toHaveLength(3); + results!.forEach((r) => expect(r.data).toBeNull()); + }); + + it('should handle QID custom type entities', async () => { + mockRun.mockResolvedValue({ + statusCode: 200, + body: HOST_DETECTION_XML, + headers: {} + } as HttpRequestResponse); + + const entity = createEntity('custom', 'QID: 38623') as any; + entity.type = 'custom'; + entity.types = ['custom.qid']; + const entities: Entity[] = [entity]; + const options = createOptions(); + const context = createMockContext(); + + const results = await doLookup(entities, options, context as unknown as IntegrationContext); + + expect(results).toHaveLength(1); + expect(mockRun).toHaveBeenCalledWith( + expect.objectContaining({ + qs: expect.objectContaining({ + qids: '38623' + }) + }) + ); + }); + }); + + describe('validateOptions', () => { + it('should return no errors when all options are valid', () => { + const options = { + url: { value: 'https://qualysapi.qualys.com' }, + username: { value: 'testuser' }, + password: { value: 'testpass' } + }; + const context = createMockContext(); + + const errors = validateOptions(options as any, context as unknown as IntegrationContext); + + expect(errors).toHaveLength(0); + }); + + it('should return error when url is empty', () => { + const options = { + url: { value: '' }, + username: { value: 'testuser' }, + password: { value: 'testpass' } + }; + const context = createMockContext(); + + const errors = validateOptions(options as any, context as unknown as IntegrationContext); + + expect(errors.length).toBeGreaterThan(0); + expect(errors.some((e) => e.key === 'url')).toBe(true); + }); + + it('should return error when username is empty', () => { + const options = { + url: { value: 'https://qualysapi.qualys.com' }, + username: { value: '' }, + password: { value: 'testpass' } + }; + const context = createMockContext(); + + const errors = validateOptions(options as any, context as unknown as IntegrationContext); + + expect(errors.some((e) => e.key === 'username')).toBe(true); + }); + + it('should return error when password is empty', () => { + const options = { + url: { value: 'https://qualysapi.qualys.com' }, + username: { value: 'testuser' }, + password: { value: '' } + }; + const context = createMockContext(); + + const errors = validateOptions(options as any, context as unknown as IntegrationContext); + + expect(errors.some((e) => e.key === 'password')).toBe(true); + }); + + it('should return error when URL ends with a slash', () => { + const options = { + url: { value: 'https://qualysapi.qualys.com/' }, + username: { value: 'testuser' }, + password: { value: 'testpass' } + }; + const context = createMockContext(); + + const errors = validateOptions(options as any, context as unknown as IntegrationContext); + + expect(errors.some((e) => e.key === 'url' && e.message.includes('/'))).toBe(true); + }); + + it('should return error when URL is invalid', () => { + const options = { + url: { value: 'not-a-valid-url' }, + username: { value: 'testuser' }, + password: { value: 'testpass' } + }; + const context = createMockContext(); + + const errors = validateOptions(options as any, context as unknown as IntegrationContext); + + expect(errors.some((e) => e.key === 'url' && e.message.includes('invalid'))).toBe(true); + }); + + it('should return multiple errors when multiple fields are invalid', () => { + const options = { + url: { value: '' }, + username: { value: '' }, + password: { value: '' } + }; + const context = createMockContext(); + + const errors = validateOptions(options as any, context as unknown as IntegrationContext); + + expect(errors.length).toBeGreaterThanOrEqual(3); + }); }); }); diff --git a/test/web-components/details.test.ts b/test/web-components/details.test.ts index c89ee41..7600b8b 100644 --- a/test/web-components/details.test.ts +++ b/test/web-components/details.test.ts @@ -1,7 +1,319 @@ -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, beforeEach, afterEach } from 'vitest'; +import { DetailsComponent } from '../../web-components/details'; +import type { IBlock } from '@polarityio/pi-components'; + +customElements.define('test-qualys-details', DetailsComponent); + +function createBlock(details: Record): IBlock { + return { + integrationId: 'qualys-integration', + acronym: 'QLS', + data: { details, summary: ['Host Detections: 1'] } + }; +} + +async function renderComponent(block: IBlock): Promise { + const el = document.createElement('test-qualys-details') as DetailsComponent; + (el as any).services = { + currentServer: {}, + currentUser: {}, + flashMessages: {}, + moment: {}, + notificationsData: {}, + polarityx: {}, + searchData: {}, + session: {}, + store: {}, + windowService: {}, + log: {}, + integrationMessenger: {}, + lookupService: () => undefined + }; + el.block = block; + document.body.appendChild(el); + await el.updateComplete; + return el; +} + +function getShadowHTML(el: DetailsComponent): string { + return el.shadowRoot?.innerHTML || ''; +} describe('Qualys DetailsComponent', () => { - it('should be implemented', () => { - expect(true).toBe(true); + let el: DetailsComponent | null = null; + + afterEach(() => { + if (el && el.parentNode) { + el.parentNode.removeChild(el); + } + el = null; + }); + + it('should render without errors when given valid host detection data', async () => { + el = await renderComponent( + createBlock({ + tabKeys: ['hostDetections'], + hostDetections: [ + { label: 'IP Address', value: '192.168.1.1', isTitle: true, showLabelAndValue: true }, + { label: 'Host Detection ID', value: '12345' }, + { label: 'Asset Id', value: '67890' }, + { label: 'Operating System', value: 'Linux 4.15' } + ] + }) + ); + + const html = getShadowHTML(el); + expect(html).toContain('192.168.1.1'); + expect(html).toContain('IP Address'); + }); + + it('should render nothing when tabKeys is empty', async () => { + el = await renderComponent(createBlock({ tabKeys: [] })); + const html = getShadowHTML(el); + expect(html).not.toContain('pi-tab'); + expect(html).not.toContain('pi-key-value'); + }); + + it('should render nothing when details is undefined', async () => { + const block: IBlock = { + integrationId: 'qualys-integration', + acronym: 'QLS', + data: { details: undefined as any, summary: [] } + }; + el = await renderComponent(block); + const html = getShadowHTML(el); + expect(html).not.toContain('pi-key-value'); + }); + + it('should render key-value pairs for standard fields', async () => { + el = await renderComponent( + createBlock({ + tabKeys: ['hostDetections'], + hostDetections: [ + { label: 'Operating System', value: 'Linux 4.15' }, + { label: 'DNS', value: 'host.example.com' }, + { label: 'Category', value: 'Confirmed' } + ] + }) + ); + + const html = getShadowHTML(el); + expect(html).toContain('Linux 4.15'); + expect(html).toContain('host.example.com'); + expect(html).toContain('Confirmed'); + }); + + it('should render title fields with showLabelAndValue', async () => { + el = await renderComponent( + createBlock({ + tabKeys: ['hostDetections'], + hostDetections: [ + { label: 'IP Address', value: '10.0.0.1', isTitle: true, showLabelAndValue: true } + ] + }) + ); + + const html = getShadowHTML(el); + expect(html).toContain('IP Address'); + expect(html).toContain('10.0.0.1'); + expect(html).toContain(' { + el = await renderComponent( + createBlock({ + tabKeys: ['hostDetections'], + hostDetections: [{ label: 'Last Scanned', value: '2024-01-15T10:30:00Z', isDate: true }] + }) + ); + + const html = getShadowHTML(el); + expect(html).toContain('Last Scanned'); + // Should contain a formatted date (not the raw ISO string) + expect(html).toContain('01/15/2024'); + }); + + it('should render collapsible list items for detection lists', async () => { + el = await renderComponent( + createBlock({ + tabKeys: ['hostDetections'], + hostDetections: [ + { + label: 'Detections List', + isList: true, + collapsibleListItems: true, + indent: 1, + value: [ + [ + { label: 'Detection Result', value: 'SSL Certificate' }, + { label: 'QID', value: '38623', fieldIsCopyable: true, shouldCopyFieldLabel: true }, + { label: 'Severity', value: '3' } + ] + ] + } + ] + }) + ); + + const html = getShadowHTML(el); + expect(html).toContain('Detections List'); + expect(html).toContain('SSL Certificate'); + // Collapsed by default — inner fields should not be visible + expect(html).not.toContain('Severity'); + }); + + it('should render HTML content in expandable sections', async () => { + el = await renderComponent( + createBlock({ + tabKeys: ['hostDetections'], + hostDetections: [ + { + label: 'Diagnosis', + value: '

This is a vulnerability description

', + isHtml: true + } + ] + }) + ); + + const html = getShadowHTML(el); + expect(html).toContain('Diagnosis'); + // HTML content is collapsed by default + expect(html).not.toContain('This is a vulnerability description'); + }); + + it('should render the copy button', async () => { + el = await renderComponent( + createBlock({ + tabKeys: ['hostDetections'], + hostDetections: [{ label: 'IP', value: '192.168.1.1' }] + }) + ); + + const html = getShadowHTML(el); + expect(html).toContain('pi-copy-button'); + }); + + it('should render section breaks for isNewSectionLineBreak fields', async () => { + el = await renderComponent( + createBlock({ + tabKeys: ['hostDetections'], + hostDetections: [ + { label: 'Field1', value: 'value1' }, + { isNewSectionLineBreak: true }, + { label: 'Field2', value: 'value2' } + ] + }) + ); + + const html = getShadowHTML(el); + expect(html).toContain('section-break'); + }); + + it('should not render tabs when there is only one visible tab', async () => { + el = await renderComponent( + createBlock({ + tabKeys: ['hostDetections'], + hostDetections: [{ label: 'Field', value: 'value' }] + }) + ); + + const html = getShadowHTML(el); + expect(html).not.toContain('pi-tab-group'); + }); + + it('should render tabs when there are multiple visible tabs', async () => { + el = await renderComponent( + createBlock({ + tabKeys: ['hostDetections', 'knowledgeBase'], + hostDetections: [{ label: 'IP', value: '192.168.1.1' }], + knowledgeBase: [{ label: 'Title', value: 'Vuln Title', isTitle: true }] + }) + ); + + const html = getShadowHTML(el); + expect(html).toContain('pi-tab-group'); + expect(html).toContain('Host Detections'); + expect(html).toContain('Knowledge Base'); + }); + + it('should skip tabs with empty data arrays', async () => { + el = await renderComponent( + createBlock({ + tabKeys: ['hostDetections', 'emptyTab'], + hostDetections: [{ label: 'IP', value: '192.168.1.1' }], + emptyTab: [] + }) + ); + + const html = getShadowHTML(el); + // Should NOT show a tab group since only one tab has data + expect(html).not.toContain('pi-tab-group'); + }); + + it('should render copyable fields with copy button', async () => { + el = await renderComponent( + createBlock({ + tabKeys: ['hostDetections'], + hostDetections: [ + { label: 'QID', value: '38623', fieldIsCopyable: true, shouldCopyFieldLabel: true } + ] + }) + ); + + const html = getShadowHTML(el); + expect(html).toContain('copyable-field'); + expect(html).toContain('38623'); + expect(html).toContain('QID'); + }); + + it('should render links with pi-external-link for title fields with displayLink', async () => { + el = await renderComponent( + createBlock({ + tabKeys: ['hostDetections'], + hostDetections: [ + { + label: 'Host', + value: 'server1', + isTitle: true, + displayLink: 'https://example.com/host/1' + } + ] + }) + ); + + const html = getShadowHTML(el); + expect(html).toContain('pi-external-link'); + expect(html).toContain('https://example.com/host/1'); + }); + + it('should render list of links', async () => { + el = await renderComponent( + createBlock({ + tabKeys: ['hostDetections'], + hostDetections: [ + { + label: 'CVE IDs', + isListOfLinks: true, + value: [ + { + url: 'https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-0001', + id: 'CVE-2024-0001' + }, + { + url: 'https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-0002', + id: 'CVE-2024-0002' + } + ] + } + ] + }) + ); + + const html = getShadowHTML(el); + expect(html).toContain('CVE IDs'); + expect(html).toContain('CVE-2024-0001'); + expect(html).toContain('CVE-2024-0002'); + expect(html).toContain('pi-external-link'); }); }); diff --git a/vitest.config.ts b/vitest.config.ts index fb62fc3..e6cf8f6 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -1,10 +1,35 @@ import { defineConfig } from 'vitest/config'; import { playwright } from '@vitest/browser-playwright'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +const resolveConfig = { + alias: [ + { + find: /^polarity-integration-utils\/requests$/, + replacement: path.resolve( + __dirname, + 'node_modules/polarity-integration-utils/dist/lib/requests/index.js' + ) + }, + { + find: /^polarity-integration-utils$/, + replacement: path.resolve( + __dirname, + 'node_modules/polarity-integration-utils/dist/lib/index.js' + ) + } + ] +}; export default defineConfig({ + resolve: resolveConfig, test: { projects: [ { + resolve: resolveConfig, test: { name: 'server', environment: 'node', @@ -13,6 +38,7 @@ export default defineConfig({ } }, { + resolve: resolveConfig, test: { name: 'browser', include: ['test/web-components/**/*.test.ts'], From f5cb4d50ec9107f62d4e50af8bfee2e09fb068b9 Mon Sep 17 00:00:00 2001 From: Danbi Wyman Date: Fri, 12 Jun 2026 11:04:53 -0400 Subject: [PATCH 04/13] feat(INT-2037): relax QID regex, add editable customType data type, add customTypeValueRegex option --- config/config.json | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/config/config.json b/config/config.json index a6d8692..425b343 100644 --- a/config/config.json +++ b/config/config.json @@ -55,12 +55,29 @@ "type": "password", "userCanEdit": false, "adminOnly": true + }, + { + "key": "customTypeValueRegex", + "name": "Custom Type Value Regex", + "description": "A regular expression used to extract the numeric QID value from a matched Custom Type entity. The full regex match is used as the QID (no capture groups). Defaults to '\\d+$' which extracts trailing digits. Only applies when the Custom Type Data Type is enabled.", + "default": "\\d+$", + "type": "text", + "userCanEdit": false, + "adminOnly": true } ], "customTypes": [ { "key": "qid", - "regex": "(?:QID|qid):\\s*\\d{1,8}" + "regex": "(?:QID|qid)(?:\\s*:\\s*|\\s+)\\d{1,8}" + }, + { + "key": "customType", + "name": "Custom Type", + "description": "A customer-defined entity type. Set the regex to match your organization's QID format in the Polarity admin Data Types settings. The integration will extract a numeric QID from each match using the 'Custom Type Value Regex' option.", + "regex": "CUSTOM-\\d+", + "editable": true, + "enabled": false } ] -} +} \ No newline at end of file From 38501eb73109fbfde183549d04d85d1c04b52c99 Mon Sep 17 00:00:00 2001 From: Danbi Wyman Date: Fri, 12 Jun 2026 11:05:14 -0400 Subject: [PATCH 05/13] feat(INT-2037): fix QID value extraction regex; add customType entity handling --- src/getLookupResults.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/getLookupResults.ts b/src/getLookupResults.ts index 9ca66eb..a6d558a 100644 --- a/src/getLookupResults.ts +++ b/src/getLookupResults.ts @@ -1,4 +1,4 @@ -import { flow, map, split, first, last, trim, uniqBy } from 'lodash/fp'; +import { flow, map, split, first, last, uniqBy } from 'lodash/fp'; import type { Entity, Logger } from '@polarityio/integration-types'; import type { PolarityRequest } from 'polarity-integration-utils'; @@ -20,8 +20,19 @@ export const getLookupResults = async ( entity.type === 'custom' ? (flow(first, split('.'), last)(entity.types) as string) : entity.type; + const value = - type === 'qid' ? (flow(split(':'), last, trim)(entity.value) as string) : entity.value; + type === 'qid' + ? (/(?:QID|qid)(?:\s*:\s*|\s+)(\d{1,8})/i.exec(entity.value)?.[1] ?? entity.value) + : entity.value; + + if (type === 'customType') { + const extractRegex = new RegExp(options.customTypeValueRegex || '\\d+$'); + const extracted = extractRegex.exec(entity.value)?.[0]; + if (extracted) { + return { ...entity, type, value: extracted } as Entity; + } + } return { ...entity, type, value } as Entity; }, entities); @@ -50,4 +61,4 @@ const getData = async ( Logger.trace({ allHostDetections }, 'All Host Detections'); return { allHostDetections, allFoundKnowledgeBaseRecords: undefined }; -}; +}; \ No newline at end of file From 691721f0f154d0e3935159e503e6a83705422e94 Mon Sep 17 00:00:00 2001 From: Danbi Wyman Date: Fri, 12 Jun 2026 11:05:39 -0400 Subject: [PATCH 06/13] feat(INT-2037): add customType to QUERY_PATHS_BY_TYPE --- src/constants.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/constants.ts b/src/constants.ts index 2c130ca..f005970 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -22,6 +22,7 @@ export const QUERY_PATHS_BY_TYPE: Record> = { vulnerabilities: ['vulnerabilities.vulnerability.title'] } }; +QUERY_PATHS_BY_TYPE.customType = QUERY_PATHS_BY_TYPE.qid; export const SEARCH_COLUMN_NAMES_BY_TYPE: Record = { cve: ['title', 'category', 'diagnosis', 'solution', 'cves', 'vender_references'], @@ -103,4 +104,4 @@ export const KNOWLEDGE_BASE_RECORD_DISPLAY_FORMAT: DisplayFormat = { diagnosis: { label: 'Diagnosis', isHtml: true }, solution: { label: 'Solution', isHtml: true }, newSectionLineBreak: { isNewSectionLineBreak: true } -}; +}; \ No newline at end of file From 12258396ca544da932b6945d7498eef203c066d1 Mon Sep 17 00:00:00 2001 From: Danbi Wyman Date: Fri, 12 Jun 2026 11:06:02 -0400 Subject: [PATCH 07/13] feat(INT-2037): include customType entities in QID host detection filter --- src/querying/queryHostDetectionListForAllEntities.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/querying/queryHostDetectionListForAllEntities.ts b/src/querying/queryHostDetectionListForAllEntities.ts index 9c35db6..84b3789 100644 --- a/src/querying/queryHostDetectionListForAllEntities.ts +++ b/src/querying/queryHostDetectionListForAllEntities.ts @@ -21,7 +21,10 @@ const queryHostDetectionListForAllEntities = async ( const ipEntities = filter(flow(get('type'), or(eq('IPv4'), eq('IPv6'))), entities); const ipValues = map(get('value'), ipEntities) as string[]; - const qidEntities = filter(flow(get('type'), eq('qid')), entities); + const qidEntities = filter( + flow(get('type'), (t) => t === 'qid' || t === 'customType'), + entities + ); const qidValues = map(get('value'), qidEntities) as string[]; const allHostDetectionResultForIpAddresses = size(ipValues) @@ -126,4 +129,4 @@ const HOST_DETECTIONS_LIST_FORMAT: Record = { } }; -export default queryHostDetectionListForAllEntities; +export default queryHostDetectionListForAllEntities; \ No newline at end of file From f33fc6f01ea59ca27d297e248af893c28405c94b Mon Sep 17 00:00:00 2001 From: Danbi Wyman Date: Fri, 12 Jun 2026 11:06:21 -0400 Subject: [PATCH 08/13] feat(INT-2037): add validateCustomTypeValueRegex utility --- src/validateOptions.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/validateOptions.ts b/src/validateOptions.ts index 422d72b..f2052f1 100644 --- a/src/validateOptions.ts +++ b/src/validateOptions.ts @@ -43,3 +43,21 @@ export const validateUrlOption = ( return otherErrors; }; + +export const validateCustomTypeValueRegex = ( + options: ValidateOptionsUserOptions, + otherErrors: ValidationError[] = [] +): ValidationError[] => { + const regexValue = options.customTypeValueRegex?.value as string | undefined; + if (regexValue) { + try { + new RegExp(regexValue); + } catch { + return otherErrors.concat({ + key: 'customTypeValueRegex', + message: 'Invalid regular expression syntax.' + }); + } + } + return otherErrors; +}; \ No newline at end of file From 970fe77284d3068b089c615a3f3dbe40c886c243 Mon Sep 17 00:00:00 2001 From: Danbi Wyman Date: Fri, 12 Jun 2026 11:06:33 -0400 Subject: [PATCH 09/13] feat(INT-2037): wire validateCustomTypeValueRegex into validateOptions --- src/integration.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/integration.ts b/src/integration.ts index 696a04d..5cf6db6 100644 --- a/src/integration.ts +++ b/src/integration.ts @@ -13,7 +13,7 @@ import type { BeforeRequestHook } from 'polarity-integration-utils'; import { parseErrorToReadableJSON } from './dataTransformations'; import { getLookupResults } from './getLookupResults'; -import { validateStringOptions, validateUrlOption } from './validateOptions'; +import { validateStringOptions, validateUrlOption, validateCustomTypeValueRegex } from './validateOptions'; let request: PolarityRequest; @@ -72,7 +72,9 @@ function validateOptions( const urlValidationErrors = validateUrlOption(options.url.value as string); - return stringValidationErrors.concat(urlValidationErrors); + const customTypeRegexErrors = validateCustomTypeValueRegex(options); + + return stringValidationErrors.concat(urlValidationErrors).concat(customTypeRegexErrors); } -export { startup, doLookup, validateOptions }; +export { startup, doLookup, validateOptions }; \ No newline at end of file From 7f3dbacd0a06740e1a469d65db14ff4278512df0 Mon Sep 17 00:00:00 2001 From: Danbi Wyman Date: Fri, 12 Jun 2026 11:06:43 -0400 Subject: [PATCH 10/13] chore(INT-2037): bump version to 3.4.0 for v1 CMS store release --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 4a1f6c5..f64f275 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "qualys", - "version": "4.0.0", + "version": "3.4.0", "main": "./dist/integration.js", "private": true, "license": "UNLICENSED", @@ -41,4 +41,4 @@ "test:browser": "vitest run --project browser", "test:watch": "vitest" } -} +} \ No newline at end of file From ea1de5f983d0106185bd84b697081925e7d822ef Mon Sep 17 00:00:00 2001 From: Danbi Wyman Date: Fri, 12 Jun 2026 11:24:33 -0400 Subject: [PATCH 11/13] fix: update webComponent element version suffix to v3-4-0 --- config/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.json b/config/config.json index 425b343..8bf731e 100644 --- a/config/config.json +++ b/config/config.json @@ -19,7 +19,7 @@ "components": [ { "type": "details", - "element": "px-int-4szfuj42ymklnvnabm9q4yt1l-qls-details-v4-0-0" + "element": "px-int-4szfuj42ymklnvnabm9q4yt1l-qls-details-v3-4-0" } ] }, From c0949d71723b4d45040cb0c6e4352bf4bfc0a303 Mon Sep 17 00:00:00 2001 From: Danbi Wyman Date: Fri, 12 Jun 2026 11:28:46 -0400 Subject: [PATCH 12/13] chore: trigger CI on fix commit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 837bac5..4fed2df 100644 --- a/README.md +++ b/README.md @@ -42,4 +42,4 @@ Installation instructions for integrations are provided on the [PolarityIO GitHu ## Polarity Polarity is a memory-augmentation platform that improves and accelerates analyst decision making. For more information about the Polarity platform please see: -https://polarity.io/ \ No newline at end of file +https://polarity.io/ From 3d69426da24011f7e7eaea4fa757f0ff509b5cd8 Mon Sep 17 00:00:00 2001 From: Danbi Wyman Date: Fri, 12 Jun 2026 11:43:48 -0400 Subject: [PATCH 13/13] chore: trigger CI