diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index e7f8932..cd7d364 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -16,4 +16,6 @@ jobs:
- run: pnpm lint:check
- run: pnpm format:check
- run: pnpm type:check
+ - run: pnpm test
- run: pnpm build
+ - run: pnpm test:e2e
diff --git a/package.json b/package.json
index 84cda2c..63542c4 100644
--- a/package.json
+++ b/package.json
@@ -23,7 +23,10 @@
"format": "prettier --write \"src/**/*.{ts,tsx}\"",
"format:check": "prettier --check \"src/**/*.{ts,tsx}\"",
"type:check": "tsc --noEmit",
- "ci": "pnpm lint:check && pnpm format:check && pnpm type:check && pnpm build && pnpm docker:build"
+ "test": "vitest run",
+ "test:watch": "vitest",
+ "test:e2e": "playwright test",
+ "ci": "pnpm lint:check && pnpm format:check && pnpm type:check && pnpm test && pnpm build && pnpm test:e2e && pnpm docker:build"
},
"repository": {
"type": "git",
@@ -33,6 +36,7 @@
"url": "https://github.com/kern/filepizza/issues"
},
"dependencies": {
+ "@tailwindcss/postcss": "^4.1.11",
"@tanstack/react-query": "^5.55.2",
"autoprefixer": "^10.4.20",
"debug": "^4.3.6",
@@ -51,26 +55,35 @@
"react-qr-code": "^2.0.15",
"streamsaver": "^2.0.6",
"tailwindcss": "^4.1.11",
- "@tailwindcss/postcss": "^4.1.11",
"web-streams-polyfill": "^4.0.0",
"webrtcsupport": "^2.2.0",
"zod": "^3.23.8"
},
"devDependencies": {
+ "@eslint/js": "^9.30.0",
+ "@playwright/test": "^1.53.2",
+ "@testing-library/jest-dom": "^6.6.3",
+ "@testing-library/react": "^16.3.0",
+ "@testing-library/user-event": "^14.6.1",
"@types/debug": "^4.1.12",
"@types/node": "^22.10.2",
"@types/react": "^19.0.2",
"@typescript-eslint/eslint-plugin": "^8.18.2",
"@typescript-eslint/parser": "^8.18.2",
+ "@vitejs/plugin-react": "^4.6.0",
+ "@vitest/coverage-v8": "^3.2.4",
"eslint": "^9.17.0",
"eslint-config-next": "^15.1.3",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-react": "^7.37.3",
"husky": "^9.0.0",
+ "jsdom": "^26.1.0",
"lint-staged": "^15.0.0",
+ "playwright": "^1.53.2",
"prettier": "^3.0.0",
"typescript": "^5.0.0",
- "typescript-eslint": "^8.18.2"
+ "typescript-eslint": "^8.18.2",
+ "vitest": "^3.2.4"
},
"husky": {
"hooks": {
@@ -84,4 +97,4 @@
"git add"
]
}
-}
\ No newline at end of file
+}
diff --git a/playwright.config.ts b/playwright.config.ts
new file mode 100644
index 0000000..4338e61
--- /dev/null
+++ b/playwright.config.ts
@@ -0,0 +1,11 @@
+import { defineConfig } from '@playwright/test'
+
+export default defineConfig({
+ testDir: './tests/e2e',
+ webServer: {
+ command: 'node .next/standalone/server.js',
+ port: 3000,
+ timeout: 120 * 1000,
+ reuseExistingServer: true,
+ },
+})
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 2df5e77..e808500 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -28,13 +28,13 @@ importers:
version: 5.6.1
next:
specifier: ^15.1.3
- version: 15.3.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
+ version: 15.3.4(@babel/core@7.27.7)(@playwright/test@1.53.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
next-themes:
specifier: ^0.4.4
version: 0.4.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
next-view-transitions:
specifier: ^0.3.4
- version: 0.3.4(next@15.3.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
+ version: 0.3.4(next@15.3.4(@babel/core@7.27.7)(@playwright/test@1.53.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
nodemon:
specifier: ^3.0.0
version: 3.1.10
@@ -75,6 +75,21 @@ importers:
specifier: ^3.23.8
version: 3.25.67
devDependencies:
+ '@eslint/js':
+ specifier: ^9.30.0
+ version: 9.30.0
+ '@playwright/test':
+ specifier: ^1.53.2
+ version: 1.53.2
+ '@testing-library/jest-dom':
+ specifier: ^6.6.3
+ version: 6.6.3
+ '@testing-library/react':
+ specifier: ^16.3.0
+ version: 16.3.0(@testing-library/dom@10.4.0)(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
+ '@testing-library/user-event':
+ specifier: ^14.6.1
+ version: 14.6.1(@testing-library/dom@10.4.0)
'@types/debug':
specifier: ^4.1.12
version: 4.1.12
@@ -90,6 +105,12 @@ importers:
'@typescript-eslint/parser':
specifier: ^8.18.2
version: 8.35.1(eslint@9.30.0(jiti@2.4.2))(typescript@5.8.3)
+ '@vitejs/plugin-react':
+ specifier: ^4.6.0
+ version: 4.6.0(vite@7.0.0(@types/node@22.15.34)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0))
+ '@vitest/coverage-v8':
+ specifier: ^3.2.4
+ version: 3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.15.34)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.30.1)(yaml@2.8.0))
eslint:
specifier: ^9.17.0
version: 9.30.0(jiti@2.4.2)
@@ -105,9 +126,15 @@ importers:
husky:
specifier: ^9.0.0
version: 9.1.7
+ jsdom:
+ specifier: ^26.1.0
+ version: 26.1.0
lint-staged:
specifier: ^15.0.0
version: 15.5.2
+ playwright:
+ specifier: ^1.53.2
+ version: 1.53.2
prettier:
specifier: ^3.0.0
version: 3.6.2
@@ -117,9 +144,15 @@ importers:
typescript-eslint:
specifier: ^8.18.2
version: 8.35.1(eslint@9.30.0(jiti@2.4.2))(typescript@5.8.3)
+ vitest:
+ specifier: ^3.2.4
+ version: 3.2.4(@types/debug@4.1.12)(@types/node@22.15.34)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.30.1)(yaml@2.8.0)
packages:
+ '@adobe/css-tools@4.4.3':
+ resolution: {integrity: sha512-VQKMkwriZbaOgVCby1UDY/LDk5fIjhQicCvVPFqfe+69fWaPWydbWJ3wRt59/YzIwda1I81loas3oCoHxnqvdA==}
+
'@alloc/quick-lru@5.2.0':
resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
engines: {node: '>=10'}
@@ -128,6 +161,124 @@ packages:
resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
engines: {node: '>=6.0.0'}
+ '@asamuzakjp/css-color@3.2.0':
+ resolution: {integrity: sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==}
+
+ '@babel/code-frame@7.27.1':
+ resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/compat-data@7.27.7':
+ resolution: {integrity: sha512-xgu/ySj2mTiUFmdE9yCMfBxLp4DHd5DwmbbD05YAuICfodYT3VvRxbrh81LGQ/8UpSdtMdfKMn3KouYDX59DGQ==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/core@7.27.7':
+ resolution: {integrity: sha512-BU2f9tlKQ5CAthiMIgpzAh4eDTLWo1mqi9jqE2OxMG0E/OM199VJt2q8BztTxpnSW0i1ymdwLXRJnYzvDM5r2w==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/generator@7.27.5':
+ resolution: {integrity: sha512-ZGhA37l0e/g2s1Cnzdix0O3aLYm66eF8aufiVteOgnwxgnRP8GoyMj7VWsgWnQbVKXyge7hqrFh2K2TQM6t1Hw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-compilation-targets@7.27.2':
+ resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-module-imports@7.27.1':
+ resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-module-transforms@7.27.3':
+ resolution: {integrity: sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+
+ '@babel/helper-plugin-utils@7.27.1':
+ resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-string-parser@7.27.1':
+ resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-validator-identifier@7.27.1':
+ resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-validator-option@7.27.1':
+ resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helpers@7.27.6':
+ resolution: {integrity: sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/parser@7.27.7':
+ resolution: {integrity: sha512-qnzXzDXdr/po3bOTbTIQZ7+TxNKxpkN5IifVLXS+r7qwynkZfPyjZfE7hCXbo7IoO9TNcSyibgONsf2HauUd3Q==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+
+ '@babel/plugin-transform-react-jsx-self@7.27.1':
+ resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-transform-react-jsx-source@7.27.1':
+ resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/runtime@7.27.6':
+ resolution: {integrity: sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/template@7.27.2':
+ resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/traverse@7.27.7':
+ resolution: {integrity: sha512-X6ZlfR/O/s5EQ/SnUSLzr+6kGnkg8HXGMzpgsMsrJVcfDtH1vIp6ctCN4eZ1LS5c0+te5Cb6Y514fASjMRJ1nw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/types@7.27.7':
+ resolution: {integrity: sha512-8OLQgDScAOHXnAz2cV+RfzzNMipuLVBz2biuAJFMV9bfkNf393je3VM8CLkjQodW5+iWsSJdSgSWT6rsZoXHPw==}
+ engines: {node: '>=6.9.0'}
+
+ '@bcoe/v8-coverage@1.0.2':
+ resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==}
+ engines: {node: '>=18'}
+
+ '@csstools/color-helpers@5.0.2':
+ resolution: {integrity: sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==}
+ engines: {node: '>=18'}
+
+ '@csstools/css-calc@2.1.4':
+ resolution: {integrity: sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ '@csstools/css-parser-algorithms': ^3.0.5
+ '@csstools/css-tokenizer': ^3.0.4
+
+ '@csstools/css-color-parser@3.0.10':
+ resolution: {integrity: sha512-TiJ5Ajr6WRd1r8HSiwJvZBiJOqtH86aHpUjq5aEKWHiII2Qfjqd/HCWKPOW8EP4vcspXbHnXrwIDlu5savQipg==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ '@csstools/css-parser-algorithms': ^3.0.5
+ '@csstools/css-tokenizer': ^3.0.4
+
+ '@csstools/css-parser-algorithms@3.0.5':
+ resolution: {integrity: sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ '@csstools/css-tokenizer': ^3.0.4
+
+ '@csstools/css-tokenizer@3.0.4':
+ resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==}
+ engines: {node: '>=18'}
+
'@emnapi/core@1.4.3':
resolution: {integrity: sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g==}
@@ -137,6 +288,156 @@ packages:
'@emnapi/wasi-threads@1.0.2':
resolution: {integrity: sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA==}
+ '@esbuild/aix-ppc64@0.25.5':
+ resolution: {integrity: sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [aix]
+
+ '@esbuild/android-arm64@0.25.5':
+ resolution: {integrity: sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [android]
+
+ '@esbuild/android-arm@0.25.5':
+ resolution: {integrity: sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==}
+ engines: {node: '>=18'}
+ cpu: [arm]
+ os: [android]
+
+ '@esbuild/android-x64@0.25.5':
+ resolution: {integrity: sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [android]
+
+ '@esbuild/darwin-arm64@0.25.5':
+ resolution: {integrity: sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@esbuild/darwin-x64@0.25.5':
+ resolution: {integrity: sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@esbuild/freebsd-arm64@0.25.5':
+ resolution: {integrity: sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [freebsd]
+
+ '@esbuild/freebsd-x64@0.25.5':
+ resolution: {integrity: sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@esbuild/linux-arm64@0.25.5':
+ resolution: {integrity: sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@esbuild/linux-arm@0.25.5':
+ resolution: {integrity: sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==}
+ engines: {node: '>=18'}
+ cpu: [arm]
+ os: [linux]
+
+ '@esbuild/linux-ia32@0.25.5':
+ resolution: {integrity: sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==}
+ engines: {node: '>=18'}
+ cpu: [ia32]
+ os: [linux]
+
+ '@esbuild/linux-loong64@0.25.5':
+ resolution: {integrity: sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==}
+ engines: {node: '>=18'}
+ cpu: [loong64]
+ os: [linux]
+
+ '@esbuild/linux-mips64el@0.25.5':
+ resolution: {integrity: sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==}
+ engines: {node: '>=18'}
+ cpu: [mips64el]
+ os: [linux]
+
+ '@esbuild/linux-ppc64@0.25.5':
+ resolution: {integrity: sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@esbuild/linux-riscv64@0.25.5':
+ resolution: {integrity: sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==}
+ engines: {node: '>=18'}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@esbuild/linux-s390x@0.25.5':
+ resolution: {integrity: sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==}
+ engines: {node: '>=18'}
+ cpu: [s390x]
+ os: [linux]
+
+ '@esbuild/linux-x64@0.25.5':
+ resolution: {integrity: sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [linux]
+
+ '@esbuild/netbsd-arm64@0.25.5':
+ resolution: {integrity: sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [netbsd]
+
+ '@esbuild/netbsd-x64@0.25.5':
+ resolution: {integrity: sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [netbsd]
+
+ '@esbuild/openbsd-arm64@0.25.5':
+ resolution: {integrity: sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [openbsd]
+
+ '@esbuild/openbsd-x64@0.25.5':
+ resolution: {integrity: sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [openbsd]
+
+ '@esbuild/sunos-x64@0.25.5':
+ resolution: {integrity: sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [sunos]
+
+ '@esbuild/win32-arm64@0.25.5':
+ resolution: {integrity: sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@esbuild/win32-ia32@0.25.5':
+ resolution: {integrity: sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==}
+ engines: {node: '>=18'}
+ cpu: [ia32]
+ os: [win32]
+
+ '@esbuild/win32-x64@0.25.5':
+ resolution: {integrity: sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [win32]
+
'@eslint-community/eslint-utils@4.7.0':
resolution: {integrity: sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -318,10 +619,18 @@ packages:
'@ioredis/commands@1.2.0':
resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==}
+ '@isaacs/cliui@8.0.2':
+ resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
+ engines: {node: '>=12'}
+
'@isaacs/fs-minipass@4.0.1':
resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==}
engines: {node: '>=18.0.0'}
+ '@istanbuljs/schema@0.1.3':
+ resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==}
+ engines: {node: '>=8'}
+
'@jridgewell/gen-mapping@0.3.11':
resolution: {integrity: sha512-C512c1ytBTio4MrpWKlJpyFHT6+qfFL8SZ58zBzJ1OOzUEjHeF1BtjY2fH7n4x/g2OV/KiiMLAivOp1DXmiMMw==}
@@ -412,6 +721,118 @@ packages:
resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==}
engines: {node: '>=12.4.0'}
+ '@pkgjs/parseargs@0.11.0':
+ resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
+ engines: {node: '>=14'}
+
+ '@playwright/test@1.53.2':
+ resolution: {integrity: sha512-tEB2U5z74ebBeyfGNZ3Jfg29AnW+5HlWhvHtb/Mqco9pFdZU1ZLNdVb2UtB5CvmiilNr2ZfVH/qMmAROG/XTzw==}
+ engines: {node: '>=18'}
+ hasBin: true
+
+ '@rolldown/pluginutils@1.0.0-beta.19':
+ resolution: {integrity: sha512-3FL3mnMbPu0muGOCaKAhhFEYmqv9eTfPSJRJmANrCwtgK8VuxpsZDGK+m0LYAGoyO8+0j5uRe4PeyPDK1yA/hA==}
+
+ '@rollup/rollup-android-arm-eabi@4.44.1':
+ resolution: {integrity: sha512-JAcBr1+fgqx20m7Fwe1DxPUl/hPkee6jA6Pl7n1v2EFiktAHenTaXl5aIFjUIEsfn9w3HE4gK1lEgNGMzBDs1w==}
+ cpu: [arm]
+ os: [android]
+
+ '@rollup/rollup-android-arm64@4.44.1':
+ resolution: {integrity: sha512-RurZetXqTu4p+G0ChbnkwBuAtwAbIwJkycw1n6GvlGlBuS4u5qlr5opix8cBAYFJgaY05TWtM+LaoFggUmbZEQ==}
+ cpu: [arm64]
+ os: [android]
+
+ '@rollup/rollup-darwin-arm64@4.44.1':
+ resolution: {integrity: sha512-fM/xPesi7g2M7chk37LOnmnSTHLG/v2ggWqKj3CCA1rMA4mm5KVBT1fNoswbo1JhPuNNZrVwpTvlCVggv8A2zg==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@rollup/rollup-darwin-x64@4.44.1':
+ resolution: {integrity: sha512-gDnWk57urJrkrHQ2WVx9TSVTH7lSlU7E3AFqiko+bgjlh78aJ88/3nycMax52VIVjIm3ObXnDL2H00e/xzoipw==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@rollup/rollup-freebsd-arm64@4.44.1':
+ resolution: {integrity: sha512-wnFQmJ/zPThM5zEGcnDcCJeYJgtSLjh1d//WuHzhf6zT3Md1BvvhJnWoy+HECKu2bMxaIcfWiu3bJgx6z4g2XA==}
+ cpu: [arm64]
+ os: [freebsd]
+
+ '@rollup/rollup-freebsd-x64@4.44.1':
+ resolution: {integrity: sha512-uBmIxoJ4493YATvU2c0upGz87f99e3wop7TJgOA/bXMFd2SvKCI7xkxY/5k50bv7J6dw1SXT4MQBQSLn8Bb/Uw==}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@rollup/rollup-linux-arm-gnueabihf@4.44.1':
+ resolution: {integrity: sha512-n0edDmSHlXFhrlmTK7XBuwKlG5MbS7yleS1cQ9nn4kIeW+dJH+ExqNgQ0RrFRew8Y+0V/x6C5IjsHrJmiHtkxQ==}
+ cpu: [arm]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm-musleabihf@4.44.1':
+ resolution: {integrity: sha512-8WVUPy3FtAsKSpyk21kV52HCxB+me6YkbkFHATzC2Yd3yuqHwy2lbFL4alJOLXKljoRw08Zk8/xEj89cLQ/4Nw==}
+ cpu: [arm]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm64-gnu@4.44.1':
+ resolution: {integrity: sha512-yuktAOaeOgorWDeFJggjuCkMGeITfqvPgkIXhDqsfKX8J3jGyxdDZgBV/2kj/2DyPaLiX6bPdjJDTu9RB8lUPQ==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm64-musl@4.44.1':
+ resolution: {integrity: sha512-W+GBM4ifET1Plw8pdVaecwUgxmiH23CfAUj32u8knq0JPFyK4weRy6H7ooxYFD19YxBulL0Ktsflg5XS7+7u9g==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@rollup/rollup-linux-loongarch64-gnu@4.44.1':
+ resolution: {integrity: sha512-1zqnUEMWp9WrGVuVak6jWTl4fEtrVKfZY7CvcBmUUpxAJ7WcSowPSAWIKa/0o5mBL/Ij50SIf9tuirGx63Ovew==}
+ cpu: [loong64]
+ os: [linux]
+
+ '@rollup/rollup-linux-powerpc64le-gnu@4.44.1':
+ resolution: {integrity: sha512-Rl3JKaRu0LHIx7ExBAAnf0JcOQetQffaw34T8vLlg9b1IhzcBgaIdnvEbbsZq9uZp3uAH+JkHd20Nwn0h9zPjA==}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@rollup/rollup-linux-riscv64-gnu@4.44.1':
+ resolution: {integrity: sha512-j5akelU3snyL6K3N/iX7otLBIl347fGwmd95U5gS/7z6T4ftK288jKq3A5lcFKcx7wwzb5rgNvAg3ZbV4BqUSw==}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@rollup/rollup-linux-riscv64-musl@4.44.1':
+ resolution: {integrity: sha512-ppn5llVGgrZw7yxbIm8TTvtj1EoPgYUAbfw0uDjIOzzoqlZlZrLJ/KuiE7uf5EpTpCTrNt1EdtzF0naMm0wGYg==}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@rollup/rollup-linux-s390x-gnu@4.44.1':
+ resolution: {integrity: sha512-Hu6hEdix0oxtUma99jSP7xbvjkUM/ycke/AQQ4EC5g7jNRLLIwjcNwaUy95ZKBJJwg1ZowsclNnjYqzN4zwkAw==}
+ cpu: [s390x]
+ os: [linux]
+
+ '@rollup/rollup-linux-x64-gnu@4.44.1':
+ resolution: {integrity: sha512-EtnsrmZGomz9WxK1bR5079zee3+7a+AdFlghyd6VbAjgRJDbTANJ9dcPIPAi76uG05micpEL+gPGmAKYTschQw==}
+ cpu: [x64]
+ os: [linux]
+
+ '@rollup/rollup-linux-x64-musl@4.44.1':
+ resolution: {integrity: sha512-iAS4p+J1az6Usn0f8xhgL4PaU878KEtutP4hqw52I4IO6AGoyOkHCxcc4bqufv1tQLdDWFx8lR9YlwxKuv3/3g==}
+ cpu: [x64]
+ os: [linux]
+
+ '@rollup/rollup-win32-arm64-msvc@4.44.1':
+ resolution: {integrity: sha512-NtSJVKcXwcqozOl+FwI41OH3OApDyLk3kqTJgx8+gp6On9ZEt5mYhIsKNPGuaZr3p9T6NWPKGU/03Vw4CNU9qg==}
+ cpu: [arm64]
+ os: [win32]
+
+ '@rollup/rollup-win32-ia32-msvc@4.44.1':
+ resolution: {integrity: sha512-JYA3qvCOLXSsnTR3oiyGws1Dm0YTuxAAeaYGVlGpUsHqloPcFjPg+X0Fj2qODGLNwQOAcCiQmHub/V007kiH5A==}
+ cpu: [ia32]
+ os: [win32]
+
+ '@rollup/rollup-win32-x64-msvc@4.44.1':
+ resolution: {integrity: sha512-J8o22LuF0kTe7m+8PvW9wk3/bRq5+mRo5Dqo6+vXb7otCm3TPhYOJqOaQtGU9YMWQSL3krMnoOxMr0+9E6F3Ug==}
+ cpu: [x64]
+ os: [win32]
+
'@rtsao/scc@1.1.0':
resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==}
@@ -520,18 +941,68 @@ packages:
peerDependencies:
react: ^18 || ^19
+ '@testing-library/dom@10.4.0':
+ resolution: {integrity: sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==}
+ engines: {node: '>=18'}
+
+ '@testing-library/jest-dom@6.6.3':
+ resolution: {integrity: sha512-IteBhl4XqYNkM54f4ejhLRJiZNqcSCoXUOG2CPK7qbD322KjQozM4kHQOfkG2oln9b9HTYqs+Sae8vBATubxxA==}
+ engines: {node: '>=14', npm: '>=6', yarn: '>=1'}
+
+ '@testing-library/react@16.3.0':
+ resolution: {integrity: sha512-kFSyxiEDwv1WLl2fgsq6pPBbw5aWKrsY2/noi1Id0TK0UParSF62oFQFGHXIyaG4pp2tEub/Zlel+fjjZILDsw==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ '@testing-library/dom': ^10.0.0
+ '@types/react': ^18.0.0 || ^19.0.0
+ '@types/react-dom': ^18.0.0 || ^19.0.0
+ react: ^18.0.0 || ^19.0.0
+ react-dom: ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+
+ '@testing-library/user-event@14.6.1':
+ resolution: {integrity: sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==}
+ engines: {node: '>=12', npm: '>=6'}
+ peerDependencies:
+ '@testing-library/dom': '>=7.21.4'
+
'@tybys/wasm-util@0.9.0':
resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==}
+ '@types/aria-query@5.0.4':
+ resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==}
+
+ '@types/babel__core@7.20.5':
+ resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
+
+ '@types/babel__generator@7.27.0':
+ resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==}
+
+ '@types/babel__template@7.4.4':
+ resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==}
+
+ '@types/babel__traverse@7.20.7':
+ resolution: {integrity: sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==}
+
'@types/body-parser@1.19.6':
resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==}
+ '@types/chai@5.2.2':
+ resolution: {integrity: sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==}
+
'@types/connect@3.4.38':
resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==}
'@types/debug@4.1.12':
resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==}
+ '@types/deep-eql@4.0.2':
+ resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==}
+
'@types/estree@1.0.8':
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
@@ -731,6 +1202,50 @@ packages:
cpu: [x64]
os: [win32]
+ '@vitejs/plugin-react@4.6.0':
+ resolution: {integrity: sha512-5Kgff+m8e2PB+9j51eGHEpn5kUzRKH2Ry0qGoe8ItJg7pqnkPrYPkDQZGgGmTa0EGarHrkjLvOdU3b1fzI8otQ==}
+ engines: {node: ^14.18.0 || >=16.0.0}
+ peerDependencies:
+ vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0
+
+ '@vitest/coverage-v8@3.2.4':
+ resolution: {integrity: sha512-EyF9SXU6kS5Ku/U82E259WSnvg6c8KTjppUncuNdm5QHpe17mwREHnjDzozC8x9MZ0xfBUFSaLkRv4TMA75ALQ==}
+ peerDependencies:
+ '@vitest/browser': 3.2.4
+ vitest: 3.2.4
+ peerDependenciesMeta:
+ '@vitest/browser':
+ optional: true
+
+ '@vitest/expect@3.2.4':
+ resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==}
+
+ '@vitest/mocker@3.2.4':
+ resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==}
+ peerDependencies:
+ msw: ^2.4.9
+ vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0
+ peerDependenciesMeta:
+ msw:
+ optional: true
+ vite:
+ optional: true
+
+ '@vitest/pretty-format@3.2.4':
+ resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==}
+
+ '@vitest/runner@3.2.4':
+ resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==}
+
+ '@vitest/snapshot@3.2.4':
+ resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==}
+
+ '@vitest/spy@3.2.4':
+ resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==}
+
+ '@vitest/utils@3.2.4':
+ resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==}
+
accepts@1.3.8:
resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
engines: {node: '>= 0.6'}
@@ -749,6 +1264,10 @@ packages:
engines: {node: '>=0.4.0'}
hasBin: true
+ agent-base@7.1.3:
+ resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==}
+ engines: {node: '>= 14'}
+
ajv@6.12.6:
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
@@ -768,6 +1287,10 @@ packages:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'}
+ ansi-styles@5.2.0:
+ resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==}
+ engines: {node: '>=10'}
+
ansi-styles@6.2.1:
resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
engines: {node: '>=12'}
@@ -779,6 +1302,9 @@ packages:
argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+ aria-query@5.3.0:
+ resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==}
+
aria-query@5.3.2:
resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==}
engines: {node: '>= 0.4'}
@@ -818,9 +1344,16 @@ packages:
resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==}
engines: {node: '>= 0.4'}
+ assertion-error@2.0.1:
+ resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
+ engines: {node: '>=12'}
+
ast-types-flow@0.0.8:
resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==}
+ ast-v8-to-istanbul@0.3.3:
+ resolution: {integrity: sha512-MuXMrSLVVoA6sYN/6Hke18vMzrT4TZNbZIj/hvh0fnYFpO+/kFXcLIaiPwXXWaQUPg4yJD8fj+lfJ7/1EBconw==}
+
async-function@1.0.0:
resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==}
engines: {node: '>= 0.4'}
@@ -882,6 +1415,10 @@ packages:
resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
engines: {node: '>= 0.8'}
+ cac@6.7.14:
+ 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'}
@@ -901,6 +1438,14 @@ packages:
caniuse-lite@1.0.30001726:
resolution: {integrity: sha512-VQAUIUzBiZ/UnlM28fSp2CRF3ivUn1BWEvxMcVTNwpw91Py1pGbPIyIKtd+tzct9C3ouceCVdGAXxZOpZAsgdw==}
+ chai@5.2.0:
+ resolution: {integrity: sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==}
+ engines: {node: '>=12'}
+
+ chalk@3.0.0:
+ resolution: {integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==}
+ engines: {node: '>=8'}
+
chalk@4.1.2:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
engines: {node: '>=10'}
@@ -909,6 +1454,10 @@ packages:
resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==}
engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
+ check-error@2.1.1:
+ resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==}
+ engines: {node: '>= 16'}
+
chokidar@3.6.0:
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
engines: {node: '>= 8.10.0'}
@@ -972,6 +1521,9 @@ packages:
resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
engines: {node: '>= 0.6'}
+ convert-source-map@2.0.0:
+ resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
+
cookie-signature@1.0.6:
resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==}
@@ -995,6 +1547,13 @@ packages:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'}
+ css.escape@1.5.1:
+ resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==}
+
+ cssstyle@4.6.0:
+ resolution: {integrity: sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==}
+ engines: {node: '>=18'}
+
csstype@3.1.3:
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
@@ -1005,6 +1564,10 @@ packages:
resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==}
engines: {node: '>= 12'}
+ data-urls@5.0.0:
+ resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==}
+ engines: {node: '>=18'}
+
data-view-buffer@1.0.2:
resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==}
engines: {node: '>= 0.4'}
@@ -1042,6 +1605,13 @@ packages:
supports-color:
optional: true
+ decimal.js@10.5.0:
+ resolution: {integrity: sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==}
+
+ deep-eql@5.0.2:
+ resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==}
+ engines: {node: '>=6'}
+
deep-is@0.1.4:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
@@ -1061,6 +1631,10 @@ packages:
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
engines: {node: '>= 0.8'}
+ dequal@2.0.3:
+ resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
+ engines: {node: '>=6'}
+
destroy@1.2.0:
resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==}
engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
@@ -1073,10 +1647,19 @@ packages:
resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
engines: {node: '>=0.10.0'}
+ dom-accessibility-api@0.5.16:
+ resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==}
+
+ dom-accessibility-api@0.6.3:
+ resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==}
+
dunder-proto@1.0.1:
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
engines: {node: '>= 0.4'}
+ eastasianwidth@0.2.0:
+ resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
+
ee-first@1.1.1:
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
@@ -1104,6 +1687,10 @@ packages:
resolution: {integrity: sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ==}
engines: {node: '>=10.13.0'}
+ entities@6.0.1:
+ resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==}
+ engines: {node: '>=0.12'}
+
environment@1.1.0:
resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==}
engines: {node: '>=18'}
@@ -1124,6 +1711,9 @@ packages:
resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==}
engines: {node: '>= 0.4'}
+ es-module-lexer@1.7.0:
+ resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==}
+
es-object-atoms@1.1.1:
resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
engines: {node: '>= 0.4'}
@@ -1140,6 +1730,11 @@ packages:
resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==}
engines: {node: '>= 0.4'}
+ esbuild@0.25.5:
+ resolution: {integrity: sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==}
+ engines: {node: '>=18'}
+ hasBin: true
+
escalade@3.2.0:
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
engines: {node: '>=6'}
@@ -1263,6 +1858,9 @@ packages:
resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
engines: {node: '>=4.0'}
+ estree-walker@3.0.3:
+ resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
+
esutils@2.0.3:
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
engines: {node: '>=0.10.0'}
@@ -1281,6 +1879,10 @@ packages:
resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==}
engines: {node: '>=16.17'}
+ expect-type@1.2.1:
+ resolution: {integrity: sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==}
+ engines: {node: '>=12.0.0'}
+
express@4.21.2:
resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==}
engines: {node: '>= 0.10.0'}
@@ -1352,6 +1954,10 @@ packages:
resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==}
engines: {node: '>= 0.4'}
+ foreground-child@3.3.1:
+ resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
+ engines: {node: '>=14'}
+
formdata-polyfill@4.0.10:
resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
engines: {node: '>=12.20.0'}
@@ -1371,6 +1977,11 @@ packages:
resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==}
engines: {node: '>= 0.8'}
+ fsevents@2.3.2:
+ 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}
@@ -1386,6 +1997,10 @@ packages:
functions-have-names@1.2.3:
resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
+ gensync@1.0.0-beta.2:
+ resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
+ engines: {node: '>=6.9.0'}
+
get-caller-file@2.0.5:
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
engines: {node: 6.* || 8.* || >= 10.*}
@@ -1421,6 +2036,14 @@ packages:
resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
engines: {node: '>=10.13.0'}
+ glob@10.4.5:
+ resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==}
+ hasBin: true
+
+ globals@11.12.0:
+ resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
+ engines: {node: '>=4'}
+
globals@14.0.0:
resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
engines: {node: '>=18'}
@@ -1470,10 +2093,25 @@ packages:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'}
+ html-encoding-sniffer@4.0.0:
+ resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==}
+ engines: {node: '>=18'}
+
+ html-escaper@2.0.2:
+ resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
+
http-errors@2.0.0:
resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
engines: {node: '>= 0.8'}
+ http-proxy-agent@7.0.2:
+ 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'}
+
human-signals@5.0.0:
resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==}
engines: {node: '>=16.17.0'}
@@ -1510,6 +2148,10 @@ packages:
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
engines: {node: '>=0.8.19'}
+ indent-string@4.0.0:
+ resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}
+ engines: {node: '>=8'}
+
inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
@@ -1611,6 +2253,9 @@ packages:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
+ is-potential-custom-element-name@1.0.1:
+ resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
+
is-promise@4.0.0:
resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==}
@@ -1660,10 +2305,29 @@ packages:
isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+ istanbul-lib-coverage@3.2.2:
+ resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==}
+ engines: {node: '>=8'}
+
+ istanbul-lib-report@3.0.1:
+ resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==}
+ engines: {node: '>=10'}
+
+ istanbul-lib-source-maps@5.0.6:
+ resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==}
+ engines: {node: '>=10'}
+
+ istanbul-reports@3.1.7:
+ resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==}
+ engines: {node: '>=8'}
+
iterator.prototype@1.1.5:
resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==}
engines: {node: '>= 0.4'}
+ jackspeak@3.4.3:
+ resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
+
jiti@2.4.2:
resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==}
hasBin: true
@@ -1671,10 +2335,27 @@ packages:
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+ js-tokens@9.0.1:
+ resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==}
+
js-yaml@4.1.0:
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
hasBin: true
+ jsdom@26.1.0:
+ resolution: {integrity: sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ canvas: ^3.0.0
+ peerDependenciesMeta:
+ canvas:
+ optional: true
+
+ jsesc@3.1.0:
+ resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
+ engines: {node: '>=6'}
+ hasBin: true
+
json-buffer@3.0.1:
resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
@@ -1688,6 +2369,11 @@ packages:
resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==}
hasBin: true
+ json5@2.2.3:
+ resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
+ engines: {node: '>=6'}
+ hasBin: true
+
jsx-ast-utils@3.3.5:
resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==}
engines: {node: '>=4.0'}
@@ -1796,6 +2482,9 @@ packages:
lodash.merge@4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
+ lodash@4.17.21:
+ resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
+
log-update@6.1.0:
resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==}
engines: {node: '>=18'}
@@ -1804,9 +2493,29 @@ packages:
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
hasBin: true
+ loupe@3.1.4:
+ resolution: {integrity: sha512-wJzkKwJrheKtknCOKNEtDK4iqg/MxmZheEMtSTYvnzRdEYaZzmgH976nenp8WdJRdx5Vc1X/9MO0Oszl6ezeXg==}
+
+ lru-cache@10.4.3:
+ resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
+
+ lru-cache@5.1.1:
+ resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+
+ lz-string@1.5.0:
+ resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==}
+ hasBin: true
+
magic-string@0.30.17:
resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
+ magicast@0.3.5:
+ resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==}
+
+ make-dir@4.0.0:
+ resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
+ engines: {node: '>=10'}
+
math-intrinsics@1.1.0:
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
engines: {node: '>= 0.4'}
@@ -1870,6 +2579,10 @@ packages:
resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==}
engines: {node: '>=18'}
+ min-indent@1.0.1:
+ resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
+ engines: {node: '>=4'}
+
minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
@@ -1983,6 +2696,9 @@ packages:
resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ nwsapi@2.2.20:
+ resolution: {integrity: sha512-/ieB+mDe4MrrKMT8z+mQL8klXydZWGR5Dowt4RAGKbJ3kIGEx3X4ljUo+6V73IXtUPWgfOlU5B9MlGxFO5T+cA==}
+
object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
@@ -2046,10 +2762,16 @@ packages:
resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
engines: {node: '>=10'}
+ package-json-from-dist@1.0.1:
+ resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
+
parent-module@1.0.1:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'}
+ parse5@7.3.0:
+ resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==}
+
parseurl@1.3.3:
resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
engines: {node: '>= 0.8'}
@@ -2069,6 +2791,10 @@ packages:
path-parse@1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
+ path-scurry@1.11.1:
+ resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
+ engines: {node: '>=16 || 14 >=14.18'}
+
path-to-regexp@0.1.12:
resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==}
@@ -2076,6 +2802,13 @@ packages:
resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==}
engines: {node: '>=16'}
+ pathe@2.0.3:
+ resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
+
+ pathval@2.0.1:
+ resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==}
+ engines: {node: '>= 14.16'}
+
peer@1.0.2:
resolution: {integrity: sha512-ZObVEhAaoskd3KuSxr5DJLM8QuqQW4w3i0MqrI8H7Bzz8DjRC3DjUg2XtQQGfdc36+8Xk+wIPT/tL5wE+KnIqg==}
engines: {node: '>=14'}
@@ -2105,6 +2838,16 @@ packages:
engines: {node: '>=0.10'}
hasBin: true
+ playwright-core@1.53.2:
+ resolution: {integrity: sha512-ox/OytMy+2w1jcYEYlOo1Hhp8hZkLCximMTUTMBXjGUA1KoFfiSZ+DU+3a739jsPY0yoKH2TFy9S2fsJas8yAw==}
+ engines: {node: '>=18'}
+ hasBin: true
+
+ playwright@1.53.2:
+ resolution: {integrity: sha512-6K/qQxVFuVQhRQhFsVZ9fGeatxirtrpPgxzBYWyZLEXJzqYwuL4fuNmfOfD5et1tJE4GScKyPNeLhZeRwuTU3A==}
+ engines: {node: '>=18'}
+ hasBin: true
+
possible-typed-array-names@1.1.0:
resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==}
engines: {node: '>= 0.4'}
@@ -2129,6 +2872,10 @@ packages:
engines: {node: '>=14'}
hasBin: true
+ pretty-format@27.5.1:
+ resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==}
+ engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
+
prop-types@15.8.1:
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
@@ -2183,11 +2930,18 @@ packages:
react-is@16.13.1:
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
+ react-is@17.0.2:
+ resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==}
+
react-qr-code@2.0.16:
resolution: {integrity: sha512-8f54aTOo7DxYr1LB47pMeclV5SL/zSbJxkXHIS2a+QnAIa4XDVIdmzYRC+CBCJeDLSCeFHn8gHtltwvwZGJD/w==}
peerDependencies:
react: '*'
+ react-refresh@0.17.0:
+ resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==}
+ engines: {node: '>=0.10.0'}
+
react@19.1.0:
resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==}
engines: {node: '>=0.10.0'}
@@ -2196,6 +2950,10 @@ packages:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'}
+ redent@3.0.0:
+ resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==}
+ engines: {node: '>=8'}
+
redis-errors@1.2.0:
resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==}
engines: {node: '>=4'}
@@ -2243,10 +3001,18 @@ packages:
rfdc@1.4.1:
resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==}
+ rollup@4.44.1:
+ resolution: {integrity: sha512-x8H8aPvD+xbl0Do8oez5f5o8eMS3trfCghc4HhLAnCkj7Vl0d1JWGs0UF/D886zLW2rOj2QymV/JcSSsw+XDNg==}
+ engines: {node: '>=18.0.0', npm: '>=8.0.0'}
+ hasBin: true
+
router@2.2.0:
resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==}
engines: {node: '>= 18'}
+ rrweb-cssom@0.8.0:
+ resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==}
+
run-parallel@1.2.0:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
@@ -2268,6 +3034,10 @@ packages:
safer-buffer@2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
+ saxes@6.0.0:
+ resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==}
+ engines: {node: '>=v12.22.7'}
+
scheduler@0.26.0:
resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==}
@@ -2342,6 +3112,9 @@ packages:
resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
engines: {node: '>= 0.4'}
+ siginfo@2.0.0:
+ resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
+
signal-exit@4.1.0:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'}
@@ -2368,6 +3141,9 @@ packages:
stable-hash@0.0.5:
resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==}
+ stackback@0.0.2:
+ resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
+
standard-as-callback@2.1.0:
resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==}
@@ -2379,6 +3155,9 @@ packages:
resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==}
engines: {node: '>= 0.8'}
+ std-env@3.9.0:
+ resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==}
+
stop-iteration-iterator@1.1.0:
resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==}
engines: {node: '>= 0.4'}
@@ -2398,6 +3177,10 @@ packages:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
engines: {node: '>=8'}
+ string-width@5.1.2:
+ resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
+ engines: {node: '>=12'}
+
string-width@7.2.0:
resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==}
engines: {node: '>=18'}
@@ -2441,10 +3224,17 @@ packages:
resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==}
engines: {node: '>=12'}
+ strip-indent@3.0.0:
+ resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==}
+ engines: {node: '>=8'}
+
strip-json-comments@3.1.1:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'}
+ strip-literal@3.0.0:
+ resolution: {integrity: sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==}
+
styled-jsx@5.1.6:
resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==}
engines: {node: '>= 12.0.0'}
@@ -2470,6 +3260,9 @@ packages:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
+ symbol-tree@3.2.4:
+ resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
+
tailwindcss@4.1.11:
resolution: {integrity: sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA==}
@@ -2481,10 +3274,39 @@ packages:
resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==}
engines: {node: '>=18'}
+ test-exclude@7.0.1:
+ resolution: {integrity: sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==}
+ engines: {node: '>=18'}
+
+ tinybench@2.9.0:
+ resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
+
+ tinyexec@0.3.2:
+ resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==}
+
tinyglobby@0.2.14:
resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==}
engines: {node: '>=12.0.0'}
+ tinypool@1.1.1:
+ resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+
+ tinyrainbow@2.0.0:
+ resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==}
+ engines: {node: '>=14.0.0'}
+
+ tinyspy@4.0.3:
+ resolution: {integrity: sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==}
+ engines: {node: '>=14.0.0'}
+
+ tldts-core@6.1.86:
+ resolution: {integrity: sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==}
+
+ tldts@6.1.86:
+ resolution: {integrity: sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==}
+ hasBin: true
+
to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
@@ -2497,6 +3319,14 @@ packages:
resolution: {integrity: sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==}
hasBin: true
+ tough-cookie@5.1.2:
+ resolution: {integrity: sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==}
+ engines: {node: '>=16'}
+
+ tr46@5.1.1:
+ resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==}
+ engines: {node: '>=18'}
+
ts-api-utils@2.1.0:
resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==}
engines: {node: '>=18.12'}
@@ -2587,6 +3417,83 @@ packages:
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
engines: {node: '>= 0.8'}
+ vite-node@3.2.4:
+ resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==}
+ engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
+ hasBin: true
+
+ vite@7.0.0:
+ resolution: {integrity: sha512-ixXJB1YRgDIw2OszKQS9WxGHKwLdCsbQNkpJN171udl6szi/rIySHL6/Os3s2+oE4P/FLD4dxg4mD7Wust+u5g==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ hasBin: true
+ peerDependencies:
+ '@types/node': ^20.19.0 || >=22.12.0
+ jiti: '>=1.21.0'
+ less: ^4.0.0
+ lightningcss: ^1.21.0
+ sass: ^1.70.0
+ sass-embedded: ^1.70.0
+ stylus: '>=0.54.8'
+ sugarss: ^5.0.0
+ terser: ^5.16.0
+ tsx: ^4.8.1
+ yaml: ^2.4.2
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+ jiti:
+ optional: true
+ less:
+ optional: true
+ lightningcss:
+ optional: true
+ sass:
+ optional: true
+ sass-embedded:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+ tsx:
+ optional: true
+ yaml:
+ optional: true
+
+ vitest@3.2.4:
+ resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==}
+ engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
+ hasBin: true
+ peerDependencies:
+ '@edge-runtime/vm': '*'
+ '@types/debug': ^4.1.12
+ '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
+ '@vitest/browser': 3.2.4
+ '@vitest/ui': 3.2.4
+ happy-dom: '*'
+ jsdom: '*'
+ peerDependenciesMeta:
+ '@edge-runtime/vm':
+ optional: true
+ '@types/debug':
+ optional: true
+ '@types/node':
+ optional: true
+ '@vitest/browser':
+ optional: true
+ '@vitest/ui':
+ optional: true
+ happy-dom:
+ optional: true
+ jsdom:
+ optional: true
+
+ w3c-xmlserializer@5.0.0:
+ resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==}
+ engines: {node: '>=18'}
+
web-streams-polyfill@3.3.3:
resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}
engines: {node: '>= 8'}
@@ -2595,6 +3502,10 @@ packages:
resolution: {integrity: sha512-A7Jxrg7+eV+eZR/CIdESDnRGFb6/bcKukGvJBB5snI6cw3is1c2qamkYstC1bY1p08TyMRlN9eTMkxmnKJBPBw==}
engines: {node: '>= 8'}
+ webidl-conversions@7.0.0:
+ resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
+ engines: {node: '>=12'}
+
webrtc-adapter@9.0.3:
resolution: {integrity: sha512-5fALBcroIl31OeXAdd1YUntxiZl1eHlZZWzNg3U4Fn+J9/cGL3eT80YlrsWGvj2ojuz1rZr2OXkgCzIxAZ7vRQ==}
engines: {node: '>=6.0.0', npm: '>=3.10.0'}
@@ -2602,6 +3513,18 @@ packages:
webrtcsupport@2.2.0:
resolution: {integrity: sha512-9KvL8SxgzbMC/SUMvW+4qcvsXtAnM0iSuxjOwsCqBbA+DA5biaQq8+f4aGfb341BgoFrQX2PQNsvrL2YkuYB1w==}
+ whatwg-encoding@3.1.1:
+ 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'}
+
+ whatwg-url@14.2.0:
+ resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==}
+ engines: {node: '>=18'}
+
which-boxed-primitive@1.1.1:
resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==}
engines: {node: '>= 0.4'}
@@ -2623,6 +3546,11 @@ packages:
engines: {node: '>= 8'}
hasBin: true
+ why-is-node-running@2.3.0:
+ resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==}
+ engines: {node: '>=8'}
+ hasBin: true
+
word-wrap@1.2.5:
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
engines: {node: '>=0.10.0'}
@@ -2631,6 +3559,10 @@ packages:
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
engines: {node: '>=10'}
+ wrap-ansi@8.1.0:
+ resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
+ engines: {node: '>=12'}
+
wrap-ansi@9.0.0:
resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==}
engines: {node: '>=18'}
@@ -2650,10 +3582,20 @@ packages:
utf-8-validate:
optional: true
+ xml-name-validator@5.0.0:
+ resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==}
+ engines: {node: '>=18'}
+
+ xmlchars@2.2.0:
+ resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
+
y18n@5.0.8:
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
engines: {node: '>=10'}
+ yallist@3.1.1:
+ resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
+
yallist@5.0.0:
resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==}
engines: {node: '>=18'}
@@ -2680,6 +3622,8 @@ packages:
snapshots:
+ '@adobe/css-tools@4.4.3': {}
+
'@alloc/quick-lru@5.2.0': {}
'@ampproject/remapping@2.3.0':
@@ -2687,6 +3631,148 @@ snapshots:
'@jridgewell/gen-mapping': 0.3.11
'@jridgewell/trace-mapping': 0.3.28
+ '@asamuzakjp/css-color@3.2.0':
+ dependencies:
+ '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
+ '@csstools/css-color-parser': 3.0.10(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
+ '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
+ '@csstools/css-tokenizer': 3.0.4
+ lru-cache: 10.4.3
+
+ '@babel/code-frame@7.27.1':
+ dependencies:
+ '@babel/helper-validator-identifier': 7.27.1
+ js-tokens: 4.0.0
+ picocolors: 1.1.1
+
+ '@babel/compat-data@7.27.7': {}
+
+ '@babel/core@7.27.7':
+ dependencies:
+ '@ampproject/remapping': 2.3.0
+ '@babel/code-frame': 7.27.1
+ '@babel/generator': 7.27.5
+ '@babel/helper-compilation-targets': 7.27.2
+ '@babel/helper-module-transforms': 7.27.3(@babel/core@7.27.7)
+ '@babel/helpers': 7.27.6
+ '@babel/parser': 7.27.7
+ '@babel/template': 7.27.2
+ '@babel/traverse': 7.27.7
+ '@babel/types': 7.27.7
+ convert-source-map: 2.0.0
+ debug: 4.4.1(supports-color@5.5.0)
+ gensync: 1.0.0-beta.2
+ json5: 2.2.3
+ semver: 6.3.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/generator@7.27.5':
+ dependencies:
+ '@babel/parser': 7.27.7
+ '@babel/types': 7.27.7
+ '@jridgewell/gen-mapping': 0.3.11
+ '@jridgewell/trace-mapping': 0.3.28
+ jsesc: 3.1.0
+
+ '@babel/helper-compilation-targets@7.27.2':
+ dependencies:
+ '@babel/compat-data': 7.27.7
+ '@babel/helper-validator-option': 7.27.1
+ browserslist: 4.25.1
+ lru-cache: 5.1.1
+ semver: 6.3.1
+
+ '@babel/helper-module-imports@7.27.1':
+ dependencies:
+ '@babel/traverse': 7.27.7
+ '@babel/types': 7.27.7
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/helper-module-transforms@7.27.3(@babel/core@7.27.7)':
+ dependencies:
+ '@babel/core': 7.27.7
+ '@babel/helper-module-imports': 7.27.1
+ '@babel/helper-validator-identifier': 7.27.1
+ '@babel/traverse': 7.27.7
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/helper-plugin-utils@7.27.1': {}
+
+ '@babel/helper-string-parser@7.27.1': {}
+
+ '@babel/helper-validator-identifier@7.27.1': {}
+
+ '@babel/helper-validator-option@7.27.1': {}
+
+ '@babel/helpers@7.27.6':
+ dependencies:
+ '@babel/template': 7.27.2
+ '@babel/types': 7.27.7
+
+ '@babel/parser@7.27.7':
+ dependencies:
+ '@babel/types': 7.27.7
+
+ '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.27.7)':
+ dependencies:
+ '@babel/core': 7.27.7
+ '@babel/helper-plugin-utils': 7.27.1
+
+ '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.27.7)':
+ dependencies:
+ '@babel/core': 7.27.7
+ '@babel/helper-plugin-utils': 7.27.1
+
+ '@babel/runtime@7.27.6': {}
+
+ '@babel/template@7.27.2':
+ dependencies:
+ '@babel/code-frame': 7.27.1
+ '@babel/parser': 7.27.7
+ '@babel/types': 7.27.7
+
+ '@babel/traverse@7.27.7':
+ dependencies:
+ '@babel/code-frame': 7.27.1
+ '@babel/generator': 7.27.5
+ '@babel/parser': 7.27.7
+ '@babel/template': 7.27.2
+ '@babel/types': 7.27.7
+ debug: 4.4.1(supports-color@5.5.0)
+ globals: 11.12.0
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/types@7.27.7':
+ dependencies:
+ '@babel/helper-string-parser': 7.27.1
+ '@babel/helper-validator-identifier': 7.27.1
+
+ '@bcoe/v8-coverage@1.0.2': {}
+
+ '@csstools/color-helpers@5.0.2': {}
+
+ '@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)':
+ dependencies:
+ '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
+ '@csstools/css-tokenizer': 3.0.4
+
+ '@csstools/css-color-parser@3.0.10(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)':
+ dependencies:
+ '@csstools/color-helpers': 5.0.2
+ '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
+ '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
+ '@csstools/css-tokenizer': 3.0.4
+
+ '@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4)':
+ dependencies:
+ '@csstools/css-tokenizer': 3.0.4
+
+ '@csstools/css-tokenizer@3.0.4': {}
+
'@emnapi/core@1.4.3':
dependencies:
'@emnapi/wasi-threads': 1.0.2
@@ -2703,6 +3789,81 @@ snapshots:
tslib: 2.8.1
optional: true
+ '@esbuild/aix-ppc64@0.25.5':
+ optional: true
+
+ '@esbuild/android-arm64@0.25.5':
+ optional: true
+
+ '@esbuild/android-arm@0.25.5':
+ optional: true
+
+ '@esbuild/android-x64@0.25.5':
+ optional: true
+
+ '@esbuild/darwin-arm64@0.25.5':
+ optional: true
+
+ '@esbuild/darwin-x64@0.25.5':
+ optional: true
+
+ '@esbuild/freebsd-arm64@0.25.5':
+ optional: true
+
+ '@esbuild/freebsd-x64@0.25.5':
+ optional: true
+
+ '@esbuild/linux-arm64@0.25.5':
+ optional: true
+
+ '@esbuild/linux-arm@0.25.5':
+ optional: true
+
+ '@esbuild/linux-ia32@0.25.5':
+ optional: true
+
+ '@esbuild/linux-loong64@0.25.5':
+ optional: true
+
+ '@esbuild/linux-mips64el@0.25.5':
+ optional: true
+
+ '@esbuild/linux-ppc64@0.25.5':
+ optional: true
+
+ '@esbuild/linux-riscv64@0.25.5':
+ optional: true
+
+ '@esbuild/linux-s390x@0.25.5':
+ optional: true
+
+ '@esbuild/linux-x64@0.25.5':
+ optional: true
+
+ '@esbuild/netbsd-arm64@0.25.5':
+ optional: true
+
+ '@esbuild/netbsd-x64@0.25.5':
+ optional: true
+
+ '@esbuild/openbsd-arm64@0.25.5':
+ optional: true
+
+ '@esbuild/openbsd-x64@0.25.5':
+ optional: true
+
+ '@esbuild/sunos-x64@0.25.5':
+ optional: true
+
+ '@esbuild/win32-arm64@0.25.5':
+ optional: true
+
+ '@esbuild/win32-ia32@0.25.5':
+ optional: true
+
+ '@esbuild/win32-x64@0.25.5':
+ optional: true
+
'@eslint-community/eslint-utils@4.7.0(eslint@9.30.0(jiti@2.4.2))':
dependencies:
eslint: 9.30.0(jiti@2.4.2)
@@ -2847,10 +4008,21 @@ snapshots:
'@ioredis/commands@1.2.0': {}
+ '@isaacs/cliui@8.0.2':
+ dependencies:
+ string-width: 5.1.2
+ string-width-cjs: string-width@4.2.3
+ strip-ansi: 7.1.0
+ strip-ansi-cjs: strip-ansi@6.0.1
+ wrap-ansi: 8.1.0
+ wrap-ansi-cjs: wrap-ansi@7.0.0
+
'@isaacs/fs-minipass@4.0.1':
dependencies:
minipass: 7.1.2
+ '@istanbuljs/schema@0.1.3': {}
+
'@jridgewell/gen-mapping@0.3.11':
dependencies:
'@jridgewell/sourcemap-codec': 1.5.3
@@ -2916,7 +4088,76 @@ snapshots:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.19.1
- '@nolyfill/is-core-module@1.0.39': {}
+ '@nolyfill/is-core-module@1.0.39': {}
+
+ '@pkgjs/parseargs@0.11.0':
+ optional: true
+
+ '@playwright/test@1.53.2':
+ dependencies:
+ playwright: 1.53.2
+
+ '@rolldown/pluginutils@1.0.0-beta.19': {}
+
+ '@rollup/rollup-android-arm-eabi@4.44.1':
+ optional: true
+
+ '@rollup/rollup-android-arm64@4.44.1':
+ optional: true
+
+ '@rollup/rollup-darwin-arm64@4.44.1':
+ optional: true
+
+ '@rollup/rollup-darwin-x64@4.44.1':
+ optional: true
+
+ '@rollup/rollup-freebsd-arm64@4.44.1':
+ optional: true
+
+ '@rollup/rollup-freebsd-x64@4.44.1':
+ optional: true
+
+ '@rollup/rollup-linux-arm-gnueabihf@4.44.1':
+ optional: true
+
+ '@rollup/rollup-linux-arm-musleabihf@4.44.1':
+ optional: true
+
+ '@rollup/rollup-linux-arm64-gnu@4.44.1':
+ optional: true
+
+ '@rollup/rollup-linux-arm64-musl@4.44.1':
+ optional: true
+
+ '@rollup/rollup-linux-loongarch64-gnu@4.44.1':
+ optional: true
+
+ '@rollup/rollup-linux-powerpc64le-gnu@4.44.1':
+ optional: true
+
+ '@rollup/rollup-linux-riscv64-gnu@4.44.1':
+ optional: true
+
+ '@rollup/rollup-linux-riscv64-musl@4.44.1':
+ optional: true
+
+ '@rollup/rollup-linux-s390x-gnu@4.44.1':
+ optional: true
+
+ '@rollup/rollup-linux-x64-gnu@4.44.1':
+ optional: true
+
+ '@rollup/rollup-linux-x64-musl@4.44.1':
+ optional: true
+
+ '@rollup/rollup-win32-arm64-msvc@4.44.1':
+ optional: true
+
+ '@rollup/rollup-win32-ia32-msvc@4.44.1':
+ optional: true
+
+ '@rollup/rollup-win32-x64-msvc@4.44.1':
+ optional: true
'@rtsao/scc@1.1.0': {}
@@ -3007,16 +4248,77 @@ snapshots:
'@tanstack/query-core': 5.81.5
react: 19.1.0
+ '@testing-library/dom@10.4.0':
+ dependencies:
+ '@babel/code-frame': 7.27.1
+ '@babel/runtime': 7.27.6
+ '@types/aria-query': 5.0.4
+ aria-query: 5.3.0
+ chalk: 4.1.2
+ dom-accessibility-api: 0.5.16
+ lz-string: 1.5.0
+ pretty-format: 27.5.1
+
+ '@testing-library/jest-dom@6.6.3':
+ dependencies:
+ '@adobe/css-tools': 4.4.3
+ aria-query: 5.3.2
+ chalk: 3.0.0
+ css.escape: 1.5.1
+ dom-accessibility-api: 0.6.3
+ lodash: 4.17.21
+ redent: 3.0.0
+
+ '@testing-library/react@16.3.0(@testing-library/dom@10.4.0)(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
+ dependencies:
+ '@babel/runtime': 7.27.6
+ '@testing-library/dom': 10.4.0
+ react: 19.1.0
+ react-dom: 19.1.0(react@19.1.0)
+ optionalDependencies:
+ '@types/react': 19.1.8
+
+ '@testing-library/user-event@14.6.1(@testing-library/dom@10.4.0)':
+ dependencies:
+ '@testing-library/dom': 10.4.0
+
'@tybys/wasm-util@0.9.0':
dependencies:
tslib: 2.8.1
optional: true
+ '@types/aria-query@5.0.4': {}
+
+ '@types/babel__core@7.20.5':
+ dependencies:
+ '@babel/parser': 7.27.7
+ '@babel/types': 7.27.7
+ '@types/babel__generator': 7.27.0
+ '@types/babel__template': 7.4.4
+ '@types/babel__traverse': 7.20.7
+
+ '@types/babel__generator@7.27.0':
+ dependencies:
+ '@babel/types': 7.27.7
+
+ '@types/babel__template@7.4.4':
+ dependencies:
+ '@babel/parser': 7.27.7
+ '@babel/types': 7.27.7
+
+ '@types/babel__traverse@7.20.7':
+ dependencies:
+ '@babel/types': 7.27.7
+
'@types/body-parser@1.19.6':
dependencies:
'@types/connect': 3.4.38
'@types/node': 22.15.34
+ '@types/chai@5.2.2':
+ dependencies:
+ '@types/deep-eql': 4.0.2
+
'@types/connect@3.4.38':
dependencies:
'@types/node': 22.15.34
@@ -3025,6 +4327,8 @@ snapshots:
dependencies:
'@types/ms': 2.1.0
+ '@types/deep-eql@4.0.2': {}
+
'@types/estree@1.0.8': {}
'@types/express-serve-static-core@4.19.6':
@@ -3229,6 +4533,79 @@ snapshots:
'@unrs/resolver-binding-win32-x64-msvc@1.9.2':
optional: true
+ '@vitejs/plugin-react@4.6.0(vite@7.0.0(@types/node@22.15.34)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0))':
+ dependencies:
+ '@babel/core': 7.27.7
+ '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.27.7)
+ '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.27.7)
+ '@rolldown/pluginutils': 1.0.0-beta.19
+ '@types/babel__core': 7.20.5
+ react-refresh: 0.17.0
+ vite: 7.0.0(@types/node@22.15.34)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)
+ transitivePeerDependencies:
+ - supports-color
+
+ '@vitest/coverage-v8@3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.15.34)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.30.1)(yaml@2.8.0))':
+ dependencies:
+ '@ampproject/remapping': 2.3.0
+ '@bcoe/v8-coverage': 1.0.2
+ ast-v8-to-istanbul: 0.3.3
+ debug: 4.4.1(supports-color@5.5.0)
+ istanbul-lib-coverage: 3.2.2
+ istanbul-lib-report: 3.0.1
+ istanbul-lib-source-maps: 5.0.6
+ istanbul-reports: 3.1.7
+ magic-string: 0.30.17
+ magicast: 0.3.5
+ std-env: 3.9.0
+ test-exclude: 7.0.1
+ tinyrainbow: 2.0.0
+ vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.15.34)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.30.1)(yaml@2.8.0)
+ transitivePeerDependencies:
+ - supports-color
+
+ '@vitest/expect@3.2.4':
+ dependencies:
+ '@types/chai': 5.2.2
+ '@vitest/spy': 3.2.4
+ '@vitest/utils': 3.2.4
+ chai: 5.2.0
+ tinyrainbow: 2.0.0
+
+ '@vitest/mocker@3.2.4(vite@7.0.0(@types/node@22.15.34)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0))':
+ dependencies:
+ '@vitest/spy': 3.2.4
+ estree-walker: 3.0.3
+ magic-string: 0.30.17
+ optionalDependencies:
+ vite: 7.0.0(@types/node@22.15.34)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)
+
+ '@vitest/pretty-format@3.2.4':
+ dependencies:
+ tinyrainbow: 2.0.0
+
+ '@vitest/runner@3.2.4':
+ dependencies:
+ '@vitest/utils': 3.2.4
+ pathe: 2.0.3
+ strip-literal: 3.0.0
+
+ '@vitest/snapshot@3.2.4':
+ dependencies:
+ '@vitest/pretty-format': 3.2.4
+ magic-string: 0.30.17
+ pathe: 2.0.3
+
+ '@vitest/spy@3.2.4':
+ dependencies:
+ tinyspy: 4.0.3
+
+ '@vitest/utils@3.2.4':
+ dependencies:
+ '@vitest/pretty-format': 3.2.4
+ loupe: 3.1.4
+ tinyrainbow: 2.0.0
+
accepts@1.3.8:
dependencies:
mime-types: 2.1.35
@@ -3245,6 +4622,8 @@ snapshots:
acorn@8.15.0: {}
+ agent-base@7.1.3: {}
+
ajv@6.12.6:
dependencies:
fast-deep-equal: 3.1.3
@@ -3264,6 +4643,8 @@ snapshots:
dependencies:
color-convert: 2.0.1
+ ansi-styles@5.2.0: {}
+
ansi-styles@6.2.1: {}
anymatch@3.1.3:
@@ -3273,6 +4654,10 @@ snapshots:
argparse@2.0.1: {}
+ aria-query@5.3.0:
+ dependencies:
+ dequal: 2.0.3
+
aria-query@5.3.2: {}
array-buffer-byte-length@1.0.2:
@@ -3344,8 +4729,16 @@ snapshots:
get-intrinsic: 1.3.0
is-array-buffer: 3.0.5
+ assertion-error@2.0.1: {}
+
ast-types-flow@0.0.8: {}
+ ast-v8-to-istanbul@0.3.3:
+ dependencies:
+ '@jridgewell/trace-mapping': 0.3.28
+ estree-walker: 3.0.3
+ js-tokens: 9.0.1
+
async-function@1.0.0: {}
autoprefixer@10.4.21(postcss@8.5.6):
@@ -3427,6 +4820,8 @@ snapshots:
bytes@3.1.2: {}
+ cac@6.7.14: {}
+
call-bind-apply-helpers@1.0.2:
dependencies:
es-errors: 1.3.0
@@ -3448,6 +4843,19 @@ snapshots:
caniuse-lite@1.0.30001726: {}
+ chai@5.2.0:
+ dependencies:
+ assertion-error: 2.0.1
+ check-error: 2.1.1
+ deep-eql: 5.0.2
+ loupe: 3.1.4
+ pathval: 2.0.1
+
+ chalk@3.0.0:
+ dependencies:
+ ansi-styles: 4.3.0
+ supports-color: 7.2.0
+
chalk@4.1.2:
dependencies:
ansi-styles: 4.3.0
@@ -3455,6 +4863,8 @@ snapshots:
chalk@5.4.1: {}
+ check-error@2.1.1: {}
+
chokidar@3.6.0:
dependencies:
anymatch: 3.1.3
@@ -3522,6 +4932,8 @@ snapshots:
content-type@1.0.5: {}
+ convert-source-map@2.0.0: {}
+
cookie-signature@1.0.6: {}
cookie-signature@1.2.2: {}
@@ -3541,12 +4953,24 @@ snapshots:
shebang-command: 2.0.0
which: 2.0.2
+ css.escape@1.5.1: {}
+
+ cssstyle@4.6.0:
+ dependencies:
+ '@asamuzakjp/css-color': 3.2.0
+ rrweb-cssom: 0.8.0
+
csstype@3.1.3: {}
damerau-levenshtein@1.0.8: {}
data-uri-to-buffer@4.0.1: {}
+ data-urls@5.0.0:
+ dependencies:
+ whatwg-mimetype: 4.0.0
+ whatwg-url: 14.2.0
+
data-view-buffer@1.0.2:
dependencies:
call-bound: 1.0.4
@@ -3579,6 +5003,10 @@ snapshots:
optionalDependencies:
supports-color: 5.5.0
+ decimal.js@10.5.0: {}
+
+ deep-eql@5.0.2: {}
+
deep-is@0.1.4: {}
define-data-property@1.1.4:
@@ -3597,6 +5025,8 @@ snapshots:
depd@2.0.0: {}
+ dequal@2.0.3: {}
+
destroy@1.2.0: {}
detect-libc@2.0.4: {}
@@ -3605,12 +5035,18 @@ snapshots:
dependencies:
esutils: 2.0.3
+ dom-accessibility-api@0.5.16: {}
+
+ dom-accessibility-api@0.6.3: {}
+
dunder-proto@1.0.1:
dependencies:
call-bind-apply-helpers: 1.0.2
es-errors: 1.3.0
gopd: 1.2.0
+ eastasianwidth@0.2.0: {}
+
ee-first@1.1.1: {}
electron-to-chromium@1.5.178: {}
@@ -3630,6 +5066,8 @@ snapshots:
graceful-fs: 4.2.11
tapable: 2.2.2
+ entities@6.0.1: {}
+
environment@1.1.0: {}
es-abstract@1.24.0:
@@ -3712,6 +5150,8 @@ snapshots:
iterator.prototype: 1.1.5
safe-array-concat: 1.1.3
+ es-module-lexer@1.7.0: {}
+
es-object-atoms@1.1.1:
dependencies:
es-errors: 1.3.0
@@ -3733,6 +5173,34 @@ snapshots:
is-date-object: 1.1.0
is-symbol: 1.1.1
+ esbuild@0.25.5:
+ optionalDependencies:
+ '@esbuild/aix-ppc64': 0.25.5
+ '@esbuild/android-arm': 0.25.5
+ '@esbuild/android-arm64': 0.25.5
+ '@esbuild/android-x64': 0.25.5
+ '@esbuild/darwin-arm64': 0.25.5
+ '@esbuild/darwin-x64': 0.25.5
+ '@esbuild/freebsd-arm64': 0.25.5
+ '@esbuild/freebsd-x64': 0.25.5
+ '@esbuild/linux-arm': 0.25.5
+ '@esbuild/linux-arm64': 0.25.5
+ '@esbuild/linux-ia32': 0.25.5
+ '@esbuild/linux-loong64': 0.25.5
+ '@esbuild/linux-mips64el': 0.25.5
+ '@esbuild/linux-ppc64': 0.25.5
+ '@esbuild/linux-riscv64': 0.25.5
+ '@esbuild/linux-s390x': 0.25.5
+ '@esbuild/linux-x64': 0.25.5
+ '@esbuild/netbsd-arm64': 0.25.5
+ '@esbuild/netbsd-x64': 0.25.5
+ '@esbuild/openbsd-arm64': 0.25.5
+ '@esbuild/openbsd-x64': 0.25.5
+ '@esbuild/sunos-x64': 0.25.5
+ '@esbuild/win32-arm64': 0.25.5
+ '@esbuild/win32-ia32': 0.25.5
+ '@esbuild/win32-x64': 0.25.5
+
escalade@3.2.0: {}
escape-html@1.0.3: {}
@@ -3934,6 +5402,10 @@ snapshots:
estraverse@5.3.0: {}
+ estree-walker@3.0.3:
+ dependencies:
+ '@types/estree': 1.0.8
+
esutils@2.0.3: {}
etag@1.8.1: {}
@@ -3954,6 +5426,8 @@ snapshots:
signal-exit: 4.1.0
strip-final-newline: 3.0.0
+ expect-type@1.2.1: {}
+
express@4.21.2:
dependencies:
accepts: 1.3.8
@@ -4104,6 +5578,11 @@ snapshots:
dependencies:
is-callable: 1.2.7
+ foreground-child@3.3.1:
+ dependencies:
+ cross-spawn: 7.0.6
+ signal-exit: 4.1.0
+
formdata-polyfill@4.0.10:
dependencies:
fetch-blob: 3.2.0
@@ -4116,6 +5595,9 @@ snapshots:
fresh@2.0.0: {}
+ fsevents@2.3.2:
+ optional: true
+
fsevents@2.3.3:
optional: true
@@ -4132,6 +5614,8 @@ snapshots:
functions-have-names@1.2.3: {}
+ gensync@1.0.0-beta.2: {}
+
get-caller-file@2.0.5: {}
get-east-asian-width@1.3.0: {}
@@ -4174,6 +5658,17 @@ snapshots:
dependencies:
is-glob: 4.0.3
+ glob@10.4.5:
+ dependencies:
+ foreground-child: 3.3.1
+ jackspeak: 3.4.3
+ minimatch: 9.0.5
+ minipass: 7.1.2
+ package-json-from-dist: 1.0.1
+ path-scurry: 1.11.1
+
+ globals@11.12.0: {}
+
globals@14.0.0: {}
globalthis@1.0.4:
@@ -4211,6 +5706,12 @@ snapshots:
dependencies:
function-bind: 1.1.2
+ html-encoding-sniffer@4.0.0:
+ dependencies:
+ whatwg-encoding: 3.1.1
+
+ html-escaper@2.0.2: {}
+
http-errors@2.0.0:
dependencies:
depd: 2.0.0
@@ -4219,6 +5720,20 @@ snapshots:
statuses: 2.0.1
toidentifier: 1.0.1
+ http-proxy-agent@7.0.2:
+ dependencies:
+ agent-base: 7.1.3
+ debug: 4.4.1(supports-color@5.5.0)
+ transitivePeerDependencies:
+ - supports-color
+
+ https-proxy-agent@7.0.6:
+ dependencies:
+ agent-base: 7.1.3
+ debug: 4.4.1(supports-color@5.5.0)
+ transitivePeerDependencies:
+ - supports-color
+
human-signals@5.0.0: {}
husky@9.1.7: {}
@@ -4244,6 +5759,8 @@ snapshots:
imurmurhash@0.1.4: {}
+ indent-string@4.0.0: {}
+
inherits@2.0.4: {}
internal-slot@1.1.0:
@@ -4355,6 +5872,8 @@ snapshots:
is-number@7.0.0: {}
+ is-potential-custom-element-name@1.0.1: {}
+
is-promise@4.0.0: {}
is-regex@1.2.1:
@@ -4402,6 +5921,27 @@ snapshots:
isexe@2.0.0: {}
+ istanbul-lib-coverage@3.2.2: {}
+
+ istanbul-lib-report@3.0.1:
+ dependencies:
+ istanbul-lib-coverage: 3.2.2
+ make-dir: 4.0.0
+ supports-color: 7.2.0
+
+ istanbul-lib-source-maps@5.0.6:
+ dependencies:
+ '@jridgewell/trace-mapping': 0.3.28
+ debug: 4.4.1(supports-color@5.5.0)
+ istanbul-lib-coverage: 3.2.2
+ transitivePeerDependencies:
+ - supports-color
+
+ istanbul-reports@3.1.7:
+ dependencies:
+ html-escaper: 2.0.2
+ istanbul-lib-report: 3.0.1
+
iterator.prototype@1.1.5:
dependencies:
define-data-property: 1.1.4
@@ -4411,14 +5951,51 @@ snapshots:
has-symbols: 1.1.0
set-function-name: 2.0.2
+ jackspeak@3.4.3:
+ dependencies:
+ '@isaacs/cliui': 8.0.2
+ optionalDependencies:
+ '@pkgjs/parseargs': 0.11.0
+
jiti@2.4.2: {}
js-tokens@4.0.0: {}
+ js-tokens@9.0.1: {}
+
js-yaml@4.1.0:
dependencies:
argparse: 2.0.1
+ jsdom@26.1.0:
+ dependencies:
+ cssstyle: 4.6.0
+ data-urls: 5.0.0
+ decimal.js: 10.5.0
+ html-encoding-sniffer: 4.0.0
+ http-proxy-agent: 7.0.2
+ https-proxy-agent: 7.0.6
+ is-potential-custom-element-name: 1.0.1
+ nwsapi: 2.2.20
+ parse5: 7.3.0
+ rrweb-cssom: 0.8.0
+ saxes: 6.0.0
+ symbol-tree: 3.2.4
+ tough-cookie: 5.1.2
+ w3c-xmlserializer: 5.0.0
+ webidl-conversions: 7.0.0
+ whatwg-encoding: 3.1.1
+ whatwg-mimetype: 4.0.0
+ whatwg-url: 14.2.0
+ ws: 8.18.3
+ xml-name-validator: 5.0.0
+ transitivePeerDependencies:
+ - bufferutil
+ - supports-color
+ - utf-8-validate
+
+ jsesc@3.1.0: {}
+
json-buffer@3.0.1: {}
json-schema-traverse@0.4.1: {}
@@ -4429,6 +6006,8 @@ snapshots:
dependencies:
minimist: 1.2.8
+ json5@2.2.3: {}
+
jsx-ast-utils@3.3.5:
dependencies:
array-includes: 3.1.9
@@ -4532,6 +6111,8 @@ snapshots:
lodash.merge@4.6.2: {}
+ lodash@4.17.21: {}
+
log-update@6.1.0:
dependencies:
ansi-escapes: 7.0.0
@@ -4544,10 +6125,30 @@ snapshots:
dependencies:
js-tokens: 4.0.0
+ loupe@3.1.4: {}
+
+ lru-cache@10.4.3: {}
+
+ lru-cache@5.1.1:
+ dependencies:
+ yallist: 3.1.1
+
+ lz-string@1.5.0: {}
+
magic-string@0.30.17:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.3
+ magicast@0.3.5:
+ dependencies:
+ '@babel/parser': 7.27.7
+ '@babel/types': 7.27.7
+ source-map-js: 1.2.1
+
+ make-dir@4.0.0:
+ dependencies:
+ semver: 7.7.2
+
math-intrinsics@1.1.0: {}
media-typer@0.3.0: {}
@@ -4587,6 +6188,8 @@ snapshots:
mimic-function@5.0.1: {}
+ min-indent@1.0.1: {}
+
minimatch@3.1.2:
dependencies:
brace-expansion: 1.1.12
@@ -4624,13 +6227,13 @@ snapshots:
react: 19.1.0
react-dom: 19.1.0(react@19.1.0)
- next-view-transitions@0.3.4(next@15.3.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
+ next-view-transitions@0.3.4(next@15.3.4(@babel/core@7.27.7)(@playwright/test@1.53.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
dependencies:
- next: 15.3.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
+ next: 15.3.4(@babel/core@7.27.7)(@playwright/test@1.53.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
react: 19.1.0
react-dom: 19.1.0(react@19.1.0)
- next@15.3.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
+ next@15.3.4(@babel/core@7.27.7)(@playwright/test@1.53.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
dependencies:
'@next/env': 15.3.4
'@swc/counter': 0.1.3
@@ -4640,7 +6243,7 @@ snapshots:
postcss: 8.4.31
react: 19.1.0
react-dom: 19.1.0(react@19.1.0)
- styled-jsx: 5.1.6(react@19.1.0)
+ styled-jsx: 5.1.6(@babel/core@7.27.7)(react@19.1.0)
optionalDependencies:
'@next/swc-darwin-arm64': 15.3.4
'@next/swc-darwin-x64': 15.3.4
@@ -4650,6 +6253,7 @@ snapshots:
'@next/swc-linux-x64-musl': 15.3.4
'@next/swc-win32-arm64-msvc': 15.3.4
'@next/swc-win32-x64-msvc': 15.3.4
+ '@playwright/test': 1.53.2
sharp: 0.34.2
transitivePeerDependencies:
- '@babel/core'
@@ -4686,6 +6290,8 @@ snapshots:
dependencies:
path-key: 4.0.0
+ nwsapi@2.2.20: {}
+
object-assign@4.1.1: {}
object-inspect@1.13.4: {}
@@ -4767,10 +6373,16 @@ snapshots:
dependencies:
p-limit: 3.1.0
+ package-json-from-dist@1.0.1: {}
+
parent-module@1.0.1:
dependencies:
callsites: 3.1.0
+ parse5@7.3.0:
+ dependencies:
+ entities: 6.0.1
+
parseurl@1.3.3: {}
path-exists@4.0.0: {}
@@ -4781,10 +6393,19 @@ snapshots:
path-parse@1.0.7: {}
+ path-scurry@1.11.1:
+ dependencies:
+ lru-cache: 10.4.3
+ minipass: 7.1.2
+
path-to-regexp@0.1.12: {}
path-to-regexp@8.2.0: {}
+ pathe@2.0.3: {}
+
+ pathval@2.0.1: {}
+
peer@1.0.2:
dependencies:
'@types/express': 4.17.23
@@ -4816,6 +6437,14 @@ snapshots:
pidtree@0.6.0: {}
+ playwright-core@1.53.2: {}
+
+ playwright@1.53.2:
+ dependencies:
+ playwright-core: 1.53.2
+ optionalDependencies:
+ fsevents: 2.3.2
+
possible-typed-array-names@1.1.0: {}
postcss-value-parser@4.2.0: {}
@@ -4836,6 +6465,12 @@ snapshots:
prettier@3.6.2: {}
+ pretty-format@27.5.1:
+ dependencies:
+ ansi-regex: 5.0.1
+ ansi-styles: 5.2.0
+ react-is: 17.0.2
+
prop-types@15.8.1:
dependencies:
loose-envify: 1.4.0
@@ -4892,18 +6527,27 @@ snapshots:
react-is@16.13.1: {}
+ react-is@17.0.2: {}
+
react-qr-code@2.0.16(react@19.1.0):
dependencies:
prop-types: 15.8.1
qr.js: 0.0.0
react: 19.1.0
+ react-refresh@0.17.0: {}
+
react@19.1.0: {}
readdirp@3.6.0:
dependencies:
picomatch: 2.3.1
+ redent@3.0.0:
+ dependencies:
+ indent-string: 4.0.0
+ strip-indent: 3.0.0
+
redis-errors@1.2.0: {}
redis-parser@3.0.0:
@@ -4957,6 +6601,32 @@ snapshots:
rfdc@1.4.1: {}
+ rollup@4.44.1:
+ dependencies:
+ '@types/estree': 1.0.8
+ optionalDependencies:
+ '@rollup/rollup-android-arm-eabi': 4.44.1
+ '@rollup/rollup-android-arm64': 4.44.1
+ '@rollup/rollup-darwin-arm64': 4.44.1
+ '@rollup/rollup-darwin-x64': 4.44.1
+ '@rollup/rollup-freebsd-arm64': 4.44.1
+ '@rollup/rollup-freebsd-x64': 4.44.1
+ '@rollup/rollup-linux-arm-gnueabihf': 4.44.1
+ '@rollup/rollup-linux-arm-musleabihf': 4.44.1
+ '@rollup/rollup-linux-arm64-gnu': 4.44.1
+ '@rollup/rollup-linux-arm64-musl': 4.44.1
+ '@rollup/rollup-linux-loongarch64-gnu': 4.44.1
+ '@rollup/rollup-linux-powerpc64le-gnu': 4.44.1
+ '@rollup/rollup-linux-riscv64-gnu': 4.44.1
+ '@rollup/rollup-linux-riscv64-musl': 4.44.1
+ '@rollup/rollup-linux-s390x-gnu': 4.44.1
+ '@rollup/rollup-linux-x64-gnu': 4.44.1
+ '@rollup/rollup-linux-x64-musl': 4.44.1
+ '@rollup/rollup-win32-arm64-msvc': 4.44.1
+ '@rollup/rollup-win32-ia32-msvc': 4.44.1
+ '@rollup/rollup-win32-x64-msvc': 4.44.1
+ fsevents: 2.3.3
+
router@2.2.0:
dependencies:
debug: 4.4.1(supports-color@5.5.0)
@@ -4967,6 +6637,8 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ rrweb-cssom@0.8.0: {}
+
run-parallel@1.2.0:
dependencies:
queue-microtask: 1.2.3
@@ -4994,6 +6666,10 @@ snapshots:
safer-buffer@2.1.2: {}
+ saxes@6.0.0:
+ dependencies:
+ xmlchars: 2.2.0
+
scheduler@0.26.0: {}
sdp@3.2.1: {}
@@ -5141,6 +6817,8 @@ snapshots:
side-channel-map: 1.0.1
side-channel-weakmap: 1.0.2
+ siginfo@2.0.0: {}
+
signal-exit@4.1.0: {}
simple-swizzle@0.2.2:
@@ -5166,12 +6844,16 @@ snapshots:
stable-hash@0.0.5: {}
+ stackback@0.0.2: {}
+
standard-as-callback@2.1.0: {}
statuses@2.0.1: {}
statuses@2.0.2: {}
+ std-env@3.9.0: {}
+
stop-iteration-iterator@1.1.0:
dependencies:
es-errors: 1.3.0
@@ -5189,6 +6871,12 @@ snapshots:
is-fullwidth-code-point: 3.0.0
strip-ansi: 6.0.1
+ string-width@5.1.2:
+ dependencies:
+ eastasianwidth: 0.2.0
+ emoji-regex: 9.2.2
+ strip-ansi: 7.1.0
+
string-width@7.2.0:
dependencies:
emoji-regex: 10.4.0
@@ -5257,12 +6945,22 @@ snapshots:
strip-final-newline@3.0.0: {}
+ strip-indent@3.0.0:
+ dependencies:
+ min-indent: 1.0.1
+
strip-json-comments@3.1.1: {}
- styled-jsx@5.1.6(react@19.1.0):
+ strip-literal@3.0.0:
+ dependencies:
+ js-tokens: 9.0.1
+
+ styled-jsx@5.1.6(@babel/core@7.27.7)(react@19.1.0):
dependencies:
client-only: 0.0.1
react: 19.1.0
+ optionalDependencies:
+ '@babel/core': 7.27.7
supports-color@5.5.0:
dependencies:
@@ -5274,6 +6972,8 @@ snapshots:
supports-preserve-symlinks-flag@1.0.0: {}
+ symbol-tree@3.2.4: {}
+
tailwindcss@4.1.11: {}
tapable@2.2.2: {}
@@ -5287,11 +6987,33 @@ snapshots:
mkdirp: 3.0.1
yallist: 5.0.0
+ test-exclude@7.0.1:
+ dependencies:
+ '@istanbuljs/schema': 0.1.3
+ glob: 10.4.5
+ minimatch: 9.0.5
+
+ tinybench@2.9.0: {}
+
+ tinyexec@0.3.2: {}
+
tinyglobby@0.2.14:
dependencies:
fdir: 6.4.6(picomatch@4.0.2)
picomatch: 4.0.2
+ tinypool@1.1.1: {}
+
+ tinyrainbow@2.0.0: {}
+
+ tinyspy@4.0.3: {}
+
+ tldts-core@6.1.86: {}
+
+ tldts@6.1.86:
+ dependencies:
+ tldts-core: 6.1.86
+
to-regex-range@5.0.1:
dependencies:
is-number: 7.0.0
@@ -5300,6 +7022,14 @@ snapshots:
touch@3.1.1: {}
+ tough-cookie@5.1.2:
+ dependencies:
+ tldts: 6.1.86
+
+ tr46@5.1.1:
+ dependencies:
+ punycode: 2.3.1
+
ts-api-utils@2.1.0(typescript@5.8.3):
dependencies:
typescript: 5.8.3
@@ -5426,16 +7156,112 @@ snapshots:
vary@1.1.2: {}
+ vite-node@3.2.4(@types/node@22.15.34)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0):
+ dependencies:
+ cac: 6.7.14
+ debug: 4.4.1(supports-color@5.5.0)
+ es-module-lexer: 1.7.0
+ pathe: 2.0.3
+ vite: 7.0.0(@types/node@22.15.34)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)
+ transitivePeerDependencies:
+ - '@types/node'
+ - jiti
+ - less
+ - lightningcss
+ - sass
+ - sass-embedded
+ - stylus
+ - sugarss
+ - supports-color
+ - terser
+ - tsx
+ - yaml
+
+ vite@7.0.0(@types/node@22.15.34)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0):
+ dependencies:
+ esbuild: 0.25.5
+ fdir: 6.4.6(picomatch@4.0.2)
+ picomatch: 4.0.2
+ postcss: 8.5.6
+ rollup: 4.44.1
+ tinyglobby: 0.2.14
+ optionalDependencies:
+ '@types/node': 22.15.34
+ fsevents: 2.3.3
+ jiti: 2.4.2
+ lightningcss: 1.30.1
+ yaml: 2.8.0
+
+ vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.15.34)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.30.1)(yaml@2.8.0):
+ dependencies:
+ '@types/chai': 5.2.2
+ '@vitest/expect': 3.2.4
+ '@vitest/mocker': 3.2.4(vite@7.0.0(@types/node@22.15.34)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0))
+ '@vitest/pretty-format': 3.2.4
+ '@vitest/runner': 3.2.4
+ '@vitest/snapshot': 3.2.4
+ '@vitest/spy': 3.2.4
+ '@vitest/utils': 3.2.4
+ chai: 5.2.0
+ debug: 4.4.1(supports-color@5.5.0)
+ expect-type: 1.2.1
+ magic-string: 0.30.17
+ pathe: 2.0.3
+ picomatch: 4.0.2
+ std-env: 3.9.0
+ tinybench: 2.9.0
+ tinyexec: 0.3.2
+ tinyglobby: 0.2.14
+ tinypool: 1.1.1
+ tinyrainbow: 2.0.0
+ vite: 7.0.0(@types/node@22.15.34)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)
+ vite-node: 3.2.4(@types/node@22.15.34)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)
+ why-is-node-running: 2.3.0
+ optionalDependencies:
+ '@types/debug': 4.1.12
+ '@types/node': 22.15.34
+ jsdom: 26.1.0
+ transitivePeerDependencies:
+ - jiti
+ - less
+ - lightningcss
+ - msw
+ - sass
+ - sass-embedded
+ - stylus
+ - sugarss
+ - supports-color
+ - terser
+ - tsx
+ - yaml
+
+ w3c-xmlserializer@5.0.0:
+ dependencies:
+ xml-name-validator: 5.0.0
+
web-streams-polyfill@3.3.3: {}
web-streams-polyfill@4.1.0: {}
+ webidl-conversions@7.0.0: {}
+
webrtc-adapter@9.0.3:
dependencies:
sdp: 3.2.1
webrtcsupport@2.2.0: {}
+ whatwg-encoding@3.1.1:
+ dependencies:
+ iconv-lite: 0.6.3
+
+ whatwg-mimetype@4.0.0: {}
+
+ whatwg-url@14.2.0:
+ dependencies:
+ tr46: 5.1.1
+ webidl-conversions: 7.0.0
+
which-boxed-primitive@1.1.1:
dependencies:
is-bigint: 1.1.0
@@ -5481,6 +7307,11 @@ snapshots:
dependencies:
isexe: 2.0.0
+ why-is-node-running@2.3.0:
+ dependencies:
+ siginfo: 2.0.0
+ stackback: 0.0.2
+
word-wrap@1.2.5: {}
wrap-ansi@7.0.0:
@@ -5489,6 +7320,12 @@ snapshots:
string-width: 4.2.3
strip-ansi: 6.0.1
+ wrap-ansi@8.1.0:
+ dependencies:
+ ansi-styles: 6.2.1
+ string-width: 5.1.2
+ strip-ansi: 7.1.0
+
wrap-ansi@9.0.0:
dependencies:
ansi-styles: 6.2.1
@@ -5499,8 +7336,14 @@ snapshots:
ws@8.18.3: {}
+ xml-name-validator@5.0.0: {}
+
+ xmlchars@2.2.0: {}
+
y18n@5.0.8: {}
+ yallist@3.1.1: {}
+
yallist@5.0.0: {}
yaml@2.8.0: {}
diff --git a/tests/e2e/basic.test.ts b/tests/e2e/basic.test.ts
new file mode 100644
index 0000000..5cd4674
--- /dev/null
+++ b/tests/e2e/basic.test.ts
@@ -0,0 +1,9 @@
+///
+import { test, expect } from '@playwright/test'
+
+test('home page loads', async ({ page }) => {
+ await page.goto('http://localhost:3000/')
+ await expect(
+ page.getByText('Peer-to-peer file transfers in your browser.'),
+ ).toBeVisible()
+})
diff --git a/tests/unit/CancelButton.test.tsx b/tests/unit/CancelButton.test.tsx
new file mode 100644
index 0000000..94686fa
--- /dev/null
+++ b/tests/unit/CancelButton.test.tsx
@@ -0,0 +1,14 @@
+///
+import React from 'react'
+import { render, fireEvent } from '@testing-library/react'
+import { describe, it, expect, vi } from 'vitest'
+import CancelButton from '../../src/components/CancelButton'
+
+describe('CancelButton', () => {
+ it('calls onClick when clicked', () => {
+ const onClick = vi.fn()
+ const { getByText } = render()
+ fireEvent.click(getByText('Cancel'))
+ expect(onClick).toHaveBeenCalled()
+ })
+})
diff --git a/tests/unit/ConnectionListItem.test.tsx b/tests/unit/ConnectionListItem.test.tsx
new file mode 100644
index 0000000..057799d
--- /dev/null
+++ b/tests/unit/ConnectionListItem.test.tsx
@@ -0,0 +1,25 @@
+///
+import React from 'react'
+import { render } from '@testing-library/react'
+import { describe, it, expect } from 'vitest'
+import { ConnectionListItem } from '../../src/components/ConnectionListItem'
+import { UploaderConnectionStatus } from '../../src/types'
+
+const baseConn = {
+ status: UploaderConnectionStatus.Uploading,
+ dataConnection: {} as any,
+ completedFiles: 1,
+ totalFiles: 2,
+ currentFileProgress: 0.5,
+ browserName: 'Chrome',
+ browserVersion: '120',
+}
+
+describe('ConnectionListItem', () => {
+ it('shows status and progress', () => {
+ const { getByText } = render()
+ expect(getByText((c, e) => e?.textContent === 'Chrome v120')).toBeInTheDocument()
+ expect(getByText('UPLOADING')).toBeInTheDocument()
+ expect(getByText('Completed: 1 / 2 files')).toBeInTheDocument()
+ })
+})
diff --git a/tests/unit/CopyableInput.test.tsx b/tests/unit/CopyableInput.test.tsx
new file mode 100644
index 0000000..618c77a
--- /dev/null
+++ b/tests/unit/CopyableInput.test.tsx
@@ -0,0 +1,22 @@
+///
+import React from 'react'
+import { render, fireEvent } from '@testing-library/react'
+import { act } from 'react'
+import { describe, it, expect, vi } from 'vitest'
+import { CopyableInput } from '../../src/components/CopyableInput'
+
+Object.assign(navigator, {
+ clipboard: {
+ writeText: vi.fn().mockResolvedValue(undefined),
+ },
+})
+
+describe('CopyableInput', () => {
+ it('copies text when button clicked', async () => {
+ const { getByText } = render()
+ await act(async () => {
+ fireEvent.click(getByText('Copy'))
+ })
+ expect(navigator.clipboard.writeText).toHaveBeenCalledWith('hello')
+ })
+})
diff --git a/tests/unit/DownloadButton.test.tsx b/tests/unit/DownloadButton.test.tsx
new file mode 100644
index 0000000..5d8bc3e
--- /dev/null
+++ b/tests/unit/DownloadButton.test.tsx
@@ -0,0 +1,14 @@
+///
+import React from 'react'
+import { render, fireEvent } from '@testing-library/react'
+import { describe, it, expect, vi } from 'vitest'
+import DownloadButton from '../../src/components/DownloadButton'
+
+describe('DownloadButton', () => {
+ it('calls onClick', () => {
+ const fn = vi.fn()
+ const { getByText } = render()
+ fireEvent.click(getByText('Download'))
+ expect(fn).toHaveBeenCalled()
+ })
+})
diff --git a/tests/unit/Downloader.subcomponents.test.tsx b/tests/unit/Downloader.subcomponents.test.tsx
new file mode 100644
index 0000000..3632337
--- /dev/null
+++ b/tests/unit/Downloader.subcomponents.test.tsx
@@ -0,0 +1,60 @@
+///
+import { vi } from 'vitest'
+vi.mock('next-view-transitions', () => ({ Link: (p: any) => {p.children} }))
+import React from 'react'
+import { render, fireEvent, waitFor } from '@testing-library/react'
+import { describe, it, expect } from 'vitest'
+import {
+ ConnectingToUploader,
+ DownloadComplete,
+ DownloadInProgress,
+ ReadyToDownload,
+ PasswordEntry,
+} from '../../src/components/Downloader'
+
+const files = [{ fileName: 'a.txt', size: 1, type: 'text/plain' }]
+
+describe('Downloader subcomponents', () => {
+ it('ConnectingToUploader shows troubleshooting', async () => {
+ const { getByText } = render(
+ ,
+ )
+ await waitFor(() => {
+ expect(getByText('Having trouble connecting?')).toBeInTheDocument()
+ })
+ })
+
+ it('DownloadComplete lists files', () => {
+ const { getByText } = render(
+ ,
+ )
+ expect(getByText('You downloaded 1 file.')).toBeInTheDocument()
+ })
+
+ it('DownloadInProgress shows stop button', () => {
+ const { getByText } = render(
+ {}} />,
+ )
+ expect(getByText('Stop Download')).toBeInTheDocument()
+ })
+
+ it('ReadyToDownload shows start button', () => {
+ const { getByText } = render(
+ {}} />,
+ )
+ expect(getByText('Download')).toBeInTheDocument()
+ })
+
+ it('PasswordEntry submits value', () => {
+ let submitted = ''
+ const { getByPlaceholderText, getByText } = render(
+ (submitted = v)} />,
+ )
+ fireEvent.change(
+ getByPlaceholderText('Enter a secret password for this slice of FilePizza...'),
+ { target: { value: 'secret' } },
+ )
+ fireEvent.submit(getByText('Unlock'))
+ expect(submitted).toBe('secret')
+ })
+})
diff --git a/tests/unit/DropZone.test.tsx b/tests/unit/DropZone.test.tsx
new file mode 100644
index 0000000..db9d323
--- /dev/null
+++ b/tests/unit/DropZone.test.tsx
@@ -0,0 +1,19 @@
+///
+import React from 'react'
+import { render, fireEvent } from '@testing-library/react'
+import { describe, it, expect, vi } from 'vitest'
+import DropZone from '../../src/components/DropZone'
+
+function createFile(name: string) {
+ return new File(['hello'], name, { type: 'text/plain' })
+}
+
+describe('DropZone', () => {
+ it('calls onDrop when file selected', () => {
+ const fn = vi.fn()
+ const { container } = render()
+ const input = container.querySelector('input') as HTMLInputElement
+ fireEvent.change(input, { target: { files: [createFile('a.txt')] } })
+ expect(fn).toHaveBeenCalled()
+ })
+})
diff --git a/tests/unit/ErrorMessage.test.tsx b/tests/unit/ErrorMessage.test.tsx
new file mode 100644
index 0000000..5d16c43
--- /dev/null
+++ b/tests/unit/ErrorMessage.test.tsx
@@ -0,0 +1,12 @@
+///
+import React from 'react'
+import { render } from '@testing-library/react'
+import { describe, it, expect } from 'vitest'
+import { ErrorMessage } from '../../src/components/ErrorMessage'
+
+describe('ErrorMessage', () => {
+ it('renders message', () => {
+ const { getByText } = render()
+ expect(getByText('oops')).toBeInTheDocument()
+ })
+})
diff --git a/tests/unit/Footer.test.tsx b/tests/unit/Footer.test.tsx
new file mode 100644
index 0000000..25d1640
--- /dev/null
+++ b/tests/unit/Footer.test.tsx
@@ -0,0 +1,18 @@
+///
+import React from 'react'
+import { render, fireEvent } from '@testing-library/react'
+import { describe, it, expect } from 'vitest'
+import Footer from '../../src/components/Footer'
+
+Object.defineProperty(window, 'location', {
+ value: { href: '' },
+ writable: true,
+})
+
+describe('Footer', () => {
+ it('redirects to donate link', () => {
+ const { getByText } = render()
+ fireEvent.click(getByText('Donate'))
+ expect(window.location.href).toContain('coinbase')
+ })
+})
diff --git a/tests/unit/InputLabel.test.tsx b/tests/unit/InputLabel.test.tsx
new file mode 100644
index 0000000..a22b6ce
--- /dev/null
+++ b/tests/unit/InputLabel.test.tsx
@@ -0,0 +1,16 @@
+///
+import React from 'react'
+import { render, fireEvent } from '@testing-library/react'
+import { describe, it, expect } from 'vitest'
+import InputLabel from '../../src/components/InputLabel'
+
+describe('InputLabel', () => {
+ it('shows tooltip on hover', () => {
+ const { getByRole, getByText } = render(
+ Label,
+ )
+ const button = getByRole('button')
+ fireEvent.mouseOver(button)
+ expect(getByText('tip')).toBeInTheDocument()
+ })
+})
diff --git a/tests/unit/Loading.test.tsx b/tests/unit/Loading.test.tsx
new file mode 100644
index 0000000..98a901b
--- /dev/null
+++ b/tests/unit/Loading.test.tsx
@@ -0,0 +1,12 @@
+///
+import React from 'react'
+import { render } from '@testing-library/react'
+import { describe, it, expect } from 'vitest'
+import Loading from '../../src/components/Loading'
+
+describe('Loading', () => {
+ it('renders text', () => {
+ const { getByText } = render()
+ expect(getByText('wait')).toBeInTheDocument()
+ })
+})
diff --git a/tests/unit/ModeToggle.test.tsx b/tests/unit/ModeToggle.test.tsx
new file mode 100644
index 0000000..fd7c26b
--- /dev/null
+++ b/tests/unit/ModeToggle.test.tsx
@@ -0,0 +1,16 @@
+///
+import React from 'react'
+import { render, fireEvent } from '@testing-library/react'
+import { describe, it, expect, vi } from 'vitest'
+import { ModeToggle } from '../../src/components/ModeToggle'
+
+const setTheme = vi.fn()
+vi.mock('next-themes', () => ({ useTheme: () => ({ setTheme, resolvedTheme: 'light' }) }))
+
+describe('ModeToggle', () => {
+ it('toggles theme', () => {
+ const { getByRole } = render()
+ fireEvent.click(getByRole('button'))
+ expect(setTheme).toHaveBeenCalledWith('dark')
+ })
+})
diff --git a/tests/unit/PasswordField.test.tsx b/tests/unit/PasswordField.test.tsx
new file mode 100644
index 0000000..ac77de3
--- /dev/null
+++ b/tests/unit/PasswordField.test.tsx
@@ -0,0 +1,18 @@
+///
+import React from 'react'
+import { render, fireEvent } from '@testing-library/react'
+import { describe, it, expect } from 'vitest'
+import PasswordField from '../../src/components/PasswordField'
+
+describe('PasswordField', () => {
+ it('calls onChange', () => {
+ let val = ''
+ const { getByPlaceholderText } = render(
+ (val = v)} />,
+ )
+ fireEvent.change(getByPlaceholderText('Enter a secret password for this slice of FilePizza...'), {
+ target: { value: 'a' },
+ })
+ expect(val).toBe('a')
+ })
+})
diff --git a/tests/unit/ProgressBar.test.tsx b/tests/unit/ProgressBar.test.tsx
new file mode 100644
index 0000000..5bea75f
--- /dev/null
+++ b/tests/unit/ProgressBar.test.tsx
@@ -0,0 +1,12 @@
+///
+import React from 'react'
+import { render } from '@testing-library/react'
+import { describe, it, expect } from 'vitest'
+import ProgressBar from '../../src/components/ProgressBar'
+
+describe('ProgressBar', () => {
+ it('shows percentage', () => {
+ const { getAllByText } = render()
+ expect(getAllByText('50%').length).toBeGreaterThan(0)
+ })
+})
diff --git a/tests/unit/QueryClientProvider.test.tsx b/tests/unit/QueryClientProvider.test.tsx
new file mode 100644
index 0000000..c4d964c
--- /dev/null
+++ b/tests/unit/QueryClientProvider.test.tsx
@@ -0,0 +1,16 @@
+///
+import React from 'react'
+import { render } from '@testing-library/react'
+import { describe, it, expect } from 'vitest'
+import FilePizzaQueryClientProvider from '../../src/components/QueryClientProvider'
+
+describe('QueryClientProvider', () => {
+ it('renders children', () => {
+ const { getByText } = render(
+
+ child
+ ,
+ )
+ expect(getByText('child')).toBeInTheDocument()
+ })
+})
diff --git a/tests/unit/ReportTermsViolationButton.test.tsx b/tests/unit/ReportTermsViolationButton.test.tsx
new file mode 100644
index 0000000..e73faf3
--- /dev/null
+++ b/tests/unit/ReportTermsViolationButton.test.tsx
@@ -0,0 +1,23 @@
+///
+import React from 'react'
+import { render, fireEvent } from '@testing-library/react'
+import { describe, it, expect, vi } from 'vitest'
+import FilePizzaQueryClientProvider from '../../src/components/QueryClientProvider'
+
+vi.mock('../../src/components/WebRTCProvider', () => ({
+ useWebRTCPeer: () => ({ peer: { connect: vi.fn(() => ({ on: vi.fn(), close: vi.fn() })) } }),
+}))
+
+import ReportTermsViolationButton from '../../src/components/ReportTermsViolationButton'
+
+describe('ReportTermsViolationButton', () => {
+ it('opens modal on click', () => {
+ const { getByText } = render(
+
+
+ ,
+ )
+ fireEvent.click(getByText('Report suspicious pizza delivery'))
+ expect(getByText('Found a suspicious delivery?')).toBeInTheDocument()
+ })
+})
diff --git a/tests/unit/ReturnHome.test.tsx b/tests/unit/ReturnHome.test.tsx
new file mode 100644
index 0000000..e4e8e11
--- /dev/null
+++ b/tests/unit/ReturnHome.test.tsx
@@ -0,0 +1,14 @@
+///
+vi.mock("next-view-transitions", () => ({ Link: (p: any) => {p.children} }))
+import { vi } from "vitest"
+import React from 'react'
+import { render } from '@testing-library/react'
+import { describe, it, expect } from 'vitest'
+import ReturnHome from '../../src/components/ReturnHome'
+
+describe('ReturnHome', () => {
+ it('links to home', () => {
+ const { getByText } = render()
+ expect(getByText(/Serve up/).getAttribute('href')).toBe('/')
+ })
+})
diff --git a/tests/unit/Spinner.test.tsx b/tests/unit/Spinner.test.tsx
new file mode 100644
index 0000000..4d9d9b9
--- /dev/null
+++ b/tests/unit/Spinner.test.tsx
@@ -0,0 +1,19 @@
+///
+import React from 'react'
+import { render } from '@testing-library/react'
+import { act } from 'react'
+import { describe, it, expect } from 'vitest'
+import Spinner from '../../src/components/Spinner'
+import { setRotating } from '../../src/hooks/useRotatingSpinner'
+
+describe('Spinner', () => {
+ it('reflects rotating state', () => {
+ // @ts-ignore
+ act(() => { setRotating(true) })
+// @ts-ignore
+ const { getByLabelText } = render()
+ expect(getByLabelText('Rotating pizza')).toBeInTheDocument()
+ // @ts-ignore
+ act(() => { setRotating(false) })
+ })
+})
diff --git a/tests/unit/StartButton.test.tsx b/tests/unit/StartButton.test.tsx
new file mode 100644
index 0000000..8b74967
--- /dev/null
+++ b/tests/unit/StartButton.test.tsx
@@ -0,0 +1,14 @@
+///
+import React from 'react'
+import { render, fireEvent } from '@testing-library/react'
+import { describe, it, expect, vi } from 'vitest'
+import StartButton from '../../src/components/StartButton'
+
+describe('StartButton', () => {
+ it('calls handler', () => {
+ const fn = vi.fn()
+ const { getByText } = render()
+ fireEvent.click(getByText('Start'))
+ expect(fn).toHaveBeenCalled()
+ })
+})
diff --git a/tests/unit/StopButton.test.tsx b/tests/unit/StopButton.test.tsx
new file mode 100644
index 0000000..7bc6593
--- /dev/null
+++ b/tests/unit/StopButton.test.tsx
@@ -0,0 +1,19 @@
+///
+import React from 'react'
+import { render, fireEvent } from '@testing-library/react'
+import { describe, it, expect, vi } from 'vitest'
+import StopButton from '../../src/components/StopButton'
+
+describe('StopButton', () => {
+ it('labels correctly when downloading', () => {
+ const { getByText } = render( {}} isDownloading />)
+ expect(getByText('Stop Download')).toBeInTheDocument()
+ })
+
+ it('calls handler', () => {
+ const fn = vi.fn()
+ const { getByText } = render()
+ fireEvent.click(getByText('Stop Upload'))
+ expect(fn).toHaveBeenCalled()
+ })
+})
diff --git a/tests/unit/TermsAcceptance.test.tsx b/tests/unit/TermsAcceptance.test.tsx
new file mode 100644
index 0000000..e0f6372
--- /dev/null
+++ b/tests/unit/TermsAcceptance.test.tsx
@@ -0,0 +1,13 @@
+///
+import React from 'react'
+import { render, fireEvent } from '@testing-library/react'
+import { describe, it, expect } from 'vitest'
+import TermsAcceptance from '../../src/components/TermsAcceptance'
+
+describe('TermsAcceptance', () => {
+ it('opens modal', () => {
+ const { getByText } = render()
+ fireEvent.click(getByText('our terms'))
+ expect(getByText('FilePizza Terms')).toBeInTheDocument()
+ })
+})
diff --git a/tests/unit/ThemeProvider.test.tsx b/tests/unit/ThemeProvider.test.tsx
new file mode 100644
index 0000000..b52ff66
--- /dev/null
+++ b/tests/unit/ThemeProvider.test.tsx
@@ -0,0 +1,17 @@
+///
+Object.defineProperty(window, "matchMedia", { value: () => ({ matches: false, addListener: () => {}, removeListener: () => {} }) })
+import React from 'react'
+import { render } from '@testing-library/react'
+import { describe, it, expect } from 'vitest'
+import { ThemeProvider } from '../../src/components/ThemeProvider'
+
+describe('ThemeProvider', () => {
+ it('renders children', () => {
+ const { getByText } = render(
+
+ child
+ ,
+ )
+ expect(getByText('child')).toBeInTheDocument()
+ })
+})
diff --git a/tests/unit/TitleText.test.tsx b/tests/unit/TitleText.test.tsx
new file mode 100644
index 0000000..c7d39d5
--- /dev/null
+++ b/tests/unit/TitleText.test.tsx
@@ -0,0 +1,12 @@
+///
+import React from 'react'
+import { render } from '@testing-library/react'
+import { describe, it, expect } from 'vitest'
+import TitleText from '../../src/components/TitleText'
+
+describe('TitleText', () => {
+ it('renders children', () => {
+ const { getByText } = render(hello)
+ expect(getByText('hello')).toBeInTheDocument()
+ })
+})
diff --git a/tests/unit/TypeBadge.test.tsx b/tests/unit/TypeBadge.test.tsx
new file mode 100644
index 0000000..2c509a2
--- /dev/null
+++ b/tests/unit/TypeBadge.test.tsx
@@ -0,0 +1,12 @@
+///
+import React from 'react'
+import { render } from '@testing-library/react'
+import { describe, it, expect } from 'vitest'
+import TypeBadge from '../../src/components/TypeBadge'
+
+describe('TypeBadge', () => {
+ it('renders type', () => {
+ const { getByText } = render()
+ expect(getByText('image/png')).toBeInTheDocument()
+ })
+})
diff --git a/tests/unit/UnlockButton.test.tsx b/tests/unit/UnlockButton.test.tsx
new file mode 100644
index 0000000..fadc045
--- /dev/null
+++ b/tests/unit/UnlockButton.test.tsx
@@ -0,0 +1,14 @@
+///
+import React from 'react'
+import { render, fireEvent } from '@testing-library/react'
+import { describe, it, expect, vi } from 'vitest'
+import UnlockButton from '../../src/components/UnlockButton'
+
+describe('UnlockButton', () => {
+ it('calls onClick', () => {
+ const fn = vi.fn()
+ const { getByText } = render()
+ fireEvent.click(getByText('Unlock'))
+ expect(fn).toHaveBeenCalled()
+ })
+})
diff --git a/tests/unit/UploadFileList.test.tsx b/tests/unit/UploadFileList.test.tsx
new file mode 100644
index 0000000..21392d5
--- /dev/null
+++ b/tests/unit/UploadFileList.test.tsx
@@ -0,0 +1,15 @@
+///
+import React from 'react'
+import { render, fireEvent } from '@testing-library/react'
+import { describe, it, expect, vi } from 'vitest'
+import UploadFileList from '../../src/components/UploadFileList'
+
+describe('UploadFileList', () => {
+ it('calls onRemove', () => {
+ const fn = vi.fn()
+ const files = [{ fileName: 'a.txt', type: 'text/plain' }]
+ const { getByText } = render()
+ fireEvent.click(getByText('✕'))
+ expect(fn).toHaveBeenCalledWith(0)
+ })
+})
diff --git a/tests/unit/Uploader.test.tsx b/tests/unit/Uploader.test.tsx
new file mode 100644
index 0000000..2985a6a
--- /dev/null
+++ b/tests/unit/Uploader.test.tsx
@@ -0,0 +1,35 @@
+///
+import React from 'react'
+import { render } from '@testing-library/react'
+import { describe, it, expect, vi } from 'vitest'
+
+var mockUseUploaderChannel: any
+
+vi.mock('../../src/components/WebRTCProvider', () => ({
+ useWebRTCPeer: () => ({ peer: { id: '1' }, stop: vi.fn() }),
+}))
+vi.mock('../../src/hooks/useUploaderChannel', () => ({
+ useUploaderChannel: (...args: any[]) => mockUseUploaderChannel(...args),
+}))
+vi.mock('../../src/hooks/useUploaderConnections', () => ({ useUploaderConnections: () => [] }))
+vi.mock('react-qr-code', () => ({ default: () => QR
}))
+vi.mock('../../src/components/CopyableInput', () => ({ CopyableInput: () => Input
}))
+vi.mock('../../src/components/ConnectionListItem', () => ({ ConnectionListItem: () => Item
}))
+vi.mock('../../src/components/StopButton', () => ({ default: () => }))
+
+import Uploader from '../../src/components/Uploader'
+
+describe('Uploader', () => {
+ it('shows loading when channel loading', () => {
+ mockUseUploaderChannel = vi.fn().mockReturnValueOnce({
+ isLoading: true,
+ error: null,
+ longSlug: undefined,
+ shortSlug: undefined,
+ longURL: undefined,
+ shortURL: undefined,
+ })
+ const { getByText } = render( {}} />)
+ expect(getByText('Creating channel...')).toBeInTheDocument()
+ })
+})
diff --git a/tests/unit/WebRTCProvider.test.tsx b/tests/unit/WebRTCProvider.test.tsx
new file mode 100644
index 0000000..4b44a35
--- /dev/null
+++ b/tests/unit/WebRTCProvider.test.tsx
@@ -0,0 +1,24 @@
+///
+import React from 'react'
+import { render, waitFor } from '@testing-library/react'
+import { describe, it, expect, vi } from 'vitest'
+
+vi.stubGlobal('fetch', vi.fn(() => Promise.resolve(new Response(JSON.stringify({ iceServers: [] })))) )
+vi.mock('peerjs', () => ({
+ default: class { id = 'peer1'; on(event: string, cb: (id: string) => void) { if (event === 'open') cb('peer1') } off() {} },
+}))
+
+import WebRTCProvider from '../../src/components/WebRTCProvider'
+
+const Child = () => child
+
+describe('WebRTCProvider', () => {
+ it('renders children after init', async () => {
+ const { getByText } = render(
+
+
+ ,
+ )
+ await waitFor(() => expect(getByText('child')).toBeInTheDocument())
+ })
+})
diff --git a/tests/unit/Wordmark.test.tsx b/tests/unit/Wordmark.test.tsx
new file mode 100644
index 0000000..b857656
--- /dev/null
+++ b/tests/unit/Wordmark.test.tsx
@@ -0,0 +1,12 @@
+///
+import React from 'react'
+import { render } from '@testing-library/react'
+import { describe, it, expect } from 'vitest'
+import Wordmark from '../../src/components/Wordmark'
+
+describe('Wordmark', () => {
+ it('renders svg', () => {
+ const { getByLabelText } = render()
+ expect(getByLabelText('FilePizza logo')).toBeInTheDocument()
+ })
+})
diff --git a/tests/unit/useRotatingSpinner.test.ts b/tests/unit/useRotatingSpinner.test.ts
new file mode 100644
index 0000000..f68ccb4
--- /dev/null
+++ b/tests/unit/useRotatingSpinner.test.ts
@@ -0,0 +1,21 @@
+import { describe, it, expect, vi } from 'vitest'
+import {
+ setRotating,
+ addRotationListener,
+ removeRotationListener,
+ getRotating,
+} from '../../src/hooks/useRotatingSpinner'
+
+describe('useRotatingSpinner state helpers', () => {
+ it('notifies listeners on state change', () => {
+ const listener = vi.fn()
+ addRotationListener(listener)
+ setRotating(true)
+ expect(listener).toHaveBeenCalledWith(true)
+ expect(getRotating()).toBe(true)
+ setRotating(false)
+ expect(listener).toHaveBeenCalledWith(false)
+ expect(getRotating()).toBe(false)
+ removeRotationListener(listener)
+ })
+})
diff --git a/tsconfig.json b/tsconfig.json
index eaa6f8f..e889abe 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -24,7 +24,11 @@
"name": "next"
}
],
- "strictNullChecks": true
+ "strictNullChecks": true,
+ "types": [
+ "vitest/globals",
+ "@testing-library/jest-dom"
+ ]
},
"include": [
"tailwind.config.js",
@@ -32,6 +36,8 @@
"src/**/*.js",
"src/**/*.ts",
"src/**/*.tsx",
+ "tests/**/*.ts",
+ "tests/**/*.tsx",
".next/types/**/*.ts"
],
"exclude": [
diff --git a/vitest.config.ts b/vitest.config.ts
new file mode 100644
index 0000000..1234b31
--- /dev/null
+++ b/vitest.config.ts
@@ -0,0 +1,16 @@
+import react from '@vitejs/plugin-react'
+import { defineConfig } from 'vitest/config'
+
+export default defineConfig({
+ plugins: [react()],
+ test: {
+ environment: 'jsdom',
+ globals: true,
+ setupFiles: './vitest.setup.ts',
+ exclude: ['tests/e2e/**', '**/node_modules/**'],
+ coverage: {
+ provider: 'v8',
+ reporter: ['text', 'html'],
+ },
+ },
+})
diff --git a/vitest.setup.ts b/vitest.setup.ts
new file mode 100644
index 0000000..c44951a
--- /dev/null
+++ b/vitest.setup.ts
@@ -0,0 +1 @@
+import '@testing-library/jest-dom'