From 931c344ddf9997fe35e8b0c9b348b9cbabef5663 Mon Sep 17 00:00:00 2001 From: Igor Loskutov Date: Thu, 5 Feb 2026 18:55:15 -0500 Subject: [PATCH] feat: add frontend test infrastructure and fix CI workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix pnpm version mismatch in test_next_server.yml (8 → auto-detect 10) - Add concurrency group to cancel stale CI runs - Remove redundant setup-node step - Update jest.config.js for jsdom + tsx support - Add meetingStatusBatcher integration test (3 tests) - Extract createMeetingStatusBatcher factory for testability --- .github/workflows/test_next_server.yml | 12 +- .../__tests__/meetingStatusBatcher.test.tsx | 220 +++++ www/app/lib/meetingStatusBatcher.ts | 36 +- www/jest.config.js | 25 +- www/package.json | 4 + www/pnpm-lock.yaml | 787 +++++++++++++++++- 6 files changed, 1043 insertions(+), 41 deletions(-) create mode 100644 www/app/lib/__tests__/meetingStatusBatcher.test.tsx diff --git a/.github/workflows/test_next_server.yml b/.github/workflows/test_next_server.yml index 892566d6..fed6b1a1 100644 --- a/.github/workflows/test_next_server.yml +++ b/.github/workflows/test_next_server.yml @@ -13,6 +13,9 @@ on: jobs: test-next-server: runs-on: ubuntu-latest + concurrency: + group: test-next-server-${{ github.ref }} + cancel-in-progress: true defaults: run: @@ -21,17 +24,12 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '20' - - name: Install pnpm uses: pnpm/action-setup@v4 with: - version: 8 + package_json_file: './www/package.json' - - name: Setup Node.js cache + - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' diff --git a/www/app/lib/__tests__/meetingStatusBatcher.test.tsx b/www/app/lib/__tests__/meetingStatusBatcher.test.tsx new file mode 100644 index 00000000..43b5a4be --- /dev/null +++ b/www/app/lib/__tests__/meetingStatusBatcher.test.tsx @@ -0,0 +1,220 @@ +import "@testing-library/jest-dom"; + +// --- Module mocks (hoisted before imports) --- + +jest.mock("../apiClient", () => ({ + client: { + GET: jest.fn(), + POST: jest.fn(), + PUT: jest.fn(), + PATCH: jest.fn(), + DELETE: jest.fn(), + use: jest.fn(), + }, + $api: { + useQuery: jest.fn(), + useMutation: jest.fn(), + }, + API_URL: "http://test", + WEBSOCKET_URL: "ws://test", + configureApiAuth: jest.fn(), +})); + +jest.mock("../AuthProvider", () => ({ + useAuth: () => ({ + status: "authenticated" as const, + accessToken: "test-token", + accessTokenExpires: Date.now() + 3600000, + user: { id: "user1", name: "Test User" }, + update: jest.fn(), + signIn: jest.fn(), + signOut: jest.fn(), + lastUserId: "user1", + }), +})); + +// Recreate the batcher with a 0ms window. setTimeout(fn, 0) defers to the next +// macrotask boundary — after all synchronous React rendering completes. All +// useQuery queryFns fire within the same macrotask, so they all queue into one +// batch before the timer fires. This is deterministic and avoids fake timers. +jest.mock("../meetingStatusBatcher", () => { + const actual = jest.requireActual("../meetingStatusBatcher"); + return { + ...actual, + meetingStatusBatcher: actual.createMeetingStatusBatcher(0), + }; +}); + +// --- Imports (after mocks) --- + +import React from "react"; +import { render, waitFor, screen } from "@testing-library/react"; +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { useRoomActiveMeetings, useRoomUpcomingMeetings } from "../apiHooks"; +import { client } from "../apiClient"; +import { ErrorProvider } from "../../(errors)/errorContext"; + +const mockClient = client as { POST: jest.Mock }; + +// --- Helpers --- + +function mockBulkStatusEndpoint( + roomData?: Record< + string, + { active_meetings: unknown[]; upcoming_events: unknown[] } + >, +) { + mockClient.POST.mockImplementation( + async (_path: string, options: { body: { room_names: string[] } }) => { + const roomNames: string[] = options.body.room_names; + const data = roomData + ? Object.fromEntries( + roomNames.map((name) => [ + name, + roomData[name] ?? { active_meetings: [], upcoming_events: [] }, + ]), + ) + : Object.fromEntries( + roomNames.map((name) => [ + name, + { active_meetings: [], upcoming_events: [] }, + ]), + ); + return { data, error: undefined, response: {} }; + }, + ); +} + +// --- Test component: renders N room cards, each using both hooks --- + +function RoomCard({ roomName }: { roomName: string }) { + const active = useRoomActiveMeetings(roomName); + const upcoming = useRoomUpcomingMeetings(roomName); + + if (active.isLoading || upcoming.isLoading) { + return
loading
; + } + + return ( +
+ {active.data?.length ?? 0} active, {upcoming.data?.length ?? 0} upcoming +
+ ); +} + +function RoomList({ roomNames }: { roomNames: string[] }) { + return ( + <> + {roomNames.map((name) => ( + + ))} + + ); +} + +function createWrapper() { + const queryClient = new QueryClient({ + defaultOptions: { + queries: { retry: false }, + }, + }); + return function Wrapper({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ); + }; +} + +// --- Tests --- + +describe("meeting status batcher integration", () => { + afterEach(() => jest.clearAllMocks()); + + it("batches multiple room queries into a single POST request", async () => { + const rooms = Array.from({ length: 10 }, (_, i) => `room-${i}`); + + mockBulkStatusEndpoint(); + + render(, { wrapper: createWrapper() }); + + await waitFor(() => { + for (const name of rooms) { + expect(screen.getByTestId(`room-${name}`)).toHaveTextContent( + "0 active, 0 upcoming", + ); + } + }); + + const postCalls = mockClient.POST.mock.calls.filter( + ([path]: [string]) => path === "/v1/rooms/meetings/bulk-status", + ); + + // Without batching this would be 20 calls (2 hooks x 10 rooms). + // With the 200ms test window, all queries land in one batch → exactly 1 POST. + expect(postCalls).toHaveLength(1); + + // The single call should contain all 10 rooms (deduplicated) + const requestedRooms: string[] = postCalls[0][1].body.room_names; + for (const name of rooms) { + expect(requestedRooms).toContain(name); + } + }); + + it("batcher fetcher returns room-specific data", async () => { + const { + meetingStatusBatcher: batcher, + } = require("../meetingStatusBatcher"); + + mockBulkStatusEndpoint({ + "room-a": { + active_meetings: [{ id: "m1", room_name: "room-a" }], + upcoming_events: [], + }, + "room-b": { + active_meetings: [], + upcoming_events: [{ id: "e1", title: "Standup" }], + }, + }); + + const [resultA, resultB] = await Promise.all([ + batcher.fetch("room-a"), + batcher.fetch("room-b"), + ]); + + expect(mockClient.POST).toHaveBeenCalledTimes(1); + expect(resultA.active_meetings).toEqual([ + { id: "m1", room_name: "room-a" }, + ]); + expect(resultA.upcoming_events).toEqual([]); + expect(resultB.active_meetings).toEqual([]); + expect(resultB.upcoming_events).toEqual([{ id: "e1", title: "Standup" }]); + }); + + it("renders room-specific meeting data through hooks", async () => { + mockBulkStatusEndpoint({ + "room-a": { + active_meetings: [{ id: "m1", room_name: "room-a" }], + upcoming_events: [], + }, + "room-b": { + active_meetings: [], + upcoming_events: [{ id: "e1", title: "Standup" }], + }, + }); + + render(, { + wrapper: createWrapper(), + }); + + await waitFor(() => { + expect(screen.getByTestId("room-room-a")).toHaveTextContent( + "1 active, 0 upcoming", + ); + expect(screen.getByTestId("room-room-b")).toHaveTextContent( + "0 active, 1 upcoming", + ); + }); + }); +}); diff --git a/www/app/lib/meetingStatusBatcher.ts b/www/app/lib/meetingStatusBatcher.ts index 4f2625ae..3bb2e29e 100644 --- a/www/app/lib/meetingStatusBatcher.ts +++ b/www/app/lib/meetingStatusBatcher.ts @@ -8,18 +8,24 @@ type MeetingStatusResult = { upcoming_events: components["schemas"]["CalendarEventResponse"][]; }; -export const meetingStatusBatcher = create({ - fetcher: async (roomNames: string[]): Promise => { - const unique = [...new Set(roomNames)]; - const { data } = await client.POST("/v1/rooms/meetings/bulk-status", { - body: { room_names: unique }, - }); - return roomNames.map((name) => ({ - roomName: name, - active_meetings: data?.[name]?.active_meetings ?? [], - upcoming_events: data?.[name]?.upcoming_events ?? [], - })); - }, - resolver: keyResolver("roomName"), - scheduler: windowScheduler(10), -}); +const BATCH_WINDOW_MS = 10; + +export function createMeetingStatusBatcher(windowMs: number = BATCH_WINDOW_MS) { + return create({ + fetcher: async (roomNames: string[]): Promise => { + const unique = [...new Set(roomNames)]; + const { data } = await client.POST("/v1/rooms/meetings/bulk-status", { + body: { room_names: unique }, + }); + return roomNames.map((name) => ({ + roomName: name, + active_meetings: data?.[name]?.active_meetings ?? [], + upcoming_events: data?.[name]?.upcoming_events ?? [], + })); + }, + resolver: keyResolver("roomName"), + scheduler: windowScheduler(windowMs), + }); +} + +export const meetingStatusBatcher = createMeetingStatusBatcher(); diff --git a/www/jest.config.js b/www/jest.config.js index d2f3247b..e526a641 100644 --- a/www/jest.config.js +++ b/www/jest.config.js @@ -1,8 +1,23 @@ module.exports = { - preset: "ts-jest", - testEnvironment: "node", + testEnvironment: "jest-environment-jsdom", roots: ["/app"], - testMatch: ["**/__tests__/**/*.test.ts"], - collectCoverage: true, - collectCoverageFrom: ["app/**/*.ts", "!app/**/*.d.ts"], + testMatch: ["**/__tests__/**/*.test.ts", "**/__tests__/**/*.test.tsx"], + collectCoverage: false, + transform: { + "^.+\\.[jt]sx?$": [ + "ts-jest", + { + tsconfig: { + jsx: "react-jsx", + module: "esnext", + moduleResolution: "bundler", + esModuleInterop: true, + strict: false, + strictNullChecks: true, + downlevelIteration: true, + lib: ["dom", "dom.iterable", "esnext"], + }, + }, + ], + }, }; diff --git a/www/package.json b/www/package.json index 6bc17a6a..59a370dc 100644 --- a/www/package.json +++ b/www/package.json @@ -62,9 +62,13 @@ "author": "Andreas ", "license": "All Rights Reserved", "devDependencies": { + "@testing-library/dom": "^10.4.1", + "@testing-library/jest-dom": "^6.9.1", + "@testing-library/react": "^16.3.2", "@types/jest": "^30.0.0", "@types/react": "18.2.20", "jest": "^30.1.3", + "jest-environment-jsdom": "^30.2.0", "openapi-typescript": "^7.9.1", "prettier": "^3.0.0", "ts-jest": "^29.4.1" diff --git a/www/pnpm-lock.yaml b/www/pnpm-lock.yaml index 59d3c8c7..9897d79e 100644 --- a/www/pnpm-lock.yaml +++ b/www/pnpm-lock.yaml @@ -137,6 +137,15 @@ importers: specifier: ^4.1.5 version: 4.1.5 devDependencies: + "@testing-library/dom": + specifier: ^10.4.1 + version: 10.4.1 + "@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@18.2.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) "@types/jest": specifier: ^30.0.0 version: 30.0.0 @@ -146,6 +155,9 @@ importers: jest: specifier: ^30.1.3 version: 30.1.3(@types/node@24.2.1)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@types/node@24.2.1)(typescript@5.9.2)) + jest-environment-jsdom: + specifier: ^30.2.0 + version: 30.2.0 openapi-typescript: specifier: ^7.9.1 version: 7.9.1(typescript@5.9.2) @@ -154,9 +166,15 @@ importers: version: 3.6.2 ts-jest: specifier: ^29.4.1 - version: 29.4.1(@babel/core@7.28.3)(@jest/transform@30.1.2)(@jest/types@30.0.5)(babel-jest@30.1.2(@babel/core@7.28.3))(jest-util@30.0.5)(jest@30.1.3(@types/node@24.2.1)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@types/node@24.2.1)(typescript@5.9.2)))(typescript@5.9.2) + version: 29.4.1(@babel/core@7.28.3)(@jest/transform@30.1.2)(@jest/types@30.2.0)(babel-jest@30.1.2(@babel/core@7.28.3))(jest-util@30.2.0)(jest@30.1.3(@types/node@24.2.1)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@types/node@24.2.1)(typescript@5.9.2)))(typescript@5.9.2) packages: + "@adobe/css-tools@4.4.4": + resolution: + { + integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==, + } + "@alloc/quick-lru@5.2.0": resolution: { @@ -180,6 +198,12 @@ packages: react: ">=18.0.0" react-dom: ">=18.0.0" + "@asamuzakjp/css-color@3.2.0": + resolution: + { + integrity: sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==, + } + "@babel/code-frame@7.27.1": resolution: { @@ -496,6 +520,49 @@ packages: } engines: { node: ">=12" } + "@csstools/color-helpers@5.1.0": + resolution: + { + integrity: sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==, + } + engines: { node: ">=18" } + + "@csstools/css-calc@2.1.4": + resolution: + { + integrity: sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==, + } + engines: { node: ">=18" } + peerDependencies: + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + + "@csstools/css-color-parser@3.1.0": + resolution: + { + integrity: sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==, + } + engines: { node: ">=18" } + peerDependencies: + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + + "@csstools/css-parser-algorithms@3.0.5": + resolution: + { + integrity: sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==, + } + engines: { node: ">=18" } + peerDependencies: + "@csstools/css-tokenizer": ^3.0.4 + + "@csstools/css-tokenizer@3.0.4": + resolution: + { + integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==, + } + engines: { node: ">=18" } + "@daily-co/daily-js@0.84.0": resolution: { @@ -1047,6 +1114,19 @@ packages: } engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + "@jest/environment-jsdom-abstract@30.2.0": + resolution: + { + integrity: sha512-kazxw2L9IPuZpQ0mEt9lu9Z98SqR74xcagANmMBU16X0lS23yPc0+S6hGLUz8kVRlomZEs/5S/Zlpqwf5yu6OQ==, + } + engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + peerDependencies: + canvas: ^3.0.0 + jsdom: "*" + peerDependenciesMeta: + canvas: + optional: true + "@jest/environment@30.1.2": resolution: { @@ -1054,6 +1134,13 @@ packages: } engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + "@jest/environment@30.2.0": + resolution: + { + integrity: sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g==, + } + engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + "@jest/expect-utils@30.1.2": resolution: { @@ -1075,6 +1162,13 @@ packages: } engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + "@jest/fake-timers@30.2.0": + resolution: + { + integrity: sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw==, + } + engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + "@jest/get-type@30.1.0": resolution: { @@ -1171,6 +1265,13 @@ packages: } engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + "@jest/types@30.2.0": + resolution: + { + integrity: sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==, + } + engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + "@jridgewell/gen-mapping@0.3.13": resolution: { @@ -2646,6 +2747,38 @@ packages: peerDependencies: react: ^18 || ^19 + "@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 + "@tsconfig/node10@1.0.12": resolution: { @@ -2676,6 +2809,12 @@ packages: integrity: sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==, } + "@types/aria-query@5.0.4": + resolution: + { + integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==, + } + "@types/babel__core@7.20.5": resolution: { @@ -2779,6 +2918,12 @@ packages: integrity: sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==, } + "@types/jsdom@21.1.7": + resolution: + { + integrity: sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA==, + } + "@types/json-schema@7.0.15": resolution: { @@ -2881,6 +3026,12 @@ packages: integrity: sha512-KHPsfX/FoVbUGbyYvk1q9MMQHLPeRZhRJZdO45Q4YjvFkv4hMNghCWTvy7rdKessBsmtz4euWCWAB6/tVpI1Iw==, } + "@types/tough-cookie@4.0.5": + resolution: + { + integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==, + } + "@types/ua-parser-js@0.7.39": resolution: { @@ -3925,6 +4076,12 @@ packages: } engines: { node: ">=10" } + aria-query@5.3.0: + resolution: + { + integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==, + } + aria-query@5.3.2: resolution: { @@ -4508,6 +4665,12 @@ packages: } engines: { node: ">= 8" } + css.escape@1.5.1: + resolution: + { + integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==, + } + cssesc@3.0.0: resolution: { @@ -4516,6 +4679,13 @@ packages: engines: { node: ">=4" } hasBin: true + cssstyle@4.6.0: + resolution: + { + integrity: sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==, + } + engines: { node: ">=18" } + csstype@3.1.3: resolution: { @@ -4528,6 +4698,13 @@ packages: integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==, } + data-urls@5.0.0: + resolution: + { + integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==, + } + engines: { node: ">=18" } + data-view-buffer@1.0.2: resolution: { @@ -4584,6 +4761,12 @@ packages: supports-color: optional: true + decimal.js@10.6.0: + resolution: + { + integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==, + } + decode-named-character-reference@1.2.0: resolution: { @@ -4715,6 +4898,18 @@ packages: } engines: { node: ">=0.10.0" } + dom-accessibility-api@0.5.16: + resolution: + { + integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==, + } + + dom-accessibility-api@0.6.3: + resolution: + { + integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==, + } + domconstants@0.1.2: resolution: { @@ -4798,6 +4993,13 @@ packages: } engines: { node: ">=10.13.0" } + entities@6.0.1: + resolution: + { + integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==, + } + engines: { node: ">=0.12" } + err-code@3.0.1: resolution: { @@ -5568,6 +5770,13 @@ packages: integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==, } + html-encoding-sniffer@4.0.0: + resolution: + { + integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==, + } + engines: { node: ">=18" } + html-escaper@2.0.2: resolution: { @@ -5580,6 +5789,13 @@ packages: integrity: sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==, } + http-proxy-agent@7.0.2: + resolution: + { + integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==, + } + engines: { node: ">= 14" } + https-proxy-agent@5.0.1: resolution: { @@ -5607,6 +5823,13 @@ packages: integrity: sha512-IvLy8MzHTSJ0fDpSzrb8rcdnla6yROEmNBSxInEMyIFu2DQkbmpadTf6B4fHvnytN6iHL2gGwpe5/jHL3wMi+A==, } + iconv-lite@0.6.3: + resolution: + { + integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==, + } + engines: { node: ">=0.10.0" } + ieee754@1.2.1: resolution: { @@ -5667,6 +5890,13 @@ packages: } engines: { node: ">=0.8.19" } + indent-string@4.0.0: + resolution: + { + integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==, + } + engines: { node: ">=8" } + index-to-position@1.1.0: resolution: { @@ -5903,6 +6133,12 @@ packages: } engines: { node: ">=12" } + is-potential-custom-element-name@1.0.1: + resolution: + { + integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==, + } + is-reference@1.2.1: resolution: { @@ -6111,6 +6347,18 @@ packages: } engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + jest-environment-jsdom@30.2.0: + resolution: + { + integrity: sha512-zbBTiqr2Vl78pKp/laGBREYzbZx9ZtqPjOK4++lL4BNDhxRnahg51HtoDrk9/VjIy9IthNEWdKVd7H5bqBhiWQ==, + } + engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + peerDependencies: + canvas: ^3.0.0 + peerDependenciesMeta: + canvas: + optional: true + jest-environment-node@30.1.2: resolution: { @@ -6146,6 +6394,13 @@ packages: } engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + jest-message-util@30.2.0: + resolution: + { + integrity: sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==, + } + engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + jest-mock@30.0.5: resolution: { @@ -6153,6 +6408,13 @@ packages: } engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + jest-mock@30.2.0: + resolution: + { + integrity: sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw==, + } + engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + jest-pnp-resolver@1.2.3: resolution: { @@ -6221,6 +6483,13 @@ packages: } engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + jest-util@30.2.0: + resolution: + { + integrity: sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==, + } + engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + jest-validate@30.1.0: resolution: { @@ -6315,6 +6584,18 @@ packages: integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==, } + jsdom@26.1.0: + resolution: + { + integrity: sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==, + } + engines: { node: ">=18" } + peerDependencies: + canvas: ^3.0.0 + peerDependenciesMeta: + canvas: + optional: true + jsesc@3.1.0: resolution: { @@ -6512,6 +6793,13 @@ packages: peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + lz-string@1.5.0: + resolution: + { + integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==, + } + hasBin: true + magic-string@0.30.19: resolution: { @@ -6773,6 +7061,13 @@ packages: } engines: { node: ">=6" } + min-indent@1.0.1: + resolution: + { + integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==, + } + engines: { node: ">=4" } + minimatch@3.1.2: resolution: { @@ -7000,6 +7295,12 @@ packages: react-router-dom: optional: true + nwsapi@2.2.23: + resolution: + { + integrity: sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==, + } + oauth@0.9.15: resolution: { @@ -7214,6 +7515,12 @@ packages: } engines: { node: ">=18" } + parse5@7.3.0: + resolution: + { + integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==, + } + path-exists@4.0.0: resolution: { @@ -7462,6 +7769,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 } + pretty-format@3.8.0: resolution: { @@ -7475,6 +7789,13 @@ packages: } engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + pretty-format@30.2.0: + resolution: + { + integrity: sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==, + } + engines: { node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 } + progress@2.0.3: resolution: { @@ -7574,6 +7895,12 @@ packages: integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==, } + react-is@17.0.2: + resolution: + { + integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==, + } + react-is@18.3.1: resolution: { @@ -7688,6 +8015,13 @@ packages: } engines: { node: ">= 14.18.0" } + redent@3.0.0: + resolution: + { + integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==, + } + engines: { node: ">=8" } + redis-errors@1.2.0: resolution: { @@ -7852,6 +8186,12 @@ packages: engines: { node: ">=18.0.0", npm: ">=8.0.0" } hasBin: true + rrweb-cssom@0.8.0: + resolution: + { + integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==, + } + rtcstats@https://codeload.github.com/whereby/rtcstats/tar.gz/63bcb6420d76d34161b39e494524ae73aa6dd70d: resolution: { @@ -7899,6 +8239,12 @@ packages: } engines: { node: ">= 0.4" } + safer-buffer@2.1.2: + resolution: + { + integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==, + } + sass@1.90.0: resolution: { @@ -7907,6 +8253,13 @@ packages: engines: { node: ">=14.0.0" } hasBin: true + saxes@6.0.0: + resolution: + { + integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==, + } + engines: { node: ">=v12.22.7" } + scheduler@0.23.2: resolution: { @@ -8271,6 +8624,13 @@ packages: } engines: { node: ">=6" } + strip-indent@3.0.0: + resolution: + { + integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==, + } + engines: { node: ">=8" } + strip-json-comments@3.1.1: resolution: { @@ -8355,6 +8715,12 @@ packages: } engines: { node: ">= 0.4" } + symbol-tree@3.2.4: + resolution: + { + integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==, + } + synckit@0.11.11: resolution: { @@ -8431,6 +8797,19 @@ packages: } engines: { node: ">=12.0.0" } + tldts-core@6.1.86: + resolution: + { + integrity: sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==, + } + + tldts@6.1.86: + resolution: + { + integrity: sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==, + } + hasBin: true + tmpl@1.0.5: resolution: { @@ -8444,12 +8823,26 @@ packages: } engines: { node: ">=8.0" } + tough-cookie@5.1.2: + resolution: + { + integrity: sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==, + } + engines: { node: ">=16" } + tr46@0.0.3: resolution: { integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==, } + tr46@5.1.1: + resolution: + { + integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==, + } + engines: { node: ">=18" } + trim-lines@3.0.1: resolution: { @@ -8849,6 +9242,13 @@ packages: integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==, } + w3c-xmlserializer@5.0.0: + resolution: + { + integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==, + } + engines: { node: ">=18" } + walker@1.0.8: resolution: { @@ -8874,6 +9274,13 @@ packages: integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==, } + webidl-conversions@7.0.0: + resolution: + { + integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==, + } + engines: { node: ">=12" } + webpack-sources@3.3.3: resolution: { @@ -8907,6 +9314,28 @@ packages: } engines: { node: ">=6.0.0", npm: ">=3.10.0" } + whatwg-encoding@3.1.1: + resolution: + { + integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==, + } + engines: { node: ">=18" } + deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation + + whatwg-mimetype@4.0.0: + resolution: + { + integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==, + } + engines: { node: ">=18" } + + whatwg-url@14.2.0: + resolution: + { + integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==, + } + engines: { node: ">=18" } + whatwg-url@5.0.0: resolution: { @@ -9004,6 +9433,34 @@ packages: utf-8-validate: optional: true + ws@8.19.0: + resolution: + { + integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==, + } + engines: { node: ">=10.0.0" } + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ">=5.0.2" + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + xml-name-validator@5.0.0: + resolution: + { + integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==, + } + engines: { node: ">=18" } + + xmlchars@2.2.0: + resolution: + { + integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==, + } + xmlhttprequest-ssl@2.0.0: resolution: { @@ -9099,6 +9556,8 @@ packages: } snapshots: + "@adobe/css-tools@4.4.4": {} + "@alloc/quick-lru@5.2.0": {} "@ampproject/remapping@2.3.0": @@ -9170,6 +9629,14 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) + "@asamuzakjp/css-color@3.2.0": + dependencies: + "@csstools/css-calc": 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + "@csstools/css-color-parser": 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + "@csstools/css-parser-algorithms": 3.0.5(@csstools/css-tokenizer@3.0.4) + "@csstools/css-tokenizer": 3.0.4 + lru-cache: 10.4.3 + "@babel/code-frame@7.27.1": dependencies: "@babel/helper-validator-identifier": 7.27.1 @@ -9404,6 +9871,26 @@ snapshots: "@jridgewell/trace-mapping": 0.3.9 optional: true + "@csstools/color-helpers@5.1.0": {} + + "@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)": + dependencies: + "@csstools/css-parser-algorithms": 3.0.5(@csstools/css-tokenizer@3.0.4) + "@csstools/css-tokenizer": 3.0.4 + + "@csstools/css-color-parser@3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)": + dependencies: + "@csstools/color-helpers": 5.1.0 + "@csstools/css-calc": 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + "@csstools/css-parser-algorithms": 3.0.5(@csstools/css-tokenizer@3.0.4) + "@csstools/css-tokenizer": 3.0.4 + + "@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4)": + dependencies: + "@csstools/css-tokenizer": 3.0.4 + + "@csstools/css-tokenizer@3.0.4": {} + "@daily-co/daily-js@0.84.0": dependencies: "@babel/runtime": 7.28.2 @@ -9769,13 +10256,31 @@ snapshots: "@jest/diff-sequences@30.0.1": {} + "@jest/environment-jsdom-abstract@30.2.0(jsdom@26.1.0)": + dependencies: + "@jest/environment": 30.2.0 + "@jest/fake-timers": 30.2.0 + "@jest/types": 30.2.0 + "@types/jsdom": 21.1.7 + "@types/node": 25.0.2 + jest-mock: 30.2.0 + jest-util: 30.2.0 + jsdom: 26.1.0 + "@jest/environment@30.1.2": dependencies: "@jest/fake-timers": 30.1.2 "@jest/types": 30.0.5 - "@types/node": 24.2.1 + "@types/node": 25.0.2 jest-mock: 30.0.5 + "@jest/environment@30.2.0": + dependencies: + "@jest/fake-timers": 30.2.0 + "@jest/types": 30.2.0 + "@types/node": 25.0.2 + jest-mock: 30.2.0 + "@jest/expect-utils@30.1.2": dependencies: "@jest/get-type": 30.1.0 @@ -9791,11 +10296,20 @@ snapshots: dependencies: "@jest/types": 30.0.5 "@sinonjs/fake-timers": 13.0.5 - "@types/node": 24.2.1 + "@types/node": 25.0.2 jest-message-util: 30.1.0 jest-mock: 30.0.5 jest-util: 30.0.5 + "@jest/fake-timers@30.2.0": + dependencies: + "@jest/types": 30.2.0 + "@sinonjs/fake-timers": 13.0.5 + "@types/node": 25.0.2 + jest-message-util: 30.2.0 + jest-mock: 30.2.0 + jest-util: 30.2.0 + "@jest/get-type@30.1.0": {} "@jest/globals@30.1.2": @@ -9914,6 +10428,16 @@ snapshots: "@types/yargs": 17.0.33 chalk: 4.1.2 + "@jest/types@30.2.0": + dependencies: + "@jest/pattern": 30.0.1 + "@jest/schemas": 30.0.5 + "@types/istanbul-lib-coverage": 2.0.6 + "@types/istanbul-reports": 3.0.4 + "@types/node": 25.0.2 + "@types/yargs": 17.0.33 + chalk: 4.1.2 + "@jridgewell/gen-mapping@0.3.13": dependencies: "@jridgewell/sourcemap-codec": 1.5.5 @@ -10903,6 +11427,35 @@ snapshots: "@tanstack/query-core": 5.85.9 react: 18.3.1 + "@testing-library/dom@10.4.1": + dependencies: + "@babel/code-frame": 7.27.1 + "@babel/runtime": 7.28.2 + "@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@18.2.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)": + dependencies: + "@babel/runtime": 7.28.2 + "@testing-library/dom": 10.4.1 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + "@types/react": 18.2.20 + "@tsconfig/node10@1.0.12": optional: true @@ -10920,6 +11473,8 @@ snapshots: tslib: 2.8.1 optional: true + "@types/aria-query@5.0.4": {} + "@types/babel__core@7.20.5": dependencies: "@babel/parser": 7.28.0 @@ -10943,7 +11498,7 @@ snapshots: "@types/connect@3.4.38": dependencies: - "@types/node": 24.2.1 + "@types/node": 25.0.2 "@types/debug@4.1.12": dependencies: @@ -10992,6 +11547,12 @@ snapshots: expect: 30.1.2 pretty-format: 30.0.5 + "@types/jsdom@21.1.7": + dependencies: + "@types/node": 25.0.2 + "@types/tough-cookie": 4.0.5 + parse5: 7.3.0 + "@types/json-schema@7.0.15": {} "@types/json5@0.0.29": {} @@ -11004,11 +11565,11 @@ snapshots: "@types/mysql@2.15.27": dependencies: - "@types/node": 24.2.1 + "@types/node": 25.0.2 "@types/node-fetch@2.6.13": dependencies: - "@types/node": 24.2.1 + "@types/node": 25.0.2 form-data: 4.0.4 "@types/node@24.2.1": @@ -11027,7 +11588,7 @@ snapshots: "@types/pg@8.15.4": dependencies: - "@types/node": 24.2.1 + "@types/node": 25.0.2 pg-protocol: 1.10.3 pg-types: 2.2.0 @@ -11047,7 +11608,9 @@ snapshots: "@types/tedious@4.0.14": dependencies: - "@types/node": 24.2.1 + "@types/node": 25.0.2 + + "@types/tough-cookie@4.0.5": {} "@types/ua-parser-js@0.7.39": {} @@ -11961,6 +12524,10 @@ snapshots: dependencies: tslib: 2.8.1 + aria-query@5.3.0: + dependencies: + dequal: 2.0.3 + aria-query@5.3.2: {} array-buffer-byte-length@1.0.2: @@ -12326,12 +12893,24 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + css.escape@1.5.1: {} + cssesc@3.0.0: {} + cssstyle@4.6.0: + dependencies: + "@asamuzakjp/css-color": 3.2.0 + rrweb-cssom: 0.8.0 + csstype@3.1.3: {} damerau-levenshtein@1.0.8: {} + data-urls@5.0.0: + dependencies: + whatwg-mimetype: 4.0.0 + whatwg-url: 14.2.0 + data-view-buffer@1.0.2: dependencies: call-bound: 1.0.4 @@ -12370,6 +12949,8 @@ snapshots: optionalDependencies: supports-color: 9.4.0 + decimal.js@10.6.0: {} + decode-named-character-reference@1.2.0: dependencies: character-entities: 2.0.2 @@ -12427,6 +13008,10 @@ snapshots: dependencies: esutils: 2.0.3 + dom-accessibility-api@0.5.16: {} + + dom-accessibility-api@0.6.3: {} + domconstants@0.1.2: {} domsanitizer@0.2.3: @@ -12480,6 +13065,8 @@ snapshots: graceful-fs: 4.2.11 tapable: 2.3.0 + entities@6.0.1: {} + err-code@3.0.1: {} error-ex@1.3.2: @@ -13109,10 +13696,21 @@ snapshots: dependencies: react-is: 16.13.1 + html-encoding-sniffer@4.0.0: + dependencies: + whatwg-encoding: 3.1.1 + html-escaper@2.0.2: {} html-url-attributes@3.0.1: {} + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.4 + debug: 4.4.1(supports-color@9.4.0) + transitivePeerDependencies: + - supports-color + https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 @@ -13120,6 +13718,13 @@ snapshots: transitivePeerDependencies: - supports-color + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.4 + debug: 4.4.1(supports-color@9.4.0) + transitivePeerDependencies: + - supports-color + https-proxy-agent@7.0.6(supports-color@10.2.0): dependencies: agent-base: 7.1.4 @@ -13131,6 +13736,10 @@ snapshots: hyperhtml-style@0.1.3: {} + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + ieee754@1.2.1: {} ignore@5.3.2: {} @@ -13160,6 +13769,8 @@ snapshots: imurmurhash@0.1.4: {} + indent-string@4.0.0: {} + index-to-position@1.1.0: {} inflight@1.0.6: @@ -13297,6 +13908,8 @@ snapshots: is-plain-obj@4.1.0: {} + is-potential-custom-element-name@1.0.1: {} + is-reference@1.2.1: dependencies: "@types/estree": 1.0.8 @@ -13406,7 +14019,7 @@ snapshots: "@jest/expect": 30.1.2 "@jest/test-result": 30.1.3 "@jest/types": 30.0.5 - "@types/node": 24.2.1 + "@types/node": 25.0.2 chalk: 4.1.2 co: 4.6.0 dedent: 1.7.0(babel-plugin-macros@3.1.0) @@ -13497,12 +14110,24 @@ snapshots: jest-util: 30.0.5 pretty-format: 30.0.5 + jest-environment-jsdom@30.2.0: + dependencies: + "@jest/environment": 30.2.0 + "@jest/environment-jsdom-abstract": 30.2.0(jsdom@26.1.0) + "@types/jsdom": 21.1.7 + "@types/node": 25.0.2 + jsdom: 26.1.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + jest-environment-node@30.1.2: dependencies: "@jest/environment": 30.1.2 "@jest/fake-timers": 30.1.2 "@jest/types": 30.0.5 - "@types/node": 24.2.1 + "@types/node": 25.0.2 jest-mock: 30.0.5 jest-util: 30.0.5 jest-validate: 30.1.0 @@ -13546,12 +14171,30 @@ snapshots: slash: 3.0.0 stack-utils: 2.0.6 + jest-message-util@30.2.0: + dependencies: + "@babel/code-frame": 7.27.1 + "@jest/types": 30.2.0 + "@types/stack-utils": 2.0.3 + chalk: 4.1.2 + graceful-fs: 4.2.11 + micromatch: 4.0.8 + pretty-format: 30.2.0 + slash: 3.0.0 + stack-utils: 2.0.6 + jest-mock@30.0.5: dependencies: "@jest/types": 30.0.5 "@types/node": 24.2.1 jest-util: 30.0.5 + jest-mock@30.2.0: + dependencies: + "@jest/types": 30.2.0 + "@types/node": 25.0.2 + jest-util: 30.2.0 + jest-pnp-resolver@1.2.3(jest-resolve@30.1.3): optionalDependencies: jest-resolve: 30.1.3 @@ -13674,6 +14317,15 @@ snapshots: graceful-fs: 4.2.11 picomatch: 4.0.3 + jest-util@30.2.0: + dependencies: + "@jest/types": 30.2.0 + "@types/node": 25.0.2 + chalk: 4.1.2 + ci-info: 4.3.0 + graceful-fs: 4.2.11 + picomatch: 4.0.3 + jest-validate@30.1.0: dependencies: "@jest/get-type": 30.1.0 @@ -13709,7 +14361,7 @@ snapshots: jest-worker@30.1.0: dependencies: - "@types/node": 24.2.1 + "@types/node": 25.0.2 "@ungap/structured-clone": 1.3.0 jest-util: 30.0.5 merge-stream: 2.0.0 @@ -13747,6 +14399,33 @@ snapshots: jsbn@1.1.0: {} + jsdom@26.1.0: + dependencies: + cssstyle: 4.6.0 + data-urls: 5.0.0 + decimal.js: 10.6.0 + html-encoding-sniffer: 4.0.0 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + is-potential-custom-element-name: 1.0.1 + nwsapi: 2.2.23 + parse5: 7.3.0 + rrweb-cssom: 0.8.0 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 5.1.2 + w3c-xmlserializer: 5.0.0 + webidl-conversions: 7.0.0 + whatwg-encoding: 3.1.1 + whatwg-mimetype: 4.0.0 + whatwg-url: 14.2.0 + ws: 8.19.0 + xml-name-validator: 5.0.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + jsesc@3.1.0: {} json-buffer@3.0.1: {} @@ -13843,6 +14522,8 @@ snapshots: dependencies: react: 18.3.1 + lz-string@1.5.0: {} + magic-string@0.30.19: dependencies: "@jridgewell/sourcemap-codec": 1.5.5 @@ -14118,6 +14799,8 @@ snapshots: mimic-fn@2.1.0: {} + min-indent@1.0.1: {} + minimatch@3.1.2: dependencies: brace-expansion: 1.1.12 @@ -14233,6 +14916,8 @@ snapshots: optionalDependencies: next: 15.5.9(@babel/core@7.28.3)(@opentelemetry/api@1.9.0)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.90.0) + nwsapi@2.2.23: {} + oauth@0.9.15: {} object-assign@4.1.1: {} @@ -14382,6 +15067,10 @@ snapshots: index-to-position: 1.1.0 type-fest: 4.41.0 + parse5@7.3.0: + dependencies: + entities: 6.0.1 + path-exists@4.0.0: {} path-is-absolute@1.0.1: {} @@ -14494,6 +15183,12 @@ snapshots: prettier@3.6.2: {} + pretty-format@27.5.1: + dependencies: + ansi-regex: 5.0.1 + ansi-styles: 5.2.0 + react-is: 17.0.2 + pretty-format@3.8.0: {} pretty-format@30.0.5: @@ -14502,6 +15197,12 @@ snapshots: ansi-styles: 5.2.0 react-is: 18.3.1 + pretty-format@30.2.0: + dependencies: + "@jest/schemas": 30.0.5 + ansi-styles: 5.2.0 + react-is: 18.3.1 + progress@2.0.3: {} prop-types@15.8.1: @@ -14550,6 +15251,8 @@ snapshots: react-is@16.13.1: {} + react-is@17.0.2: {} + react-is@18.3.1: {} react-markdown@9.1.0(@types/react@18.2.20)(react@18.3.1): @@ -14634,6 +15337,11 @@ snapshots: readdirp@4.1.2: {} + redent@3.0.0: + dependencies: + indent-string: 4.0.0 + strip-indent: 3.0.0 + redis-errors@1.2.0: {} redis-parser@3.0.0: @@ -14764,6 +15472,8 @@ snapshots: "@rollup/rollup-win32-x64-msvc": 4.50.1 fsevents: 2.3.3 + rrweb-cssom@0.8.0: {} + rtcstats@https://codeload.github.com/whereby/rtcstats/tar.gz/63bcb6420d76d34161b39e494524ae73aa6dd70d: {} @@ -14794,6 +15504,8 @@ snapshots: es-errors: 1.3.0 is-regex: 1.2.1 + safer-buffer@2.1.2: {} + sass@1.90.0: dependencies: chokidar: 4.0.3 @@ -14802,6 +15514,10 @@ snapshots: optionalDependencies: "@parcel/watcher": 2.5.1 + saxes@6.0.0: + dependencies: + xmlchars: 2.2.0 + scheduler@0.23.2: dependencies: loose-envify: 1.4.0 @@ -15083,6 +15799,10 @@ snapshots: strip-final-newline@2.0.0: {} + strip-indent@3.0.0: + dependencies: + min-indent: 1.0.1 + strip-json-comments@3.1.1: {} style-to-js@1.1.17: @@ -15127,6 +15847,8 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} + symbol-tree@3.2.4: {} + synckit@0.11.11: dependencies: "@pkgr/core": 0.2.9 @@ -15195,14 +15917,28 @@ snapshots: fdir: 6.4.6(picomatch@4.0.3) picomatch: 4.0.3 + tldts-core@6.1.86: {} + + tldts@6.1.86: + dependencies: + tldts-core: 6.1.86 + tmpl@1.0.5: {} to-regex-range@5.0.1: dependencies: is-number: 7.0.0 + tough-cookie@5.1.2: + dependencies: + tldts: 6.1.86 + tr46@0.0.3: {} + tr46@5.1.1: + dependencies: + punycode: 2.3.1 + trim-lines@3.0.1: {} trough@2.2.0: {} @@ -15213,7 +15949,7 @@ snapshots: ts-interface-checker@0.1.13: {} - ts-jest@29.4.1(@babel/core@7.28.3)(@jest/transform@30.1.2)(@jest/types@30.0.5)(babel-jest@30.1.2(@babel/core@7.28.3))(jest-util@30.0.5)(jest@30.1.3(@types/node@24.2.1)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@types/node@24.2.1)(typescript@5.9.2)))(typescript@5.9.2): + ts-jest@29.4.1(@babel/core@7.28.3)(@jest/transform@30.1.2)(@jest/types@30.2.0)(babel-jest@30.1.2(@babel/core@7.28.3))(jest-util@30.2.0)(jest@30.1.3(@types/node@24.2.1)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@types/node@24.2.1)(typescript@5.9.2)))(typescript@5.9.2): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 @@ -15229,9 +15965,9 @@ snapshots: optionalDependencies: "@babel/core": 7.28.3 "@jest/transform": 30.1.2 - "@jest/types": 30.0.5 + "@jest/types": 30.2.0 babel-jest: 30.1.2(@babel/core@7.28.3) - jest-util: 30.0.5 + jest-util: 30.2.0 ts-node@10.9.1(@types/node@24.2.1)(typescript@5.9.2): dependencies: @@ -15474,6 +16210,10 @@ snapshots: "@types/unist": 3.0.3 vfile-message: 4.0.3 + w3c-xmlserializer@5.0.0: + dependencies: + xml-name-validator: 5.0.0 + walker@1.0.8: dependencies: makeerror: 1.0.12 @@ -15487,6 +16227,8 @@ snapshots: webidl-conversions@3.0.1: {} + webidl-conversions@7.0.0: {} + webpack-sources@3.3.3: {} webpack-virtual-modules@0.5.0: {} @@ -15527,6 +16269,17 @@ snapshots: dependencies: sdp: 3.2.1 + whatwg-encoding@3.1.1: + dependencies: + iconv-lite: 0.6.3 + + whatwg-mimetype@4.0.0: {} + + whatwg-url@14.2.0: + dependencies: + tr46: 5.1.1 + webidl-conversions: 7.0.0 + whatwg-url@5.0.0: dependencies: tr46: 0.0.3 @@ -15602,6 +16355,12 @@ snapshots: ws@8.17.1: {} + ws@8.19.0: {} + + xml-name-validator@5.0.0: {} + + xmlchars@2.2.0: {} + xmlhttprequest-ssl@2.0.0: {} xtend@4.0.2: {}