From 428e973548d8b156cb7eb1c4bcb6cc2db6321606 Mon Sep 17 00:00:00 2001 From: saravanakumardb1 Date: Thu, 12 Feb 2026 22:55:44 -0800 Subject: [PATCH] test(react-auth): add 10 tests with jsdom + React Testing Library Tests: createAuthProvider factory, AuthProvider rendering, login/logout flows, localStorage persistence, onLoginFallback, useAuth outside provider, custom storage prefix. --- packages/react-auth/package.json | 9 + .../src/__tests__/react-auth.test.tsx | 304 ++++++++ packages/react-auth/vitest.config.ts | 7 + pnpm-lock.yaml | 719 +++++++++++++++++- 4 files changed, 1028 insertions(+), 11 deletions(-) create mode 100644 packages/react-auth/src/__tests__/react-auth.test.tsx create mode 100644 packages/react-auth/vitest.config.ts diff --git a/packages/react-auth/package.json b/packages/react-auth/package.json index b7f8813c..d71725f4 100644 --- a/packages/react-auth/package.json +++ b/packages/react-auth/package.json @@ -22,5 +22,14 @@ }, "dependencies": { "@bytelyst/api-client": "workspace:*" + }, + "devDependencies": { + "@testing-library/jest-dom": "^6.9.1", + "@testing-library/react": "^16.3.2", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "jsdom": "^28.0.0", + "react": "^19.2.4", + "react-dom": "^19.2.4" } } diff --git a/packages/react-auth/src/__tests__/react-auth.test.tsx b/packages/react-auth/src/__tests__/react-auth.test.tsx new file mode 100644 index 00000000..3be4c881 --- /dev/null +++ b/packages/react-auth/src/__tests__/react-auth.test.tsx @@ -0,0 +1,304 @@ +import { describe, expect, it, vi, beforeEach } from 'vitest'; +import { render, screen, act, cleanup } from '@testing-library/react'; +import { createAuthProvider } from '../index.js'; + +// Minimal user type for testing +interface TestUser { + email: string; + name: string; + role: string; + [key: string]: unknown; +} + +// Mock fetch globally +const mockFetch = vi.fn(); +globalThis.fetch = mockFetch; + +// localStorage mock +const store: Record = {}; +const localStorageMock = { + getItem: vi.fn((key: string) => store[key] ?? null), + setItem: vi.fn((key: string, value: string) => { + store[key] = value; + }), + removeItem: vi.fn((key: string) => { + delete store[key]; + }), + clear: vi.fn(() => { + for (const key of Object.keys(store)) delete store[key]; + }), + length: 0, + key: vi.fn(), +}; +Object.defineProperty(globalThis, 'localStorage', { value: localStorageMock }); + +function createTestAuth(overrides?: Partial>[0]>) { + return createAuthProvider({ + storagePrefix: 'test', + loginEndpoint: '/auth/login', + mapLoginResponse: (data: unknown) => { + const d = data as { user: TestUser; accessToken: string; refreshToken: string }; + return { user: d.user, accessToken: d.accessToken, refreshToken: d.refreshToken }; + }, + ...overrides, + }); +} + +describe('createAuthProvider', () => { + beforeEach(() => { + cleanup(); + localStorageMock.clear(); + vi.clearAllMocks(); + mockFetch.mockReset(); + }); + + it('returns AuthProvider and useAuth', () => { + const result = createTestAuth(); + expect(result.AuthProvider).toBeDefined(); + expect(result.useAuth).toBeDefined(); + expect(typeof result.AuthProvider).toBe('function'); + expect(typeof result.useAuth).toBe('function'); + }); + + it('renders children', () => { + const { AuthProvider } = createTestAuth(); + render( + +
Hello
+
+ ); + expect(screen.getByTestId('child')).toBeDefined(); + expect(screen.getByText('Hello')).toBeDefined(); + }); + + it('starts unauthenticated with no stored user', () => { + const { AuthProvider, useAuth } = createTestAuth(); + function Display() { + const { user, isAuthenticated, isLoading } = useAuth(); + return ( +
+ {String(isAuthenticated)} + {String(isLoading)} + {user ? user.email : 'none'} +
+ ); + } + render( + + + + ); + expect(screen.getByTestId('auth').textContent).toBe('false'); + expect(screen.getByTestId('loading').textContent).toBe('false'); + expect(screen.getByTestId('user').textContent).toBe('none'); + }); + + it('restores user from localStorage on mount', () => { + const storedUser: TestUser = { email: 'a@b.com', name: 'Stored', role: 'user' }; + store['test_auth_user'] = JSON.stringify(storedUser); + + const { AuthProvider, useAuth } = createTestAuth(); + function Display() { + const { user, isAuthenticated } = useAuth(); + return ( +
+ {String(isAuthenticated)} + {user?.email ?? 'none'} +
+ ); + } + render( + + + + ); + expect(screen.getByTestId('auth').textContent).toBe('true'); + expect(screen.getByTestId('email').textContent).toBe('a@b.com'); + }); + + it('login stores user and tokens on success', async () => { + const apiResponse = { + user: { email: 'test@example.com', name: 'Test' }, + accessToken: 'at-123', + refreshToken: 'rt-456', + }; + mockFetch.mockResolvedValueOnce({ + ok: true, + json: async () => apiResponse, + headers: new Headers({ 'content-type': 'application/json' }), + status: 200, + }); + + const { AuthProvider, useAuth } = createTestAuth(); + let loginFn: (email: string, password: string) => Promise; + + function LoginComponent() { + const { login, user, isAuthenticated } = useAuth(); + loginFn = login; + return ( +
+ {String(isAuthenticated)} + {user?.email ?? 'none'} +
+ ); + } + + render( + + + + ); + + expect(screen.getByTestId('auth').textContent).toBe('false'); + + let result: boolean = false; + await act(async () => { + result = await loginFn!('test@example.com', 'pass123'); + }); + + expect(result).toBe(true); + expect(screen.getByTestId('auth').textContent).toBe('true'); + expect(screen.getByTestId('email').textContent).toBe('test@example.com'); + expect(localStorageMock.setItem).toHaveBeenCalledWith( + 'test_auth_user', + expect.stringContaining('test@example.com') + ); + expect(localStorageMock.setItem).toHaveBeenCalledWith('test_access_token', 'at-123'); + expect(localStorageMock.setItem).toHaveBeenCalledWith('test_refresh_token', 'rt-456'); + }); + + it('login returns false on API failure', async () => { + mockFetch.mockResolvedValueOnce({ + ok: false, + status: 401, + json: async () => ({ error: 'Unauthorized' }), + headers: new Headers({ 'content-type': 'application/json' }), + }); + + const { AuthProvider, useAuth } = createTestAuth(); + let loginFn: (email: string, password: string) => Promise; + + function LoginComponent() { + const { login, isAuthenticated } = useAuth(); + loginFn = login; + return {String(isAuthenticated)}; + } + + render( + + + + ); + + let result: boolean = false; + await act(async () => { + result = await loginFn!('bad@example.com', 'wrong'); + }); + + expect(result).toBe(false); + expect(screen.getByTestId('auth').textContent).toBe('false'); + }); + + it('logout clears user and storage', async () => { + store['test_auth_user'] = JSON.stringify({ email: 'a@b.com', name: 'A', role: 'admin' }); + store['test_access_token'] = 'token'; + store['test_refresh_token'] = 'refresh'; + + const onLogout = vi.fn(); + const { AuthProvider, useAuth } = createTestAuth({ onLogout }); + let logoutFn: () => void; + + function Component() { + const { logout, isAuthenticated } = useAuth(); + logoutFn = logout; + return {String(isAuthenticated)}; + } + + render( + + + + ); + + expect(screen.getByTestId('auth').textContent).toBe('true'); + + act(() => { + logoutFn!(); + }); + + expect(screen.getByTestId('auth').textContent).toBe('false'); + expect(localStorageMock.removeItem).toHaveBeenCalledWith('test_auth_user'); + expect(localStorageMock.removeItem).toHaveBeenCalledWith('test_access_token'); + expect(localStorageMock.removeItem).toHaveBeenCalledWith('test_refresh_token'); + expect(onLogout).toHaveBeenCalledOnce(); + }); + + it('useAuth throws outside AuthProvider', () => { + const { useAuth } = createTestAuth(); + function Bad() { + useAuth(); + return null; + } + expect(() => render()).toThrow('useAuth must be used within an AuthProvider'); + }); + + it('calls onLoginFallback when API fails', async () => { + mockFetch.mockRejectedValueOnce(new Error('Network error')); + + const fallbackUser: TestUser = { email: 'mock@test.com', name: 'Mock', role: 'user' }; + const onLoginFallback = vi.fn().mockResolvedValue({ + user: fallbackUser, + accessToken: 'fallback-at', + refreshToken: 'fallback-rt', + }); + + const { AuthProvider, useAuth } = createTestAuth({ onLoginFallback }); + let loginFn: (email: string, password: string) => Promise; + + function Component() { + const { login, user } = useAuth(); + loginFn = login; + return {user?.email ?? 'none'}; + } + + render( + + + + ); + + let result = false; + await act(async () => { + result = await loginFn!('mock@test.com', 'pass'); + }); + + expect(result).toBe(true); + expect(onLoginFallback).toHaveBeenCalledWith('mock@test.com', 'pass', expect.any(String)); + expect(screen.getByTestId('email').textContent).toBe('mock@test.com'); + }); + + it('uses correct storage prefix for keys', () => { + const storedUser: TestUser = { email: 'x@y.com', name: 'X', role: 'viewer' }; + store['custom_auth_user'] = JSON.stringify(storedUser); + + const { AuthProvider, useAuth } = createAuthProvider({ + storagePrefix: 'custom', + loginEndpoint: '/login', + mapLoginResponse: (d: unknown) => + d as { user: TestUser; accessToken: string; refreshToken: string }, + }); + + function Display() { + const { user } = useAuth(); + return {user?.email ?? 'none'}; + } + + render( + + + + ); + + expect(screen.getByTestId('email').textContent).toBe('x@y.com'); + }); +}); diff --git a/packages/react-auth/vitest.config.ts b/packages/react-auth/vitest.config.ts new file mode 100644 index 00000000..647a9e54 --- /dev/null +++ b/packages/react-auth/vitest.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + environment: 'jsdom', + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f6440e99..44748c5b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -43,7 +43,7 @@ importers: version: 8.55.0(eslint@9.39.2)(typescript@5.9.3) '@vitest/coverage-v8': specifier: ^3.0.0 - version: 3.2.4(vitest@3.2.4(@types/node@20.19.33)(tsx@4.21.0)(yaml@2.8.2)) + version: 3.2.4(vitest@3.2.4(@types/node@20.19.33)(jsdom@28.0.0)(tsx@4.21.0)(yaml@2.8.2)) eslint: specifier: ^9.0.0 version: 9.39.2 @@ -61,7 +61,7 @@ importers: version: 5.9.3 vitest: specifier: ^3.0.0 - version: 3.2.4(@types/node@20.19.33)(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/node@20.19.33)(jsdom@28.0.0)(tsx@4.21.0)(yaml@2.8.2) packages/api-client: {} @@ -120,9 +120,28 @@ importers: '@bytelyst/api-client': specifier: workspace:* version: link:../api-client + devDependencies: + '@testing-library/jest-dom': + specifier: ^6.9.1 + version: 6.9.1 + '@testing-library/react': + specifier: ^16.3.2 + version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@types/react': + specifier: ^19.2.14 + version: 19.2.14 + '@types/react-dom': + specifier: ^19.2.3 + version: 19.2.3(@types/react@19.2.14) + jsdom: + specifier: ^28.0.0 + version: 28.0.0 react: - specifier: '>=18.0.0' + specifier: ^19.2.4 version: 19.2.4 + react-dom: + specifier: ^19.2.4 + version: 19.2.4(react@19.2.4) services/billing-service: dependencies: @@ -171,7 +190,7 @@ importers: version: 5.9.3 vitest: specifier: ^3.0.5 - version: 3.2.4(@types/node@22.19.11)(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/node@22.19.11)(jsdom@28.0.0)(tsx@4.21.0)(yaml@2.8.2) services/growth-service: dependencies: @@ -220,7 +239,7 @@ importers: version: 5.9.3 vitest: specifier: ^3.0.5 - version: 3.2.4(@types/node@22.19.11)(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/node@22.19.11)(jsdom@28.0.0)(tsx@4.21.0)(yaml@2.8.2) services/monitoring: devDependencies: @@ -290,7 +309,7 @@ importers: version: 5.9.3 vitest: specifier: ^3.0.5 - version: 3.2.4(@types/node@22.19.11)(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/node@22.19.11)(jsdom@28.0.0)(tsx@4.21.0)(yaml@2.8.2) services/tracker-service: dependencies: @@ -342,9 +361,21 @@ importers: version: 5.9.3 vitest: specifier: ^3.0.5 - version: 3.2.4(@types/node@22.19.11)(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/node@22.19.11)(jsdom@28.0.0)(tsx@4.21.0)(yaml@2.8.2) packages: + '@acemir/cssom@0.9.31': + resolution: + { + integrity: sha512-ZnR3GSaH+/vJ0YlHau21FjfLYjMpYVIzTD8M8vIEQvIGxeOXyXdzCI140rrCY862p/C/BbzWsjc1dgnM9mkoTA==, + } + + '@adobe/css-tools@4.4.4': + resolution: + { + integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==, + } + '@ampproject/remapping@2.3.0': resolution: { @@ -352,6 +383,24 @@ packages: } engines: { node: '>=6.0.0' } + '@asamuzakjp/css-color@4.1.2': + resolution: + { + integrity: sha512-NfBUvBaYgKIuq6E/RBLY1m0IohzNHAYyaJGuTK79Z23uNwmz2jl1mPsC5ZxCCxylinKhT1Amn5oNTlx1wN8cQg==, + } + + '@asamuzakjp/dom-selector@6.7.8': + resolution: + { + integrity: sha512-stisC1nULNc9oH5lakAj8MH88ZxeGxzyWNDfbdCxvJSJIvDsHNZqYvscGTgy/ysgXWLJPt6K/4t0/GjvtKcFJQ==, + } + + '@asamuzakjp/nwsapi@2.3.9': + resolution: + { + integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==, + } + '@azure-rest/core-client@2.5.1': resolution: { @@ -474,6 +523,13 @@ packages: } engines: { node: '>=20.0.0' } + '@babel/code-frame@7.29.0': + resolution: + { + integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==, + } + engines: { node: '>=6.9.0' } + '@babel/helper-string-parser@7.27.1': resolution: { @@ -496,6 +552,13 @@ packages: engines: { node: '>=6.0.0' } hasBin: true + '@babel/runtime@7.28.6': + resolution: + { + integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==, + } + engines: { node: '>=6.9.0' } + '@babel/types@7.29.0': resolution: { @@ -510,6 +573,55 @@ packages: } engines: { node: '>=18' } + '@csstools/color-helpers@6.0.1': + resolution: + { + integrity: sha512-NmXRccUJMk2AWA5A7e5a//3bCIMyOu2hAtdRYrhPPHjDxINuCwX1w6rnIZ4xjLcp0ayv6h8Pc3X0eJUGiAAXHQ==, + } + engines: { node: '>=20.19.0' } + + '@csstools/css-calc@3.1.0': + resolution: + { + integrity: sha512-JWouqB5za07FUA2iXZWq4gPXNGWXjRwlfwEXNr7cSsGr7OKgzhDVwkJjlsrbqSyFmDGSi1Rt7zs8ln87jX9yRg==, + } + engines: { node: '>=20.19.0' } + peerDependencies: + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 + + '@csstools/css-color-parser@4.0.1': + resolution: + { + integrity: sha512-vYwO15eRBEkeF6xjAno/KQ61HacNhfQuuU/eGwH67DplL0zD5ZixUa563phQvUelA07yDczIXdtmYojCphKJcw==, + } + engines: { node: '>=20.19.0' } + peerDependencies: + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 + + '@csstools/css-parser-algorithms@4.0.0': + resolution: + { + integrity: sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==, + } + engines: { node: '>=20.19.0' } + peerDependencies: + '@csstools/css-tokenizer': ^4.0.0 + + '@csstools/css-syntax-patches-for-csstree@1.0.27': + resolution: + { + integrity: sha512-sxP33Jwg1bviSUXAV43cVYdmjt2TLnLXNqCWl9xmxHawWVjGz/kEbdkr7F9pxJNBN2Mh+dq0crgItbW6tQvyow==, + } + + '@csstools/css-tokenizer@4.0.0': + resolution: + { + integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==, + } + engines: { node: '>=20.19.0' } + '@esbuild/aix-ppc64@0.27.3': resolution: { @@ -821,6 +933,18 @@ packages: } engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + '@exodus/bytes@1.14.1': + resolution: + { + integrity: sha512-OhkBFWI6GcRMUroChZiopRiSp2iAMvEBK47NhJooDqz1RERO4QuZIZnjP63TXX8GAiLABkYmX+fuQsdJ1dd2QQ==, + } + engines: { node: ^20.19.0 || ^22.12.0 || >=24.0.0 } + peerDependencies: + '@noble/hashes': ^1.8.0 || ^2.0.0 + peerDependenciesMeta: + '@noble/hashes': + optional: true + '@fastify/ajv-compiler@4.0.5': resolution: { @@ -1175,6 +1299,44 @@ packages: cpu: [x64] os: [win32] + '@testing-library/dom@10.4.1': + resolution: + { + integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==, + } + engines: { node: '>=18' } + + '@testing-library/jest-dom@6.9.1': + resolution: + { + integrity: sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==, + } + engines: { node: '>=14', npm: '>=6', yarn: '>=1' } + + '@testing-library/react@16.3.2': + resolution: + { + integrity: sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==, + } + engines: { node: '>=18' } + peerDependencies: + '@testing-library/dom': ^10.0.0 + '@types/react': ^18.0.0 || ^19.0.0 + '@types/react-dom': ^18.0.0 || ^19.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@types/aria-query@5.0.4': + resolution: + { + integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==, + } + '@types/bcryptjs@2.4.6': resolution: { @@ -1217,6 +1379,14 @@ packages: integrity: sha512-BH7YwL6rA93ReqeQS1c4bsPpcfOmJasG+Fkr6Y59q83f9M1WcBRHR2vM+P9eOisYRcN3ujQoiZY8uk5W+1WL8w==, } + '@types/react-dom@19.2.3': + resolution: + { + integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==, + } + peerDependencies: + '@types/react': ^19.2.0 + '@types/react@19.2.14': resolution: { @@ -1461,6 +1631,13 @@ packages: } engines: { node: '>=8' } + ansi-styles@5.2.0: + resolution: + { + integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==, + } + engines: { node: '>=10' } + ansi-styles@6.2.3: resolution: { @@ -1474,6 +1651,19 @@ packages: integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==, } + aria-query@5.3.0: + resolution: + { + integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==, + } + + aria-query@5.3.2: + resolution: + { + integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==, + } + engines: { node: '>= 0.4' } + assertion-error@2.0.1: resolution: { @@ -1519,6 +1709,12 @@ packages: } hasBin: true + bidi-js@1.0.3: + resolution: + { + integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==, + } + bintrees@1.0.2: resolution: { @@ -1660,12 +1856,39 @@ packages: } engines: { node: '>= 8' } + css-tree@3.1.0: + resolution: + { + integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==, + } + engines: { node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0 } + + css.escape@1.5.1: + resolution: + { + integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==, + } + + cssstyle@5.3.7: + resolution: + { + integrity: sha512-7D2EPVltRrsTkhpQmksIu+LxeWAIEk6wRDMJ1qljlv+CKHJM+cJLlfhWIzNA44eAsHXSNe3+vO6DW1yCYx8SuQ==, + } + engines: { node: '>=20' } + csstype@3.2.3: resolution: { integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==, } + data-urls@7.0.0: + resolution: + { + integrity: sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==, + } + engines: { node: ^20.19.0 || ^22.12.0 || >=24.0.0 } + debug@4.4.3: resolution: { @@ -1678,6 +1901,12 @@ packages: supports-color: optional: true + decimal.js@10.6.0: + resolution: + { + integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==, + } + deep-eql@5.0.2: resolution: { @@ -1698,6 +1927,18 @@ packages: } engines: { node: '>=6' } + dom-accessibility-api@0.5.16: + resolution: + { + integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==, + } + + dom-accessibility-api@0.6.3: + resolution: + { + integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==, + } + dunder-proto@1.0.1: resolution: { @@ -1729,6 +1970,13 @@ packages: integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==, } + entities@6.0.1: + resolution: + { + integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==, + } + engines: { node: '>=0.12' } + environment@1.1.0: resolution: { @@ -2119,6 +2367,13 @@ packages: } engines: { node: '>= 0.4' } + html-encoding-sniffer@6.0.0: + resolution: + { + integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==, + } + engines: { node: ^20.19.0 || ^22.12.0 || >=24.0.0 } + html-escaper@2.0.2: resolution: { @@ -2182,6 +2437,13 @@ packages: } engines: { node: '>=0.8.19' } + indent-string@4.0.0: + resolution: + { + integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==, + } + engines: { node: '>=8' } + ipaddr.js@2.3.0: resolution: { @@ -2231,6 +2493,12 @@ packages: } engines: { node: '>=0.12.0' } + is-potential-custom-element-name@1.0.1: + resolution: + { + integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==, + } + is-stream@3.0.0: resolution: { @@ -2290,6 +2558,12 @@ packages: integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==, } + js-tokens@4.0.0: + resolution: + { + integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==, + } + js-tokens@9.0.1: resolution: { @@ -2303,6 +2577,18 @@ packages: } hasBin: true + jsdom@28.0.0: + resolution: + { + integrity: sha512-KDYJgZ6T2TKdU8yBfYueq5EPG/EylMsBvCaenWMJb2OXmjgczzwveRCoJ+Hgj1lXPDyasvrgneSn4GBuR1hYyA==, + } + engines: { node: ^20.19.0 || ^22.12.0 || >=24.0.0 } + peerDependencies: + canvas: ^3.0.0 + peerDependenciesMeta: + canvas: + optional: true + json-buffer@3.0.1: resolution: { @@ -2413,6 +2699,20 @@ packages: integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==, } + lru-cache@11.2.6: + resolution: + { + integrity: sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==, + } + engines: { node: 20 || >=22 } + + lz-string@1.5.0: + resolution: + { + integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==, + } + hasBin: true + magic-string@0.30.21: resolution: { @@ -2439,6 +2739,12 @@ packages: } engines: { node: '>= 0.4' } + mdn-data@2.12.2: + resolution: + { + integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==, + } + merge-stream@2.0.0: resolution: { @@ -2466,6 +2772,13 @@ packages: } engines: { node: '>=18' } + min-indent@1.0.1: + resolution: + { + integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==, + } + engines: { node: '>=4' } + minimatch@3.1.2: resolution: { @@ -2593,6 +2906,12 @@ packages: } engines: { node: '>=6' } + parse5@8.0.0: + resolution: + { + integrity: sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==, + } + path-exists@4.0.0: resolution: { @@ -2703,6 +3022,13 @@ packages: engines: { node: '>=14' } hasBin: true + pretty-format@27.5.1: + resolution: + { + integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==, + } + engines: { node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0 } + priorityqueuejs@2.0.0: resolution: { @@ -2748,6 +3074,20 @@ packages: integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==, } + react-dom@19.2.4: + resolution: + { + integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==, + } + peerDependencies: + react: ^19.2.4 + + react-is@17.0.2: + resolution: + { + integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==, + } + react@19.2.4: resolution: { @@ -2762,6 +3102,13 @@ packages: } engines: { node: '>= 12.13.0' } + redent@3.0.0: + resolution: + { + integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==, + } + engines: { node: '>=8' } + require-from-string@2.0.2: resolution: { @@ -2830,6 +3177,19 @@ packages: } engines: { node: '>=10' } + saxes@6.0.0: + resolution: + { + integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==, + } + engines: { node: '>=v12.22.7' } + + scheduler@0.27.0: + resolution: + { + integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==, + } + secure-json-parse@4.1.0: resolution: { @@ -3007,6 +3367,13 @@ packages: } engines: { node: '>=12' } + strip-indent@3.0.0: + resolution: + { + integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==, + } + engines: { node: '>=8' } + strip-json-comments@3.1.1: resolution: { @@ -3040,6 +3407,12 @@ packages: } engines: { node: '>=8' } + symbol-tree@3.2.4: + resolution: + { + integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==, + } + tdigest@0.1.2: resolution: { @@ -3100,6 +3473,19 @@ packages: } engines: { node: '>=14.0.0' } + tldts-core@7.0.23: + resolution: + { + integrity: sha512-0g9vrtDQLrNIiCj22HSe9d4mLVG3g5ph5DZ8zCKBr4OtrspmNB6ss7hVyzArAeE88ceZocIEGkyW1Ime7fxPtQ==, + } + + tldts@7.0.23: + resolution: + { + integrity: sha512-ASdhgQIBSay0R/eXggAkQ53G4nTJqTXqC2kbaBbdDwM7SkjyZyO0OaaN1/FH7U/yCeqOHDwFO5j8+Os/IS1dXw==, + } + hasBin: true + to-regex-range@5.0.1: resolution: { @@ -3114,6 +3500,20 @@ packages: } engines: { node: '>=12' } + tough-cookie@6.0.0: + resolution: + { + integrity: sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==, + } + engines: { node: '>=16' } + + tr46@6.0.0: + resolution: + { + integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==, + } + engines: { node: '>=20' } + ts-api-utils@2.4.0: resolution: { @@ -3158,6 +3558,13 @@ packages: integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==, } + undici@7.21.0: + resolution: + { + integrity: sha512-Hn2tCQpoDt1wv23a68Ctc8Cr/BHpUSfaPYrkajTXOS9IKpxVRx/X5m1K2YkbK2ipgZgxXSgsUinl3x+2YdSSfg==, + } + engines: { node: '>=20.18.1' } + uri-js@4.4.1: resolution: { @@ -3246,6 +3653,34 @@ packages: jsdom: optional: true + w3c-xmlserializer@5.0.0: + resolution: + { + integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==, + } + engines: { node: '>=18' } + + webidl-conversions@8.0.1: + resolution: + { + integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==, + } + engines: { node: '>=20' } + + whatwg-mimetype@5.0.0: + resolution: + { + integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==, + } + engines: { node: '>=20' } + + whatwg-url@16.0.0: + resolution: + { + integrity: sha512-9CcxtEKsf53UFwkSUZjG+9vydAsFO4lFHBpJUtjBcoJOCJpKnSJNwCw813zrYJHpCJ7sgfbtOe0V5Ku7Pa1XMQ==, + } + engines: { node: ^20.19.0 || ^22.12.0 || >=24.0.0 } + which@2.0.2: resolution: { @@ -3290,6 +3725,19 @@ packages: } engines: { node: '>=18' } + xml-name-validator@5.0.0: + resolution: + { + integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==, + } + engines: { node: '>=18' } + + xmlchars@2.2.0: + resolution: + { + integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==, + } + yaml@2.8.2: resolution: { @@ -3318,11 +3766,33 @@ packages: } snapshots: + '@acemir/cssom@0.9.31': {} + + '@adobe/css-tools@4.4.4': {} + '@ampproject/remapping@2.3.0': dependencies: '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 + '@asamuzakjp/css-color@4.1.2': + dependencies: + '@csstools/css-calc': 3.1.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-color-parser': 4.0.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + lru-cache: 11.2.6 + + '@asamuzakjp/dom-selector@6.7.8': + dependencies: + '@asamuzakjp/nwsapi': 2.3.9 + bidi-js: 1.0.3 + css-tree: 3.1.0 + is-potential-custom-element-name: 1.0.1 + lru-cache: 11.2.6 + + '@asamuzakjp/nwsapi@2.3.9': {} + '@azure-rest/core-client@2.5.1': dependencies: '@azure/abort-controller': 2.1.2 @@ -3495,6 +3965,12 @@ snapshots: - '@azure/core-client' - supports-color + '@babel/code-frame@7.29.0': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + '@babel/helper-string-parser@7.27.1': {} '@babel/helper-validator-identifier@7.28.5': {} @@ -3503,6 +3979,8 @@ snapshots: dependencies: '@babel/types': 7.29.0 + '@babel/runtime@7.28.6': {} + '@babel/types@7.29.0': dependencies: '@babel/helper-string-parser': 7.27.1 @@ -3510,6 +3988,28 @@ snapshots: '@bcoe/v8-coverage@1.0.2': {} + '@csstools/color-helpers@6.0.1': {} + + '@csstools/css-calc@3.1.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/css-color-parser@4.0.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/color-helpers': 6.0.1 + '@csstools/css-calc': 3.1.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/css-syntax-patches-for-csstree@1.0.27': {} + + '@csstools/css-tokenizer@4.0.0': {} + '@esbuild/aix-ppc64@0.27.3': optional: true @@ -3638,6 +4138,8 @@ snapshots: '@eslint/core': 0.17.0 levn: 0.4.1 + '@exodus/bytes@1.14.1': {} + '@fastify/ajv-compiler@4.0.5': dependencies: ajv: 8.17.1 @@ -3800,6 +4302,38 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.57.1': optional: true + '@testing-library/dom@10.4.1': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/runtime': 7.28.6 + '@types/aria-query': 5.0.4 + aria-query: 5.3.0 + dom-accessibility-api: 0.5.16 + lz-string: 1.5.0 + picocolors: 1.1.1 + pretty-format: 27.5.1 + + '@testing-library/jest-dom@6.9.1': + dependencies: + '@adobe/css-tools': 4.4.4 + aria-query: 5.3.2 + css.escape: 1.5.1 + dom-accessibility-api: 0.6.3 + picocolors: 1.1.1 + redent: 3.0.0 + + '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@babel/runtime': 7.28.6 + '@testing-library/dom': 10.4.1 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + + '@types/aria-query@5.0.4': {} + '@types/bcryptjs@2.4.6': {} '@types/chai@5.2.3': @@ -3821,6 +4355,10 @@ snapshots: dependencies: undici-types: 6.21.0 + '@types/react-dom@19.2.3(@types/react@19.2.14)': + dependencies: + '@types/react': 19.2.14 + '@types/react@19.2.14': dependencies: csstype: 3.2.3 @@ -3924,7 +4462,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@vitest/coverage-v8@3.2.4(vitest@3.2.4(@types/node@20.19.33)(tsx@4.21.0)(yaml@2.8.2))': + '@vitest/coverage-v8@3.2.4(vitest@3.2.4(@types/node@20.19.33)(jsdom@28.0.0)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 1.0.2 @@ -3939,7 +4477,7 @@ snapshots: std-env: 3.10.0 test-exclude: 7.0.1 tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/node@20.19.33)(tsx@4.21.0)(yaml@2.8.2) + vitest: 3.2.4(@types/node@20.19.33)(jsdom@28.0.0)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - supports-color @@ -4025,10 +4563,18 @@ snapshots: dependencies: color-convert: 2.0.1 + ansi-styles@5.2.0: {} + ansi-styles@6.2.3: {} argparse@2.0.1: {} + aria-query@5.3.0: + dependencies: + dequal: 2.0.3 + + aria-query@5.3.2: {} + assertion-error@2.0.1: {} ast-v8-to-istanbul@0.3.11: @@ -4050,6 +4596,10 @@ snapshots: bcryptjs@3.0.3: {} + bidi-js@1.0.3: + dependencies: + require-from-string: 2.0.2 + bintrees@1.0.2: {} brace-expansion@1.1.12: @@ -4125,18 +4675,45 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + css-tree@3.1.0: + dependencies: + mdn-data: 2.12.2 + source-map-js: 1.2.1 + + css.escape@1.5.1: {} + + cssstyle@5.3.7: + dependencies: + '@asamuzakjp/css-color': 4.1.2 + '@csstools/css-syntax-patches-for-csstree': 1.0.27 + css-tree: 3.1.0 + lru-cache: 11.2.6 + csstype@3.2.3: {} + data-urls@7.0.0: + dependencies: + whatwg-mimetype: 5.0.0 + whatwg-url: 16.0.0 + transitivePeerDependencies: + - '@noble/hashes' + debug@4.4.3: dependencies: ms: 2.1.3 + decimal.js@10.6.0: {} + deep-eql@5.0.2: {} deep-is@0.1.4: {} dequal@2.0.3: {} + dom-accessibility-api@0.5.16: {} + + dom-accessibility-api@0.6.3: {} + dunder-proto@1.0.1: dependencies: call-bind-apply-helpers: 1.0.2 @@ -4151,6 +4728,8 @@ snapshots: emoji-regex@9.2.2: {} + entities@6.0.1: {} + environment@1.1.0: {} es-define-property@1.0.1: {} @@ -4432,6 +5011,12 @@ snapshots: dependencies: function-bind: 1.1.2 + html-encoding-sniffer@6.0.0: + dependencies: + '@exodus/bytes': 1.14.1 + transitivePeerDependencies: + - '@noble/hashes' + html-escaper@2.0.2: {} http-proxy-agent@7.0.2: @@ -4463,6 +5048,8 @@ snapshots: imurmurhash@0.1.4: {} + indent-string@4.0.0: {} + ipaddr.js@2.3.0: {} is-extglob@2.1.1: {} @@ -4481,6 +5068,8 @@ snapshots: is-number@7.0.0: {} + is-potential-custom-element-name@1.0.1: {} + is-stream@3.0.0: {} isexe@2.0.0: {} @@ -4516,12 +5105,40 @@ snapshots: js-tokens@10.0.0: {} + js-tokens@4.0.0: {} + js-tokens@9.0.1: {} js-yaml@4.1.1: dependencies: argparse: 2.0.1 + jsdom@28.0.0: + dependencies: + '@acemir/cssom': 0.9.31 + '@asamuzakjp/dom-selector': 6.7.8 + '@exodus/bytes': 1.14.1 + cssstyle: 5.3.7 + data-urls: 7.0.0 + decimal.js: 10.6.0 + html-encoding-sniffer: 6.0.0 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + is-potential-custom-element-name: 1.0.1 + parse5: 8.0.0 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 6.0.0 + undici: 7.21.0 + w3c-xmlserializer: 5.0.0 + webidl-conversions: 8.0.1 + whatwg-mimetype: 5.0.0 + whatwg-url: 16.0.0 + xml-name-validator: 5.0.0 + transitivePeerDependencies: + - '@noble/hashes' + - supports-color + json-buffer@3.0.1: {} json-schema-ref-resolver@3.0.0: @@ -4601,6 +5218,10 @@ snapshots: lru-cache@10.4.3: {} + lru-cache@11.2.6: {} + + lz-string@1.5.0: {} + magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -4617,6 +5238,8 @@ snapshots: math-intrinsics@1.1.0: {} + mdn-data@2.12.2: {} + merge-stream@2.0.0: {} micromatch@4.0.8: @@ -4628,6 +5251,8 @@ snapshots: mimic-function@5.0.1: {} + min-indent@1.0.1: {} + minimatch@3.1.2: dependencies: brace-expansion: 1.1.12 @@ -4691,6 +5316,10 @@ snapshots: dependencies: callsites: 3.1.0 + parse5@8.0.0: + dependencies: + entities: 6.0.1 + path-exists@4.0.0: {} path-key@3.1.1: {} @@ -4744,6 +5373,12 @@ snapshots: prettier@3.8.1: {} + pretty-format@27.5.1: + dependencies: + ansi-regex: 5.0.1 + ansi-styles: 5.2.0 + react-is: 17.0.2 + priorityqueuejs@2.0.0: {} process-warning@4.0.1: {} @@ -4762,10 +5397,22 @@ snapshots: quick-format-unescaped@4.0.4: {} + react-dom@19.2.4(react@19.2.4): + dependencies: + react: 19.2.4 + scheduler: 0.27.0 + + react-is@17.0.2: {} + react@19.2.4: {} real-require@0.2.0: {} + redent@3.0.0: + dependencies: + indent-string: 4.0.0 + strip-indent: 3.0.0 + require-from-string@2.0.2: {} resolve-from@4.0.0: {} @@ -4820,6 +5467,12 @@ snapshots: safe-stable-stringify@2.5.0: {} + saxes@6.0.0: + dependencies: + xmlchars: 2.2.0 + + scheduler@0.27.0: {} + secure-json-parse@4.1.0: {} semaphore@1.1.0: {} @@ -4918,6 +5571,10 @@ snapshots: strip-final-newline@3.0.0: {} + strip-indent@3.0.0: + dependencies: + min-indent: 1.0.1 + strip-json-comments@3.1.1: {} strip-literal@3.1.0: @@ -4935,6 +5592,8 @@ snapshots: dependencies: has-flag: 4.0.0 + symbol-tree@3.2.4: {} + tdigest@0.1.2: dependencies: bintrees: 1.0.2 @@ -4964,12 +5623,26 @@ snapshots: tinyspy@4.0.4: {} + tldts-core@7.0.23: {} + + tldts@7.0.23: + dependencies: + tldts-core: 7.0.23 + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 toad-cache@3.7.0: {} + tough-cookie@6.0.0: + dependencies: + tldts: 7.0.23 + + tr46@6.0.0: + dependencies: + punycode: 2.3.1 + ts-api-utils@2.4.0(typescript@5.9.3): dependencies: typescript: 5.9.3 @@ -4991,6 +5664,8 @@ snapshots: undici-types@6.21.0: {} + undici@7.21.0: {} + uri-js@4.4.1: dependencies: punycode: 2.3.1 @@ -5065,7 +5740,7 @@ snapshots: tsx: 4.21.0 yaml: 2.8.2 - vitest@3.2.4(@types/node@20.19.33)(tsx@4.21.0)(yaml@2.8.2): + vitest@3.2.4(@types/node@20.19.33)(jsdom@28.0.0)(tsx@4.21.0)(yaml@2.8.2): dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.4 @@ -5092,6 +5767,7 @@ snapshots: why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 20.19.33 + jsdom: 28.0.0 transitivePeerDependencies: - jiti - less @@ -5106,7 +5782,7 @@ snapshots: - tsx - yaml - vitest@3.2.4(@types/node@22.19.11)(tsx@4.21.0)(yaml@2.8.2): + vitest@3.2.4(@types/node@22.19.11)(jsdom@28.0.0)(tsx@4.21.0)(yaml@2.8.2): dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.4 @@ -5133,6 +5809,7 @@ snapshots: why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 22.19.11 + jsdom: 28.0.0 transitivePeerDependencies: - jiti - less @@ -5147,6 +5824,22 @@ snapshots: - tsx - yaml + w3c-xmlserializer@5.0.0: + dependencies: + xml-name-validator: 5.0.0 + + webidl-conversions@8.0.1: {} + + whatwg-mimetype@5.0.0: {} + + whatwg-url@16.0.0: + dependencies: + '@exodus/bytes': 1.14.1 + tr46: 6.0.0 + webidl-conversions: 8.0.1 + transitivePeerDependencies: + - '@noble/hashes' + which@2.0.2: dependencies: isexe: 2.0.0 @@ -5176,6 +5869,10 @@ snapshots: string-width: 7.2.0 strip-ansi: 7.1.2 + xml-name-validator@5.0.0: {} + + xmlchars@2.2.0: {} + yaml@2.8.2: {} yocto-queue@0.1.0: {}