diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 2049b79b78..57d53bd8c9 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -8,9 +8,6 @@ on: env: NODE_JS: "22" - EXAMPLE_TEMPLATE: "web-chat" - EXAMPLE_NAME: "example" - EXAMPLE_PORT: "8080" # Firefox in container fails due to $HOME not being owned by user running commands # more details https://github.com/microsoft/playwright/issues/6500 HOME: "/root" @@ -29,11 +26,8 @@ jobs: - uses: ./.github/actions/npm - - name: Build browser container - run: npm run build --workspace=@waku/headless-tests - - - name: Build browser test environment - run: npm run build --workspace=@waku/browser-tests + - name: Build entire monorepo + run: npm run build - name: Run Playwright tests run: npm run test --workspace=@waku/browser-tests diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 03382b0d08..0000000000 --- a/Dockerfile +++ /dev/null @@ -1,45 +0,0 @@ -FROM node:20-slim - -# Install Chrome dependencies -RUN apt-get update && apt-get install -y \ - procps \ - libglib2.0-0 \ - libnss3 \ - libnspr4 \ - libatk1.0-0 \ - libatk-bridge2.0-0 \ - libcups2 \ - libdrm2 \ - libxkbcommon0 \ - libxcomposite1 \ - libxdamage1 \ - libxfixes3 \ - libxrandr2 \ - libgbm1 \ - libasound2 \ - libpango-1.0-0 \ - libcairo2 \ - && rm -rf /var/lib/apt/lists/* - -WORKDIR /app - -# Copy package files -COPY package*.json ./ -COPY packages/browser-tests/package.json ./packages/browser-tests/ -COPY packages/headless-tests/package.json ./packages/headless-tests/ - -# Install dependencies and serve -RUN npm install && npm install -g serve - -# Copy source files -COPY tsconfig.json ./ -COPY packages/ ./packages/ - -# Build packages -RUN npm run build -w packages/headless-tests && \ - npm run build:server -w packages/browser-tests && \ - npx playwright install chromium - -EXPOSE 3000 - -CMD ["npm", "run", "start:server", "-w", "packages/browser-tests"] diff --git a/README.md b/README.md index 204d78181a..7b2239b71c 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,16 @@ You can track progress on the [project board](https://github.com/orgs/waku-org/p See [CONTRIBUTING.md](https://github.com/waku-org/js-waku/blob/master/CONTRIBUTING.md). +## Dockerized browser tests + +Build and run the dockerized Playwright tests from `packages/browser-tests`: + +```bash +cd packages/browser-tests +npm run docker:build +HEADLESS_USE_CDN_IN_DOCKER=0 npx playwright test tests/docker-server.spec.ts +``` + ## License Licensed and distributed under either of diff --git a/package-lock.json b/package-lock.json index d17408b2ec..e056eebb3d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,6 @@ "packages/rln", "packages/tests", "packages/reliability-tests", - "packages/headless-tests", "packages/browser-tests", "packages/build-utils" ], @@ -98,9 +97,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.27.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.5.tgz", - "integrity": "sha512-KiRAp/VoJaWkkte84TvUd9qjdbZAdiqyvMxrGl1N6vzFogKmaLgoM3L1kgtLicp2HP5fBJS8JrZKLVIZGVJAVg==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz", + "integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -158,15 +157,15 @@ } }, "node_modules/@babel/generator": { - "version": "7.27.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.5.tgz", - "integrity": "sha512-ZGhA37l0e/g2s1Cnzdix0O3aLYm66eF8aufiVteOgnwxgnRP8GoyMj7VWsgWnQbVKXyge7hqrFh2K2TQM6t1Hw==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", + "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.27.5", - "@babel/types": "^7.27.3", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", + "@babel/parser": "^7.28.3", + "@babel/types": "^7.28.2", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" }, "engines": { @@ -174,9 +173,9 @@ } }, "node_modules/@babel/generator/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "version": "0.3.30", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz", + "integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==", "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -236,17 +235,17 @@ "license": "ISC" }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.1.tgz", - "integrity": "sha512-QwGAmuvM17btKU5VqXfb+Giw4JcN0hjuufz3DYnpeVDvZLAObloM77bhMXiqry3Iio+Ai4phVRDwl6WU10+r5A==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.3.tgz", + "integrity": "sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/traverse": "^7.27.1", + "@babel/traverse": "^7.28.3", "semver": "^6.3.1" }, "engines": { @@ -292,16 +291,16 @@ } }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.4.tgz", - "integrity": "sha512-jljfR1rGnXXNWnmQg2K3+bvhkxB51Rl32QRaOTuwwjviGrHzIbSc8+x9CpraDtbT7mfyjXObULP4w/adunNwAw==", + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz", + "integrity": "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==", "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.22.6", - "@babel/helper-plugin-utils": "^7.22.5", - "debug": "^4.1.1", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "debug": "^4.4.1", "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2" + "resolve": "^1.22.10" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -319,6 +318,15 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-member-expression-to-functions": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz", @@ -485,12 +493,12 @@ } }, "node_modules/@babel/parser": { - "version": "7.27.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.5.tgz", - "integrity": "sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.3.tgz", + "integrity": "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA==", "license": "MIT", "dependencies": { - "@babel/types": "^7.27.3" + "@babel/types": "^7.28.2" }, "bin": { "parser": "bin/babel-parser.js" @@ -499,90 +507,6 @@ "node": ">=6.0.0" } }, - "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.27.1.tgz", - "integrity": "sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", - "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", - "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", - "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/plugin-transform-optional-chaining": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.13.0" - } - }, - "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.27.1.tgz", - "integrity": "sha512-6BpaYGDavZqkI6yT+KSPdpZFfpnd68UKXbcjI9pJ13pvHhPrCKWOOLp+ysvMeA+DxnhuPpgIaRpxRxo5A9t5jw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, "node_modules/@babel/plugin-proposal-async-generator-functions": { "version": "7.20.7", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz", @@ -706,19 +630,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.0-placeholder-for-preset-env.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", - "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-async-generators": { "version": "7.8.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", @@ -773,38 +684,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz", - "integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", - "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-jsx": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", @@ -883,23 +762,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-unicode-sets-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", - "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, "node_modules/@babel/plugin-transform-arrow-functions": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", @@ -915,62 +777,10 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.27.1.tgz", - "integrity": "sha512-eST9RrwlpaoJBDHShc+DS2SG4ATTi2MYNb4OxYkf3n+7eb49LWpnS+HSpVfW4x927qQwgk8A2hGNVaajAEw0EA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-remap-async-to-generator": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz", - "integrity": "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-remap-async-to-generator": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", - "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.27.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.27.5.tgz", - "integrity": "sha512-JF6uE2s67f0y2RZcm2kpAUEbD50vH62TyWVebxwHAlbSdM49VqPz8t4a1uIjp4NIOIZ4xzLfjY5emt/RCyC7TQ==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.0.tgz", + "integrity": "sha512-gKKnwjpdx5sER/wl0WN0efUBFzF/56YZO0RJrSYP4CljXnP31ByY7fol89AzomdlLNzI36AvOTmYHsnZTCkq8Q==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -982,52 +792,18 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz", - "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.27.1.tgz", - "integrity": "sha512-s734HmYU78MVzZ++joYM+NkJusItbdRcbm+AGRgJCt3iA+yux0QpD9cBVdz3tKyrjVYWRl7j0mHSmv4lhV0aoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0" - } - }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.27.1.tgz", - "integrity": "sha512-7iLhfFAubmpeJe/Wo2TVuDrykh/zlWXLzPNdL0Jqn/Xu8R3QQ8h9ff8FQoISZOsw74/HFqFI7NX63HN7QFIHKA==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.3.tgz", + "integrity": "sha512-DoEWC5SuxuARF2KdKmGUq3ghfPMO6ZzR12Dnp5gubwbeWJo4dbNWXJPVlwvh4Zlq6Z7YVvL8VFxeSOJgjsx4Sg==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-globals": "^7.28.0", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", - "@babel/traverse": "^7.27.1", - "globals": "^11.1.0" + "@babel/traverse": "^7.28.3" }, "engines": { "node": ">=6.9.0" @@ -1036,15 +812,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-classes/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/plugin-transform-computed-properties": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", @@ -1062,78 +829,13 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.27.3.tgz", - "integrity": "sha512-s4Jrok82JpiaIprtY2nHsYmrThKvvwgHwjgd7UMiYhZaN0asdXNLr0y+NjTfkA7SyQE5i2Fb7eawUOZmLvyqOA==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz", - "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", - "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", - "dev": true, + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.0.tgz", + "integrity": "sha512-v1nrSMBiKcodhsyJ4Gf+Z0U/yawmJDBOTpEB3mcQY52r9RIyPneGyAS/yM6seP/8I+mWI3elOMtT5dB8GJVs+A==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz", - "integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", - "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.0" }, "engines": { "node": ">=6.9.0" @@ -1157,22 +859,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", - "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-transform-flow-strip-types": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.27.1.tgz", @@ -1222,22 +908,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz", - "integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-transform-literals": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", @@ -1253,55 +923,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.27.1.tgz", - "integrity": "sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", - "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", - "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-transform-modules-commonjs": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", @@ -1318,107 +939,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.27.1.tgz", - "integrity": "sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", - "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", - "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-new-target": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", - "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz", - "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz", - "integrity": "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-transform-object-assign": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-assign/-/plugin-transform-object-assign-7.27.1.tgz", @@ -1434,130 +954,10 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.27.3.tgz", - "integrity": "sha512-7ZZtznF9g4l2JCImCo5LNKFHB5eXnN39lLtLY5Tg+VkR0jwOt7TBciMckuiQIOIW7L5tkQOCh3bVGYeXgMx52Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.27.3", - "@babel/plugin-transform-parameters": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-super": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", - "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz", - "integrity": "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.27.1.tgz", - "integrity": "sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.1.tgz", - "integrity": "sha512-018KRk76HWKeZ5l4oTj2zPpSh+NbGdt0st5S6x0pga6HgrjBOJb24mMDHorFopOOd6YHkLgOZ+zaCjZGPO4aKg==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz", - "integrity": "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz", - "integrity": "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", - "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", - "dev": true, + "version": "7.27.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", + "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -1634,42 +1034,9 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.27.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.27.5.tgz", - "integrity": "sha512-uhB8yHerfe3MWnuLAhEbeQ4afVoqv8BQsPqrTv7e/jZ9y00kJL6l9a/f4OWaKxotmjzewfEyXE1vgDJenkQ2/Q==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-regexp-modifiers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz", - "integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", - "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", - "dev": true, + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.3.tgz", + "integrity": "sha512-K3/M/a4+ESb5LEldjQb+XSrpY0nF+ZBFlTCbSnKaYAMfD8v33O6PMs4uYnOk19HlcsI8WMu3McdFPTiQHF/1/A==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -1771,22 +1138,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", - "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-transform-typescript": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.27.1.tgz", @@ -1806,39 +1157,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", - "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz", - "integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-transform-unicode-regex": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", @@ -1855,152 +1173,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz", - "integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/preset-env": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.27.2.tgz", - "integrity": "sha512-Ma4zSuYSlGNRlCLO+EAzLnCmJK2vdstgv+n7aUP+/IKZrOfWHOJVdSJtuub8RzHTj3ahD37k5OKJWvzf16TQyQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.27.2", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-validator-option": "^7.27.1", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.27.1", - "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.27.1", - "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-import-assertions": "^7.27.1", - "@babel/plugin-syntax-import-attributes": "^7.27.1", - "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.27.1", - "@babel/plugin-transform-async-generator-functions": "^7.27.1", - "@babel/plugin-transform-async-to-generator": "^7.27.1", - "@babel/plugin-transform-block-scoped-functions": "^7.27.1", - "@babel/plugin-transform-block-scoping": "^7.27.1", - "@babel/plugin-transform-class-properties": "^7.27.1", - "@babel/plugin-transform-class-static-block": "^7.27.1", - "@babel/plugin-transform-classes": "^7.27.1", - "@babel/plugin-transform-computed-properties": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.27.1", - "@babel/plugin-transform-dotall-regex": "^7.27.1", - "@babel/plugin-transform-duplicate-keys": "^7.27.1", - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", - "@babel/plugin-transform-dynamic-import": "^7.27.1", - "@babel/plugin-transform-exponentiation-operator": "^7.27.1", - "@babel/plugin-transform-export-namespace-from": "^7.27.1", - "@babel/plugin-transform-for-of": "^7.27.1", - "@babel/plugin-transform-function-name": "^7.27.1", - "@babel/plugin-transform-json-strings": "^7.27.1", - "@babel/plugin-transform-literals": "^7.27.1", - "@babel/plugin-transform-logical-assignment-operators": "^7.27.1", - "@babel/plugin-transform-member-expression-literals": "^7.27.1", - "@babel/plugin-transform-modules-amd": "^7.27.1", - "@babel/plugin-transform-modules-commonjs": "^7.27.1", - "@babel/plugin-transform-modules-systemjs": "^7.27.1", - "@babel/plugin-transform-modules-umd": "^7.27.1", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", - "@babel/plugin-transform-new-target": "^7.27.1", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", - "@babel/plugin-transform-numeric-separator": "^7.27.1", - "@babel/plugin-transform-object-rest-spread": "^7.27.2", - "@babel/plugin-transform-object-super": "^7.27.1", - "@babel/plugin-transform-optional-catch-binding": "^7.27.1", - "@babel/plugin-transform-optional-chaining": "^7.27.1", - "@babel/plugin-transform-parameters": "^7.27.1", - "@babel/plugin-transform-private-methods": "^7.27.1", - "@babel/plugin-transform-private-property-in-object": "^7.27.1", - "@babel/plugin-transform-property-literals": "^7.27.1", - "@babel/plugin-transform-regenerator": "^7.27.1", - "@babel/plugin-transform-regexp-modifiers": "^7.27.1", - "@babel/plugin-transform-reserved-words": "^7.27.1", - "@babel/plugin-transform-shorthand-properties": "^7.27.1", - "@babel/plugin-transform-spread": "^7.27.1", - "@babel/plugin-transform-sticky-regex": "^7.27.1", - "@babel/plugin-transform-template-literals": "^7.27.1", - "@babel/plugin-transform-typeof-symbol": "^7.27.1", - "@babel/plugin-transform-unicode-escapes": "^7.27.1", - "@babel/plugin-transform-unicode-property-regex": "^7.27.1", - "@babel/plugin-transform-unicode-regex": "^7.27.1", - "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", - "@babel/preset-modules": "0.1.6-no-external-plugins", - "babel-plugin-polyfill-corejs2": "^0.4.10", - "babel-plugin-polyfill-corejs3": "^0.11.0", - "babel-plugin-polyfill-regenerator": "^0.6.1", - "core-js-compat": "^3.40.0", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/preset-modules": { - "version": "0.1.6-no-external-plugins", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", - "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/@babel/preset-typescript": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.27.1.tgz", - "integrity": "sha512-l7WfQfX0WK4M0v2RudjuQK4u99BS6yLHYEmdtVPP7lKV013zr9DygFuWNlnbvQ9LR+LS0Egz/XAvGx5U9MX0fQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-validator-option": "^7.27.1", - "@babel/plugin-syntax-jsx": "^7.27.1", - "@babel/plugin-transform-modules-commonjs": "^7.27.1", - "@babel/plugin-transform-typescript": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/template": { "version": "7.27.2", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", @@ -2016,36 +1188,27 @@ } }, "node_modules/@babel/traverse": { - "version": "7.27.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.4.tgz", - "integrity": "sha512-oNcu2QbHqts9BtOWJosOVJapWjBDSxGCpFvikNR5TGDYDQf3JwpIoMzIKrvfoti93cLfPJEG4tH9SPVeyCGgdA==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.3.tgz", + "integrity": "sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.27.3", - "@babel/parser": "^7.27.4", + "@babel/generator": "^7.28.3", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.3", "@babel/template": "^7.27.2", - "@babel/types": "^7.27.3", - "debug": "^4.3.1", - "globals": "^11.1.0" + "@babel/types": "^7.28.2", + "debug": "^4.3.1" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/types": { - "version": "7.27.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.6.tgz", - "integrity": "sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==", + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz", + "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", @@ -2819,16 +1982,6 @@ "node": ">=12" } }, - "node_modules/@discoveryjs/json-ext": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.6.3.tgz", - "integrity": "sha512-4B4OijXeVNOPZlYA2oEwWOTkzyltLao+xbotHQeqN++Rv27Y6s818+n2Qkp8q+Fxhn0t/5lA5X1Mxktud8eayQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.17.0" - } - }, "node_modules/@electron/get": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@electron/get/-/get-4.0.1.tgz", @@ -4204,6 +3357,16 @@ "@ethersproject/strings": "^5.8.0" } }, + "node_modules/@fastify/busboy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, "node_modules/@gerrit0/mini-shiki": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/@gerrit0/mini-shiki/-/mini-shiki-3.6.0.tgz", @@ -4604,17 +3767,13 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", - "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" } }, "node_modules/@jridgewell/gen-mapping/node_modules/@jridgewell/trace-mapping": { @@ -4636,19 +3795,11 @@ "node": ">=6.0.0" } }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@jridgewell/source-map": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -4659,6 +3810,7 @@ "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -5563,6 +4715,7 @@ "version": "1.53.1", "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.53.1.tgz", "integrity": "sha512-Z4c23LHV0muZ8hfv4jw6HngPJkbbtZxTkxPNIg7cJcTc9C28N/p2q7g3JZS2SiKBBHJ3uM1dgDye66bB7LEk5w==", + "dev": true, "license": "Apache-2.0", "dependencies": { "playwright": "1.53.1" @@ -7416,6 +6569,7 @@ "version": "9.6.1", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", + "dev": true, "license": "MIT", "dependencies": { "@types/estree": "*", @@ -7426,6 +6580,7 @@ "version": "3.7.7", "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, "license": "MIT", "dependencies": { "@types/eslint": "*", @@ -7708,6 +6863,16 @@ "@types/node": "^18.11.18" } }, + "node_modules/@types/ssh2-streams": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/@types/ssh2-streams/-/ssh2-streams-0.1.12.tgz", + "integrity": "sha512-Sy8tpEmCce4Tq0oSOYdfqaBpA3hDM8SoxoFh5vzFsu2oL+znzGz8oVWW7xb4K920yYMUY+PIG31qZnFMfPWNCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/ssh2/node_modules/@types/node": { "version": "18.19.112", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.112.tgz", @@ -8356,10 +7521,6 @@ "resolved": "packages/enr", "link": true }, - "node_modules/@waku/headless-tests": { - "resolved": "packages/headless-tests", - "link": true - }, "node_modules/@waku/interfaces": { "resolved": "packages/interfaces", "link": true @@ -8423,6 +7584,7 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", + "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/helper-numbers": "1.13.2", @@ -8433,24 +7595,28 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/helper-api-error": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/helper-buffer": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/helper-numbers": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/floating-point-hex-parser": "1.13.2", @@ -8462,12 +7628,14 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/helper-wasm-section": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", + "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -8480,6 +7648,7 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", + "dev": true, "license": "MIT", "dependencies": { "@xtuc/ieee754": "^1.2.0" @@ -8489,6 +7658,7 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@xtuc/long": "4.2.2" @@ -8498,12 +7668,14 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/wasm-edit": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", + "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -8520,6 +7692,7 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", + "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -8533,6 +7706,7 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", + "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -8545,6 +7719,7 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", + "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -8559,69 +7734,25 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", + "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", "@xtuc/long": "4.2.2" } }, - "node_modules/@webpack-cli/configtest": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-3.0.1.tgz", - "integrity": "sha512-u8d0pJ5YFgneF/GuvEiDA61Tf1VDomHHYMjv/wc9XzYj7nopltpG96nXN5dJRstxZhcNpV1g+nT6CydO7pHbjA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.12.0" - }, - "peerDependencies": { - "webpack": "^5.82.0", - "webpack-cli": "6.x.x" - } - }, - "node_modules/@webpack-cli/info": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-3.0.1.tgz", - "integrity": "sha512-coEmDzc2u/ffMvuW9aCjoRzNSPDl/XLuhPdlFRpT9tZHmJ/039az33CE7uH+8s0uL1j5ZNtfdv0HkfaKRBGJsQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.12.0" - }, - "peerDependencies": { - "webpack": "^5.82.0", - "webpack-cli": "6.x.x" - } - }, - "node_modules/@webpack-cli/serve": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-3.0.1.tgz", - "integrity": "sha512-sbgw03xQaCLiT6gcY/6u3qBDn01CWw/nbaXl3gTdTFuJJ75Gffv3E3DBpgvY2fkkrdS1fpjaXNOmJlnbtKauKg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.12.0" - }, - "peerDependencies": { - "webpack": "^5.82.0", - "webpack-cli": "6.x.x" - }, - "peerDependenciesMeta": { - "webpack-dev-server": { - "optional": true - } - } - }, "node_modules/@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true, "license": "BSD-3-Clause" }, "node_modules/@xtuc/long": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true, "license": "Apache-2.0" }, "node_modules/@yarnpkg/lockfile": { @@ -8630,12 +7761,18 @@ "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", "license": "BSD-2-Clause" }, - "node_modules/@zeit/schemas": { - "version": "2.36.0", - "resolved": "https://registry.npmjs.org/@zeit/schemas/-/schemas-2.36.0.tgz", - "integrity": "sha512-7kjMwcChYEzMKjeex9ZFXkt1AyNov9R5HZtjBKVsmVpw7pa7ZtlCGvCBC2vnnXctaYN+aRI61HjIqeetZW5ROg==", + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } }, "node_modules/abort-error": { "version": "1.0.1", @@ -10258,6 +9395,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, "license": "MIT", "dependencies": { "ajv": "^8.0.0" @@ -10275,6 +9413,7 @@ "version": "8.17.1", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -10291,6 +9430,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, "license": "MIT" }, "node_modules/allure-commandline": { @@ -10351,48 +9491,6 @@ "mocha": ">=6.2.x" } }, - "node_modules/ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.1.0" - } - }, - "node_modules/ansi-align/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/ansi-align/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-align/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", @@ -10500,10 +9598,48 @@ "node": ">=8" } }, - "node_modules/arch": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", - "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", + "node_modules/archiver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.1.tgz", + "integrity": "sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "archiver-utils": "^5.0.2", + "async": "^3.2.4", + "buffer-crc32": "^1.0.0", + "readable-stream": "^4.0.0", + "readdir-glob": "^1.1.2", + "tar-stream": "^3.0.0", + "zip-stream": "^6.0.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/archiver-utils": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-5.0.2.tgz", + "integrity": "sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob": "^10.0.0", + "graceful-fs": "^4.2.0", + "is-stream": "^2.0.1", + "lazystream": "^1.0.0", + "lodash": "^4.17.15", + "normalize-path": "^3.0.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/archiver-utils/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", "dev": true, "funding": [ { @@ -10519,7 +9655,130 @@ "url": "https://feross.org/support" } ], - "license": "MIT" + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/archiver-utils/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/archiver-utils/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, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/archiver-utils/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/archiver-utils/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "dev": true, + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/archiver/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/archiver/node_modules/buffer-crc32": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", + "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/archiver/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "dev": true, + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } }, "node_modules/archy": { "version": "1.0.0", @@ -10760,23 +10019,6 @@ "safer-buffer": "~2.1.0" } }, - "node_modules/asn1.js": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", - "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", - "license": "MIT", - "dependencies": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "node_modules/asn1.js/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", - "license": "MIT" - }, "node_modules/assert": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz", @@ -10827,6 +10069,13 @@ "node": ">= 0.4" } }, + "node_modules/async-lock": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/async-lock/-/async-lock-1.4.1.tgz", + "integrity": "sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ==", + "dev": true, + "license": "MIT" + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -10877,153 +10126,14 @@ "dev": true, "license": "Apache-2.0" }, - "node_modules/babel-loader": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.2.1.tgz", - "integrity": "sha512-fqe8naHt46e0yIdkjUZYqddSXfej3AHajX+CSO5X7oy0EmPc6o5Xh+RClNoHjnieWz9AW4kZxW9yyFMhVB1QLA==", - "dev": true, - "license": "MIT", - "dependencies": { - "find-cache-dir": "^4.0.0", - "schema-utils": "^4.0.0" - }, - "engines": { - "node": ">= 14.15.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0", - "webpack": ">=5" - } - }, - "node_modules/babel-loader/node_modules/find-cache-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", - "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", - "dev": true, - "license": "MIT", - "dependencies": { - "common-path-prefix": "^3.0.0", - "pkg-dir": "^7.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/babel-loader/node_modules/find-up": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", - "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^7.1.0", - "path-exists": "^5.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/babel-loader/node_modules/locate-path": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", - "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^6.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/babel-loader/node_modules/p-limit": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", - "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^1.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/babel-loader/node_modules/p-locate": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", - "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/babel-loader/node_modules/path-exists": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", - "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } - }, - "node_modules/babel-loader/node_modules/pkg-dir": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", - "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", - "dev": true, - "license": "MIT", - "dependencies": { - "find-up": "^6.3.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/babel-loader/node_modules/yocto-queue": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.1.tgz", - "integrity": "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.13", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.13.tgz", - "integrity": "sha512-3sX/eOms8kd3q2KZ6DAhKPc0dgm525Gqq5NtWKZ7QYYZEv57OQ54KtblzJzH1lQF/eQxO8KjWGIK9IPUJNus5g==", + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz", + "integrity": "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==", "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.22.6", - "@babel/helper-define-polyfill-provider": "^0.6.4", + "@babel/compat-data": "^7.27.7", + "@babel/helper-define-polyfill-provider": "^0.6.5", "semver": "^6.3.1" }, "peerDependencies": { @@ -11053,12 +10163,12 @@ } }, "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.4.tgz", - "integrity": "sha512-7gD3pRadPrbjhjLyxebmx/WrFYcuSjZ0XbdUujQMZ/fcE9oeewk2U/7PCvez84UeuK3oSjmPZ0Ch0dlupQvGzw==", + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz", + "integrity": "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==", "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.4" + "@babel/helper-define-polyfill-provider": "^0.6.5" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -11303,153 +10413,6 @@ "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==", "license": "MIT" }, - "node_modules/boxen": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.0.0.tgz", - "integrity": "sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-align": "^3.0.1", - "camelcase": "^7.0.0", - "chalk": "^5.0.1", - "cli-boxes": "^3.0.0", - "string-width": "^5.1.2", - "type-fest": "^2.13.0", - "widest-line": "^4.0.1", - "wrap-ansi": "^8.0.1" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/boxen/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/boxen/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/boxen/node_modules/camelcase": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", - "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/boxen/node_modules/chalk": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", - "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/boxen/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, - "license": "MIT" - }, - "node_modules/boxen/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/boxen/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/boxen/node_modules/type-fest": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", - "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/boxen/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/brace-expansion": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", @@ -11477,144 +10440,12 @@ "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", "license": "MIT" }, - "node_modules/browser-resolve": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-2.0.0.tgz", - "integrity": "sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ==", - "license": "MIT", - "dependencies": { - "resolve": "^1.17.0" - } - }, "node_modules/browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", "license": "ISC" }, - "node_modules/browserify-aes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "license": "MIT", - "dependencies": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/browserify-cipher": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", - "license": "MIT", - "dependencies": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" - } - }, - "node_modules/browserify-des": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", - "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", - "license": "MIT", - "dependencies": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/browserify-rsa": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.1.tgz", - "integrity": "sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==", - "license": "MIT", - "dependencies": { - "bn.js": "^5.2.1", - "randombytes": "^2.1.0", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/browserify-sign": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.3.tgz", - "integrity": "sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==", - "license": "ISC", - "dependencies": { - "bn.js": "^5.2.1", - "browserify-rsa": "^4.1.0", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "elliptic": "^6.5.5", - "hash-base": "~3.0", - "inherits": "^2.0.4", - "parse-asn1": "^5.1.7", - "readable-stream": "^2.3.8", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.12" - } - }, - "node_modules/browserify-sign/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "license": "MIT" - }, - "node_modules/browserify-sign/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/browserify-sign/node_modules/readable-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/browserify-sign/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/browserify-sign/node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/browserify-zlib": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", - "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", - "license": "MIT", - "dependencies": { - "pako": "~1.0.5" - } - }, "node_modules/browserslist": { "version": "4.25.0", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.0.tgz", @@ -11686,12 +10517,6 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "license": "MIT" }, - "node_modules/buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", - "license": "MIT" - }, "node_modules/buildcheck": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/buildcheck/-/buildcheck-0.0.6.tgz", @@ -11701,11 +10526,15 @@ "node": ">=10.0.0" } }, - "node_modules/builtin-status-codes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", - "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==", - "license": "MIT" + "node_modules/byline": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz", + "integrity": "sha512-s6webAy+R4SR8XVuJWt2V2rGvhnrhxN+9S15GNuTK3wKPOXFF6RNc+8ug2XhH+2s4f+uudG4kUVYmYOQWL2g0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, "node_modules/bytes": { "version": "3.1.2", @@ -12192,6 +11021,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.0" @@ -12228,19 +11058,6 @@ "node": ">=8" } }, - "node_modules/cipher-base": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.6.tgz", - "integrity": "sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.4", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -12287,19 +11104,6 @@ "node": ">=8" } }, - "node_modules/cli-boxes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", - "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/cli-cursor": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", @@ -12493,140 +11297,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/clipboardy": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-3.0.0.tgz", - "integrity": "sha512-Su+uU5sr1jkUy1sGRpLKjKrvEOVXgSgiSInwa/qeID6aJ07yh+5NWc3h2QfjHjBnfX4LhtFcuAWKUsJ3r+fjbg==", - "dev": true, - "license": "MIT", - "dependencies": { - "arch": "^2.2.0", - "execa": "^5.1.1", - "is-wsl": "^2.2.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/clipboardy/node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "license": "MIT", - "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/clipboardy/node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/clipboardy/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, - "license": "Apache-2.0", - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/clipboardy/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, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/clipboardy/node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/clipboardy/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, - "license": "MIT", - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/clipboardy/node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/clipboardy/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, - "license": "ISC" - }, - "node_modules/clipboardy/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, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -12696,34 +11366,6 @@ "node": ">=0.8" } }, - "node_modules/clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/clone-deep/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "license": "MIT", - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", @@ -12815,13 +11457,6 @@ "node": ">= 12.0.0" } }, - "node_modules/common-path-prefix": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", - "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", - "dev": true, - "license": "ISC" - }, "node_modules/commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -12838,72 +11473,78 @@ "dot-prop": "^5.1.0" } }, - "node_modules/compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "node_modules/compress-commons": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz", + "integrity": "sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==", "dev": true, "license": "MIT", "dependencies": { - "mime-db": ">= 1.43.0 < 2" + "crc-32": "^1.2.0", + "crc32-stream": "^6.0.0", + "is-stream": "^2.0.1", + "normalize-path": "^3.0.0", + "readable-stream": "^4.0.0" }, "engines": { - "node": ">= 0.6" + "node": ">= 14" } }, - "node_modules/compression": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", - "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "node_modules/compress-commons/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "license": "MIT", "dependencies": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", - "debug": "2.6.9", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" } }, - "node_modules/compression/node_modules/bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "node_modules/compress-commons/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, "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/compression/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/compress-commons/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", "dev": true, "license": "MIT", "dependencies": { - "ms": "2.0.0" + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/compression/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" - }, - "node_modules/compression/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -12959,17 +11600,6 @@ "dev": true, "license": "MIT" }, - "node_modules/console-browserify": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", - "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==" - }, - "node_modules/constants-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", - "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==", - "license": "MIT" - }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -13263,47 +11893,73 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/create-ecdh": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", - "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/crc32-stream": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-6.0.0.tgz", + "integrity": "sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==", + "dev": true, "license": "MIT", "dependencies": { - "bn.js": "^4.1.0", - "elliptic": "^6.5.3" + "crc-32": "^1.2.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" } }, - "node_modules/create-ecdh/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", - "license": "MIT" - }, - "node_modules/create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "node_modules/crc32-stream/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "license": "MIT", "dependencies": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" } }, - "node_modules/create-hmac": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "node_modules/crc32-stream/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "dev": true, "license": "MIT", "dependencies": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/create-require": { @@ -13336,32 +11992,6 @@ "node": "*" } }, - "node_modules/crypto-browserify": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.1.tgz", - "integrity": "sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==", - "license": "MIT", - "dependencies": { - "browserify-cipher": "^1.0.1", - "browserify-sign": "^4.2.3", - "create-ecdh": "^4.0.4", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "diffie-hellman": "^5.0.3", - "hash-base": "~3.0.4", - "inherits": "^2.0.4", - "pbkdf2": "^3.1.2", - "public-encrypt": "^4.0.3", - "randombytes": "^2.1.0", - "randomfill": "^1.0.4" - }, - "engines": { - "node": ">= 0.10" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/crypto-random-string": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", @@ -14273,16 +12903,6 @@ "node": ">=6" } }, - "node_modules/des.js": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", - "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, "node_modules/destroy": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", @@ -14345,23 +12965,6 @@ "node": ">=0.3.1" } }, - "node_modules/diffie-hellman": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", - "license": "MIT", - "dependencies": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - } - }, - "node_modules/diffie-hellman/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", - "license": "MIT" - }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -14396,6 +12999,19 @@ "node": ">=6" } }, + "node_modules/docker-compose": { + "version": "0.24.8", + "resolved": "https://registry.npmjs.org/docker-compose/-/docker-compose-0.24.8.tgz", + "integrity": "sha512-plizRs/Vf15H+GCVxq2EUvyPK7ei9b/cVesHvjnX4xaXjM9spHe2Ytq0BitndFgvTJ3E3NljPNUEl7BAN43iZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "yaml": "^2.2.2" + }, + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/docker-modem": { "version": "5.0.6", "resolved": "https://registry.npmjs.org/docker-modem/-/docker-modem-5.0.6.tgz", @@ -14482,18 +13098,6 @@ "void-elements": "^2.0.0" } }, - "node_modules/domain-browser": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-4.22.0.tgz", - "integrity": "sha512-IGBwjF7tNk3cwypFNH/7bfzBcgSCbaMOD3GsaY1AU/JRrnHnYgEM0+9kQt52iZxjNsjBtJYtao146V+f8jFZNw==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://bevry.me/fund" - } - }, "node_modules/dot-prop": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", @@ -15000,19 +13604,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/envinfo": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.14.0.tgz", - "integrity": "sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg==", - "dev": true, - "license": "MIT", - "bin": { - "envinfo": "dist/cli.js" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/environment": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", @@ -15151,6 +13742,7 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, "license": "MIT" }, "node_modules/es-object-atoms": { @@ -16408,6 +15000,16 @@ "integrity": "sha512-KGft0ldl31BZVV//jj+IAIGCxkvvUkkON+ScH6zfoX+l+omX6001ggyRSpI0Io2Hlro0ThXotswCtfzS8UkIiQ==", "license": "MIT" }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", @@ -16424,16 +15026,6 @@ "node": ">=0.8.x" } }, - "node_modules/evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "license": "MIT", - "dependencies": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, "node_modules/execa": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", @@ -16745,6 +15337,7 @@ "version": "3.0.6", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", + "dev": true, "funding": [ { "type": "github", @@ -16757,16 +15350,6 @@ ], "license": "BSD-3-Clause" }, - "node_modules/fastest-levenshtein": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", - "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4.9.1" - } - }, "node_modules/fastq": { "version": "1.19.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", @@ -16870,7 +15453,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-2.0.2.tgz", "integrity": "sha512-lO3ttPjHZRfjMcxWKb1j1eDhTFsu4meeR3lnMcnBFhk6RuLhvEiuALu2TlfL310ph4lCYYwgF/ElIjdP739tdg==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -17391,6 +15973,19 @@ "node": ">=8.0.0" } }, + "node_modules/get-port": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-7.1.0.tgz", + "integrity": "sha512-QB9NKEeDg3xxVwCCwJQ9+xycaz6pBB6iQ76wiWMl1927n0Kir6alPiP+yuiICLLU4jpMe08dXfpebuQppFA2zw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", @@ -17545,6 +16140,7 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true, "license": "BSD-2-Clause" }, "node_modules/glob/node_modules/brace-expansion": { @@ -17897,19 +16493,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/hash-base": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.5.tgz", - "integrity": "sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.4", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/hash.js": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", @@ -18142,12 +16725,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/https-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", - "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==", - "license": "MIT" - }, "node_modules/https-proxy-agent": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", @@ -18262,26 +16839,6 @@ "node": ">=18.20" } }, - "node_modules/import-local": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", - "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", - "dev": true, - "license": "MIT", - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/import-meta-resolve": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", @@ -18378,16 +16935,6 @@ "node": ">= 0.4" } }, - "node_modules/interpret": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", - "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.13.0" - } - }, "node_modules/into-stream": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-7.0.0.tgz", @@ -19045,19 +17592,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-port-reachable": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-port-reachable/-/is-port-reachable-4.0.0.tgz", - "integrity": "sha512-9UoipoxYmSk6Xy7QFgRv2HDyaysmgSG75TFQs6S+3pDM7ZhKTF/bskZV+0UlABHzKjNVhPjYCLfeZUEg1wXxig==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-promise": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", @@ -19292,16 +17826,6 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "license": "ISC" }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/isomorphic-fetch": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz", @@ -19313,15 +17837,6 @@ "whatwg-fetch": "^3.4.1" } }, - "node_modules/isomorphic-timers-promises": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/isomorphic-timers-promises/-/isomorphic-timers-promises-1.0.1.tgz", - "integrity": "sha512-u4sej9B1LPSxTGKB/HiuzvEQnXH0ECYkSVQU39koSwmFAxhlEAFl9RdTvLv4TOTQUgBS5O3O5fwUxk6byBZ+IQ==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, "node_modules/isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -19776,6 +18291,7 @@ "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, "license": "MIT", "dependencies": { "@types/node": "*", @@ -19790,6 +18306,7 @@ "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -20347,6 +18864,59 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, + "node_modules/lazystream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lazystream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/lazystream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/lazystream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -21002,6 +19572,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.11.5" @@ -21553,17 +20124,6 @@ "is-buffer": "~1.1.6" } }, - "node_modules/md5.js": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "license": "MIT", - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, "node_modules/mdast-util-find-and-replace": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", @@ -22481,25 +21041,6 @@ "node": ">=8.6" } }, - "node_modules/miller-rabin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", - "license": "MIT", - "dependencies": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" - }, - "bin": { - "miller-rabin": "bin/miller-rabin" - } - }, - "node_modules/miller-rabin/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", - "license": "MIT" - }, "node_modules/mime": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", @@ -23191,34 +21732,6 @@ } } }, - "node_modules/node-polyfill-webpack-plugin": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/node-polyfill-webpack-plugin/-/node-polyfill-webpack-plugin-4.1.0.tgz", - "integrity": "sha512-b4ei444EKkOagG/yFqojrD3QTYM5IOU1f8tn9o6uwrG4qL+brI7oVhjPVd0ZL2xy+Z6CP5bu9w8XTvlWgiXHcw==", - "license": "MIT", - "dependencies": { - "node-stdlib-browser": "^1.3.0", - "type-fest": "^4.27.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "webpack": ">=5" - } - }, - "node_modules/node-polyfill-webpack-plugin/node_modules/type-fest": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", - "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/node-preload": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", @@ -23237,56 +21750,6 @@ "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", "license": "MIT" }, - "node_modules/node-stdlib-browser": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-stdlib-browser/-/node-stdlib-browser-1.3.1.tgz", - "integrity": "sha512-X75ZN8DCLftGM5iKwoYLA3rjnrAEs97MkzvSd4q2746Tgpg8b8XWiBGiBG4ZpgcAqBgtgPHTiAc8ZMCvZuikDw==", - "license": "MIT", - "dependencies": { - "assert": "^2.0.0", - "browser-resolve": "^2.0.0", - "browserify-zlib": "^0.2.0", - "buffer": "^5.7.1", - "console-browserify": "^1.1.0", - "constants-browserify": "^1.0.0", - "create-require": "^1.1.1", - "crypto-browserify": "^3.12.1", - "domain-browser": "4.22.0", - "events": "^3.0.0", - "https-browserify": "^1.0.0", - "isomorphic-timers-promises": "^1.0.1", - "os-browserify": "^0.3.0", - "path-browserify": "^1.0.1", - "pkg-dir": "^5.0.0", - "process": "^0.11.10", - "punycode": "^1.4.1", - "querystring-es3": "^0.2.1", - "readable-stream": "^3.6.0", - "stream-browserify": "^3.0.0", - "stream-http": "^3.2.0", - "string_decoder": "^1.0.0", - "timers-browserify": "^2.0.4", - "tty-browserify": "0.0.1", - "url": "^0.11.4", - "util": "^0.12.4", - "vm-browserify": "^1.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-stdlib-browser/node_modules/pkg-dir": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz", - "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==", - "license": "MIT", - "dependencies": { - "find-up": "^5.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/normalize-package-data": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", @@ -26899,16 +25362,6 @@ "node": ">= 0.8" } }, - "node_modules/on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -27056,12 +25509,6 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/os-browserify": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", - "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==", - "license": "MIT" - }, "node_modules/os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", @@ -27368,12 +25815,6 @@ "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", "license": "BlueOak-1.0.0" }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "license": "(MIT AND Zlib)" - }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -27386,23 +25827,6 @@ "node": ">=6" } }, - "node_modules/parse-asn1": { - "version": "5.1.7", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.7.tgz", - "integrity": "sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==", - "license": "ISC", - "dependencies": { - "asn1.js": "^4.10.1", - "browserify-aes": "^1.2.0", - "evp_bytestokey": "^1.0.3", - "hash-base": "~3.0", - "pbkdf2": "^3.1.2", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/parse-imports-exports": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/parse-imports-exports/-/parse-imports-exports-0.2.4.tgz", @@ -27705,13 +26129,6 @@ "node": ">=0.10.0" } }, - "node_modules/path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", - "dev": true, - "license": "(WTFPL OR MIT)" - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -27788,54 +26205,6 @@ "node": "*" } }, - "node_modules/pbkdf2": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.3.tgz", - "integrity": "sha512-wfRLBZ0feWRhCIkoMB6ete7czJcnNnqRpcoWQBLqatqXXmelSRqfdDK4F3u9T2s2cXas/hQJcryI/4lAL+XTlA==", - "license": "MIT", - "dependencies": { - "create-hash": "~1.1.3", - "create-hmac": "^1.1.7", - "ripemd160": "=2.0.1", - "safe-buffer": "^5.2.1", - "sha.js": "^2.4.11", - "to-buffer": "^1.2.0" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/pbkdf2/node_modules/create-hash": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz", - "integrity": "sha512-snRpch/kwQhcdlnZKYanNF1m0RDlrCdSKQaH87w1FCFPVPNCQ/Il9QJKAX2jVBZddRdaHBMC+zXa9Gw9tmkNUA==", - "license": "MIT", - "dependencies": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "sha.js": "^2.4.0" - } - }, - "node_modules/pbkdf2/node_modules/hash-base": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-2.0.2.tgz", - "integrity": "sha512-0TROgQ1/SxE6KmxWSvXHvRj90/Xo1JvZShofnYF+f6ZsGtR4eES7WfrQzPalmyagfKZCXpVnitiRebZulWsbiw==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.1" - } - }, - "node_modules/pbkdf2/node_modules/ripemd160": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.1.tgz", - "integrity": "sha512-J7f4wutN8mdbV08MJnXibYpCOPHR+yzy+iQ/AsjMv2j8cLavQ8VGagDFUwwTAdF8FmRKVeNpbTTEwNHCW1g94w==", - "license": "MIT", - "dependencies": { - "hash-base": "^2.0.0", - "inherits": "^2.0.1" - } - }, "node_modules/pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -28118,6 +26487,7 @@ "version": "1.53.1", "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.53.1.tgz", "integrity": "sha512-LJ13YLr/ocweuwxyGf1XNFWIU4M2zUSo149Qbp+A4cpwDjsxRPj7k6H25LBrEHiEwxvRbD8HdwvQmRMSvquhYw==", + "dev": true, "license": "Apache-2.0", "dependencies": { "playwright-core": "1.53.1" @@ -28136,6 +26506,7 @@ "version": "1.53.1", "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.53.1.tgz", "integrity": "sha512-Z46Oq7tLAyT0lGoFx4DOuB1IA9D1TPj0QkYxpPVUnGDqHHvDpCftu1J2hM2PiWsNMoZh8+LQaarAWcDfPBc6zg==", + "dev": true, "license": "Apache-2.0", "bin": { "playwright-core": "cli.js" @@ -28863,6 +27234,7 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -29170,6 +27542,36 @@ "node": ">=0.10" } }, + "node_modules/properties-reader": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/properties-reader/-/properties-reader-2.3.0.tgz", + "integrity": "sha512-z597WicA7nDZxK12kZqHr2TcvwNU1GCfA5UwfDY/HDp3hXPoPlb5rlEx9bwGTiJnc0OqbBTkU975jDToth8Gxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mkdirp": "^1.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/steveukx/properties?sponsor=1" + } + }, + "node_modules/properties-reader/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/proto-list": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", @@ -29416,26 +27818,6 @@ "dev": true, "license": "MIT" }, - "node_modules/public-encrypt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", - "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", - "license": "MIT", - "dependencies": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/public-encrypt/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", - "license": "MIT" - }, "node_modules/pump": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", @@ -29450,6 +27832,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "dev": true, "license": "MIT" }, "node_modules/punycode.js": { @@ -29663,14 +28046,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/querystring-es3": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", - "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==", - "engines": { - "node": ">=0.4.x" - } - }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -29730,16 +28105,6 @@ "safe-buffer": "^5.1.0" } }, - "node_modules/randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", - "license": "MIT", - "dependencies": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } - }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -30504,6 +28869,29 @@ "node": ">= 6" } }, + "node_modules/readdir-glob": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", + "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.1.0" + } + }, + "node_modules/readdir-glob/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -30516,19 +28904,6 @@ "node": ">=8.10.0" } }, - "node_modules/rechoir": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", - "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "resolve": "^1.20.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, "node_modules/redent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", @@ -30710,6 +29085,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -30770,29 +29146,6 @@ "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", "license": "MIT" }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-cwd/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/resolve-dir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", @@ -30921,16 +29274,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "license": "MIT", - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, "node_modules/roarr": { "version": "2.15.4", "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", @@ -31203,6 +29546,7 @@ "version": "4.3.2", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", + "dev": true, "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.9", @@ -31222,6 +29566,7 @@ "version": "8.17.1", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -31238,6 +29583,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3" @@ -31250,6 +29596,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, "license": "MIT" }, "node_modules/scrypt-js": { @@ -32026,132 +30373,6 @@ "randombytes": "^2.1.0" } }, - "node_modules/serve": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/serve/-/serve-14.2.4.tgz", - "integrity": "sha512-qy1S34PJ/fcY8gjVGszDB3EXiPSk5FKhUa7tQe0UPRddxRidc2V6cNHPNewbE1D7MAkgLuWEt3Vw56vYy73tzQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@zeit/schemas": "2.36.0", - "ajv": "8.12.0", - "arg": "5.0.2", - "boxen": "7.0.0", - "chalk": "5.0.1", - "chalk-template": "0.4.0", - "clipboardy": "3.0.0", - "compression": "1.7.4", - "is-port-reachable": "4.0.0", - "serve-handler": "6.1.6", - "update-check": "1.5.4" - }, - "bin": { - "serve": "build/main.js" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/serve-handler": { - "version": "6.1.6", - "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.6.tgz", - "integrity": "sha512-x5RL9Y2p5+Sh3D38Fh9i/iQ5ZK+e4xuXRd/pGbM4D13tgo/MGwbttUk8emytcr1YYzBYs+apnUngBDFYfpjPuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "bytes": "3.0.0", - "content-disposition": "0.5.2", - "mime-types": "2.1.18", - "minimatch": "3.1.2", - "path-is-inside": "1.0.2", - "path-to-regexp": "3.3.0", - "range-parser": "1.2.0" - } - }, - "node_modules/serve-handler/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/serve-handler/node_modules/bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/serve-handler/node_modules/content-disposition": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", - "integrity": "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serve-handler/node_modules/mime-db": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", - "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serve-handler/node_modules/mime-types": { - "version": "2.1.18", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", - "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": "~1.33.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serve-handler/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/serve-handler/node_modules/path-to-regexp": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.3.0.tgz", - "integrity": "sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==", - "dev": true, - "license": "MIT" - }, - "node_modules/serve-handler/node_modules/range-parser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", - "integrity": "sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/serve-static": { "version": "1.16.2", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", @@ -32176,83 +30397,6 @@ "node": ">= 0.8" } }, - "node_modules/serve/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/serve/node_modules/arg": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", - "dev": true, - "license": "MIT" - }, - "node_modules/serve/node_modules/chalk": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.1.tgz", - "integrity": "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/serve/node_modules/chalk-template": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/chalk-template/-/chalk-template-0.4.0.tgz", - "integrity": "sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.1.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/chalk-template?sponsor=1" - } - }, - "node_modules/serve/node_modules/chalk-template/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/serve/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -32305,44 +30449,12 @@ "node": ">= 0.4" } }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "license": "MIT" - }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "license": "ISC" }, - "node_modules/sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "license": "(MIT AND BSD-3-Clause)", - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - }, - "bin": { - "sha.js": "bin.js" - } - }, - "node_modules/shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "dev": true, - "license": "MIT", - "dependencies": { - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -33013,6 +31125,28 @@ "devOptional": true, "license": "BSD-3-Clause" }, + "node_modules/ssh-remote-port-forward": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/ssh-remote-port-forward/-/ssh-remote-port-forward-1.0.4.tgz", + "integrity": "sha512-x0LV1eVDwjf1gmG7TTnfqIzf+3VPRz7vrNIjX6oYLbeCrf/PeVY6hkT68Mg+q02qXxQhrLjB0jfgvhevoCRmLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ssh2": "^0.5.48", + "ssh2": "^1.4.0" + } + }, + "node_modules/ssh-remote-port-forward/node_modules/@types/ssh2": { + "version": "0.5.52", + "resolved": "https://registry.npmjs.org/@types/ssh2/-/ssh2-0.5.52.tgz", + "integrity": "sha512-lbLLlXxdCZOSJMCInKH2+9V/77ET2J6NPQHpFI0kda61Dd1KglJs+fPQBchizmzYSOJBgdTajhPqBO1xxLywvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/ssh2-streams": "*" + } + }, "node_modules/ssh2": { "version": "1.16.0", "resolved": "https://registry.npmjs.org/ssh2/-/ssh2-1.16.0.tgz", @@ -33145,18 +31279,6 @@ "safe-buffer": "~5.1.0" } }, - "node_modules/stream-http": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.2.0.tgz", - "integrity": "sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==", - "license": "MIT", - "dependencies": { - "builtin-status-codes": "^3.0.0", - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "xtend": "^4.0.2" - } - }, "node_modules/streamroller": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz", @@ -33715,6 +31837,7 @@ "version": "5.43.1", "resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz", "integrity": "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -33733,6 +31856,7 @@ "version": "5.3.14", "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz", "integrity": "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", @@ -33767,6 +31891,7 @@ "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -33777,6 +31902,7 @@ "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, "license": "MIT" }, "node_modules/test-exclude": { @@ -33828,6 +31954,30 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/testcontainers": { + "version": "10.28.0", + "resolved": "https://registry.npmjs.org/testcontainers/-/testcontainers-10.28.0.tgz", + "integrity": "sha512-1fKrRRCsgAQNkarjHCMKzBKXSJFmzNTiTbhb5E/j5hflRXChEtHvkefjaHlgkNUjfw92/Dq8LTgwQn6RDBFbMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@balena/dockerignore": "^1.0.2", + "@types/dockerode": "^3.3.35", + "archiver": "^7.0.1", + "async-lock": "^1.4.1", + "byline": "^5.0.0", + "debug": "^4.3.5", + "docker-compose": "^0.24.8", + "dockerode": "^4.0.5", + "get-port": "^7.1.0", + "proper-lockfile": "^4.1.2", + "properties-reader": "^2.3.0", + "ssh-remote-port-forward": "^1.0.4", + "tar-fs": "^3.0.7", + "tmp": "^0.2.3", + "undici": "^5.29.0" + } + }, "node_modules/text-decoder": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", @@ -33932,18 +32082,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/timers-browserify": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", - "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", - "license": "MIT", - "dependencies": { - "setimmediate": "^1.0.4" - }, - "engines": { - "node": ">=0.6.0" - } - }, "node_modules/tinyglobby": { "version": "0.2.14", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", @@ -33996,20 +32134,6 @@ "node": ">=14.14" } }, - "node_modules/to-buffer": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.1.tgz", - "integrity": "sha512-tB82LpAIWjhLYbqjx3X4zEeHN6M8CiuOEy2JY8SEQVdYRe3CCHOFaqrBW1doLDrfpWhplcW7BL+bO3/6S3pcDQ==", - "license": "MIT", - "dependencies": { - "isarray": "^2.0.5", - "safe-buffer": "^5.2.1", - "typed-array-buffer": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -34262,12 +32386,6 @@ "devOptional": true, "license": "0BSD" }, - "node_modules/tty-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", - "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==", - "license": "MIT" - }, "node_modules/tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", @@ -35043,6 +33161,19 @@ "dev": true, "license": "MIT" }, + "node_modules/undici": { + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz", + "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, "node_modules/undici-types": { "version": "7.8.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz", @@ -35268,41 +33399,6 @@ "browserslist": ">= 4.21.0" } }, - "node_modules/update-check": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/update-check/-/update-check-1.5.4.tgz", - "integrity": "sha512-5YHsflzHP4t1G+8WGPlvKbJEbAJGCgw+Em+dGR1KmBUbr1J36SJBqlHLjR7oob7sco5hWHGQVcr9B2poIVDDTQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "registry-auth-token": "3.3.2", - "registry-url": "3.1.0" - } - }, - "node_modules/update-check/node_modules/registry-auth-token": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz", - "integrity": "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "rc": "^1.1.6", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/update-check/node_modules/registry-url": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", - "integrity": "sha512-ZbgR5aZEdf4UKZVBPYIgaglBmSF2Hi94s2PcIHhRGFjKYu+chjJdYfHn4rt3hB6eCKLJ8giVIIfgMa1ehDfZKA==", - "dev": true, - "license": "MIT", - "dependencies": { - "rc": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -35321,19 +33417,6 @@ "node": ">=6" } }, - "node_modules/url": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.4.tgz", - "integrity": "sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==", - "license": "MIT", - "dependencies": { - "punycode": "^1.4.1", - "qs": "^6.12.3" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/url-join": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/url-join/-/url-join-5.0.0.tgz", @@ -35459,12 +33542,6 @@ "node": ">= 0.8" } }, - "node_modules/vm-browserify": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", - "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", - "license": "MIT" - }, "node_modules/void-elements": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", @@ -35491,6 +33568,7 @@ "version": "2.4.4", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz", "integrity": "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==", + "dev": true, "license": "MIT", "dependencies": { "glob-to-regexp": "^0.4.1", @@ -35551,6 +33629,7 @@ "version": "5.99.9", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.9.tgz", "integrity": "sha512-brOPwM3JnmOa+7kd3NsmOUOwbDAj8FT9xDsG3IW0MgbN9yZV7Oi/s/+MNQ/EcSMqw7qfoRyXPoeEWT8zLVdVGg==", + "dev": true, "license": "MIT", "dependencies": { "@types/eslint-scope": "^3.7.7", @@ -35594,64 +33673,6 @@ } } }, - "node_modules/webpack-cli": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-6.0.1.tgz", - "integrity": "sha512-MfwFQ6SfwinsUVi0rNJm7rHZ31GyTcpVE5pgVA3hwFRb7COD4TzjUUwhGWKfO50+xdc2MQPuEBBJoqIMGt3JDw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@discoveryjs/json-ext": "^0.6.1", - "@webpack-cli/configtest": "^3.0.1", - "@webpack-cli/info": "^3.0.1", - "@webpack-cli/serve": "^3.0.1", - "colorette": "^2.0.14", - "commander": "^12.1.0", - "cross-spawn": "^7.0.3", - "envinfo": "^7.14.0", - "fastest-levenshtein": "^1.0.12", - "import-local": "^3.0.2", - "interpret": "^3.1.1", - "rechoir": "^0.8.0", - "webpack-merge": "^6.0.1" - }, - "bin": { - "webpack-cli": "bin/cli.js" - }, - "engines": { - "node": ">=18.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.82.0" - }, - "peerDependenciesMeta": { - "webpack-bundle-analyzer": { - "optional": true - }, - "webpack-dev-server": { - "optional": true - } - } - }, - "node_modules/webpack-cli/node_modules/webpack-merge": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", - "integrity": "sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "clone-deep": "^4.0.1", - "flat": "^5.0.2", - "wildcard": "^2.0.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, "node_modules/webpack-merge": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.2.tgz", @@ -35666,6 +33687,7 @@ "version": "3.3.3", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz", "integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==", + "dev": true, "license": "MIT", "engines": { "node": ">=10.13.0" @@ -35675,6 +33697,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", @@ -35688,6 +33711,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=4.0" @@ -35830,83 +33854,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/widest-line": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", - "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", - "dev": true, - "license": "MIT", - "dependencies": { - "string-width": "^5.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/widest-line/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/widest-line/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, - "license": "MIT" - }, - "node_modules/widest-line/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/widest-line/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/wildcard": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", - "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", - "dev": true, - "license": "MIT" - }, "node_modules/winston": { "version": "2.4.7", "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.7.tgz", @@ -36316,6 +34263,63 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/zip-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-6.0.1.tgz", + "integrity": "sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "archiver-utils": "^5.0.0", + "compress-commons": "^6.0.2", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/zip-stream/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/zip-stream/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "dev": true, + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, "node_modules/zod": { "version": "3.22.4", "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", @@ -36340,317 +34344,497 @@ "name": "@waku/browser-tests", "version": "0.1.0", "dependencies": { - "@playwright/test": "^1.51.1", - "@waku/sdk": "^0.0.30", + "@waku/discovery": "^0.0.11", + "@waku/interfaces": "^0.0.33", + "@waku/sdk": "^0.0.34", "cors": "^2.8.5", + "dotenv-flow": "^0.4.0", "express": "^4.21.2", - "node-polyfill-webpack-plugin": "^4.1.0" + "filter-obj": "^2.0.2", + "it-first": "^3.0.9" }, "devDependencies": { + "@playwright/test": "^1.51.1", "@types/cors": "^2.8.15", "@types/express": "^4.17.21", "@types/node": "^20.10.0", "axios": "^1.8.4", - "dotenv-flow": "^0.4.0", + "esbuild": "^0.21.5", "npm-run-all": "^4.1.5", - "serve": "^14.2.3", - "typescript": "5.8.3", - "webpack-cli": "^6.0.1" + "testcontainers": "^10.9.0", + "typescript": "5.8.3" } }, - "packages/browser-tests/node_modules/@chainsafe/as-sha256": { - "version": "0.4.2", - "license": "Apache-2.0" + "packages/browser-tests/node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } }, - "packages/browser-tests/node_modules/@chainsafe/libp2p-noise": { - "version": "16.0.0", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/as-chacha20poly1305": "^0.1.0", - "@chainsafe/as-sha256": "^0.4.1", - "@libp2p/crypto": "^5.0.0", - "@libp2p/interface": "^2.0.0", - "@libp2p/peer-id": "^5.0.0", - "@noble/ciphers": "^0.6.0", - "@noble/curves": "^1.1.0", - "@noble/hashes": "^1.3.1", - "it-length-prefixed": "^9.0.1", - "it-length-prefixed-stream": "^1.0.0", - "it-pair": "^2.0.6", - "it-pipe": "^3.0.1", - "it-stream-types": "^2.0.1", - "protons-runtime": "^5.5.0", - "uint8arraylist": "^2.4.3", - "uint8arrays": "^5.0.0", - "wherearewe": "^2.0.1" + "packages/browser-tests/node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" } }, - "packages/browser-tests/node_modules/@libp2p/ping": { - "version": "2.0.1", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@libp2p/crypto": "^5.0.1", - "@libp2p/interface": "^2.0.1", - "@libp2p/interface-internal": "^2.0.1", - "@multiformats/multiaddr": "^12.2.3", - "it-first": "^3.0.6", - "it-pipe": "^3.0.1", - "uint8arrays": "^5.1.0" + "packages/browser-tests/node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" } }, - "packages/browser-tests/node_modules/@noble/ciphers": { - "version": "0.6.0", + "packages/browser-tests/node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, "license": "MIT", - "funding": { - "url": "https://paulmillr.com/funding/" + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" } }, - "packages/browser-tests/node_modules/@types/node": { - "version": "20.17.52", + "packages/browser-tests/node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "undici-types": "~6.19.2" + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" } }, - "packages/browser-tests/node_modules/@waku/core": { - "version": "0.0.34", - "license": "MIT OR Apache-2.0", - "dependencies": { - "@libp2p/ping": "2.0.1", - "@waku/enr": "^0.0.28", - "@waku/interfaces": "0.0.29", - "@waku/proto": "0.0.9", - "@waku/utils": "0.0.22", - "debug": "^4.3.4", - "it-all": "^3.0.4", - "it-length-prefixed": "^9.0.4", - "it-pipe": "^3.0.1", - "uint8arraylist": "^2.4.3", - "uuid": "^9.0.0" - }, + "packages/browser-tests/node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=20" - }, - "peerDependencies": { - "@multiformats/multiaddr": "^12.0.0", - "libp2p": "2.1.8" - }, - "peerDependenciesMeta": { - "@multiformats/multiaddr": { - "optional": true - }, - "libp2p": { - "optional": true - } + "node": ">=12" } }, - "packages/browser-tests/node_modules/@waku/discovery": { - "version": "0.0.7", - "license": "MIT OR Apache-2.0", - "dependencies": { - "@waku/core": "0.0.34", - "@waku/enr": "0.0.28", - "@waku/interfaces": "0.0.29", - "@waku/proto": "^0.0.9", - "@waku/utils": "0.0.22", - "debug": "^4.3.4", - "dns-over-http-resolver": "^3.0.8", - "hi-base32": "^0.5.1", - "uint8arrays": "^5.0.1" - }, + "packages/browser-tests/node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=20" + "node": ">=12" } }, - "packages/browser-tests/node_modules/@waku/enr": { - "version": "0.0.28", - "license": "MIT OR Apache-2.0", - "dependencies": { - "@ethersproject/rlp": "^5.7.0", - "@libp2p/crypto": "^5.0.1", - "@libp2p/peer-id": "^5.0.1", - "@multiformats/multiaddr": "^12.0.0", - "@noble/secp256k1": "^1.7.1", - "@waku/utils": "0.0.22", - "debug": "^4.3.4", - "js-sha3": "^0.9.2" - }, + "packages/browser-tests/node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=20" - }, - "peerDependencies": { - "@multiformats/multiaddr": "^12.0.0" - }, - "peerDependenciesMeta": { - "@multiformats/multiaddr": { - "optional": true - } + "node": ">=12" } }, - "packages/browser-tests/node_modules/@waku/interfaces": { - "version": "0.0.29", - "license": "MIT OR Apache-2.0", - "dependencies": { - "@waku/proto": "^0.0.9" - }, + "packages/browser-tests/node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=20" + "node": ">=12" } }, - "packages/browser-tests/node_modules/@waku/message-hash": { - "version": "0.1.18", - "license": "MIT OR Apache-2.0", - "dependencies": { - "@noble/hashes": "^1.3.2", - "@waku/utils": "0.0.22" - }, + "packages/browser-tests/node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=20" + "node": ">=12" } }, - "packages/browser-tests/node_modules/@waku/proto": { - "version": "0.0.9", - "license": "MIT OR Apache-2.0", - "dependencies": { - "protons-runtime": "^5.4.0" - }, + "packages/browser-tests/node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=20" + "node": ">=12" } }, - "packages/browser-tests/node_modules/@waku/sdk": { - "version": "0.0.30", - "license": "MIT OR Apache-2.0", - "dependencies": { - "@chainsafe/libp2p-noise": "16.0.0", - "@libp2p/bootstrap": "^11.0.1", - "@libp2p/identify": "^3.0.1", - "@libp2p/mplex": "^11.0.1", - "@libp2p/ping": "2.0.1", - "@libp2p/websockets": "^9.0.1", - "@noble/hashes": "^1.3.3", - "@waku/core": "0.0.34", - "@waku/discovery": "0.0.7", - "@waku/interfaces": "0.0.29", - "@waku/message-hash": "0.1.18", - "@waku/proto": "^0.0.9", - "@waku/utils": "0.0.22", - "libp2p": "2.1.8" - }, + "packages/browser-tests/node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=20" + "node": ">=12" } }, - "packages/browser-tests/node_modules/@waku/utils": { - "version": "0.0.22", - "license": "MIT OR Apache-2.0", - "dependencies": { - "@noble/hashes": "^1.3.2", - "@waku/interfaces": "0.0.29", - "chai": "^4.3.10", - "debug": "^4.3.4", - "uint8arrays": "^5.0.1" - }, + "packages/browser-tests/node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=20" + "node": ">=12" } }, - "packages/browser-tests/node_modules/dotenv": { - "version": "7.0.0", + "packages/browser-tests/node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6" + "node": ">=12" } }, - "packages/browser-tests/node_modules/dotenv-flow": { - "version": "0.4.0", + "packages/browser-tests/node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], "dev": true, "license": "MIT", - "dependencies": { - "dotenv": "^7.0.0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "packages/browser-tests/node_modules/it-byte-stream": { - "version": "1.1.1", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "it-queueless-pushable": "^1.0.0", - "it-stream-types": "^2.0.2", - "uint8arraylist": "^2.4.8" + "packages/browser-tests/node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "packages/browser-tests/node_modules/it-length-prefixed-stream": { - "version": "1.2.1", - "license": "Apache-2.0 OR MIT", + "packages/browser-tests/node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "packages/browser-tests/node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "packages/browser-tests/node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "packages/browser-tests/node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "packages/browser-tests/node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "packages/browser-tests/node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "packages/browser-tests/node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "packages/browser-tests/node_modules/@types/node": { + "version": "20.17.52", + "dev": true, + "license": "MIT", "dependencies": { - "it-byte-stream": "^1.0.0", - "it-stream-types": "^2.0.2", - "uint8-varint": "^2.0.4", - "uint8arraylist": "^2.4.8" + "undici-types": "~6.19.2" } }, - "packages/browser-tests/node_modules/it-queueless-pushable": { - "version": "1.0.2", - "license": "Apache-2.0 OR MIT", + "packages/browser-tests/node_modules/@waku/discovery/node_modules/@waku/interfaces": { + "version": "0.0.26", + "resolved": "https://registry.npmjs.org/@waku/interfaces/-/interfaces-0.0.26.tgz", + "integrity": "sha512-YZU4+1j8n7lEKFTz3RTHaNm4Jsv1kurG87G7ZZZwFRuzHjTVizGldI5Nfu8eUemr8dGIBCgadybXqJY/GjsLcA==", + "extraneous": true, + "license": "MIT OR Apache-2.0", "dependencies": { - "p-defer": "^4.0.1", - "race-signal": "^1.1.3" + "@waku/proto": "^0.0.8" + }, + "engines": { + "node": ">=20" } }, - "packages/browser-tests/node_modules/js-sha3": { - "version": "0.9.3", - "license": "MIT" + "packages/browser-tests/node_modules/dotenv": { + "version": "7.0.0", + "license": "BSD-2-Clause", + "engines": { + "node": ">=6" + } }, - "packages/browser-tests/node_modules/libp2p": { - "version": "2.1.8", - "license": "Apache-2.0 OR MIT", + "packages/browser-tests/node_modules/dotenv-flow": { + "version": "0.4.0", + "license": "MIT", "dependencies": { - "@libp2p/crypto": "^5.0.5", - "@libp2p/interface": "^2.1.3", - "@libp2p/interface-internal": "^2.0.8", - "@libp2p/logger": "^5.1.1", - "@libp2p/multistream-select": "^6.0.6", - "@libp2p/peer-collections": "^6.0.8", - "@libp2p/peer-id": "^5.0.5", - "@libp2p/peer-store": "^11.0.8", - "@libp2p/utils": "^6.1.1", - "@multiformats/dns": "^1.0.6", - "@multiformats/multiaddr": "^12.2.3", - "@multiformats/multiaddr-matcher": "^1.2.1", - "any-signal": "^4.1.1", - "datastore-core": "^10.0.0", - "interface-datastore": "^8.3.0", - "it-byte-stream": "^1.0.12", - "it-merge": "^3.0.5", - "it-parallel": "^3.0.7", - "merge-options": "^3.0.4", - "multiformats": "^13.1.0", - "p-defer": "^4.0.1", - "p-retry": "^6.2.0", - "progress-events": "^1.0.0", - "race-event": "^1.3.0", - "race-signal": "^1.0.2", - "uint8arrays": "^5.1.0" + "dotenv": "^7.0.0" } }, - "packages/browser-tests/node_modules/undici-types": { - "version": "6.19.8", + "packages/browser-tests/node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, - "license": "MIT" - }, - "packages/browser-tests/node_modules/uuid": { - "version": "9.0.1", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], + "hasInstallScript": true, "license": "MIT", "bin": { - "uuid": "dist/bin/uuid" + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" } }, + "packages/browser-tests/node_modules/undici-types": { + "version": "6.19.8", + "dev": true, + "license": "MIT" + }, "packages/build-utils": { "name": "@waku/build-utils", "version": "1.0.0", @@ -36810,6 +34994,7 @@ "packages/headless-tests": { "name": "@waku/headless-tests", "version": "0.1.0", + "extraneous": true, "dependencies": { "@waku/sdk": "^0.0.30" }, @@ -36826,479 +35011,6 @@ "webpack-cli": "^5.1.4" } }, - "packages/headless-tests/node_modules/@chainsafe/as-sha256": { - "version": "0.4.2", - "license": "Apache-2.0" - }, - "packages/headless-tests/node_modules/@chainsafe/libp2p-noise": { - "version": "16.0.0", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/as-chacha20poly1305": "^0.1.0", - "@chainsafe/as-sha256": "^0.4.1", - "@libp2p/crypto": "^5.0.0", - "@libp2p/interface": "^2.0.0", - "@libp2p/peer-id": "^5.0.0", - "@noble/ciphers": "^0.6.0", - "@noble/curves": "^1.1.0", - "@noble/hashes": "^1.3.1", - "it-length-prefixed": "^9.0.1", - "it-length-prefixed-stream": "^1.0.0", - "it-pair": "^2.0.6", - "it-pipe": "^3.0.1", - "it-stream-types": "^2.0.1", - "protons-runtime": "^5.5.0", - "uint8arraylist": "^2.4.3", - "uint8arrays": "^5.0.0", - "wherearewe": "^2.0.1" - } - }, - "packages/headless-tests/node_modules/@discoveryjs/json-ext": { - "version": "0.5.7", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.0" - } - }, - "packages/headless-tests/node_modules/@libp2p/ping": { - "version": "2.0.1", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@libp2p/crypto": "^5.0.1", - "@libp2p/interface": "^2.0.1", - "@libp2p/interface-internal": "^2.0.1", - "@multiformats/multiaddr": "^12.2.3", - "it-first": "^3.0.6", - "it-pipe": "^3.0.1", - "uint8arrays": "^5.1.0" - } - }, - "packages/headless-tests/node_modules/@noble/ciphers": { - "version": "0.6.0", - "license": "MIT", - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "packages/headless-tests/node_modules/@waku/core": { - "version": "0.0.34", - "license": "MIT OR Apache-2.0", - "dependencies": { - "@libp2p/ping": "2.0.1", - "@waku/enr": "^0.0.28", - "@waku/interfaces": "0.0.29", - "@waku/proto": "0.0.9", - "@waku/utils": "0.0.22", - "debug": "^4.3.4", - "it-all": "^3.0.4", - "it-length-prefixed": "^9.0.4", - "it-pipe": "^3.0.1", - "uint8arraylist": "^2.4.3", - "uuid": "^9.0.0" - }, - "engines": { - "node": ">=20" - }, - "peerDependencies": { - "@multiformats/multiaddr": "^12.0.0", - "libp2p": "2.1.8" - }, - "peerDependenciesMeta": { - "@multiformats/multiaddr": { - "optional": true - }, - "libp2p": { - "optional": true - } - } - }, - "packages/headless-tests/node_modules/@waku/discovery": { - "version": "0.0.7", - "license": "MIT OR Apache-2.0", - "dependencies": { - "@waku/core": "0.0.34", - "@waku/enr": "0.0.28", - "@waku/interfaces": "0.0.29", - "@waku/proto": "^0.0.9", - "@waku/utils": "0.0.22", - "debug": "^4.3.4", - "dns-over-http-resolver": "^3.0.8", - "hi-base32": "^0.5.1", - "uint8arrays": "^5.0.1" - }, - "engines": { - "node": ">=20" - } - }, - "packages/headless-tests/node_modules/@waku/enr": { - "version": "0.0.28", - "license": "MIT OR Apache-2.0", - "dependencies": { - "@ethersproject/rlp": "^5.7.0", - "@libp2p/crypto": "^5.0.1", - "@libp2p/peer-id": "^5.0.1", - "@multiformats/multiaddr": "^12.0.0", - "@noble/secp256k1": "^1.7.1", - "@waku/utils": "0.0.22", - "debug": "^4.3.4", - "js-sha3": "^0.9.2" - }, - "engines": { - "node": ">=20" - }, - "peerDependencies": { - "@multiformats/multiaddr": "^12.0.0" - }, - "peerDependenciesMeta": { - "@multiformats/multiaddr": { - "optional": true - } - } - }, - "packages/headless-tests/node_modules/@waku/interfaces": { - "version": "0.0.29", - "license": "MIT OR Apache-2.0", - "dependencies": { - "@waku/proto": "^0.0.9" - }, - "engines": { - "node": ">=20" - } - }, - "packages/headless-tests/node_modules/@waku/message-hash": { - "version": "0.1.18", - "license": "MIT OR Apache-2.0", - "dependencies": { - "@noble/hashes": "^1.3.2", - "@waku/utils": "0.0.22" - }, - "engines": { - "node": ">=20" - } - }, - "packages/headless-tests/node_modules/@waku/proto": { - "version": "0.0.9", - "license": "MIT OR Apache-2.0", - "dependencies": { - "protons-runtime": "^5.4.0" - }, - "engines": { - "node": ">=20" - } - }, - "packages/headless-tests/node_modules/@waku/sdk": { - "version": "0.0.30", - "license": "MIT OR Apache-2.0", - "dependencies": { - "@chainsafe/libp2p-noise": "16.0.0", - "@libp2p/bootstrap": "^11.0.1", - "@libp2p/identify": "^3.0.1", - "@libp2p/mplex": "^11.0.1", - "@libp2p/ping": "2.0.1", - "@libp2p/websockets": "^9.0.1", - "@noble/hashes": "^1.3.3", - "@waku/core": "0.0.34", - "@waku/discovery": "0.0.7", - "@waku/interfaces": "0.0.29", - "@waku/message-hash": "0.1.18", - "@waku/proto": "^0.0.9", - "@waku/utils": "0.0.22", - "libp2p": "2.1.8" - }, - "engines": { - "node": ">=20" - } - }, - "packages/headless-tests/node_modules/@waku/utils": { - "version": "0.0.22", - "license": "MIT OR Apache-2.0", - "dependencies": { - "@noble/hashes": "^1.3.2", - "@waku/interfaces": "0.0.29", - "chai": "^4.3.10", - "debug": "^4.3.4", - "uint8arrays": "^5.0.1" - }, - "engines": { - "node": ">=20" - } - }, - "packages/headless-tests/node_modules/@webpack-cli/configtest": { - "version": "2.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.15.0" - }, - "peerDependencies": { - "webpack": "5.x.x", - "webpack-cli": "5.x.x" - } - }, - "packages/headless-tests/node_modules/@webpack-cli/info": { - "version": "2.0.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.15.0" - }, - "peerDependencies": { - "webpack": "5.x.x", - "webpack-cli": "5.x.x" - } - }, - "packages/headless-tests/node_modules/@webpack-cli/serve": { - "version": "2.0.5", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.15.0" - }, - "peerDependencies": { - "webpack": "5.x.x", - "webpack-cli": "5.x.x" - }, - "peerDependenciesMeta": { - "webpack-dev-server": { - "optional": true - } - } - }, - "packages/headless-tests/node_modules/buffer": { - "version": "6.0.3", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "packages/headless-tests/node_modules/commander": { - "version": "10.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - } - }, - "packages/headless-tests/node_modules/it-byte-stream": { - "version": "1.1.1", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "it-queueless-pushable": "^1.0.0", - "it-stream-types": "^2.0.2", - "uint8arraylist": "^2.4.8" - } - }, - "packages/headless-tests/node_modules/it-length-prefixed-stream": { - "version": "1.2.1", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "it-byte-stream": "^1.0.0", - "it-stream-types": "^2.0.2", - "uint8-varint": "^2.0.4", - "uint8arraylist": "^2.4.8" - } - }, - "packages/headless-tests/node_modules/it-queueless-pushable": { - "version": "1.0.2", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "p-defer": "^4.0.1", - "race-signal": "^1.1.3" - } - }, - "packages/headless-tests/node_modules/js-sha3": { - "version": "0.9.3", - "license": "MIT" - }, - "packages/headless-tests/node_modules/libp2p": { - "version": "2.1.8", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@libp2p/crypto": "^5.0.5", - "@libp2p/interface": "^2.1.3", - "@libp2p/interface-internal": "^2.0.8", - "@libp2p/logger": "^5.1.1", - "@libp2p/multistream-select": "^6.0.6", - "@libp2p/peer-collections": "^6.0.8", - "@libp2p/peer-id": "^5.0.5", - "@libp2p/peer-store": "^11.0.8", - "@libp2p/utils": "^6.1.1", - "@multiformats/dns": "^1.0.6", - "@multiformats/multiaddr": "^12.2.3", - "@multiformats/multiaddr-matcher": "^1.2.1", - "any-signal": "^4.1.1", - "datastore-core": "^10.0.0", - "interface-datastore": "^8.3.0", - "it-byte-stream": "^1.0.12", - "it-merge": "^3.0.5", - "it-parallel": "^3.0.7", - "merge-options": "^3.0.4", - "multiformats": "^13.1.0", - "p-defer": "^4.0.1", - "p-retry": "^6.2.0", - "progress-events": "^1.0.0", - "race-event": "^1.3.0", - "race-signal": "^1.0.2", - "uint8arrays": "^5.1.0" - } - }, - "packages/headless-tests/node_modules/node-polyfill-webpack-plugin": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "assert": "^2.0.0", - "browserify-zlib": "^0.2.0", - "buffer": "^6.0.3", - "console-browserify": "^1.2.0", - "constants-browserify": "^1.0.0", - "crypto-browserify": "^3.12.0", - "domain-browser": "^4.22.0", - "events": "^3.3.0", - "filter-obj": "^2.0.2", - "https-browserify": "^1.0.0", - "os-browserify": "^0.3.0", - "path-browserify": "^1.0.1", - "process": "^0.11.10", - "punycode": "^2.1.1", - "querystring-es3": "^0.2.1", - "readable-stream": "^4.0.0", - "stream-browserify": "^3.0.0", - "stream-http": "^3.2.0", - "string_decoder": "^1.3.0", - "timers-browserify": "^2.0.12", - "tty-browserify": "^0.0.1", - "type-fest": "^2.14.0", - "url": "^0.11.0", - "util": "^0.12.4", - "vm-browserify": "^1.1.2" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "webpack": ">=5" - } - }, - "packages/headless-tests/node_modules/punycode": { - "version": "2.3.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "packages/headless-tests/node_modules/readable-stream": { - "version": "4.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "abort-controller": "^3.0.0", - "buffer": "^6.0.3", - "events": "^3.3.0", - "process": "^0.11.10", - "string_decoder": "^1.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "packages/headless-tests/node_modules/type-fest": { - "version": "2.19.0", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "packages/headless-tests/node_modules/uuid": { - "version": "9.0.1", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "packages/headless-tests/node_modules/webpack-cli": { - "version": "5.1.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^2.1.1", - "@webpack-cli/info": "^2.0.2", - "@webpack-cli/serve": "^2.0.5", - "colorette": "^2.0.14", - "commander": "^10.0.1", - "cross-spawn": "^7.0.3", - "envinfo": "^7.7.3", - "fastest-levenshtein": "^1.0.12", - "import-local": "^3.0.2", - "interpret": "^3.1.1", - "rechoir": "^0.8.0", - "webpack-merge": "^5.7.3" - }, - "bin": { - "webpack-cli": "bin/cli.js" - }, - "engines": { - "node": ">=14.15.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "5.x.x" - }, - "peerDependenciesMeta": { - "@webpack-cli/generators": { - "optional": true - }, - "webpack-bundle-analyzer": { - "optional": true - }, - "webpack-dev-server": { - "optional": true - } - } - }, - "packages/headless-tests/node_modules/webpack-merge": { - "version": "5.10.0", - "dev": true, - "license": "MIT", - "dependencies": { - "clone-deep": "^4.0.1", - "flat": "^5.0.2", - "wildcard": "^2.0.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, "packages/interfaces": { "name": "@waku/interfaces", "version": "0.0.33", diff --git a/package.json b/package.json index 53baf7ee6b..a3100863f7 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,6 @@ "packages/rln", "packages/tests", "packages/reliability-tests", - "packages/headless-tests", "packages/browser-tests", "packages/build-utils" ], diff --git a/packages/browser-tests/.dockerignore b/packages/browser-tests/.dockerignore index 5da2ccb7c4..ddabfcd06a 100644 --- a/packages/browser-tests/.dockerignore +++ b/packages/browser-tests/.dockerignore @@ -1,5 +1,4 @@ node_modules -dist build .DS_Store *.log diff --git a/packages/browser-tests/.eslintrc.cjs b/packages/browser-tests/.eslintrc.cjs index 2e2c5c6384..5591af2222 100644 --- a/packages/browser-tests/.eslintrc.cjs +++ b/packages/browser-tests/.eslintrc.cjs @@ -12,7 +12,8 @@ module.exports = { plugins: ["import"], extends: ["eslint:recommended"], rules: { - "no-console": "off" + "no-console": "off", + "no-unused-vars": ["error", { "argsIgnorePattern": "^_", "ignoreRestSiblings": true }] }, globals: { process: true diff --git a/packages/browser-tests/Dockerfile b/packages/browser-tests/Dockerfile new file mode 100644 index 0000000000..76dfc9a741 --- /dev/null +++ b/packages/browser-tests/Dockerfile @@ -0,0 +1,72 @@ +# syntax=docker/dockerfile:1 + +# Build stage - install all dependencies and build +FROM node:22-bullseye AS builder + +WORKDIR /app + +# Copy package.json and temporarily remove workspace dependencies that can't be resolved +COPY package.json package.json.orig +RUN sed '/"@waku\/tests": "\*",/d' package.json.orig > package.json +RUN npm install --no-audit --no-fund + +COPY src ./src +COPY types ./types +COPY tsconfig.json ./ +COPY web ./web + +RUN npm run build + +# Production stage - only runtime dependencies +FROM node:22-bullseye + +# Install required system deps for Playwright Chromium +RUN apt-get update && apt-get install -y \ + wget \ + gnupg \ + ca-certificates \ + fonts-liberation \ + libatk-bridge2.0-0 \ + libatk1.0-0 \ + libatspi2.0-0 \ + libcups2 \ + libdbus-1-3 \ + libdrm2 \ + libgtk-3-0 \ + libnspr4 \ + libnss3 \ + libx11-xcb1 \ + libxcomposite1 \ + libxdamage1 \ + libxfixes3 \ + libxkbcommon0 \ + libxrandr2 \ + xdg-utils \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /app + +# Copy package files and install only production dependencies +COPY package.json package.json.orig +RUN sed '/"@waku\/tests": "\*",/d' package.json.orig > package.json +RUN npm install --only=production --no-audit --no-fund + +# Copy built application from builder stage +COPY --from=builder /app/dist ./dist + +# Install Playwright browsers (Chromium only) at runtime layer +RUN npx playwright install --with-deps chromium + +ENV PORT=8080 \ + NODE_ENV=production + +EXPOSE 8080 + +# Use a script to handle CLI arguments and environment variables +COPY scripts/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh +RUN chmod +x /usr/local/bin/docker-entrypoint.sh + +ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] +CMD ["npm", "run", "start:server"] + + diff --git a/packages/browser-tests/README.md b/packages/browser-tests/README.md index d3ca0a5908..9b75f3ca8d 100644 --- a/packages/browser-tests/README.md +++ b/packages/browser-tests/README.md @@ -1,182 +1,174 @@ # Waku Browser Tests -This project provides a system for testing the Waku SDK in a browser environment. +This package provides a containerized Waku light node simulation server for testing and development. The server runs a headless browser using Playwright and exposes a REST API similar to the nwaku REST API. A Dockerfile is provided to allow programmatic simulation and "deployment" of js-waku nodes in any Waku orchestration environment that uses Docker (e.g. [10ksim](https://github.com/vacp2p/10ksim) ). -## Architecture +## Quick Start -The system consists of: +### Build and Run -1. **Headless Web App**: A simple web application (in the `@waku/headless-tests` package) that loads the Waku SDK and exposes shared API functions. -2. **Express Server**: A server that communicates with the headless app using Playwright. -3. **Shared API**: TypeScript functions shared between the server and web app. +```bash +# Build the application +npm run build -## Setup +# Start the server (port 8080) +npm run start:server -1. Install dependencies: +# Build and run Docker container +npm run docker:build +docker run -p 8080:8080 waku-browser-tests:local +``` -```bash -# Install main dependencies -npm install +## Configuration -# Install headless app dependencies -cd ../headless-tests -npm install -cd ../browser-tests -``` +Configure the Waku node using environment variables: -2. Build the application: +### Network Configuration +- `WAKU_CLUSTER_ID`: Cluster ID (default: 1) +- `WAKU_SHARD`: Specific shard number - enables static sharding mode (optional) -```bash -npm run build -``` +**Sharding Behavior:** +- **Auto-sharding** (default): Uses `numShardsInCluster: 8` across cluster 1 +- **Static sharding**: When `WAKU_SHARD` is set, uses only that specific shard -This will: -- Build the headless web app using webpack -- Compile the TypeScript server code +### Bootstrap Configuration +- `WAKU_ENR_BOOTSTRAP`: Enable ENR bootstrap mode with custom bootstrap peers (comma-separated) +- `WAKU_LIGHTPUSH_NODE`: Preferred lightpush node multiaddr (Docker only) -## Running +### ENR Bootstrap Mode -Start the server with: +When `WAKU_ENR_BOOTSTRAP` is set: +- Disables default bootstrap (`defaultBootstrap: false`) +- Enables DNS discovery using production ENR trees +- Enables peer exchange and peer cache +- Uses the specified ENR for additional bootstrap peers ```bash -npm run start:server +# Example: ENR bootstrap mode +WAKU_ENR_BOOTSTRAP="enr:-QEnuEBEAyErHEfhiQxAVQoWowGTCuEF9fKZtXSd7H_PymHFhGJA3rGAYDVSHKCyJDGRLBGsloNbS8AZF33IVuefjOO6BIJpZIJ2NIJpcIQS39tkim11bHRpYWRkcnO4lgAvNihub2RlLTAxLmRvLWFtczMud2FrdXYyLnRlc3Quc3RhdHVzaW0ubmV0BgG73gMAODcxbm9kZS0wMS5hYy1jbi1ob25na29uZy1jLndha3V2Mi50ZXN0LnN0YXR1c2ltLm5ldAYBu94DACm9A62t7AQL4Ef5ZYZosRpQTzFVAB8jGjf1TER2wH-0zBOe1-MDBNLeA4lzZWNwMjU2azGhAzfsxbxyCkgCqq8WwYsVWH7YkpMLnU2Bw5xJSimxKav-g3VkcIIjKA" npm run start:server ``` -This will: -1. Serve the headless app on port 8080 -2. Start a headless browser to load the app -3. Expose API endpoints to interact with Waku - ## API Endpoints -- `GET /info`: Get information about the Waku node -- `GET /debug/v1/info`: Get debug information from the Waku node -- `POST /push`: Push a message to the Waku network (legacy) -- `POST /lightpush/v1/message`: Push a message to the Waku network (Waku REST API compatible) -- `POST /admin/v1/create-node`: Create a new Waku node (requires networkConfig) -- `POST /admin/v1/start-node`: Start the Waku node -- `POST /admin/v1/stop-node`: Stop the Waku node -- `POST /admin/v1/peers`: Dial to specified peers (Waku REST API compatible) -- `GET /filter/v2/messages/:contentTopic`: Subscribe to messages on a specific content topic using Server-Sent Events (Waku REST API compatible) -- `GET /filter/v1/messages/:contentTopic`: Retrieve stored messages from a content topic (Waku REST API compatible) +The server exposes the following HTTP endpoints: -### Example: Pushing a message with the legacy endpoint +### Node Management +- `GET /`: Health check - returns server status +- `GET /waku/v1/peer-info`: Get node peer information +- `POST /waku/v1/wait-for-peers`: Wait for peers with specific protocols -```bash -curl -X POST http://localhost:3000/push \ - -H "Content-Type: application/json" \ - -d '{"contentTopic": "/toy-chat/2/huilong/proto", "payload": [1, 2, 3]}' -``` +### Messaging +- `POST /lightpush/v3/message`: Send message via lightpush -### Example: Pushing a message with the Waku REST API compatible endpoint +### Static Files +- `GET /app/index.html`: Web application entry point +- `GET /app/*`: Static web application files +### Examples + +#### Send a Message (Auto-sharding) ```bash -curl -X POST http://localhost:3000/lightpush/v1/message \ +curl -X POST http://localhost:8080/lightpush/v3/message \ -H "Content-Type: application/json" \ -d '{ - "pubsubTopic": "/waku/2/rs/0/0", + "pubsubTopic": "", "message": { - "payload": "SGVsbG8sIFdha3Uh", - "contentTopic": "/toy-chat/2/huilong/proto", - "timestamp": 1712135330213797632 + "contentTopic": "/test/1/example/proto", + "payload": "SGVsbG8gV2FrdQ==", + "version": 1 } }' ``` -### Example: Executing a function - +#### Send a Message (Explicit pubsub topic) ```bash -curl -X POST http://localhost:3000/execute \ - -H "Content-Type: application/json" \ - -d '{"functionName": "getPeerInfo", "params": []}' -``` - -### Example: Creating a Waku node - -```bash -curl -X POST http://localhost:3000/admin/v1/create-node \ +curl -X POST http://localhost:8080/lightpush/v3/message \ -H "Content-Type: application/json" \ -d '{ - "defaultBootstrap": true, - "networkConfig": { - "clusterId": 1, - "shards": [0, 1] + "pubsubTopic": "/waku/2/rs/1/4", + "message": { + "contentTopic": "/test/1/example/proto", + "payload": "SGVsbG8gV2FrdQ==", + "version": 1 } }' ``` -### Example: Starting and stopping a Waku node - -```bash -# Start the node -curl -X POST http://localhost:3000/admin/v1/start-node - -# Stop the node -curl -X POST http://localhost:3000/admin/v1/stop-node -``` - -### Example: Dialing to specific peers with the Waku REST API compatible endpoint - +#### Wait for Peers ```bash -curl -X POST http://localhost:3000/admin/v1/peers \ +curl -X POST http://localhost:8080/waku/v1/wait-for-peers \ -H "Content-Type: application/json" \ -d '{ - "peerMultiaddrs": [ - "/ip4/127.0.0.1/tcp/8000/p2p/16Uiu2HAm4v8KuHUH6Cwz3upPeQbkyxQJsFGPdt7kHtkN8F79QiE6"] - ] + "timeoutMs": 30000, + "protocols": ["lightpush", "filter"] }' ``` -### Example: Dialing to specific peers with the execute endpoint - +#### Get Peer Info ```bash -curl -X POST http://localhost:3000/execute \ - -H "Content-Type: application/json" \ - -d '{ - "functionName": "dialPeers", - "params": [ - ["/ip4/127.0.0.1/tcp/8000/p2p/16Uiu2HAm4v8KuHUH6Cwz3upPeQbkyxQJsFGPdt7kHtkN8F79QiE6"] - ] - }' +curl -X GET http://localhost:8080/waku/v1/peer-info ``` -### Example: Subscribing to a content topic with the filter endpoint +## CLI Usage -```bash -# Open a persistent connection to receive messages as Server-Sent Events -curl -N http://localhost:3000/filter/v2/messages/%2Ftoy-chat%2F2%2Fhuilong%2Fproto +Run with CLI arguments: -# You can also specify clustering options -curl -N "http://localhost:3000/filter/v2/messages/%2Ftoy-chat%2F2%2Fhuilong%2Fproto?clusterId=0&shard=0" +```bash +# Custom cluster and shard +node dist/src/server.js --cluster-id=2 --shard=0 ``` -### Example: Retrieving stored messages from a content topic +## Testing + +The package includes several test suites: ```bash -# Get the most recent 20 messages -curl http://localhost:3000/filter/v1/messages/%2Ftoy-chat%2F2%2Fhuilong%2Fproto +# Basic server functionality tests (default) +npm test -# Get messages with pagination and time filtering -curl "http://localhost:3000/filter/v1/messages/%2Ftoy-chat%2F2%2Fhuilong%2Fproto?pageSize=10&startTime=1712000000000&endTime=1713000000000&ascending=true" -``` +# Docker testing workflow +npm run docker:build +npm run test:integration -## Extending +# All tests +npm run test:all -To add new functionality: +# Individual test suites: +npm run test:server # Server-only tests +npm run test:e2e # End-to-end tests +``` + +**Test Types:** +- `server.spec.ts` - Tests basic server functionality and static file serving +- `integration.spec.ts` - Tests Docker container integration with external services +- `e2e.spec.ts` - Full end-to-end tests using nwaku nodes -1. Add your function to `src/api/shared.ts` -2. Add your function to the `API` object in `src/api/shared.ts` -3. Use it via the server endpoints +## Docker Usage -### Example: Dialing to specific peers +The package includes Docker support for containerized testing: ```bash -curl -X POST http://localhost:3000/execute \ - -H "Content-Type: application/json" \ - -d '{ - "functionName": "dialPeers", - "params": [ - ["/ip4/127.0.0.1/tcp/8000/p2p/16Uiu2HAm4v8KuHUH6Cwz3upPeQbkyxQJsFGPdt7kHtkN8F79QiE6"] - ] - }' +# Build image +docker build -t waku-browser-tests:local . + +# Run with ENR bootstrap +docker run -p 8080:8080 \ + -e WAKU_ENR_BOOTSTRAP="enr:-QEnuE..." \ + -e WAKU_CLUSTER_ID="1" \ + waku-browser-tests:local + +# Run with specific configuration +docker run -p 8080:8080 \ + -e WAKU_CLUSTER_ID="2" \ + -e WAKU_SHARD="0" \ + waku-browser-tests:local ``` + +## Development + +The server automatically: +- Creates a Waku light node on startup +- Configures network settings from environment variables +- Enables appropriate protocols (lightpush, filter) +- Handles peer discovery and connection management + +All endpoints are CORS-enabled for cross-origin requests. diff --git a/packages/browser-tests/package.json b/packages/browser-tests/package.json index 6cb3cdc230..b573b3ac82 100644 --- a/packages/browser-tests/package.json +++ b/packages/browser-tests/package.json @@ -5,27 +5,37 @@ "type": "module", "scripts": { "start": "npm run start:server", - "start:server": "node ./dist/server.js", - "test": "npx playwright test", + "start:server": "PORT=8080 node ./dist/src/server.js", + "test": "npx playwright test tests/server.spec.ts --reporter=line", + "test:all": "npx playwright test --reporter=line", + "test:server": "npx playwright test tests/server.spec.ts --reporter=line", + "test:integration": "npx playwright test tests/integration.spec.ts --reporter=line", + "test:e2e": "npx playwright test tests/e2e.spec.ts --reporter=line", "build:server": "tsc -p tsconfig.json", - "build": "npm run build:server" + "build:web": "esbuild web/index.ts --bundle --format=esm --platform=browser --outdir=dist/web && cp web/index.html dist/web/index.html", + "build": "npm-run-all -s build:server build:web", + "docker:build": "docker build -t waku-browser-tests:local ." + }, + "dependencies": { + "@playwright/test": "^1.51.1", + "@waku/discovery": "^0.0.11", + "@waku/interfaces": "^0.0.33", + "@waku/sdk": "^0.0.34", + "cors": "^2.8.5", + "dotenv-flow": "^0.4.0", + "express": "^4.21.2", + "filter-obj": "^2.0.2", + "it-first": "^3.0.9" }, "devDependencies": { "@types/cors": "^2.8.15", "@types/express": "^4.17.21", "@types/node": "^20.10.0", + "@waku/tests": "*", "axios": "^1.8.4", - "dotenv-flow": "^0.4.0", + "esbuild": "^0.21.5", "npm-run-all": "^4.1.5", - "serve": "^14.2.3", - "typescript": "5.8.3", - "webpack-cli": "^6.0.1" - }, - "dependencies": { - "@playwright/test": "^1.51.1", - "@waku/sdk": "^0.0.30", - "cors": "^2.8.5", - "express": "^4.21.2", - "node-polyfill-webpack-plugin": "^4.1.0" + "testcontainers": "^10.9.0", + "typescript": "5.8.3" } } diff --git a/packages/browser-tests/playwright.config.ts b/packages/browser-tests/playwright.config.ts index 2c90278bf2..345d96bc4c 100644 --- a/packages/browser-tests/playwright.config.ts +++ b/packages/browser-tests/playwright.config.ts @@ -1,57 +1,36 @@ -// For dynamic import of dotenv-flow import { defineConfig, devices } from "@playwright/test"; -// Only load dotenv-flow in non-CI environments if (!process.env.CI) { - // Need to use .js extension for ES modules - // eslint-disable-next-line import/extensions - await import("dotenv-flow/config.js"); + try { + await import("dotenv-flow/config.js"); + } catch (e) { + console.warn("dotenv-flow not found; skipping env loading"); + } } const EXAMPLE_PORT = process.env.EXAMPLE_PORT || "8080"; -// web-chat specific thingy -const EXAMPLE_TEMPLATE = process.env.EXAMPLE_TEMPLATE || ""; -const BASE_URL = `http://127.0.0.1:${EXAMPLE_PORT}/${EXAMPLE_TEMPLATE}`; +const BASE_URL = `http://127.0.0.1:${EXAMPLE_PORT}`; +const TEST_IGNORE = process.env.CI ? ["tests/docker-*.spec.ts"] : []; -/** - * See https://playwright.dev/docs/test-configuration. - */ export default defineConfig({ testDir: "./tests", - /* Run tests in files in parallel */ + testIgnore: TEST_IGNORE, fullyParallel: true, - /* Fail the build on CI if you accidentally left test.only in the source code. */ forbidOnly: !!process.env.CI, - /* Retry on CI only */ retries: process.env.CI ? 2 : 0, - /* Opt out of parallel tests on CI. */ workers: process.env.CI ? 2 : undefined, - /* Reporter to use. See https://playwright.dev/docs/test-reporters */ reporter: "html", - /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { - /* Base URL to use in actions like `await page.goto('/')`. */ baseURL: BASE_URL, - /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ trace: "on-first-retry" }, - /* Configure projects for major browsers */ projects: [ { name: "chromium", use: { ...devices["Desktop Chrome"] } } - ], + ] - /* Run your local dev server before starting the tests */ - webServer: { - url: BASE_URL, - stdout: "pipe", - stderr: "pipe", - command: "npm run start:server", - reuseExistingServer: !process.env.CI, - timeout: 5 * 60 * 1000 // five minutes for bootstrapping an example - } }); diff --git a/packages/browser-tests/scripts/docker-entrypoint.sh b/packages/browser-tests/scripts/docker-entrypoint.sh new file mode 100644 index 0000000000..b8f72be9d7 --- /dev/null +++ b/packages/browser-tests/scripts/docker-entrypoint.sh @@ -0,0 +1,64 @@ +#!/bin/bash + +# Docker entrypoint script for waku-browser-tests +# Handles CLI arguments and converts them to environment variables +# Supports reading discovered addresses from /etc/addrs/addrs.env (10k sim pattern) +echo "docker-entrypoint.sh" +echo "Using address: $addrs1" +export WAKU_LIGHTPUSH_NODE="$addrs1" +echo "Num Args: $#" +echo "Args: $@" + + +# Check if address file exists and source it +# if [ -f "/etc/addrs/addrs.env" ]; then +# echo "Sourcing discovered addresses from /etc/addrs/addrs.env" +# source /etc/addrs/addrs.env +# if [ -n "$addrs1" ]; then +# export WAKU_LIGHTPUSH_NODE="$addrs1" +# echo "Using discovered lightpush node: $WAKU_LIGHTPUSH_NODE" +# else +# echo "addrs1 already set. Using $addrs1" +# fi +# fi + +echo "WAKU_LIGHTPUSH_NODE=$addrs1" + +# Parse command line arguments +while [[ $# -gt 0 ]]; do + case $1 in + --cluster-id=*) + export WAKU_CLUSTER_ID="${1#*=}" + echo "Setting WAKU_CLUSTER_ID=${WAKU_CLUSTER_ID}" + shift + ;; + --shard=*) + export WAKU_SHARD="${1#*=}" + echo "Setting WAKU_SHARD=${WAKU_SHARD}" + shift + ;; + --lightpushnode=*) + export WAKU_LIGHTPUSH_NODE="${1#*=}" + echo "Setting WAKU_LIGHTPUSH_NODE=${WAKU_LIGHTPUSH_NODE}" + shift + ;; + --enr-bootstrap=*) + export WAKU_ENR_BOOTSTRAP="${1#*=}" + echo "Setting WAKU_ENR_BOOTSTRAP=${WAKU_ENR_BOOTSTRAP}" + shift + ;; + *) + # Unknown argument, notify user and keep it for the main command + echo "Warning: Unknown argument '$1' will be passed to the main command" + break + ;; + esac +done + +# If no specific command is provided, use the default CMD +if [ $# -eq 0 ]; then + set -- "npm" "run" "start:server" +fi + +# Execute the main command +exec "$@" diff --git a/packages/browser-tests/src/api/common.d.ts b/packages/browser-tests/src/api/common.d.ts deleted file mode 100644 index 292d30430c..0000000000 --- a/packages/browser-tests/src/api/common.d.ts +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Shared utilities for working with Waku nodes - * This file contains functions used by both browser tests and server - */ - -/** - * Type definition for a minimal Waku node interface - * This allows us to use the same code in different contexts - */ -export interface IWakuNode { - libp2p: { - peerId: { toString(): string }; - getMultiaddrs(): Array<{ toString(): string }>; - getProtocols(): any; - peerStore: { - all(): Promise>; - }; - }; - lightPush: { - send: (encoder: any, message: { payload: Uint8Array }) => Promise<{ successes: any[] }>; - }; -} diff --git a/packages/browser-tests/src/api/debug.ts b/packages/browser-tests/src/api/debug.ts deleted file mode 100644 index 1d4bf4a143..0000000000 --- a/packages/browser-tests/src/api/debug.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { IWakuNode } from "./common.js"; - -/** - * Gets peer information from a Waku node - * Used in both server API endpoints and headless tests - */ -export async function getPeerInfo(waku: IWakuNode): Promise<{ - peerId: string; - multiaddrs: string[]; - peers: string[]; -}> { - const multiaddrs = waku.libp2p.getMultiaddrs(); - const peers = await waku.libp2p.peerStore.all(); - - return { - peerId: waku.libp2p.peerId.toString(), - multiaddrs: multiaddrs.map((addr) => addr.toString()), - peers: peers.map((peer) => peer.id.toString()) - }; -} - -/** - * Gets debug information from a Waku node - * Used in both server API endpoints and tests - */ -export async function getDebugInfo(waku: IWakuNode): Promise<{ - listenAddresses: string[]; - peerId: string; - protocols: string[]; -}> { - return { - listenAddresses: waku.libp2p.getMultiaddrs().map((addr) => addr.toString()), - peerId: waku.libp2p.peerId.toString(), - protocols: Array.from(waku.libp2p.getProtocols()) - }; -} diff --git a/packages/browser-tests/src/api/push.ts b/packages/browser-tests/src/api/push.ts deleted file mode 100644 index 298a3ece8d..0000000000 --- a/packages/browser-tests/src/api/push.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { createEncoder, LightNode, SDKProtocolResult } from "@waku/sdk"; - -export async function pushMessage( - waku: LightNode, - contentTopic: string, - payload?: Uint8Array -): Promise { - const enc = createEncoder({ - contentTopic - }); - - const result = await waku.lightPush.send(enc, { - payload: payload ?? new Uint8Array() - }); - return result; -} diff --git a/packages/browser-tests/src/api/shared.ts b/packages/browser-tests/src/api/shared.ts deleted file mode 100644 index 1eb7950155..0000000000 --- a/packages/browser-tests/src/api/shared.ts +++ /dev/null @@ -1,274 +0,0 @@ -import { - createDecoder, - createEncoder, - createLightNode, - CreateNodeOptions, - DecodedMessage, - LightNode, - SDKProtocolResult, - SubscribeResult -} from "@waku/sdk"; - -import { IWakuNode } from "./common.js"; - -/** - * Gets peer information from a Waku node - */ -export async function getPeerInfo(waku: IWakuNode): Promise<{ - peerId: string; - multiaddrs: string[]; - peers: string[]; -}> { - const multiaddrs = waku.libp2p.getMultiaddrs(); - const peers = await waku.libp2p.peerStore.all(); - - return { - peerId: waku.libp2p.peerId.toString(), - multiaddrs: multiaddrs.map((addr) => addr.toString()), - peers: peers.map((peer) => peer.id.toString()) - }; -} - -/** - * Gets debug information from a Waku node - */ -export async function getDebugInfo(waku: IWakuNode): Promise<{ - listenAddresses: string[]; - peerId: string; - protocols: string[]; -}> { - return { - listenAddresses: waku.libp2p.getMultiaddrs().map((addr) => addr.toString()), - peerId: waku.libp2p.peerId.toString(), - protocols: Array.from(waku.libp2p.getProtocols()) - }; -} - -/** - * Pushes a message to the network - */ -export async function pushMessage( - waku: LightNode, - contentTopic: string, - payload?: Uint8Array, - options?: { - clusterId?: number; - shard?: number; - } -): Promise { - if (!waku) { - throw new Error("Waku node not found"); - } - - const encoder = createEncoder({ - contentTopic, - pubsubTopicShardInfo: { - clusterId: options?.clusterId ?? 1, - shard: options?.shard ?? 1 - } - }); - - const result = await waku.lightPush.send(encoder, { - payload: payload ?? new Uint8Array() - }); - return result; -} - -/** - * Creates and initializes a Waku node - * Checks if a node is already running in window and stops it if it exists - */ -export async function createWakuNode( - options: CreateNodeOptions -): Promise<{ success: boolean; error?: string }> { - // Check if we're in a browser environment and a node already exists - if (typeof window === "undefined") { - return { success: false, error: "No window found" }; - } - - try { - if ((window as any).waku) { - await (window as any).waku.stop(); - } - (window as any).waku = await createLightNode(options); - return { success: true }; - } catch (error: any) { - return { success: false, error: error.message }; - } -} - -export async function startNode(): Promise<{ - success: boolean; - error?: string; -}> { - if (typeof window !== "undefined" && (window as any).waku) { - try { - await (window as any).waku.start(); - return { success: true }; - } catch (error: any) { - // Silently continue if there's an error starting the node - return { success: false, error: error.message }; - } - } - return { success: false, error: "Waku node not found in window" }; -} - -export async function stopNode(): Promise<{ - success: boolean; - error?: string; -}> { - if (typeof window !== "undefined" && (window as any).waku) { - await (window as any).waku.stop(); - return { success: true }; - } - return { success: false, error: "Waku node not found in window" }; -} - -export async function dialPeers( - waku: LightNode, - peers: string[] -): Promise<{ - total: number; - errors: string[]; -}> { - const total = peers.length; - const errors: string[] = []; - - await Promise.allSettled( - peers.map((peer) => - waku.dial(peer).catch((error: any) => { - errors.push(error.message); - }) - ) - ); - - return { total, errors }; -} - -export async function subscribe( - waku: LightNode, - contentTopic: string, - options?: { - clusterId?: number; - shard?: number; - }, - // eslint-disable-next-line no-unused-vars - callback?: (message: DecodedMessage) => void -): Promise { - const clusterId = options?.clusterId ?? 42; - const shard = options?.shard ?? 0; - - console.log( - `Creating decoder for content topic ${contentTopic} with clusterId=${clusterId}, shard=${shard}` - ); - - const pubsubTopic = `/waku/2/rs/${clusterId}/${shard}`; - - let configuredTopics: string[] = []; - - try { - const protocols = waku.libp2p.getProtocols(); - console.log(`Available protocols: ${Array.from(protocols).join(", ")}`); - - const metadataMethod = (waku.libp2p as any)._services?.metadata?.getInfo; - if (metadataMethod) { - const metadata = metadataMethod(); - console.log(`Node metadata: ${JSON.stringify(metadata)}`); - - if (metadata?.pubsubTopics && Array.isArray(metadata.pubsubTopics)) { - configuredTopics = metadata.pubsubTopics; - console.log( - `Found configured pubsub topics: ${configuredTopics.join(", ")}` - ); - } - } - - if ( - configuredTopics.length > 0 && - !configuredTopics.includes(pubsubTopic) - ) { - console.warn( - `Pubsub topic ${pubsubTopic} is not configured. Configured topics: ${configuredTopics.join(", ")}` - ); - - for (const topic of configuredTopics) { - const parts = topic.split("/"); - if (parts.length === 6 && parts[1] === "waku" && parts[3] === "rs") { - console.log(`Found potential matching pubsub topic: ${topic}`); - - // Use the first topic as a fallback if no exact match is found - // This isn't ideal but allows tests to continue - const topicClusterId = parseInt(parts[4]); - const topicShard = parseInt(parts[5]); - - if (!isNaN(topicClusterId) && !isNaN(topicShard)) { - console.log( - `Using pubsub topic with clusterId=${topicClusterId}, shard=${topicShard} instead` - ); - - const decoder = createDecoder(contentTopic, { - clusterId: topicClusterId, - shard: topicShard - }); - - try { - const subscription = await waku.filter.subscribe( - decoder, - callback ?? - ((_message) => { - console.log(_message); - }) - ); - return subscription; - } catch (innerErr: any) { - console.error( - `Error with alternative pubsub topic: ${innerErr.message}` - ); - } - } - } - } - } - } catch (err) { - console.error(`Error checking node protocols: ${String(err)}`); - } - - const decoder = createDecoder(contentTopic, { - clusterId, - shard - }); - - try { - const subscription = await waku.filter.subscribe( - decoder, - callback ?? - ((_message) => { - console.log(_message); - }) - ); - return subscription; - } catch (err: any) { - if (err.message && err.message.includes("Pubsub topic")) { - console.error(`Pubsub topic error: ${err.message}`); - console.log("Subscription failed, but continuing with empty result"); - - return { - unsubscribe: async () => { - console.log("No-op unsubscribe from failed subscription"); - } - } as unknown as SubscribeResult; - } - throw err; - } -} - -export const API = { - getPeerInfo, - getDebugInfo, - pushMessage, - createWakuNode, - startNode, - stopNode, - dialPeers, - subscribe -}; diff --git a/packages/browser-tests/src/browser/index.ts b/packages/browser-tests/src/browser/index.ts index c073c84bc5..6dd537db0f 100644 --- a/packages/browser-tests/src/browser/index.ts +++ b/packages/browser-tests/src/browser/index.ts @@ -1,43 +1,60 @@ import { Browser, chromium, Page } from "@playwright/test"; -// Global variable to store the browser and page let browser: Browser | undefined; let page: Page | undefined; -/** - * Initialize browser and load headless page - */ -export async function initBrowser(): Promise { - browser = await chromium.launch({ - headless: true - }); +export async function initBrowser(appPort: number): Promise { + try { + const launchArgs = ["--no-sandbox", "--disable-setuid-sandbox"]; - if (!browser) { - throw new Error("Failed to initialize browser"); - } + browser = await chromium.launch({ + headless: true, + args: launchArgs + }); + + if (!browser) { + throw new Error("Failed to initialize browser"); + } + + page = await browser.newPage(); + + // Forward browser console to server logs + page.on('console', msg => { + const type = msg.type(); + const text = msg.text(); + console.log(`[Browser Console ${type.toUpperCase()}] ${text}`); + }); - page = await browser.newPage(); + page.on('pageerror', error => { + console.error('[Browser Page Error]', error.message); + }); - await page.goto("http://localhost:8080"); + await page.goto(`http://localhost:${appPort}/app/index.html`, { + waitUntil: "networkidle", + }); + + await page.waitForFunction( + () => { + return window.wakuApi && typeof window.wakuApi.createWakuNode === "function"; + }, + { timeout: 30000 } + ); + + console.log("Browser initialized successfully with wakuApi"); + } catch (error) { + console.error("Error initializing browser:", error); + throw error; + } } -/** - * Get the current page instance - */ export function getPage(): Page | undefined { return page; } -/** - * Set the page instance (for use by server.ts) - */ export function setPage(pageInstance: Page | undefined): void { page = pageInstance; } -/** - * Closes the browser instance - */ export async function closeBrowser(): Promise { if (browser) { await browser.close(); diff --git a/packages/browser-tests/src/queue/index.ts b/packages/browser-tests/src/queue/index.ts deleted file mode 100644 index 4162093a4a..0000000000 --- a/packages/browser-tests/src/queue/index.ts +++ /dev/null @@ -1,89 +0,0 @@ -// Message queue to store received messages by content topic -export interface QueuedMessage { - payload: number[] | undefined; - contentTopic: string; - timestamp: number; - receivedAt: number; -} - -export interface MessageQueue { - [contentTopic: string]: QueuedMessage[]; -} - -// Global message queue storage -const messageQueue: MessageQueue = {}; - -/** - * Store a message in the queue - */ -export function storeMessage(message: QueuedMessage): void { - const { contentTopic } = message; - - if (!messageQueue[contentTopic]) { - messageQueue[contentTopic] = []; - } - - messageQueue[contentTopic].push(message); -} - -/** - * Get messages for a specific content topic - */ -export function getMessages( - contentTopic: string, - options?: { - startTime?: number; - endTime?: number; - pageSize?: number; - ascending?: boolean; - } -): QueuedMessage[] { - if (!messageQueue[contentTopic]) { - return []; - } - - let messages = [...messageQueue[contentTopic]]; - - // Filter by time if specified - if (options?.startTime || options?.endTime) { - messages = messages.filter((msg) => { - const afterStart = options.startTime - ? msg.timestamp >= options.startTime - : true; - const beforeEnd = options.endTime - ? msg.timestamp <= options.endTime - : true; - return afterStart && beforeEnd; - }); - } - - // Sort by timestamp - messages.sort((a, b) => { - return options?.ascending - ? a.timestamp - b.timestamp - : b.timestamp - a.timestamp; - }); - - // Limit result size - if (options?.pageSize && options.pageSize > 0) { - messages = messages.slice(0, options.pageSize); - } - - return messages; -} - -/** - * Clear all messages from the queue - */ -export function clearQueue(): void { - Object.keys(messageQueue).forEach((topic) => { - delete messageQueue[topic]; - }); -} - -/** - * Get all content topics in the queue - */ -export function getContentTopics(): string[] { - return Object.keys(messageQueue); -} diff --git a/packages/browser-tests/src/routes/admin.ts b/packages/browser-tests/src/routes/admin.ts deleted file mode 100644 index bb06ad82ea..0000000000 --- a/packages/browser-tests/src/routes/admin.ts +++ /dev/null @@ -1,223 +0,0 @@ -import express, { Request, Response, Router } from "express"; - -import { getPage } from "../browser/index.js"; - -const router = Router(); - -router.head("/admin/v1/create-node", (_req: Request, res: Response) => { - res.status(200).end(); -}); - -router.head("/admin/v1/start-node", (_req: Request, res: Response) => { - res.status(200).end(); -}); - -router.head("/admin/v1/stop-node", (_req: Request, res: Response) => { - res.status(200).end(); -}); - -router.post("/admin/v1/create-node", (async (req: Request, res: Response) => { - try { - const { - defaultBootstrap = true, - networkConfig - } = req.body; - - // Validate that networkConfig is provided - if (!networkConfig) { - return res.status(400).json({ - code: 400, - message: "networkConfig is required" - }); - } - - // Validate that networkConfig has required properties - if (networkConfig.clusterId === undefined) { - return res.status(400).json({ - code: 400, - message: "networkConfig.clusterId is required" - }); - } - - const page = getPage(); - - if (!page) { - return res.status(503).json({ - code: 503, - message: "Browser not initialized" - }); - } - - const result = await page.evaluate( - ({ defaultBootstrap, networkConfig }) => { - const nodeOptions: any = { - defaultBootstrap, - relay: { - advertise: true, - gossipsubOptions: { - allowPublishToZeroPeers: true - } - }, - filter: true, - peers: [], - networkConfig: { - clusterId: networkConfig.clusterId, - shards: networkConfig.shards || [0] - } - }; - - return window.wakuAPI.createWakuNode(nodeOptions); - }, - { defaultBootstrap, networkConfig } - ); - - if (result && result.success) { - res.status(200).json({ - success: true, - message: "Waku node created successfully" - }); - } else { - res.status(500).json({ - code: 500, - message: "Failed to create Waku node", - details: result?.error || "Unknown error" - }); - } - } catch (error: any) { - res.status(500).json({ - code: 500, - message: `Could not create Waku node: ${error.message}` - }); - } -}) as express.RequestHandler); - -// Start Waku node endpoint -router.post("/admin/v1/start-node", (async (_req: Request, res: Response) => { - try { - const page = getPage(); - - if (!page) { - return res.status(503).json({ - code: 503, - message: "Browser not initialized" - }); - } - - const result = await page.evaluate(() => { - return window.wakuAPI.startNode - ? window.wakuAPI.startNode() - : { error: "startNode function not available" }; - }); - - if (result && !result.error) { - res.status(200).json({ - success: true, - message: "Waku node started successfully" - }); - } else { - res.status(500).json({ - code: 500, - message: "Failed to start Waku node", - details: result?.error || "Unknown error" - }); - } - } catch (error: any) { - res.status(500).json({ - code: 500, - message: `Could not start Waku node: ${error.message}` - }); - } -}) as express.RequestHandler); - -// Stop Waku node endpoint -router.post("/admin/v1/stop-node", (async (_req: Request, res: Response) => { - try { - const page = getPage(); - - if (!page) { - return res.status(503).json({ - code: 503, - message: "Browser not initialized" - }); - } - - const result = await page.evaluate(() => { - return window.wakuAPI.stopNode - ? window.wakuAPI.stopNode() - : { error: "stopNode function not available" }; - }); - - if (result && !result.error) { - res.status(200).json({ - success: true, - message: "Waku node stopped successfully" - }); - } else { - res.status(500).json({ - code: 500, - message: "Failed to stop Waku node", - details: result?.error || "Unknown error" - }); - } - } catch (error: any) { - res.status(500).json({ - code: 500, - message: `Could not stop Waku node: ${error.message}` - }); - } -}) as express.RequestHandler); - -// Dial to peers endpoint -router.post("/admin/v1/peers", (async (req: Request, res: Response) => { - try { - const { peerMultiaddrs } = req.body; - - if (!peerMultiaddrs || !Array.isArray(peerMultiaddrs)) { - return res.status(400).json({ - code: 400, - message: "Invalid request. peerMultiaddrs array is required." - }); - } - - const page = getPage(); - - if (!page) { - return res.status(503).json({ - code: 503, - message: "Browser not initialized" - }); - } - - const result = await page.evaluate( - ({ peerAddrs }) => { - return window.wakuAPI.dialPeers(window.waku, peerAddrs); - }, - { peerAddrs: peerMultiaddrs } - ); - - if (result) { - res.status(200).json({ - peersAdded: peerMultiaddrs.length - (result.errors?.length || 0), - peerErrors: - result.errors?.map((error: string, index: number) => { - return { - peerMultiaddr: peerMultiaddrs[index], - error - }; - }) || [] - }); - } else { - res.status(500).json({ - code: 500, - message: "Failed to dial peers" - }); - } - } catch (error: any) { - res.status(500).json({ - code: 500, - message: `Could not dial peers: ${error.message}` - }); - } -}) as express.RequestHandler); - -export default router; diff --git a/packages/browser-tests/src/routes/info.ts b/packages/browser-tests/src/routes/info.ts deleted file mode 100644 index 9bfd12f820..0000000000 --- a/packages/browser-tests/src/routes/info.ts +++ /dev/null @@ -1,51 +0,0 @@ -import express, { Request, Response, Router } from "express"; - -import { getPage } from "../browser/index.js"; - -const router = Router(); - -// Get node info endpoint -router.get("/info", (async (_req: Request, res: Response) => { - try { - const page = getPage(); - if (!page) { - return res.status(503).json({ - code: 503, - message: "Browser not initialized" - }); - } - - const result = await page.evaluate(() => { - return window.wakuAPI.getPeerInfo(window.waku); - }); - - res.json(result); - } catch (error: any) { - console.error("Error getting info:", error); - res.status(500).json({ error: error.message }); - } -}) as express.RequestHandler); - -// Get node debug info endpoint -router.get("/debug/v1/info", (async (_req: Request, res: Response) => { - try { - const page = getPage(); - if (!page) { - return res.status(503).json({ - code: 503, - message: "Browser not initialized" - }); - } - - const result = await page.evaluate(() => { - return window.wakuAPI.getDebugInfo(window.waku); - }); - - res.json(result); - } catch (error: any) { - console.error("Error getting debug info:", error); - res.status(500).json({ error: error.message }); - } -}) as express.RequestHandler); - -export default router; diff --git a/packages/browser-tests/src/routes/push.ts b/packages/browser-tests/src/routes/push.ts deleted file mode 100644 index 37e533986a..0000000000 --- a/packages/browser-tests/src/routes/push.ts +++ /dev/null @@ -1,131 +0,0 @@ -import express, { Request, Response, Router } from "express"; - -import { getPage } from "../browser/index.js"; - -const router = Router(); - -// Legacy push message endpoint -router.post("/push", (async (req: Request, res: Response) => { - try { - const { contentTopic, payload } = req.body; - - if (!contentTopic) { - return res.status(400).json({ - code: 400, - message: "Invalid request. contentTopic is required." - }); - } - - const page = getPage(); - if (!page) { - return res.status(503).json({ - code: 503, - message: "Browser not initialized" - }); - } - - const result = await page.evaluate( - ({ topic, data }) => { - return window.wakuAPI.pushMessage(window.waku, topic, data); - }, - { - topic: contentTopic, - data: payload - } - ); - - if (result) { - res.status(200).json({ - messageId: - "0x" + - Buffer.from(contentTopic + Date.now().toString()).toString("hex") - }); - } else { - res.status(503).json({ - code: 503, - message: "Could not publish message: no suitable peers" - }); - } - } catch (error: any) { - if ( - error.message.includes("size exceeds") || - error.message.includes("stream reset") - ) { - res.status(503).json({ - code: 503, - message: - "Could not publish message: message size exceeds gossipsub max message size" - }); - } else { - res.status(500).json({ - code: 500, - message: `Could not publish message: ${error.message}` - }); - } - } -}) as express.RequestHandler); - -// Waku REST API compatible push endpoint -router.post("/lightpush/v1/message", (async (req: Request, res: Response) => { - try { - const { message } = req.body; - - if (!message || !message.contentTopic) { - return res.status(400).json({ - code: 400, - message: "Invalid request. contentTopic is required." - }); - } - - const page = getPage(); - if (!page) { - return res.status(503).json({ - code: 503, - message: "Browser not initialized" - }); - } - - const result = await page.evaluate( - ({ contentTopic, payload }) => { - return window.wakuAPI.pushMessage(window.waku, contentTopic, payload); - }, - { - contentTopic: message.contentTopic, - payload: message.payload - } - ); - - if (result) { - res.status(200).json({ - messageId: - "0x" + - Buffer.from(message.contentTopic + Date.now().toString()).toString( - "hex" - ) - }); - } else { - res.status(503).json({ - code: 503, - message: "Could not publish message: no suitable peers" - }); - } - } catch (error: any) { - if ( - error.message.includes("size exceeds") || - error.message.includes("stream reset") - ) { - res.status(503).json({ - code: 503, - message: - "Could not publish message: message size exceeds gossipsub max message size" - }); - } else { - res.status(500).json({ - code: 500, - message: `Could not publish message: ${error.message}` - }); - } - } -}) as express.RequestHandler); - -export default router; diff --git a/packages/browser-tests/src/routes/waku.ts b/packages/browser-tests/src/routes/waku.ts new file mode 100644 index 0000000000..0569328c90 --- /dev/null +++ b/packages/browser-tests/src/routes/waku.ts @@ -0,0 +1,85 @@ +import { Router } from "express"; +import { + createEndpointHandler, + validators, + errorHandlers, +} from "../utils/endpoint-handler.js"; + +const router = Router(); + +const corsEndpoints = [ + "/waku/v1/wait-for-peers", + "/waku/v1/peer-info", + "/lightpush/v3/message", +]; + +corsEndpoints.forEach((endpoint) => { + router.head(endpoint, (_req, res) => { + res.status(200).end(); + }); +}); + +router.post( + "/waku/v1/wait-for-peers", + createEndpointHandler({ + methodName: "waitForPeers", + validateInput: (body) => [ + body.timeoutMs || 10000, + body.protocols || ["lightpush", "filter"], + ], + transformResult: () => ({ + success: true, + message: "Successfully connected to peers", + }), + }), +); + +router.get( + "/waku/v1/peer-info", + createEndpointHandler({ + methodName: "getPeerInfo", + validateInput: validators.noInput, + }), +); + +router.post( + "/lightpush/v3/message", + createEndpointHandler({ + methodName: "pushMessageV3", + validateInput: (body: any): [string, string, string] => { + const validatedRequest = validators.requireLightpushV3(body); + + return [ + validatedRequest.message.contentTopic, + validatedRequest.message.payload, + validatedRequest.pubsubTopic, + ]; + }, + handleError: errorHandlers.lightpushError, + transformResult: (result) => { + if (result && result.successes && result.successes.length > 0) { + console.log("[Server] Message successfully sent via v3 lightpush!"); + + const sentTime = Date.now() * 1000000; + const msgHash = result.messageHash; + + const myPeerId = result.myPeerId || 'unknown'; + result.successes.forEach((peerId: string) => { + console.log(`publishWithConn my_peer_id=${myPeerId} peer_id=${peerId} msg_hash=${msgHash} sentTime=${sentTime}`); + }); + + return { + success: true, + result, + }; + } else { + return { + success: false, + error: "Could not publish message: no suitable peers", + }; + } + }, + }), +); + +export default router; diff --git a/packages/browser-tests/src/server.ts b/packages/browser-tests/src/server.ts index 269de9d161..c297c34501 100644 --- a/packages/browser-tests/src/server.ts +++ b/packages/browser-tests/src/server.ts @@ -1,507 +1,228 @@ -import { ChildProcess, exec } from "child_process"; -import * as net from "net"; -import { dirname, join } from "path"; import { fileURLToPath } from "url"; +import * as path from "path"; -import { chromium } from "@playwright/test"; import cors from "cors"; import express, { Request, Response } from "express"; -import adminRouter from "./routes/admin.js"; -import { setPage, getPage, closeBrowser } from "./browser/index.js"; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); +import wakuRouter from "./routes/waku.js"; +import { initBrowser, getPage, closeBrowser } from "./browser/index.js"; +import { DEFAULT_CLUSTER_ID, DEFAULT_NUM_SHARDS } from "@waku/interfaces"; const app = express(); app.use(cors()); app.use(express.json()); -app.use(adminRouter); -let headlessServerProcess: ChildProcess | undefined; - -interface MessageQueue { - [contentTopic: string]: Array<{ - payload: number[] | undefined; - contentTopic: string; - timestamp: number; - receivedAt: number; - }>; -} +import * as fs from "fs"; -const messageQueue: MessageQueue = {}; +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const distRoot = path.resolve(__dirname, ".."); +const webDir = path.resolve(distRoot, "web"); -async function startHeadlessServer(): Promise { - return new Promise((resolve, reject) => { - try { - headlessServerProcess = exec( - `serve ${join(__dirname, "../../headless-tests")} -p 8080 -s`, - (error) => { - if (error) { - console.error(`Error starting serve: ${error}`); - return; - } - } - ); +app.get("/app/index.html", (_req: Request, res: Response) => { + try { + const htmlPath = path.join(webDir, "index.html"); + let htmlContent = fs.readFileSync(htmlPath, "utf8"); - setTimeout(resolve, 2000); - } catch (error) { - console.error("Failed to start headless server:", error); - reject(error); + const networkConfig: any = {}; + if (process.env.WAKU_CLUSTER_ID) { + networkConfig.clusterId = parseInt(process.env.WAKU_CLUSTER_ID, 10); + } + if (process.env.WAKU_SHARD) { + networkConfig.shards = [parseInt(process.env.WAKU_SHARD, 10)]; + console.log("Using static shard:", networkConfig.shards); } - }); -} -async function initBrowser(): Promise { - try { - const browser = await chromium.launch({ - headless: true - }); + const lightpushNode = process.env.WAKU_LIGHTPUSH_NODE || null; + const enrBootstrap = process.env.WAKU_ENR_BOOTSTRAP || null; - if (!browser) { - throw new Error("Failed to initialize browser"); - } + console.log("Network config on server start, pre headless:", networkConfig); - const page = await browser.newPage(); + const configScript = ` `; + const originalPattern = + ' '; + const replacement = `${configScript}\n `; - try { - await checkServerAvailability("http://localhost:8080", 3); - await page.goto("http://localhost:8080"); - } catch (error) { - console.error( - "Error loading headless app, continuing without it:", - error - ); - await page.setContent(` - - Waku Test Environment - -

