From 12e28cdf9dd0be73c250a3e40f62ea2bfbe054d1 Mon Sep 17 00:00:00 2001 From: Nick Chapman Date: Tue, 10 Jun 2025 16:06:48 -0700 Subject: [PATCH] Add unit tests and GitHub actions. --- .github/workflows/ci.yml | 53 + .prettierignore | 11 + .prettierrc | 3 + package.json | 5 +- pnpm-lock.yaml | 2376 ++++++++++++++++++++---------- src/browser/ariaBrowser.ts | 5 +- src/browser/playwrightBrowser.ts | 53 +- src/events.ts | 6 +- src/index.ts | 6 +- src/loggers.ts | 140 +- src/prompts.ts | 96 +- src/templateUtils.ts | 2 +- src/webAgent.ts | 83 +- test/ariaBrowser.test.ts | 234 +++ test/events.test.ts | 410 ++++++ test/loggers.test.ts | 562 +++++++ test/mockBrowser.ts | 79 - test/pageCapture.test.ts | 617 -------- test/prompts.test.ts | 379 +++++ test/schemas.test.ts | 380 +++++ test/templateUtils.test.ts | 218 +++ test/webAgent.test.ts | 735 +++++++++ 22 files changed, 4717 insertions(+), 1736 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 .prettierignore create mode 100644 .prettierrc create mode 100644 test/ariaBrowser.test.ts create mode 100644 test/events.test.ts create mode 100644 test/loggers.test.ts delete mode 100644 test/mockBrowser.ts delete mode 100644 test/pageCapture.test.ts create mode 100644 test/prompts.test.ts create mode 100644 test/schemas.test.ts create mode 100644 test/templateUtils.test.ts create mode 100644 test/webAgent.test.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..db14f783 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,53 @@ +name: CI + +on: + push: + branches: [main, develop] + pull_request: + branches: [main, develop] + +jobs: + ci: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "22" + + - name: Setup pnpm + uses: pnpm/action-setup@v2 + with: + version: 8 + + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - name: Setup pnpm cache + uses: actions/cache@v3 + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Install dependencies + run: pnpm install --no-frozen-lockfile + + - name: Check formatting + run: pnpm run format:check + + - name: Run type check + run: pnpm run typecheck + + - name: Run tests + run: pnpm test + + - name: Build project + run: pnpm run build diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..312da40d --- /dev/null +++ b/.prettierignore @@ -0,0 +1,11 @@ +# Lock files +pnpm-lock.yaml +package-lock.json +yarn.lock + +# Build outputs +dist/ +build/ + +# Dependencies +node_modules/ \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..de753c53 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,3 @@ +{ + "printWidth": 100 +} diff --git a/package.json b/package.json index 8bb3ce86..d0f2d67b 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,9 @@ "spark": "node --no-warnings --loader ts-node/esm src/index.ts", "test": "vitest run", "test:watch": "vitest", - "install-cli": "npm run build && chmod +x dist/index.js && npm install -g ." + "install-cli": "npm run build && chmod +x dist/index.js && npm install -g .", + "format": "prettier --write .", + "format:check": "prettier --check ." }, "keywords": [], "author": "", @@ -24,6 +26,7 @@ "@types/node": "^20.17.25", "jsdom": "^24.1.3", "nodemon": "^3.1.9", + "prettier": "^3.5.3", "ts-node": "^10.9.2", "typescript": "^5.8.2", "vitest": "^1.6.1" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3105ce91..a66bd2fe 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,17 +1,16 @@ -lockfileVersion: '9.0' +lockfileVersion: "9.0" settings: autoInstallPeers: true excludeLinksFromLockfile: false importers: - .: dependencies: - '@ai-sdk/openai': + "@ai-sdk/openai": specifier: ^1.3.0 version: 1.3.0(zod@3.24.2) - '@ghostery/adblocker-playwright': + "@ghostery/adblocker-playwright": specifier: ^2.5.0 version: 2.5.0(playwright@1.52.0-alpha-2025-03-21) ai: @@ -39,10 +38,10 @@ importers: specifier: ^3.24.2 version: 3.24.2 devDependencies: - '@types/jsdom': + "@types/jsdom": specifier: ^21.1.7 version: 21.1.7 - '@types/node': + "@types/node": specifier: ^20.17.25 version: 20.17.25 jsdom: @@ -51,6 +50,9 @@ importers: nodemon: specifier: ^3.1.9 version: 3.1.9 + prettier: + specifier: ^3.5.3 + version: 3.5.3 ts-node: specifier: ^10.9.2 version: 10.9.2(@types/node@20.17.25)(typescript@5.8.2) @@ -62,26 +64,37 @@ importers: version: 1.6.1(@types/node@20.17.25)(jsdom@24.1.3) packages: - - '@ai-sdk/openai@1.3.0': - resolution: {integrity: sha512-zKKacGH8AyUjC63GizDpts+Nf8qAEtvAtO5O/AfVML8pIrtNWsbF+U3nT6mM8Oqvkp9X7ivuc4hCurivMFlJ6Q==} - engines: {node: '>=18'} + "@ai-sdk/openai@1.3.0": + resolution: + { + integrity: sha512-zKKacGH8AyUjC63GizDpts+Nf8qAEtvAtO5O/AfVML8pIrtNWsbF+U3nT6mM8Oqvkp9X7ivuc4hCurivMFlJ6Q==, + } + engines: { node: ">=18" } peerDependencies: zod: ^3.0.0 - '@ai-sdk/provider-utils@2.2.0': - resolution: {integrity: sha512-RX5BnDSqudjvZjwwpROcxVQElyX7rUn/xImBgaZLXekSGqq8f7/tefqDcQiRbDZjuCd4CVIfhrK8y/Pta8cPfQ==} - engines: {node: '>=18'} + "@ai-sdk/provider-utils@2.2.0": + resolution: + { + integrity: sha512-RX5BnDSqudjvZjwwpROcxVQElyX7rUn/xImBgaZLXekSGqq8f7/tefqDcQiRbDZjuCd4CVIfhrK8y/Pta8cPfQ==, + } + engines: { node: ">=18" } peerDependencies: zod: ^3.23.8 - '@ai-sdk/provider@1.1.0': - resolution: {integrity: sha512-0M+qjp+clUD0R1E5eWQFhxEvWLNaOtGQRUaBn8CUABnSKredagq92hUS9VjOzGsTm37xLfpaxl97AVtbeOsHew==} - engines: {node: '>=18'} - - '@ai-sdk/react@1.2.0': - resolution: {integrity: sha512-fUTZkAsxOMz8ijjWf87E/GfYkgsH4V5MH2yuj7EXh5ShjWe/oayn2ZJkyoqFMr4Jf8m5kptDaivmbIenDq5OXA==} - engines: {node: '>=18'} + "@ai-sdk/provider@1.1.0": + resolution: + { + integrity: sha512-0M+qjp+clUD0R1E5eWQFhxEvWLNaOtGQRUaBn8CUABnSKredagq92hUS9VjOzGsTm37xLfpaxl97AVtbeOsHew==, + } + engines: { node: ">=18" } + + "@ai-sdk/react@1.2.0": + resolution: + { + integrity: sha512-fUTZkAsxOMz8ijjWf87E/GfYkgsH4V5MH2yuj7EXh5ShjWe/oayn2ZJkyoqFMr4Jf8m5kptDaivmbIenDq5OXA==, + } + engines: { node: ">=18" } peerDependencies: react: ^18 || ^19 || ^19.0.0-rc zod: ^3.23.8 @@ -89,396 +102,651 @@ packages: zod: optional: true - '@ai-sdk/ui-utils@1.2.0': - resolution: {integrity: sha512-0IZwCqe7E+GkCASTDPAbzMr+POm9GDzWvFd37FvzpOeKNeibmge/LZEkTDbGSa+3b928H8wPwOLsOXBWPLUPDQ==} - engines: {node: '>=18'} + "@ai-sdk/ui-utils@1.2.0": + resolution: + { + integrity: sha512-0IZwCqe7E+GkCASTDPAbzMr+POm9GDzWvFd37FvzpOeKNeibmge/LZEkTDbGSa+3b928H8wPwOLsOXBWPLUPDQ==, + } + engines: { node: ">=18" } peerDependencies: zod: ^3.23.8 - '@asamuzakjp/css-color@3.1.1': - resolution: {integrity: sha512-hpRD68SV2OMcZCsrbdkccTw5FXjNDLo5OuqSHyHZfwweGsDWZwDJ2+gONyNAbazZclobMirACLw0lk8WVxIqxA==} - - '@cspotcode/source-map-support@0.8.1': - resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} - engines: {node: '>=12'} - - '@csstools/color-helpers@5.0.2': - resolution: {integrity: sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==} - engines: {node: '>=18'} - - '@csstools/css-calc@2.1.2': - resolution: {integrity: sha512-TklMyb3uBB28b5uQdxjReG4L80NxAqgrECqLZFQbyLekwwlcDDS8r3f07DKqeo8C4926Br0gf/ZDe17Zv4wIuw==} - engines: {node: '>=18'} + "@asamuzakjp/css-color@3.1.1": + resolution: + { + integrity: sha512-hpRD68SV2OMcZCsrbdkccTw5FXjNDLo5OuqSHyHZfwweGsDWZwDJ2+gONyNAbazZclobMirACLw0lk8WVxIqxA==, + } + + "@cspotcode/source-map-support@0.8.1": + resolution: + { + integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==, + } + engines: { node: ">=12" } + + "@csstools/color-helpers@5.0.2": + resolution: + { + integrity: sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==, + } + engines: { node: ">=18" } + + "@csstools/css-calc@2.1.2": + resolution: + { + integrity: sha512-TklMyb3uBB28b5uQdxjReG4L80NxAqgrECqLZFQbyLekwwlcDDS8r3f07DKqeo8C4926Br0gf/ZDe17Zv4wIuw==, + } + engines: { node: ">=18" } peerDependencies: - '@csstools/css-parser-algorithms': ^3.0.4 - '@csstools/css-tokenizer': ^3.0.3 - - '@csstools/css-color-parser@3.0.8': - resolution: {integrity: sha512-pdwotQjCCnRPuNi06jFuP68cykU1f3ZWExLe/8MQ1LOs8Xq+fTkYgd+2V8mWUWMrOn9iS2HftPVaMZDaXzGbhQ==} - engines: {node: '>=18'} + "@csstools/css-parser-algorithms": ^3.0.4 + "@csstools/css-tokenizer": ^3.0.3 + + "@csstools/css-color-parser@3.0.8": + resolution: + { + integrity: sha512-pdwotQjCCnRPuNi06jFuP68cykU1f3ZWExLe/8MQ1LOs8Xq+fTkYgd+2V8mWUWMrOn9iS2HftPVaMZDaXzGbhQ==, + } + engines: { node: ">=18" } peerDependencies: - '@csstools/css-parser-algorithms': ^3.0.4 - '@csstools/css-tokenizer': ^3.0.3 - - '@csstools/css-parser-algorithms@3.0.4': - resolution: {integrity: sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A==} - engines: {node: '>=18'} + "@csstools/css-parser-algorithms": ^3.0.4 + "@csstools/css-tokenizer": ^3.0.3 + + "@csstools/css-parser-algorithms@3.0.4": + resolution: + { + integrity: sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A==, + } + engines: { node: ">=18" } peerDependencies: - '@csstools/css-tokenizer': ^3.0.3 - - '@csstools/css-tokenizer@3.0.3': - resolution: {integrity: sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==} - engines: {node: '>=18'} - - '@esbuild/aix-ppc64@0.21.5': - resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} - engines: {node: '>=12'} + "@csstools/css-tokenizer": ^3.0.3 + + "@csstools/css-tokenizer@3.0.3": + resolution: + { + integrity: sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==, + } + engines: { node: ">=18" } + + "@esbuild/aix-ppc64@0.21.5": + resolution: + { + integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==, + } + engines: { node: ">=12" } cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.21.5': - resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} - engines: {node: '>=12'} + "@esbuild/android-arm64@0.21.5": + resolution: + { + integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==, + } + engines: { node: ">=12" } cpu: [arm64] os: [android] - '@esbuild/android-arm@0.21.5': - resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} - engines: {node: '>=12'} + "@esbuild/android-arm@0.21.5": + resolution: + { + integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==, + } + engines: { node: ">=12" } cpu: [arm] os: [android] - '@esbuild/android-x64@0.21.5': - resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} - engines: {node: '>=12'} + "@esbuild/android-x64@0.21.5": + resolution: + { + integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==, + } + engines: { node: ">=12" } cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.21.5': - resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} - engines: {node: '>=12'} + "@esbuild/darwin-arm64@0.21.5": + resolution: + { + integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==, + } + engines: { node: ">=12" } cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.21.5': - resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} - engines: {node: '>=12'} + "@esbuild/darwin-x64@0.21.5": + resolution: + { + integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==, + } + engines: { node: ">=12" } cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.21.5': - resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} - engines: {node: '>=12'} + "@esbuild/freebsd-arm64@0.21.5": + resolution: + { + integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==, + } + engines: { node: ">=12" } cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.21.5': - resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} - engines: {node: '>=12'} + "@esbuild/freebsd-x64@0.21.5": + resolution: + { + integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==, + } + engines: { node: ">=12" } cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.21.5': - resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} - engines: {node: '>=12'} + "@esbuild/linux-arm64@0.21.5": + resolution: + { + integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==, + } + engines: { node: ">=12" } cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.21.5': - resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} - engines: {node: '>=12'} + "@esbuild/linux-arm@0.21.5": + resolution: + { + integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==, + } + engines: { node: ">=12" } cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.21.5': - resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} - engines: {node: '>=12'} + "@esbuild/linux-ia32@0.21.5": + resolution: + { + integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==, + } + engines: { node: ">=12" } cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.21.5': - resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} - engines: {node: '>=12'} + "@esbuild/linux-loong64@0.21.5": + resolution: + { + integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==, + } + engines: { node: ">=12" } cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.21.5': - resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} - engines: {node: '>=12'} + "@esbuild/linux-mips64el@0.21.5": + resolution: + { + integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==, + } + engines: { node: ">=12" } cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.21.5': - resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} - engines: {node: '>=12'} + "@esbuild/linux-ppc64@0.21.5": + resolution: + { + integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==, + } + engines: { node: ">=12" } cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.21.5': - resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} - engines: {node: '>=12'} + "@esbuild/linux-riscv64@0.21.5": + resolution: + { + integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==, + } + engines: { node: ">=12" } cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.21.5': - resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} - engines: {node: '>=12'} + "@esbuild/linux-s390x@0.21.5": + resolution: + { + integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==, + } + engines: { node: ">=12" } cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.21.5': - resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} - engines: {node: '>=12'} + "@esbuild/linux-x64@0.21.5": + resolution: + { + integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==, + } + engines: { node: ">=12" } cpu: [x64] os: [linux] - '@esbuild/netbsd-x64@0.21.5': - resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} - engines: {node: '>=12'} + "@esbuild/netbsd-x64@0.21.5": + resolution: + { + integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==, + } + engines: { node: ">=12" } cpu: [x64] os: [netbsd] - '@esbuild/openbsd-x64@0.21.5': - resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} - engines: {node: '>=12'} + "@esbuild/openbsd-x64@0.21.5": + resolution: + { + integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==, + } + engines: { node: ">=12" } cpu: [x64] os: [openbsd] - '@esbuild/sunos-x64@0.21.5': - resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} - engines: {node: '>=12'} + "@esbuild/sunos-x64@0.21.5": + resolution: + { + integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==, + } + engines: { node: ">=12" } cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.21.5': - resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} - engines: {node: '>=12'} + "@esbuild/win32-arm64@0.21.5": + resolution: + { + integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==, + } + engines: { node: ">=12" } cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.21.5': - resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} - engines: {node: '>=12'} + "@esbuild/win32-ia32@0.21.5": + resolution: + { + integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==, + } + engines: { node: ">=12" } cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.21.5': - resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} - engines: {node: '>=12'} + "@esbuild/win32-x64@0.21.5": + resolution: + { + integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==, + } + engines: { node: ">=12" } cpu: [x64] os: [win32] - '@ghostery/adblocker-content@2.5.0': - resolution: {integrity: sha512-Gn9fslZdacx1m1e3/2LSUPWagLObYmIDbkgvZTtgqT/OHc17VbM71AxWEjtC/xzo5K4PI25958PjvidoEH7ufw==} - - '@ghostery/adblocker-extended-selectors@2.5.0': - resolution: {integrity: sha512-/GBAwErjktcBKLjCMl/n+jz2MxXFfTmEGw+hcPtAhEin49eSC09PK1TAdzDPDXkCTF4Jmb/zC+MYtbX1eZ1WsQ==} - - '@ghostery/adblocker-playwright@2.5.0': - resolution: {integrity: sha512-2mnZSYO2Qj1tr0UXO3c8FSdUtsmbTBjvkat7BhvBQ+2iQj6YvQke7LJgrP9dsAFsOFuqzup/xqME3YAu9TE6uA==} + "@ghostery/adblocker-content@2.5.0": + resolution: + { + integrity: sha512-Gn9fslZdacx1m1e3/2LSUPWagLObYmIDbkgvZTtgqT/OHc17VbM71AxWEjtC/xzo5K4PI25958PjvidoEH7ufw==, + } + + "@ghostery/adblocker-extended-selectors@2.5.0": + resolution: + { + integrity: sha512-/GBAwErjktcBKLjCMl/n+jz2MxXFfTmEGw+hcPtAhEin49eSC09PK1TAdzDPDXkCTF4Jmb/zC+MYtbX1eZ1WsQ==, + } + + "@ghostery/adblocker-playwright@2.5.0": + resolution: + { + integrity: sha512-2mnZSYO2Qj1tr0UXO3c8FSdUtsmbTBjvkat7BhvBQ+2iQj6YvQke7LJgrP9dsAFsOFuqzup/xqME3YAu9TE6uA==, + } peerDependencies: playwright: ^1.x - '@ghostery/adblocker@2.5.0': - resolution: {integrity: sha512-CcmWiTLKxDqYiTlPyOAWr3xeZYXjWlpu6UOCDkk33k0w7jTgVrdvwbXf8Tv4XE0m3uNX6Idfj4H+Umv8L3AiUw==} - - '@jest/schemas@29.6.3': - resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - '@jridgewell/resolve-uri@3.1.2': - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} - - '@jridgewell/sourcemap-codec@1.5.0': - resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} - - '@jridgewell/trace-mapping@0.3.9': - resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - - '@opentelemetry/api@1.9.0': - resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} - engines: {node: '>=8.0.0'} - - '@remusao/guess-url-type@1.3.0': - resolution: {integrity: sha512-SNSJGxH5ckvxb3EUHj4DqlAm/bxNxNv2kx/AESZva/9VfcBokwKNS+C4D1lQdWIDM1R3d3UG+xmVzlkNG8CPTQ==} - - '@remusao/small@1.3.0': - resolution: {integrity: sha512-bydAhJI+ywmg5xMUcbqoR8KahetcfkFywEZpsyFZ8EBofilvWxbXnMSe4vnjDI1Y+SWxnNhR4AL/2BAXkf4b8A==} - - '@remusao/smaz-compress@1.10.0': - resolution: {integrity: sha512-E/lC8OSU+3bQrUl64vlLyPzIxo7dxF2RvNBe9KzcM4ax43J/d+YMinmMztHyCIHqRbz7rBCtkp3c0KfeIbHmEg==} - - '@remusao/smaz-decompress@1.10.0': - resolution: {integrity: sha512-aA5ImUH480Pcs5/cOgToKmFnzi7osSNG6ft+7DdmQTaQEEst3nLq3JLlBEk+gwidURymjbx6DYs60LHaZ415VQ==} - - '@remusao/smaz@1.10.0': - resolution: {integrity: sha512-GQzCxmmMpLkyZwcwNgz8TpuBEWl0RUQa8IcvKiYlPxuyYKqyqPkCr0hlHI15ckn3kDUPS68VmTVgyPnLNrdVmg==} - - '@remusao/trie@1.5.0': - resolution: {integrity: sha512-UX+3utJKgwCsg6sUozjxd38gNMVRXrY4TNX9VvCdSrlZBS1nZjRPi98ON3QjRAdf6KCguJFyQARRsulTeqQiPg==} - - '@rollup/rollup-android-arm-eabi@4.37.0': - resolution: {integrity: sha512-l7StVw6WAa8l3vA1ov80jyetOAEo1FtHvZDbzXDO/02Sq/QVvqlHkYoFwDJPIMj0GKiistsBudfx5tGFnwYWDQ==} + "@ghostery/adblocker@2.5.0": + resolution: + { + integrity: sha512-CcmWiTLKxDqYiTlPyOAWr3xeZYXjWlpu6UOCDkk33k0w7jTgVrdvwbXf8Tv4XE0m3uNX6Idfj4H+Umv8L3AiUw==, + } + + "@jest/schemas@29.6.3": + resolution: + { + integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + "@jridgewell/resolve-uri@3.1.2": + resolution: + { + integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==, + } + engines: { node: ">=6.0.0" } + + "@jridgewell/sourcemap-codec@1.5.0": + resolution: + { + integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==, + } + + "@jridgewell/trace-mapping@0.3.9": + resolution: + { + integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==, + } + + "@opentelemetry/api@1.9.0": + resolution: + { + integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==, + } + engines: { node: ">=8.0.0" } + + "@remusao/guess-url-type@1.3.0": + resolution: + { + integrity: sha512-SNSJGxH5ckvxb3EUHj4DqlAm/bxNxNv2kx/AESZva/9VfcBokwKNS+C4D1lQdWIDM1R3d3UG+xmVzlkNG8CPTQ==, + } + + "@remusao/small@1.3.0": + resolution: + { + integrity: sha512-bydAhJI+ywmg5xMUcbqoR8KahetcfkFywEZpsyFZ8EBofilvWxbXnMSe4vnjDI1Y+SWxnNhR4AL/2BAXkf4b8A==, + } + + "@remusao/smaz-compress@1.10.0": + resolution: + { + integrity: sha512-E/lC8OSU+3bQrUl64vlLyPzIxo7dxF2RvNBe9KzcM4ax43J/d+YMinmMztHyCIHqRbz7rBCtkp3c0KfeIbHmEg==, + } + + "@remusao/smaz-decompress@1.10.0": + resolution: + { + integrity: sha512-aA5ImUH480Pcs5/cOgToKmFnzi7osSNG6ft+7DdmQTaQEEst3nLq3JLlBEk+gwidURymjbx6DYs60LHaZ415VQ==, + } + + "@remusao/smaz@1.10.0": + resolution: + { + integrity: sha512-GQzCxmmMpLkyZwcwNgz8TpuBEWl0RUQa8IcvKiYlPxuyYKqyqPkCr0hlHI15ckn3kDUPS68VmTVgyPnLNrdVmg==, + } + + "@remusao/trie@1.5.0": + resolution: + { + integrity: sha512-UX+3utJKgwCsg6sUozjxd38gNMVRXrY4TNX9VvCdSrlZBS1nZjRPi98ON3QjRAdf6KCguJFyQARRsulTeqQiPg==, + } + + "@rollup/rollup-android-arm-eabi@4.37.0": + resolution: + { + integrity: sha512-l7StVw6WAa8l3vA1ov80jyetOAEo1FtHvZDbzXDO/02Sq/QVvqlHkYoFwDJPIMj0GKiistsBudfx5tGFnwYWDQ==, + } cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.37.0': - resolution: {integrity: sha512-6U3SlVyMxezt8Y+/iEBcbp945uZjJwjZimu76xoG7tO1av9VO691z8PkhzQ85ith2I8R2RddEPeSfcbyPfD4hA==} + "@rollup/rollup-android-arm64@4.37.0": + resolution: + { + integrity: sha512-6U3SlVyMxezt8Y+/iEBcbp945uZjJwjZimu76xoG7tO1av9VO691z8PkhzQ85ith2I8R2RddEPeSfcbyPfD4hA==, + } cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.37.0': - resolution: {integrity: sha512-+iTQ5YHuGmPt10NTzEyMPbayiNTcOZDWsbxZYR1ZnmLnZxG17ivrPSWFO9j6GalY0+gV3Jtwrrs12DBscxnlYA==} + "@rollup/rollup-darwin-arm64@4.37.0": + resolution: + { + integrity: sha512-+iTQ5YHuGmPt10NTzEyMPbayiNTcOZDWsbxZYR1ZnmLnZxG17ivrPSWFO9j6GalY0+gV3Jtwrrs12DBscxnlYA==, + } cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.37.0': - resolution: {integrity: sha512-m8W2UbxLDcmRKVjgl5J/k4B8d7qX2EcJve3Sut7YGrQoPtCIQGPH5AMzuFvYRWZi0FVS0zEY4c8uttPfX6bwYQ==} + "@rollup/rollup-darwin-x64@4.37.0": + resolution: + { + integrity: sha512-m8W2UbxLDcmRKVjgl5J/k4B8d7qX2EcJve3Sut7YGrQoPtCIQGPH5AMzuFvYRWZi0FVS0zEY4c8uttPfX6bwYQ==, + } cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.37.0': - resolution: {integrity: sha512-FOMXGmH15OmtQWEt174v9P1JqqhlgYge/bUjIbiVD1nI1NeJ30HYT9SJlZMqdo1uQFyt9cz748F1BHghWaDnVA==} + "@rollup/rollup-freebsd-arm64@4.37.0": + resolution: + { + integrity: sha512-FOMXGmH15OmtQWEt174v9P1JqqhlgYge/bUjIbiVD1nI1NeJ30HYT9SJlZMqdo1uQFyt9cz748F1BHghWaDnVA==, + } cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.37.0': - resolution: {integrity: sha512-SZMxNttjPKvV14Hjck5t70xS3l63sbVwl98g3FlVVx2YIDmfUIy29jQrsw06ewEYQ8lQSuY9mpAPlmgRD2iSsA==} + "@rollup/rollup-freebsd-x64@4.37.0": + resolution: + { + integrity: sha512-SZMxNttjPKvV14Hjck5t70xS3l63sbVwl98g3FlVVx2YIDmfUIy29jQrsw06ewEYQ8lQSuY9mpAPlmgRD2iSsA==, + } cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.37.0': - resolution: {integrity: sha512-hhAALKJPidCwZcj+g+iN+38SIOkhK2a9bqtJR+EtyxrKKSt1ynCBeqrQy31z0oWU6thRZzdx53hVgEbRkuI19w==} + "@rollup/rollup-linux-arm-gnueabihf@4.37.0": + resolution: + { + integrity: sha512-hhAALKJPidCwZcj+g+iN+38SIOkhK2a9bqtJR+EtyxrKKSt1ynCBeqrQy31z0oWU6thRZzdx53hVgEbRkuI19w==, + } cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.37.0': - resolution: {integrity: sha512-jUb/kmn/Gd8epbHKEqkRAxq5c2EwRt0DqhSGWjPFxLeFvldFdHQs/n8lQ9x85oAeVb6bHcS8irhTJX2FCOd8Ag==} + "@rollup/rollup-linux-arm-musleabihf@4.37.0": + resolution: + { + integrity: sha512-jUb/kmn/Gd8epbHKEqkRAxq5c2EwRt0DqhSGWjPFxLeFvldFdHQs/n8lQ9x85oAeVb6bHcS8irhTJX2FCOd8Ag==, + } cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.37.0': - resolution: {integrity: sha512-oNrJxcQT9IcbcmKlkF+Yz2tmOxZgG9D9GRq+1OE6XCQwCVwxixYAa38Z8qqPzQvzt1FCfmrHX03E0pWoXm1DqA==} + "@rollup/rollup-linux-arm64-gnu@4.37.0": + resolution: + { + integrity: sha512-oNrJxcQT9IcbcmKlkF+Yz2tmOxZgG9D9GRq+1OE6XCQwCVwxixYAa38Z8qqPzQvzt1FCfmrHX03E0pWoXm1DqA==, + } cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.37.0': - resolution: {integrity: sha512-pfxLBMls+28Ey2enpX3JvjEjaJMBX5XlPCZNGxj4kdJyHduPBXtxYeb8alo0a7bqOoWZW2uKynhHxF/MWoHaGQ==} + "@rollup/rollup-linux-arm64-musl@4.37.0": + resolution: + { + integrity: sha512-pfxLBMls+28Ey2enpX3JvjEjaJMBX5XlPCZNGxj4kdJyHduPBXtxYeb8alo0a7bqOoWZW2uKynhHxF/MWoHaGQ==, + } cpu: [arm64] os: [linux] - '@rollup/rollup-linux-loongarch64-gnu@4.37.0': - resolution: {integrity: sha512-yCE0NnutTC/7IGUq/PUHmoeZbIwq3KRh02e9SfFh7Vmc1Z7atuJRYWhRME5fKgT8aS20mwi1RyChA23qSyRGpA==} + "@rollup/rollup-linux-loongarch64-gnu@4.37.0": + resolution: + { + integrity: sha512-yCE0NnutTC/7IGUq/PUHmoeZbIwq3KRh02e9SfFh7Vmc1Z7atuJRYWhRME5fKgT8aS20mwi1RyChA23qSyRGpA==, + } cpu: [loong64] os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.37.0': - resolution: {integrity: sha512-NxcICptHk06E2Lh3a4Pu+2PEdZ6ahNHuK7o6Np9zcWkrBMuv21j10SQDJW3C9Yf/A/P7cutWoC/DptNLVsZ0VQ==} + "@rollup/rollup-linux-powerpc64le-gnu@4.37.0": + resolution: + { + integrity: sha512-NxcICptHk06E2Lh3a4Pu+2PEdZ6ahNHuK7o6Np9zcWkrBMuv21j10SQDJW3C9Yf/A/P7cutWoC/DptNLVsZ0VQ==, + } cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.37.0': - resolution: {integrity: sha512-PpWwHMPCVpFZLTfLq7EWJWvrmEuLdGn1GMYcm5MV7PaRgwCEYJAwiN94uBuZev0/J/hFIIJCsYw4nLmXA9J7Pw==} + "@rollup/rollup-linux-riscv64-gnu@4.37.0": + resolution: + { + integrity: sha512-PpWwHMPCVpFZLTfLq7EWJWvrmEuLdGn1GMYcm5MV7PaRgwCEYJAwiN94uBuZev0/J/hFIIJCsYw4nLmXA9J7Pw==, + } cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.37.0': - resolution: {integrity: sha512-DTNwl6a3CfhGTAOYZ4KtYbdS8b+275LSLqJVJIrPa5/JuIufWWZ/QFvkxp52gpmguN95eujrM68ZG+zVxa8zHA==} + "@rollup/rollup-linux-riscv64-musl@4.37.0": + resolution: + { + integrity: sha512-DTNwl6a3CfhGTAOYZ4KtYbdS8b+275LSLqJVJIrPa5/JuIufWWZ/QFvkxp52gpmguN95eujrM68ZG+zVxa8zHA==, + } cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.37.0': - resolution: {integrity: sha512-hZDDU5fgWvDdHFuExN1gBOhCuzo/8TMpidfOR+1cPZJflcEzXdCy1LjnklQdW8/Et9sryOPJAKAQRw8Jq7Tg+A==} + "@rollup/rollup-linux-s390x-gnu@4.37.0": + resolution: + { + integrity: sha512-hZDDU5fgWvDdHFuExN1gBOhCuzo/8TMpidfOR+1cPZJflcEzXdCy1LjnklQdW8/Et9sryOPJAKAQRw8Jq7Tg+A==, + } cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.37.0': - resolution: {integrity: sha512-pKivGpgJM5g8dwj0ywBwe/HeVAUSuVVJhUTa/URXjxvoyTT/AxsLTAbkHkDHG7qQxLoW2s3apEIl26uUe08LVQ==} + "@rollup/rollup-linux-x64-gnu@4.37.0": + resolution: + { + integrity: sha512-pKivGpgJM5g8dwj0ywBwe/HeVAUSuVVJhUTa/URXjxvoyTT/AxsLTAbkHkDHG7qQxLoW2s3apEIl26uUe08LVQ==, + } cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.37.0': - resolution: {integrity: sha512-E2lPrLKE8sQbY/2bEkVTGDEk4/49UYRVWgj90MY8yPjpnGBQ+Xi1Qnr7b7UIWw1NOggdFQFOLZ8+5CzCiz143w==} + "@rollup/rollup-linux-x64-musl@4.37.0": + resolution: + { + integrity: sha512-E2lPrLKE8sQbY/2bEkVTGDEk4/49UYRVWgj90MY8yPjpnGBQ+Xi1Qnr7b7UIWw1NOggdFQFOLZ8+5CzCiz143w==, + } cpu: [x64] os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.37.0': - resolution: {integrity: sha512-Jm7biMazjNzTU4PrQtr7VS8ibeys9Pn29/1bm4ph7CP2kf21950LgN+BaE2mJ1QujnvOc6p54eWWiVvn05SOBg==} + "@rollup/rollup-win32-arm64-msvc@4.37.0": + resolution: + { + integrity: sha512-Jm7biMazjNzTU4PrQtr7VS8ibeys9Pn29/1bm4ph7CP2kf21950LgN+BaE2mJ1QujnvOc6p54eWWiVvn05SOBg==, + } cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.37.0': - resolution: {integrity: sha512-e3/1SFm1OjefWICB2Ucstg2dxYDkDTZGDYgwufcbsxTHyqQps1UQf33dFEChBNmeSsTOyrjw2JJq0zbG5GF6RA==} + "@rollup/rollup-win32-ia32-msvc@4.37.0": + resolution: + { + integrity: sha512-e3/1SFm1OjefWICB2Ucstg2dxYDkDTZGDYgwufcbsxTHyqQps1UQf33dFEChBNmeSsTOyrjw2JJq0zbG5GF6RA==, + } cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.37.0': - resolution: {integrity: sha512-LWbXUBwn/bcLx2sSsqy7pK5o+Nr+VCoRoAohfJ5C/aBio9nfJmGQqHAhU6pwxV/RmyTk5AqdySma7uwWGlmeuA==} + "@rollup/rollup-win32-x64-msvc@4.37.0": + resolution: + { + integrity: sha512-LWbXUBwn/bcLx2sSsqy7pK5o+Nr+VCoRoAohfJ5C/aBio9nfJmGQqHAhU6pwxV/RmyTk5AqdySma7uwWGlmeuA==, + } cpu: [x64] os: [win32] - '@sinclair/typebox@0.27.8': - resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} - - '@tsconfig/node10@1.0.11': - resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} - - '@tsconfig/node12@1.0.11': - resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} - - '@tsconfig/node14@1.0.3': - resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} - - '@tsconfig/node16@1.0.4': - resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} - - '@types/diff-match-patch@1.0.36': - resolution: {integrity: sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg==} - - '@types/estree@1.0.6': - resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} - - '@types/jsdom@21.1.7': - resolution: {integrity: sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA==} - - '@types/node@20.17.25': - resolution: {integrity: sha512-bT+r2haIlplJUYtlZrEanFHdPIZTeiMeh/fSOEbOOfWf9uTn+lg8g0KU6Q3iMgjd9FLuuMAgfCNSkjUbxL6E3Q==} - - '@types/tough-cookie@4.0.5': - resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} - - '@vitest/expect@1.6.1': - resolution: {integrity: sha512-jXL+9+ZNIJKruofqXuuTClf44eSpcHlgj3CiuNihUF3Ioujtmc0zIa3UJOW5RjDK1YLBJZnWBlPuqhYycLioog==} - - '@vitest/runner@1.6.1': - resolution: {integrity: sha512-3nSnYXkVkf3mXFfE7vVyPmi3Sazhb/2cfZGGs0JRzFsPFvAMBEcrweV1V1GsrstdXeKCTXlJbvnQwGWgEIHmOA==} - - '@vitest/snapshot@1.6.1': - resolution: {integrity: sha512-WvidQuWAzU2p95u8GAKlRMqMyN1yOJkGHnx3M1PL9Raf7AQ1kwLKg04ADlCa3+OXUZE7BceOhVZiuWAbzCKcUQ==} - - '@vitest/spy@1.6.1': - resolution: {integrity: sha512-MGcMmpGkZebsMZhbQKkAf9CX5zGvjkBTqf8Zx3ApYWXr3wG+QvEu2eXWfnIIWYSJExIp4V9FCKDEeygzkYrXMw==} - - '@vitest/utils@1.6.1': - resolution: {integrity: sha512-jOrrUvXM4Av9ZWiG1EajNto0u96kWAhJ1LmPmJhXXQx/32MecEKd10pOLYgS2BQx1TgkGhloPU1ArDW2vvaY6g==} + "@sinclair/typebox@0.27.8": + resolution: + { + integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==, + } + + "@tsconfig/node10@1.0.11": + resolution: + { + integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==, + } + + "@tsconfig/node12@1.0.11": + resolution: + { + integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==, + } + + "@tsconfig/node14@1.0.3": + resolution: + { + integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==, + } + + "@tsconfig/node16@1.0.4": + resolution: + { + integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==, + } + + "@types/diff-match-patch@1.0.36": + resolution: + { + integrity: sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg==, + } + + "@types/estree@1.0.6": + resolution: + { + integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==, + } + + "@types/jsdom@21.1.7": + resolution: + { + integrity: sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA==, + } + + "@types/node@20.17.25": + resolution: + { + integrity: sha512-bT+r2haIlplJUYtlZrEanFHdPIZTeiMeh/fSOEbOOfWf9uTn+lg8g0KU6Q3iMgjd9FLuuMAgfCNSkjUbxL6E3Q==, + } + + "@types/tough-cookie@4.0.5": + resolution: + { + integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==, + } + + "@vitest/expect@1.6.1": + resolution: + { + integrity: sha512-jXL+9+ZNIJKruofqXuuTClf44eSpcHlgj3CiuNihUF3Ioujtmc0zIa3UJOW5RjDK1YLBJZnWBlPuqhYycLioog==, + } + + "@vitest/runner@1.6.1": + resolution: + { + integrity: sha512-3nSnYXkVkf3mXFfE7vVyPmi3Sazhb/2cfZGGs0JRzFsPFvAMBEcrweV1V1GsrstdXeKCTXlJbvnQwGWgEIHmOA==, + } + + "@vitest/snapshot@1.6.1": + resolution: + { + integrity: sha512-WvidQuWAzU2p95u8GAKlRMqMyN1yOJkGHnx3M1PL9Raf7AQ1kwLKg04ADlCa3+OXUZE7BceOhVZiuWAbzCKcUQ==, + } + + "@vitest/spy@1.6.1": + resolution: + { + integrity: sha512-MGcMmpGkZebsMZhbQKkAf9CX5zGvjkBTqf8Zx3ApYWXr3wG+QvEu2eXWfnIIWYSJExIp4V9FCKDEeygzkYrXMw==, + } + + "@vitest/utils@1.6.1": + resolution: + { + integrity: sha512-jOrrUvXM4Av9ZWiG1EajNto0u96kWAhJ1LmPmJhXXQx/32MecEKd10pOLYgS2BQx1TgkGhloPU1ArDW2vvaY6g==, + } acorn-walk@8.3.4: - resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} - engines: {node: '>=0.4.0'} + resolution: + { + integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==, + } + engines: { node: ">=0.4.0" } acorn@8.14.1: - resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==} - engines: {node: '>=0.4.0'} + resolution: + { + integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==, + } + engines: { node: ">=0.4.0" } hasBin: true agent-base@7.1.3: - resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==} - engines: {node: '>= 14'} + resolution: + { + integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==, + } + engines: { node: ">= 14" } ai@4.2.0: - resolution: {integrity: sha512-3xJWzBZpBS3n/UY360IopufV5dpfgYoY08eCAV2A2m7CcyJxVOAQ4lXvBGSsB+mR+BYJ8Y/JOesFfc0+k4jz3A==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-3xJWzBZpBS3n/UY360IopufV5dpfgYoY08eCAV2A2m7CcyJxVOAQ4lXvBGSsB+mR+BYJ8Y/JOesFfc0+k4jz3A==, + } + engines: { node: ">=18" } peerDependencies: react: ^18 || ^19 || ^19.0.0-rc zod: ^3.23.8 @@ -487,289 +755,511 @@ packages: optional: true ansi-styles@5.2.0: - resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==, + } + engines: { node: ">=10" } anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} + resolution: + { + integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==, + } + engines: { node: ">= 8" } arg@4.1.3: - resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + resolution: + { + integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==, + } assertion-error@1.1.0: - resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} + resolution: + { + integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==, + } asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + resolution: + { + integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==, + } balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + resolution: + { + integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==, + } binary-extensions@2.3.0: - resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==, + } + engines: { node: ">=8" } brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + resolution: + { + integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==, + } braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==, + } + engines: { node: ">=8" } cac@6.7.14: - resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==, + } + engines: { node: ">=8" } call-bind-apply-helpers@1.0.2: - resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==, + } + engines: { node: ">= 0.4" } chai@4.5.0: - resolution: {integrity: sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==} - engines: {node: '>=4'} + resolution: + { + integrity: sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==, + } + engines: { node: ">=4" } chalk@5.4.1: - resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==} - engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + resolution: + { + integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==, + } + engines: { node: ^12.17.0 || ^14.13 || >=16.0.0 } check-error@1.0.3: - resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} + resolution: + { + integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==, + } chokidar@3.6.0: - resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} - engines: {node: '>= 8.10.0'} + resolution: + { + integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==, + } + engines: { node: ">= 8.10.0" } combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} + resolution: + { + integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==, + } + engines: { node: ">= 0.8" } concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + resolution: + { + integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==, + } confbox@0.1.8: - resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + resolution: + { + integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==, + } create-require@1.1.1: - resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + resolution: + { + integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==, + } cross-fetch@4.1.0: - resolution: {integrity: sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==} + resolution: + { + integrity: sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==, + } cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} + resolution: + { + integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==, + } + engines: { node: ">= 8" } cssstyle@4.3.0: - resolution: {integrity: sha512-6r0NiY0xizYqfBvWp1G7WXJ06/bZyrk7Dc6PHql82C/pKGUTKu4yAX4Y8JPamb1ob9nBKuxWzCGTRuGwU3yxJQ==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-6r0NiY0xizYqfBvWp1G7WXJ06/bZyrk7Dc6PHql82C/pKGUTKu4yAX4Y8JPamb1ob9nBKuxWzCGTRuGwU3yxJQ==, + } + engines: { node: ">=18" } data-urls@5.0.0: - resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==, + } + engines: { node: ">=18" } debug@4.4.0: - resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} - engines: {node: '>=6.0'} + resolution: + { + integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==, + } + engines: { node: ">=6.0" } peerDependencies: - supports-color: '*' + supports-color: "*" peerDependenciesMeta: supports-color: optional: true decimal.js@10.5.0: - resolution: {integrity: sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==} + resolution: + { + integrity: sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==, + } deep-eql@4.1.4: - resolution: {integrity: sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==} - engines: {node: '>=6'} + resolution: + { + integrity: sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==, + } + engines: { node: ">=6" } delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} + resolution: + { + integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==, + } + engines: { node: ">=0.4.0" } dequal@2.0.3: - resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} - engines: {node: '>=6'} + resolution: + { + integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==, + } + engines: { node: ">=6" } diff-match-patch@1.0.5: - resolution: {integrity: sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==} + resolution: + { + integrity: sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==, + } diff-sequences@29.6.3: - resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + resolution: + { + integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } diff@4.0.2: - resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} - engines: {node: '>=0.3.1'} + resolution: + { + integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==, + } + engines: { node: ">=0.3.1" } dotenv@16.4.7: - resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==} - engines: {node: '>=12'} + resolution: + { + integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==, + } + engines: { node: ">=12" } dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==, + } + engines: { node: ">= 0.4" } entities@4.5.0: - resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} - engines: {node: '>=0.12'} + resolution: + { + integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==, + } + engines: { node: ">=0.12" } es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==, + } + engines: { node: ">= 0.4" } es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==, + } + engines: { node: ">= 0.4" } es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==, + } + engines: { node: ">= 0.4" } es-set-tostringtag@2.1.0: - resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==, + } + engines: { node: ">= 0.4" } esbuild@0.21.5: - resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} - engines: {node: '>=12'} + resolution: + { + integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==, + } + engines: { node: ">=12" } hasBin: true estree-walker@3.0.3: - resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + resolution: + { + integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==, + } eventemitter3@5.0.1: - resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + resolution: + { + integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==, + } eventsource-parser@3.0.0: - resolution: {integrity: sha512-T1C0XCUimhxVQzW4zFipdx0SficT651NnkR0ZSH3yQwh+mFMdLfgjABVi4YtMTtaL4s168593DaoaRLMqryavA==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-T1C0XCUimhxVQzW4zFipdx0SficT651NnkR0ZSH3yQwh+mFMdLfgjABVi4YtMTtaL4s168593DaoaRLMqryavA==, + } + engines: { node: ">=18.0.0" } execa@8.0.1: - resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} - engines: {node: '>=16.17'} + resolution: + { + integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==, + } + engines: { node: ">=16.17" } fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==, + } + engines: { node: ">=8" } form-data@4.0.2: - resolution: {integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==} - engines: {node: '>= 6'} + resolution: + { + integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==, + } + engines: { node: ">= 6" } fsevents@2.3.2: - resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + resolution: + { + integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==, + } + engines: { node: ^8.16.0 || ^10.6.0 || >=11.0.0 } os: [darwin] fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + resolution: + { + integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==, + } + engines: { node: ^8.16.0 || ^10.6.0 || >=11.0.0 } os: [darwin] function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + resolution: + { + integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==, + } get-func-name@2.0.2: - resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} + resolution: + { + integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==, + } get-intrinsic@1.3.0: - resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==, + } + engines: { node: ">= 0.4" } get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==, + } + engines: { node: ">= 0.4" } get-stream@8.0.1: - resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} - engines: {node: '>=16'} + resolution: + { + integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==, + } + engines: { node: ">=16" } glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} + resolution: + { + integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==, + } + engines: { node: ">= 6" } gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==, + } + engines: { node: ">= 0.4" } handlebars@4.7.8: - resolution: {integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==} - engines: {node: '>=0.4.7'} + resolution: + { + integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==, + } + engines: { node: ">=0.4.7" } hasBin: true has-flag@3.0.0: - resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} - engines: {node: '>=4'} + resolution: + { + integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==, + } + engines: { node: ">=4" } has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==, + } + engines: { node: ">= 0.4" } has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==, + } + engines: { node: ">= 0.4" } hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==, + } + engines: { node: ">= 0.4" } html-encoding-sniffer@4.0.0: - resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==, + } + engines: { node: ">=18" } http-proxy-agent@7.0.2: - resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} - engines: {node: '>= 14'} + resolution: + { + integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==, + } + engines: { node: ">= 14" } https-proxy-agent@7.0.6: - resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} - engines: {node: '>= 14'} + resolution: + { + integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==, + } + engines: { node: ">= 14" } human-signals@5.0.0: - resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} - engines: {node: '>=16.17.0'} + resolution: + { + integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==, + } + engines: { node: ">=16.17.0" } iconv-lite@0.6.3: - resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==, + } + engines: { node: ">=0.10.0" } ignore-by-default@1.0.1: - resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==} + resolution: + { + integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==, + } is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==, + } + engines: { node: ">=8" } is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==, + } + engines: { node: ">=0.10.0" } is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==, + } + engines: { node: ">=0.10.0" } is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} + resolution: + { + integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==, + } + engines: { node: ">=0.12.0" } is-potential-custom-element-name@1.0.1: - resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + resolution: + { + integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==, + } is-stream@3.0.0: - resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + resolution: + { + integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==, + } + engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + resolution: + { + integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==, + } js-tokens@9.0.1: - resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} + resolution: + { + integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==, + } jsdom@24.1.3: - resolution: {integrity: sha512-MyL55p3Ut3cXbeBEG7Hcv0mVM8pp8PBNWxRqchZnSfAiES1v1mRnMeFfaHWIPULpwsYfvO+ZmMZz5tGCnjzDUQ==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-MyL55p3Ut3cXbeBEG7Hcv0mVM8pp8PBNWxRqchZnSfAiES1v1mRnMeFfaHWIPULpwsYfvO+ZmMZz5tGCnjzDUQ==, + } + engines: { node: ">=18" } peerDependencies: canvas: ^2.11.2 peerDependenciesMeta: @@ -777,71 +1267,128 @@ packages: optional: true json-schema@0.4.0: - resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} + resolution: + { + integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==, + } jsondiffpatch@0.6.0: - resolution: {integrity: sha512-3QItJOXp2AP1uv7waBkao5nCvhEv+QmJAd38Ybq7wNI74Q+BBmnLn4EDKz6yI9xGAIQoUF87qHt+kc1IVxB4zQ==} - engines: {node: ^18.0.0 || >=20.0.0} + resolution: + { + integrity: sha512-3QItJOXp2AP1uv7waBkao5nCvhEv+QmJAd38Ybq7wNI74Q+BBmnLn4EDKz6yI9xGAIQoUF87qHt+kc1IVxB4zQ==, + } + engines: { node: ^18.0.0 || >=20.0.0 } hasBin: true local-pkg@0.5.1: - resolution: {integrity: sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==} - engines: {node: '>=14'} + resolution: + { + integrity: sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==, + } + engines: { node: ">=14" } loupe@2.3.7: - resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} + resolution: + { + integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==, + } lru-cache@10.4.3: - resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + resolution: + { + integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==, + } magic-string@0.30.17: - resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + resolution: + { + integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==, + } make-error@1.3.6: - resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + resolution: + { + integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==, + } math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==, + } + engines: { node: ">= 0.4" } merge-stream@2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + resolution: + { + integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==, + } mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} + resolution: + { + integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==, + } + engines: { node: ">= 0.6" } mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} + resolution: + { + integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==, + } + engines: { node: ">= 0.6" } mimic-fn@4.0.0: - resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} - engines: {node: '>=12'} + resolution: + { + integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==, + } + engines: { node: ">=12" } minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + resolution: + { + integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==, + } minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + resolution: + { + integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==, + } mlly@1.7.4: - resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==} + resolution: + { + integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==, + } ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + resolution: + { + integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==, + } nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + resolution: + { + integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==, + } + engines: { node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1 } hasBin: true neo-async@2.6.2: - resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + resolution: + { + integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==, + } node-fetch@2.7.0: - resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} - engines: {node: 4.x || >=6.0.0} + resolution: + { + integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==, + } + engines: { node: 4.x || >=6.0.0 } peerDependencies: encoding: ^0.1.0 peerDependenciesMeta: @@ -849,294 +1396,518 @@ packages: optional: true nodemon@3.1.9: - resolution: {integrity: sha512-hdr1oIb2p6ZSxu3PB2JWWYS7ZQ0qvaZsc3hK8DR8f02kRzc8rjYmxAIvdz+aYC+8F2IjNaB7HMcSDg8nQpJxyg==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-hdr1oIb2p6ZSxu3PB2JWWYS7ZQ0qvaZsc3hK8DR8f02kRzc8rjYmxAIvdz+aYC+8F2IjNaB7HMcSDg8nQpJxyg==, + } + engines: { node: ">=10" } hasBin: true normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==, + } + engines: { node: ">=0.10.0" } npm-run-path@5.3.0: - resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + resolution: + { + integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==, + } + engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } nwsapi@2.2.19: - resolution: {integrity: sha512-94bcyI3RsqiZufXjkr3ltkI86iEl+I7uiHVDtcq9wJUTwYQJ5odHDeSzkkrRzi80jJ8MaeZgqKjH1bAWAFw9bA==} + resolution: + { + integrity: sha512-94bcyI3RsqiZufXjkr3ltkI86iEl+I7uiHVDtcq9wJUTwYQJ5odHDeSzkkrRzi80jJ8MaeZgqKjH1bAWAFw9bA==, + } onetime@6.0.0: - resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} - engines: {node: '>=12'} + resolution: + { + integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==, + } + engines: { node: ">=12" } p-limit@5.0.0: - resolution: {integrity: sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==, + } + engines: { node: ">=18" } parse5@7.2.1: - resolution: {integrity: sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==} + resolution: + { + integrity: sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==, + } path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==, + } + engines: { node: ">=8" } path-key@4.0.0: - resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} - engines: {node: '>=12'} + resolution: + { + integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==, + } + engines: { node: ">=12" } pathe@1.1.2: - resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + resolution: + { + integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==, + } pathe@2.0.3: - resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + resolution: + { + integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==, + } pathval@1.1.1: - resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} + resolution: + { + integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==, + } picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + resolution: + { + integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==, + } picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} + resolution: + { + integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==, + } + engines: { node: ">=8.6" } pkg-types@1.3.1: - resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + resolution: + { + integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==, + } playwright-core@1.52.0-alpha-2025-03-21: - resolution: {integrity: sha512-T7lqGZ1I8TZXuVTBz1dwE5yrwBimlIXlE88kiq9Rgub3jM8xaGtVKSlspeyozFZYS/GhCqPU6fG1oC8ndYvmGw==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-T7lqGZ1I8TZXuVTBz1dwE5yrwBimlIXlE88kiq9Rgub3jM8xaGtVKSlspeyozFZYS/GhCqPU6fG1oC8ndYvmGw==, + } + engines: { node: ">=18" } hasBin: true playwright@1.52.0-alpha-2025-03-21: - resolution: {integrity: sha512-KPF+1SS3V8/jmejyFRjx3PqXm0nbxI6ya+fVNpC4eWXA+TTmo3Oia52ZT6scEbmqDGG8S+YUXbmhTQMpfyL0Ow==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-KPF+1SS3V8/jmejyFRjx3PqXm0nbxI6ya+fVNpC4eWXA+TTmo3Oia52ZT6scEbmqDGG8S+YUXbmhTQMpfyL0Ow==, + } + engines: { node: ">=18" } hasBin: true postcss@8.5.3: - resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} - engines: {node: ^10 || ^12 || >=14} + resolution: + { + integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==, + } + engines: { node: ^10 || ^12 || >=14 } + + prettier@3.5.3: + resolution: + { + integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==, + } + engines: { node: ">=14" } + hasBin: true pretty-format@29.7.0: - resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + resolution: + { + integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } psl@1.15.0: - resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==} + resolution: + { + integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==, + } pstree.remy@1.1.8: - resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==} + resolution: + { + integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==, + } punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} + resolution: + { + integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==, + } + engines: { node: ">=6" } querystringify@2.2.0: - resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} + resolution: + { + integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==, + } react-is@18.3.1: - resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + resolution: + { + integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==, + } react@19.0.0: - resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==, + } + engines: { node: ">=0.10.0" } readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} + resolution: + { + integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==, + } + engines: { node: ">=8.10.0" } requires-port@1.0.0: - resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} + resolution: + { + integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==, + } rollup@4.37.0: - resolution: {integrity: sha512-iAtQy/L4QFU+rTJ1YUjXqJOJzuwEghqWzCEYD2FEghT7Gsy1VdABntrO4CLopA5IkflTyqNiLNwPcOJ3S7UKLg==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} + resolution: + { + integrity: sha512-iAtQy/L4QFU+rTJ1YUjXqJOJzuwEghqWzCEYD2FEghT7Gsy1VdABntrO4CLopA5IkflTyqNiLNwPcOJ3S7UKLg==, + } + engines: { node: ">=18.0.0", npm: ">=8.0.0" } hasBin: true rrweb-cssom@0.7.1: - resolution: {integrity: sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==} + resolution: + { + integrity: sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==, + } rrweb-cssom@0.8.0: - resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==} + resolution: + { + integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==, + } safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + resolution: + { + integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==, + } saxes@6.0.0: - resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} - engines: {node: '>=v12.22.7'} + resolution: + { + integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==, + } + engines: { node: ">=v12.22.7" } secure-json-parse@2.7.0: - resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} + resolution: + { + integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==, + } semver@7.7.1: - resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==, + } + engines: { node: ">=10" } hasBin: true shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==, + } + engines: { node: ">=8" } shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==, + } + engines: { node: ">=8" } siginfo@2.0.0: - resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + resolution: + { + integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==, + } signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} + resolution: + { + integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==, + } + engines: { node: ">=14" } simple-update-notifier@2.0.0: - resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==, + } + engines: { node: ">=10" } source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==, + } + engines: { node: ">=0.10.0" } source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==, + } + engines: { node: ">=0.10.0" } stackback@0.0.2: - resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + resolution: + { + integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==, + } std-env@3.8.1: - resolution: {integrity: sha512-vj5lIj3Mwf9D79hBkltk5qmkFI+biIKWS2IBxEyEU3AX1tUf7AoL8nSazCOiiqQsGKIq01SClsKEzweu34uwvA==} + resolution: + { + integrity: sha512-vj5lIj3Mwf9D79hBkltk5qmkFI+biIKWS2IBxEyEU3AX1tUf7AoL8nSazCOiiqQsGKIq01SClsKEzweu34uwvA==, + } strip-final-newline@3.0.0: - resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} - engines: {node: '>=12'} + resolution: + { + integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==, + } + engines: { node: ">=12" } strip-literal@2.1.1: - resolution: {integrity: sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q==} + resolution: + { + integrity: sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q==, + } supports-color@5.5.0: - resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} - engines: {node: '>=4'} + resolution: + { + integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==, + } + engines: { node: ">=4" } swr@2.3.3: - resolution: {integrity: sha512-dshNvs3ExOqtZ6kJBaAsabhPdHyeY4P2cKwRCniDVifBMoG/SVI7tfLWqPXriVspf2Rg4tPzXJTnwaihIeFw2A==} + resolution: + { + integrity: sha512-dshNvs3ExOqtZ6kJBaAsabhPdHyeY4P2cKwRCniDVifBMoG/SVI7tfLWqPXriVspf2Rg4tPzXJTnwaihIeFw2A==, + } peerDependencies: react: ^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 symbol-tree@3.2.4: - resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + resolution: + { + integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==, + } throttleit@2.1.0: - resolution: {integrity: sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==, + } + engines: { node: ">=18" } tinybench@2.9.0: - resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + resolution: + { + integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==, + } tinypool@0.8.4: - resolution: {integrity: sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==} - engines: {node: '>=14.0.0'} + resolution: + { + integrity: sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==, + } + engines: { node: ">=14.0.0" } tinyspy@2.2.1: - resolution: {integrity: sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==} - engines: {node: '>=14.0.0'} + resolution: + { + integrity: sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==, + } + engines: { node: ">=14.0.0" } tldts-core@6.1.85: - resolution: {integrity: sha512-DTjUVvxckL1fIoPSb3KE7ISNtkWSawZdpfxGxwiIrZoO6EbHVDXXUIlIuWympPaeS+BLGyggozX/HTMsRAdsoA==} + resolution: + { + integrity: sha512-DTjUVvxckL1fIoPSb3KE7ISNtkWSawZdpfxGxwiIrZoO6EbHVDXXUIlIuWympPaeS+BLGyggozX/HTMsRAdsoA==, + } tldts-experimental@6.1.85: - resolution: {integrity: sha512-oM+m5GnOdxgbnfSfix98YvzAIgkKZbdqMD/BTLbnbL349MyaEeNo6z8jVX9/lrL6DvnjgW7RV+sIVojrFvB+hw==} + resolution: + { + integrity: sha512-oM+m5GnOdxgbnfSfix98YvzAIgkKZbdqMD/BTLbnbL349MyaEeNo6z8jVX9/lrL6DvnjgW7RV+sIVojrFvB+hw==, + } to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} + resolution: + { + integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==, + } + engines: { node: ">=8.0" } touch@3.1.1: - resolution: {integrity: sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==} + resolution: + { + integrity: sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==, + } hasBin: true tough-cookie@4.1.4: - resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==} - engines: {node: '>=6'} + resolution: + { + integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==, + } + engines: { node: ">=6" } tr46@0.0.3: - resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + resolution: + { + integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==, + } tr46@5.1.0: - resolution: {integrity: sha512-IUWnUK7ADYR5Sl1fZlO1INDUhVhatWl7BtJWsIhwJ0UAK7ilzzIa8uIqOO/aYVWHZPJkKbEL+362wrzoeRF7bw==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-IUWnUK7ADYR5Sl1fZlO1INDUhVhatWl7BtJWsIhwJ0UAK7ilzzIa8uIqOO/aYVWHZPJkKbEL+362wrzoeRF7bw==, + } + engines: { node: ">=18" } ts-node@10.9.2: - resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + resolution: + { + integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==, + } hasBin: true peerDependencies: - '@swc/core': '>=1.2.50' - '@swc/wasm': '>=1.2.50' - '@types/node': '*' - typescript: '>=2.7' + "@swc/core": ">=1.2.50" + "@swc/wasm": ">=1.2.50" + "@types/node": "*" + typescript: ">=2.7" peerDependenciesMeta: - '@swc/core': + "@swc/core": optional: true - '@swc/wasm': + "@swc/wasm": optional: true type-detect@4.1.0: - resolution: {integrity: sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==} - engines: {node: '>=4'} + resolution: + { + integrity: sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==, + } + engines: { node: ">=4" } typescript@5.8.2: - resolution: {integrity: sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==} - engines: {node: '>=14.17'} + resolution: + { + integrity: sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==, + } + engines: { node: ">=14.17" } hasBin: true ufo@1.5.4: - resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==} + resolution: + { + integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==, + } uglify-js@3.19.3: - resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==} - engines: {node: '>=0.8.0'} + resolution: + { + integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==, + } + engines: { node: ">=0.8.0" } hasBin: true undefsafe@2.0.5: - resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==} + resolution: + { + integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==, + } undici-types@6.19.8: - resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + resolution: + { + integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==, + } universalify@0.2.0: - resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} - engines: {node: '>= 4.0.0'} + resolution: + { + integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==, + } + engines: { node: ">= 4.0.0" } url-parse@1.5.10: - resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} + resolution: + { + integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==, + } use-sync-external-store@1.4.0: - resolution: {integrity: sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==} + resolution: + { + integrity: sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==, + } peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 v8-compile-cache-lib@3.0.1: - resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + resolution: + { + integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==, + } vite-node@1.6.1: - resolution: {integrity: sha512-YAXkfvGtuTzwWbDSACdJSg4A4DZiAqckWe90Zapc/sEX3XvHcw1NdurM/6od8J207tSDqNbSsgdCacBgvJKFuA==} - engines: {node: ^18.0.0 || >=20.0.0} + resolution: + { + integrity: sha512-YAXkfvGtuTzwWbDSACdJSg4A4DZiAqckWe90Zapc/sEX3XvHcw1NdurM/6od8J207tSDqNbSsgdCacBgvJKFuA==, + } + engines: { node: ^18.0.0 || >=20.0.0 } hasBin: true vite@5.4.14: - resolution: {integrity: sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==} - engines: {node: ^18.0.0 || >=20.0.0} + resolution: + { + integrity: sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==, + } + engines: { node: ^18.0.0 || >=20.0.0 } hasBin: true peerDependencies: - '@types/node': ^18.0.0 || >=20.0.0 - less: '*' + "@types/node": ^18.0.0 || >=20.0.0 + less: "*" lightningcss: ^1.21.0 - sass: '*' - sass-embedded: '*' - stylus: '*' - sugarss: '*' + sass: "*" + sass-embedded: "*" + stylus: "*" + sugarss: "*" terser: ^5.4.0 peerDependenciesMeta: - '@types/node': + "@types/node": optional: true less: optional: true @@ -1154,24 +1925,27 @@ packages: optional: true vitest@1.6.1: - resolution: {integrity: sha512-Ljb1cnSJSivGN0LqXd/zmDbWEM0RNNg2t1QW/XUhYl/qPqyu7CsqeWtqQXHVaJsecLPuDoak2oJcZN2QoRIOag==} - engines: {node: ^18.0.0 || >=20.0.0} + resolution: + { + integrity: sha512-Ljb1cnSJSivGN0LqXd/zmDbWEM0RNNg2t1QW/XUhYl/qPqyu7CsqeWtqQXHVaJsecLPuDoak2oJcZN2QoRIOag==, + } + engines: { node: ^18.0.0 || >=20.0.0 } hasBin: true peerDependencies: - '@edge-runtime/vm': '*' - '@types/node': ^18.0.0 || >=20.0.0 - '@vitest/browser': 1.6.1 - '@vitest/ui': 1.6.1 - happy-dom: '*' - jsdom: '*' + "@edge-runtime/vm": "*" + "@types/node": ^18.0.0 || >=20.0.0 + "@vitest/browser": 1.6.1 + "@vitest/ui": 1.6.1 + happy-dom: "*" + jsdom: "*" peerDependenciesMeta: - '@edge-runtime/vm': + "@edge-runtime/vm": optional: true - '@types/node': + "@types/node": optional: true - '@vitest/browser': + "@vitest/browser": optional: true - '@vitest/ui': + "@vitest/ui": optional: true happy-dom: optional: true @@ -1179,50 +1953,83 @@ packages: optional: true w3c-xmlserializer@5.0.0: - resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==, + } + engines: { node: ">=18" } webidl-conversions@3.0.1: - resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + resolution: + { + integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==, + } webidl-conversions@7.0.0: - resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} - engines: {node: '>=12'} + resolution: + { + integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==, + } + engines: { node: ">=12" } whatwg-encoding@3.1.1: - resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==, + } + engines: { node: ">=18" } whatwg-mimetype@4.0.0: - resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==, + } + engines: { node: ">=18" } whatwg-url@14.2.0: - resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==, + } + engines: { node: ">=18" } whatwg-url@5.0.0: - resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + resolution: + { + integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==, + } which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} + resolution: + { + integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==, + } + engines: { node: ">= 8" } hasBin: true why-is-node-running@2.3.0: - resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==, + } + engines: { node: ">=8" } hasBin: true wordwrap@1.0.0: - resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} + resolution: + { + integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==, + } ws@8.18.1: - resolution: {integrity: sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==} - engines: {node: '>=10.0.0'} + resolution: + { + integrity: sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==, + } + engines: { node: ">=10.0.0" } peerDependencies: bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' + utf-8-validate: ">=5.0.2" peerDependenciesMeta: bufferutil: optional: true @@ -1230,329 +2037,346 @@ packages: optional: true xml-name-validator@5.0.0: - resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==, + } + engines: { node: ">=18" } xmlchars@2.2.0: - resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + resolution: + { + integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==, + } yn@3.1.1: - resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} - engines: {node: '>=6'} + resolution: + { + integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==, + } + engines: { node: ">=6" } yocto-queue@1.2.1: - resolution: {integrity: sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==} - engines: {node: '>=12.20'} + resolution: + { + integrity: sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==, + } + engines: { node: ">=12.20" } zod-to-json-schema@3.24.5: - resolution: {integrity: sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==} + resolution: + { + integrity: sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==, + } peerDependencies: zod: ^3.24.1 zod@3.24.2: - resolution: {integrity: sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==} + resolution: + { + integrity: sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==, + } snapshots: - - '@ai-sdk/openai@1.3.0(zod@3.24.2)': + "@ai-sdk/openai@1.3.0(zod@3.24.2)": dependencies: - '@ai-sdk/provider': 1.1.0 - '@ai-sdk/provider-utils': 2.2.0(zod@3.24.2) + "@ai-sdk/provider": 1.1.0 + "@ai-sdk/provider-utils": 2.2.0(zod@3.24.2) zod: 3.24.2 - '@ai-sdk/provider-utils@2.2.0(zod@3.24.2)': + "@ai-sdk/provider-utils@2.2.0(zod@3.24.2)": dependencies: - '@ai-sdk/provider': 1.1.0 + "@ai-sdk/provider": 1.1.0 eventsource-parser: 3.0.0 nanoid: 3.3.11 secure-json-parse: 2.7.0 zod: 3.24.2 - '@ai-sdk/provider@1.1.0': + "@ai-sdk/provider@1.1.0": dependencies: json-schema: 0.4.0 - '@ai-sdk/react@1.2.0(react@19.0.0)(zod@3.24.2)': + "@ai-sdk/react@1.2.0(react@19.0.0)(zod@3.24.2)": dependencies: - '@ai-sdk/provider-utils': 2.2.0(zod@3.24.2) - '@ai-sdk/ui-utils': 1.2.0(zod@3.24.2) + "@ai-sdk/provider-utils": 2.2.0(zod@3.24.2) + "@ai-sdk/ui-utils": 1.2.0(zod@3.24.2) react: 19.0.0 swr: 2.3.3(react@19.0.0) throttleit: 2.1.0 optionalDependencies: zod: 3.24.2 - '@ai-sdk/ui-utils@1.2.0(zod@3.24.2)': + "@ai-sdk/ui-utils@1.2.0(zod@3.24.2)": dependencies: - '@ai-sdk/provider': 1.1.0 - '@ai-sdk/provider-utils': 2.2.0(zod@3.24.2) + "@ai-sdk/provider": 1.1.0 + "@ai-sdk/provider-utils": 2.2.0(zod@3.24.2) zod: 3.24.2 zod-to-json-schema: 3.24.5(zod@3.24.2) - '@asamuzakjp/css-color@3.1.1': + "@asamuzakjp/css-color@3.1.1": dependencies: - '@csstools/css-calc': 2.1.2(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3) - '@csstools/css-color-parser': 3.0.8(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3) - '@csstools/css-parser-algorithms': 3.0.4(@csstools/css-tokenizer@3.0.3) - '@csstools/css-tokenizer': 3.0.3 + "@csstools/css-calc": 2.1.2(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3) + "@csstools/css-color-parser": 3.0.8(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3) + "@csstools/css-parser-algorithms": 3.0.4(@csstools/css-tokenizer@3.0.3) + "@csstools/css-tokenizer": 3.0.3 lru-cache: 10.4.3 - '@cspotcode/source-map-support@0.8.1': + "@cspotcode/source-map-support@0.8.1": dependencies: - '@jridgewell/trace-mapping': 0.3.9 + "@jridgewell/trace-mapping": 0.3.9 - '@csstools/color-helpers@5.0.2': {} + "@csstools/color-helpers@5.0.2": {} - '@csstools/css-calc@2.1.2(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3)': + "@csstools/css-calc@2.1.2(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3)": dependencies: - '@csstools/css-parser-algorithms': 3.0.4(@csstools/css-tokenizer@3.0.3) - '@csstools/css-tokenizer': 3.0.3 + "@csstools/css-parser-algorithms": 3.0.4(@csstools/css-tokenizer@3.0.3) + "@csstools/css-tokenizer": 3.0.3 - '@csstools/css-color-parser@3.0.8(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3)': + "@csstools/css-color-parser@3.0.8(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3)": dependencies: - '@csstools/color-helpers': 5.0.2 - '@csstools/css-calc': 2.1.2(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3) - '@csstools/css-parser-algorithms': 3.0.4(@csstools/css-tokenizer@3.0.3) - '@csstools/css-tokenizer': 3.0.3 + "@csstools/color-helpers": 5.0.2 + "@csstools/css-calc": 2.1.2(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3) + "@csstools/css-parser-algorithms": 3.0.4(@csstools/css-tokenizer@3.0.3) + "@csstools/css-tokenizer": 3.0.3 - '@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3)': + "@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3)": dependencies: - '@csstools/css-tokenizer': 3.0.3 + "@csstools/css-tokenizer": 3.0.3 - '@csstools/css-tokenizer@3.0.3': {} + "@csstools/css-tokenizer@3.0.3": {} - '@esbuild/aix-ppc64@0.21.5': + "@esbuild/aix-ppc64@0.21.5": optional: true - '@esbuild/android-arm64@0.21.5': + "@esbuild/android-arm64@0.21.5": optional: true - '@esbuild/android-arm@0.21.5': + "@esbuild/android-arm@0.21.5": optional: true - '@esbuild/android-x64@0.21.5': + "@esbuild/android-x64@0.21.5": optional: true - '@esbuild/darwin-arm64@0.21.5': + "@esbuild/darwin-arm64@0.21.5": optional: true - '@esbuild/darwin-x64@0.21.5': + "@esbuild/darwin-x64@0.21.5": optional: true - '@esbuild/freebsd-arm64@0.21.5': + "@esbuild/freebsd-arm64@0.21.5": optional: true - '@esbuild/freebsd-x64@0.21.5': + "@esbuild/freebsd-x64@0.21.5": optional: true - '@esbuild/linux-arm64@0.21.5': + "@esbuild/linux-arm64@0.21.5": optional: true - '@esbuild/linux-arm@0.21.5': + "@esbuild/linux-arm@0.21.5": optional: true - '@esbuild/linux-ia32@0.21.5': + "@esbuild/linux-ia32@0.21.5": optional: true - '@esbuild/linux-loong64@0.21.5': + "@esbuild/linux-loong64@0.21.5": optional: true - '@esbuild/linux-mips64el@0.21.5': + "@esbuild/linux-mips64el@0.21.5": optional: true - '@esbuild/linux-ppc64@0.21.5': + "@esbuild/linux-ppc64@0.21.5": optional: true - '@esbuild/linux-riscv64@0.21.5': + "@esbuild/linux-riscv64@0.21.5": optional: true - '@esbuild/linux-s390x@0.21.5': + "@esbuild/linux-s390x@0.21.5": optional: true - '@esbuild/linux-x64@0.21.5': + "@esbuild/linux-x64@0.21.5": optional: true - '@esbuild/netbsd-x64@0.21.5': + "@esbuild/netbsd-x64@0.21.5": optional: true - '@esbuild/openbsd-x64@0.21.5': + "@esbuild/openbsd-x64@0.21.5": optional: true - '@esbuild/sunos-x64@0.21.5': + "@esbuild/sunos-x64@0.21.5": optional: true - '@esbuild/win32-arm64@0.21.5': + "@esbuild/win32-arm64@0.21.5": optional: true - '@esbuild/win32-ia32@0.21.5': + "@esbuild/win32-ia32@0.21.5": optional: true - '@esbuild/win32-x64@0.21.5': + "@esbuild/win32-x64@0.21.5": optional: true - '@ghostery/adblocker-content@2.5.0': + "@ghostery/adblocker-content@2.5.0": dependencies: - '@ghostery/adblocker-extended-selectors': 2.5.0 + "@ghostery/adblocker-extended-selectors": 2.5.0 - '@ghostery/adblocker-extended-selectors@2.5.0': {} + "@ghostery/adblocker-extended-selectors@2.5.0": {} - '@ghostery/adblocker-playwright@2.5.0(playwright@1.52.0-alpha-2025-03-21)': + "@ghostery/adblocker-playwright@2.5.0(playwright@1.52.0-alpha-2025-03-21)": dependencies: - '@ghostery/adblocker': 2.5.0 - '@ghostery/adblocker-content': 2.5.0 + "@ghostery/adblocker": 2.5.0 + "@ghostery/adblocker-content": 2.5.0 playwright: 1.52.0-alpha-2025-03-21 tldts-experimental: 6.1.85 - '@ghostery/adblocker@2.5.0': + "@ghostery/adblocker@2.5.0": dependencies: - '@ghostery/adblocker-content': 2.5.0 - '@ghostery/adblocker-extended-selectors': 2.5.0 - '@remusao/guess-url-type': 1.3.0 - '@remusao/small': 1.3.0 - '@remusao/smaz': 1.10.0 + "@ghostery/adblocker-content": 2.5.0 + "@ghostery/adblocker-extended-selectors": 2.5.0 + "@remusao/guess-url-type": 1.3.0 + "@remusao/small": 1.3.0 + "@remusao/smaz": 1.10.0 tldts-experimental: 6.1.85 - '@jest/schemas@29.6.3': + "@jest/schemas@29.6.3": dependencies: - '@sinclair/typebox': 0.27.8 + "@sinclair/typebox": 0.27.8 - '@jridgewell/resolve-uri@3.1.2': {} + "@jridgewell/resolve-uri@3.1.2": {} - '@jridgewell/sourcemap-codec@1.5.0': {} + "@jridgewell/sourcemap-codec@1.5.0": {} - '@jridgewell/trace-mapping@0.3.9': + "@jridgewell/trace-mapping@0.3.9": dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.0 + "@jridgewell/resolve-uri": 3.1.2 + "@jridgewell/sourcemap-codec": 1.5.0 - '@opentelemetry/api@1.9.0': {} + "@opentelemetry/api@1.9.0": {} - '@remusao/guess-url-type@1.3.0': {} + "@remusao/guess-url-type@1.3.0": {} - '@remusao/small@1.3.0': {} + "@remusao/small@1.3.0": {} - '@remusao/smaz-compress@1.10.0': + "@remusao/smaz-compress@1.10.0": dependencies: - '@remusao/trie': 1.5.0 + "@remusao/trie": 1.5.0 - '@remusao/smaz-decompress@1.10.0': {} + "@remusao/smaz-decompress@1.10.0": {} - '@remusao/smaz@1.10.0': + "@remusao/smaz@1.10.0": dependencies: - '@remusao/smaz-compress': 1.10.0 - '@remusao/smaz-decompress': 1.10.0 + "@remusao/smaz-compress": 1.10.0 + "@remusao/smaz-decompress": 1.10.0 - '@remusao/trie@1.5.0': {} + "@remusao/trie@1.5.0": {} - '@rollup/rollup-android-arm-eabi@4.37.0': + "@rollup/rollup-android-arm-eabi@4.37.0": optional: true - '@rollup/rollup-android-arm64@4.37.0': + "@rollup/rollup-android-arm64@4.37.0": optional: true - '@rollup/rollup-darwin-arm64@4.37.0': + "@rollup/rollup-darwin-arm64@4.37.0": optional: true - '@rollup/rollup-darwin-x64@4.37.0': + "@rollup/rollup-darwin-x64@4.37.0": optional: true - '@rollup/rollup-freebsd-arm64@4.37.0': + "@rollup/rollup-freebsd-arm64@4.37.0": optional: true - '@rollup/rollup-freebsd-x64@4.37.0': + "@rollup/rollup-freebsd-x64@4.37.0": optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.37.0': + "@rollup/rollup-linux-arm-gnueabihf@4.37.0": optional: true - '@rollup/rollup-linux-arm-musleabihf@4.37.0': + "@rollup/rollup-linux-arm-musleabihf@4.37.0": optional: true - '@rollup/rollup-linux-arm64-gnu@4.37.0': + "@rollup/rollup-linux-arm64-gnu@4.37.0": optional: true - '@rollup/rollup-linux-arm64-musl@4.37.0': + "@rollup/rollup-linux-arm64-musl@4.37.0": optional: true - '@rollup/rollup-linux-loongarch64-gnu@4.37.0': + "@rollup/rollup-linux-loongarch64-gnu@4.37.0": optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.37.0': + "@rollup/rollup-linux-powerpc64le-gnu@4.37.0": optional: true - '@rollup/rollup-linux-riscv64-gnu@4.37.0': + "@rollup/rollup-linux-riscv64-gnu@4.37.0": optional: true - '@rollup/rollup-linux-riscv64-musl@4.37.0': + "@rollup/rollup-linux-riscv64-musl@4.37.0": optional: true - '@rollup/rollup-linux-s390x-gnu@4.37.0': + "@rollup/rollup-linux-s390x-gnu@4.37.0": optional: true - '@rollup/rollup-linux-x64-gnu@4.37.0': + "@rollup/rollup-linux-x64-gnu@4.37.0": optional: true - '@rollup/rollup-linux-x64-musl@4.37.0': + "@rollup/rollup-linux-x64-musl@4.37.0": optional: true - '@rollup/rollup-win32-arm64-msvc@4.37.0': + "@rollup/rollup-win32-arm64-msvc@4.37.0": optional: true - '@rollup/rollup-win32-ia32-msvc@4.37.0': + "@rollup/rollup-win32-ia32-msvc@4.37.0": optional: true - '@rollup/rollup-win32-x64-msvc@4.37.0': + "@rollup/rollup-win32-x64-msvc@4.37.0": optional: true - '@sinclair/typebox@0.27.8': {} + "@sinclair/typebox@0.27.8": {} - '@tsconfig/node10@1.0.11': {} + "@tsconfig/node10@1.0.11": {} - '@tsconfig/node12@1.0.11': {} + "@tsconfig/node12@1.0.11": {} - '@tsconfig/node14@1.0.3': {} + "@tsconfig/node14@1.0.3": {} - '@tsconfig/node16@1.0.4': {} + "@tsconfig/node16@1.0.4": {} - '@types/diff-match-patch@1.0.36': {} + "@types/diff-match-patch@1.0.36": {} - '@types/estree@1.0.6': {} + "@types/estree@1.0.6": {} - '@types/jsdom@21.1.7': + "@types/jsdom@21.1.7": dependencies: - '@types/node': 20.17.25 - '@types/tough-cookie': 4.0.5 + "@types/node": 20.17.25 + "@types/tough-cookie": 4.0.5 parse5: 7.2.1 - '@types/node@20.17.25': + "@types/node@20.17.25": dependencies: undici-types: 6.19.8 - '@types/tough-cookie@4.0.5': {} + "@types/tough-cookie@4.0.5": {} - '@vitest/expect@1.6.1': + "@vitest/expect@1.6.1": dependencies: - '@vitest/spy': 1.6.1 - '@vitest/utils': 1.6.1 + "@vitest/spy": 1.6.1 + "@vitest/utils": 1.6.1 chai: 4.5.0 - '@vitest/runner@1.6.1': + "@vitest/runner@1.6.1": dependencies: - '@vitest/utils': 1.6.1 + "@vitest/utils": 1.6.1 p-limit: 5.0.0 pathe: 1.1.2 - '@vitest/snapshot@1.6.1': + "@vitest/snapshot@1.6.1": dependencies: magic-string: 0.30.17 pathe: 1.1.2 pretty-format: 29.7.0 - '@vitest/spy@1.6.1': + "@vitest/spy@1.6.1": dependencies: tinyspy: 2.2.1 - '@vitest/utils@1.6.1': + "@vitest/utils@1.6.1": dependencies: diff-sequences: 29.6.3 estree-walker: 3.0.3 @@ -1569,11 +2393,11 @@ snapshots: ai@4.2.0(react@19.0.0)(zod@3.24.2): dependencies: - '@ai-sdk/provider': 1.1.0 - '@ai-sdk/provider-utils': 2.2.0(zod@3.24.2) - '@ai-sdk/react': 1.2.0(react@19.0.0)(zod@3.24.2) - '@ai-sdk/ui-utils': 1.2.0(zod@3.24.2) - '@opentelemetry/api': 1.9.0 + "@ai-sdk/provider": 1.1.0 + "@ai-sdk/provider-utils": 2.2.0(zod@3.24.2) + "@ai-sdk/react": 1.2.0(react@19.0.0)(zod@3.24.2) + "@ai-sdk/ui-utils": 1.2.0(zod@3.24.2) + "@opentelemetry/api": 1.9.0 eventsource-parser: 3.0.0 jsondiffpatch: 0.6.0 zod: 3.24.2 @@ -1665,7 +2489,7 @@ snapshots: cssstyle@4.3.0: dependencies: - '@asamuzakjp/css-color': 3.1.1 + "@asamuzakjp/css-color": 3.1.1 rrweb-cssom: 0.8.0 data-urls@5.0.0: @@ -1722,33 +2546,33 @@ snapshots: esbuild@0.21.5: 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 + "@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 estree-walker@3.0.3: dependencies: - '@types/estree': 1.0.6 + "@types/estree": 1.0.6 eventemitter3@5.0.1: {} @@ -1912,7 +2736,7 @@ snapshots: jsondiffpatch@0.6.0: dependencies: - '@types/diff-match-patch': 1.0.36 + "@types/diff-match-patch": 1.0.36 chalk: 5.4.1 diff-match-patch: 1.0.5 @@ -1929,7 +2753,7 @@ snapshots: magic-string@0.30.17: dependencies: - '@jridgewell/sourcemap-codec': 1.5.0 + "@jridgewell/sourcemap-codec": 1.5.0 make-error@1.3.6: {} @@ -2035,9 +2859,11 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + prettier@3.5.3: {} + pretty-format@29.7.0: dependencies: - '@jest/schemas': 29.6.3 + "@jest/schemas": 29.6.3 ansi-styles: 5.2.0 react-is: 18.3.1 @@ -2063,28 +2889,28 @@ snapshots: rollup@4.37.0: dependencies: - '@types/estree': 1.0.6 + "@types/estree": 1.0.6 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.37.0 - '@rollup/rollup-android-arm64': 4.37.0 - '@rollup/rollup-darwin-arm64': 4.37.0 - '@rollup/rollup-darwin-x64': 4.37.0 - '@rollup/rollup-freebsd-arm64': 4.37.0 - '@rollup/rollup-freebsd-x64': 4.37.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.37.0 - '@rollup/rollup-linux-arm-musleabihf': 4.37.0 - '@rollup/rollup-linux-arm64-gnu': 4.37.0 - '@rollup/rollup-linux-arm64-musl': 4.37.0 - '@rollup/rollup-linux-loongarch64-gnu': 4.37.0 - '@rollup/rollup-linux-powerpc64le-gnu': 4.37.0 - '@rollup/rollup-linux-riscv64-gnu': 4.37.0 - '@rollup/rollup-linux-riscv64-musl': 4.37.0 - '@rollup/rollup-linux-s390x-gnu': 4.37.0 - '@rollup/rollup-linux-x64-gnu': 4.37.0 - '@rollup/rollup-linux-x64-musl': 4.37.0 - '@rollup/rollup-win32-arm64-msvc': 4.37.0 - '@rollup/rollup-win32-ia32-msvc': 4.37.0 - '@rollup/rollup-win32-x64-msvc': 4.37.0 + "@rollup/rollup-android-arm-eabi": 4.37.0 + "@rollup/rollup-android-arm64": 4.37.0 + "@rollup/rollup-darwin-arm64": 4.37.0 + "@rollup/rollup-darwin-x64": 4.37.0 + "@rollup/rollup-freebsd-arm64": 4.37.0 + "@rollup/rollup-freebsd-x64": 4.37.0 + "@rollup/rollup-linux-arm-gnueabihf": 4.37.0 + "@rollup/rollup-linux-arm-musleabihf": 4.37.0 + "@rollup/rollup-linux-arm64-gnu": 4.37.0 + "@rollup/rollup-linux-arm64-musl": 4.37.0 + "@rollup/rollup-linux-loongarch64-gnu": 4.37.0 + "@rollup/rollup-linux-powerpc64le-gnu": 4.37.0 + "@rollup/rollup-linux-riscv64-gnu": 4.37.0 + "@rollup/rollup-linux-riscv64-musl": 4.37.0 + "@rollup/rollup-linux-s390x-gnu": 4.37.0 + "@rollup/rollup-linux-x64-gnu": 4.37.0 + "@rollup/rollup-linux-x64-musl": 4.37.0 + "@rollup/rollup-win32-arm64-msvc": 4.37.0 + "@rollup/rollup-win32-ia32-msvc": 4.37.0 + "@rollup/rollup-win32-x64-msvc": 4.37.0 fsevents: 2.3.3 rrweb-cssom@0.7.1: {} @@ -2176,12 +3002,12 @@ snapshots: ts-node@10.9.2(@types/node@20.17.25)(typescript@5.8.2): dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.11 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.4 - '@types/node': 20.17.25 + "@cspotcode/source-map-support": 0.8.1 + "@tsconfig/node10": 1.0.11 + "@tsconfig/node12": 1.0.11 + "@tsconfig/node14": 1.0.3 + "@tsconfig/node16": 1.0.4 + "@types/node": 20.17.25 acorn: 8.14.1 acorn-walk: 8.3.4 arg: 4.1.3 @@ -2226,7 +3052,7 @@ snapshots: picocolors: 1.1.1 vite: 5.4.14(@types/node@20.17.25) transitivePeerDependencies: - - '@types/node' + - "@types/node" - less - lightningcss - sass @@ -2242,16 +3068,16 @@ snapshots: postcss: 8.5.3 rollup: 4.37.0 optionalDependencies: - '@types/node': 20.17.25 + "@types/node": 20.17.25 fsevents: 2.3.3 vitest@1.6.1(@types/node@20.17.25)(jsdom@24.1.3): dependencies: - '@vitest/expect': 1.6.1 - '@vitest/runner': 1.6.1 - '@vitest/snapshot': 1.6.1 - '@vitest/spy': 1.6.1 - '@vitest/utils': 1.6.1 + "@vitest/expect": 1.6.1 + "@vitest/runner": 1.6.1 + "@vitest/snapshot": 1.6.1 + "@vitest/spy": 1.6.1 + "@vitest/utils": 1.6.1 acorn-walk: 8.3.4 chai: 4.5.0 debug: 4.4.0(supports-color@5.5.0) @@ -2268,7 +3094,7 @@ snapshots: vite-node: 1.6.1(@types/node@20.17.25) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 20.17.25 + "@types/node": 20.17.25 jsdom: 24.1.3 transitivePeerDependencies: - less diff --git a/src/browser/ariaBrowser.ts b/src/browser/ariaBrowser.ts index ddb059aa..155e280e 100644 --- a/src/browser/ariaBrowser.ts +++ b/src/browser/ariaBrowser.ts @@ -73,8 +73,5 @@ export interface AriaBrowser { * @param state The load state to wait for * @param options Additional options like timeout */ - waitForLoadState( - state: LoadState, - options?: { timeout?: number } - ): Promise; + waitForLoadState(state: LoadState, options?: { timeout?: number }): Promise; } diff --git a/src/browser/playwrightBrowser.ts b/src/browser/playwrightBrowser.ts index d9be4ac4..eaf61287 100644 --- a/src/browser/playwrightBrowser.ts +++ b/src/browser/playwrightBrowser.ts @@ -26,10 +26,8 @@ export class PlaywrightBrowser implements AriaBrowser { device?: string; bypassCSP?: boolean; blockAds?: boolean; - blockResources?: Array< - "image" | "stylesheet" | "font" | "media" | "manifest" - >; - } = {} + blockResources?: Array<"image" | "stylesheet" | "font" | "media" | "manifest">; + } = {}, ) {} async start(): Promise { @@ -99,7 +97,7 @@ export class PlaywrightBrowser implements AriaBrowser { console.error( `❌ Navigation failed to: ${url} - ${ error instanceof Error ? error.message : String(error) - }` + }`, ); throw error; // Re-throw to allow caller to handle } @@ -117,9 +115,7 @@ export class PlaywrightBrowser implements AriaBrowser { await this.ensureOptimizedPageLoad(); } catch (error) { console.error( - `❌ Back navigation failed: ${ - error instanceof Error ? error.message : String(error) - }` + `❌ Back navigation failed: ${error instanceof Error ? error.message : String(error)}`, ); throw error; // Re-throw to allow caller to handle } @@ -137,9 +133,7 @@ export class PlaywrightBrowser implements AriaBrowser { await this.ensureOptimizedPageLoad(); } catch (error) { console.error( - `❌ Forward navigation failed: ${ - error instanceof Error ? error.message : String(error) - }` + `❌ Forward navigation failed: ${error instanceof Error ? error.message : String(error)}`, ); throw error; // Re-throw to allow caller to handle } @@ -155,9 +149,7 @@ export class PlaywrightBrowser implements AriaBrowser { console.debug("✅ DOM content loaded successfully"); } catch (error) { console.error( - `❌ DOM content load failed: ${ - error instanceof Error ? error.message : String(error) - }` + `❌ DOM content load failed: ${error instanceof Error ? error.message : String(error)}`, ); // Still continue since we might be able to interact with what's loaded } @@ -173,7 +165,7 @@ export class PlaywrightBrowser implements AriaBrowser { console.debug( `⚠️ Page load timed out after ${this.ACTION_TIMEOUT_MS}ms: ${ error instanceof Error ? error.message : String(error) - }` + }`, ); } } @@ -198,16 +190,13 @@ export class PlaywrightBrowser implements AriaBrowser { return await this.page.screenshot(); } - async waitForLoadState( - state: LoadState, - options?: { timeout?: number } - ): Promise { + async waitForLoadState(state: LoadState, options?: { timeout?: number }): Promise { if (!this.page) throw new Error("Browser not started"); try { console.debug( `🔄 Waiting for load state: ${state}${ options?.timeout ? ` with timeout ${options.timeout}ms` : "" - }` + }`, ); await this.page.waitForLoadState(state, options); console.debug(`✅ Load state "${state}" reached successfully`); @@ -215,17 +204,13 @@ export class PlaywrightBrowser implements AriaBrowser { console.error( `❌ Failed to reach load state "${state}": ${ error instanceof Error ? error.message : String(error) - }` + }`, ); throw error; // Re-throw to allow caller to handle } } - async performAction( - ref: string, - action: PageAction, - value?: string - ): Promise { + async performAction(ref: string, action: PageAction, value?: string): Promise { if (!this.page) throw new Error("Browser not started"); try { @@ -233,7 +218,7 @@ export class PlaywrightBrowser implements AriaBrowser { console.debug( `🔄 Performing ${action} action on element with ref=${ref}${ value ? ` with value="${value}"` : "" - }` + }`, ); // Create a locator for the element @@ -256,9 +241,7 @@ export class PlaywrightBrowser implements AriaBrowser { case PageAction.Fill: if (!value) throw new Error("Value required for fill action"); await locator.fill(value, { timeout: this.ACTION_TIMEOUT_MS }); - console.debug( - `✅ Fill successful on ref=${ref} with value="${value}"` - ); + console.debug(`✅ Fill successful on ref=${ref} with value="${value}"`); break; case PageAction.Focus: @@ -281,9 +264,7 @@ export class PlaywrightBrowser implements AriaBrowser { await locator.selectOption(value, { timeout: this.ACTION_TIMEOUT_MS, }); - console.debug( - `✅ Select successful on ref=${ref} with value="${value}"` - ); + console.debug(`✅ Select successful on ref=${ref} with value="${value}"`); // Forms might trigger page reloads on select await this.ensureOptimizedPageLoad(); break; @@ -326,12 +307,10 @@ export class PlaywrightBrowser implements AriaBrowser { console.error( `❌ Failed to perform ${action} action on ref=${ref}${ value ? ` with value="${value}"` : "" - }: ${error instanceof Error ? error.message : String(error)}` + }: ${error instanceof Error ? error.message : String(error)}`, ); throw new Error( - `Failed to perform action: ${ - error instanceof Error ? error.message : String(error) - }` + `Failed to perform action: ${error instanceof Error ? error.message : String(error)}`, ); } } diff --git a/src/events.ts b/src/events.ts index 188a850b..0785bec6 100644 --- a/src/events.ts +++ b/src/events.ts @@ -194,7 +194,7 @@ export class WebAgentEventEmitter extends EventEmitter { */ onEvent( eventType: T, - listener: (data: Extract["data"]) => void + listener: (data: Extract["data"]) => void, ): this { return this.on(eventType, listener); } @@ -204,7 +204,7 @@ export class WebAgentEventEmitter extends EventEmitter { */ onceEvent( eventType: T, - listener: (data: Extract["data"]) => void + listener: (data: Extract["data"]) => void, ): this { return this.once(eventType, listener); } @@ -214,7 +214,7 @@ export class WebAgentEventEmitter extends EventEmitter { */ offEvent( eventType: T, - listener: (data: Extract["data"]) => void + listener: (data: Extract["data"]) => void, ): this { return this.off(eventType, listener); } diff --git a/src/index.ts b/src/index.ts index 7dbc262e..f43d51bf 100644 --- a/src/index.ts +++ b/src/index.ts @@ -19,11 +19,9 @@ if (!task) { console.log(` ${chalk.cyan("spark")} ${chalk.green("")} ${chalk.yellow("[url]")}`); console.log(""); console.log(chalk.white.bold("Examples:")); + console.log(` ${chalk.cyan("spark")} ${chalk.green('"search for flights to Paris"')}`); console.log( - ` ${chalk.cyan("spark")} ${chalk.green('"search for flights to Paris"')}` - ); - console.log( - ` ${chalk.cyan("spark")} ${chalk.green('"find the latest news"')} ${chalk.yellow("https://news.ycombinator.com")}` + ` ${chalk.cyan("spark")} ${chalk.green('"find the latest news"')} ${chalk.yellow("https://news.ycombinator.com")}`, ); console.log(""); process.exit(1); diff --git a/src/loggers.ts b/src/loggers.ts index 687d45c5..ce68661f 100644 --- a/src/loggers.ts +++ b/src/loggers.ts @@ -46,16 +46,10 @@ export class ConsoleLogger implements Logger { // Task events emitter.onEvent(WebAgentEventType.TASK_START, this.handleTaskStart); emitter.onEvent(WebAgentEventType.TASK_COMPLETE, this.handleTaskComplete); - emitter.onEvent( - WebAgentEventType.TASK_VALIDATION, - this.handleTaskValidation - ); + emitter.onEvent(WebAgentEventType.TASK_VALIDATION, this.handleTaskValidation); // Page events - emitter.onEvent( - WebAgentEventType.PAGE_NAVIGATION, - this.handlePageNavigation - ); + emitter.onEvent(WebAgentEventType.PAGE_NAVIGATION, this.handlePageNavigation); // Agent reasoning events emitter.onEvent(WebAgentEventType.CURRENT_STEP, this.handleCurrentStep); @@ -64,29 +58,17 @@ export class ConsoleLogger implements Logger { emitter.onEvent(WebAgentEventType.EXTRACTED_DATA, this.handleExtractedData); // Action events - emitter.onEvent( - WebAgentEventType.ACTION_EXECUTION, - this.handleActionExecution - ); + emitter.onEvent(WebAgentEventType.ACTION_EXECUTION, this.handleActionExecution); emitter.onEvent(WebAgentEventType.ACTION_RESULT, this.handleActionResult); // Debug events - emitter.onEvent( - WebAgentEventType.DEBUG_COMPRESSION, - this.handleCompressionDebug - ); + emitter.onEvent(WebAgentEventType.DEBUG_COMPRESSION, this.handleCompressionDebug); emitter.onEvent(WebAgentEventType.DEBUG_MESSAGES, this.handleMessagesDebug); // Waiting events emitter.onEvent(WebAgentEventType.WAITING, this.handleWaiting); - emitter.onEvent( - WebAgentEventType.NETWORK_WAITING, - this.handleNetworkWaiting - ); - emitter.onEvent( - WebAgentEventType.NETWORK_TIMEOUT, - this.handleNetworkTimeout - ); + emitter.onEvent(WebAgentEventType.NETWORK_WAITING, this.handleNetworkWaiting); + emitter.onEvent(WebAgentEventType.NETWORK_TIMEOUT, this.handleNetworkTimeout); } dispose(): void { @@ -94,66 +76,30 @@ export class ConsoleLogger implements Logger { if (this.emitter) { // Task events this.emitter.offEvent(WebAgentEventType.TASK_START, this.handleTaskStart); - this.emitter.offEvent( - WebAgentEventType.TASK_COMPLETE, - this.handleTaskComplete - ); - this.emitter.offEvent( - WebAgentEventType.TASK_VALIDATION, - this.handleTaskValidation - ); + this.emitter.offEvent(WebAgentEventType.TASK_COMPLETE, this.handleTaskComplete); + this.emitter.offEvent(WebAgentEventType.TASK_VALIDATION, this.handleTaskValidation); // Page events - this.emitter.offEvent( - WebAgentEventType.PAGE_NAVIGATION, - this.handlePageNavigation - ); + this.emitter.offEvent(WebAgentEventType.PAGE_NAVIGATION, this.handlePageNavigation); // Agent reasoning events - this.emitter.offEvent( - WebAgentEventType.CURRENT_STEP, - this.handleCurrentStep - ); - this.emitter.offEvent( - WebAgentEventType.OBSERVATION, - this.handleObservation - ); + this.emitter.offEvent(WebAgentEventType.CURRENT_STEP, this.handleCurrentStep); + this.emitter.offEvent(WebAgentEventType.OBSERVATION, this.handleObservation); this.emitter.offEvent(WebAgentEventType.THOUGHT, this.handleThought); - this.emitter.offEvent( - WebAgentEventType.EXTRACTED_DATA, - this.handleExtractedData - ); + this.emitter.offEvent(WebAgentEventType.EXTRACTED_DATA, this.handleExtractedData); // Action events - this.emitter.offEvent( - WebAgentEventType.ACTION_EXECUTION, - this.handleActionExecution - ); - this.emitter.offEvent( - WebAgentEventType.ACTION_RESULT, - this.handleActionResult - ); + this.emitter.offEvent(WebAgentEventType.ACTION_EXECUTION, this.handleActionExecution); + this.emitter.offEvent(WebAgentEventType.ACTION_RESULT, this.handleActionResult); // Debug events - this.emitter.offEvent( - WebAgentEventType.DEBUG_COMPRESSION, - this.handleCompressionDebug - ); - this.emitter.offEvent( - WebAgentEventType.DEBUG_MESSAGES, - this.handleMessagesDebug - ); + this.emitter.offEvent(WebAgentEventType.DEBUG_COMPRESSION, this.handleCompressionDebug); + this.emitter.offEvent(WebAgentEventType.DEBUG_MESSAGES, this.handleMessagesDebug); // Waiting events this.emitter.offEvent(WebAgentEventType.WAITING, this.handleWaiting); - this.emitter.offEvent( - WebAgentEventType.NETWORK_WAITING, - this.handleNetworkWaiting - ); - this.emitter.offEvent( - WebAgentEventType.NETWORK_TIMEOUT, - this.handleNetworkTimeout - ); + this.emitter.offEvent(WebAgentEventType.NETWORK_WAITING, this.handleNetworkWaiting); + this.emitter.offEvent(WebAgentEventType.NETWORK_TIMEOUT, this.handleNetworkTimeout); // Reset emitter reference this.emitter = null; @@ -166,55 +112,35 @@ export class ConsoleLogger implements Logger { console.log(chalk.whiteBright(data.explanation)); console.log(chalk.magenta.bold("\n📋 Plan:")); console.log(chalk.whiteBright(data.plan)); - console.log( - chalk.blue.bold("🌐 Starting URL: "), - chalk.blue.underline(data.url) - ); + console.log(chalk.blue.bold("🌐 Starting URL: "), chalk.blue.underline(data.url)); }; private handleTaskComplete = (data: TaskCompleteEventData): void => { if (data.finalAnswer) { - console.log( - chalk.green.bold("\n✨ Final Answer:"), - chalk.whiteBright(data.finalAnswer) - ); + console.log(chalk.green.bold("\n✨ Final Answer:"), chalk.whiteBright(data.finalAnswer)); } }; private handleTaskValidation = (data: TaskValidationEventData): void => { if (data.isValid) { - console.log( - chalk.green.bold("\n✅ Task Validation:"), - chalk.green("Answer is valid") - ); + console.log(chalk.green.bold("\n✅ Task Validation:"), chalk.green("Answer is valid")); } else { console.log( chalk.yellow.bold("\n⚠️ Task Validation:"), - chalk.yellow("Answer needs improvement") + chalk.yellow("Answer needs improvement"), ); if (data.feedback) { - console.log( - chalk.yellow(" Feedback:"), - chalk.whiteBright(data.feedback) - ); + console.log(chalk.yellow(" Feedback:"), chalk.whiteBright(data.feedback)); } } }; private handlePageNavigation = (data: PageNavigationEventData): void => { - console.log( - chalk.gray( - "\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n" - ) - ); + console.log(chalk.gray("\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n")); - const truncatedTitle = - data.title.length > 50 ? data.title.slice(0, 47) + "..." : data.title; + const truncatedTitle = data.title.length > 50 ? data.title.slice(0, 47) + "..." : data.title; - console.log( - chalk.blue.bold("📍 Current Page:"), - chalk.blue(truncatedTitle) - ); + console.log(chalk.blue.bold("📍 Current Page:"), chalk.blue(truncatedTitle)); }; private handleCurrentStep = (data: CurrentStepEventData): void => { @@ -242,14 +168,14 @@ export class ConsoleLogger implements Logger { console.log( chalk.whiteBright(` 1. ${data.action.toUpperCase()}`), data.ref ? chalk.cyan(`ref: ${data.ref}`) : "", - data.value ? chalk.green(`value: "${data.value}"`) : "" + data.value ? chalk.green(`value: "${data.value}"`) : "", ); console.log( chalk.cyan.bold("\n▶️ Executing action:"), chalk.whiteBright(data.action.toUpperCase()), data.ref ? chalk.cyan(`ref: ${data.ref}`) : "", - data.value ? chalk.green(`value: "${data.value}"`) : "" + data.value ? chalk.green(`value: "${data.value}"`) : "", ); }; @@ -257,7 +183,7 @@ export class ConsoleLogger implements Logger { if (!data.success) { console.error( chalk.red.bold(`❌ Failed to execute action: `), - chalk.whiteBright(data.error || "Unknown error") + chalk.whiteBright(data.error || "Unknown error"), ); } }; @@ -266,7 +192,7 @@ export class ConsoleLogger implements Logger { console.log( chalk.gray("\n📝 Compression:"), chalk.green(`${data.compressionPercent}%`), - chalk.gray(`(${data.originalSize} → ${data.compressedSize} chars)`) + chalk.gray(`(${data.originalSize} → ${data.compressedSize} chars)`), ); }; @@ -277,11 +203,7 @@ export class ConsoleLogger implements Logger { private handleWaiting = (data: WaitingEventData): void => { console.log( - chalk.yellow.bold( - `⏳ Waiting for ${data.seconds} second${ - data.seconds !== 1 ? "s" : "" - }...` - ) + chalk.yellow.bold(`⏳ Waiting for ${data.seconds} second${data.seconds !== 1 ? "s" : ""}...`), ); }; diff --git a/src/prompts.ts b/src/prompts.ts index c466c37b..07e30f48 100644 --- a/src/prompts.ts +++ b/src/prompts.ts @@ -7,7 +7,8 @@ You adapt to situations and find creative ways to complete tasks without getting import { buildPromptTemplate } from "./templateUtils.js"; -const planPromptTemplate = buildPromptTemplate(` +const planPromptTemplate = buildPromptTemplate( + ` {{youArePrompt}} Create a plan for this web navigation task. Provide a clear explanation{{#if includeUrl}}, step-by-step plan, and starting URL{{else}} and step-by-step plan{{/if}}. @@ -33,23 +34,24 @@ Respond with a JSON object matching this structure: "url": "Must be a real top-level domain with no path OR a web search: https://duckduckgo.com/?q=search+query"{{/if}} } \`\`\` -`.trim()); +`.trim(), +); -export const buildPlanAndUrlPrompt = (task: string) => +export const buildPlanAndUrlPrompt = (task: string) => planPromptTemplate({ youArePrompt, task, currentDate: getCurrentFormattedDate(), - includeUrl: true + includeUrl: true, }); -export const buildPlanPrompt = (task: string, startingUrl?: string) => +export const buildPlanPrompt = (task: string, startingUrl?: string) => planPromptTemplate({ youArePrompt, task, currentDate: getCurrentFormattedDate(), includeUrl: false, - startingUrl + startingUrl, }); const actionLoopResponseFormat = `{ @@ -101,25 +103,25 @@ ${actionLoopResponseFormat} \`\`\` `.trim(); -const taskAndPlanTemplate = buildPromptTemplate(` +const taskAndPlanTemplate = buildPromptTemplate( + ` Task: {{task}} Explanation: {{explanation}} Plan: {{plan}} Today's Date: {{currentDate}} -`.trim()); - -export const buildTaskAndPlanPrompt = ( - task: string, - explanation: string, - plan: string -) => taskAndPlanTemplate({ - task, - explanation, - plan, - currentDate: getCurrentFormattedDate() -}); - -const pageSnapshotTemplate = buildPromptTemplate(` +`.trim(), +); + +export const buildTaskAndPlanPrompt = (task: string, explanation: string, plan: string) => + taskAndPlanTemplate({ + task, + explanation, + plan, + currentDate: getCurrentFormattedDate(), + }); + +const pageSnapshotTemplate = buildPromptTemplate( + ` This is a text snapshot of the current page in the browser. Title: {{title}} @@ -133,19 +135,18 @@ Assess the current state and choose your next action. Focus on the most relevant elements that help complete your task. If content appears dynamic or paginated, consider waiting or exploring navigation options. If an action has failed twice, try something else or move on. -`.trim()); - -export const buildPageSnapshotPrompt = ( - title: string, - url: string, - snapshot: string -) => pageSnapshotTemplate({ - title, - url, - snapshot -}); - -const validationFeedbackTemplate = buildPromptTemplate(` +`.trim(), +); + +export const buildPageSnapshotPrompt = (title: string, url: string, snapshot: string) => + pageSnapshotTemplate({ + title, + url, + snapshot, + }); + +const validationFeedbackTemplate = buildPromptTemplate( + ` Your previous response did not match the required format. Here are the validation errors: {{validationErrors}} @@ -161,15 +162,17 @@ Remember: - For "wait" action, you MUST provide a "value" with the number of seconds - For "done" action, you MUST provide a "value" with the final result - For "back" and "forward" actions, you must NOT provide a "ref" or "value" -`.trim()); +`.trim(), +); -export const buildValidationFeedbackPrompt = (validationErrors: string) => +export const buildValidationFeedbackPrompt = (validationErrors: string) => validationFeedbackTemplate({ validationErrors, - actionLoopResponseFormat + actionLoopResponseFormat, }); -const taskValidationTemplate = buildPromptTemplate(` +const taskValidationTemplate = buildPromptTemplate( + ` Review the task completion and determine if it was successful. Task: {{task}} @@ -181,15 +184,14 @@ Consider: 3. Does it provide the requested information or perform the requested action? If the task was not completed successfully, provide a brief, direct instruction on what needs to be done to complete it. -`.trim()); - -export const buildTaskValidationPrompt = ( - task: string, - finalAnswer: string -): string => taskValidationTemplate({ - task, - finalAnswer -}); +`.trim(), +); + +export const buildTaskValidationPrompt = (task: string, finalAnswer: string): string => + taskValidationTemplate({ + task, + finalAnswer, + }); function getCurrentFormattedDate() { const date = new Date(); diff --git a/src/templateUtils.ts b/src/templateUtils.ts index 33da572c..c4f410e5 100644 --- a/src/templateUtils.ts +++ b/src/templateUtils.ts @@ -6,4 +6,4 @@ import Handlebars from "handlebars"; */ export function buildPromptTemplate(templateSource: string): HandlebarsTemplateDelegate { return Handlebars.compile(templateSource, { noEscape: true }); -} \ No newline at end of file +} diff --git a/src/webAgent.ts b/src/webAgent.ts index cd06557e..051fb7e9 100644 --- a/src/webAgent.ts +++ b/src/webAgent.ts @@ -58,7 +58,10 @@ export class WebAgent { private readonly ARIA_REF_REGEX = /^s\d+e\d+$/; private readonly ARIA_REF_EXTRACT_REGEX = /\b(s\d+e\d+)\b/; - constructor(private browser: AriaBrowser, options: WebAgentOptions = {}) { + constructor( + private browser: AriaBrowser, + options: WebAgentOptions = {}, + ) { this.DEBUG = options.debug || false; this.provider = options.provider || openai("gpt-4.1"); this.eventEmitter = new WebAgentEventEmitter(); @@ -176,33 +179,22 @@ export class WebAgent { case "check": case "uncheck": if (!action.ref) { - errors.push( - `Missing required "ref" field for ${action.action} action` - ); + errors.push(`Missing required "ref" field for ${action.action} action`); } else { - const { isValid, error, correctedRef } = this.validateAriaRef( - action.ref - ); + const { isValid, error, correctedRef } = this.validateAriaRef(action.ref); if (!isValid && error) { errors.push(error); } else if (correctedRef) { correctedResponse.action.ref = correctedRef; } } - if ( - (action.action === "fill" || action.action === "select") && - !action.value?.trim() - ) { - errors.push( - `Missing required "value" field for ${action.action} action` - ); + if ((action.action === "fill" || action.action === "select") && !action.value?.trim()) { + errors.push(`Missing required "value" field for ${action.action} action`); } break; case "wait": if (!action.value || isNaN(Number(action.value))) { - errors.push( - 'Missing or invalid "value" field for wait action (must be a number)' - ); + errors.push('Missing or invalid "value" field for wait action (must be a number)'); } break; case "done": @@ -218,9 +210,7 @@ export class WebAgent { case "back": case "forward": if (action.ref || action.value) { - errors.push( - `${action.action} action should not have ref or value fields` - ); + errors.push(`${action.action} action should not have ref or value fields`); } break; } @@ -287,16 +277,14 @@ export class WebAgent { temperature: 0, }); - const { isValid, errors, correctedResponse } = this.validateActionResponse( - response.object - ); + const { isValid, errors, correctedResponse } = this.validateActionResponse(response.object); if (!isValid) { if (retryCount >= 2) { throw new Error( `Failed to get valid response after ${ retryCount + 1 - } attempts. Errors: ${errors.join(", ")}` + } attempts. Errors: ${errors.join(", ")}`, ); } @@ -314,9 +302,7 @@ export class WebAgent { private logCompressionStats(original: string, compressed: string) { const originalSize = original.length; const compressedSize = compressed.length; - const compressionPercent = Math.round( - (1 - compressedSize / originalSize) * 100 - ); + const compressionPercent = Math.round((1 - compressedSize / originalSize) * 100); this.eventEmitter.emitEvent({ type: WebAgentEventType.DEBUG_COMPRESSION, @@ -329,21 +315,10 @@ export class WebAgent { }); } - private updateMessagesWithSnapshot( - pageTitle: string, - pageUrl: string, - snapshot: string - ) { + private updateMessagesWithSnapshot(pageTitle: string, pageUrl: string, snapshot: string) { this.messages.forEach((msg: any) => { - if ( - msg.role === "user" && - msg.content.includes("snapshot") && - msg.content.includes("```") - ) { - msg.content = msg.content.replace( - /```[\s\S]*$/g, - "```[snapshot clipped for length]```" - ); + if (msg.role === "user" && msg.content.includes("snapshot") && msg.content.includes("```")) { + msg.content = msg.content.replace(/```[\s\S]*$/g, "```[snapshot clipped for length]```"); } }); @@ -407,7 +382,7 @@ export class WebAgent { private async validateTaskCompletion( task: string, - finalAnswer: string + finalAnswer: string, ): Promise { const response = await generateObject({ model: this.provider, @@ -530,10 +505,7 @@ export class WebAgent { } // Validate the task completion - const { isValid, feedback } = await this.validateTaskCompletion( - task, - finalAnswer - ); + const { isValid, feedback } = await this.validateTaskCompletion(task, finalAnswer); if (isValid) { // Emit task complete event @@ -566,7 +538,7 @@ export class WebAgent { } throw new Error( - `Failed to complete task after ${validationAttempts} attempts. Last feedback: ${lastValidationFeedback}` + `Failed to complete task after ${validationAttempts} attempts. Last feedback: ${lastValidationFeedback}`, ); } } @@ -624,7 +596,7 @@ export class WebAgent { await this.browser.performAction( result.action.ref, result.action.action, - result.action.value + result.action.value, ); // For actions that potentially cause navigation (click, select), @@ -636,10 +608,7 @@ export class WebAgent { ]); // Only record navigation if URL or title changed - if ( - actionUrl !== this.currentPage.url || - actionTitle !== this.currentPage.title - ) { + if (actionUrl !== this.currentPage.url || actionTitle !== this.currentPage.title) { this.recordNavigationEvent(actionTitle, actionUrl); } } @@ -700,15 +669,11 @@ export class WebAgent { .split("\n") .map((line) => line.trim()) .map((line) => line.replace(/^- /, "")) - .filter( - (line) => - !this.FILTERED_PREFIXES.some((start) => line.startsWith(start)) - ) + .filter((line) => !this.FILTERED_PREFIXES.some((start) => line.startsWith(start))) .map((line) => { return this.ARIA_TRANSFORMATIONS.reduce( - (processed, [pattern, replacement]) => - processed.replace(pattern, replacement), - line + (processed, [pattern, replacement]) => processed.replace(pattern, replacement), + line, ); }) .filter(Boolean); diff --git a/test/ariaBrowser.test.ts b/test/ariaBrowser.test.ts new file mode 100644 index 00000000..d52ee246 --- /dev/null +++ b/test/ariaBrowser.test.ts @@ -0,0 +1,234 @@ +import { describe, it, expect } from "vitest"; +import { PageAction, LoadState } from "../src/browser/ariaBrowser.js"; + +describe("AriaBrowser interface", () => { + describe("PageAction enum", () => { + it("should have all required action types", () => { + const expectedActions = [ + "click", + "hover", + "fill", + "focus", + "check", + "uncheck", + "select", + "wait", + "goto", + "back", + "forward", + "done", + ]; + + const actualActions = Object.values(PageAction); + + expectedActions.forEach((action) => { + expect(actualActions).toContain(action); + }); + + expect(actualActions.length).toBe(expectedActions.length); + }); + + it("should have correct string values", () => { + expect(PageAction.Click).toBe("click"); + expect(PageAction.Hover).toBe("hover"); + expect(PageAction.Fill).toBe("fill"); + expect(PageAction.Focus).toBe("focus"); + expect(PageAction.Check).toBe("check"); + expect(PageAction.Uncheck).toBe("uncheck"); + expect(PageAction.Select).toBe("select"); + expect(PageAction.Wait).toBe("wait"); + expect(PageAction.Goto).toBe("goto"); + expect(PageAction.Back).toBe("back"); + expect(PageAction.Forward).toBe("forward"); + expect(PageAction.Done).toBe("done"); + }); + + it("should categorize actions correctly", () => { + // Element interaction actions (require ref) + const elementActions = [ + PageAction.Click, + PageAction.Hover, + PageAction.Fill, + PageAction.Focus, + PageAction.Check, + PageAction.Uncheck, + PageAction.Select, + ]; + + // Navigation actions + const navigationActions = [PageAction.Goto, PageAction.Back, PageAction.Forward]; + + // Control actions + const controlActions = [PageAction.Wait, PageAction.Done]; + + const allActions = [...elementActions, ...navigationActions, ...controlActions]; + const enumValues = Object.values(PageAction); + + expect(allActions.length).toBe(enumValues.length); + allActions.forEach((action) => { + expect(enumValues).toContain(action); + }); + }); + }); + + describe("LoadState enum", () => { + it("should have all required load states", () => { + const expectedStates = ["networkidle", "domcontentloaded", "load"]; + + const actualStates = Object.values(LoadState); + + expectedStates.forEach((state) => { + expect(actualStates).toContain(state); + }); + + expect(actualStates.length).toBe(expectedStates.length); + }); + + it("should have correct string values", () => { + expect(LoadState.NetworkIdle).toBe("networkidle"); + expect(LoadState.DOMContentLoaded).toBe("domcontentloaded"); + expect(LoadState.Load).toBe("load"); + }); + + it("should represent different load completion levels", () => { + // These represent progressive levels of page load completion + expect(LoadState.DOMContentLoaded).toBe("domcontentloaded"); // Basic DOM ready + expect(LoadState.Load).toBe("load"); // All resources loaded + expect(LoadState.NetworkIdle).toBe("networkidle"); // Network activity settled + }); + }); + + describe("Interface contract", () => { + it("should define all required browser methods", () => { + // This test ensures the interface contract is complete + // We can't instantiate an interface, but we can verify the types exist + const expectedMethods = [ + "start", + "shutdown", + "goto", + "goBack", + "goForward", + "getUrl", + "getTitle", + "getText", + "getScreenshot", + "performAction", + "waitForLoadState", + ]; + + // TypeScript compilation ensures these methods exist in the interface + // This test documents the expected interface contract + expect(expectedMethods.length).toBe(11); + }); + }); + + describe("Action requirements", () => { + it("should identify actions that require element references", () => { + const refRequiredActions = [ + PageAction.Click, + PageAction.Hover, + PageAction.Fill, + PageAction.Focus, + PageAction.Check, + PageAction.Uncheck, + PageAction.Select, + ]; + + // These actions operate on specific elements and need refs + refRequiredActions.forEach((action) => { + expect(typeof action).toBe("string"); + expect(action.length).toBeGreaterThan(0); + }); + }); + + it("should identify actions that require values", () => { + const valueRequiredActions = [ + PageAction.Fill, // text to fill + PageAction.Select, // option to select + PageAction.Wait, // seconds to wait + PageAction.Goto, // URL to navigate to + PageAction.Done, // final result + ]; + + // These actions need additional data to function + valueRequiredActions.forEach((action) => { + expect(typeof action).toBe("string"); + expect(action.length).toBeGreaterThan(0); + }); + }); + + it("should identify actions that are standalone", () => { + const standaloneActions = [PageAction.Back, PageAction.Forward]; + + // These actions don't need refs or values + standaloneActions.forEach((action) => { + expect(typeof action).toBe("string"); + expect(action.length).toBeGreaterThan(0); + }); + }); + }); + + describe("Type safety", () => { + it("should use string enum pattern", () => { + // Ensure all PageAction values are strings (not numeric) + Object.values(PageAction).forEach((action) => { + expect(typeof action).toBe("string"); + }); + + // Ensure all LoadState values are strings (not numeric) + Object.values(LoadState).forEach((state) => { + expect(typeof state).toBe("string"); + }); + }); + + it("should have consistent naming convention", () => { + // PageAction values should be lowercase + Object.values(PageAction).forEach((action) => { + expect(action).toBe(action.toLowerCase()); + expect(action).not.toContain(" "); + expect(action).not.toContain("-"); + expect(action).not.toContain("_"); + }); + + // LoadState values should be lowercase + Object.values(LoadState).forEach((state) => { + expect(state).toBe(state.toLowerCase()); + }); + }); + }); + + describe("Enum completeness", () => { + it("should cover all common browser automation actions", () => { + const actionCategories = { + clicking: [PageAction.Click], + typing: [PageAction.Fill], + selecting: [PageAction.Select], + checkboxes: [PageAction.Check, PageAction.Uncheck], + navigation: [PageAction.Goto, PageAction.Back, PageAction.Forward], + interaction: [PageAction.Hover, PageAction.Focus], + control: [PageAction.Wait, PageAction.Done], + }; + + // Verify we have actions for all major categories + Object.entries(actionCategories).forEach(([category, actions]) => { + expect(actions.length).toBeGreaterThan(0); + actions.forEach((action) => { + expect(Object.values(PageAction)).toContain(action); + }); + }); + }); + + it("should cover all common load states", () => { + const loadCategories = { + domReady: LoadState.DOMContentLoaded, + fullyLoaded: LoadState.Load, + networkQuiet: LoadState.NetworkIdle, + }; + + // Verify we have states for different load conditions + Object.values(loadCategories).forEach((state) => { + expect(Object.values(LoadState)).toContain(state); + }); + }); + }); +}); diff --git a/test/events.test.ts b/test/events.test.ts new file mode 100644 index 00000000..1cfd63ac --- /dev/null +++ b/test/events.test.ts @@ -0,0 +1,410 @@ +import { describe, it, expect, vi, beforeEach } from "vitest"; +import { + WebAgentEventEmitter, + WebAgentEventType, + WebAgentEvent, + TaskStartEventData, + TaskCompleteEventData, + PageNavigationEventData, + CurrentStepEventData, + ObservationEventData, + ThoughtEventData, + ExtractedDataEventData, + ActionExecutionEventData, + ActionResultEventData, + CompressionDebugEventData, + MessagesDebugEventData, + WaitingEventData, + NetworkWaitingEventData, + NetworkTimeoutEventData, + TaskValidationEventData, +} from "../src/events.js"; + +describe("WebAgentEventEmitter", () => { + let emitter: WebAgentEventEmitter; + + beforeEach(() => { + emitter = new WebAgentEventEmitter(); + }); + + describe("Basic event emission and listening", () => { + it("should emit and listen to events", () => { + const listener = vi.fn(); + const eventData: TaskStartEventData = { + timestamp: Date.now(), + task: "Test task", + explanation: "Test explanation", + plan: "Test plan", + url: "https://example.com", + }; + + emitter.onEvent(WebAgentEventType.TASK_START, listener); + emitter.emitEvent({ + type: WebAgentEventType.TASK_START, + data: eventData, + }); + + expect(listener).toHaveBeenCalledWith(eventData); + expect(listener).toHaveBeenCalledTimes(1); + }); + + it("should listen to events only once with onceEvent", () => { + const listener = vi.fn(); + const eventData: TaskCompleteEventData = { + timestamp: Date.now(), + finalAnswer: "Test answer", + }; + + emitter.onceEvent(WebAgentEventType.TASK_COMPLETE, listener); + emitter.emitEvent({ + type: WebAgentEventType.TASK_COMPLETE, + data: eventData, + }); + emitter.emitEvent({ + type: WebAgentEventType.TASK_COMPLETE, + data: eventData, + }); + + expect(listener).toHaveBeenCalledWith(eventData); + expect(listener).toHaveBeenCalledTimes(1); + }); + + it("should remove event listeners with offEvent", () => { + const listener = vi.fn(); + const eventData: PageNavigationEventData = { + timestamp: Date.now(), + title: "Test Page", + url: "https://example.com", + }; + + emitter.onEvent(WebAgentEventType.PAGE_NAVIGATION, listener); + emitter.offEvent(WebAgentEventType.PAGE_NAVIGATION, listener); + emitter.emitEvent({ + type: WebAgentEventType.PAGE_NAVIGATION, + data: eventData, + }); + + expect(listener).not.toHaveBeenCalled(); + }); + + it("should handle multiple listeners for the same event", () => { + const listener1 = vi.fn(); + const listener2 = vi.fn(); + const eventData: CurrentStepEventData = { + timestamp: Date.now(), + currentStep: "Step 1", + }; + + emitter.onEvent(WebAgentEventType.CURRENT_STEP, listener1); + emitter.onEvent(WebAgentEventType.CURRENT_STEP, listener2); + emitter.emitEvent({ + type: WebAgentEventType.CURRENT_STEP, + data: eventData, + }); + + expect(listener1).toHaveBeenCalledWith(eventData); + expect(listener2).toHaveBeenCalledWith(eventData); + expect(listener1).toHaveBeenCalledTimes(1); + expect(listener2).toHaveBeenCalledTimes(1); + }); + }); + + describe("Event type validation", () => { + it("should handle all WebAgentEventType values", () => { + // Verify all event types are defined + const expectedEventTypes = [ + "task:start", + "task:complete", + "page:navigation", + "agent:current_step", + "agent:observation", + "agent:thought", + "agent:extracted_data", + "action:execution", + "action:result", + "debug:compression", + "debug:messages", + "system:waiting", + "system:network_waiting", + "system:network_timeout", + "task:validation", + ]; + + const actualEventTypes = Object.values(WebAgentEventType); + expect(actualEventTypes).toEqual(expect.arrayContaining(expectedEventTypes)); + expect(actualEventTypes.length).toBe(expectedEventTypes.length); + }); + + it("should emit events with correct event type strings", () => { + const listeners: { [key: string]: any } = {}; + + // Set up listeners for all event types + Object.values(WebAgentEventType).forEach((eventType) => { + listeners[eventType] = vi.fn(); + emitter.onEvent(eventType as any, listeners[eventType]); + }); + + // Test each event type + const testEvents: WebAgentEvent[] = [ + { + type: WebAgentEventType.TASK_START, + data: { + timestamp: Date.now(), + task: "test", + explanation: "test", + plan: "test", + url: "test", + }, + }, + { + type: WebAgentEventType.TASK_COMPLETE, + data: { timestamp: Date.now(), finalAnswer: "test" }, + }, + { + type: WebAgentEventType.PAGE_NAVIGATION, + data: { timestamp: Date.now(), title: "test", url: "test" }, + }, + { + type: WebAgentEventType.CURRENT_STEP, + data: { timestamp: Date.now(), currentStep: "test" }, + }, + { + type: WebAgentEventType.OBSERVATION, + data: { timestamp: Date.now(), observation: "test" }, + }, + { + type: WebAgentEventType.THOUGHT, + data: { timestamp: Date.now(), thought: "test" }, + }, + { + type: WebAgentEventType.EXTRACTED_DATA, + data: { timestamp: Date.now(), extractedData: "test" }, + }, + { + type: WebAgentEventType.ACTION_EXECUTION, + data: { timestamp: Date.now(), action: "click", ref: "s1e23" }, + }, + { + type: WebAgentEventType.ACTION_RESULT, + data: { timestamp: Date.now(), success: true }, + }, + { + type: WebAgentEventType.DEBUG_COMPRESSION, + data: { + timestamp: Date.now(), + originalSize: 1000, + compressedSize: 500, + compressionPercent: 50, + }, + }, + { + type: WebAgentEventType.DEBUG_MESSAGES, + data: { timestamp: Date.now(), messages: [] }, + }, + { + type: WebAgentEventType.WAITING, + data: { timestamp: Date.now(), seconds: 5 }, + }, + { + type: WebAgentEventType.NETWORK_WAITING, + data: { timestamp: Date.now(), action: "click" }, + }, + { + type: WebAgentEventType.NETWORK_TIMEOUT, + data: { timestamp: Date.now(), action: "click" }, + }, + { + type: WebAgentEventType.TASK_VALIDATION, + data: { + timestamp: Date.now(), + isValid: true, + feedback: "test", + finalAnswer: "test", + }, + }, + ]; + + // Emit each event and verify the correct listener was called + testEvents.forEach((event) => { + emitter.emitEvent(event); + expect(listeners[event.type]).toHaveBeenCalledWith(event.data); + }); + }); + }); + + describe("Event data structures", () => { + it("should handle TaskStartEventData correctly", () => { + const listener = vi.fn(); + const eventData: TaskStartEventData = { + timestamp: 1234567890, + task: "Complete a web form", + explanation: "Fill out and submit a contact form", + plan: "1. Navigate to form\n2. Fill fields\n3. Submit", + url: "https://example.com/contact", + }; + + emitter.onEvent(WebAgentEventType.TASK_START, listener); + emitter.emitEvent({ + type: WebAgentEventType.TASK_START, + data: eventData, + }); + + expect(listener).toHaveBeenCalledWith(eventData); + }); + + it("should handle ActionExecutionEventData with optional fields", () => { + const listener = vi.fn(); + + // Test with all fields + const fullEventData: ActionExecutionEventData = { + timestamp: Date.now(), + action: "fill", + ref: "s1e23", + value: "test@example.com", + }; + + emitter.onEvent(WebAgentEventType.ACTION_EXECUTION, listener); + emitter.emitEvent({ + type: WebAgentEventType.ACTION_EXECUTION, + data: fullEventData, + }); + + expect(listener).toHaveBeenCalledWith(fullEventData); + + // Test with minimal fields + const minimalEventData: ActionExecutionEventData = { + timestamp: Date.now(), + action: "back", + }; + + listener.mockClear(); + emitter.emitEvent({ + type: WebAgentEventType.ACTION_EXECUTION, + data: minimalEventData, + }); + + expect(listener).toHaveBeenCalledWith(minimalEventData); + }); + + it("should handle ActionResultEventData with success and error", () => { + const listener = vi.fn(); + + // Test success case + const successData: ActionResultEventData = { + timestamp: Date.now(), + success: true, + }; + + emitter.onEvent(WebAgentEventType.ACTION_RESULT, listener); + emitter.emitEvent({ + type: WebAgentEventType.ACTION_RESULT, + data: successData, + }); + + expect(listener).toHaveBeenCalledWith(successData); + + // Test error case + const errorData: ActionResultEventData = { + timestamp: Date.now(), + success: false, + error: "Element not found", + }; + + listener.mockClear(); + emitter.emitEvent({ + type: WebAgentEventType.ACTION_RESULT, + data: errorData, + }); + + expect(listener).toHaveBeenCalledWith(errorData); + }); + + it("should handle TaskValidationEventData with optional feedback", () => { + const listener = vi.fn(); + + // Test with feedback + const withFeedback: TaskValidationEventData = { + timestamp: Date.now(), + isValid: false, + feedback: "Task incomplete, missing confirmation step", + finalAnswer: "Form submitted", + }; + + emitter.onEvent(WebAgentEventType.TASK_VALIDATION, listener); + emitter.emitEvent({ + type: WebAgentEventType.TASK_VALIDATION, + data: withFeedback, + }); + + expect(listener).toHaveBeenCalledWith(withFeedback); + + // Test without feedback + const withoutFeedback: TaskValidationEventData = { + timestamp: Date.now(), + isValid: true, + finalAnswer: "Task completed successfully", + }; + + listener.mockClear(); + emitter.emitEvent({ + type: WebAgentEventType.TASK_VALIDATION, + data: withoutFeedback, + }); + + expect(listener).toHaveBeenCalledWith(withoutFeedback); + }); + }); + + describe("Error handling", () => { + it("should handle listener errors gracefully", () => { + const errorListener = vi.fn().mockImplementation(() => { + throw new Error("Listener error"); + }); + const successListener = vi.fn(); + + const eventData: ObservationEventData = { + timestamp: Date.now(), + observation: "Test observation", + }; + + emitter.onEvent(WebAgentEventType.OBSERVATION, errorListener); + emitter.onEvent(WebAgentEventType.OBSERVATION, successListener); + + // EventEmitter will throw when a listener throws, but both listeners should be called + expect(() => { + emitter.emitEvent({ + type: WebAgentEventType.OBSERVATION, + data: eventData, + }); + }).toThrow("Listener error"); + + expect(errorListener).toHaveBeenCalled(); + // Note: successListener may not be called if errorListener throws first + // This is expected EventEmitter behavior + }); + }); + + describe("Memory management", () => { + it("should not leak memory when listeners are removed", () => { + const listener = vi.fn(); + + emitter.onEvent(WebAgentEventType.THOUGHT, listener); + expect(emitter.listenerCount(WebAgentEventType.THOUGHT)).toBe(1); + + emitter.offEvent(WebAgentEventType.THOUGHT, listener); + expect(emitter.listenerCount(WebAgentEventType.THOUGHT)).toBe(0); + }); + + it("should support removing all listeners", () => { + const listener1 = vi.fn(); + const listener2 = vi.fn(); + + emitter.onEvent(WebAgentEventType.EXTRACTED_DATA, listener1); + emitter.onEvent(WebAgentEventType.EXTRACTED_DATA, listener2); + expect(emitter.listenerCount(WebAgentEventType.EXTRACTED_DATA)).toBe(2); + + emitter.removeAllListeners(WebAgentEventType.EXTRACTED_DATA); + expect(emitter.listenerCount(WebAgentEventType.EXTRACTED_DATA)).toBe(0); + }); + }); +}); diff --git a/test/loggers.test.ts b/test/loggers.test.ts new file mode 100644 index 00000000..de1b6b20 --- /dev/null +++ b/test/loggers.test.ts @@ -0,0 +1,562 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import { ConsoleLogger, Logger } from "../src/loggers.js"; +import { WebAgentEventEmitter, WebAgentEventType } from "../src/events.js"; +import type { + TaskStartEventData, + TaskCompleteEventData, + TaskValidationEventData, + PageNavigationEventData, + CurrentStepEventData, + ObservationEventData, + ThoughtEventData, + ExtractedDataEventData, + ActionExecutionEventData, + ActionResultEventData, + CompressionDebugEventData, + MessagesDebugEventData, + WaitingEventData, + NetworkWaitingEventData, + NetworkTimeoutEventData, +} from "../src/events.js"; + +// Mock console methods +const mockConsole = { + log: vi.fn(), + error: vi.fn(), +}; + +// Store original console methods +const originalConsole = { + log: console.log, + error: console.error, +}; + +describe("ConsoleLogger", () => { + let logger: ConsoleLogger; + let emitter: WebAgentEventEmitter; + + beforeEach(() => { + // Replace console methods with mocks + console.log = mockConsole.log; + console.error = mockConsole.error; + + // Clear mock call history + mockConsole.log.mockClear(); + mockConsole.error.mockClear(); + + logger = new ConsoleLogger(); + emitter = new WebAgentEventEmitter(); + logger.initialize(emitter); + }); + + afterEach(() => { + // Restore original console methods + console.log = originalConsole.log; + console.error = originalConsole.error; + + // Clean up logger + logger.dispose(); + }); + + describe("Logger interface", () => { + it("should implement Logger interface", () => { + expect(logger).toBeInstanceOf(ConsoleLogger); + expect(typeof logger.initialize).toBe("function"); + expect(typeof logger.dispose).toBe("function"); + }); + + it("should initialize with event emitter", () => { + const newLogger = new ConsoleLogger(); + const newEmitter = new WebAgentEventEmitter(); + + expect(() => { + newLogger.initialize(newEmitter); + }).not.toThrow(); + + newLogger.dispose(); + }); + + it("should dispose properly", () => { + const newLogger = new ConsoleLogger(); + const newEmitter = new WebAgentEventEmitter(); + newLogger.initialize(newEmitter); + + expect(() => { + newLogger.dispose(); + }).not.toThrow(); + + // Should be safe to call dispose multiple times + expect(() => { + newLogger.dispose(); + }).not.toThrow(); + }); + }); + + describe("Task events", () => { + it("should handle TASK_START events", () => { + const eventData: TaskStartEventData = { + timestamp: Date.now(), + task: "Complete a web form", + explanation: "Fill out and submit a contact form on the website", + plan: "1. Navigate to contact page\n2. Fill required fields\n3. Submit form", + url: "https://example.com/contact", + }; + + emitter.emitEvent({ + type: WebAgentEventType.TASK_START, + data: eventData, + }); + + expect(mockConsole.log).toHaveBeenCalled(); + const calls = mockConsole.log.mock.calls; + + // Check that task, explanation, plan, and URL are logged + const allOutput = calls.flat().join(" "); + expect(allOutput).toContain("Complete a web form"); + expect(allOutput).toContain("Fill out and submit a contact form"); + expect(allOutput).toContain("1. Navigate to contact page"); + expect(allOutput).toContain("https://example.com/contact"); + }); + + it("should handle TASK_COMPLETE events", () => { + const eventData: TaskCompleteEventData = { + timestamp: Date.now(), + finalAnswer: "Form submitted successfully with confirmation ID: 12345", + }; + + emitter.emitEvent({ + type: WebAgentEventType.TASK_COMPLETE, + data: eventData, + }); + + expect(mockConsole.log).toHaveBeenCalled(); + const allOutput = mockConsole.log.mock.calls.flat().join(" "); + expect(allOutput).toContain("Form submitted successfully"); + expect(allOutput).toContain("12345"); + }); + + it("should handle TASK_COMPLETE events with null finalAnswer", () => { + const eventData: TaskCompleteEventData = { + timestamp: Date.now(), + finalAnswer: null, + }; + + emitter.emitEvent({ + type: WebAgentEventType.TASK_COMPLETE, + data: eventData, + }); + + // Should not log anything for null final answer + expect(mockConsole.log).not.toHaveBeenCalled(); + }); + + it("should handle TASK_VALIDATION events (valid)", () => { + const eventData: TaskValidationEventData = { + timestamp: Date.now(), + isValid: true, + finalAnswer: "Task completed successfully", + }; + + emitter.emitEvent({ + type: WebAgentEventType.TASK_VALIDATION, + data: eventData, + }); + + expect(mockConsole.log).toHaveBeenCalled(); + const allOutput = mockConsole.log.mock.calls.flat().join(" "); + expect(allOutput).toContain("valid"); + }); + + it("should handle TASK_VALIDATION events (invalid with feedback)", () => { + const eventData: TaskValidationEventData = { + timestamp: Date.now(), + isValid: false, + feedback: "Missing confirmation step in the process", + finalAnswer: "Form submitted", + }; + + emitter.emitEvent({ + type: WebAgentEventType.TASK_VALIDATION, + data: eventData, + }); + + expect(mockConsole.log).toHaveBeenCalled(); + const allOutput = mockConsole.log.mock.calls.flat().join(" "); + expect(allOutput).toContain("improvement"); + expect(allOutput).toContain("Missing confirmation step"); + }); + }); + + describe("Page events", () => { + it("should handle PAGE_NAVIGATION events", () => { + const eventData: PageNavigationEventData = { + timestamp: Date.now(), + title: "Contact Us - Example Company", + url: "https://example.com/contact", + }; + + emitter.emitEvent({ + type: WebAgentEventType.PAGE_NAVIGATION, + data: eventData, + }); + + expect(mockConsole.log).toHaveBeenCalled(); + const allOutput = mockConsole.log.mock.calls.flat().join(" "); + expect(allOutput).toContain("Contact Us - Example Company"); + }); + + it("should handle PAGE_NAVIGATION events with long titles", () => { + const longTitle = + "This is a very long page title that exceeds fifty characters and should be truncated for display purposes"; + const eventData: PageNavigationEventData = { + timestamp: Date.now(), + title: longTitle, + url: "https://example.com/page", + }; + + emitter.emitEvent({ + type: WebAgentEventType.PAGE_NAVIGATION, + data: eventData, + }); + + expect(mockConsole.log).toHaveBeenCalled(); + const allOutput = mockConsole.log.mock.calls.flat().join(" "); + expect(allOutput).toContain("..."); + expect(allOutput).not.toContain(longTitle); + }); + }); + + describe("Agent reasoning events", () => { + it("should handle CURRENT_STEP events", () => { + const eventData: CurrentStepEventData = { + timestamp: Date.now(), + currentStep: "Working on Step 1: Navigate to contact form", + }; + + emitter.emitEvent({ + type: WebAgentEventType.CURRENT_STEP, + data: eventData, + }); + + expect(mockConsole.log).toHaveBeenCalled(); + const allOutput = mockConsole.log.mock.calls.flat().join(" "); + expect(allOutput).toContain("Working on Step 1"); + }); + + it("should handle OBSERVATION events", () => { + const eventData: ObservationEventData = { + timestamp: Date.now(), + observation: "Found contact form with name, email, and message fields", + }; + + emitter.emitEvent({ + type: WebAgentEventType.OBSERVATION, + data: eventData, + }); + + expect(mockConsole.log).toHaveBeenCalled(); + const allOutput = mockConsole.log.mock.calls.flat().join(" "); + expect(allOutput).toContain("Found contact form"); + }); + + it("should handle THOUGHT events", () => { + const eventData: ThoughtEventData = { + timestamp: Date.now(), + thought: "I need to fill in all required fields before submitting", + }; + + emitter.emitEvent({ + type: WebAgentEventType.THOUGHT, + data: eventData, + }); + + expect(mockConsole.log).toHaveBeenCalled(); + const allOutput = mockConsole.log.mock.calls.flat().join(" "); + expect(allOutput).toContain("required fields"); + }); + + it("should handle EXTRACTED_DATA events", () => { + const eventData: ExtractedDataEventData = { + timestamp: Date.now(), + extractedData: "Confirmation ID: 12345, Status: Submitted", + }; + + emitter.emitEvent({ + type: WebAgentEventType.EXTRACTED_DATA, + data: eventData, + }); + + expect(mockConsole.log).toHaveBeenCalled(); + const allOutput = mockConsole.log.mock.calls.flat().join(" "); + expect(allOutput).toContain("Confirmation ID: 12345"); + }); + }); + + describe("Action events", () => { + it("should handle ACTION_EXECUTION events", () => { + const eventData: ActionExecutionEventData = { + timestamp: Date.now(), + action: "fill", + ref: "s1e23", + value: "john@example.com", + }; + + emitter.emitEvent({ + type: WebAgentEventType.ACTION_EXECUTION, + data: eventData, + }); + + expect(mockConsole.log).toHaveBeenCalled(); + const allOutput = mockConsole.log.mock.calls.flat().join(" "); + expect(allOutput).toContain("FILL"); + expect(allOutput).toContain("s1e23"); + expect(allOutput).toContain("john@example.com"); + }); + + it("should handle ACTION_EXECUTION events without ref and value", () => { + const eventData: ActionExecutionEventData = { + timestamp: Date.now(), + action: "back", + }; + + emitter.emitEvent({ + type: WebAgentEventType.ACTION_EXECUTION, + data: eventData, + }); + + expect(mockConsole.log).toHaveBeenCalled(); + const allOutput = mockConsole.log.mock.calls.flat().join(" "); + expect(allOutput).toContain("BACK"); + }); + + it("should handle ACTION_RESULT events (success)", () => { + const eventData: ActionResultEventData = { + timestamp: Date.now(), + success: true, + }; + + emitter.emitEvent({ + type: WebAgentEventType.ACTION_RESULT, + data: eventData, + }); + + // Success events don't log anything + expect(mockConsole.log).not.toHaveBeenCalled(); + expect(mockConsole.error).not.toHaveBeenCalled(); + }); + + it("should handle ACTION_RESULT events (failure)", () => { + const eventData: ActionResultEventData = { + timestamp: Date.now(), + success: false, + error: "Element not found: s1e23", + }; + + emitter.emitEvent({ + type: WebAgentEventType.ACTION_RESULT, + data: eventData, + }); + + expect(mockConsole.error).toHaveBeenCalled(); + const allOutput = mockConsole.error.mock.calls.flat().join(" "); + expect(allOutput).toContain("Element not found"); + }); + + it("should handle ACTION_RESULT events (failure without error message)", () => { + const eventData: ActionResultEventData = { + timestamp: Date.now(), + success: false, + }; + + emitter.emitEvent({ + type: WebAgentEventType.ACTION_RESULT, + data: eventData, + }); + + expect(mockConsole.error).toHaveBeenCalled(); + const allOutput = mockConsole.error.mock.calls.flat().join(" "); + expect(allOutput).toContain("Unknown error"); + }); + }); + + describe("Debug events", () => { + it("should handle DEBUG_COMPRESSION events", () => { + const eventData: CompressionDebugEventData = { + timestamp: Date.now(), + originalSize: 10000, + compressedSize: 3000, + compressionPercent: 70, + }; + + emitter.emitEvent({ + type: WebAgentEventType.DEBUG_COMPRESSION, + data: eventData, + }); + + expect(mockConsole.log).toHaveBeenCalled(); + const allOutput = mockConsole.log.mock.calls.flat().join(" "); + expect(allOutput).toContain("70%"); + expect(allOutput).toContain("10000"); + expect(allOutput).toContain("3000"); + }); + + it("should handle DEBUG_MESSAGES events", () => { + const eventData: MessagesDebugEventData = { + timestamp: Date.now(), + messages: [ + { role: "system", content: "You are a helpful assistant" }, + { role: "user", content: "Help me with this task" }, + ], + }; + + emitter.emitEvent({ + type: WebAgentEventType.DEBUG_MESSAGES, + data: eventData, + }); + + expect(mockConsole.log).toHaveBeenCalled(); + const allOutput = mockConsole.log.mock.calls.flat().join(" "); + expect(allOutput).toContain("system"); + expect(allOutput).toContain("helpful assistant"); + }); + }); + + describe("Waiting events", () => { + it("should handle WAITING events (single second)", () => { + const eventData: WaitingEventData = { + timestamp: Date.now(), + seconds: 1, + }; + + emitter.emitEvent({ + type: WebAgentEventType.WAITING, + data: eventData, + }); + + expect(mockConsole.log).toHaveBeenCalled(); + const allOutput = mockConsole.log.mock.calls.flat().join(" "); + expect(allOutput).toContain("1 second"); + expect(allOutput).not.toContain("seconds"); + }); + + it("should handle WAITING events (multiple seconds)", () => { + const eventData: WaitingEventData = { + timestamp: Date.now(), + seconds: 5, + }; + + emitter.emitEvent({ + type: WebAgentEventType.WAITING, + data: eventData, + }); + + expect(mockConsole.log).toHaveBeenCalled(); + const allOutput = mockConsole.log.mock.calls.flat().join(" "); + expect(allOutput).toContain("5 seconds"); + }); + + it("should handle NETWORK_WAITING events", () => { + const eventData: NetworkWaitingEventData = { + timestamp: Date.now(), + action: "click", + }; + + emitter.emitEvent({ + type: WebAgentEventType.NETWORK_WAITING, + data: eventData, + }); + + expect(mockConsole.log).toHaveBeenCalled(); + const allOutput = mockConsole.log.mock.calls.flat().join(" "); + expect(allOutput).toContain("network activity"); + }); + + it("should handle NETWORK_TIMEOUT events", () => { + const eventData: NetworkTimeoutEventData = { + timestamp: Date.now(), + action: "submit", + }; + + emitter.emitEvent({ + type: WebAgentEventType.NETWORK_TIMEOUT, + data: eventData, + }); + + expect(mockConsole.log).toHaveBeenCalled(); + const allOutput = mockConsole.log.mock.calls.flat().join(" "); + expect(allOutput).toContain("timed out"); + }); + }); + + describe("Event listener management", () => { + it("should remove all listeners on dispose", () => { + const eventCounts = [ + WebAgentEventType.TASK_START, + WebAgentEventType.TASK_COMPLETE, + WebAgentEventType.PAGE_NAVIGATION, + WebAgentEventType.CURRENT_STEP, + WebAgentEventType.OBSERVATION, + WebAgentEventType.THOUGHT, + WebAgentEventType.EXTRACTED_DATA, + WebAgentEventType.ACTION_EXECUTION, + WebAgentEventType.ACTION_RESULT, + WebAgentEventType.DEBUG_COMPRESSION, + WebAgentEventType.DEBUG_MESSAGES, + WebAgentEventType.WAITING, + WebAgentEventType.NETWORK_WAITING, + WebAgentEventType.NETWORK_TIMEOUT, + WebAgentEventType.TASK_VALIDATION, + ].map((eventType) => ({ + eventType, + count: emitter.listenerCount(eventType), + })); + + // All events should have listeners + eventCounts.forEach(({ eventType, count }) => { + expect(count).toBeGreaterThan(0); + }); + + logger.dispose(); + + // After dispose, all events should have no listeners from this logger + eventCounts.forEach(({ eventType }) => { + const newCount = emitter.listenerCount(eventType); + expect(newCount).toBe(0); + }); + }); + + it("should handle dispose when emitter is null", () => { + const newLogger = new ConsoleLogger(); + + // Dispose without initializing should not throw + expect(() => { + newLogger.dispose(); + }).not.toThrow(); + }); + }); + + describe("Multiple logger instances", () => { + it("should support multiple logger instances", () => { + const logger2 = new ConsoleLogger(); + logger2.initialize(emitter); + + const eventData: TaskStartEventData = { + timestamp: Date.now(), + task: "Test task", + explanation: "Test explanation", + plan: "Test plan", + url: "https://example.com", + }; + + emitter.emitEvent({ + type: WebAgentEventType.TASK_START, + data: eventData, + }); + + // Both loggers should handle the event + expect(mockConsole.log).toHaveBeenCalled(); + + logger2.dispose(); + }); + }); +}); diff --git a/test/mockBrowser.ts b/test/mockBrowser.ts deleted file mode 100644 index a417783a..00000000 --- a/test/mockBrowser.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { Browser } from "../src/browser/Browser"; -import { SimplifierConfig, SimplifierResult, ActionResult } from "../src/types"; -import { - pageTransformer, - elementActionPerformer, - getDefaultConfig, -} from "../src/pageCapture.js"; - -/** - * MockBrowser - A test implementation of the Browser interface - * This runs entirely in JSDOM without any external browser dependency - */ -export class MockBrowser implements Browser { - constructor() {} - - async launch(): Promise { - // Nothing to launch in the mock - } - - async close(): Promise { - // Nothing to close in the mock - } - - async goto(url: string): Promise { - // Set the location in JSDOM - window.location.href = url; - } - - async evaluate(fn: Function, ...args: any[]): Promise { - // In the mock, just execute the function directly - return fn(...args) as T; - } - - async addScriptTag(): Promise { - // Scripts are already available in the mock - } - - async waitForLoadState(): Promise { - // No waiting needed in the mock - } - - async goBack(): Promise { - // No real navigation in the mock - } - - async getCurrentUrl(): Promise { - return window.location.href; - } - - async waitForSelector(): Promise { - // No waiting needed in the mock - } - - async capturePage( - selector: string, - userConfig?: Partial - ): Promise { - // For testing, we want a few test-specific defaults - const testDefaults: Partial = { - includeHiddenElements: true, // Always include hidden elements in tests - cleanupWhitespace: false, // Keep whitespace for predictable test assertions - }; - - // Pass the merged config to the pageTransformer - return pageTransformer(selector, { - ...testDefaults, - ...userConfig, - }); - } - - async performAction( - selector: string, - action: string, - value?: string - ): Promise { - // In the mock browser, we can call elementActionPerformer directly - return await elementActionPerformer(selector, action, value); - } -} diff --git a/test/pageCapture.test.ts b/test/pageCapture.test.ts deleted file mode 100644 index ab64cbe5..00000000 --- a/test/pageCapture.test.ts +++ /dev/null @@ -1,617 +0,0 @@ -import { describe, it, expect, beforeEach } from "vitest"; -import { PageCapture, getDefaultConfig } from "../src/pageCapture"; -import { MockBrowser } from "./MockBrowser"; -import { JSDOM } from "jsdom"; - -// Patch for JSDOM environment compatibility -function applyJSDOMPatches() { - // JSDOM doesn't implement focus properly, so we need to mock it - if (!HTMLElement.prototype.focus) { - HTMLElement.prototype.focus = function () { - // We can't directly set activeElement as it's read-only - // But we can track focused state on the element itself - (this as any)._focused = true; - this.dispatchEvent(new Event("focus")); - }; - } - - // JSDOM doesn't always handle events properly, this helps ensure events work - if (typeof Event === "function" && typeof CustomEvent !== "function") { - // @ts-ignore - global.CustomEvent = Event; - } -} - -describe("PageCapture", () => { - let simplifier: PageCapture; - let mockBrowser: MockBrowser; - let dom: JSDOM; - - beforeEach(() => { - // Create a fresh JSDOM instance for each test - dom = new JSDOM("", { - url: "http://localhost", - pretendToBeVisual: true, - }); - - // Set up the global environment - global.document = dom.window.document; - // @ts-ignore - JSDOM types don't match exactly but functionality is correct - global.window = dom.window; - global.HTMLElement = dom.window.HTMLElement; - global.HTMLInputElement = dom.window.HTMLInputElement; - global.HTMLTextAreaElement = dom.window.HTMLTextAreaElement; - global.HTMLSelectElement = dom.window.HTMLSelectElement; - global.Event = dom.window.Event; - global.getComputedStyle = dom.window.getComputedStyle; - - // Apply JSDOM compatibility patches - applyJSDOMPatches(); - - // Create our mock browser - mockBrowser = new MockBrowser(); - - // Create a test-optimized simplifier with custom config - simplifier = new PageCapture(mockBrowser, { - // We need to keep whitespace cleaner for testing - cleanupWhitespace: false, - // Handle hidden elements more simply in tests - includeHiddenElements: true, - }); - }); - - describe("Basic Text Transformation", () => { - it("should transform simple text content", async () => { - dom.window.document.body.innerHTML = ` -
-

