From 82fadf587b188a565da4b8620ed7b753f05ccd92 Mon Sep 17 00:00:00 2001 From: Teffen Ellis Date: Thu, 3 Apr 2025 21:07:39 +0200 Subject: [PATCH] web: Use ESBuild for bundling. Split out webauthn utils. Prep for TypeScript monorepo. --- .github/workflows/api-ts-publish.yml | 5 - Dockerfile | 1 - authentik/flows/templates/if/flow-sfe.html | 2 +- package-lock.json | 4 +- web/authentication/index.js | 211 ++ web/eslint.config.mjs | 15 +- web/package-lock.json | 1914 ++--------------- web/package.json | 39 +- web/packages/sfe/.prettierrc.json | 23 - web/packages/sfe/LICENSE.txt | 18 - web/packages/sfe/package.json | 68 - web/packages/sfe/rollup.config.js | 43 - web/packages/sfe/src/index.ts | 527 ----- web/packages/sfe/tsconfig.json | 7 - web/paths.js | 25 + web/scripts/build-sfe.mjs | 90 + web/scripts/build-web.mjs | 5 +- web/{packages => }/sfe/README.md | 0 web/sfe/lib/AuthenticatorValidateStage.js | 191 ++ web/sfe/lib/AutosubmitStage.js | 35 + web/sfe/lib/IdentificationStage.js | 50 + web/sfe/lib/PasswordStage.js | 37 + web/sfe/lib/RedirectStage.js | 14 + web/sfe/lib/SimpleFlowExecutor.js | 113 + web/sfe/lib/Stage.js | 116 + web/sfe/lib/index.js | 12 + web/sfe/lib/utils.js | 20 + web/sfe/main.js | 17 + web/sfe/tsconfig.json | 46 + web/src/common/helpers/webauthn.ts | 145 -- .../AuthenticatorValidateStageWebAuthn.ts | 12 +- .../WebAuthnAuthenticatorRegisterStage.ts | 14 +- web/tsconfig.base.json | 12 +- web/tsconfig.json | 11 +- web/tsconfig.test.json | 7 +- 35 files changed, 1273 insertions(+), 2576 deletions(-) create mode 100644 web/authentication/index.js delete mode 100644 web/packages/sfe/.prettierrc.json delete mode 100644 web/packages/sfe/LICENSE.txt delete mode 100644 web/packages/sfe/package.json delete mode 100644 web/packages/sfe/rollup.config.js delete mode 100644 web/packages/sfe/src/index.ts delete mode 100644 web/packages/sfe/tsconfig.json create mode 100644 web/paths.js create mode 100644 web/scripts/build-sfe.mjs rename web/{packages => }/sfe/README.md (100%) create mode 100644 web/sfe/lib/AuthenticatorValidateStage.js create mode 100644 web/sfe/lib/AutosubmitStage.js create mode 100644 web/sfe/lib/IdentificationStage.js create mode 100644 web/sfe/lib/PasswordStage.js create mode 100644 web/sfe/lib/RedirectStage.js create mode 100644 web/sfe/lib/SimpleFlowExecutor.js create mode 100644 web/sfe/lib/Stage.js create mode 100644 web/sfe/lib/index.js create mode 100644 web/sfe/lib/utils.js create mode 100644 web/sfe/main.js create mode 100644 web/sfe/tsconfig.json delete mode 100644 web/src/common/helpers/webauthn.ts diff --git a/.github/workflows/api-ts-publish.yml b/.github/workflows/api-ts-publish.yml index 7176cb5ed1..7599518f1a 100644 --- a/.github/workflows/api-ts-publish.yml +++ b/.github/workflows/api-ts-publish.yml @@ -36,11 +36,6 @@ jobs: run: | export VERSION=`node -e 'console.log(require("../gen-ts-api/package.json").version)'` npm i @goauthentik/api@$VERSION - - name: Upgrade /web/packages/sfe - working-directory: web/packages/sfe - run: | - export VERSION=`node -e 'console.log(require("../gen-ts-api/package.json").version)'` - npm i @goauthentik/api@$VERSION - uses: peter-evans/create-pull-request@v7 id: cpr with: diff --git a/Dockerfile b/Dockerfile index d7fdca789a..7bfb71a54a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -30,7 +30,6 @@ WORKDIR /work/web RUN --mount=type=bind,target=/work/web/package.json,src=./web/package.json \ --mount=type=bind,target=/work/web/package-lock.json,src=./web/package-lock.json \ - --mount=type=bind,target=/work/web/packages/sfe/package.json,src=./web/packages/sfe/package.json \ --mount=type=bind,target=/work/web/scripts,src=./web/scripts \ --mount=type=cache,id=npm-web,sharing=shared,target=/root/.npm \ npm ci --include=dev diff --git a/authentik/flows/templates/if/flow-sfe.html b/authentik/flows/templates/if/flow-sfe.html index abea71934b..edea3ee50b 100644 --- a/authentik/flows/templates/if/flow-sfe.html +++ b/authentik/flows/templates/if/flow-sfe.html @@ -49,6 +49,6 @@ {% trans 'Powered by authentik' %} - + diff --git a/package-lock.json b/package-lock.json index 1196020e4e..e9af9633c1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@goauthentik/authentik", - "version": "2025.2.1", + "version": "2025.2.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@goauthentik/authentik", - "version": "2025.2.1" + "version": "2025.2.3" } } } diff --git a/web/authentication/index.js b/web/authentication/index.js new file mode 100644 index 0000000000..9b035f7aa3 --- /dev/null +++ b/web/authentication/index.js @@ -0,0 +1,211 @@ +/** + * @file WebAuthn utilities. + * + * @remarks + * + * This duplicates much of the logic in the main web app's WebAuthn utilities. + * Can we share this code while keeping IE11 support? + */ +import { fromByteArray } from "base64-js"; + +//@ts-check + +//#region Type Definitions + +/** + * @typedef {object} Assertion + * @property {string} id + * @property {string} rawId + * @property {string} type + * @property {string} registrationClientExtensions + * @property {object} response + * @property {string} response.clientDataJSON + * @property {string} response.attestationObject + */ + +/** + * @typedef {object} AuthAssertion + * @property {string} id + * @property {string} rawId + * @property {string} type + * @property {string} assertionClientExtensions + * @property {object} response + * @property {string} response.clientDataJSON + * @property {string} response.authenticatorData + * @property {string} response.signature + * @property {string | null} response.userHandle + */ + +//#endregion + +//#region Encoding/Decoding + +/** + * Encodes a byte array into a URL-safe base64 string. + * + * @param {Uint8Array} buffer + * @returns {string} + */ +export function encodeBase64(buffer) { + return fromByteArray(buffer).replace(/\+/g, "-").replace(/\//g, "_").replace(/[=]/g, ""); +} + +/** + * Encodes a byte array into a base64 string without URL-safe encoding, i.e., with padding. + * @param {Uint8Array} buffer + * @returns {string} + */ +export function encodeBase64Raw(buffer) { + return fromByteArray(buffer).replace(/\+/g, "-").replace(/\//g, "_"); +} + +/** + * Decodes a base64 string into a byte array. + * + * @param {string} input + * @returns {Uint8Array} + */ +export function decodeBase64(input) { + return Uint8Array.from(atob(input.replace(/_/g, "/").replace(/-/g, "+")), (c) => + c.charCodeAt(0), + ); +} + +//#endregion + +//#region Utility Functions + +/** + * Checks if the browser supports WebAuthn. + * + * @returns {boolean} + */ +export function isWebAuthnSupported() { + if ("credentials" in navigator) return true; + + if (window.location.protocol === "http:" && window.location.hostname !== "localhost") { + console.warn("WebAuthn requires this page to be accessed via HTTPS."); + return false; + } + + console.warn("WebAuthn not supported by browser."); + return false; +} + +/** + * Asserts that the browser supports WebAuthn and that we're in a secure context. + * + * @throws {Error} If WebAuthn is not supported. + */ +export function assertWebAuthnSupport() { + // Is the navigator exposing the credentials API? + if ("credentials" in navigator) return; + + if (window.location.protocol === "http:" && window.location.hostname !== "localhost") { + throw new Error("WebAuthn requires this page to be accessed via HTTPS."); + } + throw new Error("WebAuthn not supported by browser."); +} + +/** + * Transforms items in the credentialCreateOptions generated on the server + * into byte arrays expected by the navigator.credentials.create() call + * @param {PublicKeyCredentialCreationOptions} credentialCreateOptions + * @param {string} userID + * @returns {PublicKeyCredentialCreationOptions} + */ +export function transformCredentialCreateOptions(credentialCreateOptions, userID) { + const user = credentialCreateOptions.user; + // Because json can't contain raw bytes, the server base64-encodes the User ID + // So to get the base64 encoded byte array, we first need to convert it to a regular + // string, then a byte array, re-encode it and wrap that in an array. + const stringId = decodeURIComponent(window.atob(userID)); + + user.id = decodeBase64(encodeBase64(decodeBase64(stringId))); + const challenge = decodeBase64(credentialCreateOptions.challenge.toString()); + + return { + ...credentialCreateOptions, + challenge, + user, + }; +} + +/** + * Transforms the binary data in the credential into base64 strings + * for posting to the server. + * + * @param {PublicKeyCredential} newAssertion + * @returns {Assertion} + */ +export function transformNewAssertionForServer(newAssertion) { + const response = /** @type {AuthenticatorAttestationResponse} */ (newAssertion.response); + + const attObj = new Uint8Array(response.attestationObject); + const clientDataJSON = new Uint8Array(newAssertion.response.clientDataJSON); + const rawId = new Uint8Array(newAssertion.rawId); + + const registrationClientExtensions = newAssertion.getClientExtensionResults(); + + return { + id: newAssertion.id, + rawId: encodeBase64(rawId), + type: newAssertion.type, + registrationClientExtensions: JSON.stringify(registrationClientExtensions), + response: { + clientDataJSON: encodeBase64(clientDataJSON), + attestationObject: encodeBase64(attObj), + }, + }; +} + +/** + * Transforms the items in the credentialRequestOptions generated on the server + * + * @param {PublicKeyCredentialRequestOptions} credentialRequestOptions + * @returns {PublicKeyCredentialRequestOptions} + */ +export function transformCredentialRequestOptions(credentialRequestOptions) { + const challenge = decodeBase64(credentialRequestOptions.challenge.toString()); + + const allowCredentials = (credentialRequestOptions.allowCredentials || []).map( + (credentialDescriptor) => { + const id = decodeBase64(credentialDescriptor.id.toString()); + return Object.assign({}, credentialDescriptor, { id }); + }, + ); + + return Object.assign({}, credentialRequestOptions, { + challenge, + allowCredentials, + }); +} + +/** + * Encodes the binary data in the assertion into strings for posting to the server. + * @param {PublicKeyCredential} newAssertion + * @returns {AuthAssertion} + */ +export function transformAssertionForServer(newAssertion) { + const response = /** @type {AuthenticatorAssertionResponse} */ (newAssertion.response); + + const authData = new Uint8Array(response.authenticatorData); + const clientDataJSON = new Uint8Array(response.clientDataJSON); + const rawId = new Uint8Array(newAssertion.rawId); + const sig = new Uint8Array(response.signature); + const assertionClientExtensions = newAssertion.getClientExtensionResults(); + + return { + id: newAssertion.id, + rawId: encodeBase64(rawId), + type: newAssertion.type, + assertionClientExtensions: JSON.stringify(assertionClientExtensions), + + response: { + clientDataJSON: encodeBase64Raw(clientDataJSON), + signature: encodeBase64Raw(sig), + authenticatorData: encodeBase64Raw(authData), + userHandle: null, + }, + }; +} diff --git a/web/eslint.config.mjs b/web/eslint.config.mjs index 1d3fd5911d..6996611a4e 100644 --- a/web/eslint.config.mjs +++ b/web/eslint.config.mjs @@ -48,6 +48,9 @@ export default [ "lit/no-template-bind": "error", "no-unused-vars": "off", "no-console": ["error", { allow: ["debug", "warn", "error"] }], + // TODO: TypeScript already handles this. + // Remove after project-wide ESLint config is properly set up. + "no-undef": "off", "@typescript-eslint/ban-ts-comment": "off", "@typescript-eslint/no-unused-vars": [ "error", @@ -71,8 +74,18 @@ export default [ ...globals.node, }, }, - files: ["scripts/**/*.mjs", "*.ts", "*.mjs"], + files: [ + // TODO:Remove after project-wide ESLint config is properly set up. + "scripts/**/*.mjs", + "authentication/**/*.js", + "sfe/**/*.js", + "*.ts", + "*.mjs", + ], rules: { + "no-undef": "off", + // TODO: TypeScript already handles this. + // Remove after project-wide ESLint config is properly set up. "no-unused-vars": "off", // We WANT our scripts to output to the console! "no-console": "off", diff --git a/web/package-lock.json b/web/package-lock.json index d196cdd3c5..752042a89a 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -38,6 +38,7 @@ "@spotlightjs/spotlight": "^2.4.2", "@webcomponents/webcomponentsjs": "^2.8.0", "base64-js": "^1.5.1", + "bootstrap": "^4.6.1", "change-case": "^5.4.4", "chart.js": "^4.4.4", "chartjs-adapter-date-fns": "^3.0.0", @@ -48,9 +49,11 @@ "date-fns": "^4.1.0", "deepmerge-ts": "^7.1.5", "dompurify": "^3.2.4", + "formdata-polyfill": "^4.0.10", "fuse.js": "^7.0.0", "guacamole-common-js": "^1.5.0", "hastscript": "^9.0.1", + "jquery": "^3.7.1", "lit": "^3.2.0", "md-front-matter": "^1.0.4", "mermaid": "^11.4.1", @@ -68,6 +71,7 @@ "style-mod": "^4.1.2", "ts-pattern": "^5.4.0", "unist-util-visit": "^5.0.0", + "weakmap-polyfill": "^2.0.4", "webcomponent-qr-code": "^1.2.0", "yaml": "^2.5.1" }, @@ -91,6 +95,7 @@ "@types/eslint__js": "^8.42.3", "@types/grecaptcha": "^3.0.9", "@types/guacamole-common-js": "^1.5.2", + "@types/jquery": "^3.5.31", "@types/mocha": "^10.0.8", "@types/node": "^22.7.4", "@types/react": "^18.3.13", @@ -102,6 +107,8 @@ "@wdio/spec-reporter": "^9.1.2", "chromedriver": "^131.0.1", "esbuild": "^0.25.0", + "esbuild-plugin-copy": "^2.1.1", + "esbuild-plugin-es5": "^2.1.1", "esbuild-plugin-polyfill-node": "^0.3.0", "esbuild-plugins-node-modules-polyfill": "^1.7.0", "eslint": "^9.11.1", @@ -1843,10 +1850,6 @@ "resolved": "", "link": true }, - "node_modules/@goauthentik/web-sfe": { - "resolved": "packages/sfe", - "link": true - }, "node_modules/@hcaptcha/types": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@hcaptcha/types/-/types-1.0.4.tgz", @@ -2717,313 +2720,6 @@ "langium": "3.0.0" } }, - "node_modules/@mole-inc/bin-wrapper": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@mole-inc/bin-wrapper/-/bin-wrapper-8.0.1.tgz", - "integrity": "sha512-sTGoeZnjI8N4KS+sW2AN95gDBErhAguvkw/tWdCjeM8bvxpz5lqrnd0vOJABA1A+Ic3zED7PYoLP/RANLgVotA==", - "dev": true, - "dependencies": { - "bin-check": "^4.1.0", - "bin-version-check": "^5.0.0", - "content-disposition": "^0.5.4", - "ext-name": "^5.0.0", - "file-type": "^17.1.6", - "filenamify": "^5.0.2", - "got": "^11.8.5", - "os-filter-obj": "^2.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } - }, - "node_modules/@napi-rs/nice": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice/-/nice-1.0.1.tgz", - "integrity": "sha512-zM0mVWSXE0a0h9aKACLwKmD6nHcRiKrPpCfvaKqG1CqDEyjEawId0ocXxVzPMCAm6kkWr2P025msfxXEnt8UGQ==", - "dev": true, - "optional": true, - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - }, - "optionalDependencies": { - "@napi-rs/nice-android-arm-eabi": "1.0.1", - "@napi-rs/nice-android-arm64": "1.0.1", - "@napi-rs/nice-darwin-arm64": "1.0.1", - "@napi-rs/nice-darwin-x64": "1.0.1", - "@napi-rs/nice-freebsd-x64": "1.0.1", - "@napi-rs/nice-linux-arm-gnueabihf": "1.0.1", - "@napi-rs/nice-linux-arm64-gnu": "1.0.1", - "@napi-rs/nice-linux-arm64-musl": "1.0.1", - "@napi-rs/nice-linux-ppc64-gnu": "1.0.1", - "@napi-rs/nice-linux-riscv64-gnu": "1.0.1", - "@napi-rs/nice-linux-s390x-gnu": "1.0.1", - "@napi-rs/nice-linux-x64-gnu": "1.0.1", - "@napi-rs/nice-linux-x64-musl": "1.0.1", - "@napi-rs/nice-win32-arm64-msvc": "1.0.1", - "@napi-rs/nice-win32-ia32-msvc": "1.0.1", - "@napi-rs/nice-win32-x64-msvc": "1.0.1" - } - }, - "node_modules/@napi-rs/nice-android-arm-eabi": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm-eabi/-/nice-android-arm-eabi-1.0.1.tgz", - "integrity": "sha512-5qpvOu5IGwDo7MEKVqqyAxF90I6aLj4n07OzpARdgDRfz8UbBztTByBp0RC59r3J1Ij8uzYi6jI7r5Lws7nn6w==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/nice-android-arm64": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm64/-/nice-android-arm64-1.0.1.tgz", - "integrity": "sha512-GqvXL0P8fZ+mQqG1g0o4AO9hJjQaeYG84FRfZaYjyJtZZZcMjXW5TwkL8Y8UApheJgyE13TQ4YNUssQaTgTyvA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/nice-darwin-arm64": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-arm64/-/nice-darwin-arm64-1.0.1.tgz", - "integrity": "sha512-91k3HEqUl2fsrz/sKkuEkscj6EAj3/eZNCLqzD2AA0TtVbkQi8nqxZCZDMkfklULmxLkMxuUdKe7RvG/T6s2AA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/nice-darwin-x64": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-x64/-/nice-darwin-x64-1.0.1.tgz", - "integrity": "sha512-jXnMleYSIR/+TAN/p5u+NkCA7yidgswx5ftqzXdD5wgy/hNR92oerTXHc0jrlBisbd7DpzoaGY4cFD7Sm5GlgQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/nice-freebsd-x64": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-freebsd-x64/-/nice-freebsd-x64-1.0.1.tgz", - "integrity": "sha512-j+iJ/ezONXRQsVIB/FJfwjeQXX7A2tf3gEXs4WUGFrJjpe/z2KB7sOv6zpkm08PofF36C9S7wTNuzHZ/Iiccfw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/nice-linux-arm-gnueabihf": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm-gnueabihf/-/nice-linux-arm-gnueabihf-1.0.1.tgz", - "integrity": "sha512-G8RgJ8FYXYkkSGQwywAUh84m946UTn6l03/vmEXBYNJxQJcD+I3B3k5jmjFG/OPiU8DfvxutOP8bi+F89MCV7Q==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/nice-linux-arm64-gnu": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-gnu/-/nice-linux-arm64-gnu-1.0.1.tgz", - "integrity": "sha512-IMDak59/W5JSab1oZvmNbrms3mHqcreaCeClUjwlwDr0m3BoR09ZiN8cKFBzuSlXgRdZ4PNqCYNeGQv7YMTjuA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/nice-linux-arm64-musl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-musl/-/nice-linux-arm64-musl-1.0.1.tgz", - "integrity": "sha512-wG8fa2VKuWM4CfjOjjRX9YLIbysSVV1S3Kgm2Fnc67ap/soHBeYZa6AGMeR5BJAylYRjnoVOzV19Cmkco3QEPw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/nice-linux-ppc64-gnu": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-ppc64-gnu/-/nice-linux-ppc64-gnu-1.0.1.tgz", - "integrity": "sha512-lxQ9WrBf0IlNTCA9oS2jg/iAjQyTI6JHzABV664LLrLA/SIdD+I1i3Mjf7TsnoUbgopBcCuDztVLfJ0q9ubf6Q==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/nice-linux-riscv64-gnu": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-riscv64-gnu/-/nice-linux-riscv64-gnu-1.0.1.tgz", - "integrity": "sha512-3xs69dO8WSWBb13KBVex+yvxmUeEsdWexxibqskzoKaWx9AIqkMbWmE2npkazJoopPKX2ULKd8Fm9veEn0g4Ig==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/nice-linux-s390x-gnu": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-s390x-gnu/-/nice-linux-s390x-gnu-1.0.1.tgz", - "integrity": "sha512-lMFI3i9rlW7hgToyAzTaEybQYGbQHDrpRkg+1gJWEpH0PLAQoZ8jiY0IzakLfNWnVda1eTYYlxxFYzW8Rqczkg==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/nice-linux-x64-gnu": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-gnu/-/nice-linux-x64-gnu-1.0.1.tgz", - "integrity": "sha512-XQAJs7DRN2GpLN6Fb+ZdGFeYZDdGl2Fn3TmFlqEL5JorgWKrQGRUrpGKbgZ25UeZPILuTKJ+OowG2avN8mThBA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/nice-linux-x64-musl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-musl/-/nice-linux-x64-musl-1.0.1.tgz", - "integrity": "sha512-/rodHpRSgiI9o1faq9SZOp/o2QkKQg7T+DK0R5AkbnI/YxvAIEHf2cngjYzLMQSQgUhxym+LFr+UGZx4vK4QdQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/nice-win32-arm64-msvc": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-arm64-msvc/-/nice-win32-arm64-msvc-1.0.1.tgz", - "integrity": "sha512-rEcz9vZymaCB3OqEXoHnp9YViLct8ugF+6uO5McifTedjq4QMQs3DHz35xBEGhH3gJWEsXMUbzazkz5KNM5YUg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/nice-win32-ia32-msvc": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-ia32-msvc/-/nice-win32-ia32-msvc-1.0.1.tgz", - "integrity": "sha512-t7eBAyPUrWL8su3gDxw9xxxqNwZzAqKo0Szv3IjVQd1GpXXVkb6vBBQUuxfIYaXMzZLwlxRQ7uzM2vdUE9ULGw==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/nice-win32-x64-msvc": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-x64-msvc/-/nice-win32-x64-msvc-1.0.1.tgz", - "integrity": "sha512-JlF+uDcatt3St2ntBG8H02F1mM45i5SF9W+bIKiReVE6wiy3o16oBP/yxt+RZ+N6LbCImJXJ6bXNO2kn9AXicg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -3275,68 +2971,6 @@ "node": ">=18" } }, - "node_modules/@rollup/plugin-commonjs": { - "version": "28.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.0.tgz", - "integrity": "sha512-BJcu+a+Mpq476DMXG+hevgPSl56bkUoi88dKT8t3RyUp8kGuOh+2bU8Gs7zXDlu+fyZggnJ+iOBGrb/O1SorYg==", - "dev": true, - "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "commondir": "^1.0.1", - "estree-walker": "^2.0.2", - "fdir": "^6.1.1", - "is-reference": "1.2.1", - "magic-string": "^0.30.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=16.0.0 || 14 >= 14.17" - }, - "peerDependencies": { - "rollup": "^2.68.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/plugin-commonjs/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/@rollup/plugin-node-resolve": { - "version": "15.3.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.3.0.tgz", - "integrity": "sha512-9eO5McEICxMzJpDW9OnMYSv4Sta3hmt7VtBFz5zR9273suNOydOyq/FrGeGy+KsTRFm8w0SLVhzig2ILFT63Ag==", - "dev": true, - "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "@types/resolve": "1.20.2", - "deepmerge": "^4.2.2", - "is-module": "^1.0.0", - "resolve": "^1.22.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^2.78.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, "node_modules/@rollup/plugin-replace": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-6.0.1.tgz", @@ -3358,28 +2992,6 @@ } } }, - "node_modules/@rollup/plugin-swc": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-swc/-/plugin-swc-0.4.0.tgz", - "integrity": "sha512-oAtqXa8rOl7BOK1Rz3rRxI+LIL53S9SqO2KSq2UUUzWgOgXg6492Jh5mL2mv/f9cpit8zFWdwILuVeozZ0C8mg==", - "dev": true, - "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "smob": "^1.4.0" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "@swc/core": "^1.3.0", - "rollup": "^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, "node_modules/@rollup/plugin-virtual": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/@rollup/plugin-virtual/-/plugin-virtual-3.0.2.tgz", @@ -3756,18 +3368,6 @@ "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", "dev": true }, - "node_modules/@sindresorhus/is": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", - "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/is?sponsor=1" - } - }, "node_modules/@sindresorhus/merge-streams": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", @@ -5466,6 +5066,7 @@ "cpu": [ "arm64" ], + "dev": true, "optional": true, "os": [ "darwin" @@ -5481,6 +5082,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "darwin" @@ -5496,6 +5098,7 @@ "cpu": [ "arm" ], + "dev": true, "optional": true, "os": [ "linux" @@ -5511,6 +5114,7 @@ "cpu": [ "arm64" ], + "dev": true, "optional": true, "os": [ "linux" @@ -5526,6 +5130,7 @@ "cpu": [ "arm64" ], + "dev": true, "optional": true, "os": [ "linux" @@ -5541,6 +5146,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "linux" @@ -5556,6 +5162,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "linux" @@ -5571,6 +5178,7 @@ "cpu": [ "arm64" ], + "dev": true, "optional": true, "os": [ "win32" @@ -5586,6 +5194,7 @@ "cpu": [ "ia32" ], + "dev": true, "optional": true, "os": [ "win32" @@ -5601,6 +5210,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "win32" @@ -5615,6 +5225,16 @@ "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", "dev": true }, + "node_modules/@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, "node_modules/@swc/types": { "version": "0.1.12", "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.12.tgz", @@ -5624,30 +5244,12 @@ "@swc/counter": "^0.1.3" } }, - "node_modules/@szmarczak/http-timer": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", - "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", - "dev": true, - "dependencies": { - "defer-to-connect": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@testim/chrome-version": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/@testim/chrome-version/-/chrome-version-1.1.4.tgz", "integrity": "sha512-kIhULpw9TrGYnHp/8VfdcneIcxKnLixmADtukQRtJUmsVlMg0niMkwV0xZmi8hqa57xqilIHjWFA0GKvEjVU5g==", "dev": true }, - "node_modules/@tokenizer/token": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", - "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", - "dev": true - }, "node_modules/@tootallnate/quickjs-emscripten": { "version": "0.23.0", "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", @@ -5765,18 +5367,6 @@ "@types/node": "*" } }, - "node_modules/@types/cacheable-request": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", - "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", - "dev": true, - "dependencies": { - "@types/http-cache-semantics": "*", - "@types/keyv": "^3.1.4", - "@types/node": "*", - "@types/responselike": "^1.0.0" - } - }, "node_modules/@types/chart.js": { "version": "2.9.41", "resolved": "https://registry.npmjs.org/@types/chart.js/-/chart.js-2.9.41.tgz", @@ -6139,31 +5729,12 @@ "integrity": "sha512-frsJrz2t/CeGifcu/6uRo4b+SzAwT4NYCVPu1GN8IB9XTzrpPkGuV0tmh9mN+/L0PklAlsC3u5Fxt0ju00LXIw==", "dev": true }, - "node_modules/@types/fs-extra": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.5.tgz", - "integrity": "sha512-0dzKcwO+S8s2kuF5Z9oUWatQJj5Uq/iqphEtE3GQJVRRYm/tD1LglU2UnXi2A8jLq5umkGouOXOR9y0n613ZwQ==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/geojson": { "version": "7946.0.16", "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", "license": "MIT" }, - "node_modules/@types/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", - "dev": true, - "dependencies": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, "node_modules/@types/grecaptcha": { "version": "3.0.9", "resolved": "https://registry.npmjs.org/@types/grecaptcha/-/grecaptcha-3.0.9.tgz", @@ -6184,12 +5755,6 @@ "@types/unist": "*" } }, - "node_modules/@types/http-cache-semantics": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", - "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", - "dev": true - }, "node_modules/@types/http-errors": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", @@ -6235,15 +5800,6 @@ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, - "node_modules/@types/keyv": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", - "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/lodash": { "version": "4.17.10", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.10.tgz", @@ -6270,12 +5826,6 @@ "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", "dev": true }, - "node_modules/@types/minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", - "dev": true - }, "node_modules/@types/mocha": { "version": "10.0.8", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.8.tgz", @@ -6359,21 +5909,6 @@ "@types/react": "^18.0.0" } }, - "node_modules/@types/resolve": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", - "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", - "dev": true - }, - "node_modules/@types/responselike": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", - "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/send": { "version": "0.17.4", "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", @@ -8263,47 +7798,6 @@ "node": ">=10.0.0" } }, - "node_modules/@yarnpkg/parsers": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@yarnpkg/parsers/-/parsers-3.0.2.tgz", - "integrity": "sha512-/HcYgtUSiJiot/XWGLOlGxPYUG65+/31V8oqk17vZLW1xlCoR4PampyePljOxY2n8/3jz9+tIFzICsyGujJZoA==", - "dev": true, - "dependencies": { - "js-yaml": "^3.10.0", - "tslib": "^2.4.0" - }, - "engines": { - "node": ">=18.12.0" - } - }, - "node_modules/@yarnpkg/parsers/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/@yarnpkg/parsers/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@yarnpkg/parsers/node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, "node_modules/@zip.js/zip.js": { "version": "2.7.52", "resolved": "https://registry.npmjs.org/@zip.js/zip.js/-/zip.js-2.7.52.tgz", @@ -8535,26 +8029,6 @@ "resolved": "https://registry.npmjs.org/apg-lite/-/apg-lite-1.0.4.tgz", "integrity": "sha512-B32zCN3IdHIc99Vy7V9BaYTUzLeRA8YXYY1aQD1/5I2aqIrO0coi4t6hJPqMisidlBxhyME8UexkHt31SlR6Og==" }, - "node_modules/arch": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", - "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/archiver": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.1.tgz", @@ -8939,264 +8413,6 @@ "node": ">=12.0.0" } }, - "node_modules/bin-check": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bin-check/-/bin-check-4.1.0.tgz", - "integrity": "sha512-b6weQyEUKsDGFlACWSIOfveEnImkJyK/FGW6FAG42loyoquvjdtOIqO6yBFzHyqyVVhNgNkQxxx09SFLK28YnA==", - "dev": true, - "dependencies": { - "execa": "^0.7.0", - "executable": "^4.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/bin-check/node_modules/cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==", - "dev": true, - "dependencies": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "node_modules/bin-check/node_modules/execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha512-RztN09XglpYI7aBBrJCPW95jEH7YF1UEPOoX9yDhUTPdp7mK+CQvnLTuD10BNXZ3byLTu2uehZ8EcKT/4CGiFw==", - "dev": true, - "dependencies": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/bin-check/node_modules/get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/bin-check/node_modules/is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/bin-check/node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/bin-check/node_modules/lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dev": true, - "dependencies": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "node_modules/bin-check/node_modules/npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", - "dev": true, - "dependencies": { - "path-key": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/bin-check/node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/bin-check/node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", - "dev": true, - "dependencies": { - "shebang-regex": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/bin-check/node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/bin-check/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/bin-check/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/bin-check/node_modules/yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", - "dev": true - }, - "node_modules/bin-version": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/bin-version/-/bin-version-6.0.0.tgz", - "integrity": "sha512-nk5wEsP4RiKjG+vF+uG8lFsEn4d7Y6FVDamzzftSunXOoOcOOkzcWdKVlGgFFwlUQCj63SgnUkLLGF8v7lufhw==", - "dev": true, - "dependencies": { - "execa": "^5.0.0", - "find-versions": "^5.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/bin-version-check": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/bin-version-check/-/bin-version-check-5.1.0.tgz", - "integrity": "sha512-bYsvMqJ8yNGILLz1KP9zKLzQ6YpljV3ln1gqhuLkUtyfGi3qXKGuK2p+U4NAvjVFzDFiBBtOpCOSFNuYYEGZ5g==", - "dev": true, - "dependencies": { - "bin-version": "^6.0.0", - "semver": "^7.5.3", - "semver-truncate": "^3.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/bin-version/node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/bin-version/node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/bin-version/node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/bin-version/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/bin-version/node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/bin-version/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/bin-version/node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -9532,48 +8748,6 @@ "node": ">=8.10.0" } }, - "node_modules/cacheable-lookup": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", - "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", - "dev": true, - "engines": { - "node": ">=10.6.0" - } - }, - "node_modules/cacheable-request": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", - "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", - "dev": true, - "dependencies": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^4.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^6.0.1", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cacheable-request/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/call-bind": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", @@ -10055,27 +9229,6 @@ "node": ">=0.8" } }, - "node_modules/clone-response": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", - "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", - "dev": true, - "dependencies": { - "mimic-response": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/clone-response/node_modules/mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/codemirror": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz", @@ -10118,12 +9271,6 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/colorette": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", - "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", - "dev": true - }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -11079,7 +10226,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "devOptional": true, + "optional": true, "dependencies": { "mimic-response": "^3.1.0" }, @@ -11135,15 +10282,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/defer-to-connect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", - "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -12135,6 +11273,191 @@ "node": ">=12" } }, + "node_modules/esbuild-plugin-copy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/esbuild-plugin-copy/-/esbuild-plugin-copy-2.1.1.tgz", + "integrity": "sha512-Bk66jpevTcV8KMFzZI1P7MZKZ+uDcrZm2G2egZ2jNIvVnivDpodZI+/KnpL3Jnap0PBdIHU7HwFGB8r+vV5CVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "fs-extra": "^10.0.1", + "globby": "^11.0.3" + }, + "peerDependencies": { + "esbuild": ">= 0.14.0" + } + }, + "node_modules/esbuild-plugin-copy/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/esbuild-plugin-copy/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/esbuild-plugin-copy/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/esbuild-plugin-copy/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/esbuild-plugin-copy/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/esbuild-plugin-copy/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/esbuild-plugin-copy/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/esbuild-plugin-copy/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/esbuild-plugin-copy/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/esbuild-plugin-copy/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/esbuild-plugin-es5": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/esbuild-plugin-es5/-/esbuild-plugin-es5-2.1.1.tgz", + "integrity": "sha512-GRcHLUwjmrjxz9bN24ooTedrBrAVx7+F8M1aD7FFB+7RTHkt7FY8tHAQ9znyzsV16+95ojbTyJLY+HPO0OI7zA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@swc/core": "^1.5.25", + "@swc/helpers": "^0.5.11", + "deepmerge": "^4.3.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "esbuild": "*" + } + }, "node_modules/esbuild-plugin-polyfill-node": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/esbuild-plugin-polyfill-node/-/esbuild-plugin-polyfill-node-0.3.0.tgz", @@ -12855,27 +12178,6 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/executable": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz", - "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==", - "dev": true, - "dependencies": { - "pify": "^2.2.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/executable/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/expand-template": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", @@ -12996,31 +12298,6 @@ "dev": true, "license": "MIT" }, - "node_modules/ext-list": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", - "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", - "dev": true, - "dependencies": { - "mime-db": "^1.28.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ext-name": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz", - "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==", - "dev": true, - "dependencies": { - "ext-list": "^2.0.0", - "sort-keys-length": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -13208,20 +12485,6 @@ "pend": "~1.2.0" } }, - "node_modules/fdir": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.0.tgz", - "integrity": "sha512-3oB133prH1o4j/L5lLW7uOCF1PlD+/It2L0eL/iAqWMB91RBbqTewABqxhj0ibBd90EEmWZq7ntIWzVaWcXTGQ==", - "dev": true, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, "node_modules/fetch-blob": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", @@ -13305,23 +12568,6 @@ "url": "https://opencollective.com/ramda" } }, - "node_modules/file-type": { - "version": "17.1.6", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-17.1.6.tgz", - "integrity": "sha512-hlDw5Ev+9e883s0pwUsuuYNu4tD7GgpUnOvykjv1Gya0ZIjuKumthDRua90VUn6/nlRKAjcxLUnHNTIUWwWIiw==", - "dev": true, - "dependencies": { - "readable-web-to-node-stream": "^3.0.2", - "strtok3": "^7.0.0-alpha.9", - "token-types": "^5.0.0-alpha.2" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/file-type?sponsor=1" - } - }, "node_modules/filelist": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", @@ -13343,35 +12589,6 @@ "node": ">=10" } }, - "node_modules/filename-reserved-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-3.0.0.tgz", - "integrity": "sha512-hn4cQfU6GOT/7cFHXBqeBg2TbrMBgdD0kcjLhvSQYYwm3s4B6cjvBfb7nBALJLAXqmU5xajSa7X2NnUud/VCdw==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/filenamify": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-5.1.1.tgz", - "integrity": "sha512-M45CbrJLGACfrPOkrTp3j2EcO9OBkKUYME0eiqOCa7i2poaklU0jhlIaMlr8ijLorT0uLAzrn3qXOp5684CkfA==", - "dev": true, - "dependencies": { - "filename-reserved-regex": "^3.0.0", - "strip-outer": "^2.0.0", - "trim-repeated": "^2.0.0" - }, - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -13457,21 +12674,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/find-versions": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-5.1.0.tgz", - "integrity": "sha512-+iwzCJ7C5v5KgcBuueqVoNiHVoQpwiUK5XFLjf0affFTep+Wcw93tPvmb8tqujDNmzhBDPddnWV/qgWSXgq+Hg==", - "dev": true, - "dependencies": { - "semver-regex": "^4.0.5" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/flat": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", @@ -14040,31 +13242,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/got": { - "version": "11.8.6", - "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", - "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", - "dev": true, - "dependencies": { - "@sindresorhus/is": "^4.0.0", - "@szmarczak/http-timer": "^4.0.5", - "@types/cacheable-request": "^6.0.1", - "@types/responselike": "^1.0.0", - "cacheable-lookup": "^5.0.3", - "cacheable-request": "^7.0.2", - "decompress-response": "^6.0.0", - "http2-wrapper": "^1.0.0-beta.5.2", - "lowercase-keys": "^2.0.0", - "p-cancelable": "^2.0.0", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=10.19.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/got?sponsor=1" - } - }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -14545,12 +13722,6 @@ "entities": "^4.5.0" } }, - "node_modules/http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "dev": true - }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -14580,19 +13751,6 @@ "node": ">= 14" } }, - "node_modules/http2-wrapper": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", - "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", - "dev": true, - "dependencies": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.0.0" - }, - "engines": { - "node": ">=10.19.0" - } - }, "node_modules/https-proxy-agent": { "version": "7.0.5", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", @@ -15092,12 +14250,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", - "dev": true - }, "node_modules/is-negative-zero": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", @@ -15145,30 +14297,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-plain-object": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.1.tgz", - "integrity": "sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-potential-custom-element-name": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", "dev": true }, - "node_modules/is-reference": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", - "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", - "dev": true, - "dependencies": { - "@types/estree": "*" - } - }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -16577,39 +15711,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lockfile-lint": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/lockfile-lint/-/lockfile-lint-4.14.0.tgz", - "integrity": "sha512-uyXZ8X4J6EsicG87p0y4SHorJBwABLcaXOpI/j3h8SO/OX4fKTJ6Cqqi+U3zjgU0fo+u/4KbB7fl8ZzTewd0Ow==", - "dev": true, - "dependencies": { - "cosmiconfig": "^9.0.0", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "lockfile-lint-api": "^5.9.1", - "yargs": "^17.7.2" - }, - "bin": { - "lockfile-lint": "bin/lockfile-lint.js" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/lockfile-lint-api": { - "version": "5.9.1", - "resolved": "https://registry.npmjs.org/lockfile-lint-api/-/lockfile-lint-api-5.9.1.tgz", - "integrity": "sha512-us5IT1bGA6KXbq1WrhrSzk9mtPgHKz5nhvv3S4hwcYnhcVOKW2uK0W8+PN9oIgv4pI49WsD5wBdTQFTpNChF/Q==", - "dev": true, - "dependencies": { - "@yarnpkg/parsers": "^3.0.0-rc.48.1", - "debug": "^4.3.4", - "object-hash": "^3.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -16788,15 +15889,6 @@ "loose-envify": "cli.js" } }, - "node_modules/lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/lowlight": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-3.3.0.tgz", @@ -17321,7 +16413,8 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true + "dev": true, + "optional": true }, "node_modules/merge2": { "version": "1.4.1", @@ -18213,7 +17306,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "devOptional": true, + "optional": true, "engines": { "node": ">=10" }, @@ -18913,18 +18006,6 @@ "node": ">=0.10.0" } }, - "node_modules/normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/npm-package-arg": { "version": "11.0.3", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.3.tgz", @@ -19291,15 +18372,6 @@ "node": ">=0.10.0" } }, - "node_modules/object-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, "node_modules/object-inspect": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", @@ -19536,18 +18608,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/os-filter-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/os-filter-obj/-/os-filter-obj-2.0.0.tgz", - "integrity": "sha512-uksVLsqG3pVdzzPvmAHpBK0wKxYItuzZr7SziusRPoz67tGV8rL1szZ6IdeUrbqLjGDwApBtN29eEE3IqGHOjg==", - "dev": true, - "dependencies": { - "arch": "^2.1.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", @@ -19612,24 +18672,6 @@ "node": "*" } }, - "node_modules/p-cancelable": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", - "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -19925,19 +18967,6 @@ "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", "dev": true }, - "node_modules/peek-readable": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.2.0.tgz", - "integrity": "sha512-U94a+eXHzct7vAd19GH3UQ2dH4Satbng0MyYTMaQatL0pvYYL5CTPR25HBhKtecl+4bfu1/i3vC6k0hydO5Vcw==", - "dev": true, - "engines": { - "node": ">=14.16" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, "node_modules/pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -19989,15 +19018,6 @@ "node": ">=4" } }, - "node_modules/piscina": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.7.0.tgz", - "integrity": "sha512-b8hvkpp9zS0zsfa939b/jXbe64Z2gZv0Ha7FYPNUiDIB1y2AtxcOZdfP8xN8HFjUaqQiT9gRlfjAsoL8vdJ1Iw==", - "dev": true, - "optionalDependencies": { - "@napi-rs/nice": "^1.0.1" - } - }, "node_modules/pkg-dir": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", @@ -20479,12 +19499,6 @@ "node": ">=14" } }, - "node_modules/pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", - "dev": true - }, "node_modules/pump": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", @@ -20633,18 +19647,6 @@ "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", "dev": true }, - "node_modules/quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/ramda": { "version": "0.30.1", "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.30.1.tgz", @@ -21091,36 +20093,6 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/readable-web-to-node-stream": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", - "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", - "dev": true, - "dependencies": { - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, - "node_modules/readable-web-to-node-stream/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/readdir-glob": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", @@ -21662,12 +20634,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/resolve-alpn": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", - "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", - "dev": true - }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -21696,18 +20662,6 @@ "node": ">=10" } }, - "node_modules/responselike": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", - "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", - "dev": true, - "dependencies": { - "lowercase-keys": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/resq": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/resq/-/resq-1.11.0.tgz", @@ -21819,125 +20773,6 @@ "fsevents": "~2.3.2" } }, - "node_modules/rollup-plugin-copy": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-copy/-/rollup-plugin-copy-3.5.0.tgz", - "integrity": "sha512-wI8D5dvYovRMx/YYKtUNt3Yxaw4ORC9xo6Gt9t22kveWz1enG9QrhVlagzwrxSC455xD1dHMKhIJkbsQ7d48BA==", - "dev": true, - "dependencies": { - "@types/fs-extra": "^8.0.1", - "colorette": "^1.1.0", - "fs-extra": "^8.1.0", - "globby": "10.0.1", - "is-plain-object": "^3.0.0" - }, - "engines": { - "node": ">=8.3" - } - }, - "node_modules/rollup-plugin-copy/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/rollup-plugin-copy/node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/rollup-plugin-copy/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rollup-plugin-copy/node_modules/globby": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.1.tgz", - "integrity": "sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==", - "dev": true, - "dependencies": { - "@types/glob": "^7.1.1", - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.0.3", - "glob": "^7.1.3", - "ignore": "^5.1.1", - "merge2": "^1.2.3", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/rollup-plugin-copy/node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/rollup-plugin-copy/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/rollup-plugin-copy/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/rollup-plugin-copy/node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/rollup-plugin-modify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/rollup-plugin-modify/-/rollup-plugin-modify-3.0.0.tgz", @@ -22169,33 +21004,6 @@ "node": ">=10" } }, - "node_modules/semver-regex": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-4.0.5.tgz", - "integrity": "sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/semver-truncate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/semver-truncate/-/semver-truncate-3.0.0.tgz", - "integrity": "sha512-LJWA9kSvMolR51oDE6PN3kALBNaUdkxzAGcexw8gjMA8xr5zUqK0JiR3CgARSqanYF3Z1YHvsErb1KDgh+v7Rg==", - "dev": true, - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/send": { "version": "0.19.0", "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", @@ -22468,12 +21276,6 @@ "npm": ">= 3.0.0" } }, - "node_modules/smob": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz", - "integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==", - "dev": true - }, "node_modules/smol-toml": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.3.0.tgz", @@ -22514,39 +21316,6 @@ "node": ">= 14" } }, - "node_modules/sort-keys": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", - "integrity": "sha512-vzn8aSqKgytVik0iwdBEi+zevbTYZogewTUM6dtpmGwEcdzbub/TX4bCzRhebDCRC3QzXgJsLRKB2V/Oof7HXg==", - "dev": true, - "dependencies": { - "is-plain-obj": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sort-keys-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz", - "integrity": "sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw==", - "dev": true, - "dependencies": { - "sort-keys": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sort-keys/node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/source-map": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", @@ -22987,15 +21756,6 @@ "node": ">=4" } }, - "node_modules/strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/strip-final-newline": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", @@ -23040,41 +21800,12 @@ "dev": true, "optional": true }, - "node_modules/strip-outer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-2.0.0.tgz", - "integrity": "sha512-A21Xsm1XzUkK0qK1ZrytDUvqsQWict2Cykhvi0fBQntGG5JSprESasEyV1EZ/4CiR5WB5KjzLTrP/bO37B0wPg==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/strnum": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", "dev": true }, - "node_modules/strtok3": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-7.1.1.tgz", - "integrity": "sha512-mKX8HA/cdBqMKUr0MMZAFssCkIGoZeSCMXgnt79yKxNFguMLVFgRe6wB+fsL0NmoHDbeyZXczy7vEPSoo3rkzg==", - "dev": true, - "dependencies": { - "@tokenizer/token": "^0.3.0", - "peek-readable": "^5.1.3" - }, - "engines": { - "node": ">=16" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, "node_modules/style-mod": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz", @@ -23481,23 +22212,6 @@ "node": ">=0.6" } }, - "node_modules/token-types": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/token-types/-/token-types-5.0.1.tgz", - "integrity": "sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==", - "dev": true, - "dependencies": { - "@tokenizer/token": "^0.3.0", - "ieee754": "^1.2.1" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, "node_modules/toml": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", @@ -23569,30 +22283,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/trim-repeated": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-2.0.0.tgz", - "integrity": "sha512-QUHBFTJGdOwmp0tbOG505xAgOp/YliZP/6UgafFXYZ26WT1bvQmSMJUvkeVSASuJJHbqsFbynTvkd5W8RBTipg==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^5.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/trim-repeated/node_modules/escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/trough": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", @@ -23665,9 +22355,10 @@ } }, "node_modules/tslib": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", - "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==" + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" }, "node_modules/tsx": { "version": "4.19.1", @@ -26375,171 +25066,6 @@ "type": "github", "url": "https://github.com/sponsors/wooorm" } - }, - "packages/sfe": { - "name": "@goauthentik/web-sfe", - "version": "0.0.0", - "license": "MIT", - "dependencies": { - "@goauthentik/api": "^2024.6.0-1719577139", - "base64-js": "^1.5.1", - "bootstrap": "^4.6.1", - "formdata-polyfill": "^4.0.10", - "jquery": "^3.7.1", - "weakmap-polyfill": "^2.0.4" - }, - "devDependencies": { - "@rollup/plugin-commonjs": "^28.0.0", - "@rollup/plugin-node-resolve": "^15.3.0", - "@rollup/plugin-swc": "^0.4.0", - "@swc/cli": "^0.4.0", - "@swc/core": "^1.7.28", - "@trivago/prettier-plugin-sort-imports": "^4.3.0", - "@types/jquery": "^3.5.31", - "lockfile-lint": "^4.14.0", - "prettier": "^3.3.2", - "rollup": "^4.23.0", - "rollup-plugin-copy": "^3.5.0", - "wireit": "^0.14.9" - }, - "optionalDependencies": { - "@swc/core": "^1.7.28", - "@swc/core-darwin-arm64": "^1.6.13", - "@swc/core-darwin-x64": "^1.6.13", - "@swc/core-linux-arm-gnueabihf": "^1.6.13", - "@swc/core-linux-arm64-gnu": "^1.6.13", - "@swc/core-linux-arm64-musl": "^1.6.13", - "@swc/core-linux-x64-gnu": "^1.6.13", - "@swc/core-linux-x64-musl": "^1.6.13", - "@swc/core-win32-arm64-msvc": "^1.6.13", - "@swc/core-win32-ia32-msvc": "^1.6.13", - "@swc/core-win32-x64-msvc": "^1.6.13" - } - }, - "packages/sfe/node_modules/@goauthentik/api": { - "version": "2024.6.0-1720200294", - "resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2024.6.0-1720200294.tgz", - "integrity": "sha512-qGpI+0BpsHWlO8waj89q+6SWjVVuRtYqdmpSIrKFsZt9GLNXCvIAvgS5JI1Sq2z1uWK/8kLNZKDocI/XagqMPQ==" - }, - "packages/sfe/node_modules/@swc/cli": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@swc/cli/-/cli-0.4.0.tgz", - "integrity": "sha512-4JdVrPtF/4rCMXp6Q1h5I6YkYZrCCcqod7Wk97ZQq7K8vNGzJUryBv4eHCvqx5sJOJBrbYm9fcswe1B0TygNoA==", - "dev": true, - "dependencies": { - "@mole-inc/bin-wrapper": "^8.0.1", - "@swc/counter": "^0.1.3", - "commander": "^8.3.0", - "fast-glob": "^3.2.5", - "minimatch": "^9.0.3", - "piscina": "^4.3.0", - "semver": "^7.3.8", - "slash": "3.0.0", - "source-map": "^0.7.3" - }, - "bin": { - "spack": "bin/spack.js", - "swc": "bin/swc.js", - "swcx": "bin/swcx.js" - }, - "engines": { - "node": ">= 16.14.0" - }, - "peerDependencies": { - "@swc/core": "^1.2.66", - "chokidar": "^3.5.1" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, - "packages/sfe/node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "packages/sfe/node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "dev": true, - "engines": { - "node": ">= 12" - } - }, - "packages/sfe/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "packages/sfe/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "packages/sfe/node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "packages/sfe/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } } } } diff --git a/web/package.json b/web/package.json index 5a51954c17..c8c0323686 100644 --- a/web/package.json +++ b/web/package.json @@ -57,9 +57,14 @@ "ts-pattern": "^5.4.0", "unist-util-visit": "^5.0.0", "webcomponent-qr-code": "^1.2.0", - "yaml": "^2.5.1" + "yaml": "^2.5.1", + "bootstrap": "^4.6.1", + "formdata-polyfill": "^4.0.10", + "jquery": "^3.7.1", + "weakmap-polyfill": "^2.0.4" }, "devDependencies": { + "@types/jquery": "^3.5.31", "@eslint/js": "^9.11.1", "@hcaptcha/types": "^1.0.4", "@lit/localize-tools": "^0.8.0", @@ -90,6 +95,8 @@ "@wdio/spec-reporter": "^9.1.2", "chromedriver": "^131.0.1", "esbuild": "^0.25.0", + "esbuild-plugin-copy": "^2.1.1", + "esbuild-plugin-es5": "^2.1.1", "esbuild-plugin-polyfill-node": "^0.3.0", "esbuild-plugins-node-modules-polyfill": "^1.7.0", "eslint": "^9.11.1", @@ -161,6 +168,12 @@ "watch": "run-s build-locales esbuild:watch" }, "type": "module", + "exports": { + "./package.json": "./package.json", + "./paths": "./paths.js", + "./authentication": "./authentication/index.js", + "./scripts/*": "./scripts/*.mjs" + }, "wireit": { "build": { "#comment": [ @@ -193,8 +206,7 @@ "./dist/patternfly.min.css" ], "dependencies": [ - "build-locales", - "./packages/sfe:build" + "build-locales" ], "env": { "NODE_RUNNER": { @@ -204,12 +216,7 @@ } }, "build:sfe": { - "dependencies": [ - "./packages/sfe:build" - ], - "files": [ - "./packages/sfe/**/*.ts" - ] + "command": "node scripts/build-sfe.mjs" }, "build-proxy": { "command": "node scripts/build-web.mjs --proxy", @@ -242,11 +249,6 @@ "lint:package" ] }, - "format:packages": { - "dependencies": [ - "./packages/sfe:prettier" - ] - }, "lint": { "command": "eslint --max-warnings 0 --fix", "env": { @@ -274,11 +276,6 @@ "shell": true, "command": "sh ./scripts/lint-lockfile.sh package-lock.json" }, - "lint:lockfiles": { - "dependencies": [ - "./packages/sfe:lint:lockfile" - ] - }, "lint:package": { "command": "syncpack format -i ' '" }, @@ -314,9 +311,7 @@ "lint:spelling", "lint:package", "lint:lockfile", - "lint:lockfiles", - "lint:precommit", - "format:packages" + "lint:precommit" ] }, "prettier": { diff --git a/web/packages/sfe/.prettierrc.json b/web/packages/sfe/.prettierrc.json deleted file mode 100644 index 0a4c18708b..0000000000 --- a/web/packages/sfe/.prettierrc.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "arrowParens": "always", - "bracketSpacing": true, - "embeddedLanguageFormatting": "auto", - "htmlWhitespaceSensitivity": "css", - "insertPragma": false, - "jsxSingleQuote": false, - "printWidth": 100, - "proseWrap": "preserve", - "quoteProps": "consistent", - "requirePragma": false, - "semi": true, - "singleQuote": false, - "tabWidth": 4, - "trailingComma": "all", - "useTabs": false, - "vueIndentScriptAndStyle": false, - "plugins": ["@trivago/prettier-plugin-sort-imports"], - "importOrder": ["^(@?)lit(.*)$", "\\.css$", "^@goauthentik/api$", "^[./]"], - "importOrderSeparation": true, - "importOrderSortSpecifiers": true, - "importOrderParserPlugins": ["typescript", "classProperties", "decorators-legacy"] -} diff --git a/web/packages/sfe/LICENSE.txt b/web/packages/sfe/LICENSE.txt deleted file mode 100644 index 7e25b63ae0..0000000000 --- a/web/packages/sfe/LICENSE.txt +++ /dev/null @@ -1,18 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2024 Authentik Security, 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. diff --git a/web/packages/sfe/package.json b/web/packages/sfe/package.json deleted file mode 100644 index d490030c7b..0000000000 --- a/web/packages/sfe/package.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "name": "@goauthentik/web-sfe", - "version": "0.0.0", - "dependencies": { - "@goauthentik/api": "^2024.6.0-1719577139", - "base64-js": "^1.5.1", - "bootstrap": "^4.6.1", - "formdata-polyfill": "^4.0.10", - "jquery": "^3.7.1", - "weakmap-polyfill": "^2.0.4" - }, - "devDependencies": { - "@rollup/plugin-commonjs": "^28.0.0", - "@rollup/plugin-node-resolve": "^15.3.0", - "@rollup/plugin-swc": "^0.4.0", - "@swc/cli": "^0.4.0", - "@swc/core": "^1.7.28", - "@trivago/prettier-plugin-sort-imports": "^4.3.0", - "@types/jquery": "^3.5.31", - "lockfile-lint": "^4.14.0", - "prettier": "^3.3.2", - "rollup": "^4.23.0", - "rollup-plugin-copy": "^3.5.0", - "wireit": "^0.14.9" - }, - "license": "MIT", - "optionalDependencies": { - "@swc/core": "^1.7.28", - "@swc/core-darwin-arm64": "^1.6.13", - "@swc/core-darwin-x64": "^1.6.13", - "@swc/core-linux-arm-gnueabihf": "^1.6.13", - "@swc/core-linux-arm64-gnu": "^1.6.13", - "@swc/core-linux-arm64-musl": "^1.6.13", - "@swc/core-linux-x64-gnu": "^1.6.13", - "@swc/core-linux-x64-musl": "^1.6.13", - "@swc/core-win32-arm64-msvc": "^1.6.13", - "@swc/core-win32-ia32-msvc": "^1.6.13", - "@swc/core-win32-x64-msvc": "^1.6.13" - }, - "private": true, - "scripts": { - "build": "wireit", - "lint:lockfile": "wireit", - "prettier": "prettier --write ./src ./tsconfig.json ./rollup.config.js ./package.json", - "watch": "rollup -w -c rollup.config.js --bundleConfigAsCjs" - }, - "wireit": { - "build:sfe": { - "command": "rollup -c rollup.config.js --bundleConfigAsCjs", - "files": [ - "../../node_modules/bootstrap/dist/css/bootstrap.min.css", - "src/index.ts" - ], - "output": [ - "./dist/sfe/*" - ] - }, - "build": { - "command": "mkdir -p ../../dist/sfe && cp -r dist/sfe/* ../../dist/sfe", - "dependencies": [ - "build:sfe" - ] - }, - "lint:lockfile": { - "command": "lockfile-lint --path package.json --type npm --allowed-hosts npm --validate-https" - } - } -} diff --git a/web/packages/sfe/rollup.config.js b/web/packages/sfe/rollup.config.js deleted file mode 100644 index 19fa6cf035..0000000000 --- a/web/packages/sfe/rollup.config.js +++ /dev/null @@ -1,43 +0,0 @@ -import commonjs from "@rollup/plugin-commonjs"; -import resolve from "@rollup/plugin-node-resolve"; -import swc from "@rollup/plugin-swc"; -import copy from "rollup-plugin-copy"; - -export default { - input: "src/index.ts", - output: { - dir: "./dist/sfe", - format: "cjs", - }, - context: "window", - plugins: [ - copy({ - targets: [ - { - src: "../../node_modules/bootstrap/dist/css/bootstrap.min.css", - dest: "./dist/sfe", - }, - ], - }), - resolve({ browser: true }), - commonjs(), - swc({ - swc: { - jsc: { - loose: false, - externalHelpers: false, - // Requires v1.2.50 or upper and requires target to be es2016 or upper. - keepClassNames: false, - }, - minify: false, - env: { - targets: { - edge: "17", - ie: "11", - }, - mode: "entry", - }, - }, - }), - ], -}; diff --git a/web/packages/sfe/src/index.ts b/web/packages/sfe/src/index.ts deleted file mode 100644 index a33e54a22a..0000000000 --- a/web/packages/sfe/src/index.ts +++ /dev/null @@ -1,527 +0,0 @@ -import { fromByteArray } from "base64-js"; -import "formdata-polyfill"; -import $ from "jquery"; -import "weakmap-polyfill"; - -import { - type AuthenticatorValidationChallenge, - type AutosubmitChallenge, - type ChallengeTypes, - ChallengeTypesFromJSON, - type ContextualFlowInfo, - type DeviceChallenge, - type ErrorDetail, - type IdentificationChallenge, - type PasswordChallenge, - type RedirectChallenge, -} from "@goauthentik/api"; - -interface GlobalAuthentik { - brand: { - branding_logo: string; - }; - api: { - base: string; - }; -} - -function ak(): GlobalAuthentik { - return ( - window as unknown as { - authentik: GlobalAuthentik; - } - ).authentik; -} - -class SimpleFlowExecutor { - challenge?: ChallengeTypes; - flowSlug: string; - container: HTMLDivElement; - - constructor(container: HTMLDivElement) { - this.flowSlug = window.location.pathname.split("/")[3]; - this.container = container; - } - - get apiURL() { - return `${ak().api.base}api/v3/flows/executor/${this.flowSlug}/?query=${encodeURIComponent(window.location.search.substring(1))}`; - } - - start() { - $.ajax({ - type: "GET", - url: this.apiURL, - success: (data) => { - this.challenge = ChallengeTypesFromJSON(data); - this.renderChallenge(); - }, - }); - } - - submit(data: { [key: string]: unknown } | FormData) { - $("button[type=submit]").addClass("disabled") - .html(` - Loading...`); - let finalData: { [key: string]: unknown } = {}; - if (data instanceof FormData) { - finalData = {}; - data.forEach((value, key) => { - finalData[key] = value; - }); - } else { - finalData = data; - } - $.ajax({ - type: "POST", - url: this.apiURL, - data: JSON.stringify(finalData), - success: (data) => { - this.challenge = ChallengeTypesFromJSON(data); - this.renderChallenge(); - }, - contentType: "application/json", - dataType: "json", - }); - } - - renderChallenge() { - switch (this.challenge?.component) { - case "ak-stage-identification": - new IdentificationStage(this, this.challenge).render(); - return; - case "ak-stage-password": - new PasswordStage(this, this.challenge).render(); - return; - case "xak-flow-redirect": - new RedirectStage(this, this.challenge).render(); - return; - case "ak-stage-autosubmit": - new AutosubmitStage(this, this.challenge).render(); - return; - case "ak-stage-authenticator-validate": - new AuthenticatorValidateStage(this, this.challenge).render(); - return; - default: - this.container.innerText = "Unsupported stage: " + this.challenge?.component; - return; - } - } -} - -export interface FlowInfoChallenge { - flowInfo?: ContextualFlowInfo; - responseErrors?: { - [key: string]: Array; - }; -} - -class Stage { - constructor( - public executor: SimpleFlowExecutor, - public challenge: T, - ) {} - - error(fieldName: string) { - if (!this.challenge.responseErrors) { - return []; - } - return this.challenge.responseErrors[fieldName] || []; - } - - renderInputError(fieldName: string) { - return `${this.error(fieldName) - .map((error) => { - return `
- ${error.string} -
`; - }) - .join("")}`; - } - - renderNonFieldErrors() { - return `${this.error("non_field_errors") - .map((error) => { - return ``; - }) - .join("")}`; - } - - html(html: string) { - this.executor.container.innerHTML = html; - } - - render() { - throw new Error("Abstract method"); - } -} - -const IS_INVALID = "is-invalid"; - -class IdentificationStage extends Stage { - render() { - this.html(` -
- -

${this.challenge?.flowInfo?.title}

- ${ - this.challenge.applicationPre - ? `

- Log in to continue to ${this.challenge.applicationPre}. -

` - : "" - } -
- -
- ${ - this.challenge.passwordFields - ? `
- 0 ? IS_INVALID : ""}" name="password" placeholder="Password"> - ${this.renderInputError("password")} -
` - : "" - } - ${this.renderNonFieldErrors()} - -
`); - $("#ident-form input[name=uid_field]").trigger("focus"); - $("#ident-form").on("submit", (ev) => { - ev.preventDefault(); - const data = new FormData(ev.target as HTMLFormElement); - this.executor.submit(data); - }); - } -} - -class PasswordStage extends Stage { - render() { - this.html(` -
- -

${this.challenge?.flowInfo?.title}

-
- 0 ? IS_INVALID : ""}" name="password" placeholder="Password"> - ${this.renderInputError("password")} -
- -
`); - $("#password-form input").trigger("focus"); - $("#password-form").on("submit", (ev) => { - ev.preventDefault(); - const data = new FormData(ev.target as HTMLFormElement); - this.executor.submit(data); - }); - } -} - -class RedirectStage extends Stage { - render() { - window.location.assign(this.challenge.to); - } -} - -class AutosubmitStage extends Stage { - render() { - this.html(` -
- -

${this.challenge?.flowInfo?.title}

- ${Object.entries(this.challenge.attrs).map(([key, value]) => { - return ``; - })} -
-
- Loading... -
-
-
`); - $("#autosubmit-form").submit(); - } -} - -export interface Assertion { - id: string; - rawId: string; - type: string; - registrationClientExtensions: string; - response: { - clientDataJSON: string; - attestationObject: string; - }; -} - -export interface AuthAssertion { - id: string; - rawId: string; - type: string; - assertionClientExtensions: string; - response: { - clientDataJSON: string; - authenticatorData: string; - signature: string; - userHandle: string | null; - }; -} - -class AuthenticatorValidateStage extends Stage { - deviceChallenge?: DeviceChallenge; - - b64enc(buf: Uint8Array): string { - return fromByteArray(buf).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, ""); - } - - b64RawEnc(buf: Uint8Array): string { - return fromByteArray(buf).replace(/\+/g, "-").replace(/\//g, "_"); - } - - u8arr(input: string): Uint8Array { - return Uint8Array.from(atob(input.replace(/_/g, "/").replace(/-/g, "+")), (c) => - c.charCodeAt(0), - ); - } - - checkWebAuthnSupport(): boolean { - if ("credentials" in navigator) { - return true; - } - if (window.location.protocol === "http:" && window.location.hostname !== "localhost") { - console.warn("WebAuthn requires this page to be accessed via HTTPS."); - return false; - } - console.warn("WebAuthn not supported by browser."); - return false; - } - - /** - * Transforms items in the credentialCreateOptions generated on the server - * into byte arrays expected by the navigator.credentials.create() call - */ - transformCredentialCreateOptions( - credentialCreateOptions: PublicKeyCredentialCreationOptions, - userId: string, - ): PublicKeyCredentialCreationOptions { - const user = credentialCreateOptions.user; - // Because json can't contain raw bytes, the server base64-encodes the User ID - // So to get the base64 encoded byte array, we first need to convert it to a regular - // string, then a byte array, re-encode it and wrap that in an array. - const stringId = decodeURIComponent(window.atob(userId)); - user.id = this.u8arr(this.b64enc(this.u8arr(stringId))); - const challenge = this.u8arr(credentialCreateOptions.challenge.toString()); - - return Object.assign({}, credentialCreateOptions, { - challenge, - user, - }); - } - - /** - * Transforms the binary data in the credential into base64 strings - * for posting to the server. - * @param {PublicKeyCredential} newAssertion - */ - transformNewAssertionForServer(newAssertion: PublicKeyCredential): Assertion { - const attObj = new Uint8Array( - (newAssertion.response as AuthenticatorAttestationResponse).attestationObject, - ); - const clientDataJSON = new Uint8Array(newAssertion.response.clientDataJSON); - const rawId = new Uint8Array(newAssertion.rawId); - - const registrationClientExtensions = newAssertion.getClientExtensionResults(); - return { - id: newAssertion.id, - rawId: this.b64enc(rawId), - type: newAssertion.type, - registrationClientExtensions: JSON.stringify(registrationClientExtensions), - response: { - clientDataJSON: this.b64enc(clientDataJSON), - attestationObject: this.b64enc(attObj), - }, - }; - } - - transformCredentialRequestOptions( - credentialRequestOptions: PublicKeyCredentialRequestOptions, - ): PublicKeyCredentialRequestOptions { - const challenge = this.u8arr(credentialRequestOptions.challenge.toString()); - - const allowCredentials = (credentialRequestOptions.allowCredentials || []).map( - (credentialDescriptor) => { - const id = this.u8arr(credentialDescriptor.id.toString()); - return Object.assign({}, credentialDescriptor, { id }); - }, - ); - - return Object.assign({}, credentialRequestOptions, { - challenge, - allowCredentials, - }); - } - - /** - * Encodes the binary data in the assertion into strings for posting to the server. - * @param {PublicKeyCredential} newAssertion - */ - transformAssertionForServer(newAssertion: PublicKeyCredential): AuthAssertion { - const response = newAssertion.response as AuthenticatorAssertionResponse; - const authData = new Uint8Array(response.authenticatorData); - const clientDataJSON = new Uint8Array(response.clientDataJSON); - const rawId = new Uint8Array(newAssertion.rawId); - const sig = new Uint8Array(response.signature); - const assertionClientExtensions = newAssertion.getClientExtensionResults(); - - return { - id: newAssertion.id, - rawId: this.b64enc(rawId), - type: newAssertion.type, - assertionClientExtensions: JSON.stringify(assertionClientExtensions), - - response: { - clientDataJSON: this.b64RawEnc(clientDataJSON), - signature: this.b64RawEnc(sig), - authenticatorData: this.b64RawEnc(authData), - userHandle: null, - }, - }; - } - - render() { - if (!this.deviceChallenge) { - return this.renderChallengePicker(); - } - switch (this.deviceChallenge.deviceClass) { - case "static": - case "totp": - this.renderCodeInput(); - break; - case "webauthn": - this.renderWebauthn(); - break; - default: - break; - } - } - - renderChallengePicker() { - const challenges = this.challenge.deviceChallenges.filter((challenge) => - challenge.deviceClass === "webauthn" && !this.checkWebAuthnSupport() - ? undefined - : challenge, - ); - this.html(`
- -

${this.challenge?.flowInfo?.title}

- ${ - challenges.length > 0 - ? "

Select an authentication method.

" - : ` -

No compatible authentication method available

- ` - } - ${challenges - .map((challenge) => { - let label = undefined; - switch (challenge.deviceClass) { - case "static": - label = "Recovery keys"; - break; - case "totp": - label = "Traditional authenticator"; - break; - case "webauthn": - label = "Security key"; - break; - } - if (!label) { - return ""; - } - return `
- -
`; - }) - .join("")} -
`); - this.challenge.deviceChallenges.forEach((challenge) => { - $(`#picker-form button#${challenge.deviceClass}-${challenge.deviceUid}`).on( - "click", - () => { - this.deviceChallenge = challenge; - this.render(); - }, - ); - }); - } - - renderCodeInput() { - this.html(` -
- -

${this.challenge?.flowInfo?.title}

-
- 0 ? IS_INVALID : ""}" name="code" placeholder="Please enter your code" autocomplete="one-time-code"> - ${this.renderInputError("code")} -
- -
`); - $("#totp-form input").trigger("focus"); - $("#totp-form").on("submit", (ev) => { - ev.preventDefault(); - const data = new FormData(ev.target as HTMLFormElement); - this.executor.submit(data); - }); - } - - renderWebauthn() { - this.html(` -
- -

${this.challenge?.flowInfo?.title}

-
-
- Loading... -
-
-
- `); - navigator.credentials - .get({ - publicKey: this.transformCredentialRequestOptions( - this.deviceChallenge?.challenge as PublicKeyCredentialRequestOptions, - ), - }) - .then((assertion) => { - if (!assertion) { - throw new Error("No assertion"); - } - try { - // we now have an authentication assertion! encode the byte arrays contained - // in the assertion data as strings for posting to the server - const transformedAssertionForServer = this.transformAssertionForServer( - assertion as PublicKeyCredential, - ); - - // post the assertion to the server for verification. - this.executor.submit({ - webauthn: transformedAssertionForServer, - }); - } catch (err) { - throw new Error(`Error when validating assertion on server: ${err}`); - } - }) - .catch((error) => { - console.warn(error); - this.deviceChallenge = undefined; - this.render(); - }); - } -} - -const sfe = new SimpleFlowExecutor($("#flow-sfe-container")[0] as HTMLDivElement); -sfe.start(); diff --git a/web/packages/sfe/tsconfig.json b/web/packages/sfe/tsconfig.json deleted file mode 100644 index 82116e7003..0000000000 --- a/web/packages/sfe/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "compilerOptions": { - "types": ["jquery"], - "esModuleInterop": true, - "lib": ["DOM", "ES2015", "ES2017"] - } -} diff --git a/web/paths.js b/web/paths.js new file mode 100644 index 0000000000..0e87f9bae3 --- /dev/null +++ b/web/paths.js @@ -0,0 +1,25 @@ +/** + * @file Path constants for the web package. + */ +import { dirname, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; + +const __dirname = dirname(fileURLToPath(import.meta.url)); + +/** + * @typedef {'@goauthentik/web'} WebPackageIdentifier + */ + +/** + * The root of the web package. + */ +export const PackageRoot = /** @type {WebPackageIdentifier} */ (resolve(__dirname)); + +/** + * Path to the web package's distribution directory. + * + * This is where the built files are located after running the build process. + */ +export const DistDirectory = /** @type {`${WebPackageIdentifier}/dist`} */ ( + resolve(__dirname, "dist") +); diff --git a/web/scripts/build-sfe.mjs b/web/scripts/build-sfe.mjs new file mode 100644 index 0000000000..d303825061 --- /dev/null +++ b/web/scripts/build-sfe.mjs @@ -0,0 +1,90 @@ +/** + * @file Build script for the simplified flow executor (SFE). + */ +import { DistDirectory, PackageRoot } from "@goauthentik/web/paths"; +import esbuild from "esbuild"; +import copy from "esbuild-plugin-copy"; +import { es5Plugin } from "esbuild-plugin-es5"; +import { createRequire } from "node:module"; +import * as path from "node:path"; + +/** + * Builds the Simplified Flow Executor bundle. + * + * @remarks + * The output directory and file names are referenced by the backend. + * @see {@link ../../authentik/flows/templates/if/flow-sfe.html} + * @returns {Promise} + */ +async function buildSFE() { + const require = createRequire(import.meta.url); + + const sourceDirectory = path.join(PackageRoot, "sfe"); + + const entryPoint = path.join(sourceDirectory, "main.js"); + const outDirectory = path.join(DistDirectory, "sfe"); + + const bootstrapCSSPath = require.resolve( + path.join("bootstrap", "dist", "css", "bootstrap.min.css"), + ); + + /** + * @type {esbuild.BuildOptions} + */ + const config = { + tsconfig: path.join(sourceDirectory, "tsconfig.json"), + entryPoints: [entryPoint], + minify: false, + bundle: true, + sourcemap: true, + treeShaking: true, + legalComments: "external", + platform: "browser", + format: "iife", + alias: { + "@swc/helpers": path.dirname(require.resolve("@swc/helpers/package.json")), + }, + banner: { + js: [ + // --- + "// Simplified Flow Executor (SFE)", + `// Bundled on ${new Date().toISOString()}`, + "// @ts-nocheck", + "", + ].join("\n"), + }, + plugins: [ + copy({ + assets: [ + { + from: bootstrapCSSPath, + to: outDirectory, + }, + ], + }), + es5Plugin({ + swc: { + jsc: { + loose: false, + externalHelpers: false, + keepClassNames: false, + }, + minify: false, + }, + }), + ], + target: ["es5"], + outdir: outDirectory, + }; + + esbuild.build(config); +} + +buildSFE() + .then(() => { + console.log("Build complete"); + }) + .catch((error) => { + console.error("Build failed", error); + process.exit(1); + }); diff --git a/web/scripts/build-web.mjs b/web/scripts/build-web.mjs index b75e46d30f..eb5a008d3d 100644 --- a/web/scripts/build-web.mjs +++ b/web/scripts/build-web.mjs @@ -1,3 +1,4 @@ +import { DistDirectory, PackageRoot } from "@goauthentik/web/paths"; import { execFileSync } from "child_process"; import { deepmerge } from "deepmerge-ts"; import esbuild from "esbuild"; @@ -170,7 +171,7 @@ function composeVersionID() { * @throws {Error} on build failure */ function createEntryPointOptions([source, dest], overrides = {}) { - const outdir = path.join(__dirname, "..", "dist", dest); + const outdir = path.join(DistDirectory, dest); /** * @type {esbuild.BuildOptions} @@ -233,7 +234,7 @@ async function doWatch() { buildObserverPlugin({ serverURL, logPrefix: entryPoint[1], - relativeRoot: path.join(__dirname, ".."), + relativeRoot: PackageRoot, }), ], define: { diff --git a/web/packages/sfe/README.md b/web/sfe/README.md similarity index 100% rename from web/packages/sfe/README.md rename to web/sfe/README.md diff --git a/web/sfe/lib/AuthenticatorValidateStage.js b/web/sfe/lib/AuthenticatorValidateStage.js new file mode 100644 index 0000000000..9bb91c4e9d --- /dev/null +++ b/web/sfe/lib/AuthenticatorValidateStage.js @@ -0,0 +1,191 @@ +/** + * @import { AuthenticatorValidationChallenge, DeviceChallenge } from "@goauthentik/api"; + * @import { FlowExecutor } from './Stage.js'; + */ +import { + isWebAuthnSupported, + transformAssertionForServer, + transformCredentialRequestOptions, +} from "@goauthentik/web/authentication"; +import $ from "jquery"; + +import { Stage } from "./Stage.js"; +import { ak } from "./utils.js"; + +//@ts-check + +/** + * @template {AuthenticatorValidationChallenge} T + * @extends {Stage} + */ +export class AuthenticatorValidateStage extends Stage { + /** + * @param {FlowExecutor} executor - The executor for this stage + * @param {T} challenge - The challenge for this stage + */ + constructor(executor, challenge) { + super(executor, challenge); + + /** + * @type {DeviceChallenge | null} + */ + this.deviceChallenge = null; + } + + render() { + if (!this.deviceChallenge) { + this.renderChallengePicker(); + return; + } + + switch (this.deviceChallenge.deviceClass) { + case "static": + case "totp": + this.renderCodeInput(); + break; + case "webauthn": + this.renderWebauthn(); + break; + default: + break; + } + } + + /** + * @private + */ + renderChallengePicker() { + const challenges = this.challenge.deviceChallenges.filter((challenge) => + challenge.deviceClass === "webauthn" && !isWebAuthnSupported() ? undefined : challenge, + ); + + this.html(/* html */ `
+ +

${this.challenge?.flowInfo?.title}

+ ${ + challenges.length > 0 + ? /* html */ `

Select an authentication method.

` + : /* html */ `

No compatible authentication method available

` + } + ${challenges + .map((challenge) => { + let label = undefined; + + switch (challenge.deviceClass) { + case "static": + label = "Recovery keys"; + break; + case "totp": + label = "Traditional authenticator"; + break; + case "webauthn": + label = "Security key"; + break; + } + + if (!label) return ""; + + return /* html */ `
+ +
`; + }) + .join("")} +
`); + + this.challenge.deviceChallenges.forEach((challenge) => { + $(`#picker-form button#${challenge.deviceClass}-${challenge.deviceUid}`).on( + "click", + () => { + this.deviceChallenge = challenge; + this.render(); + }, + ); + }); + } + + /** + * @private + */ + renderCodeInput() { + this.html(/* html */ ` +
+ +

${this.challenge?.flowInfo?.title}

+
+ 0 ? "is-invalid" : ""}" name="code" placeholder="Please enter your code" autocomplete="one-time-code"> + ${this.renderInputError("code")} +
+ +
`); + + $("#totp-form input").trigger("focus"); + + $("#totp-form").on("submit", (ev) => { + ev.preventDefault(); + + const target = /** @type {HTMLFormElement} */ (ev.target); + + const data = new FormData(target); + this.executor.submit(data); + }); + } + + /** + * @private + */ + renderWebauthn() { + this.html(/* html */ ` +
+ +

${this.challenge?.flowInfo?.title}

+
+
+ Loading... +
+
+
+ `); + + const challenge = /** @type {PublicKeyCredentialRequestOptions} */ ( + this.deviceChallenge?.challenge + ); + + navigator.credentials + .get({ + publicKey: transformCredentialRequestOptions(challenge), + }) + .then((credential) => { + if (!credential) { + throw new Error("No assertion"); + } + + if (credential.type !== "public-key") { + throw new Error("Invalid assertion type"); + } + + try { + // We now have an authentication assertion! + // Encode the byte arrays contained in the assertion data as strings + // for posting to the server. + const transformedAssertionForServer = transformAssertionForServer( + /** @type {PublicKeyCredential} */ (credential), + ); + + // Post the assertion to the server for verification. + this.executor.submit({ + webauthn: transformedAssertionForServer, + }); + } catch (err) { + throw new Error(`Error when validating assertion on server: ${err}`); + } + }) + .catch((error) => { + console.warn(error); + + this.deviceChallenge = null; + this.render(); + }); + } +} diff --git a/web/sfe/lib/AutosubmitStage.js b/web/sfe/lib/AutosubmitStage.js new file mode 100644 index 0000000000..84541d94d6 --- /dev/null +++ b/web/sfe/lib/AutosubmitStage.js @@ -0,0 +1,35 @@ +/** + * @import { AutosubmitChallenge } from "@goauthentik/api"; + */ +import $ from "jquery"; + +import { Stage } from "./Stage.js"; +import { ak } from "./utils.js"; + +/** + * @template {AutosubmitChallenge} T + * @extends {Stage} + */ +export class AutosubmitStage extends Stage { + render() { + this.html(/* html */ ` +
+ +

${this.challenge?.flowInfo?.title}

+ ${Object.entries(this.challenge.attrs).map(([key, value]) => { + return /* html */ ``; + })} +
+
+ Loading... +
+
+
`); + + $("#autosubmit-form").submit(); + } +} diff --git a/web/sfe/lib/IdentificationStage.js b/web/sfe/lib/IdentificationStage.js new file mode 100644 index 0000000000..3357dd8c2c --- /dev/null +++ b/web/sfe/lib/IdentificationStage.js @@ -0,0 +1,50 @@ +/** + * @import { IdentificationChallenge } from "@goauthentik/api"; + */ +import $ from "jquery"; + +import { Stage } from "./Stage.js"; +import { ak } from "./utils.js"; + +/** + * @template {IdentificationChallenge} T + * @extends {Stage} + */ +export class IdentificationStage extends Stage { + render() { + this.html(/* html */ ` +
+ +

${this.challenge?.flowInfo?.title}

+ ${ + this.challenge.applicationPre + ? /* html */ `

+ Log in to continue to ${this.challenge.applicationPre}. +

` + : "" + } +
+ +
+ ${ + this.challenge.passwordFields + ? /* html */ `
+ 0 ? "is-invalid" : ""}" name="password" placeholder="Password"> + ${this.renderInputError("password")} +
` + : "" + } + ${this.renderNonFieldErrors()} + +
`); + + $("#ident-form input[name=uid_field]").trigger("focus"); + $("#ident-form").on("submit", (ev) => { + ev.preventDefault(); + const target = /** @type {HTMLFormElement} */ (ev.target); + + const data = new FormData(target); + this.executor.submit(data); + }); + } +} diff --git a/web/sfe/lib/PasswordStage.js b/web/sfe/lib/PasswordStage.js new file mode 100644 index 0000000000..7ab5fe7db9 --- /dev/null +++ b/web/sfe/lib/PasswordStage.js @@ -0,0 +1,37 @@ +/** + * @import { PasswordChallenge } from "@goauthentik/api"; + */ +import $ from "jquery"; + +import { Stage } from "./Stage.js"; +import { ak } from "./utils.js"; + +/** + * @template {PasswordChallenge} T + * @extends {Stage} + */ +export class PasswordStage extends Stage { + render() { + this.html(/* html */ ` +
+ +

${this.challenge?.flowInfo?.title}

+
+ 0 ? "is-invalid" : ""}" name="password" placeholder="Password"> + ${this.renderInputError("password")} +
+ +
`); + + $("#password-form input").trigger("focus"); + + $("#password-form").on("submit", (ev) => { + ev.preventDefault(); + + const target = /** @type {HTMLFormElement} */ (ev.target); + + const data = new FormData(target); + this.executor.submit(data); + }); + } +} diff --git a/web/sfe/lib/RedirectStage.js b/web/sfe/lib/RedirectStage.js new file mode 100644 index 0000000000..a5a825a1f7 --- /dev/null +++ b/web/sfe/lib/RedirectStage.js @@ -0,0 +1,14 @@ +/** + * @import { RedirectChallenge } from "@goauthentik/api"; + */ +import { Stage } from "./Stage.js"; + +/** + * @template {RedirectChallenge} T + * @extends {Stage} + */ +export class RedirectStage extends Stage { + render() { + window.location.assign(this.challenge.to); + } +} diff --git a/web/sfe/lib/SimpleFlowExecutor.js b/web/sfe/lib/SimpleFlowExecutor.js new file mode 100644 index 0000000000..625961a5ad --- /dev/null +++ b/web/sfe/lib/SimpleFlowExecutor.js @@ -0,0 +1,113 @@ +/** + * @import { ChallengeTypes } from "@goauthentik/api"; + * @import { FlowExecutor } from './Stage.js'; + */ +import $ from "jquery"; + +import { ChallengeTypesFromJSON } from "@goauthentik/api"; + +import { AuthenticatorValidateStage } from "./AuthenticatorValidateStage.js"; +import { AutosubmitStage } from "./AutosubmitStage.js"; +import { IdentificationStage } from "./IdentificationStage.js"; +import { PasswordStage } from "./PasswordStage.js"; +import { RedirectStage } from "./RedirectStage.js"; +import { ak } from "./utils.js"; + +/** + * Simple Flow Executor lifecycle. + * + * @implements {FlowExecutor} + */ +export class SimpleFlowExecutor { + /** + * + * @param {HTMLDivElement} container + */ + constructor(container) { + /** + * @type {ChallengeTypes | null} The current challenge. + */ + this.challenge = null; + /** + * @type {string} The flow slug. + */ + this.flowSlug = window.location.pathname.split("/")[3] || ""; + /** + * @type {HTMLDivElement} The container element for the flow executor. + */ + this.container = container; + } + + get apiURL() { + return `${ak().api.base}api/v3/flows/executor/${this.flowSlug}/?query=${encodeURIComponent(window.location.search.substring(1))}`; + } + + start() { + $.ajax({ + type: "GET", + url: this.apiURL, + success: (data) => { + this.challenge = ChallengeTypesFromJSON(data); + + this.renderChallenge(); + }, + }); + } + + /** + * Submits the form data. + * @param {Record | FormData} payload + */ + submit(payload) { + $("button[type=submit]").addClass("disabled") + .html(` + Loading...`); + /** + * @type {Record} + */ + let finalData; + + if (payload instanceof FormData) { + finalData = {}; + + payload.forEach((value, key) => { + finalData[key] = value; + }); + } else { + finalData = payload; + } + + $.ajax({ + type: "POST", + url: this.apiURL, + data: JSON.stringify(finalData), + success: (data) => { + this.challenge = ChallengeTypesFromJSON(data); + this.renderChallenge(); + }, + contentType: "application/json", + dataType: "json", + }); + } + + /** + * @returns {void} + */ + renderChallenge() { + switch (this.challenge?.component) { + case "ak-stage-identification": + return new IdentificationStage(this, this.challenge).render(); + case "ak-stage-password": + return new PasswordStage(this, this.challenge).render(); + case "xak-flow-redirect": + return new RedirectStage(this, this.challenge).render(); + case "ak-stage-autosubmit": + return new AutosubmitStage(this, this.challenge).render(); + case "ak-stage-authenticator-validate": + return new AuthenticatorValidateStage(this, this.challenge).render(); + default: + this.container.innerText = `Unsupported stage: ${this.challenge?.component}`; + return; + } + } +} diff --git a/web/sfe/lib/Stage.js b/web/sfe/lib/Stage.js new file mode 100644 index 0000000000..04a93c42e1 --- /dev/null +++ b/web/sfe/lib/Stage.js @@ -0,0 +1,116 @@ +/** + * @import { ContextualFlowInfo, ErrorDetail } from "@goauthentik/api"; + */ + +/** + * @typedef {object} FlowInfoChallenge + * @property {ContextualFlowInfo} [flowInfo] + * @property {Record>} [responseErrors] + */ + +/** + * @abstract + */ +export class FlowExecutor { + constructor() { + /** + * The DOM container element. + * + * @type {HTMLElement} + * @abstract + * @returns {void} + */ + // eslint-disable-next-line @typescript-eslint/no-unused-expressions + this.container; + } + + /** + * Submits the form data. + * + * @param {Record | FormData} data The data to submit. + * @abstract + * @returns {void} + */ + // eslint-disable-next-line @typescript-eslint/no-unused-vars + submit(data) { + throw new Error(`Method 'submit' not implemented in ${this.constructor.name}`); + } +} + +/** + * Represents a stage in a flow + * @template {FlowInfoChallenge} T + * @abstract + */ +export class Stage { + /** + * @param {FlowExecutor} executor - The executor for this stage + * @param {T} challenge - The challenge for this stage + */ + constructor(executor, challenge) { + /** @type {FlowExecutor} */ + this.executor = executor; + + /** @type {T} */ + this.challenge = challenge; + } + + /** + * @protected + * @param {string} fieldName + */ + error(fieldName) { + if (!this.challenge.responseErrors) { + return []; + } + return this.challenge.responseErrors[fieldName] || []; + } + + /** + * @protected + * @param {string} fieldName + * @returns {string} + */ + renderInputError(fieldName) { + return `${this.error(fieldName) + .map((error) => { + return /* html */ `
+ ${error.string} +
`; + }) + .join("")}`; + } + + /** + * @protected + * @returns {string} + */ + renderNonFieldErrors() { + return `${this.error("non_field_errors") + .map((error) => { + return /* html */ ``; + }) + .join("")}`; + } + + /** + * @protected + * @param {string} innerHTML + * @returns {void} + */ + html(innerHTML) { + this.executor.container.innerHTML = innerHTML; + } + + /** + * Renders the stage (must be implemented by subclasses) + * + * @abstract + * @returns {void} + */ + render() { + throw new Error("Abstract method"); + } +} diff --git a/web/sfe/lib/index.js b/web/sfe/lib/index.js new file mode 100644 index 0000000000..f3d367b5dc --- /dev/null +++ b/web/sfe/lib/index.js @@ -0,0 +1,12 @@ +/** + * @file Simplified Flow Executor (SFE) library module. + */ + +export * from "./Stage.js"; +export * from "./SimpleFlowExecutor.js"; +export * from "./AuthenticatorValidateStage.js"; +export * from "./AutosubmitStage.js"; +export * from "./IdentificationStage.js"; +export * from "./PasswordStage.js"; +export * from "./RedirectStage.js"; +export * from "./utils.js"; diff --git a/web/sfe/lib/utils.js b/web/sfe/lib/utils.js new file mode 100644 index 0000000000..540aa6688d --- /dev/null +++ b/web/sfe/lib/utils.js @@ -0,0 +1,20 @@ +/** + * @typedef {object} GlobalAuthentik + * @property {object} brand + * @property {string} brand.branding_logo + * @property {object} api + * @property {string} api.base + */ + +/** + * Retrieves the global authentik object from the window. + * @throws {Error} If the object not found + * @returns {GlobalAuthentik} + */ +export function ak() { + if (!("authentik" in window)) { + throw new Error("No authentik object found in window"); + } + + return /** @type {GlobalAuthentik} */ (window.authentik); +} diff --git a/web/sfe/main.js b/web/sfe/main.js new file mode 100644 index 0000000000..168f02f00b --- /dev/null +++ b/web/sfe/main.js @@ -0,0 +1,17 @@ +/** + * @file Simplified Flow Executor (SFE) entry point. + */ +import "formdata-polyfill"; +import $ from "jquery"; + +import { SimpleFlowExecutor } from "./lib/index.js"; + +const flowContainer = /** @type {HTMLDivElement} */ ($("#flow-sfe-container")[0]); + +if (!flowContainer) { + throw new Error("No flow container element found"); +} + +const sfe = new SimpleFlowExecutor(flowContainer); + +sfe.start(); diff --git a/web/sfe/tsconfig.json b/web/sfe/tsconfig.json new file mode 100644 index 0000000000..f1a9754e00 --- /dev/null +++ b/web/sfe/tsconfig.json @@ -0,0 +1,46 @@ +{ + // TODO: Replace with @goauthentik/tsconfig after project compilation. + "$schema": "https://json.schemastore.org/tsconfig", + + "compilerOptions": { + "paths": { + "@goauthentik/web/authentication": ["../authentication/index.js"] + }, + "alwaysStrict": true, + "baseUrl": ".", + "rootDir": "../", + "composite": true, + "declaration": true, + "allowJs": true, + "declarationMap": true, + "isolatedModules": true, + "incremental": true, + "emitDeclarationOnly": true, + "esModuleInterop": true, + "lib": ["DOM", "ES2015", "ES2017"], + "module": "NodeNext", + "moduleResolution": "NodeNext", + "newLine": "lf", + "noFallthroughCasesInSwitch": true, + "noImplicitOverride": false, + "outDir": "${configDir}/out", + "pretty": true, + "skipDefaultLibCheck": true, + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "noUncheckedIndexedAccess": true, + "target": "ESNext", + "useUnknownInCatchVariables": true + }, + "exclude": [ + // --- + "./out/**/*", + "./dist/**/*" + ], + "include": [ + // --- + "./**/*.js", + "../authentication/**/*.js" + ] +} diff --git a/web/src/common/helpers/webauthn.ts b/web/src/common/helpers/webauthn.ts deleted file mode 100644 index 68b29ce760..0000000000 --- a/web/src/common/helpers/webauthn.ts +++ /dev/null @@ -1,145 +0,0 @@ -import * as base64js from "base64-js"; - -import { msg } from "@lit/localize"; - -export function b64enc(buf: Uint8Array): string { - return base64js.fromByteArray(buf).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, ""); -} - -export function b64RawEnc(buf: Uint8Array): string { - return base64js.fromByteArray(buf).replace(/\+/g, "-").replace(/\//g, "_"); -} - -export function u8arr(input: string): Uint8Array { - return Uint8Array.from(atob(input.replace(/_/g, "/").replace(/-/g, "+")), (c) => - c.charCodeAt(0), - ); -} - -export function checkWebAuthnSupport() { - if ("credentials" in navigator) { - return; - } - if (window.location.protocol === "http:" && window.location.hostname !== "localhost") { - throw new Error(msg("WebAuthn requires this page to be accessed via HTTPS.")); - } - throw new Error(msg("WebAuthn not supported by browser.")); -} - -/** - * Transforms items in the credentialCreateOptions generated on the server - * into byte arrays expected by the navigator.credentials.create() call - */ -export function transformCredentialCreateOptions( - credentialCreateOptions: PublicKeyCredentialCreationOptions, - userId: string, -): PublicKeyCredentialCreationOptions { - const user = credentialCreateOptions.user; - // Because json can't contain raw bytes, the server base64-encodes the User ID - // So to get the base64 encoded byte array, we first need to convert it to a regular - // string, then a byte array, re-encode it and wrap that in an array. - const stringId = decodeURIComponent(window.atob(userId)); - user.id = u8arr(b64enc(u8arr(stringId))); - const challenge = u8arr(credentialCreateOptions.challenge.toString()); - - return { - ...credentialCreateOptions, - challenge, - user, - }; -} - -export interface Assertion { - id: string; - rawId: string; - type: string; - registrationClientExtensions: string; - response: { - clientDataJSON: string; - attestationObject: string; - }; -} - -/** - * Transforms the binary data in the credential into base64 strings - * for posting to the server. - * @param {PublicKeyCredential} newAssertion - */ -export function transformNewAssertionForServer(newAssertion: PublicKeyCredential): Assertion { - const attObj = new Uint8Array( - (newAssertion.response as AuthenticatorAttestationResponse).attestationObject, - ); - const clientDataJSON = new Uint8Array(newAssertion.response.clientDataJSON); - const rawId = new Uint8Array(newAssertion.rawId); - - const registrationClientExtensions = newAssertion.getClientExtensionResults(); - return { - id: newAssertion.id, - rawId: b64enc(rawId), - type: newAssertion.type, - registrationClientExtensions: JSON.stringify(registrationClientExtensions), - response: { - clientDataJSON: b64enc(clientDataJSON), - attestationObject: b64enc(attObj), - }, - }; -} - -export function transformCredentialRequestOptions( - credentialRequestOptions: PublicKeyCredentialRequestOptions, -): PublicKeyCredentialRequestOptions { - const challenge = u8arr(credentialRequestOptions.challenge.toString()); - - const allowCredentials = (credentialRequestOptions.allowCredentials || []).map( - (credentialDescriptor) => { - const id = u8arr(credentialDescriptor.id.toString()); - return Object.assign({}, credentialDescriptor, { id }); - }, - ); - - return { - ...credentialRequestOptions, - challenge, - allowCredentials, - }; -} - -export interface AuthAssertion { - id: string; - rawId: string; - type: string; - assertionClientExtensions: string; - response: { - clientDataJSON: string; - authenticatorData: string; - signature: string; - userHandle: string | null; - }; -} - -/** - * Encodes the binary data in the assertion into strings for posting to the server. - * @param {PublicKeyCredential} newAssertion - */ -export function transformAssertionForServer(newAssertion: PublicKeyCredential): AuthAssertion { - const response = newAssertion.response as AuthenticatorAssertionResponse; - const authData = new Uint8Array(response.authenticatorData); - const clientDataJSON = new Uint8Array(response.clientDataJSON); - const rawId = new Uint8Array(newAssertion.rawId); - const sig = new Uint8Array(response.signature); - const assertionClientExtensions = newAssertion.getClientExtensionResults(); - - return { - id: newAssertion.id, - rawId: b64enc(rawId), - type: newAssertion.type, - assertionClientExtensions: JSON.stringify(assertionClientExtensions), - - response: { - clientDataJSON: b64RawEnc(clientDataJSON), - signature: b64RawEnc(sig), - authenticatorData: b64RawEnc(authData), - userHandle: null, - }, - }; -} diff --git a/web/src/flow/stages/authenticator_validate/AuthenticatorValidateStageWebAuthn.ts b/web/src/flow/stages/authenticator_validate/AuthenticatorValidateStageWebAuthn.ts index d211cbc180..e6605ecf17 100644 --- a/web/src/flow/stages/authenticator_validate/AuthenticatorValidateStageWebAuthn.ts +++ b/web/src/flow/stages/authenticator_validate/AuthenticatorValidateStageWebAuthn.ts @@ -1,10 +1,10 @@ -import { - checkWebAuthnSupport, - transformAssertionForServer, - transformCredentialRequestOptions, -} from "@goauthentik/common/helpers/webauthn"; import "@goauthentik/elements/EmptyState"; import { BaseDeviceStage } from "@goauthentik/flow/stages/authenticator_validate/base"; +import { assertWebAuthnSupport } from "@goauthentik/web/authentication"; +import { + transformAssertionForServer, + transformCredentialRequestOptions, +} from "@goauthentik/web/authentication"; import { msg } from "@lit/localize"; import { PropertyValues, TemplateResult, html, nothing } from "lit"; @@ -39,7 +39,7 @@ export class AuthenticatorValidateStageWebAuthn extends BaseDeviceStage< // request the authenticator to create an assertion signature using the // credential private key let assertion; - checkWebAuthnSupport(); + assertWebAuthnSupport(); try { assertion = await navigator.credentials.get({ publicKey: this.transformedCredentialRequestOptions, diff --git a/web/src/flow/stages/authenticator_webauthn/WebAuthnAuthenticatorRegisterStage.ts b/web/src/flow/stages/authenticator_webauthn/WebAuthnAuthenticatorRegisterStage.ts index 8673e16862..91c8bfcfcc 100644 --- a/web/src/flow/stages/authenticator_webauthn/WebAuthnAuthenticatorRegisterStage.ts +++ b/web/src/flow/stages/authenticator_webauthn/WebAuthnAuthenticatorRegisterStage.ts @@ -1,11 +1,11 @@ -import { - Assertion, - checkWebAuthnSupport, - transformCredentialCreateOptions, - transformNewAssertionForServer, -} from "@goauthentik/common/helpers/webauthn"; import "@goauthentik/elements/EmptyState"; import { BaseStage } from "@goauthentik/flow/stages/base"; +import { assertWebAuthnSupport } from "@goauthentik/web/authentication"; +import { + Assertion, + transformCredentialCreateOptions, + transformNewAssertionForServer, +} from "@goauthentik/web/authentication"; import { msg, str } from "@lit/localize"; import { CSSResult, PropertyValues, TemplateResult, css, html, nothing } from "lit"; @@ -66,7 +66,7 @@ export class WebAuthnAuthenticatorRegisterStage extends BaseStage< if (!this.challenge) { return; } - checkWebAuthnSupport(); + assertWebAuthnSupport(); // request the authenticator(s) to create a new credential keypair. let credential; try { diff --git a/web/tsconfig.base.json b/web/tsconfig.base.json index 31d05ab479..8453ccabd3 100644 --- a/web/tsconfig.base.json +++ b/web/tsconfig.base.json @@ -2,6 +2,8 @@ "compilerOptions": { "strict": true, "baseUrl": ".", + "emitDeclarationOnly": true, + "declaration": true, "esModuleInterop": true, "paths": { "@goauthentik/docs/*": ["../website/docs/*"] @@ -14,6 +16,7 @@ "grecaptcha" ], "jsx": "react-jsx", + "allowJs": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "experimentalDecorators": true, @@ -67,5 +70,12 @@ } ] }, - "exclude": ["src/**/*.test.ts", "./tests"] + "exclude": [ + // --- + "./out/**/*", + "./dist/**/*", + + "src/**/*.test.ts", + "./tests" + ] } diff --git a/web/tsconfig.json b/web/tsconfig.json index 333347a361..7d3046a672 100644 --- a/web/tsconfig.json +++ b/web/tsconfig.json @@ -1,8 +1,15 @@ { "extends": "./tsconfig.base.json", "compilerOptions": { - "types": ["@wdio/types", "grecaptcha", "node", "@wdio/mocha-framework", "expect-webdriverio"], + "types": [ + "@wdio/types", + "grecaptcha", + "node", + "@wdio/mocha-framework", + "expect-webdriverio" + ], "paths": { + "@goauthentik/web/authentication": ["./authentication/index.js"], "@goauthentik/admin/*": ["./src/admin/*"], "@goauthentik/common/*": ["./src/common/*"], "@goauthentik/components/*": ["./src/components/*"], @@ -14,5 +21,5 @@ "@goauthentik/standalone/*": ["./src/standalone/*"], "@goauthentik/user/*": ["./src/user/*"] } - }, + } } diff --git a/web/tsconfig.test.json b/web/tsconfig.test.json index f93c6adf05..17dc928ece 100644 --- a/web/tsconfig.test.json +++ b/web/tsconfig.test.json @@ -31,5 +31,10 @@ "@goauthentik/standalone/*": ["./src/standalone/*"], "@goauthentik/user/*": ["./src/user/*"] } - } + }, + "exclude": [ + // --- + "./out/**/*", + "./dist/**/*" + ] }