Waku Test Environment (No headless app available)

- - - - `); - } + htmlContent = htmlContent.replace(originalPattern, replacement); - setPage(page); + res.setHeader("Content-Type", "text/html"); + res.send(htmlContent); } catch (error) { - console.error("Error initializing browser:", error); - throw error; - } -} - -async function checkServerAvailability( - url: string, - retries = 3 -): Promise { - for (let i = 0; i < retries; i++) { - try { - const response = await fetch(url, { method: "HEAD" }); - if (response.ok) return true; - } catch (e) { - await new Promise((resolve) => setTimeout(resolve, 1000)); - } + console.error("Error serving dynamic index.html:", error); + res.status(500).send("Error loading page"); } - throw new Error(`Server at ${url} not available after ${retries} retries`); -} - -async function findAvailablePort( - startPort: number, - maxAttempts = 10 -): Promise { - for (let attempt = 0; attempt < maxAttempts; attempt++) { - const port = startPort + attempt; - try { - // Try to create a server on the port - await new Promise((resolve, reject) => { - const server = net - .createServer() - .once("error", (err: any) => { - reject(err); - }) - .once("listening", () => { - // If we can listen, the port is available - server.close(); - resolve(); - }) - .listen(port); - }); +}); - // If we get here, the port is available - return port; - } catch (err) { - // Port is not available, continue to next port - } - } +app.use("/app", express.static(webDir, { index: false })); - // If we tried all ports and none are available, throw an error - throw new Error( - `Unable to find an available port after ${maxAttempts} attempts` - ); -} +app.use(wakuRouter); -async function startServer(port: number = 3000): Promise { +async function startAPI(requestedPort: number): Promise { try { - await startHeadlessServer(); + app.get("/", (_req: Request, res: Response) => { + res.json({ status: "Waku simulation server is running" }); + }); - await initBrowser(); + app + .listen(requestedPort, () => { + console.log(`API server running on http://localhost:${requestedPort}`); + }) + .on("error", (error: any) => { + if (error.code === "EADDRINUSE") { + console.error( + `Port ${requestedPort} is already in use. Please close the application using this port and try again.`, + ); + } else { + console.error("Error starting server:", error); + } + throw error; + }); - await startAPI(port); + return requestedPort; } catch (error: any) { console.error("Error starting server:", error); + throw error; } } -async function startAPI(requestedPort: number): Promise { +async function startServer(port: number = 3000): Promise { try { - app.get("/", (_req: Request, res: Response) => { - res.json({ status: "Waku simulation server is running" }); - }); - - app.get("/info", (async (_req: Request, res: Response) => { - try { - const result = await getPage()?.evaluate(() => { - return window.wakuAPI.getPeerInfo(window.waku); - }); - - res.json(result); - } catch (error: any) { - console.error("Error getting info:", error); - res.status(500).json({ error: error.message }); - } - }) as express.RequestHandler); - - app.get("/debug/v1/info", (async (_req: Request, res: Response) => { - try { - const result = await getPage()?.evaluate(() => { - return window.wakuAPI.getDebugInfo(window.waku); - }); - - res.json(result); - } catch (error: any) { - console.error("Error getting debug info:", error); - res.status(500).json({ error: error.message }); - } - }) as express.RequestHandler); + const actualPort = await startAPI(port); + await initBrowser(actualPort); - app.post("/lightpush/v1/message", (async (req: Request, res: Response) => { - try { - const { message } = req.body; - - if (!message || !message.contentTopic) { - return res.status(400).json({ - code: 400, - message: "Invalid request. contentTopic is required." - }); - } - - const result = await getPage()?.evaluate( - ({ contentTopic, payload }) => { - return window.wakuAPI.pushMessage( - window.waku, - contentTopic, - payload - ); + try { + console.log("Auto-starting node with CLI configuration..."); + + const hasEnrBootstrap = Boolean(process.env.WAKU_ENR_BOOTSTRAP); + const networkConfig: any = { + defaultBootstrap: false, + ...(hasEnrBootstrap && { + discovery: { + dns: true, + peerExchange: true, + peerCache: true, }, - { - contentTopic: message.contentTopic, - payload: message.payload - } - ); - - if (result) { - res.status(200).json({ - messageId: - "0x" + - Buffer.from( - message.contentTopic + Date.now().toString() - ).toString("hex") - }); - } else { - res.status(503).json({ - code: 503, - message: "Could not publish message: no suitable peers" - }); - } - } catch (error: any) { - - if ( - error.message.includes("size exceeds") || - error.message.includes("stream reset") - ) { - res.status(503).json({ - code: 503, - - message: - "Could not publish message: message size exceeds gossipsub max message size" - }); - } else { - res.status(500).json({ - code: 500, - message: `Could not publish message: ${error.message}` - }); - } + }), + }; + + // console.log( + // `Bootstrap mode: ${hasEnrBootstrap ? "ENR-only (defaultBootstrap=false)" : "default bootstrap (defaultBootstrap=true)"}`, + // ); + if (hasEnrBootstrap) { + console.log(`ENR bootstrap peers: ${process.env.WAKU_ENR_BOOTSTRAP}`); } - }) as express.RequestHandler); - - app.get("/filter/v2/messages/:contentTopic", (async ( - req: Request, - res: Response - ) => { - try { - const { contentTopic } = req.params; - const { clusterId, shard } = req.query; - - const options = { - clusterId: clusterId ? parseInt(clusterId as string, 10) : 42, // Default to match node creation - shard: shard ? parseInt(shard as string, 10) : 0 // Default to match node creation - }; - - - // Set up SSE (Server-Sent Events) - res.setHeader("Content-Type", "text/event-stream"); - res.setHeader("Cache-Control", "no-cache"); - res.setHeader("Connection", "keep-alive"); - - // Function to send SSE - const sendSSE = (data: any): void => { - res.write(`data: ${JSON.stringify(data)}\n\n`); - }; - - // Subscribe to messages - await getPage()?.evaluate( - ({ contentTopic, options }) => { - // Message handler that will send messages back to the client - const callback = (message: any): void => { - // Post message to the browser context - window.postMessage( - { - type: "WAKU_MESSAGE", - payload: { - payload: message.payload - ? Array.from(message.payload) - : undefined, - contentTopic: message.contentTopic, - timestamp: message.timestamp - } - }, - "*" - ); - }; - - return window.wakuAPI.subscribe( - window.waku, - contentTopic, - options, - callback - ); - }, - { contentTopic, options } - ); - // Set up event listener for messages from the page - await getPage()?.exposeFunction("sendMessageToServer", (message: any) => { - // Send the message as SSE - sendSSE(message); - - const topic = message.contentTopic; - if (!messageQueue[topic]) { - messageQueue[topic] = []; - } - - messageQueue[topic].push({ - ...message, - receivedAt: Date.now() - }); - - if (messageQueue[topic].length > 1000) { - messageQueue[topic].shift(); - } - }); - - // Add event listener in the browser context to forward messages to the server - await getPage()?.evaluate(() => { - window.addEventListener("message", (event) => { - if (event.data.type === "WAKU_MESSAGE") { - (window as any).sendMessageToServer(event.data.payload); - } - }); - }); - - req.on("close", () => { - }); - } catch (error: any) { - console.error("Error in filter subscription:", error); - res.write(`data: ${JSON.stringify({ error: error.message })}\n\n`); - res.end(); + networkConfig.networkConfig = { + clusterId: process.env.WAKU_CLUSTER_ID + ? parseInt(process.env.WAKU_CLUSTER_ID, 10) + : DEFAULT_CLUSTER_ID, + numShardsInCluster: DEFAULT_NUM_SHARDS, + }; + + if (process.env.WAKU_SHARD) { + networkConfig.networkConfig.shards = [ + parseInt(process.env.WAKU_SHARD, 10), + ]; + delete networkConfig.networkConfig.numShardsInCluster; } - }) as express.RequestHandler); - app.get("/filter/v1/messages/:contentTopic", (async ( - req: Request, - res: Response - ) => { - try { - const { contentTopic } = req.params; - const { - pageSize = "20", - startTime, - endTime, - ascending = "false" - } = req.query; - - if (!messageQueue[contentTopic]) { - return res.status(200).json({ messages: [] }); - } + console.log( + `Network config: ${JSON.stringify(networkConfig.networkConfig)}`, + ); - const limit = parseInt(pageSize as string, 10); - const isAscending = (ascending as string).toLowerCase() === "true"; - const timeStart = startTime ? parseInt(startTime as string, 10) : 0; - const timeEnd = endTime ? parseInt(endTime as string, 10) : Date.now(); - - const filteredMessages = messageQueue[contentTopic] - .filter((msg) => { - const msgTime = msg.timestamp || msg.receivedAt; - return msgTime >= timeStart && msgTime <= timeEnd; - }) - .sort((a, b) => { - const timeA = a.timestamp || a.receivedAt; - const timeB = b.timestamp || b.receivedAt; - return isAscending ? timeA - timeB : timeB - timeA; - }) - .slice(0, limit); - - - // Format response to match Waku REST API format - const response = { - messages: filteredMessages.map((msg) => ({ - payload: msg.payload - ? Buffer.from(msg.payload).toString("base64") - : "", - contentTopic: msg.contentTopic, - timestamp: msg.timestamp, - version: 0 // Default version - })) - }; - - res.status(200).json(response); - } catch (error: any) { - console.error("Error retrieving messages:", error); - res.status(500).json({ - code: 500, - message: `Failed to retrieve messages: ${error.message}` - }); - } - }) as express.RequestHandler); + await getPage()?.evaluate((config) => { + return window.wakuApi.createWakuNode(config); + }, networkConfig); + await getPage()?.evaluate(() => window.wakuApi.startNode()); - // Helper endpoint for executing functions (useful for testing) - app.post("/execute", (async (req: Request, res: Response) => { try { - const { functionName, params = [] } = req.body; - - if (functionName === "simulateMessages") { - const [contentTopic, messages] = params; - - if (!messageQueue[contentTopic]) { - messageQueue[contentTopic] = []; - } - - // Add messages to the queue - for (const msg of messages) { - messageQueue[contentTopic].push({ - ...msg, - contentTopic, - receivedAt: Date.now() - }); - } - - return res.status(200).json({ - success: true, - messagesAdded: messages.length - }); - } - - const result = await getPage()?.evaluate( - ({ fnName, fnParams }) => { - if (!window.wakuAPI[fnName]) { - return { error: `Function ${fnName} not found` }; - } - return window.wakuAPI[fnName](...fnParams); - }, - { fnName: functionName, fnParams: params } + await getPage()?.evaluate(() => + window.wakuApi.waitForPeers?.(5000, ["lightpush"] as any), ); - - res.status(200).json(result); - } catch (error: any) { - console.error( - `Error executing function ${req.body.functionName}:`, - error + console.log("Auto-start completed with bootstrap peers"); + } catch (peerError) { + console.log( + "Auto-start completed (no bootstrap peers found - may be expected with test ENRs)", ); - res.status(500).json({ - error: error.message - }); } - }) as express.RequestHandler); - - - let actualPort: number; - try { - actualPort = await findAvailablePort(requestedPort); - } catch (error) { - console.error("Failed to find an available port:", error); - throw error; + } catch (e) { + console.warn("Auto-start failed:", e); } - - app - .listen(actualPort, () => { - }) - .on("error", (error: any) => { - if (error.code === "EADDRINUSE") { - console.error( - `Port ${actualPort} is already in use. Please close the application using this port and try again.` - ); - } else { - console.error("Error starting server:", error); - } - }); - - return Promise.resolve(); } catch (error: any) { console.error("Error starting server:", error); - return Promise.reject(error); } } -process.on("SIGINT", (async () => { - await closeBrowser(); +process.on("uncaughtException", (error) => { + console.error("Uncaught Exception:", error); + if (process.env.NODE_ENV !== "production") { + process.exit(1); + } +}); - if (headlessServerProcess && headlessServerProcess.pid) { - try { - process.kill(headlessServerProcess.pid); - } catch (e) { - // Process already stopped - } +process.on("unhandledRejection", (reason, promise) => { + console.error("Unhandled Rejection at:", promise, "reason:", reason); + if (process.env.NODE_ENV !== "production") { + process.exit(1); } +}); +const gracefulShutdown = async (signal: string) => { + console.log(`Received ${signal}, gracefully shutting down...`); + try { + await closeBrowser(); + } catch (e) { + console.warn("Error closing browser:", e); + } process.exit(0); -}) as any); +}; + +process.on("SIGINT", () => gracefulShutdown("SIGINT")); +process.on("SIGTERM", () => gracefulShutdown("SIGTERM")); + +function parseCliArgs() { + const args = process.argv.slice(2); + let clusterId: number | undefined; + let shard: number | undefined; + + for (const arg of args) { + if (arg.startsWith("--cluster-id=")) { + clusterId = parseInt(arg.split("=")[1], 10); + if (isNaN(clusterId)) { + console.error("Invalid cluster-id value. Must be a number."); + process.exit(1); + } + } else if (arg.startsWith("--shard=")) { + shard = parseInt(arg.split("=")[1], 10); + if (isNaN(shard)) { + console.error("Invalid shard value. Must be a number."); + process.exit(1); + } + } + } + + return { clusterId, shard }; +} const isMainModule = process.argv[1] === fileURLToPath(import.meta.url); if (isMainModule) { const port = process.env.PORT ? parseInt(process.env.PORT, 10) : 3000; + const cliArgs = parseCliArgs(); + + if (cliArgs.clusterId !== undefined) { + process.env.WAKU_CLUSTER_ID = cliArgs.clusterId.toString(); + console.log(`Using CLI cluster ID: ${cliArgs.clusterId}`); + } + if (cliArgs.shard !== undefined) { + process.env.WAKU_SHARD = cliArgs.shard.toString(); + console.log(`Using CLI shard: ${cliArgs.shard}`); + } + void startServer(port); } diff --git a/packages/browser-tests/src/utils.js b/packages/browser-tests/src/utils.js deleted file mode 100644 index 0122958d04..0000000000 --- a/packages/browser-tests/src/utils.js +++ /dev/null @@ -1,8 +0,0 @@ -import { readFileSync } from "fs"; -import { dirname } from "path"; -import { fileURLToPath } from "url"; - -const __filename = fileURLToPath(import.meta.url); -export const __dirname = dirname(__filename); - -export const readJSON = (path) => JSON.parse(readFileSync(path, "utf-8")); diff --git a/packages/browser-tests/src/utils/endpoint-handler.ts b/packages/browser-tests/src/utils/endpoint-handler.ts new file mode 100644 index 0000000000..5c8bbe4476 --- /dev/null +++ b/packages/browser-tests/src/utils/endpoint-handler.ts @@ -0,0 +1,183 @@ +import { Request, Response } from "express"; +import { getPage } from "../browser/index.js"; +import type { ITestBrowser } from "../../types/global.js"; + +export interface LightpushV3Request { + pubsubTopic: string; + message: { + payload: string; + contentTopic: string; + version: number; + }; +} + +export interface LightpushV3Response { + success?: boolean; + error?: string; + result?: { + successes: string[]; + failures: Array<{ + error: string; + peerId?: string; + }>; + }; +} + +export interface EndpointConfig { + methodName: string; + validateInput?: (_requestBody: any) => TInput; + transformResult?: (_sdkResult: any) => TOutput; + handleError?: (_caughtError: Error) => { code: number; message: string }; + preCheck?: () => Promise | void; + logResult?: boolean; +} + +export function createEndpointHandler( + config: EndpointConfig, +) { + return async (req: Request, res: Response) => { + try { + let input: TInput; + try { + input = config.validateInput + ? config.validateInput(req.body) + : req.body; + } catch (validationError: any) { + return res.status(400).json({ + code: 400, + message: `Invalid input: ${validationError.message}`, + }); + } + + if (config.preCheck) { + try { + await config.preCheck(); + } catch (checkError: any) { + return res.status(503).json({ + code: 503, + message: checkError.message, + }); + } + } + + const page = getPage(); + if (!page) { + return res.status(503).json({ + code: 503, + message: "Browser not initialized", + }); + } + + const result = await page.evaluate( + ({ methodName, params }) => { + const testWindow = window as ITestBrowser; + if (!testWindow.wakuApi) { + throw new Error("window.wakuApi is not available"); + } + + const method = (testWindow.wakuApi as any)[methodName]; + if (typeof method !== "function") { + throw new Error(`window.wakuApi.${methodName} is not a function`); + } + + if (params === null || params === undefined) { + return method.call(testWindow.wakuApi); + } else if (Array.isArray(params)) { + return method.apply(testWindow.wakuApi, params); + } else { + return method.call(testWindow.wakuApi, params); + } + }, + { methodName: config.methodName, params: input }, + ); + + if (config.logResult !== false) { + console.log( + `[${config.methodName}] Result:`, + JSON.stringify(result, null, 2), + ); + } + + const finalResult = config.transformResult + ? config.transformResult(result) + : result; + + res.status(200).json(finalResult); + } catch (error: any) { + if (config.handleError) { + const errorResponse = config.handleError(error); + return res.status(errorResponse.code).json({ + code: errorResponse.code, + message: errorResponse.message, + }); + } + + console.error(`[${config.methodName}] Error:`, error); + res.status(500).json({ + code: 500, + message: `Could not execute ${config.methodName}: ${error.message}`, + }); + } + }; +} + +export const validators = { + requireLightpushV3: (body: any): LightpushV3Request => { + if ( + body.pubsubTopic !== undefined && + typeof body.pubsubTopic !== "string" + ) { + throw new Error("pubsubTopic must be a string if provided"); + } + if (!body.message || typeof body.message !== "object") { + throw new Error("message is required and must be an object"); + } + if ( + !body.message.contentTopic || + typeof body.message.contentTopic !== "string" + ) { + throw new Error("message.contentTopic is required and must be a string"); + } + if (!body.message.payload || typeof body.message.payload !== "string") { + throw new Error( + "message.payload is required and must be a string (base64 encoded)", + ); + } + if ( + body.message.version !== undefined && + typeof body.message.version !== "number" + ) { + throw new Error("message.version must be a number if provided"); + } + + return { + pubsubTopic: body.pubsubTopic || "", + message: { + payload: body.message.payload, + contentTopic: body.message.contentTopic, + version: body.message.version || 1, + }, + }; + }, + + noInput: () => null, +}; + +export const errorHandlers = { + lightpushError: (error: Error) => { + if ( + error.message.includes("size exceeds") || + error.message.includes("stream reset") + ) { + return { + code: 503, + message: + "Could not publish message: message size exceeds gossipsub max message size", + }; + } + return { + code: 500, + message: `Could not publish message: ${error.message}`, + }; + }, +}; diff --git a/packages/browser-tests/tests/e2e.spec.ts b/packages/browser-tests/tests/e2e.spec.ts new file mode 100644 index 0000000000..9254dda07b --- /dev/null +++ b/packages/browser-tests/tests/e2e.spec.ts @@ -0,0 +1,113 @@ +import { test, expect } from "@playwright/test"; +import axios from "axios"; +import { StartedTestContainer } from "testcontainers"; +import { ServiceNodesFleet } from "@waku/tests"; +import { DefaultTestRoutingInfo } from "@waku/tests"; +import { + startBrowserTestsContainer, + stopContainer +} from "./utils/container-helpers.js"; +import { + createTwoNodeNetwork, + getDockerAccessibleMultiaddr, + stopNwakuNodes +} from "./utils/nwaku-helpers.js"; +import { + ENV_BUILDERS, + TEST_CONFIG, + ASSERTIONS +} from "./utils/test-config.js"; + +test.describe.configure({ mode: "serial" }); + +let container: StartedTestContainer; +let nwakuNodes: ServiceNodesFleet; +let baseUrl: string; + +test.beforeAll(async () => { + nwakuNodes = await createTwoNodeNetwork(); + + const lightPushPeerAddr = await getDockerAccessibleMultiaddr(nwakuNodes.nodes[0]); + + const result = await startBrowserTestsContainer({ + environment: ENV_BUILDERS.withLocalLightPush(lightPushPeerAddr), + networkMode: "waku", + }); + + container = result.container; + baseUrl = result.baseUrl; +}); + +test.afterAll(async () => { + await Promise.all([ + stopContainer(container), + stopNwakuNodes(nwakuNodes?.nodes || []), + ]); +}); + +test("WakuHeadless can discover nwaku peer and use it for light push", async () => { + test.setTimeout(TEST_CONFIG.DEFAULT_TEST_TIMEOUT); + + const contentTopic = TEST_CONFIG.DEFAULT_CONTENT_TOPIC; + const testMessage = TEST_CONFIG.DEFAULT_TEST_MESSAGE; + + await new Promise((r) => setTimeout(r, TEST_CONFIG.WAKU_INIT_DELAY)); + + const healthResponse = await axios.get(`${baseUrl}/`, { timeout: 5000 }); + ASSERTIONS.serverHealth(healthResponse); + + try { + await axios.post(`${baseUrl}/waku/v1/wait-for-peers`, { + timeoutMs: 10000, + protocols: ["lightpush"], + }, { timeout: 15000 }); + } catch { + // Ignore errors + } + + const peerInfoResponse = await axios.get(`${baseUrl}/waku/v1/peer-info`); + ASSERTIONS.peerInfo(peerInfoResponse); + + const routingInfo = DefaultTestRoutingInfo; + + const subscriptionResults = await Promise.all([ + nwakuNodes.nodes[0].ensureSubscriptions([routingInfo.pubsubTopic]), + nwakuNodes.nodes[1].ensureSubscriptions([routingInfo.pubsubTopic]) + ]); + + expect(subscriptionResults[0]).toBe(true); + expect(subscriptionResults[1]).toBe(true); + + await new Promise((r) => setTimeout(r, TEST_CONFIG.SUBSCRIPTION_DELAY)); + + const base64Payload = btoa(testMessage); + + const pushResponse = await axios.post(`${baseUrl}/lightpush/v3/message`, { + pubsubTopic: routingInfo.pubsubTopic, + message: { + contentTopic, + payload: base64Payload, + version: 1, + }, + }); + + ASSERTIONS.lightPushV3Success(pushResponse); + + await new Promise((r) => setTimeout(r, TEST_CONFIG.MESSAGE_PROPAGATION_DELAY)); + + const [node1Messages, node2Messages] = await Promise.all([ + nwakuNodes.nodes[0].messages(contentTopic), + nwakuNodes.nodes[1].messages(contentTopic) + ]); + + + const totalMessages = node1Messages.length + node2Messages.length; + expect(totalMessages).toBeGreaterThanOrEqual(1); + + const receivedMessages = [...node1Messages, ...node2Messages]; + expect(receivedMessages.length).toBeGreaterThan(0); + + const receivedMessage = receivedMessages[0]; + ASSERTIONS.messageContent(receivedMessage, testMessage, contentTopic); + +}); \ No newline at end of file diff --git a/packages/browser-tests/tests/headless.spec.ts b/packages/browser-tests/tests/headless.spec.ts deleted file mode 100644 index 0817d1c1cf..0000000000 --- a/packages/browser-tests/tests/headless.spec.ts +++ /dev/null @@ -1,136 +0,0 @@ -import { expect, test } from "@playwright/test"; -import { LightNode } from "@waku/sdk"; - -import { API } from "../src/api/shared.js"; -import { NETWORK_CONFIG, ACTIVE_PEERS } from "./test-config.js"; - -// Define the window interface for TypeScript -declare global { - // eslint-disable-next-line no-unused-vars - interface Window { - waku: LightNode; - wakuAPI: typeof API; - } -} - -test.describe("waku", () => { - test.beforeEach(async ({ page }) => { - await page.goto(""); - await page.waitForTimeout(5000); - - // Create and initialize a fresh Waku node for each test - const setupResult = await page.evaluate(async (config) => { - try { - await window.wakuAPI.createWakuNode({ - ...config.defaultNodeConfig, - networkConfig: config.networkConfig - }); - await window.wakuAPI.startNode(); - return { success: true }; - } catch (error) { - console.error("Failed to initialize Waku node:", error); - return { success: false, error: String(error) }; - } - }, NETWORK_CONFIG); - - expect(setupResult.success).toBe(true); - }); - - test("can get peer id", async ({ page }) => { - const peerId = await page.evaluate(() => { - return window.waku.libp2p.peerId.toString(); - }); - - expect(peerId).toBeDefined(); - console.log("Peer ID:", peerId); - }); - - test("can get info", async ({ page }) => { - const info = await page.evaluate(() => { - return window.wakuAPI.getPeerInfo(window.waku); - }); - - expect(info).toBeDefined(); - expect(info.peerId).toBeDefined(); - expect(info.multiaddrs).toBeDefined(); - expect(info.peers).toBeDefined(); - console.log("Info:", info); - }); - - test("can get debug info", async ({ page }) => { - const debug = await page.evaluate(() => { - return window.wakuAPI.getDebugInfo(window.waku); - }); - - expect(debug).toBeDefined(); - expect(debug.listenAddresses).toBeDefined(); - expect(debug.peerId).toBeDefined(); - expect(debug.protocols).toBeDefined(); - console.log("Debug:", debug); - }); - - test("can dial peers", async ({ page }) => { - const result = await page.evaluate((peerAddrs) => { - return window.wakuAPI.dialPeers(window.waku, peerAddrs); - }, ACTIVE_PEERS); - - expect(result).toBeDefined(); - expect(result.total).toBe(ACTIVE_PEERS.length); - expect(result.errors.length >= result.total).toBe(false); - console.log("Dial result:", result); - }); - - test("can push a message", async ({ page }) => { - // First dial to peers - await page.evaluate((peersToDial) => { - return window.wakuAPI.dialPeers(window.waku, peersToDial); - }, ACTIVE_PEERS); - - // Create a test message - const contentTopic = NETWORK_CONFIG.testMessage.contentTopic; - const payload = new TextEncoder().encode(NETWORK_CONFIG.testMessage.payload); - const arrayPayload = Array.from(payload); - - // Push the message - const result = await page.evaluate( - ({ topic, data }) => { - return window.wakuAPI.pushMessage( - window.waku, - topic, - new Uint8Array(data) - ); - }, - { topic: contentTopic, data: arrayPayload } - ); - - expect(result).toBeDefined(); - console.log("Push result:", result); - }); - - test("can recreate Waku node", async ({ page }) => { - // Get the current node's peer ID - const initialPeerId = await page.evaluate(() => { - return window.waku.libp2p.peerId.toString(); - }); - - // Create a new node with different parameters - const result = await page.evaluate(() => { - return window.wakuAPI.createWakuNode({ - defaultBootstrap: true // Different from beforeEach - }); - }); - - expect(result.success).toBe(true); - - // Start the new node - await page.evaluate(() => window.wakuAPI.startNode()); - - // Get the new peer ID - const newPeerId = await page.evaluate(() => { - return window.waku.libp2p.peerId.toString(); - }); - - expect(newPeerId).not.toBe(initialPeerId); - console.log("Initial:", initialPeerId, "New:", newPeerId); - }); -}); diff --git a/packages/browser-tests/tests/integration.spec.ts b/packages/browser-tests/tests/integration.spec.ts new file mode 100644 index 0000000000..c5be3fcbf6 --- /dev/null +++ b/packages/browser-tests/tests/integration.spec.ts @@ -0,0 +1,132 @@ +import { test, expect } from "@playwright/test"; +import axios from "axios"; +import { StartedTestContainer } from "testcontainers"; +import { + createLightNode, + waitForRemotePeer, + LightNode, + Protocols, +} from "@waku/sdk"; +import { DEFAULT_CLUSTER_ID, DEFAULT_NUM_SHARDS } from "@waku/interfaces"; +import { startBrowserTestsContainer, stopContainer } from "./utils/container-helpers.js"; +import { ENV_BUILDERS, TEST_CONFIG } from "./utils/test-config.js"; + +test.describe.configure({ mode: "serial" }); + +let container: StartedTestContainer; +let baseUrl: string; +let wakuNode: LightNode; + +test.beforeAll(async () => { + const result = await startBrowserTestsContainer({ + environment: ENV_BUILDERS.withProductionEnr(), + }); + + container = result.container; + baseUrl = result.baseUrl; +}); + +test.afterAll(async () => { + if (wakuNode) { + try { + await wakuNode.stop(); + } catch { + // Ignore errors + } + } + + await stopContainer(container); +}); + +test("cross-network message delivery: SDK light node receives server lightpush", async () => { + test.setTimeout(TEST_CONFIG.DEFAULT_TEST_TIMEOUT); + + const contentTopic = TEST_CONFIG.DEFAULT_CONTENT_TOPIC; + const testMessage = TEST_CONFIG.DEFAULT_TEST_MESSAGE; + + wakuNode = await createLightNode({ + defaultBootstrap: true, + discovery: { + dns: true, + peerExchange: true, + peerCache: true, + }, + networkConfig: { + clusterId: DEFAULT_CLUSTER_ID, + numShardsInCluster: DEFAULT_NUM_SHARDS, + }, + libp2p: { + filterMultiaddrs: false, + }, + }); + + await wakuNode.start(); + + await waitForRemotePeer( + wakuNode, + [Protocols.Filter, Protocols.LightPush], + 30000, + ); + + const messages: any[] = []; + const decoder = wakuNode.createDecoder({ contentTopic }); + + if ( + !(await wakuNode.filter.subscribe([decoder], (message) => { + messages.push(message); + })) + ) { + throw new Error("Failed to subscribe to Filter"); + } + + await new Promise((r) => setTimeout(r, 2000)); + + const messagePromise = new Promise((resolve) => { + const originalLength = messages.length; + const checkForMessage = () => { + if (messages.length > originalLength) { + resolve(); + } else { + setTimeout(checkForMessage, 100); + } + }; + checkForMessage(); + }); + + await axios.post(`${baseUrl}/waku/v1/wait-for-peers`, { + timeoutMs: 30000, // Increased timeout + protocols: ["lightpush", "filter"], + }); + + await new Promise((r) => setTimeout(r, 10000)); + + const base64Payload = btoa(testMessage); + + const pushResponse = await axios.post(`${baseUrl}/lightpush/v3/message`, { + pubsubTopic: decoder.pubsubTopic, + message: { + contentTopic, + payload: base64Payload, + version: 1, + }, + }); + + expect(pushResponse.status).toBe(200); + expect(pushResponse.data.success).toBe(true); + + await Promise.race([ + messagePromise, + new Promise((_, reject) => + setTimeout(() => { + reject(new Error("Timeout waiting for message")); + }, 45000), + ), + ]); + + expect(messages).toHaveLength(1); + const receivedMessage = messages[0]; + expect(receivedMessage.contentTopic).toBe(contentTopic); + + const receivedPayload = new TextDecoder().decode(receivedMessage.payload); + expect(receivedPayload).toBe(testMessage); +}); diff --git a/packages/browser-tests/tests/server.spec.ts b/packages/browser-tests/tests/server.spec.ts index 85c8098c05..bbdce49273 100644 --- a/packages/browser-tests/tests/server.spec.ts +++ b/packages/browser-tests/tests/server.spec.ts @@ -1,722 +1,82 @@ -import { ChildProcess, exec, spawn } from "child_process"; -import * as http from "http"; -import * as net from "net"; -import { join } from "path"; - -import { expect, test } from "@playwright/test"; +import { test, expect } from "@playwright/test"; import axios from "axios"; +import { spawn } from "child_process"; +import { fileURLToPath } from "url"; +import { dirname, join } from "path"; -// The default URL, but we'll update this if we detect a different port -let API_URL = "http://localhost:3000"; -// Need this for basic node initialization that doesn't rely on /execute -const PEERS = [ - "/dns4/waku-test.bloxy.one/tcp/8095/wss/p2p/16Uiu2HAmSZbDB7CusdRhgkD81VssRjQV5ZH13FbzCGcdnbbh6VwZ", - "/dns4/waku.fryorcraken.xyz/tcp/8000/wss/p2p/16Uiu2HAmMRvhDHrtiHft1FTUYnn6cVA8AWVrTyLUayJJ3MWpUZDB" -]; - -let serverProcess: ChildProcess; +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); -// Force tests to run sequentially to avoid port conflicts test.describe.configure({ mode: "serial" }); -// Helper function to check if a port is in use -async function isPortInUse(port: number): Promise { - return new Promise((resolve) => { - const server = net - .createServer() - .once("error", () => { - // Port is in use - resolve(true); - }) - .once("listening", () => { - // Port is free, close server - server.close(); - resolve(false); - }) - .listen(port); - }); -} +test.describe("Server Tests", () => { + let serverProcess: any; + let baseUrl = "http://localhost:3000"; -// Helper function to kill processes on port 3000 -async function killProcessOnPort(): Promise { - return new Promise((resolve) => { - // Different commands for different platforms - const cmd = - process.platform === "win32" - ? `netstat -ano | findstr :3000 | findstr LISTENING` - : `lsof -i:3000 -t`; - - exec(cmd, (err, stdout) => { - if (err || !stdout.trim()) { - console.log("No process running on port 3000"); - resolve(); - return; - } - - console.log(`Found processes on port 3000: ${stdout.trim()}`); - - // Kill the process - const killCmd = - process.platform === "win32" - ? `FOR /F "tokens=5" %P IN ('netstat -ano ^| findstr :3000 ^| findstr LISTENING') DO taskkill /F /PID %P` - : `kill -9 ${stdout.trim()}`; - - exec(killCmd, (killErr) => { - if (killErr) { - console.error(`Error killing process: ${killErr.message}`); - } else { - console.log("Killed process on port 3000"); - } + test.beforeAll(async () => { + const serverPath = join(__dirname, "..", "dist", "src", "server.js"); - // Wait a moment for OS to release the port - setTimeout(resolve, 500); - }); + serverProcess = spawn("node", [serverPath], { + stdio: "pipe", + env: { ...process.env, PORT: "3000" } }); - }); -} - -// Helper function to wait for the API server to be available -async function waitForApiServer( - maxRetries = 10, - interval = 1000 -): Promise { - for (let i = 0; i < maxRetries; i++) { - try { - const response = await axios.get(API_URL, { timeout: 2000 }); - if (response.status === 200) { - console.log(`API server is available at ${API_URL}`); - return true; - } - } catch (e) { - console.log( - `API server not available at ${API_URL}, retrying (${i + 1}/${maxRetries})...` - ); - await new Promise((resolve) => setTimeout(resolve, interval)); - } - } - console.warn( - `API server at ${API_URL} not available after ${maxRetries} attempts` - ); - return false; -} - -// Setup and teardown for the whole test suite -test.beforeAll(async () => { - // First check if port 3000 is already in use - if so, try to kill it - const portInUse = await isPortInUse(3000); - if (portInUse) { - console.log( - "Port 3000 is already in use. Attempting to kill the process..." - ); - await killProcessOnPort(); - - // Check again - const stillInUse = await isPortInUse(3000); - if (stillInUse) { - console.log("Failed to free port 3000. Waiting for it to be released..."); - await new Promise((resolve) => setTimeout(resolve, 5000)); - } - } - // Start the server - console.log("Starting server for tests..."); - serverProcess = spawn("node", [join(process.cwd(), "dist/server.js")], { - stdio: "pipe", - detached: true - }); - - // Log server output for debugging and capture the actual port - serverProcess.stdout?.on("data", (data) => { - const output = data.toString(); - console.log(`Server: ${output}`); - - // Check if the output contains the port information - const portMatch = output.match( - /API server running on http:\/\/localhost:(\d+)/ - ); - if (portMatch && portMatch[1]) { - const detectedPort = parseInt(portMatch[1], 10); - if (detectedPort !== 3000) { - console.log( - `Server is running on port ${detectedPort} instead of 3000` - ); - API_URL = `http://localhost:${detectedPort}`; - } - } - }); - - serverProcess.stderr?.on("data", (data) => { - console.error(`Server Error: ${data}`); - }); - - // Wait for server to start and API to be available - console.log("Waiting for server to start..."); - await new Promise((resolve) => setTimeout(resolve, 5000)); - - const apiAvailable = await waitForApiServer(); - if (!apiAvailable) { - console.warn("API server is not available, tests may fail"); - } - - if (apiAvailable) { - // Create a node for the tests - try { - console.log("Creating node for tests..."); - const createNodeResponse = await axios.post( - `${API_URL}/admin/v1/create-node`, - { - defaultBootstrap: false, - networkConfig: { - clusterId: 42, - shards: [0] - }, - pubsubTopics: ["/waku/2/rs/42/0"] // Explicitly configure the pubsub topic - }, - { timeout: 10000 } - ); - - if (createNodeResponse.status === 200) { - console.log("Node creation response:", createNodeResponse.data); - - // Start the node - const startNodeResponse = await axios.post( - `${API_URL}/admin/v1/start-node`, - {}, - { timeout: 5000 } - ); - - if (startNodeResponse.status === 200) { - console.log("Node started successfully"); - } - } - } catch (error) { - console.warn( - "Failed to create/start node through API, some tests may fail:", - error - ); - } - } else { - console.warn( - "Skipping node creation as server doesn't appear to be running" - ); - } -}); - -test.afterAll(async () => { - // Stop the server - console.log("Stopping server..."); - if (serverProcess && serverProcess.pid) { - if (process.platform === "win32") { - spawn("taskkill", ["/pid", serverProcess.pid.toString(), "/f", "/t"]); - } else { - // Ensure the process and all its children are terminated - try { - process.kill(-serverProcess.pid, "SIGINT"); - } catch (e) { - console.log("Server process already terminated"); - } - } - } - - // Verify no processes running on port 3000 - await killProcessOnPort(); + serverProcess.stdout?.on("data", (_data: Buffer) => { + }); - // Give time for all processes to terminate - await new Promise((resolve) => setTimeout(resolve, 1000)); -}); + serverProcess.stderr?.on("data", (_data: Buffer) => { + }); -test.describe("Waku Server API", () => { - // Direct test of filter endpoint - this runs first - test("can directly access filter/v1/messages endpoint", async () => { - // Try with different content topic formats - const testTopics = [ - "test-topic", - "/test/topic", - "%2Ftest%2Ftopic", // Pre-encoded - "%2Ftest%2Ftopic" // Pre-encoded - ]; + await new Promise((resolve) => setTimeout(resolve, 3000)); - for (const topic of testTopics) { - console.log(`Testing direct access with topic: ${topic}`); + let serverReady = false; + for (let i = 0; i < 30; i++) { try { - const response = await axios.get( - `${API_URL}/filter/v1/messages/${topic}`, - { - timeout: 5000, - validateStatus: () => true - } - ); - - console.log(` Status: ${response.status}`); - console.log(` Content-Type: ${response.headers["content-type"]}`); - console.log(` Data: ${JSON.stringify(response.data)}`); - - // If this succeeds, we'll use this topic format for our tests - if (response.status === 200) { - console.log(` Found working topic format: ${topic}`); + const res = await axios.get(`${baseUrl}/`, { timeout: 2000 }); + if (res.status === 200) { + serverReady = true; break; } - } catch (error: any) { - console.error(` Error with topic ${topic}:`, error.message); - if (error.response) { - console.error(` Response status: ${error.response.status}`); - } + } catch { + // Ignore errors } + await new Promise((r) => setTimeout(r, 1000)); } - }); - - // This test checks if the server is running and can serve the basic endpoints - test("can get server status and verify endpoints", async () => { - // Get initial server status with retry mechanism - let initialResponse; - for (let attempt = 0; attempt < 5; attempt++) { - try { - initialResponse = await axios.get(`${API_URL}/`, { - timeout: 5000, - validateStatus: () => true // Accept any status code - }); - if (initialResponse.status === 200) { - break; - } - } catch (e) { - console.log( - `Server not responding on attempt ${attempt + 1}/5, retrying...` - ); - await new Promise((resolve) => setTimeout(resolve, 1000)); - } - } - - // If we still couldn't connect, skip this test - if (!initialResponse || initialResponse.status !== 200) { - console.warn("Server is not responding, skipping endpoint checks"); - test.skip(); - return; - } - - expect(initialResponse.status).toBe(200); - expect(initialResponse.data.status).toBe( - "Waku simulation server is running" - ); - - // Check if key endpoints are available - console.log("Checking if server endpoints are properly registered..."); - - try { - // Try to access the various endpoints with simple HEAD requests - const endpoints = [ - "/info", - "/debug/v1/info", - "/admin/v1/create-node", - "/admin/v1/start-node", - "/admin/v1/stop-node", - "/filter/v1/messages/test-topic", - "/filter/v2/messages/test-topic" - ]; - - for (const endpoint of endpoints) { - try { - const response = await axios.head(`${API_URL}${endpoint}`, { - validateStatus: () => true, // Accept any status code - timeout: 3000 // Short timeout to avoid hanging - }); - - // Some endpoints may return 404 or 405 if they only support specific methods, - // but at least we should get a response if the route is registered - console.log(`Endpoint ${endpoint}: Status ${response.status}`); - - // If we get a 404, the route is not registered - expect(response.status).not.toBe(404); - } catch (error) { - console.warn(`Error checking endpoint ${endpoint}:`, error.message); - // Continue checking other endpoints even if one fails - } - } - } catch (error: any) { - console.error("Error checking endpoints:", error.message); - throw error; - } - }); - - // Test node lifecycle operations using the dedicated endpoints - test("can create, start, and stop a node", async () => { - // 1. Create a new node - const createResponse = await axios.post(`${API_URL}/admin/v1/create-node`, { - defaultBootstrap: true, - networkConfig: { - clusterId: 42, - shards: [0] - }, - pubsubTopics: ["/waku/2/rs/42/0"] // Explicitly configure the pubsub topic - }); - expect(createResponse.status).toBe(200); - expect(createResponse.data.success).toBe(true); - - // 2. Start the node - const startResponse = await axios.post(`${API_URL}/admin/v1/start-node`); - expect(startResponse.status).toBe(200); - expect(startResponse.data.success).toBe(true); - - // 3. Get info to verify it's running - const infoResponse = await axios.get(`${API_URL}/info`); - expect(infoResponse.status).toBe(200); - expect(infoResponse.data.peerId).toBeDefined(); - console.log("Node peer ID:", infoResponse.data.peerId); - // 4. Stop the node - const stopResponse = await axios.post(`${API_URL}/admin/v1/stop-node`); - expect(stopResponse.status).toBe(200); - expect(stopResponse.data.success).toBe(true); - - // 5. Start it again - const restartResponse = await axios.post(`${API_URL}/admin/v1/start-node`); - expect(restartResponse.status).toBe(200); - expect(restartResponse.data.success).toBe(true); - - // 6. Verify it's running again - const finalInfoResponse = await axios.get(`${API_URL}/info`); - expect(finalInfoResponse.status).toBe(200); - expect(finalInfoResponse.data.peerId).toBeDefined(); + expect(serverReady).toBe(true); }); - // This test requires a running node, which we now can properly initialize with our new endpoints - test("can connect to peers and get node info", async () => { - // Create and start a fresh node - await axios.post(`${API_URL}/admin/v1/create-node`, { - defaultBootstrap: false, - networkConfig: { - clusterId: 42, - shards: [0] - }, - pubsubTopics: ["/waku/2/rs/42/0"] // Explicitly configure the pubsub topic - }); - await axios.post(`${API_URL}/admin/v1/start-node`); - - // FilterConnect to peers - const dialResponse = await axios.post(`${API_URL}/admin/v1/peers`, { - peerMultiaddrs: PEERS - }); - - expect(dialResponse.status).toBe(200); - console.log("Peer connection response:", dialResponse.data); - - // Get debug info now that we have a properly initialized node - const debugResponse = await axios.get(`${API_URL}/debug/v1/info`); - expect(debugResponse.status).toBe(200); - expect(debugResponse.data).toBeDefined(); - - // Log protocols available - if (debugResponse.data.protocols) { - const wakuProtocols = debugResponse.data.protocols.filter((p: string) => - p.includes("/waku/") - ); - console.log("Waku protocols:", wakuProtocols); + test.afterAll(async () => { + if (serverProcess) { + serverProcess.kill("SIGTERM"); + await new Promise((resolve) => setTimeout(resolve, 1000)); } }); - test("can push messages", async () => { - // Create and start a fresh node - await axios.post(`${API_URL}/admin/v1/create-node`, { - defaultBootstrap: true, - networkConfig: { - clusterId: 42, - shards: [0] - }, - pubsubTopics: ["/waku/2/rs/42/0"] // Explicitly configure the pubsub topic - }); - await axios.post(`${API_URL}/admin/v1/start-node`); - - // FilterConnect to peers - await axios.post(`${API_URL}/admin/v1/peers`, { - peerMultiaddrs: PEERS - }); - - // Test the REST API format push endpoint - try { - const restPushResponse = await axios.post( - `${API_URL}/lightpush/v1/message`, - { - pubsubTopic: "/waku/2/default-waku/proto", - message: { - contentTopic: "/test/1/message/proto", - payload: Array.from( - new TextEncoder().encode("Test message via REST endpoint") - ) - } - } - ); - - expect(restPushResponse.status).toBe(200); - expect(restPushResponse.data.messageId).toBeDefined(); - console.log("Message ID:", restPushResponse.data.messageId); - } catch (error) { - console.log("REST push might fail if no peers connected:", error); - } + test("server health endpoint", async () => { + const res = await axios.get(`${baseUrl}/`); + expect(res.status).toBe(200); + expect(res.data.status).toBe("Waku simulation server is running"); }); - test("can retrieve messages from the queue", async () => { - // Create and start a fresh node - await axios.post(`${API_URL}/admin/v1/create-node`, { - defaultBootstrap: true, - networkConfig: { - clusterId: 42, - shards: [0] - }, - pubsubTopics: ["/waku/2/rs/42/0"] // Explicitly configure the pubsub topic - }); - await axios.post(`${API_URL}/admin/v1/start-node`); + test("static files are served", async () => { + const htmlRes = await axios.get(`${baseUrl}/app/index.html`); + expect(htmlRes.status).toBe(200); + expect(htmlRes.data).toContain("Waku Test Environment"); - // FilterConnect to peers - await axios.post(`${API_URL}/admin/v1/peers`, { - peerMultiaddrs: PEERS - }); - - // Use a simple content topic to avoid encoding issues - const contentTopic = "test-queue"; - - try { - // Check endpoint existence by checking available routes - console.log("Checking server routes and status..."); - const rootResponse = await axios.get(`${API_URL}/`); - console.log( - "Server root response:", - rootResponse.status, - rootResponse.data - ); - - // First ensure the queue is empty - console.log(`Attempting to get messages from ${contentTopic}...`); - const emptyQueueResponse = await axios.get( - `${API_URL}/filter/v1/messages/${contentTopic}` - ); - expect(emptyQueueResponse.status).toBe(200); - expect(emptyQueueResponse.data.messages).toEqual([]); - } catch (error: any) { - console.error("Error accessing filter endpoint:", error.message); - if (error.response) { - console.error("Response status:", error.response.status); - console.error("Response data:", error.response.data); - } - throw error; - } - - // Simulate adding messages to the queue - const messages = [ - { - payload: Array.from(new TextEncoder().encode("Message 1")), - timestamp: Date.now() - 2000, - contentTopic - }, - { - payload: Array.from(new TextEncoder().encode("Message 2")), - timestamp: Date.now() - 1000, - contentTopic - }, - { - payload: Array.from(new TextEncoder().encode("Message 3")), - timestamp: Date.now(), - contentTopic - } - ]; - - const testMessages = await axios.post(`${API_URL}/execute`, { - functionName: "simulateMessages", - params: [contentTopic, messages] - }); - expect(testMessages.status).toBe(200); - - // Now check if we can retrieve messages - const messagesResponse = await axios.get( - `${API_URL}/filter/v1/messages/${contentTopic}` - ); - expect(messagesResponse.status).toBe(200); - expect(messagesResponse.data.messages.length).toBe(3); - - // Verify message format - const message = messagesResponse.data.messages[0]; - expect(message).toHaveProperty("payload"); - expect(message).toHaveProperty("contentTopic"); - expect(message).toHaveProperty("timestamp"); - expect(message).toHaveProperty("version"); - - // Test pagination - const paginatedResponse = await axios.get( - `${API_URL}/filter/v1/messages/${contentTopic}?pageSize=2` - ); - expect(paginatedResponse.status).toBe(200); - expect(paginatedResponse.data.messages.length).toBe(2); - - // Test sorting order - const ascendingResponse = await axios.get( - `${API_URL}/filter/v1/messages/${contentTopic}?ascending=true` - ); - expect(ascendingResponse.status).toBe(200); - expect(ascendingResponse.data.messages.length).toBe(3); - const timestamps = ascendingResponse.data.messages.map( - (msg: any) => msg.timestamp - ); - expect(timestamps[0]).toBeLessThan(timestamps[1]); - expect(timestamps[1]).toBeLessThan(timestamps[2]); + const jsRes = await axios.get(`${baseUrl}/app/index.js`); + expect(jsRes.status).toBe(200); + expect(jsRes.data).toContain("WakuHeadless"); }); - test("can access filter endpoint for SSE", async () => { - // Create and start a fresh node - only if API is accessible + test("Waku node auto-started", async () => { try { - // Quick check if server is running - await axios.get(API_URL, { timeout: 2000 }); - - // Create node - await axios.post(`${API_URL}/admin/v1/create-node`, { - defaultBootstrap: true, - networkConfig: { - clusterId: 42, - shards: [0] - }, - pubsubTopics: ["/waku/2/rs/42/0"] // Explicitly configure the pubsub topic - }); - - // Start node - await axios.post(`${API_URL}/admin/v1/start-node`); - - // FilterConnect to peers - await axios.post(`${API_URL}/admin/v1/peers`, { - peerMultiaddrs: PEERS - }); - } catch (error) { - console.warn("Server appears to be unreachable, skipping test"); - test.skip(); - return; - } - - const contentTopic = "test-sse"; - - // Verify filter endpoint is accessible - // Instead of implementing a full SSE client, we'll make sure the endpoint - // returns the correct headers and status code which indicates SSE readiness - try { - const sseResponse = await axios - .get( - `${API_URL}/filter/v2/messages/${contentTopic}?clusterId=42&shard=0`, - { - // Set a timeout to avoid hanging the test - timeout: 2000, - // Expecting the request to timeout as SSE keeps connection open - validateStatus: () => true, - // We can't use responseType: 'stream' directly with axios, - // but we can check the response headers - headers: { - Accept: "text/event-stream" - } - } - ) - .catch((e) => { - // We expect a timeout error since SSE keeps connection open - if (e.code === "ECONNABORTED") { - return e.response; - } - throw e; - }); - - // If response exists and has expected SSE headers, the test passes - if (sseResponse) { - expect(sseResponse.headers["content-type"]).toBe("text/event-stream"); - expect(sseResponse.headers["cache-control"]).toBe("no-cache"); - expect(sseResponse.headers["connection"]).toBe("keep-alive"); - } else { - // If no response, we manually make an HTTP request to check the headers - const headers = await new Promise>((resolve) => { - const requestUrl = new URL( - `${API_URL}/filter/v2/messages/${contentTopic}?clusterId=42&shard=0` - ); - const req = http.get(requestUrl, (res) => { - // Only interested in headers - req.destroy(); - if (res.headers) { - resolve(res.headers as Record); - } else { - resolve({}); - } - }); - req.on("error", () => resolve({})); - }); - - if (Object.keys(headers).length === 0) { - console.warn( - "No headers received, SSE endpoint may not be accessible" - ); - test.skip(); - return; - } - - expect(headers["content-type"]).toBe("text/event-stream"); - } - } catch (error) { - console.error("Error during SSE endpoint test:", error); - test.fail(); - return; - } - - console.log("SSE endpoint is accessible with correct headers"); - }); - - // Add a specific test just for the filter/v1/messages endpoint - test("can access filter/v1/messages endpoint directly", async () => { - // Check if server is available first - try { - await axios.get(API_URL, { timeout: 2000 }); - } catch (error) { - console.warn("Server appears to be unreachable, skipping test"); - test.skip(); - return; - } - - // Create a random content topic just for this test - const contentTopic = `direct-filter-${Date.now()}`; - - try { - // Try different approaches to access the endpoint - console.log( - `Testing direct access to filter/v1/messages/${contentTopic}` - ); - - // Method 1: GET request with encoded content topic - const getResponse = await axios({ - method: "get", - url: `${API_URL}/filter/v1/messages/${contentTopic}`, - validateStatus: function () { - // Allow any status code to check what's coming back - return true; - }, - timeout: 5000 - }); - - console.log("Response status:", getResponse.status); - console.log("Response headers:", getResponse.headers); - - if (getResponse.status === 404) { - throw new Error( - `Endpoint not found (404): /filter/v1/messages/${contentTopic}` - ); - } - - // If we got here, the endpoint exists even if it returns empty results - expect(getResponse.status).toBe(200); - expect(getResponse.data).toHaveProperty("messages"); - expect(Array.isArray(getResponse.data.messages)).toBe(true); + const infoRes = await axios.get(`${baseUrl}/waku/v1/peer-info`); + expect(infoRes.status).toBe(200); + expect(infoRes.data.peerId).toBeDefined(); + expect(infoRes.data.multiaddrs).toBeDefined(); } catch (error: any) { - console.error("Error during filter/v1 endpoint test:", error.message); - - if (error.response) { - console.error("Response status:", error.response.status); - console.error("Response headers:", error.response.headers); - console.error("Response data:", error.response.data); - } else if (error.request) { - console.error("No response received:", error.request); - // If no response, we'll skip the test rather than fail it - test.skip(); - return; - } - - throw error; + expect(error.response?.status).toBe(400); } }); }); diff --git a/packages/browser-tests/tests/test-config.ts b/packages/browser-tests/tests/test-config.ts deleted file mode 100644 index a20295a056..0000000000 --- a/packages/browser-tests/tests/test-config.ts +++ /dev/null @@ -1,35 +0,0 @@ -export const NETWORK_CONFIG = { - "waku.sandbox": { - peers: [ - "/dns4/node-01.do-ams3.waku.sandbox.status.im/tcp/30303/p2p/16Uiu2HAmNaeL4p3WEYzC9mgXBmBWSgWjPHRvatZTXnp8Jgv3iKsb", - "/dns4/node-01.gc-us-central1-a.waku.sandbox.status.im/tcp/30303/p2p/16Uiu2HAmRv1iQ3NoMMcjbtRmKxPuYBbF9nLYz2SDv9MTN8WhGuUU", - "/dns4/node-01.ac-cn-hongkong-c.waku.sandbox.status.im/tcp/30303/p2p/16Uiu2HAmQYiojgZ8APsh9wqbWNyCstVhnp9gbeNrxSEQnLJchC92" - ] - }, - - "waku.test": { - peers: [ - "/dns4/node-01.do-ams3.waku.test.status.im/tcp/8000/wss/p2p/16Uiu2HAkykgaECHswi3YKJ5dMLbq2kPVCo89fcyTd38UcQD6ej5W", - "/dns4/node-01.gc-us-central1-a.waku.test.status.im/tcp/8000/wss/p2p/16Uiu2HAmDCp8XJ9z1ev18zuv8NHekAsjNyezAvmMfFEJkiharitG", - "/dns4/node-01.ac-cn-hongkong-c.waku.test.status.im/tcp/8000/wss/p2p/16Uiu2HAkzHaTP5JsUwfR9NR8Rj9HC24puS6ocaU8wze4QrXr9iXp" - ] - }, - - networkConfig: { - clusterId: 1, - shards: [0] - }, - - // Default node configuration - defaultNodeConfig: { - defaultBootstrap: false - }, - - // Test message configuration - testMessage: { - contentTopic: "/test/1/message/proto", - payload: "Hello, Waku!" - } -}; - -export const ACTIVE_PEERS = NETWORK_CONFIG["waku.test"].peers; \ No newline at end of file diff --git a/packages/browser-tests/tests/utils/container-helpers.ts b/packages/browser-tests/tests/utils/container-helpers.ts new file mode 100644 index 0000000000..32842f5b88 --- /dev/null +++ b/packages/browser-tests/tests/utils/container-helpers.ts @@ -0,0 +1,122 @@ +import axios from "axios"; +import { GenericContainer, StartedTestContainer } from "testcontainers"; + +export interface ContainerSetupOptions { + environment?: Record; + networkMode?: string; + timeout?: number; + maxAttempts?: number; +} + +export interface ContainerSetupResult { + container: StartedTestContainer; + baseUrl: string; +} + +/** + * Starts a waku-browser-tests Docker container with proper health checking. + * Follows patterns from @waku/tests package for retry logic and cleanup. + */ +export async function startBrowserTestsContainer( + options: ContainerSetupOptions = {} +): Promise { + const { + environment = {}, + networkMode = "bridge", + timeout = 2000, + maxAttempts = 60 + } = options; + + console.log("Starting waku-browser-tests container..."); + + let generic = new GenericContainer("waku-browser-tests:local") + .withExposedPorts(8080) + .withNetworkMode(networkMode); + + // Apply environment variables + for (const [key, value] of Object.entries(environment)) { + generic = generic.withEnvironment({ [key]: value }); + } + + const container = await generic.start(); + + // Set up container logging + await new Promise((r) => setTimeout(r, 5000)); + const logs = await container.logs({ tail: 100 }); + logs.on("data", (b) => process.stdout.write("[container] " + b.toString())); + logs.on("error", (err) => console.error("[container log error]", err)); + + const mappedPort = container.getMappedPort(8080); + const baseUrl = `http://127.0.0.1:${mappedPort}`; + + // Wait for server readiness with retry logic (following waku/tests patterns) + const serverReady = await waitForServerReady(baseUrl, maxAttempts, timeout); + + if (!serverReady) { + await logFinalContainerState(container); + throw new Error("Container failed to become ready"); + } + + console.log("✅ Browser tests container ready"); + await new Promise((r) => setTimeout(r, 500)); // Final settling time + + return { container, baseUrl }; +} + +/** + * Waits for server to become ready with exponential backoff and detailed logging. + * Follows retry patterns from @waku/tests ServiceNode. + */ +async function waitForServerReady( + baseUrl: string, + maxAttempts: number, + timeout: number +): Promise { + for (let i = 0; i < maxAttempts; i++) { + try { + const res = await axios.get(`${baseUrl}/`, { timeout }); + if (res.status === 200) { + console.log(`Server is ready after ${i + 1} attempts`); + return true; + } + } catch (error: any) { + if (i % 10 === 0) { + console.log(`Attempt ${i + 1}/${maxAttempts} failed:`, error.code || error.message); + } + } + await new Promise((r) => setTimeout(r, 1000)); + } + return false; +} + +/** + * Logs final container state for debugging, following waku/tests error handling patterns. + */ +async function logFinalContainerState(container: StartedTestContainer): Promise { + try { + const finalLogs = await container.logs({ tail: 50 }); + console.log("=== Final Container Logs ==="); + finalLogs.on("data", (b) => console.log(b.toString())); + await new Promise((r) => setTimeout(r, 1000)); + } catch (logError) { + console.error("Failed to get container logs:", logError); + } +} + +/** + * Gracefully stops containers with retry logic, following teardown patterns from waku/tests. + */ +export async function stopContainer(container: StartedTestContainer): Promise { + if (!container) return; + + console.log("Stopping container gracefully..."); + try { + await container.stop({ timeout: 10000 }); + console.log("Container stopped successfully"); + } catch (error) { + console.warn( + "Container stop had issues (expected):", + (error as any).message + ); + } +} \ No newline at end of file diff --git a/packages/browser-tests/tests/utils/index.ts b/packages/browser-tests/tests/utils/index.ts new file mode 100644 index 0000000000..8965565ef9 --- /dev/null +++ b/packages/browser-tests/tests/utils/index.ts @@ -0,0 +1,8 @@ +/** + * Shared test utilities for browser-tests package. + * Follows patterns established in @waku/tests package. + */ + +export * from "./container-helpers.js"; +export * from "./nwaku-helpers.js"; +export * from "./test-config.js"; \ No newline at end of file diff --git a/packages/browser-tests/tests/utils/nwaku-helpers.ts b/packages/browser-tests/tests/utils/nwaku-helpers.ts new file mode 100644 index 0000000000..e9595f9c0c --- /dev/null +++ b/packages/browser-tests/tests/utils/nwaku-helpers.ts @@ -0,0 +1,125 @@ +import { ServiceNode, ServiceNodesFleet } from "@waku/tests"; +import { DefaultTestRoutingInfo } from "@waku/tests"; + +/** + * Creates a two-node nwaku network following waku/tests patterns. + * Node 1: Relay + Light Push (service provider) + * Node 2: Relay only (network peer) + */ +export async function createTwoNodeNetwork(): Promise { + console.log("Creating nwaku node 1 (Relay + Light Push)..."); + const lightPushNode = new ServiceNode("lightpush-node-" + Math.random().toString(36).substring(7)); + + const lightPushArgs = { + relay: true, + lightpush: true, + filter: false, + store: false, + clusterId: DefaultTestRoutingInfo.clusterId, + numShardsInNetwork: DefaultTestRoutingInfo.networkConfig.numShardsInCluster, + contentTopic: [DefaultTestRoutingInfo.contentTopic] + }; + + await lightPushNode.start(lightPushArgs, { retries: 3 }); + + console.log("Creating nwaku node 2 (Relay only)..."); + const relayNode = new ServiceNode("relay-node-" + Math.random().toString(36).substring(7)); + + // Connect second node to first node (following ServiceNodesFleet pattern) + const firstNodeAddr = await lightPushNode.getExternalMultiaddr(); + const relayArgs = { + relay: true, + lightpush: false, + filter: false, + store: false, + staticnode: firstNodeAddr, + clusterId: DefaultTestRoutingInfo.clusterId, + numShardsInNetwork: DefaultTestRoutingInfo.networkConfig.numShardsInCluster, + contentTopic: [DefaultTestRoutingInfo.contentTopic] + }; + + await relayNode.start(relayArgs, { retries: 3 }); + + // Wait for network formation (following waku/tests timing patterns) + console.log("Waiting for nwaku network formation..."); + await new Promise((r) => setTimeout(r, 5000)); + + // Verify connectivity (optional, for debugging) + await verifyNetworkFormation([lightPushNode, relayNode]); + + // Return ServiceNodesFleet-compatible object + return { + nodes: [lightPushNode, relayNode], + messageCollector: null as any // Not needed for these tests + } as any; +} + +/** + * Verifies that nwaku nodes have formed connections. + * Follows error handling patterns from waku/tests. + */ +async function verifyNetworkFormation(nodes: ServiceNode[]): Promise { + try { + const peerCounts = await Promise.all( + nodes.map(async (node, index) => { + const peers = await node.peers(); + console.log(`Node ${index + 1} has ${peers.length} peer(s)`); + return peers.length; + }) + ); + + if (peerCounts.every(count => count === 0)) { + console.warn("⚠️ Nodes may not be properly connected yet"); + } + } catch (error) { + console.warn("Could not verify peer connections:", error); + } +} + +/** + * Extracts Docker-accessible multiaddr from nwaku node. + * Returns multiaddr using container's internal IP for Docker network communication. + */ +export async function getDockerAccessibleMultiaddr(node: ServiceNode): Promise { + // Get multiaddr with localhost and extract components + const localhostMultiaddr = await node.getMultiaddrWithId(); + const peerId = await node.getPeerId(); + + // Extract port from multiaddr string + const multiaddrStr = localhostMultiaddr.toString(); + const portMatch = multiaddrStr.match(/\/tcp\/(\d+)/); + const port = portMatch ? portMatch[1] : null; + + if (!port) { + throw new Error("Could not extract port from multiaddr: " + multiaddrStr); + } + + // Get Docker container IP (accessing private field safely) + const containerIp = (node as any).docker?.containerIp; + if (!containerIp) { + throw new Error("Could not get container IP from node"); + } + + // Build Docker network accessible multiaddr + const dockerMultiaddr = `/ip4/${containerIp}/tcp/${port}/ws/p2p/${peerId}`; + + console.log("Original multiaddr:", multiaddrStr); + console.log("Docker accessible multiaddr:", dockerMultiaddr); + + return dockerMultiaddr; +} + +/** + * Stops nwaku nodes with retry logic, following teardown patterns from waku/tests. + */ +export async function stopNwakuNodes(nodes: ServiceNode[]): Promise { + if (!nodes || nodes.length === 0) return; + + console.log("Stopping nwaku nodes..."); + try { + await Promise.all(nodes.map(node => node.stop())); + console.log("Nwaku nodes stopped successfully"); + } catch (error) { + console.warn("Nwaku nodes stop had issues:", (error as any).message); + } +} diff --git a/packages/browser-tests/tests/utils/test-config.ts b/packages/browser-tests/tests/utils/test-config.ts new file mode 100644 index 0000000000..18e14d684a --- /dev/null +++ b/packages/browser-tests/tests/utils/test-config.ts @@ -0,0 +1,95 @@ +import { expect } from "@playwright/test"; +import { DefaultTestRoutingInfo } from "@waku/tests"; + +/** + * Common test configuration constants following waku/tests patterns. + */ +export const TEST_CONFIG = { + // Test timeouts (following waku/tests timeout patterns) + DEFAULT_TEST_TIMEOUT: 120000, // 2 minutes + CONTAINER_READY_TIMEOUT: 60000, // 1 minute + NETWORK_FORMATION_DELAY: 5000, // 5 seconds + SUBSCRIPTION_DELAY: 3000, // 3 seconds + MESSAGE_PROPAGATION_DELAY: 5000, // 5 seconds + WAKU_INIT_DELAY: 8000, // 8 seconds + + // Network configuration + DEFAULT_CLUSTER_ID: DefaultTestRoutingInfo.clusterId.toString(), + DEFAULT_CONTENT_TOPIC: "/test/1/browser-tests/proto", + + // Test messages + DEFAULT_TEST_MESSAGE: "Hello from browser tests", +} as const; + +/** + * Environment variable builders for different test scenarios. + */ +export const ENV_BUILDERS = { + /** + * Environment for production ENR bootstrap (integration test pattern). + */ + withProductionEnr: () => ({ + WAKU_ENR_BOOTSTRAP: "enr:-QEnuEBEAyErHEfhiQxAVQoWowGTCuEF9fKZtXSd7H_PymHFhGJA3rGAYDVSHKCyJDGRLBGsloNbS8AZF33IVuefjOO6BIJpZIJ2NIJpcIQS39tkim11bHRpYWRkcnO4lgAvNihub2RlLTAxLmRvLWFtczMud2FrdXYyLnRlc3Quc3RhdHVzaW0ubmV0BgG73gMAODcxbm9kZS0wMS5hYy1jbi1ob25na29uZy1jLndha3V2Mi50ZXN0LnN0YXR1c2ltLm5ldAYBu94DACm9A62t7AQL4Ef5ZYZosRpQTzFVAB8jGjf1TER2wH-0zBOe1-MDBNLeA4lzZWNwMjU2azGhAzfsxbxyCkgCqq8WwYsVWH7YkpMLnU2Bw5xJSimxKav-g3VkcIIjKA", + WAKU_CLUSTER_ID: "1", + }), + + /** + * Environment for local nwaku node connection (e2e test pattern). + */ + withLocalLightPush: (lightpushMultiaddr: string) => ({ + WAKU_LIGHTPUSH_NODE: lightpushMultiaddr, + WAKU_CLUSTER_ID: TEST_CONFIG.DEFAULT_CLUSTER_ID, + }), +}; + +/** + * Test assertion helpers following waku/tests verification patterns. + */ +export const ASSERTIONS = { + /** + * Verifies server health response structure. + */ + serverHealth: (response: any) => { + expect(response.status).toBe(200); + expect(response.data.status).toBe("Waku simulation server is running"); + }, + + /** + * Verifies peer info response structure. + */ + peerInfo: (response: any) => { + expect(response.status).toBe(200); + expect(response.data.peerId).toBeDefined(); + expect(typeof response.data.peerId).toBe("string"); + }, + + /** + * Verifies lightpush response structure (v3 format). + */ + lightPushV3Success: (response: any) => { + expect(response.status).toBe(200); + expect(response.data).toHaveProperty('success', true); + expect(response.data).toHaveProperty('result'); + expect(response.data.result).toHaveProperty('successes'); + expect(Array.isArray(response.data.result.successes)).toBe(true); + expect(response.data.result.successes.length).toBeGreaterThan(0); + }, + + /** + * Verifies message content and structure. + */ + messageContent: (message: any, expectedContent: string, expectedTopic: string) => { + expect(message).toHaveProperty('contentTopic', expectedTopic); + expect(message).toHaveProperty('payload'); + expect(typeof message.payload).toBe('string'); + + const receivedPayload = Buffer.from(message.payload, 'base64').toString(); + expect(receivedPayload).toBe(expectedContent); + + // Optional fields + expect(message).toHaveProperty('version'); + if (message.timestamp) { + expect(['bigint', 'number']).toContain(typeof message.timestamp); + } + }, +}; \ No newline at end of file diff --git a/packages/browser-tests/tsconfig.json b/packages/browser-tests/tsconfig.json index abf2b61f89..6903a40abb 100644 --- a/packages/browser-tests/tsconfig.json +++ b/packages/browser-tests/tsconfig.json @@ -15,5 +15,5 @@ "typeRoots": ["./node_modules/@types", "./types"] }, "include": ["src/server.ts", "types/**/*.d.ts"], - "exclude": ["node_modules", "dist"] + "exclude": ["node_modules", "dist", "web"] } diff --git a/packages/browser-tests/types/global.d.ts b/packages/browser-tests/types/global.d.ts index 5e0b68cbce..73c02e9724 100644 --- a/packages/browser-tests/types/global.d.ts +++ b/packages/browser-tests/types/global.d.ts @@ -1,27 +1,14 @@ -import { LightNode } from "@waku/sdk"; -import { IWakuNode } from "../src/api/common.js"; -import { - createWakuNode, - dialPeers, - getDebugInfo, - getPeerInfo, - pushMessage, - subscribe -} from "../src/api/shared.js"; +import type { WakuHeadless } from "../web/index.js"; + +export interface ITestBrowser extends Window { + wakuApi: WakuHeadless; + __WAKU_NETWORK_CONFIG?: any; + __WAKU_LIGHTPUSH_NODE?: string | null; + __WAKU_ENR_BOOTSTRAP?: string | null; +} -// Define types for the Waku node and window declare global { - // eslint-disable-next-line no-unused-vars interface Window { - waku: IWakuNode & LightNode; - wakuAPI: { - getPeerInfo: typeof getPeerInfo; - getDebugInfo: typeof getDebugInfo; - pushMessage: typeof pushMessage; - dialPeers: typeof dialPeers; - createWakuNode: typeof createWakuNode; - subscribe: typeof subscribe; - [key: string]: any; - }; + wakuApi: WakuHeadless; } } diff --git a/packages/browser-tests/types/serve.d.ts b/packages/browser-tests/types/serve.d.ts index f35d627c51..47ff4758f2 100644 --- a/packages/browser-tests/types/serve.d.ts +++ b/packages/browser-tests/types/serve.d.ts @@ -1,7 +1,7 @@ declare module "serve" { function serve( folder: string, - options: { port: number; single: boolean; listen: boolean } + options: { port: number; single: boolean; listen: boolean }, ): any; export default serve; } diff --git a/packages/browser-tests/web/index.html b/packages/browser-tests/web/index.html new file mode 100644 index 0000000000..8f8d0aa647 --- /dev/null +++ b/packages/browser-tests/web/index.html @@ -0,0 +1,14 @@ + + + + + + Waku Test Environment + + +