Hello World

-

This is a test

-
- `; - - const result = await simplifier.transform("body"); - expect(result.text).toContain("Hello World"); - expect(result.text).toContain("This is a test"); - expect(result.references).toEqual({}); - }); - - it("should handle nested elements", async () => { - dom.window.document.body.innerHTML = ` -
-
-

Title

-

Paragraph with inline elements

-
-
- `; - - const result = await simplifier.transform("body"); - expect(result.text).toContain("# Title"); - expect(result.text).toContain("Paragraph with inline elements"); - }); - - it("should handle inline elements with proper spacing", async () => { - // Create a test DOM with inline elements - dom.window.document.body.innerHTML = ` -
- Prime Video Direct - Video Distribution - Some text - -
- `; - - const result = await simplifier.transform("div"); - - // Verify that elements are preserved with proper spacing - expect(result.text.trim()).toBe( - 'Prime Video Direct Video Distribution Some text ' - ); - - // Verify that interactive elements are preserved (but not spans) - const elementIds = Object.keys(result.references); - expect(elementIds.length).toBe(3); // Should have 3 elements (2 anchors and 1 button, not the span) - - // Verify each preserved element has correct tag name - expect(result.references["1"].tagName).toBe("a"); - expect(result.references["2"].tagName).toBe("a"); - expect(result.references["3"].tagName).toBe("button"); - }); - }); - - describe("Element Preservation", () => { - it("should preserve interactive elements with attributes", async () => { - dom.window.document.body.innerHTML = ` -
- - - Link text -
- `; - - const result = await simplifier.transform("body"); - expect(Object.keys(result.references).length).toBeGreaterThan(0); - - // Check that elements are preserved with correct attributes - const references = Object.values(result.references); - expect(references.some((ref) => ref.tagName === "button")).toBe(true); - expect(references.some((ref) => ref.tagName === "input")).toBe(true); - expect(references.some((ref) => ref.tagName === "a")).toBe(true); - }); - }); - - describe("Block Element Handling", () => { - it("should add appropriate spacing around block elements", async () => { - dom.window.document.body.innerHTML = ` -
First block
-

