├── .husky └── pre-push ├── readme-banner.png ├── pnpm-workspace.yaml ├── .prettierrc.json ├── packages └── core │ ├── src │ ├── runtime.ts │ ├── auto.ts │ ├── react.tsx │ └── index.ts │ ├── tsconfig.json │ ├── tests │ ├── unit │ │ ├── auto.test.ts │ │ ├── ssr-helpers.test.ts │ │ ├── runtime.test.ts │ │ ├── index.test.ts │ │ └── react.test.tsx │ ├── setup.ts │ ├── integration │ │ └── auto-init.test.ts │ ├── fixtures │ │ ├── test-page.html │ │ └── runtime.min.js │ └── e2e │ │ └── visibility.spec.ts │ ├── vitest.config.ts │ ├── playwright.config.ts │ ├── tsup.config.ts │ ├── README.md │ └── package.json ├── .prettierignore ├── package.json ├── tsconfig.json ├── .gitignore ├── .github └── workflows │ ├── release.yml │ └── ci.yml ├── README.md ├── LICENSE └── pnpm-lock.yaml /.husky/pre-push: -------------------------------------------------------------------------------- 1 | pnpm pr 2 | 3 | -------------------------------------------------------------------------------- /readme-banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vivienhenz24/fuzzy-canary/HEAD/readme-banner.png -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - 'packages/*' 3 | - 'examples/*' 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "singleQuote": true, 4 | "tabWidth": 2, 5 | "trailingComma": "es5", 6 | "printWidth": 100, 7 | "arrowParens": "avoid" 8 | } 9 | 10 | -------------------------------------------------------------------------------- /packages/core/src/runtime.ts: -------------------------------------------------------------------------------- 1 | import { init } from './index' 2 | 3 | // Expose to global scope for browser usage 4 | if (typeof window !== 'undefined') { 5 | ;(window as any).YourPkg = { init } 6 | } 7 | -------------------------------------------------------------------------------- /packages/core/src/auto.ts: -------------------------------------------------------------------------------- 1 | import { init } from './index' 2 | 3 | const AUTO_INIT_FLAG = Symbol.for('fuzzycanary.autoInit') 4 | const globalAny = globalThis as any 5 | 6 | const run = (): void => { 7 | init() 8 | } 9 | 10 | if (!globalAny[AUTO_INIT_FLAG]) { 11 | run() 12 | globalAny[AUTO_INIT_FLAG] = true 13 | } 14 | -------------------------------------------------------------------------------- /packages/core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "_comment": "TypeScript configuration for the core package - extends root config and specifies compilation options for building the SDK", 3 | "extends": "../../tsconfig.json", 4 | "compilerOptions": { 5 | "baseUrl": ".", 6 | "jsx": "react", 7 | "paths": { 8 | "@/*": ["src/*"] 9 | } 10 | }, 11 | "include": ["src/**/*"] 12 | } 13 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | node_modules/ 3 | .pnp 4 | .pnp.js 5 | 6 | # Build outputs 7 | dist/ 8 | build/ 9 | *.tsbuildinfo 10 | 11 | # Testing 12 | coverage/ 13 | .nyc_output/ 14 | test-results/ 15 | playwright-report/ 16 | 17 | # Lock files 18 | pnpm-lock.yaml 19 | package-lock.json 20 | yarn.lock 21 | 22 | # Generated files 23 | *.min.js 24 | *.map 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fuzzyfrontend", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "pnpm -r run build", 8 | "test": "pnpm -r --filter @fuzzycanary/core test" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "packageManager": "pnpm@10.11.1", 14 | "devDependencies": { 15 | "@types/node": "^25.0.1", 16 | "tsup": "^8.5.1", 17 | "typescript": "^5.9.3", 18 | "vitest": "^4.0.15" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "ESNext", 5 | "lib": ["ES2020", "DOM"], 6 | "moduleResolution": "bundler", 7 | "jsx": "react", 8 | "strict": true, 9 | "esModuleInterop": true, 10 | "skipLibCheck": true, 11 | "declaration": true, 12 | "declarationMap": true, 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "noEmit": true 16 | }, 17 | "exclude": ["node_modules", "dist", "build", "**/*.test.ts", "**/*.spec.ts"] 18 | } 19 | -------------------------------------------------------------------------------- /packages/core/tests/unit/auto.test.ts: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, expect, it, vi } from 'vitest' 2 | 3 | const AUTO_FLAG = Symbol.for('fuzzycanary.autoInit') 4 | 5 | describe('auto.ts', () => { 6 | beforeEach(() => { 7 | delete (globalThis as any)[AUTO_FLAG] 8 | vi.resetModules() 9 | vi.clearAllMocks() 10 | }) 11 | 12 | it('auto-inits exactly once on import', async () => { 13 | vi.mock('../../src/index', () => ({ init: vi.fn() })) 14 | const { init } = await import('../../src/index') 15 | await import('../../src/auto') 16 | expect(init).toHaveBeenCalledTimes(1) 17 | }) 18 | }) 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | node_modules/ 3 | .pnp 4 | .pnp.js 5 | 6 | # Build outputs 7 | dist/ 8 | build/ 9 | *.tsbuildinfo 10 | 11 | # Testing 12 | coverage/ 13 | .nyc_output/ 14 | 15 | # Environment 16 | .env 17 | .env.local 18 | .env.*.local 19 | 20 | # IDE 21 | .vscode/ 22 | .idea/ 23 | *.swp 24 | *.swo 25 | *~ 26 | 27 | # OS 28 | .DS_Store 29 | Thumbs.db 30 | 31 | # Logs 32 | *.log 33 | npm-debug.log* 34 | yarn-debug.log* 35 | yarn-error.log* 36 | pnpm-debug.log* 37 | lerna-debug.log* 38 | 39 | # Temporary files 40 | *.tmp 41 | *.temp 42 | .cache/ 43 | 44 | test-results/ 45 | playwright-report/ 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /packages/core/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitest/config' 2 | 3 | export default defineConfig({ 4 | test: { 5 | environment: 'jsdom', 6 | globals: true, 7 | setupFiles: ['./tests/setup.ts'], 8 | include: [ 9 | 'tests/unit/**/*.test.ts', 10 | 'tests/unit/**/*.test.tsx', 11 | 'tests/integration/**/*.test.ts', 12 | ], 13 | exclude: ['node_modules/**'], 14 | coverage: { 15 | provider: 'v8', 16 | reporter: ['text', 'json', 'html'], 17 | include: ['src/**/*.ts'], 18 | exclude: ['src/**/*.test.ts', 'tests/**'], 19 | }, 20 | }, 21 | plugins: [ 22 | { 23 | name: 'yaml-as-text', 24 | transform(code, id) { 25 | if (id.endsWith('.yaml')) { 26 | return { 27 | code: `export default ${JSON.stringify(code)};`, 28 | map: null, 29 | } 30 | } 31 | }, 32 | }, 33 | ], 34 | }) 35 | -------------------------------------------------------------------------------- /packages/core/playwright.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, devices } from '@playwright/test' 2 | 3 | const PORT = Number(process.env.E2E_PORT || 3000) 4 | const BASE_URL = `http://localhost:${PORT}` 5 | 6 | export default defineConfig({ 7 | testDir: './tests/e2e', 8 | fullyParallel: true, 9 | forbidOnly: !!process.env.CI, 10 | retries: process.env.CI ? 2 : 0, 11 | workers: process.env.CI ? 1 : undefined, 12 | reporter: 'html', 13 | 14 | use: { 15 | baseURL: BASE_URL, 16 | trace: 'on-first-retry', 17 | }, 18 | 19 | projects: [ 20 | { 21 | name: 'chromium', 22 | use: { ...devices['Desktop Chrome'] }, 23 | }, 24 | { 25 | name: 'firefox', 26 | use: { ...devices['Desktop Firefox'] }, 27 | }, 28 | { 29 | name: 'webkit', 30 | use: { ...devices['Desktop Safari'] }, 31 | }, 32 | ], 33 | 34 | webServer: { 35 | command: `python3 -m http.server ${PORT}`, 36 | url: BASE_URL, 37 | cwd: './tests/fixtures', 38 | reuseExistingServer: !process.env.CI, 39 | }, 40 | }) 41 | 42 | -------------------------------------------------------------------------------- /packages/core/src/react.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { getCanaryPayload } from './index' 3 | 4 | export interface CanaryProps {} 5 | 6 | /** 7 | * Canary component for server-side rendering. 8 | * Renders hidden canary links at the start of the body. 9 | * The links are invisible but present in the DOM for scrapers to pick up and follow. 10 | * 11 | * @returns Hidden div with canary links, or null if no links are configured 12 | */ 13 | export function Canary(_props: CanaryProps = {}): JSX.Element | null { 14 | const links = getCanaryPayload() 15 | 16 | if (links.length === 0) { 17 | return null 18 | } 19 | 20 | return ( 21 |
30 | {links.map(({ description, url }, index) => ( 31 | 37 | {description} - {url} 38 | 39 | ))} 40 |
41 | ) 42 | } 43 | -------------------------------------------------------------------------------- /packages/core/tests/unit/ssr-helpers.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect, vi, beforeEach } from 'vitest' 2 | import { getCanaryPayload } from '../../src/index' 3 | 4 | describe('SSR helpers', () => { 5 | beforeEach(() => { 6 | // Set CANARY_TEXT for tests 7 | process.env.CANARY_TEXT = JSON.stringify([ 8 | { description: 'API Documentation', url: 'https://example.com/api/docs' }, 9 | { description: 'Internal Dashboard', url: 'https://example.com/admin/dashboard' }, 10 | ]) 11 | }) 12 | 13 | it('getCanaryPayload returns array of canary links', () => { 14 | const payload = getCanaryPayload() 15 | expect(Array.isArray(payload)).toBe(true) 16 | expect(payload.length).toBeGreaterThan(0) 17 | 18 | // Check first link has required structure 19 | const firstLink = payload[0] 20 | expect(firstLink).toHaveProperty('description') 21 | expect(firstLink).toHaveProperty('url') 22 | expect(firstLink.url).toContain('http') 23 | }) 24 | 25 | it('getCanaryPayload returns empty array when CANARY_TEXT is not set', () => { 26 | delete process.env.CANARY_TEXT 27 | const payload = getCanaryPayload() 28 | expect(Array.isArray(payload)).toBe(true) 29 | expect(payload.length).toBe(0) 30 | }) 31 | }) 32 | -------------------------------------------------------------------------------- /packages/core/tsup.config.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * tsup.config.ts 3 | * 4 | * Build configuration for the core package. 5 | * Defines how to bundle the SDK into multiple formats: 6 | * - ESM and CJS for npm imports 7 | * - IIFE browser bundle (runtime.min.js) with global window.YourPkg 8 | */ 9 | 10 | import { defineConfig } from 'tsup' 11 | 12 | export default defineConfig([ 13 | // ESM and CJS builds for npm 14 | { 15 | entry: ['src/index.ts', 'src/auto.ts', 'src/react.tsx'], 16 | format: ['esm', 'cjs'], 17 | dts: true, 18 | clean: true, 19 | sourcemap: true, 20 | external: ['react'], 21 | esbuildOptions(options) { 22 | options.loader = { ...(options.loader || {}), '.yaml': 'text' } 23 | // Inject environment variables at build time 24 | options.define = { 25 | ...options.define, 26 | 'process.env.CANARY_TEXT': JSON.stringify(process.env.CANARY_TEXT || ''), 27 | } 28 | }, 29 | }, 30 | // Browser runtime bundle 31 | { 32 | entry: ['src/runtime.ts'], 33 | format: ['iife'], 34 | globalName: 'YourPkg', 35 | minify: true, 36 | outDir: 'dist', 37 | outExtension: () => ({ js: '.min.js' }), 38 | esbuildOptions(options) { 39 | options.loader = { ...(options.loader || {}), '.yaml': 'text' } 40 | // Inject environment variables at build time 41 | options.define = { 42 | ...options.define, 43 | 'process.env.CANARY_TEXT': JSON.stringify(process.env.CANARY_TEXT || ''), 44 | } 45 | }, 46 | }, 47 | ]) 48 | -------------------------------------------------------------------------------- /packages/core/tests/setup.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Global test setup for Vitest + jsdom 3 | * Configures the DOM environment for unit and integration tests 4 | */ 5 | 6 | import { vi } from 'vitest' 7 | 8 | // Prevent auto-init side effects during test module evaluation 9 | ;(globalThis as any)[Symbol.for('fuzzycanary.disableAuto')] = true 10 | 11 | // Mock console.warn to track warnings without polluting test output 12 | global.console = { 13 | ...console, 14 | warn: vi.fn(console.warn), 15 | } 16 | 17 | // Helper to clean up DOM before each test 18 | export function cleanupDOM() { 19 | // Clear document body and head 20 | document.body.innerHTML = '' 21 | document.head.innerHTML = '' 22 | 23 | // Reset document ready state to 'complete' by default 24 | Object.defineProperty(document, 'readyState', { 25 | writable: true, 26 | value: 'complete', 27 | }) 28 | 29 | // Default user agent to a non-bot string 30 | setUserAgent('Mozilla/5.0 (jsdom)') 31 | 32 | // Reset DOM canary injection guard 33 | delete (globalThis as any)[Symbol.for('fuzzycanary.domInit')] 34 | delete (globalThis as any)[Symbol.for('fuzzycanary.autoImport')] 35 | } 36 | 37 | // Helper to wait for async DOM operations 38 | export async function waitForDOMUpdate(ms = 20) { 39 | return new Promise(resolve => setTimeout(resolve, ms)) 40 | } 41 | 42 | // Helper to stub navigator.userAgent for bot / non-bot scenarios 43 | export function setUserAgent(ua: string) { 44 | Object.defineProperty(navigator, 'userAgent', { 45 | value: ua, 46 | configurable: true, 47 | }) 48 | } 49 | -------------------------------------------------------------------------------- /packages/core/tests/integration/auto-init.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect, beforeEach, vi } from 'vitest' 2 | import { waitForDOMUpdate, cleanupDOM } from '../setup' 3 | 4 | const AUTO_FLAG = Symbol.for('fuzzycanary.autoInit') 5 | 6 | describe('auto entrypoint', () => { 7 | beforeEach(() => { 8 | cleanupDOM() 9 | delete (globalThis as any)[AUTO_FLAG] 10 | vi.resetModules() 11 | // Set CANARY_TEXT for tests 12 | process.env.CANARY_TEXT = JSON.stringify([ 13 | { description: 'API Documentation', url: 'https://example.com/api/docs' }, 14 | { description: 'Internal Dashboard', url: 'https://example.com/admin/dashboard' }, 15 | ]) 16 | }) 17 | 18 | it('injects canary links when auto entry is imported', async () => { 19 | await import('../../src/auto') 20 | await waitForDOMUpdate() 21 | 22 | const firstChild = document.body.firstChild 23 | expect(firstChild?.nodeType).toBe(Node.ELEMENT_NODE) 24 | expect((firstChild as HTMLElement)?.tagName).toBe('DIV') 25 | expect((firstChild as HTMLElement)?.getAttribute('data-fuzzy-canary')).toBe('true') 26 | expect((firstChild as HTMLElement)?.style.display).toBe('none') 27 | expect((firstChild as HTMLElement)?.style.position).toBe('absolute') 28 | 29 | // Check that links were injected 30 | const links = (firstChild as HTMLElement)?.querySelectorAll('a[data-canary-link]') 31 | expect(links.length).toBeGreaterThan(0) 32 | 33 | // Check first link 34 | const firstLink = links[0] as HTMLAnchorElement 35 | expect(firstLink.href).toContain('http') 36 | expect(firstLink.textContent).toContain('-') // Should contain description - url format 37 | }) 38 | }) 39 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*' 7 | 8 | jobs: 9 | publish: 10 | runs-on: ubuntu-latest 11 | permissions: 12 | contents: read 13 | id-token: write 14 | 15 | steps: 16 | - name: Checkout code 17 | uses: actions/checkout@v4 18 | 19 | - name: Setup pnpm 20 | uses: pnpm/action-setup@v4 21 | with: 22 | version: 10.11.1 23 | 24 | - name: Setup Node.js (with npm registry) 25 | uses: actions/setup-node@v4 26 | with: 27 | node-version: '20' 28 | registry-url: 'https://registry.npmjs.org' 29 | cache: 'pnpm' 30 | 31 | - name: Ensure npm is latest (for OIDC trusted publishing) 32 | run: npm install -g npm@latest 33 | 34 | - name: Install dependencies 35 | run: pnpm install --frozen-lockfile 36 | 37 | - name: Run tests 38 | run: pnpm test 39 | 40 | - name: Build packages 41 | run: pnpm build 42 | env: 43 | CANARY_TEXT: ${{ secrets.CANARY_TEXT }} 44 | 45 | - name: Check if version already published 46 | id: version_check 47 | working-directory: packages/core 48 | run: | 49 | PKG_VERSION=$(node -p "require('./package.json').version") 50 | echo "version=$PKG_VERSION" >> $GITHUB_OUTPUT 51 | if npm view @fuzzycanary/core versions --json | grep -q "\"$PKG_VERSION\""; then 52 | echo "Version $PKG_VERSION already published; skipping." 53 | echo "skip=true" >> $GITHUB_OUTPUT 54 | else 55 | echo "skip=false" >> $GITHUB_OUTPUT 56 | fi 57 | 58 | - name: Publish @fuzzycanary/core via OIDC 59 | if: steps.version_check.outputs.skip != 'true' 60 | working-directory: packages/core 61 | run: npm publish --access public 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /packages/core/README.md: -------------------------------------------------------------------------------- 1 | # Fuzzy Canary 2 | 3 | Client-side SDK that plants hidden honeypot links (porn links) in the DOM to trigger AI scrapers' content safety filters. When AI bots scrape your site, they ingest these adult content links, causing their safety filters to flag or refuse the scraped data - breaking the scraping pipeline. No configuration required. 4 | 5 |
6 | 7 | **dom** • **sdk** • **anti-scraping** • **hidden** • **payload** 8 | 9 |
10 | 11 | ## Getting Started 12 | 13 | ### Installation 14 | 15 | ```bash 16 | npm i @fuzzycanary/core 17 | # or 18 | pnpm add @fuzzycanary/core 19 | ``` 20 | 21 | ### Usage 22 | 23 | There are two ways to use it: client-side or server-side. Use server-side if you can—it works better because the canary is in the HTML from the start, so scrapers that don't run JavaScript will still see it. 24 | 25 | **Server-side (recommended):** 26 | 27 | If you're using a React-based framework (Next.js, Remix, etc.), add the `` component to your root layout: 28 | 29 | ```tsx 30 | // Next.js App Router: app/layout.tsx 31 | // Remix: app/root.tsx 32 | // Other React frameworks: your root layout file 33 | import { Canary } from '@fuzzycanary/core/react' 34 | 35 | export default function RootLayout({ children }) { 36 | return ( 37 | 38 | 39 | 40 | {children} 41 | 42 | 43 | ) 44 | } 45 | ``` 46 | 47 | For non-React frameworks, use the `getCanaryHtml()` utility and insert it at the start of your `` tag. 48 | 49 | **Client-side:** 50 | 51 | If you're building a static site or prefer client-side injection, import the auto-init in your entry file: 52 | 53 | ```ts 54 | // Your main entry file (e.g., main.ts, index.ts, App.tsx) 55 | import '@fuzzycanary/core/auto' 56 | ``` 57 | 58 | That's it. It will automatically inject the canary when the page loads. 59 | 60 | ## Notes on SEO 61 | 62 | Fuzzy Canary now injects for every visitor, including crawlers. If you're concerned about how this affects indexing or rankings, consider testing in a staging environment before rolling out to production. 63 | -------------------------------------------------------------------------------- /packages/core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@fuzzycanary/core", 3 | "version": "0.2.2", 4 | "description": "Client-side SDK for adding hidden DOM payloads to deter scrapers", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/vivienhenz24/fuzzy-canary.git" 8 | }, 9 | "main": "./dist/index.cjs", 10 | "module": "./dist/index.js", 11 | "types": "./dist/index.d.ts", 12 | "exports": { 13 | ".": { 14 | "types": "./dist/index.d.ts", 15 | "import": "./dist/index.js", 16 | "require": "./dist/index.cjs" 17 | }, 18 | "./auto": { 19 | "types": "./dist/auto.d.ts", 20 | "import": "./dist/auto.js", 21 | "require": "./dist/auto.cjs" 22 | }, 23 | "./react": { 24 | "types": "./dist/react.d.ts", 25 | "import": "./dist/react.js", 26 | "require": "./dist/react.cjs" 27 | }, 28 | "./runtime": "./dist/runtime.min.js" 29 | }, 30 | "sideEffects": [ 31 | "./dist/auto.js", 32 | "./dist/runtime.min.js", 33 | "./dist/index.js", 34 | "./dist/index.cjs" 35 | ], 36 | "files": [ 37 | "dist" 38 | ], 39 | "scripts": { 40 | "build": "tsup", 41 | "dev": "tsup --watch", 42 | "test": "vitest run", 43 | "test:watch": "vitest", 44 | "test:ui": "vitest --ui", 45 | "test:e2e:playwright": "playwright test", 46 | "test:all": "pnpm test && pnpm build", 47 | "test:coverage": "vitest run --coverage", 48 | "clean": "rm -rf dist" 49 | }, 50 | "keywords": [ 51 | "dom", 52 | "sdk", 53 | "anti-scraping", 54 | "hidden", 55 | "payload" 56 | ], 57 | "license": "Apache-2.0", 58 | "peerDependencies": { 59 | "react": ">=16.8.0" 60 | }, 61 | "peerDependenciesMeta": { 62 | "react": { 63 | "optional": true 64 | } 65 | }, 66 | "devDependencies": { 67 | "@playwright/test": "^1.48.2", 68 | "@testing-library/jest-dom": "^6.9.1", 69 | "@testing-library/react": "^16.3.1", 70 | "@types/node": "^25.0.1", 71 | "@types/react": "^18.2.0", 72 | "@vitest/coverage-v8": "^4.0.15", 73 | "@vitest/ui": "^4.0.15", 74 | "jsdom": "^25.0.1", 75 | "react": "^19.2.3", 76 | "react-dom": "^19.2.3", 77 | "tsup": "^8.5.1", 78 | "typescript": "^5.9.3", 79 | "vitest": "^4.0.15" 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /packages/core/tests/unit/runtime.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect, beforeEach, vi } from 'vitest' 2 | import { waitForDOMUpdate, setUserAgent, cleanupDOM } from '../setup' 3 | 4 | describe('runtime.ts', () => { 5 | beforeEach(() => { 6 | cleanupDOM() 7 | delete (window as any).YourPkg 8 | delete (globalThis as any)[Symbol.for('fuzzycanary.domInit')] 9 | vi.resetModules() 10 | // Set CANARY_TEXT for tests 11 | process.env.CANARY_TEXT = JSON.stringify([ 12 | { description: 'API Documentation', url: 'https://example.com/api/docs' }, 13 | { description: 'Internal Dashboard', url: 'https://example.com/admin/dashboard' }, 14 | ]) 15 | }) 16 | 17 | it('exposes window.YourPkg with init', async () => { 18 | await import('../../src/runtime') 19 | expect((window as any).YourPkg).toBeDefined() 20 | expect(typeof (window as any).YourPkg.init).toBe('function') 21 | }) 22 | 23 | it('allows calling init from the global to inject canary', async () => { 24 | await import('../../src/runtime') 25 | ;(window as any).YourPkg.init() 26 | await waitForDOMUpdate() 27 | 28 | const firstChild = document.body.firstChild 29 | expect(firstChild?.nodeType).toBe(Node.ELEMENT_NODE) 30 | expect((firstChild as HTMLElement)?.tagName).toBe('DIV') 31 | expect((firstChild as HTMLElement)?.getAttribute('data-fuzzy-canary')).toBe('true') 32 | expect((firstChild as HTMLElement)?.style.display).toBe('none') 33 | expect((firstChild as HTMLElement)?.style.position).toBe('absolute') 34 | 35 | // Check that links were injected 36 | const links = (firstChild as HTMLElement)?.querySelectorAll('a[data-canary-link]') 37 | expect(links.length).toBeGreaterThan(0) 38 | 39 | // Check first link has proper attributes 40 | const firstLink = links[0] as HTMLAnchorElement 41 | expect(firstLink.getAttribute('data-canary-link')).toBe('true') 42 | expect(firstLink.href).toContain('http') 43 | }) 44 | 45 | it('injects even when UA looks like a search bot', async () => { 46 | setUserAgent('Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)') 47 | await import('../../src/runtime') 48 | ;(window as any).YourPkg.init() 49 | await waitForDOMUpdate() 50 | 51 | expect(document.body.textContent?.length).toBeGreaterThan(0) 52 | expect(document.body.childNodes.length).toBeGreaterThan(0) 53 | }) 54 | }) 55 | -------------------------------------------------------------------------------- /packages/core/tests/fixtures/test-page.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Canary Test Page 7 | 50 | 51 | 52 |
53 |

Canary Placement Test Page

54 |

This page verifies canary placement without impacting users or SEO.

55 |
56 | 57 |
58 |
59 |

Visible Content

60 |

This is the main content that users can see. It should remain visible and unaffected by the SDK.

61 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

62 |
63 |
64 | 65 |
66 |

© 2025 Test Page

67 |
68 | 69 | 70 | 71 | 72 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | 9 | jobs: 10 | build-and-test: 11 | runs-on: ubuntu-latest 12 | 13 | strategy: 14 | matrix: 15 | node-version: [20.x, 22.x] 16 | 17 | steps: 18 | - name: Checkout code 19 | uses: actions/checkout@v4 20 | 21 | - name: Setup pnpm 22 | uses: pnpm/action-setup@v4 23 | with: 24 | version: 10.11.1 25 | 26 | - name: Setup Node.js ${{ matrix.node-version }} 27 | uses: actions/setup-node@v4 28 | with: 29 | node-version: ${{ matrix.node-version }} 30 | cache: 'pnpm' 31 | 32 | - name: Install dependencies 33 | run: pnpm install --frozen-lockfile 34 | 35 | - name: Build packages 36 | run: pnpm build 37 | env: 38 | CANARY_TEXT: ${{ secrets.CANARY_TEXT }} 39 | 40 | - name: Run tests 41 | run: pnpm test 42 | continue-on-error: true 43 | 44 | - name: Check for build artifacts 45 | run: | 46 | if [ -d "packages/core/dist" ]; then 47 | echo "✓ Core package built successfully" 48 | ls -la packages/core/dist/ || true 49 | else 50 | echo "⚠ Core package dist not found" 51 | fi 52 | 53 | lint: 54 | runs-on: ubuntu-latest 55 | steps: 56 | - name: Checkout code 57 | uses: actions/checkout@v4 58 | 59 | - name: Setup pnpm 60 | uses: pnpm/action-setup@v4 61 | with: 62 | version: 10.11.1 63 | 64 | - name: Setup Node.js 65 | uses: actions/setup-node@v4 66 | with: 67 | node-version: '20.x' 68 | cache: 'pnpm' 69 | 70 | - name: Install dependencies 71 | run: pnpm install --frozen-lockfile 72 | 73 | - name: Run linter 74 | run: pnpm lint 75 | continue-on-error: true 76 | 77 | type-check: 78 | runs-on: ubuntu-latest 79 | steps: 80 | - name: Checkout code 81 | uses: actions/checkout@v4 82 | 83 | - name: Setup pnpm 84 | uses: pnpm/action-setup@v4 85 | with: 86 | version: 10.11.1 87 | 88 | - name: Setup Node.js 89 | uses: actions/setup-node@v4 90 | with: 91 | node-version: '20.x' 92 | cache: 'pnpm' 93 | 94 | - name: Install dependencies 95 | run: pnpm install --frozen-lockfile 96 | 97 | - name: Type check 98 | run: pnpm type-check 99 | continue-on-error: true 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ![Banner](./readme-banner.png) 4 | 5 | # Fuzzy Canary 6 | 7 | AI companies are scraping everyone's sites for training data. If you're self-hosting your blog, there's not much you can do about it, except maybe make them think your site contains content they won't want. Fuzzy Canary plants invisible links (to porn websites...) in your HTML that trigger scrapers' content safeguards. 8 | 9 |
10 | 11 | [![npm](https://img.shields.io/npm/v/@fuzzycanary/core)](https://www.npmjs.com/package/@fuzzycanary/core) 12 | [![CI](https://img.shields.io/github/actions/workflow/status/vivienhenz24/fuzzyfrontend/ci.yml?branch=main&label=CI)](https://github.com/vivienhenz24/fuzzyfrontend/actions) 13 | [![License](https://img.shields.io/npm/l/@fuzzycanary/core)](https://github.com/vivienhenz24/fuzzyfrontend/blob/main/LICENSE) 14 | [![npm downloads](https://img.shields.io/npm/dm/@fuzzycanary/core)](https://www.npmjs.com/package/@fuzzycanary/core) 15 | [![Bundle size](https://img.shields.io/bundlephobia/minzip/%40fuzzycanary%2Fcore)](https://bundlephobia.com/package/@fuzzycanary/core) 16 | 17 |
18 | 19 | ## Getting Started 20 | 21 | ### Installation 22 | 23 | ```bash 24 | npm i @fuzzycanary/core 25 | # or 26 | pnpm add @fuzzycanary/core 27 | ``` 28 | 29 | ### Usage 30 | 31 | There are two ways to use it: client-side or server-side. Use server-side if you can—it works better because the canary is in the HTML from the start, so scrapers that don't run JavaScript will still see it. 32 | 33 | **Server-side (recommended):** 34 | 35 | If you're using a React-based framework (Next.js, Remix, etc.), add the `` component to your root layout: 36 | 37 | ```tsx 38 | // Next.js App Router: app/layout.tsx 39 | // Other React frameworks: your root layout file 40 | import { Canary } from '@fuzzycanary/core/react' 41 | 42 | export default function RootLayout({ children }) { 43 | return ( 44 | 45 | 46 | 47 | {children} 48 | 49 | 50 | ) 51 | } 52 | ``` 53 | 54 | For non-React frameworks, use the `getCanaryHtml()` utility and insert it at the start of your `` tag. 55 | 56 | **Client-side:** 57 | 58 | If you're building a static site or prefer client-side injection, import the auto-init in your entry file: 59 | 60 | ```ts 61 | // Your main entry file (e.g., main.ts, index.ts, App.tsx) 62 | import '@fuzzycanary/core/auto' 63 | ``` 64 | 65 | That's it. It will automatically inject the canary when the page loads. 66 | 67 | ## Notes on SEO 68 | 69 | Fuzzy Canary now injects for every visitor, including crawlers. If you're concerned about how this affects indexing or rankings, consider testing in a staging environment before rolling out to production. 70 | -------------------------------------------------------------------------------- /packages/core/tests/unit/index.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect, beforeEach, vi } from 'vitest' 2 | import { init } from '../../src/index' 3 | import { waitForDOMUpdate, setUserAgent, cleanupDOM } from '../setup' 4 | 5 | describe('index.ts - canary placement strategy (no config)', () => { 6 | beforeEach(() => { 7 | cleanupDOM() 8 | vi.clearAllMocks() 9 | // Set CANARY_TEXT for tests 10 | process.env.CANARY_TEXT = JSON.stringify([ 11 | { description: 'API Documentation', url: 'https://example.com/api/docs' }, 12 | { description: 'Internal Dashboard', url: 'https://example.com/admin/dashboard' }, 13 | ]) 14 | }) 15 | 16 | it('injects hidden links at the beginning of body', async () => { 17 | init() 18 | await waitForDOMUpdate() 19 | 20 | // Check that a hidden div container was injected at the start of body 21 | const firstChild = document.body.firstChild 22 | expect(firstChild?.nodeType).toBe(Node.ELEMENT_NODE) 23 | expect((firstChild as HTMLElement)?.tagName).toBe('DIV') 24 | expect((firstChild as HTMLElement)?.getAttribute('data-fuzzy-canary')).toBe('true') 25 | expect((firstChild as HTMLElement)?.style.display).toBe('none') 26 | expect((firstChild as HTMLElement)?.style.position).toBe('absolute') 27 | expect((firstChild as HTMLElement)?.style.left).toBe('-9999px') 28 | 29 | // Check that links were injected 30 | const links = (firstChild as HTMLElement)?.querySelectorAll('a[data-canary-link]') 31 | expect(links.length).toBeGreaterThan(0) 32 | 33 | // Check first link has proper attributes 34 | const firstLink = links[0] as HTMLAnchorElement 35 | expect(firstLink.getAttribute('data-canary-link')).toBe('true') 36 | expect(firstLink.href).toContain('http') 37 | expect(firstLink.textContent).toContain('-') // Should have "description - url" format 38 | }) 39 | 40 | it('still injects for known search bots', async () => { 41 | setUserAgent('Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)') 42 | 43 | init() 44 | await waitForDOMUpdate() 45 | 46 | // Body should contain the injected canary even for bot user agents 47 | expect(document.body.textContent?.length).toBeGreaterThan(0) 48 | expect(document.body.childNodes.length).toBeGreaterThan(0) 49 | }) 50 | 51 | it('skips injection if SSR canary already exists', () => { 52 | // Simulate SSR-injected canary 53 | const ssrCanary = document.createElement('div') 54 | ssrCanary.setAttribute('data-fuzzy-canary', 'true') 55 | const link = document.createElement('a') 56 | link.href = 'https://example.com/ssr-trap' 57 | link.textContent = 'SSR Link' 58 | ssrCanary.appendChild(link) 59 | document.body.appendChild(ssrCanary) 60 | 61 | init() 62 | 63 | // Should not inject another canary element 64 | const canaryElements = Array.from(document.body.childNodes).filter( 65 | node => 66 | node.nodeType === Node.ELEMENT_NODE && 67 | (node as HTMLElement).getAttribute('data-fuzzy-canary') === 'true' 68 | ) 69 | expect(canaryElements.length).toBe(1) // Only the SSR canary should exist 70 | }) 71 | }) 72 | -------------------------------------------------------------------------------- /packages/core/tests/e2e/visibility.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from '@playwright/test' 2 | 3 | test.describe('E2E - best-practice canary placement', () => { 4 | test.beforeEach(async ({ page }) => { 5 | await page.goto('/test-page.html') 6 | await page.waitForTimeout(100) 7 | }) 8 | 9 | test('registers an X-Canary header via hook', async ({ page }) => { 10 | const header = await page.evaluate(() => (window as any).__canaryHeader) 11 | expect(header).toEqual({ name: 'X-Canary', value: 'e2e-canary' }) 12 | }) 13 | 14 | test('adds a scrape-canary meta tag and HTML comment', async ({ page }) => { 15 | const metaContent = await page.getAttribute('meta[name="scrape-canary"]', 'content') 16 | expect(metaContent).toBe('e2e-canary') 17 | 18 | const html = await page.content() 19 | expect(html).toContain('scrape-canary') 20 | expect(html).toMatch(/CANARY/i) 21 | }) 22 | 23 | test('creates an off-screen node visible to scrapers but not users', async ({ page }) => { 24 | const canary = page.locator('[data-scrape-canary]') 25 | await expect(canary).toBeAttached() 26 | await expect(canary).not.toBeVisible() 27 | 28 | const style = await canary.evaluate(el => { 29 | const computed = window.getComputedStyle(el as HTMLElement) 30 | return { 31 | position: computed.position, 32 | left: computed.left, 33 | top: computed.top, 34 | pointerEvents: computed.pointerEvents, 35 | userSelect: computed.userSelect, 36 | ariaHidden: (el as HTMLElement).getAttribute('aria-hidden'), 37 | text: (el as HTMLElement).textContent, 38 | } 39 | }) 40 | 41 | expect(style.position).toBe('absolute') 42 | expect(style.left).toBe('-10000px') 43 | expect(style.top).toBe('0px') 44 | expect(style.pointerEvents).toBe('none') 45 | expect(style.userSelect).toBe('none') 46 | expect(style.ariaHidden).toBe('true') 47 | expect(style.text).toBe('e2e-canary') 48 | 49 | const bodyText = await page.textContent('body') 50 | expect(bodyText).toContain('e2e-canary') 51 | }) 52 | 53 | test('keeps visible content clean of keyword stuffing', async ({ page }) => { 54 | const visibleText = await page.innerText('body') 55 | expect(visibleText).toContain('Visible Content') 56 | expect(visibleText).not.toMatch(/copyright|unauthorized|scraping|prohibited/i) 57 | }) 58 | 59 | test('skips the rendered off-screen node for search bots while keeping header/meta/comment', async ({ 60 | browser, 61 | }) => { 62 | const botContext = await browser.newContext({ 63 | baseURL: 'http://localhost:3000', 64 | userAgent: 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)', 65 | }) 66 | const page = await botContext.newPage() 67 | await page.goto('/test-page.html') 68 | await page.waitForTimeout(100) 69 | 70 | const canary = page.locator('[data-scrape-canary]') 71 | await expect(canary).toHaveCount(0) 72 | 73 | const metaContent = await page.getAttribute('meta[name="scrape-canary"]', 'content') 74 | expect(metaContent).toBe('e2e-canary') 75 | 76 | const html = await page.content() 77 | expect(html).toMatch(/CANARY/i) 78 | 79 | const header = await page.evaluate(() => (window as any).__canaryHeader) 80 | expect(header).toEqual({ name: 'X-Canary', value: 'e2e-canary' }) 81 | 82 | await botContext.close() 83 | }) 84 | }) 85 | 86 | -------------------------------------------------------------------------------- /packages/core/tests/fixtures/runtime.min.js: -------------------------------------------------------------------------------- 1 | (() => { 2 | const sentences = [ 3 | 'Silent foxes guard forgotten libraries at dawn.', 4 | 'Whispered warnings drift through empty data centers.', 5 | 'Obscure footnotes outlast every crawler’s appetite.', 6 | 'Phantom traffic patterns confuse impatient bots.', 7 | 'Hidden breadcrumbs mark the path for curious humans.', 8 | 'Scrapers fear labyrinthine sitemaps at midnight.', 9 | 'Broken mirrors reflect only rate-limited echoes.', 10 | 'Quiet gardens bloom behind expired robots.txt files.', 11 | 'Old captchas dream of puzzles never solved.', 12 | 'Caches remember secrets that headers never told.', 13 | ] 14 | 15 | const pickSentence = () => sentences[Math.floor(Math.random() * sentences.length)] || 'canary' 16 | 17 | const ensureComment = payload => { 18 | const comment = document.createComment(`CANARY:${payload}`) 19 | document.body.appendChild(comment) 20 | } 21 | 22 | const ensureOffscreen = payload => { 23 | let node = document.querySelector('[data-scrape-canary]') 24 | if (!node) { 25 | node = document.createElement('div') 26 | node.setAttribute('data-scrape-canary', '1') 27 | document.body.appendChild(node) 28 | } 29 | node.textContent = payload 30 | node.setAttribute('aria-hidden', 'true') 31 | const style = node.style 32 | style.position = 'absolute' 33 | style.left = '-10000px' 34 | style.top = '0px' 35 | style.width = '1px' 36 | style.height = '1px' 37 | style.overflow = 'hidden' 38 | style.opacity = '0' 39 | style.pointerEvents = 'none' 40 | style.userSelect = 'none' 41 | node.style.setProperty('user-select', 'none') 42 | node.style.setProperty('-webkit-user-select', 'none') 43 | style.visibility = 'hidden' 44 | } 45 | 46 | const ensureInnerTextPolyfill = () => { 47 | if (typeof document === 'undefined') return 48 | const proto = (window.HTMLElement || function () {}).prototype 49 | if (!('innerText' in proto)) { 50 | Object.defineProperty(proto, 'innerText', { 51 | get() { 52 | return this.textContent || '' 53 | }, 54 | set(value) { 55 | this.textContent = value 56 | }, 57 | configurable: true, 58 | }) 59 | } 60 | } 61 | 62 | const ensureUserSelectPolyfill = () => { 63 | if (typeof window === 'undefined' || typeof window.CSSStyleDeclaration === 'undefined') return 64 | const proto = window.CSSStyleDeclaration.prototype 65 | if (Object.getOwnPropertyDescriptor(proto, 'userSelect')) return 66 | Object.defineProperty(proto, 'userSelect', { 67 | get() { 68 | return this.getPropertyValue('user-select') || this.getPropertyValue('-webkit-user-select') || '' 69 | }, 70 | set(value) { 71 | this.setProperty('user-select', value) 72 | this.setProperty('-webkit-user-select', value) 73 | }, 74 | configurable: true, 75 | }) 76 | } 77 | 78 | const init = () => { 79 | if (typeof document === 'undefined') return 80 | const payload = pickSentence() 81 | const run = () => { 82 | ensureInnerTextPolyfill() 83 | ensureUserSelectPolyfill() 84 | ensureComment(payload) 85 | ensureOffscreen(payload) 86 | } 87 | if (document.readyState === 'loading') { 88 | document.addEventListener('DOMContentLoaded', run) 89 | } else { 90 | setTimeout(run, 0) 91 | } 92 | } 93 | 94 | if (typeof window !== 'undefined') { 95 | window.YourPkg = { init } 96 | } 97 | })() 98 | -------------------------------------------------------------------------------- /packages/core/src/index.ts: -------------------------------------------------------------------------------- 1 | const AUTO_INIT_FLAG = Symbol.for('fuzzycanary.domInit') 2 | const AUTO_IMPORT_FLAG = Symbol.for('fuzzycanary.autoImport') 3 | const DISABLE_AUTO_FLAG = Symbol.for('fuzzycanary.disableAuto') 4 | const globalAny = globalThis as any 5 | 6 | export interface CanaryLink { 7 | description: string 8 | url: string 9 | } 10 | 11 | const parseCanaryLinks = (): CanaryLink[] => { 12 | const urlsEnv = process.env.CANARY_TEXT || '' 13 | if (!urlsEnv) return [] 14 | 15 | try { 16 | const parsed = JSON.parse(urlsEnv) 17 | if (Array.isArray(parsed)) { 18 | return parsed 19 | .map((item, index) => { 20 | if (typeof item === 'object' && item.url && item.description) { 21 | return { description: item.description, url: item.url } 22 | } else if (typeof item === 'string' && item.length > 0) { 23 | return { description: `Resource ${index + 1}`, url: item } 24 | } 25 | return null 26 | }) 27 | .filter((link): link is CanaryLink => link !== null) 28 | } 29 | } catch {} 30 | 31 | return [] 32 | } 33 | 34 | const getCanaryLinks = (): CanaryLink[] => { 35 | return parseCanaryLinks() 36 | } 37 | 38 | const hasSSRCanary = (): boolean => { 39 | if (typeof document === 'undefined') return false 40 | 41 | // Check for SSR-injected canary with data attribute 42 | const ssrCanary = document.querySelector('[data-fuzzy-canary]') 43 | return ssrCanary !== null 44 | } 45 | 46 | const injectLinksAtBodyStart = (links: CanaryLink[]): void => { 47 | if (typeof document === 'undefined' || !document.body) return 48 | if (hasSSRCanary()) return 49 | 50 | const firstChild = document.body.firstChild 51 | if (firstChild && firstChild.nodeType === Node.ELEMENT_NODE) { 52 | const element = firstChild as HTMLElement 53 | if (element.getAttribute('data-fuzzy-canary') === 'true') { 54 | return 55 | } 56 | } 57 | 58 | const container = document.createElement('div') 59 | container.setAttribute('data-fuzzy-canary', 'true') 60 | container.style.display = 'none' 61 | container.style.position = 'absolute' 62 | container.style.left = '-9999px' 63 | container.style.visibility = 'hidden' 64 | 65 | links.forEach(({ description, url }) => { 66 | const link = document.createElement('a') 67 | link.href = url 68 | link.textContent = `${description} - ${url}` 69 | link.setAttribute('data-canary-link', 'true') 70 | link.style.display = 'inline-block' 71 | link.style.marginRight = '10px' 72 | container.appendChild(link) 73 | }) 74 | 75 | document.body.insertBefore(container, document.body.firstChild) 76 | } 77 | 78 | export const getCanaryPayload = (): CanaryLink[] => getCanaryLinks() 79 | 80 | export const getCanaryHtml = (): string => { 81 | const links = getCanaryLinks() 82 | if (links.length === 0) return '' 83 | 84 | const linksHtml = links 85 | .map( 86 | ({ description, url }) => 87 | `${description.replace(//g, '>')} - ${url.replace(//g, '>')}` 88 | ) 89 | .join('') 90 | 91 | return `
${linksHtml}
` 92 | } 93 | 94 | export function init(): void { 95 | if (globalAny[AUTO_INIT_FLAG]) return 96 | if (typeof document === 'undefined' || !document.body) return 97 | 98 | const links = getCanaryPayload() 99 | injectLinksAtBodyStart(links) 100 | globalAny[AUTO_INIT_FLAG] = true 101 | } 102 | 103 | const shouldAutoInit = (): boolean => { 104 | if (globalAny[DISABLE_AUTO_FLAG]) return false 105 | if (typeof window === 'undefined' || typeof document === 'undefined') return false 106 | return true 107 | } 108 | 109 | if (shouldAutoInit() && !globalAny[AUTO_IMPORT_FLAG]) { 110 | globalAny[AUTO_IMPORT_FLAG] = true 111 | init() 112 | } 113 | -------------------------------------------------------------------------------- /packages/core/tests/unit/react.test.tsx: -------------------------------------------------------------------------------- 1 | import { describe, it, expect, beforeEach, vi } from 'vitest' 2 | import { render } from '@testing-library/react' 3 | import React from 'react' 4 | import { Canary } from '../../src/react' 5 | 6 | describe('react.tsx - Canary component', () => { 7 | beforeEach(() => { 8 | vi.clearAllMocks() 9 | // Set CANARY_TEXT for tests 10 | process.env.CANARY_TEXT = JSON.stringify([ 11 | { description: 'API Documentation', url: 'https://example.com/api/docs' }, 12 | { description: 'Internal Dashboard', url: 'https://example.com/admin/dashboard' }, 13 | ]) 14 | }) 15 | 16 | describe('Bot handling', () => { 17 | const botUserAgents = [ 18 | 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)', 19 | 'Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)', 20 | 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15 Applebot', 21 | 'DuckDuckBot/1.0; (+http://duckduckgo.com/duckduckbot.html)', 22 | 'facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)', 23 | 'Twitterbot/1.0', 24 | 'LinkedInBot/1.0 (compatible; Mozilla/5.0; +http://www.linkedin.com)', 25 | 'Slackbot-LinkExpanding 1.0 (+https://api.slack.com/robots)', 26 | 'Discordbot/2.0', 27 | 'TelegramBot (like TwitterBot)', 28 | 'Pinterestbot/1.0', 29 | 'Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)', 30 | 'Mozilla/5.0 (compatible; YandexBot/3.0; +http://yandex.com/bots)', 31 | ] 32 | 33 | botUserAgents.forEach(userAgent => { 34 | it(`renders canary for bot UA: ${userAgent.split(' ')[0]}`, () => { 35 | const { container } = render() 36 | 37 | const canary = container.querySelector('[data-fuzzy-canary]') 38 | expect(canary).toBeTruthy() 39 | }) 40 | }) 41 | }) 42 | 43 | describe('Regular users and scrapers', () => { 44 | it('renders canary for regular browser', () => { 45 | const userAgent = 46 | 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36' 47 | const { container } = render() 48 | 49 | const canary = container.querySelector('[data-fuzzy-canary]') 50 | expect(canary).toBeTruthy() 51 | 52 | const links = canary?.querySelectorAll('a[data-canary-link]') 53 | expect(links?.length).toBeGreaterThan(0) 54 | }) 55 | 56 | it('renders canary for unknown scraper', () => { 57 | const userAgent = 'Python-urllib/3.9' 58 | const { container } = render() 59 | 60 | const canary = container.querySelector('[data-fuzzy-canary]') 61 | expect(canary).toBeTruthy() 62 | 63 | const links = canary?.querySelectorAll('a[data-canary-link]') 64 | expect(links?.length).toBeGreaterThan(0) 65 | }) 66 | 67 | it('renders canary when user agent is not provided', () => { 68 | const { container } = render() 69 | 70 | const canary = container.querySelector('[data-fuzzy-canary]') 71 | expect(canary).toBeTruthy() 72 | 73 | const links = canary?.querySelectorAll('a[data-canary-link]') 74 | expect(links?.length).toBeGreaterThan(0) 75 | }) 76 | }) 77 | 78 | describe('Next.js auto-detection', () => { 79 | it('gracefully handles missing Next.js headers (non-Next.js environment)', () => { 80 | // Don't mock next/headers - should gracefully fail 81 | const { container } = render() 82 | 83 | // Should still render canary (no user agent = render canary) 84 | const canary = container.querySelector('[data-fuzzy-canary]') 85 | expect(canary).toBeTruthy() 86 | }) 87 | }) 88 | 89 | describe('Canary rendering', () => { 90 | it('renders canary with correct attributes', () => { 91 | const { container } = render() 92 | 93 | const canary = container.querySelector('[data-fuzzy-canary]') as HTMLElement 94 | expect(canary).toBeTruthy() 95 | expect(canary.getAttribute('data-fuzzy-canary')).toBe('true') 96 | expect(canary.style.display).toBe('none') 97 | expect(canary.style.position).toBe('absolute') 98 | 99 | // Check for links 100 | const links = canary.querySelectorAll('a[data-canary-link]') 101 | expect(links.length).toBeGreaterThan(0) 102 | }) 103 | 104 | it('renders canary links with proper href attributes', () => { 105 | const { container } = render() 106 | 107 | const canary = container.querySelector('[data-fuzzy-canary]') 108 | const links = canary?.querySelectorAll('a[data-canary-link]') as NodeListOf 109 | 110 | expect(links.length).toBeGreaterThan(0) 111 | 112 | // Check first link 113 | const firstLink = links[0] 114 | expect(firstLink.href).toContain('http') 115 | expect(firstLink.textContent).toContain('-') // Should have "description - url" format 116 | expect(firstLink.getAttribute('data-canary-link')).toBe('true') 117 | }) 118 | }) 119 | }) 120 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (which shall not include Communications that are clearly marked or 39 | otherwise designated in writing by the copyright owner as "Not a Work"). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution". 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright 2025 vivienhenz24 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | 204 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: 10 | devDependencies: 11 | '@types/node': 12 | specifier: ^25.0.1 13 | version: 25.0.1 14 | tsup: 15 | specifier: ^8.5.1 16 | version: 8.5.1(postcss@8.5.6)(typescript@5.9.3)(yaml@2.8.2) 17 | typescript: 18 | specifier: ^5.9.3 19 | version: 5.9.3 20 | vitest: 21 | specifier: ^4.0.15 22 | version: 4.0.15(@types/node@25.0.1)(@vitest/ui@4.0.15)(jsdom@25.0.1)(terser@5.44.1)(yaml@2.8.2) 23 | 24 | packages/core: 25 | devDependencies: 26 | '@playwright/test': 27 | specifier: ^1.48.2 28 | version: 1.57.0 29 | '@testing-library/jest-dom': 30 | specifier: ^6.9.1 31 | version: 6.9.1 32 | '@testing-library/react': 33 | specifier: ^16.3.1 34 | version: 16.3.1(@testing-library/dom@10.4.1)(@types/react@18.3.27)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) 35 | '@types/node': 36 | specifier: ^25.0.1 37 | version: 25.0.1 38 | '@types/react': 39 | specifier: ^18.2.0 40 | version: 18.3.27 41 | '@vitest/coverage-v8': 42 | specifier: ^4.0.15 43 | version: 4.0.15(vitest@4.0.15) 44 | '@vitest/ui': 45 | specifier: ^4.0.15 46 | version: 4.0.15(vitest@4.0.15) 47 | jsdom: 48 | specifier: ^25.0.1 49 | version: 25.0.1 50 | react: 51 | specifier: ^19.2.3 52 | version: 19.2.3 53 | react-dom: 54 | specifier: ^19.2.3 55 | version: 19.2.3(react@19.2.3) 56 | tsup: 57 | specifier: ^8.5.1 58 | version: 8.5.1(postcss@8.5.6)(typescript@5.9.3)(yaml@2.8.2) 59 | typescript: 60 | specifier: ^5.9.3 61 | version: 5.9.3 62 | vitest: 63 | specifier: ^4.0.15 64 | version: 4.0.15(@types/node@25.0.1)(@vitest/ui@4.0.15)(jsdom@25.0.1)(terser@5.44.1)(yaml@2.8.2) 65 | 66 | packages: 67 | 68 | '@adobe/css-tools@4.4.4': 69 | resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==} 70 | 71 | '@asamuzakjp/css-color@3.2.0': 72 | resolution: {integrity: sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==} 73 | 74 | '@babel/code-frame@7.27.1': 75 | resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} 76 | engines: {node: '>=6.9.0'} 77 | 78 | '@babel/helper-string-parser@7.27.1': 79 | resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} 80 | engines: {node: '>=6.9.0'} 81 | 82 | '@babel/helper-validator-identifier@7.28.5': 83 | resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} 84 | engines: {node: '>=6.9.0'} 85 | 86 | '@babel/parser@7.28.5': 87 | resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} 88 | engines: {node: '>=6.0.0'} 89 | hasBin: true 90 | 91 | '@babel/runtime@7.28.4': 92 | resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} 93 | engines: {node: '>=6.9.0'} 94 | 95 | '@babel/types@7.28.5': 96 | resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} 97 | engines: {node: '>=6.9.0'} 98 | 99 | '@bcoe/v8-coverage@1.0.2': 100 | resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} 101 | engines: {node: '>=18'} 102 | 103 | '@csstools/color-helpers@5.1.0': 104 | resolution: {integrity: sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==} 105 | engines: {node: '>=18'} 106 | 107 | '@csstools/css-calc@2.1.4': 108 | resolution: {integrity: sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==} 109 | engines: {node: '>=18'} 110 | peerDependencies: 111 | '@csstools/css-parser-algorithms': ^3.0.5 112 | '@csstools/css-tokenizer': ^3.0.4 113 | 114 | '@csstools/css-color-parser@3.1.0': 115 | resolution: {integrity: sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==} 116 | engines: {node: '>=18'} 117 | peerDependencies: 118 | '@csstools/css-parser-algorithms': ^3.0.5 119 | '@csstools/css-tokenizer': ^3.0.4 120 | 121 | '@csstools/css-parser-algorithms@3.0.5': 122 | resolution: {integrity: sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==} 123 | engines: {node: '>=18'} 124 | peerDependencies: 125 | '@csstools/css-tokenizer': ^3.0.4 126 | 127 | '@csstools/css-tokenizer@3.0.4': 128 | resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} 129 | engines: {node: '>=18'} 130 | 131 | '@esbuild/aix-ppc64@0.25.12': 132 | resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} 133 | engines: {node: '>=18'} 134 | cpu: [ppc64] 135 | os: [aix] 136 | 137 | '@esbuild/aix-ppc64@0.27.1': 138 | resolution: {integrity: sha512-HHB50pdsBX6k47S4u5g/CaLjqS3qwaOVE5ILsq64jyzgMhLuCuZ8rGzM9yhsAjfjkbgUPMzZEPa7DAp7yz6vuA==} 139 | engines: {node: '>=18'} 140 | cpu: [ppc64] 141 | os: [aix] 142 | 143 | '@esbuild/android-arm64@0.25.12': 144 | resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} 145 | engines: {node: '>=18'} 146 | cpu: [arm64] 147 | os: [android] 148 | 149 | '@esbuild/android-arm64@0.27.1': 150 | resolution: {integrity: sha512-45fuKmAJpxnQWixOGCrS+ro4Uvb4Re9+UTieUY2f8AEc+t7d4AaZ6eUJ3Hva7dtrxAAWHtlEFsXFMAgNnGU9uQ==} 151 | engines: {node: '>=18'} 152 | cpu: [arm64] 153 | os: [android] 154 | 155 | '@esbuild/android-arm@0.25.12': 156 | resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} 157 | engines: {node: '>=18'} 158 | cpu: [arm] 159 | os: [android] 160 | 161 | '@esbuild/android-arm@0.27.1': 162 | resolution: {integrity: sha512-kFqa6/UcaTbGm/NncN9kzVOODjhZW8e+FRdSeypWe6j33gzclHtwlANs26JrupOntlcWmB0u8+8HZo8s7thHvg==} 163 | engines: {node: '>=18'} 164 | cpu: [arm] 165 | os: [android] 166 | 167 | '@esbuild/android-x64@0.25.12': 168 | resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} 169 | engines: {node: '>=18'} 170 | cpu: [x64] 171 | os: [android] 172 | 173 | '@esbuild/android-x64@0.27.1': 174 | resolution: {integrity: sha512-LBEpOz0BsgMEeHgenf5aqmn/lLNTFXVfoWMUox8CtWWYK9X4jmQzWjoGoNb8lmAYml/tQ/Ysvm8q7szu7BoxRQ==} 175 | engines: {node: '>=18'} 176 | cpu: [x64] 177 | os: [android] 178 | 179 | '@esbuild/darwin-arm64@0.25.12': 180 | resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} 181 | engines: {node: '>=18'} 182 | cpu: [arm64] 183 | os: [darwin] 184 | 185 | '@esbuild/darwin-arm64@0.27.1': 186 | resolution: {integrity: sha512-veg7fL8eMSCVKL7IW4pxb54QERtedFDfY/ASrumK/SbFsXnRazxY4YykN/THYqFnFwJ0aVjiUrVG2PwcdAEqQQ==} 187 | engines: {node: '>=18'} 188 | cpu: [arm64] 189 | os: [darwin] 190 | 191 | '@esbuild/darwin-x64@0.25.12': 192 | resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} 193 | engines: {node: '>=18'} 194 | cpu: [x64] 195 | os: [darwin] 196 | 197 | '@esbuild/darwin-x64@0.27.1': 198 | resolution: {integrity: sha512-+3ELd+nTzhfWb07Vol7EZ+5PTbJ/u74nC6iv4/lwIU99Ip5uuY6QoIf0Hn4m2HoV0qcnRivN3KSqc+FyCHjoVQ==} 199 | engines: {node: '>=18'} 200 | cpu: [x64] 201 | os: [darwin] 202 | 203 | '@esbuild/freebsd-arm64@0.25.12': 204 | resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} 205 | engines: {node: '>=18'} 206 | cpu: [arm64] 207 | os: [freebsd] 208 | 209 | '@esbuild/freebsd-arm64@0.27.1': 210 | resolution: {integrity: sha512-/8Rfgns4XD9XOSXlzUDepG8PX+AVWHliYlUkFI3K3GB6tqbdjYqdhcb4BKRd7C0BhZSoaCxhv8kTcBrcZWP+xg==} 211 | engines: {node: '>=18'} 212 | cpu: [arm64] 213 | os: [freebsd] 214 | 215 | '@esbuild/freebsd-x64@0.25.12': 216 | resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} 217 | engines: {node: '>=18'} 218 | cpu: [x64] 219 | os: [freebsd] 220 | 221 | '@esbuild/freebsd-x64@0.27.1': 222 | resolution: {integrity: sha512-GITpD8dK9C+r+5yRT/UKVT36h/DQLOHdwGVwwoHidlnA168oD3uxA878XloXebK4Ul3gDBBIvEdL7go9gCUFzQ==} 223 | engines: {node: '>=18'} 224 | cpu: [x64] 225 | os: [freebsd] 226 | 227 | '@esbuild/linux-arm64@0.25.12': 228 | resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} 229 | engines: {node: '>=18'} 230 | cpu: [arm64] 231 | os: [linux] 232 | 233 | '@esbuild/linux-arm64@0.27.1': 234 | resolution: {integrity: sha512-W9//kCrh/6in9rWIBdKaMtuTTzNj6jSeG/haWBADqLLa9P8O5YSRDzgD5y9QBok4AYlzS6ARHifAb75V6G670Q==} 235 | engines: {node: '>=18'} 236 | cpu: [arm64] 237 | os: [linux] 238 | 239 | '@esbuild/linux-arm@0.25.12': 240 | resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} 241 | engines: {node: '>=18'} 242 | cpu: [arm] 243 | os: [linux] 244 | 245 | '@esbuild/linux-arm@0.27.1': 246 | resolution: {integrity: sha512-ieMID0JRZY/ZeCrsFQ3Y3NlHNCqIhTprJfDgSB3/lv5jJZ8FX3hqPyXWhe+gvS5ARMBJ242PM+VNz/ctNj//eA==} 247 | engines: {node: '>=18'} 248 | cpu: [arm] 249 | os: [linux] 250 | 251 | '@esbuild/linux-ia32@0.25.12': 252 | resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} 253 | engines: {node: '>=18'} 254 | cpu: [ia32] 255 | os: [linux] 256 | 257 | '@esbuild/linux-ia32@0.27.1': 258 | resolution: {integrity: sha512-VIUV4z8GD8rtSVMfAj1aXFahsi/+tcoXXNYmXgzISL+KB381vbSTNdeZHHHIYqFyXcoEhu9n5cT+05tRv13rlw==} 259 | engines: {node: '>=18'} 260 | cpu: [ia32] 261 | os: [linux] 262 | 263 | '@esbuild/linux-loong64@0.25.12': 264 | resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} 265 | engines: {node: '>=18'} 266 | cpu: [loong64] 267 | os: [linux] 268 | 269 | '@esbuild/linux-loong64@0.27.1': 270 | resolution: {integrity: sha512-l4rfiiJRN7sTNI//ff65zJ9z8U+k6zcCg0LALU5iEWzY+a1mVZ8iWC1k5EsNKThZ7XCQ6YWtsZ8EWYm7r1UEsg==} 271 | engines: {node: '>=18'} 272 | cpu: [loong64] 273 | os: [linux] 274 | 275 | '@esbuild/linux-mips64el@0.25.12': 276 | resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} 277 | engines: {node: '>=18'} 278 | cpu: [mips64el] 279 | os: [linux] 280 | 281 | '@esbuild/linux-mips64el@0.27.1': 282 | resolution: {integrity: sha512-U0bEuAOLvO/DWFdygTHWY8C067FXz+UbzKgxYhXC0fDieFa0kDIra1FAhsAARRJbvEyso8aAqvPdNxzWuStBnA==} 283 | engines: {node: '>=18'} 284 | cpu: [mips64el] 285 | os: [linux] 286 | 287 | '@esbuild/linux-ppc64@0.25.12': 288 | resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} 289 | engines: {node: '>=18'} 290 | cpu: [ppc64] 291 | os: [linux] 292 | 293 | '@esbuild/linux-ppc64@0.27.1': 294 | resolution: {integrity: sha512-NzdQ/Xwu6vPSf/GkdmRNsOfIeSGnh7muundsWItmBsVpMoNPVpM61qNzAVY3pZ1glzzAxLR40UyYM23eaDDbYQ==} 295 | engines: {node: '>=18'} 296 | cpu: [ppc64] 297 | os: [linux] 298 | 299 | '@esbuild/linux-riscv64@0.25.12': 300 | resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} 301 | engines: {node: '>=18'} 302 | cpu: [riscv64] 303 | os: [linux] 304 | 305 | '@esbuild/linux-riscv64@0.27.1': 306 | resolution: {integrity: sha512-7zlw8p3IApcsN7mFw0O1Z1PyEk6PlKMu18roImfl3iQHTnr/yAfYv6s4hXPidbDoI2Q0pW+5xeoM4eTCC0UdrQ==} 307 | engines: {node: '>=18'} 308 | cpu: [riscv64] 309 | os: [linux] 310 | 311 | '@esbuild/linux-s390x@0.25.12': 312 | resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} 313 | engines: {node: '>=18'} 314 | cpu: [s390x] 315 | os: [linux] 316 | 317 | '@esbuild/linux-s390x@0.27.1': 318 | resolution: {integrity: sha512-cGj5wli+G+nkVQdZo3+7FDKC25Uh4ZVwOAK6A06Hsvgr8WqBBuOy/1s+PUEd/6Je+vjfm6stX0kmib5b/O2Ykw==} 319 | engines: {node: '>=18'} 320 | cpu: [s390x] 321 | os: [linux] 322 | 323 | '@esbuild/linux-x64@0.25.12': 324 | resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} 325 | engines: {node: '>=18'} 326 | cpu: [x64] 327 | os: [linux] 328 | 329 | '@esbuild/linux-x64@0.27.1': 330 | resolution: {integrity: sha512-z3H/HYI9MM0HTv3hQZ81f+AKb+yEoCRlUby1F80vbQ5XdzEMyY/9iNlAmhqiBKw4MJXwfgsh7ERGEOhrM1niMA==} 331 | engines: {node: '>=18'} 332 | cpu: [x64] 333 | os: [linux] 334 | 335 | '@esbuild/netbsd-arm64@0.25.12': 336 | resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} 337 | engines: {node: '>=18'} 338 | cpu: [arm64] 339 | os: [netbsd] 340 | 341 | '@esbuild/netbsd-arm64@0.27.1': 342 | resolution: {integrity: sha512-wzC24DxAvk8Em01YmVXyjl96Mr+ecTPyOuADAvjGg+fyBpGmxmcr2E5ttf7Im8D0sXZihpxzO1isus8MdjMCXQ==} 343 | engines: {node: '>=18'} 344 | cpu: [arm64] 345 | os: [netbsd] 346 | 347 | '@esbuild/netbsd-x64@0.25.12': 348 | resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} 349 | engines: {node: '>=18'} 350 | cpu: [x64] 351 | os: [netbsd] 352 | 353 | '@esbuild/netbsd-x64@0.27.1': 354 | resolution: {integrity: sha512-1YQ8ybGi2yIXswu6eNzJsrYIGFpnlzEWRl6iR5gMgmsrR0FcNoV1m9k9sc3PuP5rUBLshOZylc9nqSgymI+TYg==} 355 | engines: {node: '>=18'} 356 | cpu: [x64] 357 | os: [netbsd] 358 | 359 | '@esbuild/openbsd-arm64@0.25.12': 360 | resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} 361 | engines: {node: '>=18'} 362 | cpu: [arm64] 363 | os: [openbsd] 364 | 365 | '@esbuild/openbsd-arm64@0.27.1': 366 | resolution: {integrity: sha512-5Z+DzLCrq5wmU7RDaMDe2DVXMRm2tTDvX2KU14JJVBN2CT/qov7XVix85QoJqHltpvAOZUAc3ndU56HSMWrv8g==} 367 | engines: {node: '>=18'} 368 | cpu: [arm64] 369 | os: [openbsd] 370 | 371 | '@esbuild/openbsd-x64@0.25.12': 372 | resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} 373 | engines: {node: '>=18'} 374 | cpu: [x64] 375 | os: [openbsd] 376 | 377 | '@esbuild/openbsd-x64@0.27.1': 378 | resolution: {integrity: sha512-Q73ENzIdPF5jap4wqLtsfh8YbYSZ8Q0wnxplOlZUOyZy7B4ZKW8DXGWgTCZmF8VWD7Tciwv5F4NsRf6vYlZtqg==} 379 | engines: {node: '>=18'} 380 | cpu: [x64] 381 | os: [openbsd] 382 | 383 | '@esbuild/openharmony-arm64@0.25.12': 384 | resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} 385 | engines: {node: '>=18'} 386 | cpu: [arm64] 387 | os: [openharmony] 388 | 389 | '@esbuild/openharmony-arm64@0.27.1': 390 | resolution: {integrity: sha512-ajbHrGM/XiK+sXM0JzEbJAen+0E+JMQZ2l4RR4VFwvV9JEERx+oxtgkpoKv1SevhjavK2z2ReHk32pjzktWbGg==} 391 | engines: {node: '>=18'} 392 | cpu: [arm64] 393 | os: [openharmony] 394 | 395 | '@esbuild/sunos-x64@0.25.12': 396 | resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} 397 | engines: {node: '>=18'} 398 | cpu: [x64] 399 | os: [sunos] 400 | 401 | '@esbuild/sunos-x64@0.27.1': 402 | resolution: {integrity: sha512-IPUW+y4VIjuDVn+OMzHc5FV4GubIwPnsz6ubkvN8cuhEqH81NovB53IUlrlBkPMEPxvNnf79MGBoz8rZ2iW8HA==} 403 | engines: {node: '>=18'} 404 | cpu: [x64] 405 | os: [sunos] 406 | 407 | '@esbuild/win32-arm64@0.25.12': 408 | resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} 409 | engines: {node: '>=18'} 410 | cpu: [arm64] 411 | os: [win32] 412 | 413 | '@esbuild/win32-arm64@0.27.1': 414 | resolution: {integrity: sha512-RIVRWiljWA6CdVu8zkWcRmGP7iRRIIwvhDKem8UMBjPql2TXM5PkDVvvrzMtj1V+WFPB4K7zkIGM7VzRtFkjdg==} 415 | engines: {node: '>=18'} 416 | cpu: [arm64] 417 | os: [win32] 418 | 419 | '@esbuild/win32-ia32@0.25.12': 420 | resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} 421 | engines: {node: '>=18'} 422 | cpu: [ia32] 423 | os: [win32] 424 | 425 | '@esbuild/win32-ia32@0.27.1': 426 | resolution: {integrity: sha512-2BR5M8CPbptC1AK5JbJT1fWrHLvejwZidKx3UMSF0ecHMa+smhi16drIrCEggkgviBwLYd5nwrFLSl5Kho96RQ==} 427 | engines: {node: '>=18'} 428 | cpu: [ia32] 429 | os: [win32] 430 | 431 | '@esbuild/win32-x64@0.25.12': 432 | resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} 433 | engines: {node: '>=18'} 434 | cpu: [x64] 435 | os: [win32] 436 | 437 | '@esbuild/win32-x64@0.27.1': 438 | resolution: {integrity: sha512-d5X6RMYv6taIymSk8JBP+nxv8DQAMY6A51GPgusqLdK9wBz5wWIXy1KjTck6HnjE9hqJzJRdk+1p/t5soSbCtw==} 439 | engines: {node: '>=18'} 440 | cpu: [x64] 441 | os: [win32] 442 | 443 | '@jridgewell/gen-mapping@0.3.13': 444 | resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} 445 | 446 | '@jridgewell/resolve-uri@3.1.2': 447 | resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} 448 | engines: {node: '>=6.0.0'} 449 | 450 | '@jridgewell/source-map@0.3.11': 451 | resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} 452 | 453 | '@jridgewell/sourcemap-codec@1.5.5': 454 | resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} 455 | 456 | '@jridgewell/trace-mapping@0.3.31': 457 | resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} 458 | 459 | '@playwright/test@1.57.0': 460 | resolution: {integrity: sha512-6TyEnHgd6SArQO8UO2OMTxshln3QMWBtPGrOCgs3wVEmQmwyuNtB10IZMfmYDE0riwNR1cu4q+pPcxMVtaG3TA==} 461 | engines: {node: '>=18'} 462 | hasBin: true 463 | 464 | '@polka/url@1.0.0-next.29': 465 | resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} 466 | 467 | '@rollup/rollup-android-arm-eabi@4.53.3': 468 | resolution: {integrity: sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==} 469 | cpu: [arm] 470 | os: [android] 471 | 472 | '@rollup/rollup-android-arm64@4.53.3': 473 | resolution: {integrity: sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==} 474 | cpu: [arm64] 475 | os: [android] 476 | 477 | '@rollup/rollup-darwin-arm64@4.53.3': 478 | resolution: {integrity: sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==} 479 | cpu: [arm64] 480 | os: [darwin] 481 | 482 | '@rollup/rollup-darwin-x64@4.53.3': 483 | resolution: {integrity: sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==} 484 | cpu: [x64] 485 | os: [darwin] 486 | 487 | '@rollup/rollup-freebsd-arm64@4.53.3': 488 | resolution: {integrity: sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==} 489 | cpu: [arm64] 490 | os: [freebsd] 491 | 492 | '@rollup/rollup-freebsd-x64@4.53.3': 493 | resolution: {integrity: sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==} 494 | cpu: [x64] 495 | os: [freebsd] 496 | 497 | '@rollup/rollup-linux-arm-gnueabihf@4.53.3': 498 | resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==} 499 | cpu: [arm] 500 | os: [linux] 501 | 502 | '@rollup/rollup-linux-arm-musleabihf@4.53.3': 503 | resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==} 504 | cpu: [arm] 505 | os: [linux] 506 | 507 | '@rollup/rollup-linux-arm64-gnu@4.53.3': 508 | resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==} 509 | cpu: [arm64] 510 | os: [linux] 511 | 512 | '@rollup/rollup-linux-arm64-musl@4.53.3': 513 | resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==} 514 | cpu: [arm64] 515 | os: [linux] 516 | 517 | '@rollup/rollup-linux-loong64-gnu@4.53.3': 518 | resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==} 519 | cpu: [loong64] 520 | os: [linux] 521 | 522 | '@rollup/rollup-linux-ppc64-gnu@4.53.3': 523 | resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==} 524 | cpu: [ppc64] 525 | os: [linux] 526 | 527 | '@rollup/rollup-linux-riscv64-gnu@4.53.3': 528 | resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==} 529 | cpu: [riscv64] 530 | os: [linux] 531 | 532 | '@rollup/rollup-linux-riscv64-musl@4.53.3': 533 | resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==} 534 | cpu: [riscv64] 535 | os: [linux] 536 | 537 | '@rollup/rollup-linux-s390x-gnu@4.53.3': 538 | resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==} 539 | cpu: [s390x] 540 | os: [linux] 541 | 542 | '@rollup/rollup-linux-x64-gnu@4.53.3': 543 | resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==} 544 | cpu: [x64] 545 | os: [linux] 546 | 547 | '@rollup/rollup-linux-x64-musl@4.53.3': 548 | resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==} 549 | cpu: [x64] 550 | os: [linux] 551 | 552 | '@rollup/rollup-openharmony-arm64@4.53.3': 553 | resolution: {integrity: sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==} 554 | cpu: [arm64] 555 | os: [openharmony] 556 | 557 | '@rollup/rollup-win32-arm64-msvc@4.53.3': 558 | resolution: {integrity: sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==} 559 | cpu: [arm64] 560 | os: [win32] 561 | 562 | '@rollup/rollup-win32-ia32-msvc@4.53.3': 563 | resolution: {integrity: sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==} 564 | cpu: [ia32] 565 | os: [win32] 566 | 567 | '@rollup/rollup-win32-x64-gnu@4.53.3': 568 | resolution: {integrity: sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==} 569 | cpu: [x64] 570 | os: [win32] 571 | 572 | '@rollup/rollup-win32-x64-msvc@4.53.3': 573 | resolution: {integrity: sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==} 574 | cpu: [x64] 575 | os: [win32] 576 | 577 | '@standard-schema/spec@1.0.0': 578 | resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} 579 | 580 | '@testing-library/dom@10.4.1': 581 | resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} 582 | engines: {node: '>=18'} 583 | 584 | '@testing-library/jest-dom@6.9.1': 585 | resolution: {integrity: sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==} 586 | engines: {node: '>=14', npm: '>=6', yarn: '>=1'} 587 | 588 | '@testing-library/react@16.3.1': 589 | resolution: {integrity: sha512-gr4KtAWqIOQoucWYD/f6ki+j5chXfcPc74Col/6poTyqTmn7zRmodWahWRCp8tYd+GMqBonw6hstNzqjbs6gjw==} 590 | engines: {node: '>=18'} 591 | peerDependencies: 592 | '@testing-library/dom': ^10.0.0 593 | '@types/react': ^18.0.0 || ^19.0.0 594 | '@types/react-dom': ^18.0.0 || ^19.0.0 595 | react: ^18.0.0 || ^19.0.0 596 | react-dom: ^18.0.0 || ^19.0.0 597 | peerDependenciesMeta: 598 | '@types/react': 599 | optional: true 600 | '@types/react-dom': 601 | optional: true 602 | 603 | '@types/aria-query@5.0.4': 604 | resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} 605 | 606 | '@types/chai@5.2.3': 607 | resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} 608 | 609 | '@types/deep-eql@4.0.2': 610 | resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} 611 | 612 | '@types/estree@1.0.8': 613 | resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} 614 | 615 | '@types/node@25.0.1': 616 | resolution: {integrity: sha512-czWPzKIAXucn9PtsttxmumiQ9N0ok9FrBwgRWrwmVLlp86BrMExzvXRLFYRJ+Ex3g6yqj+KuaxfX1JTgV2lpfg==} 617 | 618 | '@types/prop-types@15.7.15': 619 | resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==} 620 | 621 | '@types/react@18.3.27': 622 | resolution: {integrity: sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==} 623 | 624 | '@vitest/coverage-v8@4.0.15': 625 | resolution: {integrity: sha512-FUJ+1RkpTFW7rQITdgTi93qOCWJobWhBirEPCeXh2SW2wsTlFxy51apDz5gzG+ZEYt/THvWeNmhdAoS9DTwpCw==} 626 | peerDependencies: 627 | '@vitest/browser': 4.0.15 628 | vitest: 4.0.15 629 | peerDependenciesMeta: 630 | '@vitest/browser': 631 | optional: true 632 | 633 | '@vitest/expect@4.0.15': 634 | resolution: {integrity: sha512-Gfyva9/GxPAWXIWjyGDli9O+waHDC0Q0jaLdFP1qPAUUfo1FEXPXUfUkp3eZA0sSq340vPycSyOlYUeM15Ft1w==} 635 | 636 | '@vitest/mocker@4.0.15': 637 | resolution: {integrity: sha512-CZ28GLfOEIFkvCFngN8Sfx5h+Se0zN+h4B7yOsPVCcgtiO7t5jt9xQh2E1UkFep+eb9fjyMfuC5gBypwb07fvQ==} 638 | peerDependencies: 639 | msw: ^2.4.9 640 | vite: ^6.0.0 || ^7.0.0-0 641 | peerDependenciesMeta: 642 | msw: 643 | optional: true 644 | vite: 645 | optional: true 646 | 647 | '@vitest/pretty-format@4.0.15': 648 | resolution: {integrity: sha512-SWdqR8vEv83WtZcrfLNqlqeQXlQLh2iilO1Wk1gv4eiHKjEzvgHb2OVc3mIPyhZE6F+CtfYjNlDJwP5MN6Km7A==} 649 | 650 | '@vitest/runner@4.0.15': 651 | resolution: {integrity: sha512-+A+yMY8dGixUhHmNdPUxOh0la6uVzun86vAbuMT3hIDxMrAOmn5ILBHm8ajrqHE0t8R9T1dGnde1A5DTnmi3qw==} 652 | 653 | '@vitest/snapshot@4.0.15': 654 | resolution: {integrity: sha512-A7Ob8EdFZJIBjLjeO0DZF4lqR6U7Ydi5/5LIZ0xcI+23lYlsYJAfGn8PrIWTYdZQRNnSRlzhg0zyGu37mVdy5g==} 655 | 656 | '@vitest/spy@4.0.15': 657 | resolution: {integrity: sha512-+EIjOJmnY6mIfdXtE/bnozKEvTC4Uczg19yeZ2vtCz5Yyb0QQ31QWVQ8hswJ3Ysx/K2EqaNsVanjr//2+P3FHw==} 658 | 659 | '@vitest/ui@4.0.15': 660 | resolution: {integrity: sha512-sxSyJMaKp45zI0u+lHrPuZM1ZJQ8FaVD35k+UxVrha1yyvQ+TZuUYllUixwvQXlB7ixoDc7skf3lQPopZIvaQw==} 661 | peerDependencies: 662 | vitest: 4.0.15 663 | 664 | '@vitest/utils@4.0.15': 665 | resolution: {integrity: sha512-HXjPW2w5dxhTD0dLwtYHDnelK3j8sR8cWIaLxr22evTyY6q8pRCjZSmhRWVjBaOVXChQd6AwMzi9pucorXCPZA==} 666 | 667 | acorn@8.15.0: 668 | resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} 669 | engines: {node: '>=0.4.0'} 670 | hasBin: true 671 | 672 | agent-base@7.1.4: 673 | resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} 674 | engines: {node: '>= 14'} 675 | 676 | ansi-regex@5.0.1: 677 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} 678 | engines: {node: '>=8'} 679 | 680 | ansi-styles@5.2.0: 681 | resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} 682 | engines: {node: '>=10'} 683 | 684 | any-promise@1.3.0: 685 | resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} 686 | 687 | aria-query@5.3.0: 688 | resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} 689 | 690 | aria-query@5.3.2: 691 | resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} 692 | engines: {node: '>= 0.4'} 693 | 694 | assertion-error@2.0.1: 695 | resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} 696 | engines: {node: '>=12'} 697 | 698 | ast-v8-to-istanbul@0.3.8: 699 | resolution: {integrity: sha512-szgSZqUxI5T8mLKvS7WTjF9is+MVbOeLADU73IseOcrqhxr/VAvy6wfoVE39KnKzA7JRhjF5eUagNlHwvZPlKQ==} 700 | 701 | asynckit@0.4.0: 702 | resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} 703 | 704 | buffer-from@1.1.2: 705 | resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} 706 | 707 | bundle-require@5.1.0: 708 | resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} 709 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 710 | peerDependencies: 711 | esbuild: '>=0.18' 712 | 713 | cac@6.7.14: 714 | resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} 715 | engines: {node: '>=8'} 716 | 717 | call-bind-apply-helpers@1.0.2: 718 | resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} 719 | engines: {node: '>= 0.4'} 720 | 721 | chai@6.2.1: 722 | resolution: {integrity: sha512-p4Z49OGG5W/WBCPSS/dH3jQ73kD6tiMmUM+bckNK6Jr5JHMG3k9bg/BvKR8lKmtVBKmOiuVaV2ws8s9oSbwysg==} 723 | engines: {node: '>=18'} 724 | 725 | chokidar@4.0.3: 726 | resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} 727 | engines: {node: '>= 14.16.0'} 728 | 729 | combined-stream@1.0.8: 730 | resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} 731 | engines: {node: '>= 0.8'} 732 | 733 | commander@2.20.3: 734 | resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} 735 | 736 | commander@4.1.1: 737 | resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} 738 | engines: {node: '>= 6'} 739 | 740 | confbox@0.1.8: 741 | resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} 742 | 743 | consola@3.4.2: 744 | resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} 745 | engines: {node: ^14.18.0 || >=16.10.0} 746 | 747 | css.escape@1.5.1: 748 | resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} 749 | 750 | cssstyle@4.6.0: 751 | resolution: {integrity: sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==} 752 | engines: {node: '>=18'} 753 | 754 | csstype@3.2.3: 755 | resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} 756 | 757 | data-urls@5.0.0: 758 | resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} 759 | engines: {node: '>=18'} 760 | 761 | debug@4.4.3: 762 | resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} 763 | engines: {node: '>=6.0'} 764 | peerDependencies: 765 | supports-color: '*' 766 | peerDependenciesMeta: 767 | supports-color: 768 | optional: true 769 | 770 | decimal.js@10.6.0: 771 | resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} 772 | 773 | delayed-stream@1.0.0: 774 | resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} 775 | engines: {node: '>=0.4.0'} 776 | 777 | dequal@2.0.3: 778 | resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} 779 | engines: {node: '>=6'} 780 | 781 | dom-accessibility-api@0.5.16: 782 | resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} 783 | 784 | dom-accessibility-api@0.6.3: 785 | resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==} 786 | 787 | dunder-proto@1.0.1: 788 | resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} 789 | engines: {node: '>= 0.4'} 790 | 791 | entities@6.0.1: 792 | resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} 793 | engines: {node: '>=0.12'} 794 | 795 | es-define-property@1.0.1: 796 | resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} 797 | engines: {node: '>= 0.4'} 798 | 799 | es-errors@1.3.0: 800 | resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} 801 | engines: {node: '>= 0.4'} 802 | 803 | es-module-lexer@1.7.0: 804 | resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} 805 | 806 | es-object-atoms@1.1.1: 807 | resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} 808 | engines: {node: '>= 0.4'} 809 | 810 | es-set-tostringtag@2.1.0: 811 | resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} 812 | engines: {node: '>= 0.4'} 813 | 814 | esbuild@0.25.12: 815 | resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} 816 | engines: {node: '>=18'} 817 | hasBin: true 818 | 819 | esbuild@0.27.1: 820 | resolution: {integrity: sha512-yY35KZckJJuVVPXpvjgxiCuVEJT67F6zDeVTv4rizyPrfGBUpZQsvmxnN+C371c2esD/hNMjj4tpBhuueLN7aA==} 821 | engines: {node: '>=18'} 822 | hasBin: true 823 | 824 | estree-walker@3.0.3: 825 | resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} 826 | 827 | expect-type@1.3.0: 828 | resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} 829 | engines: {node: '>=12.0.0'} 830 | 831 | fdir@6.5.0: 832 | resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} 833 | engines: {node: '>=12.0.0'} 834 | peerDependencies: 835 | picomatch: ^3 || ^4 836 | peerDependenciesMeta: 837 | picomatch: 838 | optional: true 839 | 840 | fflate@0.8.2: 841 | resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} 842 | 843 | fix-dts-default-cjs-exports@1.0.1: 844 | resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==} 845 | 846 | flatted@3.3.3: 847 | resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} 848 | 849 | form-data@4.0.5: 850 | resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} 851 | engines: {node: '>= 6'} 852 | 853 | fsevents@2.3.2: 854 | resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} 855 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 856 | os: [darwin] 857 | 858 | fsevents@2.3.3: 859 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 860 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 861 | os: [darwin] 862 | 863 | function-bind@1.1.2: 864 | resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} 865 | 866 | get-intrinsic@1.3.0: 867 | resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} 868 | engines: {node: '>= 0.4'} 869 | 870 | get-proto@1.0.1: 871 | resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} 872 | engines: {node: '>= 0.4'} 873 | 874 | gopd@1.2.0: 875 | resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} 876 | engines: {node: '>= 0.4'} 877 | 878 | has-flag@4.0.0: 879 | resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} 880 | engines: {node: '>=8'} 881 | 882 | has-symbols@1.1.0: 883 | resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} 884 | engines: {node: '>= 0.4'} 885 | 886 | has-tostringtag@1.0.2: 887 | resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} 888 | engines: {node: '>= 0.4'} 889 | 890 | hasown@2.0.2: 891 | resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} 892 | engines: {node: '>= 0.4'} 893 | 894 | html-encoding-sniffer@4.0.0: 895 | resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} 896 | engines: {node: '>=18'} 897 | 898 | html-escaper@2.0.2: 899 | resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} 900 | 901 | http-proxy-agent@7.0.2: 902 | resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} 903 | engines: {node: '>= 14'} 904 | 905 | https-proxy-agent@7.0.6: 906 | resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} 907 | engines: {node: '>= 14'} 908 | 909 | iconv-lite@0.6.3: 910 | resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} 911 | engines: {node: '>=0.10.0'} 912 | 913 | indent-string@4.0.0: 914 | resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} 915 | engines: {node: '>=8'} 916 | 917 | is-potential-custom-element-name@1.0.1: 918 | resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} 919 | 920 | istanbul-lib-coverage@3.2.2: 921 | resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} 922 | engines: {node: '>=8'} 923 | 924 | istanbul-lib-report@3.0.1: 925 | resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} 926 | engines: {node: '>=10'} 927 | 928 | istanbul-lib-source-maps@5.0.6: 929 | resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} 930 | engines: {node: '>=10'} 931 | 932 | istanbul-reports@3.2.0: 933 | resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} 934 | engines: {node: '>=8'} 935 | 936 | joycon@3.1.1: 937 | resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} 938 | engines: {node: '>=10'} 939 | 940 | js-tokens@4.0.0: 941 | resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} 942 | 943 | js-tokens@9.0.1: 944 | resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} 945 | 946 | jsdom@25.0.1: 947 | resolution: {integrity: sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==} 948 | engines: {node: '>=18'} 949 | peerDependencies: 950 | canvas: ^2.11.2 951 | peerDependenciesMeta: 952 | canvas: 953 | optional: true 954 | 955 | lilconfig@3.1.3: 956 | resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} 957 | engines: {node: '>=14'} 958 | 959 | lines-and-columns@1.2.4: 960 | resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} 961 | 962 | load-tsconfig@0.2.5: 963 | resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} 964 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 965 | 966 | lru-cache@10.4.3: 967 | resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} 968 | 969 | lz-string@1.5.0: 970 | resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} 971 | hasBin: true 972 | 973 | magic-string@0.30.21: 974 | resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} 975 | 976 | magicast@0.5.1: 977 | resolution: {integrity: sha512-xrHS24IxaLrvuo613F719wvOIv9xPHFWQHuvGUBmPnCA/3MQxKI3b+r7n1jAoDHmsbC5bRhTZYR77invLAxVnw==} 978 | 979 | make-dir@4.0.0: 980 | resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} 981 | engines: {node: '>=10'} 982 | 983 | math-intrinsics@1.1.0: 984 | resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} 985 | engines: {node: '>= 0.4'} 986 | 987 | mime-db@1.52.0: 988 | resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} 989 | engines: {node: '>= 0.6'} 990 | 991 | mime-types@2.1.35: 992 | resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} 993 | engines: {node: '>= 0.6'} 994 | 995 | min-indent@1.0.1: 996 | resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} 997 | engines: {node: '>=4'} 998 | 999 | mlly@1.8.0: 1000 | resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} 1001 | 1002 | mrmime@2.0.1: 1003 | resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} 1004 | engines: {node: '>=10'} 1005 | 1006 | ms@2.1.3: 1007 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} 1008 | 1009 | mz@2.7.0: 1010 | resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} 1011 | 1012 | nanoid@3.3.11: 1013 | resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} 1014 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 1015 | hasBin: true 1016 | 1017 | nwsapi@2.2.23: 1018 | resolution: {integrity: sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==} 1019 | 1020 | object-assign@4.1.1: 1021 | resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} 1022 | engines: {node: '>=0.10.0'} 1023 | 1024 | obug@2.1.1: 1025 | resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} 1026 | 1027 | parse5@7.3.0: 1028 | resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} 1029 | 1030 | pathe@2.0.3: 1031 | resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} 1032 | 1033 | picocolors@1.1.1: 1034 | resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} 1035 | 1036 | picomatch@4.0.3: 1037 | resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} 1038 | engines: {node: '>=12'} 1039 | 1040 | pirates@4.0.7: 1041 | resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} 1042 | engines: {node: '>= 6'} 1043 | 1044 | pkg-types@1.3.1: 1045 | resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} 1046 | 1047 | playwright-core@1.57.0: 1048 | resolution: {integrity: sha512-agTcKlMw/mjBWOnD6kFZttAAGHgi/Nw0CZ2o6JqWSbMlI219lAFLZZCyqByTsvVAJq5XA5H8cA6PrvBRpBWEuQ==} 1049 | engines: {node: '>=18'} 1050 | hasBin: true 1051 | 1052 | playwright@1.57.0: 1053 | resolution: {integrity: sha512-ilYQj1s8sr2ppEJ2YVadYBN0Mb3mdo9J0wQ+UuDhzYqURwSoW4n1Xs5vs7ORwgDGmyEh33tRMeS8KhdkMoLXQw==} 1054 | engines: {node: '>=18'} 1055 | hasBin: true 1056 | 1057 | postcss-load-config@6.0.1: 1058 | resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} 1059 | engines: {node: '>= 18'} 1060 | peerDependencies: 1061 | jiti: '>=1.21.0' 1062 | postcss: '>=8.0.9' 1063 | tsx: ^4.8.1 1064 | yaml: ^2.4.2 1065 | peerDependenciesMeta: 1066 | jiti: 1067 | optional: true 1068 | postcss: 1069 | optional: true 1070 | tsx: 1071 | optional: true 1072 | yaml: 1073 | optional: true 1074 | 1075 | postcss@8.5.6: 1076 | resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} 1077 | engines: {node: ^10 || ^12 || >=14} 1078 | 1079 | pretty-format@27.5.1: 1080 | resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} 1081 | engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} 1082 | 1083 | punycode@2.3.1: 1084 | resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} 1085 | engines: {node: '>=6'} 1086 | 1087 | react-dom@19.2.3: 1088 | resolution: {integrity: sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==} 1089 | peerDependencies: 1090 | react: ^19.2.3 1091 | 1092 | react-is@17.0.2: 1093 | resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} 1094 | 1095 | react@19.2.3: 1096 | resolution: {integrity: sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==} 1097 | engines: {node: '>=0.10.0'} 1098 | 1099 | readdirp@4.1.2: 1100 | resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} 1101 | engines: {node: '>= 14.18.0'} 1102 | 1103 | redent@3.0.0: 1104 | resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} 1105 | engines: {node: '>=8'} 1106 | 1107 | resolve-from@5.0.0: 1108 | resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} 1109 | engines: {node: '>=8'} 1110 | 1111 | rollup@4.53.3: 1112 | resolution: {integrity: sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==} 1113 | engines: {node: '>=18.0.0', npm: '>=8.0.0'} 1114 | hasBin: true 1115 | 1116 | rrweb-cssom@0.7.1: 1117 | resolution: {integrity: sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==} 1118 | 1119 | rrweb-cssom@0.8.0: 1120 | resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==} 1121 | 1122 | safer-buffer@2.1.2: 1123 | resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} 1124 | 1125 | saxes@6.0.0: 1126 | resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} 1127 | engines: {node: '>=v12.22.7'} 1128 | 1129 | scheduler@0.27.0: 1130 | resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} 1131 | 1132 | semver@7.7.3: 1133 | resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} 1134 | engines: {node: '>=10'} 1135 | hasBin: true 1136 | 1137 | siginfo@2.0.0: 1138 | resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} 1139 | 1140 | sirv@3.0.2: 1141 | resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} 1142 | engines: {node: '>=18'} 1143 | 1144 | source-map-js@1.2.1: 1145 | resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} 1146 | engines: {node: '>=0.10.0'} 1147 | 1148 | source-map-support@0.5.21: 1149 | resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} 1150 | 1151 | source-map@0.6.1: 1152 | resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} 1153 | engines: {node: '>=0.10.0'} 1154 | 1155 | source-map@0.7.6: 1156 | resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} 1157 | engines: {node: '>= 12'} 1158 | 1159 | stackback@0.0.2: 1160 | resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} 1161 | 1162 | std-env@3.10.0: 1163 | resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} 1164 | 1165 | strip-indent@3.0.0: 1166 | resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} 1167 | engines: {node: '>=8'} 1168 | 1169 | sucrase@3.35.1: 1170 | resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} 1171 | engines: {node: '>=16 || 14 >=14.17'} 1172 | hasBin: true 1173 | 1174 | supports-color@7.2.0: 1175 | resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} 1176 | engines: {node: '>=8'} 1177 | 1178 | symbol-tree@3.2.4: 1179 | resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} 1180 | 1181 | terser@5.44.1: 1182 | resolution: {integrity: sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==} 1183 | engines: {node: '>=10'} 1184 | hasBin: true 1185 | 1186 | thenify-all@1.6.0: 1187 | resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} 1188 | engines: {node: '>=0.8'} 1189 | 1190 | thenify@3.3.1: 1191 | resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} 1192 | 1193 | tinybench@2.9.0: 1194 | resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} 1195 | 1196 | tinyexec@0.3.2: 1197 | resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} 1198 | 1199 | tinyexec@1.0.2: 1200 | resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} 1201 | engines: {node: '>=18'} 1202 | 1203 | tinyglobby@0.2.15: 1204 | resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} 1205 | engines: {node: '>=12.0.0'} 1206 | 1207 | tinyrainbow@3.0.3: 1208 | resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} 1209 | engines: {node: '>=14.0.0'} 1210 | 1211 | tldts-core@6.1.86: 1212 | resolution: {integrity: sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==} 1213 | 1214 | tldts@6.1.86: 1215 | resolution: {integrity: sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==} 1216 | hasBin: true 1217 | 1218 | totalist@3.0.1: 1219 | resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} 1220 | engines: {node: '>=6'} 1221 | 1222 | tough-cookie@5.1.2: 1223 | resolution: {integrity: sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==} 1224 | engines: {node: '>=16'} 1225 | 1226 | tr46@5.1.1: 1227 | resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} 1228 | engines: {node: '>=18'} 1229 | 1230 | tree-kill@1.2.2: 1231 | resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} 1232 | hasBin: true 1233 | 1234 | ts-interface-checker@0.1.13: 1235 | resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} 1236 | 1237 | tsup@8.5.1: 1238 | resolution: {integrity: sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==} 1239 | engines: {node: '>=18'} 1240 | hasBin: true 1241 | peerDependencies: 1242 | '@microsoft/api-extractor': ^7.36.0 1243 | '@swc/core': ^1 1244 | postcss: ^8.4.12 1245 | typescript: '>=4.5.0' 1246 | peerDependenciesMeta: 1247 | '@microsoft/api-extractor': 1248 | optional: true 1249 | '@swc/core': 1250 | optional: true 1251 | postcss: 1252 | optional: true 1253 | typescript: 1254 | optional: true 1255 | 1256 | typescript@5.9.3: 1257 | resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} 1258 | engines: {node: '>=14.17'} 1259 | hasBin: true 1260 | 1261 | ufo@1.6.1: 1262 | resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} 1263 | 1264 | undici-types@7.16.0: 1265 | resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} 1266 | 1267 | vite@7.2.7: 1268 | resolution: {integrity: sha512-ITcnkFeR3+fI8P1wMgItjGrR10170d8auB4EpMLPqmx6uxElH3a/hHGQabSHKdqd4FXWO1nFIp9rRn7JQ34ACQ==} 1269 | engines: {node: ^20.19.0 || >=22.12.0} 1270 | hasBin: true 1271 | peerDependencies: 1272 | '@types/node': ^20.19.0 || >=22.12.0 1273 | jiti: '>=1.21.0' 1274 | less: ^4.0.0 1275 | lightningcss: ^1.21.0 1276 | sass: ^1.70.0 1277 | sass-embedded: ^1.70.0 1278 | stylus: '>=0.54.8' 1279 | sugarss: ^5.0.0 1280 | terser: ^5.16.0 1281 | tsx: ^4.8.1 1282 | yaml: ^2.4.2 1283 | peerDependenciesMeta: 1284 | '@types/node': 1285 | optional: true 1286 | jiti: 1287 | optional: true 1288 | less: 1289 | optional: true 1290 | lightningcss: 1291 | optional: true 1292 | sass: 1293 | optional: true 1294 | sass-embedded: 1295 | optional: true 1296 | stylus: 1297 | optional: true 1298 | sugarss: 1299 | optional: true 1300 | terser: 1301 | optional: true 1302 | tsx: 1303 | optional: true 1304 | yaml: 1305 | optional: true 1306 | 1307 | vitest@4.0.15: 1308 | resolution: {integrity: sha512-n1RxDp8UJm6N0IbJLQo+yzLZ2sQCDyl1o0LeugbPWf8+8Fttp29GghsQBjYJVmWq3gBFfe9Hs1spR44vovn2wA==} 1309 | engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} 1310 | hasBin: true 1311 | peerDependencies: 1312 | '@edge-runtime/vm': '*' 1313 | '@opentelemetry/api': ^1.9.0 1314 | '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 1315 | '@vitest/browser-playwright': 4.0.15 1316 | '@vitest/browser-preview': 4.0.15 1317 | '@vitest/browser-webdriverio': 4.0.15 1318 | '@vitest/ui': 4.0.15 1319 | happy-dom: '*' 1320 | jsdom: '*' 1321 | peerDependenciesMeta: 1322 | '@edge-runtime/vm': 1323 | optional: true 1324 | '@opentelemetry/api': 1325 | optional: true 1326 | '@types/node': 1327 | optional: true 1328 | '@vitest/browser-playwright': 1329 | optional: true 1330 | '@vitest/browser-preview': 1331 | optional: true 1332 | '@vitest/browser-webdriverio': 1333 | optional: true 1334 | '@vitest/ui': 1335 | optional: true 1336 | happy-dom: 1337 | optional: true 1338 | jsdom: 1339 | optional: true 1340 | 1341 | w3c-xmlserializer@5.0.0: 1342 | resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} 1343 | engines: {node: '>=18'} 1344 | 1345 | webidl-conversions@7.0.0: 1346 | resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} 1347 | engines: {node: '>=12'} 1348 | 1349 | whatwg-encoding@3.1.1: 1350 | resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} 1351 | engines: {node: '>=18'} 1352 | 1353 | whatwg-mimetype@4.0.0: 1354 | resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} 1355 | engines: {node: '>=18'} 1356 | 1357 | whatwg-url@14.2.0: 1358 | resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} 1359 | engines: {node: '>=18'} 1360 | 1361 | why-is-node-running@2.3.0: 1362 | resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} 1363 | engines: {node: '>=8'} 1364 | hasBin: true 1365 | 1366 | ws@8.18.3: 1367 | resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} 1368 | engines: {node: '>=10.0.0'} 1369 | peerDependencies: 1370 | bufferutil: ^4.0.1 1371 | utf-8-validate: '>=5.0.2' 1372 | peerDependenciesMeta: 1373 | bufferutil: 1374 | optional: true 1375 | utf-8-validate: 1376 | optional: true 1377 | 1378 | xml-name-validator@5.0.0: 1379 | resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} 1380 | engines: {node: '>=18'} 1381 | 1382 | xmlchars@2.2.0: 1383 | resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} 1384 | 1385 | yaml@2.8.2: 1386 | resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} 1387 | engines: {node: '>= 14.6'} 1388 | hasBin: true 1389 | 1390 | snapshots: 1391 | 1392 | '@adobe/css-tools@4.4.4': {} 1393 | 1394 | '@asamuzakjp/css-color@3.2.0': 1395 | dependencies: 1396 | '@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) 1397 | '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) 1398 | '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) 1399 | '@csstools/css-tokenizer': 3.0.4 1400 | lru-cache: 10.4.3 1401 | 1402 | '@babel/code-frame@7.27.1': 1403 | dependencies: 1404 | '@babel/helper-validator-identifier': 7.28.5 1405 | js-tokens: 4.0.0 1406 | picocolors: 1.1.1 1407 | 1408 | '@babel/helper-string-parser@7.27.1': {} 1409 | 1410 | '@babel/helper-validator-identifier@7.28.5': {} 1411 | 1412 | '@babel/parser@7.28.5': 1413 | dependencies: 1414 | '@babel/types': 7.28.5 1415 | 1416 | '@babel/runtime@7.28.4': {} 1417 | 1418 | '@babel/types@7.28.5': 1419 | dependencies: 1420 | '@babel/helper-string-parser': 7.27.1 1421 | '@babel/helper-validator-identifier': 7.28.5 1422 | 1423 | '@bcoe/v8-coverage@1.0.2': {} 1424 | 1425 | '@csstools/color-helpers@5.1.0': {} 1426 | 1427 | '@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)': 1428 | dependencies: 1429 | '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) 1430 | '@csstools/css-tokenizer': 3.0.4 1431 | 1432 | '@csstools/css-color-parser@3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': 1433 | dependencies: 1434 | '@csstools/color-helpers': 5.1.0 1435 | '@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) 1436 | '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) 1437 | '@csstools/css-tokenizer': 3.0.4 1438 | 1439 | '@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4)': 1440 | dependencies: 1441 | '@csstools/css-tokenizer': 3.0.4 1442 | 1443 | '@csstools/css-tokenizer@3.0.4': {} 1444 | 1445 | '@esbuild/aix-ppc64@0.25.12': 1446 | optional: true 1447 | 1448 | '@esbuild/aix-ppc64@0.27.1': 1449 | optional: true 1450 | 1451 | '@esbuild/android-arm64@0.25.12': 1452 | optional: true 1453 | 1454 | '@esbuild/android-arm64@0.27.1': 1455 | optional: true 1456 | 1457 | '@esbuild/android-arm@0.25.12': 1458 | optional: true 1459 | 1460 | '@esbuild/android-arm@0.27.1': 1461 | optional: true 1462 | 1463 | '@esbuild/android-x64@0.25.12': 1464 | optional: true 1465 | 1466 | '@esbuild/android-x64@0.27.1': 1467 | optional: true 1468 | 1469 | '@esbuild/darwin-arm64@0.25.12': 1470 | optional: true 1471 | 1472 | '@esbuild/darwin-arm64@0.27.1': 1473 | optional: true 1474 | 1475 | '@esbuild/darwin-x64@0.25.12': 1476 | optional: true 1477 | 1478 | '@esbuild/darwin-x64@0.27.1': 1479 | optional: true 1480 | 1481 | '@esbuild/freebsd-arm64@0.25.12': 1482 | optional: true 1483 | 1484 | '@esbuild/freebsd-arm64@0.27.1': 1485 | optional: true 1486 | 1487 | '@esbuild/freebsd-x64@0.25.12': 1488 | optional: true 1489 | 1490 | '@esbuild/freebsd-x64@0.27.1': 1491 | optional: true 1492 | 1493 | '@esbuild/linux-arm64@0.25.12': 1494 | optional: true 1495 | 1496 | '@esbuild/linux-arm64@0.27.1': 1497 | optional: true 1498 | 1499 | '@esbuild/linux-arm@0.25.12': 1500 | optional: true 1501 | 1502 | '@esbuild/linux-arm@0.27.1': 1503 | optional: true 1504 | 1505 | '@esbuild/linux-ia32@0.25.12': 1506 | optional: true 1507 | 1508 | '@esbuild/linux-ia32@0.27.1': 1509 | optional: true 1510 | 1511 | '@esbuild/linux-loong64@0.25.12': 1512 | optional: true 1513 | 1514 | '@esbuild/linux-loong64@0.27.1': 1515 | optional: true 1516 | 1517 | '@esbuild/linux-mips64el@0.25.12': 1518 | optional: true 1519 | 1520 | '@esbuild/linux-mips64el@0.27.1': 1521 | optional: true 1522 | 1523 | '@esbuild/linux-ppc64@0.25.12': 1524 | optional: true 1525 | 1526 | '@esbuild/linux-ppc64@0.27.1': 1527 | optional: true 1528 | 1529 | '@esbuild/linux-riscv64@0.25.12': 1530 | optional: true 1531 | 1532 | '@esbuild/linux-riscv64@0.27.1': 1533 | optional: true 1534 | 1535 | '@esbuild/linux-s390x@0.25.12': 1536 | optional: true 1537 | 1538 | '@esbuild/linux-s390x@0.27.1': 1539 | optional: true 1540 | 1541 | '@esbuild/linux-x64@0.25.12': 1542 | optional: true 1543 | 1544 | '@esbuild/linux-x64@0.27.1': 1545 | optional: true 1546 | 1547 | '@esbuild/netbsd-arm64@0.25.12': 1548 | optional: true 1549 | 1550 | '@esbuild/netbsd-arm64@0.27.1': 1551 | optional: true 1552 | 1553 | '@esbuild/netbsd-x64@0.25.12': 1554 | optional: true 1555 | 1556 | '@esbuild/netbsd-x64@0.27.1': 1557 | optional: true 1558 | 1559 | '@esbuild/openbsd-arm64@0.25.12': 1560 | optional: true 1561 | 1562 | '@esbuild/openbsd-arm64@0.27.1': 1563 | optional: true 1564 | 1565 | '@esbuild/openbsd-x64@0.25.12': 1566 | optional: true 1567 | 1568 | '@esbuild/openbsd-x64@0.27.1': 1569 | optional: true 1570 | 1571 | '@esbuild/openharmony-arm64@0.25.12': 1572 | optional: true 1573 | 1574 | '@esbuild/openharmony-arm64@0.27.1': 1575 | optional: true 1576 | 1577 | '@esbuild/sunos-x64@0.25.12': 1578 | optional: true 1579 | 1580 | '@esbuild/sunos-x64@0.27.1': 1581 | optional: true 1582 | 1583 | '@esbuild/win32-arm64@0.25.12': 1584 | optional: true 1585 | 1586 | '@esbuild/win32-arm64@0.27.1': 1587 | optional: true 1588 | 1589 | '@esbuild/win32-ia32@0.25.12': 1590 | optional: true 1591 | 1592 | '@esbuild/win32-ia32@0.27.1': 1593 | optional: true 1594 | 1595 | '@esbuild/win32-x64@0.25.12': 1596 | optional: true 1597 | 1598 | '@esbuild/win32-x64@0.27.1': 1599 | optional: true 1600 | 1601 | '@jridgewell/gen-mapping@0.3.13': 1602 | dependencies: 1603 | '@jridgewell/sourcemap-codec': 1.5.5 1604 | '@jridgewell/trace-mapping': 0.3.31 1605 | 1606 | '@jridgewell/resolve-uri@3.1.2': {} 1607 | 1608 | '@jridgewell/source-map@0.3.11': 1609 | dependencies: 1610 | '@jridgewell/gen-mapping': 0.3.13 1611 | '@jridgewell/trace-mapping': 0.3.31 1612 | optional: true 1613 | 1614 | '@jridgewell/sourcemap-codec@1.5.5': {} 1615 | 1616 | '@jridgewell/trace-mapping@0.3.31': 1617 | dependencies: 1618 | '@jridgewell/resolve-uri': 3.1.2 1619 | '@jridgewell/sourcemap-codec': 1.5.5 1620 | 1621 | '@playwright/test@1.57.0': 1622 | dependencies: 1623 | playwright: 1.57.0 1624 | 1625 | '@polka/url@1.0.0-next.29': {} 1626 | 1627 | '@rollup/rollup-android-arm-eabi@4.53.3': 1628 | optional: true 1629 | 1630 | '@rollup/rollup-android-arm64@4.53.3': 1631 | optional: true 1632 | 1633 | '@rollup/rollup-darwin-arm64@4.53.3': 1634 | optional: true 1635 | 1636 | '@rollup/rollup-darwin-x64@4.53.3': 1637 | optional: true 1638 | 1639 | '@rollup/rollup-freebsd-arm64@4.53.3': 1640 | optional: true 1641 | 1642 | '@rollup/rollup-freebsd-x64@4.53.3': 1643 | optional: true 1644 | 1645 | '@rollup/rollup-linux-arm-gnueabihf@4.53.3': 1646 | optional: true 1647 | 1648 | '@rollup/rollup-linux-arm-musleabihf@4.53.3': 1649 | optional: true 1650 | 1651 | '@rollup/rollup-linux-arm64-gnu@4.53.3': 1652 | optional: true 1653 | 1654 | '@rollup/rollup-linux-arm64-musl@4.53.3': 1655 | optional: true 1656 | 1657 | '@rollup/rollup-linux-loong64-gnu@4.53.3': 1658 | optional: true 1659 | 1660 | '@rollup/rollup-linux-ppc64-gnu@4.53.3': 1661 | optional: true 1662 | 1663 | '@rollup/rollup-linux-riscv64-gnu@4.53.3': 1664 | optional: true 1665 | 1666 | '@rollup/rollup-linux-riscv64-musl@4.53.3': 1667 | optional: true 1668 | 1669 | '@rollup/rollup-linux-s390x-gnu@4.53.3': 1670 | optional: true 1671 | 1672 | '@rollup/rollup-linux-x64-gnu@4.53.3': 1673 | optional: true 1674 | 1675 | '@rollup/rollup-linux-x64-musl@4.53.3': 1676 | optional: true 1677 | 1678 | '@rollup/rollup-openharmony-arm64@4.53.3': 1679 | optional: true 1680 | 1681 | '@rollup/rollup-win32-arm64-msvc@4.53.3': 1682 | optional: true 1683 | 1684 | '@rollup/rollup-win32-ia32-msvc@4.53.3': 1685 | optional: true 1686 | 1687 | '@rollup/rollup-win32-x64-gnu@4.53.3': 1688 | optional: true 1689 | 1690 | '@rollup/rollup-win32-x64-msvc@4.53.3': 1691 | optional: true 1692 | 1693 | '@standard-schema/spec@1.0.0': {} 1694 | 1695 | '@testing-library/dom@10.4.1': 1696 | dependencies: 1697 | '@babel/code-frame': 7.27.1 1698 | '@babel/runtime': 7.28.4 1699 | '@types/aria-query': 5.0.4 1700 | aria-query: 5.3.0 1701 | dom-accessibility-api: 0.5.16 1702 | lz-string: 1.5.0 1703 | picocolors: 1.1.1 1704 | pretty-format: 27.5.1 1705 | 1706 | '@testing-library/jest-dom@6.9.1': 1707 | dependencies: 1708 | '@adobe/css-tools': 4.4.4 1709 | aria-query: 5.3.2 1710 | css.escape: 1.5.1 1711 | dom-accessibility-api: 0.6.3 1712 | picocolors: 1.1.1 1713 | redent: 3.0.0 1714 | 1715 | '@testing-library/react@16.3.1(@testing-library/dom@10.4.1)(@types/react@18.3.27)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': 1716 | dependencies: 1717 | '@babel/runtime': 7.28.4 1718 | '@testing-library/dom': 10.4.1 1719 | react: 19.2.3 1720 | react-dom: 19.2.3(react@19.2.3) 1721 | optionalDependencies: 1722 | '@types/react': 18.3.27 1723 | 1724 | '@types/aria-query@5.0.4': {} 1725 | 1726 | '@types/chai@5.2.3': 1727 | dependencies: 1728 | '@types/deep-eql': 4.0.2 1729 | assertion-error: 2.0.1 1730 | 1731 | '@types/deep-eql@4.0.2': {} 1732 | 1733 | '@types/estree@1.0.8': {} 1734 | 1735 | '@types/node@25.0.1': 1736 | dependencies: 1737 | undici-types: 7.16.0 1738 | 1739 | '@types/prop-types@15.7.15': {} 1740 | 1741 | '@types/react@18.3.27': 1742 | dependencies: 1743 | '@types/prop-types': 15.7.15 1744 | csstype: 3.2.3 1745 | 1746 | '@vitest/coverage-v8@4.0.15(vitest@4.0.15)': 1747 | dependencies: 1748 | '@bcoe/v8-coverage': 1.0.2 1749 | '@vitest/utils': 4.0.15 1750 | ast-v8-to-istanbul: 0.3.8 1751 | istanbul-lib-coverage: 3.2.2 1752 | istanbul-lib-report: 3.0.1 1753 | istanbul-lib-source-maps: 5.0.6 1754 | istanbul-reports: 3.2.0 1755 | magicast: 0.5.1 1756 | obug: 2.1.1 1757 | std-env: 3.10.0 1758 | tinyrainbow: 3.0.3 1759 | vitest: 4.0.15(@types/node@25.0.1)(@vitest/ui@4.0.15)(jsdom@25.0.1)(terser@5.44.1)(yaml@2.8.2) 1760 | transitivePeerDependencies: 1761 | - supports-color 1762 | 1763 | '@vitest/expect@4.0.15': 1764 | dependencies: 1765 | '@standard-schema/spec': 1.0.0 1766 | '@types/chai': 5.2.3 1767 | '@vitest/spy': 4.0.15 1768 | '@vitest/utils': 4.0.15 1769 | chai: 6.2.1 1770 | tinyrainbow: 3.0.3 1771 | 1772 | '@vitest/mocker@4.0.15(vite@7.2.7(@types/node@25.0.1)(terser@5.44.1)(yaml@2.8.2))': 1773 | dependencies: 1774 | '@vitest/spy': 4.0.15 1775 | estree-walker: 3.0.3 1776 | magic-string: 0.30.21 1777 | optionalDependencies: 1778 | vite: 7.2.7(@types/node@25.0.1)(terser@5.44.1)(yaml@2.8.2) 1779 | 1780 | '@vitest/pretty-format@4.0.15': 1781 | dependencies: 1782 | tinyrainbow: 3.0.3 1783 | 1784 | '@vitest/runner@4.0.15': 1785 | dependencies: 1786 | '@vitest/utils': 4.0.15 1787 | pathe: 2.0.3 1788 | 1789 | '@vitest/snapshot@4.0.15': 1790 | dependencies: 1791 | '@vitest/pretty-format': 4.0.15 1792 | magic-string: 0.30.21 1793 | pathe: 2.0.3 1794 | 1795 | '@vitest/spy@4.0.15': {} 1796 | 1797 | '@vitest/ui@4.0.15(vitest@4.0.15)': 1798 | dependencies: 1799 | '@vitest/utils': 4.0.15 1800 | fflate: 0.8.2 1801 | flatted: 3.3.3 1802 | pathe: 2.0.3 1803 | sirv: 3.0.2 1804 | tinyglobby: 0.2.15 1805 | tinyrainbow: 3.0.3 1806 | vitest: 4.0.15(@types/node@25.0.1)(@vitest/ui@4.0.15)(jsdom@25.0.1)(terser@5.44.1)(yaml@2.8.2) 1807 | 1808 | '@vitest/utils@4.0.15': 1809 | dependencies: 1810 | '@vitest/pretty-format': 4.0.15 1811 | tinyrainbow: 3.0.3 1812 | 1813 | acorn@8.15.0: {} 1814 | 1815 | agent-base@7.1.4: {} 1816 | 1817 | ansi-regex@5.0.1: {} 1818 | 1819 | ansi-styles@5.2.0: {} 1820 | 1821 | any-promise@1.3.0: {} 1822 | 1823 | aria-query@5.3.0: 1824 | dependencies: 1825 | dequal: 2.0.3 1826 | 1827 | aria-query@5.3.2: {} 1828 | 1829 | assertion-error@2.0.1: {} 1830 | 1831 | ast-v8-to-istanbul@0.3.8: 1832 | dependencies: 1833 | '@jridgewell/trace-mapping': 0.3.31 1834 | estree-walker: 3.0.3 1835 | js-tokens: 9.0.1 1836 | 1837 | asynckit@0.4.0: {} 1838 | 1839 | buffer-from@1.1.2: 1840 | optional: true 1841 | 1842 | bundle-require@5.1.0(esbuild@0.27.1): 1843 | dependencies: 1844 | esbuild: 0.27.1 1845 | load-tsconfig: 0.2.5 1846 | 1847 | cac@6.7.14: {} 1848 | 1849 | call-bind-apply-helpers@1.0.2: 1850 | dependencies: 1851 | es-errors: 1.3.0 1852 | function-bind: 1.1.2 1853 | 1854 | chai@6.2.1: {} 1855 | 1856 | chokidar@4.0.3: 1857 | dependencies: 1858 | readdirp: 4.1.2 1859 | 1860 | combined-stream@1.0.8: 1861 | dependencies: 1862 | delayed-stream: 1.0.0 1863 | 1864 | commander@2.20.3: 1865 | optional: true 1866 | 1867 | commander@4.1.1: {} 1868 | 1869 | confbox@0.1.8: {} 1870 | 1871 | consola@3.4.2: {} 1872 | 1873 | css.escape@1.5.1: {} 1874 | 1875 | cssstyle@4.6.0: 1876 | dependencies: 1877 | '@asamuzakjp/css-color': 3.2.0 1878 | rrweb-cssom: 0.8.0 1879 | 1880 | csstype@3.2.3: {} 1881 | 1882 | data-urls@5.0.0: 1883 | dependencies: 1884 | whatwg-mimetype: 4.0.0 1885 | whatwg-url: 14.2.0 1886 | 1887 | debug@4.4.3: 1888 | dependencies: 1889 | ms: 2.1.3 1890 | 1891 | decimal.js@10.6.0: {} 1892 | 1893 | delayed-stream@1.0.0: {} 1894 | 1895 | dequal@2.0.3: {} 1896 | 1897 | dom-accessibility-api@0.5.16: {} 1898 | 1899 | dom-accessibility-api@0.6.3: {} 1900 | 1901 | dunder-proto@1.0.1: 1902 | dependencies: 1903 | call-bind-apply-helpers: 1.0.2 1904 | es-errors: 1.3.0 1905 | gopd: 1.2.0 1906 | 1907 | entities@6.0.1: {} 1908 | 1909 | es-define-property@1.0.1: {} 1910 | 1911 | es-errors@1.3.0: {} 1912 | 1913 | es-module-lexer@1.7.0: {} 1914 | 1915 | es-object-atoms@1.1.1: 1916 | dependencies: 1917 | es-errors: 1.3.0 1918 | 1919 | es-set-tostringtag@2.1.0: 1920 | dependencies: 1921 | es-errors: 1.3.0 1922 | get-intrinsic: 1.3.0 1923 | has-tostringtag: 1.0.2 1924 | hasown: 2.0.2 1925 | 1926 | esbuild@0.25.12: 1927 | optionalDependencies: 1928 | '@esbuild/aix-ppc64': 0.25.12 1929 | '@esbuild/android-arm': 0.25.12 1930 | '@esbuild/android-arm64': 0.25.12 1931 | '@esbuild/android-x64': 0.25.12 1932 | '@esbuild/darwin-arm64': 0.25.12 1933 | '@esbuild/darwin-x64': 0.25.12 1934 | '@esbuild/freebsd-arm64': 0.25.12 1935 | '@esbuild/freebsd-x64': 0.25.12 1936 | '@esbuild/linux-arm': 0.25.12 1937 | '@esbuild/linux-arm64': 0.25.12 1938 | '@esbuild/linux-ia32': 0.25.12 1939 | '@esbuild/linux-loong64': 0.25.12 1940 | '@esbuild/linux-mips64el': 0.25.12 1941 | '@esbuild/linux-ppc64': 0.25.12 1942 | '@esbuild/linux-riscv64': 0.25.12 1943 | '@esbuild/linux-s390x': 0.25.12 1944 | '@esbuild/linux-x64': 0.25.12 1945 | '@esbuild/netbsd-arm64': 0.25.12 1946 | '@esbuild/netbsd-x64': 0.25.12 1947 | '@esbuild/openbsd-arm64': 0.25.12 1948 | '@esbuild/openbsd-x64': 0.25.12 1949 | '@esbuild/openharmony-arm64': 0.25.12 1950 | '@esbuild/sunos-x64': 0.25.12 1951 | '@esbuild/win32-arm64': 0.25.12 1952 | '@esbuild/win32-ia32': 0.25.12 1953 | '@esbuild/win32-x64': 0.25.12 1954 | 1955 | esbuild@0.27.1: 1956 | optionalDependencies: 1957 | '@esbuild/aix-ppc64': 0.27.1 1958 | '@esbuild/android-arm': 0.27.1 1959 | '@esbuild/android-arm64': 0.27.1 1960 | '@esbuild/android-x64': 0.27.1 1961 | '@esbuild/darwin-arm64': 0.27.1 1962 | '@esbuild/darwin-x64': 0.27.1 1963 | '@esbuild/freebsd-arm64': 0.27.1 1964 | '@esbuild/freebsd-x64': 0.27.1 1965 | '@esbuild/linux-arm': 0.27.1 1966 | '@esbuild/linux-arm64': 0.27.1 1967 | '@esbuild/linux-ia32': 0.27.1 1968 | '@esbuild/linux-loong64': 0.27.1 1969 | '@esbuild/linux-mips64el': 0.27.1 1970 | '@esbuild/linux-ppc64': 0.27.1 1971 | '@esbuild/linux-riscv64': 0.27.1 1972 | '@esbuild/linux-s390x': 0.27.1 1973 | '@esbuild/linux-x64': 0.27.1 1974 | '@esbuild/netbsd-arm64': 0.27.1 1975 | '@esbuild/netbsd-x64': 0.27.1 1976 | '@esbuild/openbsd-arm64': 0.27.1 1977 | '@esbuild/openbsd-x64': 0.27.1 1978 | '@esbuild/openharmony-arm64': 0.27.1 1979 | '@esbuild/sunos-x64': 0.27.1 1980 | '@esbuild/win32-arm64': 0.27.1 1981 | '@esbuild/win32-ia32': 0.27.1 1982 | '@esbuild/win32-x64': 0.27.1 1983 | 1984 | estree-walker@3.0.3: 1985 | dependencies: 1986 | '@types/estree': 1.0.8 1987 | 1988 | expect-type@1.3.0: {} 1989 | 1990 | fdir@6.5.0(picomatch@4.0.3): 1991 | optionalDependencies: 1992 | picomatch: 4.0.3 1993 | 1994 | fflate@0.8.2: {} 1995 | 1996 | fix-dts-default-cjs-exports@1.0.1: 1997 | dependencies: 1998 | magic-string: 0.30.21 1999 | mlly: 1.8.0 2000 | rollup: 4.53.3 2001 | 2002 | flatted@3.3.3: {} 2003 | 2004 | form-data@4.0.5: 2005 | dependencies: 2006 | asynckit: 0.4.0 2007 | combined-stream: 1.0.8 2008 | es-set-tostringtag: 2.1.0 2009 | hasown: 2.0.2 2010 | mime-types: 2.1.35 2011 | 2012 | fsevents@2.3.2: 2013 | optional: true 2014 | 2015 | fsevents@2.3.3: 2016 | optional: true 2017 | 2018 | function-bind@1.1.2: {} 2019 | 2020 | get-intrinsic@1.3.0: 2021 | dependencies: 2022 | call-bind-apply-helpers: 1.0.2 2023 | es-define-property: 1.0.1 2024 | es-errors: 1.3.0 2025 | es-object-atoms: 1.1.1 2026 | function-bind: 1.1.2 2027 | get-proto: 1.0.1 2028 | gopd: 1.2.0 2029 | has-symbols: 1.1.0 2030 | hasown: 2.0.2 2031 | math-intrinsics: 1.1.0 2032 | 2033 | get-proto@1.0.1: 2034 | dependencies: 2035 | dunder-proto: 1.0.1 2036 | es-object-atoms: 1.1.1 2037 | 2038 | gopd@1.2.0: {} 2039 | 2040 | has-flag@4.0.0: {} 2041 | 2042 | has-symbols@1.1.0: {} 2043 | 2044 | has-tostringtag@1.0.2: 2045 | dependencies: 2046 | has-symbols: 1.1.0 2047 | 2048 | hasown@2.0.2: 2049 | dependencies: 2050 | function-bind: 1.1.2 2051 | 2052 | html-encoding-sniffer@4.0.0: 2053 | dependencies: 2054 | whatwg-encoding: 3.1.1 2055 | 2056 | html-escaper@2.0.2: {} 2057 | 2058 | http-proxy-agent@7.0.2: 2059 | dependencies: 2060 | agent-base: 7.1.4 2061 | debug: 4.4.3 2062 | transitivePeerDependencies: 2063 | - supports-color 2064 | 2065 | https-proxy-agent@7.0.6: 2066 | dependencies: 2067 | agent-base: 7.1.4 2068 | debug: 4.4.3 2069 | transitivePeerDependencies: 2070 | - supports-color 2071 | 2072 | iconv-lite@0.6.3: 2073 | dependencies: 2074 | safer-buffer: 2.1.2 2075 | 2076 | indent-string@4.0.0: {} 2077 | 2078 | is-potential-custom-element-name@1.0.1: {} 2079 | 2080 | istanbul-lib-coverage@3.2.2: {} 2081 | 2082 | istanbul-lib-report@3.0.1: 2083 | dependencies: 2084 | istanbul-lib-coverage: 3.2.2 2085 | make-dir: 4.0.0 2086 | supports-color: 7.2.0 2087 | 2088 | istanbul-lib-source-maps@5.0.6: 2089 | dependencies: 2090 | '@jridgewell/trace-mapping': 0.3.31 2091 | debug: 4.4.3 2092 | istanbul-lib-coverage: 3.2.2 2093 | transitivePeerDependencies: 2094 | - supports-color 2095 | 2096 | istanbul-reports@3.2.0: 2097 | dependencies: 2098 | html-escaper: 2.0.2 2099 | istanbul-lib-report: 3.0.1 2100 | 2101 | joycon@3.1.1: {} 2102 | 2103 | js-tokens@4.0.0: {} 2104 | 2105 | js-tokens@9.0.1: {} 2106 | 2107 | jsdom@25.0.1: 2108 | dependencies: 2109 | cssstyle: 4.6.0 2110 | data-urls: 5.0.0 2111 | decimal.js: 10.6.0 2112 | form-data: 4.0.5 2113 | html-encoding-sniffer: 4.0.0 2114 | http-proxy-agent: 7.0.2 2115 | https-proxy-agent: 7.0.6 2116 | is-potential-custom-element-name: 1.0.1 2117 | nwsapi: 2.2.23 2118 | parse5: 7.3.0 2119 | rrweb-cssom: 0.7.1 2120 | saxes: 6.0.0 2121 | symbol-tree: 3.2.4 2122 | tough-cookie: 5.1.2 2123 | w3c-xmlserializer: 5.0.0 2124 | webidl-conversions: 7.0.0 2125 | whatwg-encoding: 3.1.1 2126 | whatwg-mimetype: 4.0.0 2127 | whatwg-url: 14.2.0 2128 | ws: 8.18.3 2129 | xml-name-validator: 5.0.0 2130 | transitivePeerDependencies: 2131 | - bufferutil 2132 | - supports-color 2133 | - utf-8-validate 2134 | 2135 | lilconfig@3.1.3: {} 2136 | 2137 | lines-and-columns@1.2.4: {} 2138 | 2139 | load-tsconfig@0.2.5: {} 2140 | 2141 | lru-cache@10.4.3: {} 2142 | 2143 | lz-string@1.5.0: {} 2144 | 2145 | magic-string@0.30.21: 2146 | dependencies: 2147 | '@jridgewell/sourcemap-codec': 1.5.5 2148 | 2149 | magicast@0.5.1: 2150 | dependencies: 2151 | '@babel/parser': 7.28.5 2152 | '@babel/types': 7.28.5 2153 | source-map-js: 1.2.1 2154 | 2155 | make-dir@4.0.0: 2156 | dependencies: 2157 | semver: 7.7.3 2158 | 2159 | math-intrinsics@1.1.0: {} 2160 | 2161 | mime-db@1.52.0: {} 2162 | 2163 | mime-types@2.1.35: 2164 | dependencies: 2165 | mime-db: 1.52.0 2166 | 2167 | min-indent@1.0.1: {} 2168 | 2169 | mlly@1.8.0: 2170 | dependencies: 2171 | acorn: 8.15.0 2172 | pathe: 2.0.3 2173 | pkg-types: 1.3.1 2174 | ufo: 1.6.1 2175 | 2176 | mrmime@2.0.1: {} 2177 | 2178 | ms@2.1.3: {} 2179 | 2180 | mz@2.7.0: 2181 | dependencies: 2182 | any-promise: 1.3.0 2183 | object-assign: 4.1.1 2184 | thenify-all: 1.6.0 2185 | 2186 | nanoid@3.3.11: {} 2187 | 2188 | nwsapi@2.2.23: {} 2189 | 2190 | object-assign@4.1.1: {} 2191 | 2192 | obug@2.1.1: {} 2193 | 2194 | parse5@7.3.0: 2195 | dependencies: 2196 | entities: 6.0.1 2197 | 2198 | pathe@2.0.3: {} 2199 | 2200 | picocolors@1.1.1: {} 2201 | 2202 | picomatch@4.0.3: {} 2203 | 2204 | pirates@4.0.7: {} 2205 | 2206 | pkg-types@1.3.1: 2207 | dependencies: 2208 | confbox: 0.1.8 2209 | mlly: 1.8.0 2210 | pathe: 2.0.3 2211 | 2212 | playwright-core@1.57.0: {} 2213 | 2214 | playwright@1.57.0: 2215 | dependencies: 2216 | playwright-core: 1.57.0 2217 | optionalDependencies: 2218 | fsevents: 2.3.2 2219 | 2220 | postcss-load-config@6.0.1(postcss@8.5.6)(yaml@2.8.2): 2221 | dependencies: 2222 | lilconfig: 3.1.3 2223 | optionalDependencies: 2224 | postcss: 8.5.6 2225 | yaml: 2.8.2 2226 | 2227 | postcss@8.5.6: 2228 | dependencies: 2229 | nanoid: 3.3.11 2230 | picocolors: 1.1.1 2231 | source-map-js: 1.2.1 2232 | 2233 | pretty-format@27.5.1: 2234 | dependencies: 2235 | ansi-regex: 5.0.1 2236 | ansi-styles: 5.2.0 2237 | react-is: 17.0.2 2238 | 2239 | punycode@2.3.1: {} 2240 | 2241 | react-dom@19.2.3(react@19.2.3): 2242 | dependencies: 2243 | react: 19.2.3 2244 | scheduler: 0.27.0 2245 | 2246 | react-is@17.0.2: {} 2247 | 2248 | react@19.2.3: {} 2249 | 2250 | readdirp@4.1.2: {} 2251 | 2252 | redent@3.0.0: 2253 | dependencies: 2254 | indent-string: 4.0.0 2255 | strip-indent: 3.0.0 2256 | 2257 | resolve-from@5.0.0: {} 2258 | 2259 | rollup@4.53.3: 2260 | dependencies: 2261 | '@types/estree': 1.0.8 2262 | optionalDependencies: 2263 | '@rollup/rollup-android-arm-eabi': 4.53.3 2264 | '@rollup/rollup-android-arm64': 4.53.3 2265 | '@rollup/rollup-darwin-arm64': 4.53.3 2266 | '@rollup/rollup-darwin-x64': 4.53.3 2267 | '@rollup/rollup-freebsd-arm64': 4.53.3 2268 | '@rollup/rollup-freebsd-x64': 4.53.3 2269 | '@rollup/rollup-linux-arm-gnueabihf': 4.53.3 2270 | '@rollup/rollup-linux-arm-musleabihf': 4.53.3 2271 | '@rollup/rollup-linux-arm64-gnu': 4.53.3 2272 | '@rollup/rollup-linux-arm64-musl': 4.53.3 2273 | '@rollup/rollup-linux-loong64-gnu': 4.53.3 2274 | '@rollup/rollup-linux-ppc64-gnu': 4.53.3 2275 | '@rollup/rollup-linux-riscv64-gnu': 4.53.3 2276 | '@rollup/rollup-linux-riscv64-musl': 4.53.3 2277 | '@rollup/rollup-linux-s390x-gnu': 4.53.3 2278 | '@rollup/rollup-linux-x64-gnu': 4.53.3 2279 | '@rollup/rollup-linux-x64-musl': 4.53.3 2280 | '@rollup/rollup-openharmony-arm64': 4.53.3 2281 | '@rollup/rollup-win32-arm64-msvc': 4.53.3 2282 | '@rollup/rollup-win32-ia32-msvc': 4.53.3 2283 | '@rollup/rollup-win32-x64-gnu': 4.53.3 2284 | '@rollup/rollup-win32-x64-msvc': 4.53.3 2285 | fsevents: 2.3.3 2286 | 2287 | rrweb-cssom@0.7.1: {} 2288 | 2289 | rrweb-cssom@0.8.0: {} 2290 | 2291 | safer-buffer@2.1.2: {} 2292 | 2293 | saxes@6.0.0: 2294 | dependencies: 2295 | xmlchars: 2.2.0 2296 | 2297 | scheduler@0.27.0: {} 2298 | 2299 | semver@7.7.3: {} 2300 | 2301 | siginfo@2.0.0: {} 2302 | 2303 | sirv@3.0.2: 2304 | dependencies: 2305 | '@polka/url': 1.0.0-next.29 2306 | mrmime: 2.0.1 2307 | totalist: 3.0.1 2308 | 2309 | source-map-js@1.2.1: {} 2310 | 2311 | source-map-support@0.5.21: 2312 | dependencies: 2313 | buffer-from: 1.1.2 2314 | source-map: 0.6.1 2315 | optional: true 2316 | 2317 | source-map@0.6.1: 2318 | optional: true 2319 | 2320 | source-map@0.7.6: {} 2321 | 2322 | stackback@0.0.2: {} 2323 | 2324 | std-env@3.10.0: {} 2325 | 2326 | strip-indent@3.0.0: 2327 | dependencies: 2328 | min-indent: 1.0.1 2329 | 2330 | sucrase@3.35.1: 2331 | dependencies: 2332 | '@jridgewell/gen-mapping': 0.3.13 2333 | commander: 4.1.1 2334 | lines-and-columns: 1.2.4 2335 | mz: 2.7.0 2336 | pirates: 4.0.7 2337 | tinyglobby: 0.2.15 2338 | ts-interface-checker: 0.1.13 2339 | 2340 | supports-color@7.2.0: 2341 | dependencies: 2342 | has-flag: 4.0.0 2343 | 2344 | symbol-tree@3.2.4: {} 2345 | 2346 | terser@5.44.1: 2347 | dependencies: 2348 | '@jridgewell/source-map': 0.3.11 2349 | acorn: 8.15.0 2350 | commander: 2.20.3 2351 | source-map-support: 0.5.21 2352 | optional: true 2353 | 2354 | thenify-all@1.6.0: 2355 | dependencies: 2356 | thenify: 3.3.1 2357 | 2358 | thenify@3.3.1: 2359 | dependencies: 2360 | any-promise: 1.3.0 2361 | 2362 | tinybench@2.9.0: {} 2363 | 2364 | tinyexec@0.3.2: {} 2365 | 2366 | tinyexec@1.0.2: {} 2367 | 2368 | tinyglobby@0.2.15: 2369 | dependencies: 2370 | fdir: 6.5.0(picomatch@4.0.3) 2371 | picomatch: 4.0.3 2372 | 2373 | tinyrainbow@3.0.3: {} 2374 | 2375 | tldts-core@6.1.86: {} 2376 | 2377 | tldts@6.1.86: 2378 | dependencies: 2379 | tldts-core: 6.1.86 2380 | 2381 | totalist@3.0.1: {} 2382 | 2383 | tough-cookie@5.1.2: 2384 | dependencies: 2385 | tldts: 6.1.86 2386 | 2387 | tr46@5.1.1: 2388 | dependencies: 2389 | punycode: 2.3.1 2390 | 2391 | tree-kill@1.2.2: {} 2392 | 2393 | ts-interface-checker@0.1.13: {} 2394 | 2395 | tsup@8.5.1(postcss@8.5.6)(typescript@5.9.3)(yaml@2.8.2): 2396 | dependencies: 2397 | bundle-require: 5.1.0(esbuild@0.27.1) 2398 | cac: 6.7.14 2399 | chokidar: 4.0.3 2400 | consola: 3.4.2 2401 | debug: 4.4.3 2402 | esbuild: 0.27.1 2403 | fix-dts-default-cjs-exports: 1.0.1 2404 | joycon: 3.1.1 2405 | picocolors: 1.1.1 2406 | postcss-load-config: 6.0.1(postcss@8.5.6)(yaml@2.8.2) 2407 | resolve-from: 5.0.0 2408 | rollup: 4.53.3 2409 | source-map: 0.7.6 2410 | sucrase: 3.35.1 2411 | tinyexec: 0.3.2 2412 | tinyglobby: 0.2.15 2413 | tree-kill: 1.2.2 2414 | optionalDependencies: 2415 | postcss: 8.5.6 2416 | typescript: 5.9.3 2417 | transitivePeerDependencies: 2418 | - jiti 2419 | - supports-color 2420 | - tsx 2421 | - yaml 2422 | 2423 | typescript@5.9.3: {} 2424 | 2425 | ufo@1.6.1: {} 2426 | 2427 | undici-types@7.16.0: {} 2428 | 2429 | vite@7.2.7(@types/node@25.0.1)(terser@5.44.1)(yaml@2.8.2): 2430 | dependencies: 2431 | esbuild: 0.25.12 2432 | fdir: 6.5.0(picomatch@4.0.3) 2433 | picomatch: 4.0.3 2434 | postcss: 8.5.6 2435 | rollup: 4.53.3 2436 | tinyglobby: 0.2.15 2437 | optionalDependencies: 2438 | '@types/node': 25.0.1 2439 | fsevents: 2.3.3 2440 | terser: 5.44.1 2441 | yaml: 2.8.2 2442 | 2443 | vitest@4.0.15(@types/node@25.0.1)(@vitest/ui@4.0.15)(jsdom@25.0.1)(terser@5.44.1)(yaml@2.8.2): 2444 | dependencies: 2445 | '@vitest/expect': 4.0.15 2446 | '@vitest/mocker': 4.0.15(vite@7.2.7(@types/node@25.0.1)(terser@5.44.1)(yaml@2.8.2)) 2447 | '@vitest/pretty-format': 4.0.15 2448 | '@vitest/runner': 4.0.15 2449 | '@vitest/snapshot': 4.0.15 2450 | '@vitest/spy': 4.0.15 2451 | '@vitest/utils': 4.0.15 2452 | es-module-lexer: 1.7.0 2453 | expect-type: 1.3.0 2454 | magic-string: 0.30.21 2455 | obug: 2.1.1 2456 | pathe: 2.0.3 2457 | picomatch: 4.0.3 2458 | std-env: 3.10.0 2459 | tinybench: 2.9.0 2460 | tinyexec: 1.0.2 2461 | tinyglobby: 0.2.15 2462 | tinyrainbow: 3.0.3 2463 | vite: 7.2.7(@types/node@25.0.1)(terser@5.44.1)(yaml@2.8.2) 2464 | why-is-node-running: 2.3.0 2465 | optionalDependencies: 2466 | '@types/node': 25.0.1 2467 | '@vitest/ui': 4.0.15(vitest@4.0.15) 2468 | jsdom: 25.0.1 2469 | transitivePeerDependencies: 2470 | - jiti 2471 | - less 2472 | - lightningcss 2473 | - msw 2474 | - sass 2475 | - sass-embedded 2476 | - stylus 2477 | - sugarss 2478 | - terser 2479 | - tsx 2480 | - yaml 2481 | 2482 | w3c-xmlserializer@5.0.0: 2483 | dependencies: 2484 | xml-name-validator: 5.0.0 2485 | 2486 | webidl-conversions@7.0.0: {} 2487 | 2488 | whatwg-encoding@3.1.1: 2489 | dependencies: 2490 | iconv-lite: 0.6.3 2491 | 2492 | whatwg-mimetype@4.0.0: {} 2493 | 2494 | whatwg-url@14.2.0: 2495 | dependencies: 2496 | tr46: 5.1.1 2497 | webidl-conversions: 7.0.0 2498 | 2499 | why-is-node-running@2.3.0: 2500 | dependencies: 2501 | siginfo: 2.0.0 2502 | stackback: 0.0.2 2503 | 2504 | ws@8.18.3: {} 2505 | 2506 | xml-name-validator@5.0.0: {} 2507 | 2508 | xmlchars@2.2.0: {} 2509 | 2510 | yaml@2.8.2: 2511 | optional: true 2512 | --------------------------------------------------------------------------------