From 083a50cbcd1956fe8e8be36827ddd85539b67a6b Mon Sep 17 00:00:00 2001 From: Igor Loskutov Date: Thu, 5 Feb 2026 20:04:31 -0500 Subject: [PATCH] fix: batch room meeting status queries via prop-drilling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Alternative to the batcher approach (#848): parent fetches all room meeting statuses in a single bulk POST and passes data down as props. No extra dependency (@yornaath/batshit), no implicit batching magic. Backend: POST /v1/rooms/meetings/bulk-status + bulk DB methods. Frontend: useRoomsBulkMeetingStatus hook in RoomList, MeetingStatus receives data as props instead of calling per-room hooks. CI: fix pnpm 8→10 auto-detect, add concurrency group. Tests: Jest+jsdom+testing-library for bulk hook. --- .github/workflows/test_next_server.yml | 14 +- server/reflector/db/calendar_events.py | 20 + server/reflector/db/meetings.py | 17 + server/reflector/db/rooms.py | 5 + server/reflector/views/rooms.py | 68 +- www/app/(app)/rooms/_components/RoomList.tsx | 11 + www/app/(app)/rooms/_components/RoomTable.tsx | 38 +- .../lib/__tests__/bulkMeetingStatus.test.tsx | 197 +++++ www/app/lib/apiHooks.ts | 58 +- www/app/reflector-api.d.ts | 64 ++ www/jest.config.js | 24 +- www/package.json | 4 + www/pnpm-lock.yaml | 787 +++++++++++++++++- 13 files changed, 1253 insertions(+), 54 deletions(-) create mode 100644 www/app/lib/__tests__/bulkMeetingStatus.test.tsx diff --git a/.github/workflows/test_next_server.yml b/.github/workflows/test_next_server.yml index 892566d6..0e7d01f4 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' @@ -42,4 +40,4 @@ jobs: run: pnpm install - name: Run tests - run: pnpm test \ No newline at end of file + run: pnpm test diff --git a/server/reflector/db/calendar_events.py b/server/reflector/db/calendar_events.py index 3eddc3f1..07cc6499 100644 --- a/server/reflector/db/calendar_events.py +++ b/server/reflector/db/calendar_events.py @@ -104,6 +104,26 @@ class CalendarEventController: results = await get_database().fetch_all(query) return [CalendarEvent(**result) for result in results] + async def get_upcoming_for_rooms( + self, room_ids: list[str], minutes_ahead: int = 120 + ) -> list[CalendarEvent]: + now = datetime.now(timezone.utc) + future_time = now + timedelta(minutes=minutes_ahead) + query = ( + calendar_events.select() + .where( + sa.and_( + calendar_events.c.room_id.in_(room_ids), + calendar_events.c.is_deleted == False, + calendar_events.c.start_time <= future_time, + calendar_events.c.end_time >= now, + ) + ) + .order_by(calendar_events.c.start_time.asc()) + ) + results = await get_database().fetch_all(query) + return [CalendarEvent(**result) for result in results] + async def get_by_id(self, event_id: str) -> CalendarEvent | None: query = calendar_events.select().where(calendar_events.c.id == event_id) result = await get_database().fetch_one(query) diff --git a/server/reflector/db/meetings.py b/server/reflector/db/meetings.py index 02f407b2..89fe3d74 100644 --- a/server/reflector/db/meetings.py +++ b/server/reflector/db/meetings.py @@ -301,6 +301,23 @@ class MeetingController: results = await get_database().fetch_all(query) return [Meeting(**result) for result in results] + async def get_all_active_for_rooms( + self, room_ids: list[str], current_time: datetime + ) -> list[Meeting]: + query = ( + meetings.select() + .where( + sa.and_( + meetings.c.room_id.in_(room_ids), + meetings.c.end_date > current_time, + meetings.c.is_active, + ) + ) + .order_by(meetings.c.end_date.desc()) + ) + results = await get_database().fetch_all(query) + return [Meeting(**result) for result in results] + async def get_active_by_calendar_event( self, room: Room, calendar_event_id: str, current_time: datetime ) -> Meeting | None: diff --git a/server/reflector/db/rooms.py b/server/reflector/db/rooms.py index 8228144c..308817f0 100644 --- a/server/reflector/db/rooms.py +++ b/server/reflector/db/rooms.py @@ -245,6 +245,11 @@ class RoomController: return room + async def get_by_names(self, names: list[str]) -> list[Room]: + query = rooms.select().where(rooms.c.name.in_(names)) + results = await get_database().fetch_all(query) + return [Room(**r) for r in results] + async def get_ics_enabled(self) -> list[Room]: query = rooms.select().where( rooms.c.ics_enabled == True, rooms.c.ics_url != None diff --git a/server/reflector/views/rooms.py b/server/reflector/views/rooms.py index 11e668c0..f461ee56 100644 --- a/server/reflector/views/rooms.py +++ b/server/reflector/views/rooms.py @@ -1,4 +1,6 @@ +import asyncio import logging +from collections import defaultdict from datetime import datetime, timedelta, timezone from enum import Enum from typing import Annotated, Any, Literal, Optional @@ -6,13 +8,14 @@ from typing import Annotated, Any, Literal, Optional from fastapi import APIRouter, Depends, HTTPException from fastapi_pagination import Page from fastapi_pagination.ext.databases import apaginate -from pydantic import BaseModel +from pydantic import BaseModel, Field from redis.exceptions import LockError import reflector.auth as auth from reflector.db import get_database from reflector.db.calendar_events import calendar_events_controller from reflector.db.meetings import meetings_controller +from reflector.db.rooms import Room as DbRoom from reflector.db.rooms import rooms_controller from reflector.redis_cache import RedisAsyncLock from reflector.schemas.platform import Platform @@ -195,6 +198,69 @@ async def rooms_list( return paginated +class BulkStatusRequest(BaseModel): + room_names: list[str] = Field(max_length=100) + + +class RoomMeetingStatus(BaseModel): + active_meetings: list[Meeting] + upcoming_events: list[CalendarEventResponse] + + +@router.post("/rooms/meetings/bulk-status", response_model=dict[str, RoomMeetingStatus]) +async def rooms_bulk_meeting_status( + request: BulkStatusRequest, + user: Annotated[Optional[auth.UserInfo], Depends(auth.current_user_optional)], +): + user_id = user["sub"] if user else None + + all_rooms = await rooms_controller.get_by_names(request.room_names) + # Filter to rooms the user can see (owned or shared), matching rooms_list behavior + rooms = [ + r + for r in all_rooms + if r.is_shared or (user_id is not None and r.user_id == user_id) + ] + room_by_id: dict[str, DbRoom] = {r.id: r for r in rooms} + room_ids = list(room_by_id.keys()) + + current_time = datetime.now(timezone.utc) + active_meetings, upcoming_events = await asyncio.gather( + meetings_controller.get_all_active_for_rooms(room_ids, current_time), + calendar_events_controller.get_upcoming_for_rooms(room_ids), + ) + + # Group by room name + active_by_room: dict[str, list[Meeting]] = defaultdict(list) + for m in active_meetings: + room = room_by_id.get(m.room_id) + if not room: + continue + m.platform = room.platform + if user_id != room.user_id and m.platform == "whereby": + m.host_room_url = "" + active_by_room[room.name].append(m) + + upcoming_by_room: dict[str, list[CalendarEventResponse]] = defaultdict(list) + for e in upcoming_events: + room = room_by_id.get(e.room_id) + if not room: + continue + if user_id != room.user_id: + e.description = None + e.attendees = None + upcoming_by_room[room.name].append(e) + + result: dict[str, RoomMeetingStatus] = {} + for name in request.room_names: + result[name] = RoomMeetingStatus( + active_meetings=active_by_room.get(name, []), + upcoming_events=upcoming_by_room.get(name, []), + ) + + return result + + @router.get("/rooms/{room_id}", response_model=RoomDetails) async def rooms_get( room_id: str, diff --git a/www/app/(app)/rooms/_components/RoomList.tsx b/www/app/(app)/rooms/_components/RoomList.tsx index 8cd83277..adffd01a 100644 --- a/www/app/(app)/rooms/_components/RoomList.tsx +++ b/www/app/(app)/rooms/_components/RoomList.tsx @@ -1,5 +1,10 @@ +import { useMemo } from "react"; import { Box, Heading, Text, VStack } from "@chakra-ui/react"; import type { components } from "../../../reflector-api"; +import { + useRoomsBulkMeetingStatus, + BulkMeetingStatusMap, +} from "../../../lib/apiHooks"; type Room = components["schemas"]["Room"]; import { RoomTable } from "./RoomTable"; @@ -31,6 +36,10 @@ export function RoomList({ pt, loading, }: RoomListProps) { + const roomNames = useMemo(() => rooms.map((r) => r.name), [rooms]); + const bulkStatusQuery = useRoomsBulkMeetingStatus(roomNames); + const meetingStatusMap: BulkMeetingStatusMap = bulkStatusQuery.data ?? {}; + return ( {title} @@ -43,6 +52,8 @@ export function RoomList({ onEdit={onEdit} onDelete={onDelete} loading={loading} + meetingStatusMap={meetingStatusMap} + meetingStatusLoading={bulkStatusQuery.isLoading} /> void; onDelete: (roomId: string) => void; loading?: boolean; + meetingStatusMap: BulkMeetingStatusMap; + meetingStatusLoading: boolean; } const getRoomModeDisplay = (mode: string): string => { @@ -104,14 +102,16 @@ const getZulipDisplay = ( return "Enabled"; }; -function MeetingStatus({ roomName }: { roomName: string }) { - const activeMeetingsQuery = useRoomActiveMeetings(roomName); - const upcomingMeetingsQuery = useRoomUpcomingMeetings(roomName); - - const activeMeetings = activeMeetingsQuery.data || []; - const upcomingMeetings = upcomingMeetingsQuery.data || []; - - if (activeMeetingsQuery.isLoading || upcomingMeetingsQuery.isLoading) { +function MeetingStatus({ + activeMeetings, + upcomingMeetings, + isLoading, +}: { + activeMeetings: Meeting[]; + upcomingMeetings: CalendarEventResponse[]; + isLoading: boolean; +}) { + if (isLoading) { return ; } @@ -176,6 +176,8 @@ export function RoomTable({ onEdit, onDelete, loading, + meetingStatusMap, + meetingStatusLoading, }: RoomTableProps) { const [syncingRooms, setSyncingRooms] = useState>( new Set(), @@ -252,7 +254,15 @@ export function RoomTable({ {room.name} - + {getZulipDisplay( diff --git a/www/app/lib/__tests__/bulkMeetingStatus.test.tsx b/www/app/lib/__tests__/bulkMeetingStatus.test.tsx new file mode 100644 index 00000000..72d23988 --- /dev/null +++ b/www/app/lib/__tests__/bulkMeetingStatus.test.tsx @@ -0,0 +1,197 @@ +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(), + queryOptions: (method: string, path: string, init?: unknown) => + init === undefined + ? { queryKey: [method, path] } + : { queryKey: [method, path, init] }, + }, + 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", + }), +})); + +// --- Imports (after mocks) --- + +import React from "react"; +import { render, waitFor, screen } from "@testing-library/react"; +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { useRoomsBulkMeetingStatus, BulkMeetingStatusMap } 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 src = roomData ?? {}; + const data = Object.fromEntries( + roomNames.map((name) => [ + name, + src[name] ?? { active_meetings: [], upcoming_events: [] }, + ]), + ); + return { data, error: undefined, response: {} }; + }, + ); +} + +// --- Test component: uses the bulk hook and displays results --- + +function BulkStatusDisplay({ roomNames }: { roomNames: string[] }) { + const { data, isLoading } = useRoomsBulkMeetingStatus(roomNames); + + if (isLoading) { + return
loading
; + } + + if (!data) { + return
no data
; + } + + return ( +
+ {roomNames.map((name) => { + const status = data[name]; + return ( +
+ {status?.active_meetings?.length ?? 0} active,{" "} + {status?.upcoming_events?.length ?? 0} upcoming +
+ ); + })} +
+ ); +} + +function createWrapper() { + const queryClient = new QueryClient({ + defaultOptions: { + queries: { retry: false }, + }, + }); + return function Wrapper({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ); + }; +} + +// --- Tests --- + +describe("bulk meeting status (prop-drilling)", () => { + afterEach(() => jest.clearAllMocks()); + + it("fetches all room statuses in 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", + ); + + // Prop-drilling: exactly 1 POST for all rooms (no batcher needed) + expect(postCalls).toHaveLength(1); + + // The single call contains all room names + const requestedRooms: string[] = postCalls[0][1].body.room_names; + expect(requestedRooms).toHaveLength(10); + for (const name of rooms) { + expect(requestedRooms).toContain(name); + } + }); + + it("returns room-specific data correctly", 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", + ); + }); + + // Still just 1 POST + expect(mockClient.POST).toHaveBeenCalledTimes(1); + }); + + it("does not fetch when roomNames is empty", async () => { + mockBulkStatusEndpoint(); + + render(, { + wrapper: createWrapper(), + }); + + await waitFor(() => { + expect(screen.getByTestId("status")).toHaveTextContent("no data"); + }); + + // No POST calls when no rooms + expect(mockClient.POST).not.toHaveBeenCalled(); + }); +}); diff --git a/www/app/lib/apiHooks.ts b/www/app/lib/apiHooks.ts index 788dfac6..8e427943 100644 --- a/www/app/lib/apiHooks.ts +++ b/www/app/lib/apiHooks.ts @@ -1,8 +1,8 @@ "use client"; -import { $api } from "./apiClient"; +import { $api, client } from "./apiClient"; import { useError } from "../(errors)/errorContext"; -import { QueryClient, useQueryClient } from "@tanstack/react-query"; +import { QueryClient, useQuery, useQueryClient } from "@tanstack/react-query"; import type { components } from "../reflector-api"; import { useAuth } from "./AuthProvider"; import { MeetingId } from "./types"; @@ -641,16 +641,21 @@ export function useMeetingDeactivate() { setError(error as Error, "Failed to end meeting"); }, onSuccess: () => { - return queryClient.invalidateQueries({ - predicate: (query) => { - const key = query.queryKey; - return key.some( - (k) => - typeof k === "string" && - !!MEETING_LIST_PATH_PARTIALS.find((e) => k.includes(e)), - ); - }, - }); + return Promise.all([ + queryClient.invalidateQueries({ + predicate: (query) => { + const key = query.queryKey; + return key.some( + (k) => + typeof k === "string" && + !!MEETING_LIST_PATH_PARTIALS.find((e) => k.includes(e)), + ); + }, + }), + queryClient.invalidateQueries({ + queryKey: ["bulk-meeting-status"], + }), + ]); }, }); } @@ -707,6 +712,9 @@ export function useRoomsCreateMeeting() { }, ).queryKey, }), + queryClient.invalidateQueries({ + queryKey: ["bulk-meeting-status"], + }), ]); }, onError: (error) => { @@ -772,6 +780,32 @@ export function useRoomActiveMeetings(roomName: string | null) { ); } +type RoomMeetingStatus = components["schemas"]["RoomMeetingStatus"]; + +export type BulkMeetingStatusMap = Record; + +export function useRoomsBulkMeetingStatus(roomNames: string[]) { + const { isAuthenticated } = useAuthReady(); + + return useQuery({ + queryKey: ["bulk-meeting-status", roomNames], + queryFn: async (): Promise => { + if (roomNames.length === 0) return {}; + const { data, error } = await client.POST( + "/v1/rooms/meetings/bulk-status", + { body: { room_names: roomNames } }, + ); + if (error || !data) { + throw new Error( + `bulk-status fetch failed: ${JSON.stringify(error ?? "no data")}`, + ); + } + return data; + }, + enabled: roomNames.length > 0 && isAuthenticated, + }); +} + export function useRoomGetMeeting( roomName: string | null, meetingId: MeetingId | null, diff --git a/www/app/reflector-api.d.ts b/www/app/reflector-api.d.ts index 12a7085c..e803e423 100644 --- a/www/app/reflector-api.d.ts +++ b/www/app/reflector-api.d.ts @@ -118,6 +118,23 @@ export interface paths { patch?: never; trace?: never; }; + "/v1/rooms/meetings/bulk-status": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Rooms Bulk Meeting Status */ + post: operations["v1_rooms_bulk_meeting_status"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; "/v1/rooms/{room_id}": { parameters: { query?: never; @@ -799,6 +816,11 @@ export interface components { */ chunk: string; }; + /** BulkStatusRequest */ + BulkStatusRequest: { + /** Room Names */ + room_names: string[]; + }; /** CalendarEventResponse */ CalendarEventResponse: { /** Id */ @@ -1675,6 +1697,13 @@ export interface components { */ skip_consent: boolean; }; + /** RoomMeetingStatus */ + RoomMeetingStatus: { + /** Active Meetings */ + active_meetings: components["schemas"]["Meeting"][]; + /** Upcoming Events */ + upcoming_events: components["schemas"]["CalendarEventResponse"][]; + }; /** RoomDetails */ RoomDetails: { /** Id */ @@ -2272,6 +2301,41 @@ export interface operations { }; }; }; + v1_rooms_bulk_meeting_status: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["BulkStatusRequest"]; + }; + }; + responses: { + /** @description Successful Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + [key: string]: components["schemas"]["RoomMeetingStatus"]; + }; + }; + }; + /** @description Validation Error */ + 422: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["HTTPValidationError"]; + }; + }; + }; + }; v1_rooms_get: { parameters: { query?: never; diff --git a/www/jest.config.js b/www/jest.config.js index d2f3247b..8348aa25 100644 --- a/www/jest.config.js +++ b/www/jest.config.js @@ -1,8 +1,22 @@ 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: true, + downlevelIteration: true, + lib: ["dom", "dom.iterable", "esnext"], + }, + }, + ], + }, }; diff --git a/www/package.json b/www/package.json index ceefbf55..2b953c5b 100644 --- a/www/package.json +++ b/www/package.json @@ -61,9 +61,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 cd65de55..5e970e1f 100644 --- a/www/pnpm-lock.yaml +++ b/www/pnpm-lock.yaml @@ -134,6 +134,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 @@ -143,6 +152,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) @@ -151,9 +163,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: { @@ -177,6 +195,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: { @@ -493,6 +517,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: { @@ -1044,6 +1111,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: { @@ -1051,6 +1131,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: { @@ -1072,6 +1159,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: { @@ -1168,6 +1262,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: { @@ -2643,6 +2744,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: { @@ -2673,6 +2806,12 @@ packages: integrity: sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==, } + "@types/aria-query@5.0.4": + resolution: + { + integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==, + } + "@types/babel__core@7.20.5": resolution: { @@ -2776,6 +2915,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: { @@ -2878,6 +3023,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: { @@ -3910,6 +4061,12 @@ packages: } engines: { node: ">=10" } + aria-query@5.3.0: + resolution: + { + integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==, + } + aria-query@5.3.2: resolution: { @@ -4493,6 +4650,12 @@ packages: } engines: { node: ">= 8" } + css.escape@1.5.1: + resolution: + { + integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==, + } + cssesc@3.0.0: resolution: { @@ -4501,6 +4664,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: { @@ -4513,6 +4683,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: { @@ -4569,6 +4746,12 @@ packages: supports-color: optional: true + decimal.js@10.6.0: + resolution: + { + integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==, + } + decode-named-character-reference@1.2.0: resolution: { @@ -4700,6 +4883,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: { @@ -4783,6 +4978,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: { @@ -5553,6 +5755,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: { @@ -5565,6 +5774,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: { @@ -5592,6 +5808,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: { @@ -5652,6 +5875,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: { @@ -5888,6 +6118,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: { @@ -6096,6 +6332,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: { @@ -6131,6 +6379,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: { @@ -6138,6 +6393,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: { @@ -6206,6 +6468,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: { @@ -6300,6 +6569,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: { @@ -6497,6 +6778,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: { @@ -6758,6 +7046,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: { @@ -6985,6 +7280,12 @@ packages: react-router-dom: optional: true + nwsapi@2.2.23: + resolution: + { + integrity: sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==, + } + oauth@0.9.15: resolution: { @@ -7199,6 +7500,12 @@ packages: } engines: { node: ">=18" } + parse5@7.3.0: + resolution: + { + integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==, + } + path-exists@4.0.0: resolution: { @@ -7447,6 +7754,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: { @@ -7460,6 +7774,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: { @@ -7559,6 +7880,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: { @@ -7673,6 +8000,13 @@ packages: } engines: { node: ">= 14.18.0" } + redent@3.0.0: + resolution: + { + integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==, + } + engines: { node: ">=8" } + redis-errors@1.2.0: resolution: { @@ -7837,6 +8171,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: { @@ -7884,6 +8224,12 @@ packages: } engines: { node: ">= 0.4" } + safer-buffer@2.1.2: + resolution: + { + integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==, + } + sass@1.90.0: resolution: { @@ -7892,6 +8238,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: { @@ -8256,6 +8609,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: { @@ -8340,6 +8700,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: { @@ -8416,6 +8782,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: { @@ -8429,12 +8808,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: { @@ -8834,6 +9227,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: { @@ -8859,6 +9259,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: { @@ -8892,6 +9299,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: { @@ -8989,6 +9418,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: { @@ -9084,6 +9541,8 @@ packages: } snapshots: + "@adobe/css-tools@4.4.4": {} + "@alloc/quick-lru@5.2.0": {} "@ampproject/remapping@2.3.0": @@ -9155,6 +9614,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 @@ -9389,6 +9856,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 @@ -9754,13 +10241,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 @@ -9776,11 +10281,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": @@ -9899,6 +10413,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 @@ -10888,6 +11412,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 @@ -10905,6 +11458,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 @@ -10928,7 +11483,7 @@ snapshots: "@types/connect@3.4.38": dependencies: - "@types/node": 24.2.1 + "@types/node": 25.0.2 "@types/debug@4.1.12": dependencies: @@ -10977,6 +11532,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": {} @@ -10989,11 +11550,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": @@ -11012,7 +11573,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 @@ -11032,7 +11593,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": {} @@ -11940,6 +12503,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: @@ -12305,12 +12872,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 @@ -12349,6 +12928,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 @@ -12406,6 +12987,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: @@ -12459,6 +13044,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: @@ -13088,10 +13675,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 @@ -13099,6 +13697,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 @@ -13110,6 +13715,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: {} @@ -13139,6 +13748,8 @@ snapshots: imurmurhash@0.1.4: {} + indent-string@4.0.0: {} + index-to-position@1.1.0: {} inflight@1.0.6: @@ -13276,6 +13887,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 @@ -13385,7 +13998,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) @@ -13476,12 +14089,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 @@ -13525,12 +14150,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 @@ -13653,6 +14296,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 @@ -13688,7 +14340,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 @@ -13726,6 +14378,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: {} @@ -13822,6 +14501,8 @@ snapshots: dependencies: react: 18.3.1 + lz-string@1.5.0: {} + magic-string@0.30.19: dependencies: "@jridgewell/sourcemap-codec": 1.5.5 @@ -14097,6 +14778,8 @@ snapshots: mimic-fn@2.1.0: {} + min-indent@1.0.1: {} + minimatch@3.1.2: dependencies: brace-expansion: 1.1.12 @@ -14212,6 +14895,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: {} @@ -14361,6 +15046,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: {} @@ -14473,6 +15162,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: @@ -14481,6 +15176,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: @@ -14529,6 +15230,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): @@ -14613,6 +15316,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: @@ -14743,6 +15451,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: {} @@ -14773,6 +15483,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 @@ -14781,6 +15493,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 @@ -15062,6 +15778,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: @@ -15106,6 +15826,8 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} + symbol-tree@3.2.4: {} + synckit@0.11.11: dependencies: "@pkgr/core": 0.2.9 @@ -15174,14 +15896,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: {} @@ -15192,7 +15928,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 @@ -15208,9 +15944,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: @@ -15453,6 +16189,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 @@ -15466,6 +16206,8 @@ snapshots: webidl-conversions@3.0.1: {} + webidl-conversions@7.0.0: {} + webpack-sources@3.3.3: {} webpack-virtual-modules@0.5.0: {} @@ -15506,6 +16248,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 @@ -15581,6 +16334,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: {}