Second block

-
Third block
- `; - - const result = await simplifier.transform("body"); - const blocks = result.text.split("\n").filter(Boolean); - - // Update to match actual number of blocks - expect(blocks.length).toBe(4); - - // Check the content of each block - expect(blocks[0]).toBe("First block"); - expect(blocks[1]).toBe("Second block"); - expect(blocks[2]).toBe("Third block"); - }); - }); - - describe("Hidden Element Handling", () => { - it("should respect the includeHiddenElements flag", async () => { - dom.window.document.body.innerHTML = ` -
Visible content
- - `; - - // Create two simplifiers with different hidden element configurations - const includeHiddenSimplifier = new PageCapture(mockBrowser, { - cleanupWhitespace: false, - includeHiddenElements: true, - }); - - const excludeHiddenSimplifier = new PageCapture(mockBrowser, { - cleanupWhitespace: false, - includeHiddenElements: false, - }); - - // Verify configuration is respected - expect(includeHiddenSimplifier["config"].includeHiddenElements).toBe( - true - ); - expect(excludeHiddenSimplifier["config"].includeHiddenElements).toBe( - false - ); - - // Simplifier with includeHiddenElements=true should include all content - const includeResult = await includeHiddenSimplifier.transform("body"); - expect(includeResult.text).toContain("Visible content"); - expect(includeResult.text).toContain("Hidden content"); - }); - }); - - describe("Action Performing", () => { - it("should perform click actions", async () => { - dom.window.document.body.innerHTML = - ''; - - let clicked = false; - const button = dom.window.document.getElementById("test-button"); - button?.addEventListener("click", () => (clicked = true)); - - const result = await simplifier.transform("body"); - const buttonRef = Object.values(result.references).find( - (ref) => ref.tagName === "button" - ); - - if (buttonRef) { - await simplifier.interactWithElement(1, "click"); - expect(clicked).toBe(true); - } - }); - - it("should perform fill actions on input elements", async () => { - dom.window.document.body.innerHTML = - ''; - - const result = await simplifier.transform("body"); - console.log("References:", result.references); - const id = Object.keys(result.references)[0]; - console.log("Selected ID:", id); - - if (id) { - const ref = result.references[parseInt(id)]; - console.log("Using selector:", ref.selector); - const actionResult = await simplifier.interactWithElement( - parseInt(id), - "fill", - "test value" - ); - console.log("Action Result:", actionResult); - const input = dom.window.document.getElementById( - "test-input" - ) as HTMLInputElement; - console.log("Input value after fill:", input.value); - expect(input.value).toBe("test value"); - } else { - throw new Error("No input element reference found"); - } - }); - }); - - describe("Form Element Handling", () => { - it("should handle form elements with various states", async () => { - dom.window.document.body.innerHTML = ` -
- - - - - -
- `; - - const result = await simplifier.transform("body"); - const refs = Object.values(result.references); - - // Check form attributes - only method should be preserved - const form = refs.find((ref) => ref.tagName === "form"); - expect(form?.attributes.method).toBe("post"); - - // Check input states - const textInput = refs.find( - (ref) => ref.tagName === "input" && ref.attributes.type === "text" - ); - expect(textInput?.attributes.disabled).toBeTruthy(); - expect(textInput?.attributes.value).toBe("test"); - - const checkbox = refs.find( - (ref) => ref.tagName === "input" && ref.attributes.type === "checkbox" - ); - expect(checkbox?.attributes.checked).toBeTruthy(); - - const radio = refs.find( - (ref) => ref.tagName === "input" && ref.attributes.type === "radio" - ); - expect(radio?.attributes.checked).toBeTruthy(); - - // Check select and option - const select = refs.find((ref) => ref.tagName === "select"); - expect(select).toBeTruthy(); - const option = refs.find( - (ref) => ref.tagName === "option" && ref.attributes.selected === "true" - ); - expect(option?.attributes.value).toBe("1"); - - // Check textarea - const textarea = refs.find((ref) => ref.tagName === "textarea"); - expect(textarea?.attributes.placeholder).toBe("Enter text"); - }); - }); - - describe("ARIA Role Handling", () => { - it("should preserve elements with actionable ARIA roles", async () => { - dom.window.document.body.innerHTML = ` -
×
- Accept terms -
Tab 1
- `; - - const result = await simplifier.transform("body"); - const refs = Object.values(result.references); - - expect(refs.some((ref) => ref.attributes.role === "button")).toBe(true); - expect(refs.some((ref) => ref.attributes.role === "checkbox")).toBe(true); - expect(refs.some((ref) => ref.attributes.role === "tab")).toBe(true); - }); - - it("should not preserve elements with non-actionable ARIA roles", async () => { - dom.window.document.body.innerHTML = ` -
Header
-
Footer
- `; - - const result = await simplifier.transform("body"); - const refs = Object.values(result.references); - - expect(refs.some((ref) => ref.attributes.role === "banner")).toBe(false); - expect(refs.some((ref) => ref.attributes.role === "contentinfo")).toBe( - false - ); - expect(result.text).toContain("Header"); - expect(result.text).toContain("Footer"); - }); - }); - - describe("List and Table Handling", () => { - it("should properly format ordered and unordered lists", async () => { - dom.window.document.body.innerHTML = ` -
    -
  • First item
  • -
  • Second item
  • -