Waku Test Environment

+ + + + + diff --git a/packages/browser-tests/web/index.ts b/packages/browser-tests/web/index.ts new file mode 100644 index 0000000000..aea8fb8d81 --- /dev/null +++ b/packages/browser-tests/web/index.ts @@ -0,0 +1,420 @@ +import { + createLightNode, + LightNode, + Protocols, + NetworkConfig, + CreateNodeOptions, +} from "@waku/sdk"; +import { + AutoSharding, + DEFAULT_CLUSTER_ID, + DEFAULT_NUM_SHARDS, + IMessage, + ShardId, + StaticSharding, +} from "@waku/interfaces"; +import { bootstrap } from "@libp2p/bootstrap"; +import { EnrDecoder, TransportProtocol } from "@waku/enr"; +import type { ITestBrowser } from "../types/global.js"; +import { StaticShardingRoutingInfo } from "@waku/utils"; +import { messageHashStr } from "@waku/core"; + +export interface SerializableSDKProtocolResult { + successes: string[]; + failures: Array<{ + error: string; + peerId?: string; + }>; + myPeerId?: string; + messageHash?: string; +} + +function makeSerializable(result: any): SerializableSDKProtocolResult { + return { + ...result, + successes: result.successes.map((peerId: any) => peerId.toString()), + failures: result.failures.map((failure: any) => ({ + error: failure.error || failure.toString(), + peerId: failure.peerId ? failure.peerId.toString() : undefined, + })), + }; +} + +async function convertEnrToMultiaddrs(enrString: string): Promise { + try { + const enr = await EnrDecoder.fromString(enrString); + const allMultiaddrs = enr.getAllLocationMultiaddrs(); + const multiaddrs: string[] = []; + + for (const multiaddr of allMultiaddrs) { + const maStr = multiaddr.toString(); + multiaddrs.push(maStr); + } + if (multiaddrs.length === 0) { + const tcpMultiaddr = enr.getFullMultiaddr(TransportProtocol.TCP); + if (tcpMultiaddr) { + const tcpStr = tcpMultiaddr.toString(); + multiaddrs.push(tcpStr); + } + const udpMultiaddr = enr.getFullMultiaddr(TransportProtocol.UDP); + if (udpMultiaddr) { + const udpStr = udpMultiaddr.toString(); + multiaddrs.push(udpStr); + } + } + + return multiaddrs; + } catch (error) { + return []; + } +} + +export class WakuHeadless { + waku: LightNode | null; + networkConfig: NetworkConfig; + lightpushNode: string | null; + enrBootstrap: string | null; + constructor( + networkConfig?: Partial, + lightpushNode?: string | null, + enrBootstrap?: string | null, + ) { + this.waku = null as unknown as LightNode; + this.networkConfig = this.buildNetworkConfig(networkConfig); + console.log("Network config on construction:", this.networkConfig); + this.lightpushNode = lightpushNode || null; + this.enrBootstrap = enrBootstrap || null; + + if (this.lightpushNode) { + console.log(`Configured preferred lightpush node: ${this.lightpushNode}`); + } + if (this.enrBootstrap) { + console.log(`Configured ENR bootstrap: ${this.enrBootstrap}`); + } + } + + private shouldUseCustomBootstrap(options: CreateNodeOptions): boolean { + const hasEnr = Boolean(this.enrBootstrap); + const isDefaultBootstrap = Boolean(options.defaultBootstrap); + + return hasEnr && !isDefaultBootstrap; + } + + private async getBootstrapMultiaddrs(): Promise { + if (!this.enrBootstrap) { + return []; + } + + const enrList = this.enrBootstrap.split(",").map((enr) => enr.trim()); + const allMultiaddrs: string[] = []; + + for (const enr of enrList) { + const multiaddrs = await convertEnrToMultiaddrs(enr); + if (multiaddrs.length > 0) { + allMultiaddrs.push(...multiaddrs); + } + } + + return allMultiaddrs; + } + + private buildNetworkConfig( + providedConfig?: Partial, + ): NetworkConfig { + const clusterId = providedConfig?.clusterId ?? DEFAULT_CLUSTER_ID; + + const staticShards = (providedConfig as any)?.shards; + if ( + staticShards && + Array.isArray(staticShards) && + staticShards.length > 0 + ) { + console.log("Using static sharding with shards:", staticShards); + return { + clusterId, + } as StaticSharding; + } + + const numShardsInCluster = + (providedConfig as any)?.numShardsInCluster ?? DEFAULT_NUM_SHARDS; + console.log( + "Using auto sharding with num shards in cluster:", + numShardsInCluster, + ); + return { + clusterId, + numShardsInCluster, + } as AutoSharding; + } + + async pushMessageV3( + contentTopic: string, + payload: string, + pubsubTopic: string, + ): Promise { + if (!this.waku) { + throw new Error("Waku node not started"); + } + console.log( + "Pushing message via v3 lightpush:", + contentTopic, + payload, + pubsubTopic, + ); + console.log("Waku node:", this.waku); + console.log("Network config:", this.networkConfig); + + let processedPayload: Uint8Array; + try { + const binaryString = atob(payload); + const bytes = new Uint8Array(binaryString.length); + for (let i = 0; i < binaryString.length; i++) { + bytes[i] = binaryString.charCodeAt(i); + } + processedPayload = bytes; + } catch (e) { + processedPayload = new TextEncoder().encode(payload); + } + + const message: IMessage = { + payload: processedPayload, + timestamp: new Date(), + }; + + try { + const lightPush = this.waku.lightPush; + if (!lightPush) { + throw new Error("Lightpush service not available"); + } + + let shardId: ShardId | undefined; + if (pubsubTopic) { + const staticShardingRoutingInfo = + StaticShardingRoutingInfo.fromPubsubTopic( + pubsubTopic, + this.networkConfig as StaticSharding, + ); + shardId = staticShardingRoutingInfo?.shardId; + } + + const encoder = this.waku.createEncoder({ + contentTopic, + shardId, + }); + console.log("Encoder:", encoder); + console.log("Pubsub topic:", pubsubTopic); + console.log("Encoder pubsub topic:", encoder.pubsubTopic); + + const protoObj = await encoder.toProtoObj(message); + if (!protoObj) { + throw new Error("Failed to convert message to proto object"); + } + + if (pubsubTopic && pubsubTopic !== encoder.pubsubTopic) { + console.warn( + `Explicit pubsubTopic ${pubsubTopic} provided, but auto-sharding determined ${encoder.pubsubTopic}. Using auto-sharding.`, + ); + } + + let result; + if (this.lightpushNode) { + try { + const preferredPeerId = this.getPeerIdFromMultiaddr( + this.lightpushNode, + ); + if (preferredPeerId) { + result = await lightPush.send(encoder, message); + console.log("✅ Message sent via preferred lightpush node"); + } else { + throw new Error( + "Could not extract peer ID from preferred node address", + ); + } + } catch (error) { + console.error( + "Couldn't send message via preferred lightpush node:", + error, + ); + result = await lightPush.send(encoder, message); + } + } else { + result = await lightPush.send(encoder, message); + } + + const serializableResult = makeSerializable(result); + + serializableResult.myPeerId = this.waku.libp2p.peerId.toString(); + + const messageHash = '0x' + messageHashStr( + encoder.pubsubTopic, + protoObj, + ); + + console.log("Message hash:", messageHash); + + serializableResult.messageHash = messageHash; + + return serializableResult; + } catch (error) { + console.error("Error sending message via v3 lightpush:", error); + throw new Error( + `Failed to send v3 message: ${error instanceof Error ? error.message : String(error)}`, + ); + } + } + + async waitForPeers( + timeoutMs: number = 10000, + protocols: Protocols[] = [Protocols.LightPush, Protocols.Filter], + ) { + if (!this.waku) { + throw new Error("Waku node not started"); + } + + const startTime = Date.now(); + + try { + await this.waku.waitForPeers(protocols, timeoutMs); + const elapsed = Date.now() - startTime; + + const peers = this.waku.libp2p.getPeers(); + + return { + success: true, + peersFound: peers.length, + protocolsRequested: protocols, + timeElapsed: elapsed, + }; + } catch (error) { + const elapsed = Date.now() - startTime; + console.error(`Failed to find peers after ${elapsed}ms:`, error); + throw error; + } + } + + async createWakuNode(options: CreateNodeOptions) { + try { + if (this.waku) { + await this.waku.stop(); + } + } catch (e) { + console.warn("ignore previous waku stop error"); + } + + // if (options.networkConfig) { + // this.networkConfig = options.networkConfig; + // console.log("Network config on createWakuNode:", this.networkConfig); + // } + + let libp2pConfig: any = { + ...options.libp2p, + filterMultiaddrs: false, + }; + + if (this.enrBootstrap) { + const multiaddrs = await this.getBootstrapMultiaddrs(); + + if (multiaddrs.length > 0) { + libp2pConfig.peerDiscovery = [ + bootstrap({ list: multiaddrs }), + ...(options.libp2p?.peerDiscovery || []), + ]; + } + } + + const createOptions = { + ...options, + networkConfig: this.networkConfig, + libp2p: libp2pConfig, + }; + + this.waku = await createLightNode(createOptions); + return { success: true }; + } + + async startNode() { + if (!this.waku) { + throw new Error("Waku node not created"); + } + await this.waku.start(); + + if (this.lightpushNode) { + await this.dialPreferredLightpushNode(); + } + + return { success: true }; + } + + private async dialPreferredLightpushNode() { + if (!this.waku || !this.lightpushNode) { + return; + } + + try { + await this.waku.dial(this.lightpushNode); + } catch { + // Ignore dial errors + console.warn( + "Failed to dial preferred lightpush node:", + this.lightpushNode, + ); + } + } + + private getPeerIdFromMultiaddr(multiaddr: string): string | null { + const parts = multiaddr.split("/"); + const p2pIndex = parts.indexOf("p2p"); + return p2pIndex !== -1 && p2pIndex + 1 < parts.length + ? parts[p2pIndex + 1] + : null; + } + + async stopNode() { + if (!this.waku) { + throw new Error("Waku node not created"); + } + await this.waku.stop(); + return { success: true }; + } + + getPeerInfo() { + if (!this.waku) { + throw new Error("Waku node not started"); + } + + const addrs = this.waku.libp2p.getMultiaddrs(); + return { + peerId: this.waku.libp2p.peerId.toString(), + multiaddrs: addrs.map((a: any) => a.toString()), + peers: [], + }; + } +} + +(() => { + try { + console.log("Initializing WakuHeadless..."); + + const testWindow = window as ITestBrowser; + const globalNetworkConfig = testWindow.__WAKU_NETWORK_CONFIG; + const globalLightpushNode = testWindow.__WAKU_LIGHTPUSH_NODE; + const globalEnrBootstrap = testWindow.__WAKU_ENR_BOOTSTRAP; + + const instance = new WakuHeadless( + globalNetworkConfig, + globalLightpushNode, + globalEnrBootstrap, + ); + + testWindow.wakuApi = instance; + console.log("WakuHeadless initialized successfully:", !!testWindow.wakuApi); + } catch (error) { + console.error("Error initializing WakuHeadless:", error); + const testWindow = window as ITestBrowser; + testWindow.wakuApi = { + start: () => + Promise.reject(new Error("WakuHeadless failed to initialize")), + error: error, + } as any; + } +})(); diff --git a/packages/headless-tests/.eslintrc.cjs b/packages/headless-tests/.eslintrc.cjs deleted file mode 100644 index d4383bc136..0000000000 --- a/packages/headless-tests/.eslintrc.cjs +++ /dev/null @@ -1,34 +0,0 @@ -module.exports = { - root: true, - env: { - browser: true, - node: true, - es2021: true - }, - plugins: ["import"], - extends: ["eslint:recommended"], - parserOptions: { - ecmaVersion: 2022, - sourceType: "module" - }, - rules: { - // Disable rules that might cause issues with this package - "no-undef": "off" - }, - ignorePatterns: [ - "node_modules", - "build", - "coverage" - ], - overrides: [ - { - files: ["*.spec.ts", "**/test_utils/*.ts", "*.js", "*.cjs"], - rules: { - "@typescript-eslint/no-non-null-assertion": "off", - "@typescript-eslint/no-explicit-any": "off", - "no-console": "off", - "import/no-extraneous-dependencies": ["error", { "devDependencies": true }] - } - } - ] -}; diff --git a/packages/headless-tests/README.md b/packages/headless-tests/README.md deleted file mode 100644 index 1ee1b340f8..0000000000 --- a/packages/headless-tests/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# Waku Headless Tests - -This package contains a minimal browser application used for testing the Waku SDK in a browser environment. It is used by the browser-tests package to run end-to-end tests on the SDK. - -## Usage - -### Build the app - -```bash -npm run build -``` - -### Start the app - -```bash -npm start -``` - -This will start a server on port 8080 by default. - -## Integration with browser-tests - -This package is designed to be used with the browser-tests package to run end-to-end tests on the SDK. It exposes the Waku API via a global object in the browser. diff --git a/packages/headless-tests/favicon.ico b/packages/headless-tests/favicon.ico deleted file mode 100644 index 74cf5df7f8..0000000000 Binary files a/packages/headless-tests/favicon.ico and /dev/null differ diff --git a/packages/headless-tests/favicon.png b/packages/headless-tests/favicon.png deleted file mode 100644 index f4cab92fbe..0000000000 Binary files a/packages/headless-tests/favicon.png and /dev/null differ diff --git a/packages/headless-tests/index.html b/packages/headless-tests/index.html deleted file mode 100644 index 44d2db8c07..0000000000 --- a/packages/headless-tests/index.html +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - Headless - - - - - - - -
-
-
-

Status:

- -
- Peer's information - -

Content topic

-

- -

Local Peer Id

-

- -

Remote Peer Id

-

-
-
- -
- - -
- - - - diff --git a/packages/headless-tests/index.js b/packages/headless-tests/index.js deleted file mode 100644 index 6349f639d8..0000000000 --- a/packages/headless-tests/index.js +++ /dev/null @@ -1,14 +0,0 @@ -/* eslint-disable */ -import { API } from "../browser-tests/src/api/shared.ts"; - -runApp().catch((err) => { - console.error(err); -}); - -async function runApp() { - if (typeof window !== "undefined") { - // Expose shared API functions for browser communication - window.wakuAPI = API; - window.subscriptions = []; - } -} diff --git a/packages/headless-tests/manifest.json b/packages/headless-tests/manifest.json deleted file mode 100644 index 6fafb2c8d0..0000000000 --- a/packages/headless-tests/manifest.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "Light Chat", - "description": "Send messages between several users (or just one) using light client targeted protocols.", - "icons": [ - { - "src": "favicon.ico", - "sizes": "64x64 32x32 24x24 16x16", - "type": "image/x-icon" - }, - { - "src": "favicon.png", - "type": "image/png", - "sizes": "192x192" - } - ], - "display": "standalone", - "theme_color": "#ffffff", - "background_color": "#ffffff" -} diff --git a/packages/headless-tests/package.json b/packages/headless-tests/package.json deleted file mode 100644 index 7dd56fd72a..0000000000 --- a/packages/headless-tests/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "@waku/headless-tests", - "version": "0.1.0", - "private": true, - "homepage": "/headless", - "type": "module", - "devDependencies": { - "@babel/core": "^7.24.0", - "@babel/preset-env": "^7.24.0", - "@babel/preset-typescript": "^7.23.3", - "babel-loader": "^9.1.3", - "filter-obj": "^2.0.2", - "it-first": "^3.0.9", - "node-polyfill-webpack-plugin": "^2.0.1", - "serve": "^14.1.2", - "webpack": "^5.99.5", - "webpack-cli": "^5.1.4" - }, - "dependencies": { - "@waku/sdk": "^0.0.30" - }, - "scripts": { - "start": "serve .", - "build": "webpack", - "format": "eslint --fix webpack.config.js" - } -} diff --git a/packages/headless-tests/style.css b/packages/headless-tests/style.css deleted file mode 100644 index ff54ed113e..0000000000 --- a/packages/headless-tests/style.css +++ /dev/null @@ -1,153 +0,0 @@ -* { - margin: 0; - padding: 0; - word-wrap: break-word; - box-sizing: border-box; -} - -html, body { - width: 100%; - height: 100%; - max-width: 100%; - max-height: 100%; -} - -html { - font-size: 16px; - overflow: hidden; -} - -body { - display: flex; - align-items: center; - padding: 10px; - justify-content: center; -} - -details { - margin-bottom: 15px; -} - -details p { - margin-bottom: 10px; -} - -summary { - cursor: pointer; - max-width: 100%; - margin-bottom: 5px; -} - -span { - font-weight: 300; -} - -input, textarea { - line-height: 1rem; - padding: 5px; -} - -textarea { - min-height: 3rem; -} - -h3 { - margin-bottom: 5px; -} - -.content { - width: 800px; - min-width: 300px; - max-width: 800px; - height: 100%; - display: flex; - flex-direction: column; - align-content: space-between; -} - -#messages { - overflow-y: scroll; - overflow-x: hidden; -} - -.message + .message { - margin-top: 15px; -} - -.message :first-child { - font-weight: bold; -} - -.message p + p { - margin-top: 5px; -} - -.message span { - font-size: 0.8rem; -} - -.inputArea { - display: flex; - gap: 10px; - flex-direction: column; - margin-top: 20px; -} - -.controls { - margin-top: 10px; - display: flex; - gap: 10px; -} - -.controls button { - flex-grow: 1; - cursor: pointer; - padding: 10px; -} - -#send { - background-color: #32d1a0; - border: none; - color: white; -} -#send:hover { - background-color: #3abd96; -} -#send:active { - background-color: #3ba183; -} - -#exit { - color: white; - border: none; - background-color: #ff3a31; -} -#exit:hover { - background-color: #e4423a; -} -#exit:active { - background-color: #c84740; -} - -.success { - color: #3ba183; -} - -.progress { - color: #9ea13b; -} - -.terminated { - color: black; -} - -.error { - color: #c84740; -} - -.footer { - display: flex; - width: 100%; - flex-direction: column; - align-self: flex-end; -} diff --git a/packages/headless-tests/tsconfig.json b/packages/headless-tests/tsconfig.json deleted file mode 100644 index a015324b34..0000000000 --- a/packages/headless-tests/tsconfig.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "compilerOptions": { - "target": "es2020", - "module": "commonjs", - "allowJs": true, - "checkJs": false, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true - }, - "include": [ - "**/*.js" - ] -} diff --git a/packages/headless-tests/webpack.config.js b/packages/headless-tests/webpack.config.js deleted file mode 100644 index 9b85739a5e..0000000000 --- a/packages/headless-tests/webpack.config.js +++ /dev/null @@ -1,47 +0,0 @@ -/* eslint-disable */ -/** - * This webpack configuration file uses ES Module syntax. - */ -import path from 'path'; -import { fileURLToPath } from 'url'; -import NodePolyfillPlugin from 'node-polyfill-webpack-plugin'; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -export default { - entry: "./index.js", - output: { - filename: "bundle.js", - path: path.resolve(__dirname, "build") - }, - mode: "production", - target: "web", - plugins: [new NodePolyfillPlugin()], - resolve: { - extensions: [".js", ".ts", ".tsx", ".jsx"], - fallback: { - fs: false, - net: false, - tls: false - }, - alias: { - // Create an alias to easily import from src - "@src": path.resolve(__dirname, "../src") - } - }, - module: { - rules: [ - { - test: /\.(js|ts|tsx)$/, - exclude: /node_modules/, - use: { - loader: "babel-loader", - options: { - presets: ["@babel/preset-env", "@babel/preset-typescript"] - } - } - } - ] - } -};