-
    -
  1. Numbered one
  2. -
  3. Numbered two
  4. -
- `; - - const result = await simplifier.transform("body"); - const paragraphs = result.text.split("\n").filter(Boolean); - - expect(paragraphs).toContain("First item"); - expect(paragraphs).toContain("Second item"); - expect(paragraphs).toContain("Numbered one"); - expect(paragraphs).toContain("Numbered two"); - }); - - it("should handle tables with proper spacing", async () => { - dom.window.document.body.innerHTML = ` - - - -
Header 1Header 2
Cell 1Cell 2
- `; - - const result = await simplifier.transform("body"); - expect(result.text).toContain("Header 1"); - expect(result.text).toContain("Header 2"); - expect(result.text).toContain("Cell 1"); - expect(result.text).toContain("Cell 2"); - }); - }); - - describe("Error Handling", () => { - it("should handle invalid selectors gracefully", async () => { - await expect(simplifier.transform("#nonexistent")).rejects.toThrow( - "Element not found" - ); - }); - - it("should handle malformed HTML gracefully", async () => { - dom.window.document.body.innerHTML = ` -
-

Unclosed paragraph - Unclosed span -

- `; - - const result = await simplifier.transform("body"); - expect(result.text).toContain("Unclosed paragraph"); - expect(result.text).toContain("Unclosed span"); - }); - - it("should handle empty elements gracefully", async () => { - dom.window.document.body.innerHTML = ` -
-

- - `; - - const result = await simplifier.transform("body"); - expect(result.text.trim()).toBe(""); - }); - }); - - describe("Empty Anchor Tag Handling", () => { - it("should skip completely empty anchor tags", async () => { - dom.window.document.body.innerHTML = ` -
- Link text - - -
- `; - - const result = await simplifier.transform("body"); - expect(result.text).toContain('Link text'); - expect(result.text).not.toContain(""); - expect(result.text).not.toContain(''); - expect( - Object.values(result.references).filter((ref) => ref.tagName === "a") - ).toHaveLength(1); - }); - - it("should skip anchor tags with only whitespace", async () => { - dom.window.document.body.innerHTML = ` -
- Link text - - -
- `; - - const result = await simplifier.transform("body"); - expect(result.text).toContain('Link text'); - expect(result.text).not.toContain(" "); - expect(result.text).not.toContain(' '); - expect( - Object.values(result.references).filter((ref) => ref.tagName === "a") - ).toHaveLength(1); - }); - - it("should skip anchor tags with only attributes", async () => { - dom.window.document.body.innerHTML = ` -
- Link text - - -
- `; - - const result = await simplifier.transform("body"); - expect(result.text).toContain('Link text'); - expect(result.text).not.toContain( - '' - ); - expect(result.text).not.toContain(''); - expect( - Object.values(result.references).filter((ref) => ref.tagName === "a") - ).toHaveLength(1); - }); - - it("should preserve anchor tags with actual content", async () => { - dom.window.document.body.innerHTML = ` - - `; - - const result = await simplifier.transform("body"); - expect(result.text).toContain('Link text'); - expect(result.text).toContain('Sign in'); - expect(result.text).toContain( - 'Orders & Returns' - ); - expect( - Object.values(result.references).filter((ref) => ref.tagName === "a") - ).toHaveLength(3); - }); - - it("should skip anchor tags with only presentational content", async () => { - dom.window.document.body.innerHTML = ` - - `; - - // Create a new simplifier that respects hidden elements - const hiddenRespectingSimplifier = new PageCapture(mockBrowser, { - cleanupWhitespace: false, - includeHiddenElements: false, - }); - - const result = await hiddenRespectingSimplifier.transform("body"); - - // The anchor tag should not be preserved since its content is only presentational - expect(result.text).not.toContain('