in index.html.
+ *
+ * StrictMode renders components twice in development to surface side effects
+ * that depend on render order. It has no effect in production builds.
+ * It's the reason you may see useEffect run twice in dev — intentional.
+ */
+createRoot(document.getElementById('root')).render(
+
+);
diff --git a/apps/client/src/pages/Home.jsx b/apps/client/src/pages/Home.jsx
new file mode 100644
index 0000000..05fac5b
--- /dev/null
+++ b/apps/client/src/pages/Home.jsx
@@ -0,0 +1,144 @@
+import { useState } from 'react';
+import { LuLogIn, LuRadio } from 'react-icons/lu';
+import Layout from '../components/Layout';
+import socket from '../socket';
+
+const SERVER_URL = import.meta.env.VITE_SERVER_URL ?? 'http://localhost:3001';
+
+export default function Home({ onJoin, onHost }) {
+ const [code, setCode] = useState('');
+ const [error, setError] = useState(null);
+ const [loading, setLoading] = useState(false);
+
+ async function handleJoin(e) {
+ e.preventDefault();
+ const trimmed = code.trim().toUpperCase();
+ if (!trimmed) return;
+ setError(null);
+ setLoading(true);
+ try {
+ const res = await fetch(`${SERVER_URL}/sessions/${trimmed}`);
+ if (!res.ok) {
+ const body = await res.json().catch(() => ({}));
+ setError(body.message ?? 'Session not found.');
+ return;
+ }
+ const session = await res.json();
+ if (session.status === 'closed') {
+ setError('This session is already closed.');
+ return;
+ }
+ socket.connect();
+ onJoin({ code: trimmed });
+ } catch {
+ setError('Could not reach the server. Is it running?');
+ } finally {
+ setLoading(false);
+ }
+ }
+
+ async function handleHost() {
+ setError(null);
+ setLoading(true);
+ try {
+ const res = await fetch(`${SERVER_URL}/sessions`, { method: 'POST' });
+ if (!res.ok) throw new Error('Failed to create session');
+ const session = await res.json();
+ socket.connect();
+ onHost({ code: session.code });
+ } catch {
+ setError('Could not create a session. Is the server running?');
+ } finally {
+ setLoading(false);
+ }
+ }
+
+ return (
+
+ );
+}
diff --git a/apps/client/src/pages/Host.jsx b/apps/client/src/pages/Host.jsx
new file mode 100644
index 0000000..97bf734
--- /dev/null
+++ b/apps/client/src/pages/Host.jsx
@@ -0,0 +1,127 @@
+import { useState } from 'react';
+import { LuPower, LuShare2 } from 'react-icons/lu';
+import Layout from '../components/Layout';
+import ConfirmModal from '../components/ConfirmModal';
+import ResultBar from '../components/ResultBar';
+import { useSession } from '../hooks/useSession';
+import { BAR_COLORS, calcPct } from '../utils';
+
+const SERVER_URL = import.meta.env.VITE_SERVER_URL ?? 'http://localhost:3001';
+
+export default function Host({ code, onClose }) {
+ const { question, results } = useSession(code, onClose);
+ const [showConfirm, setShowConfirm] = useState(false);
+
+ async function handleClose() {
+ await fetch(`${SERVER_URL}/sessions/${code}/close`, { method: 'PATCH' });
+ }
+
+ const navAction = {
+ label: 'Close session',
+ onClick: () => setShowConfirm(true),
+ className: 'btn-danger-outline btn-sm',
+ };
+
+ return (
+ <>
+
setShowConfirm(false)}
+ />
+ )}
+ >
+ );
+}
diff --git a/apps/client/src/pages/Participant.jsx b/apps/client/src/pages/Participant.jsx
new file mode 100644
index 0000000..08eef87
--- /dev/null
+++ b/apps/client/src/pages/Participant.jsx
@@ -0,0 +1,184 @@
+import { useState } from 'react';
+import confetti from 'canvas-confetti';
+import { LuClock, LuSend, LuRefreshCw } from 'react-icons/lu';
+import Layout from '../components/Layout';
+import ResultBar from '../components/ResultBar';
+import { useSession } from '../hooks/useSession';
+import { BAR_COLORS, calcPct } from '../utils';
+import socket from '../socket';
+
+export default function Participant({ code, onClose }) {
+ const { question, results } = useSession(code, onClose);
+ const [selectedId, setSelectedId] = useState(null);
+ const [phase, setPhase] = useState('voting');
+
+ function handleSubmit() {
+ socket.emit('submit_vote', { code, answerId: selectedId });
+ confetti({
+ particleCount: 80,
+ spread: 60,
+ origin: { y: 0.7 },
+ colors: ['#E17000', '#F88101', '#F8A800'],
+ });
+ setPhase('waiting');
+ }
+
+ function handleChange() {
+ setPhase('voting');
+ }
+
+ const selectedAnswer = question?.answers.find((a) => a.id === selectedId);
+
+ if (!question) {
+ return (
+
+
+
+ );
+ }
+
+ return (
+
+
+ {phase === 'voting' ? (
+ /* ── Voting phase ── */
+
+
+
+
Question
+
+ {question.text}
+
+
+
+
+ {question.answers.map((answer) => (
+
setSelectedId(answer.id)}
+ >
+
+
{answer.text}
+
+ ))}
+
+
+
+
+ Submit vote
+
+
+
+
+
How it works
+
+ Select your answer and submit. Results appear live once
+ you've voted — and you can change your mind until the host
+ closes the question.
+
+
+
+ ) : (
+ /* ── Waiting phase ── */
+
+
+
+
+
+
+
+
+ Vote submitted
+
+
+ Waiting for others…
+
+
+ {selectedAnswer && (
+
+
+
+ {selectedAnswer.text}
+
+
+ )}
+
+
+
+
+
+ Change my answer
+
+
+
+
+
+
Live results
+ {question.answers.map((answer, i) => (
+
+ ))}
+
+ Updates live as others vote
+
+
+
+ )}
+
+
+ );
+}
diff --git a/apps/client/src/socket.js b/apps/client/src/socket.js
new file mode 100644
index 0000000..5df2c76
--- /dev/null
+++ b/apps/client/src/socket.js
@@ -0,0 +1,17 @@
+import { io } from 'socket.io-client';
+
+/**
+ * Singleton Socket.io client.
+ *
+ * autoConnect: false — the socket does NOT connect on import.
+ * We call socket.connect() explicitly after the user enters a valid code,
+ * so we never open a WebSocket against a session that doesn't exist yet.
+ *
+ * One module-level instance is shared across all components: if io() were
+ * called inside a component, every re-render would create a new connection.
+ */
+const socket = io(import.meta.env.VITE_SERVER_URL ?? 'http://localhost:3001', {
+ autoConnect: false,
+});
+
+export default socket;
diff --git a/apps/client/src/styles/components.css b/apps/client/src/styles/components.css
new file mode 100644
index 0000000..97f6a81
--- /dev/null
+++ b/apps/client/src/styles/components.css
@@ -0,0 +1,550 @@
+/* ─── Animations ─────────────────────────────────────────────── */
+@keyframes pulse {
+ 0%,
+ 100% {
+ opacity: 1;
+ }
+ 50% {
+ opacity: 0.3;
+ }
+}
+
+/* ─── Logo ───────────────────────────────────────────────────── */
+.logo {
+ font-size: 18px;
+ font-weight: 500;
+ letter-spacing: -0.3px;
+}
+.logo-w {
+ color: var(--rd-text);
+}
+.logo-o {
+ color: var(--rd-brand2);
+}
+
+/* Reset button styles when the logo acts as a nav link */
+.logo-btn {
+ background: none;
+ border: none;
+ padding: 0;
+ cursor: pointer;
+ font-family: inherit;
+}
+.logo-btn:focus-visible {
+ outline: 2px solid var(--rd-brand);
+ outline-offset: 4px;
+ border-radius: 4px;
+}
+
+/* ─── Navbar ─────────────────────────────────────────────────── */
+.navbar {
+ background: var(--rd-surf);
+ border-bottom: 1px solid var(--rd-border);
+ padding: 0 var(--sp-xl);
+ height: 56px;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
+.navbar-right {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+}
+.navbar-code {
+ font-size: 13px;
+ font-weight: 500;
+ color: var(--rd-text);
+ font-family: var(--font-mono);
+ letter-spacing: 0.1em;
+}
+
+/* Modifier that adds an icon before the label in any button */
+.btn-icon {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ gap: 7px;
+}
+
+/* Copy-code button in the navbar */
+.copy-btn {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ background: none;
+ border: none;
+ padding: 4px 6px;
+ border-radius: var(--r-sm);
+ cursor: pointer;
+ color: var(--rd-muted);
+ font-family: inherit;
+ transition: color 0.15s;
+}
+.copy-btn:hover {
+ color: var(--rd-text);
+}
+
+/* ─── Badge Live ─────────────────────────────────────────────── */
+.badge-live {
+ display: inline-flex;
+ align-items: center;
+ gap: 5px;
+ background: #1c0a00;
+ border: 1px solid #e1700044;
+ border-radius: var(--r-full);
+ padding: 4px 10px;
+ font-size: 11px;
+ font-weight: 500;
+ color: var(--rd-brand2);
+}
+.live-dot {
+ width: 6px;
+ height: 6px;
+ border-radius: 50%;
+ background: var(--rd-brand);
+ animation: pulse 2s infinite;
+ flex-shrink: 0;
+}
+
+/* ─── Buttons ────────────────────────────────────────────────── */
+.btn-primary {
+ background: var(--rd-brand);
+ color: var(--rd-bg);
+ border: none;
+ border-radius: var(--r-md);
+ padding: 12px 28px;
+ font-size: 14px;
+ font-weight: 500;
+ cursor: pointer;
+ font-family: inherit;
+ transition: background 0.15s;
+}
+.btn-primary:hover {
+ background: var(--rd-brand2);
+}
+.btn-primary:disabled {
+ opacity: 0.45;
+ cursor: not-allowed;
+}
+
+.btn-ghost {
+ background: transparent;
+ color: var(--rd-text);
+ border: 1px solid var(--rd-border);
+ border-radius: var(--r-md);
+ padding: 12px 28px;
+ font-size: 14px;
+ font-weight: 500;
+ cursor: pointer;
+ font-family: inherit;
+ transition: border-color 0.15s;
+}
+.btn-ghost:hover {
+ border-color: var(--rd-muted);
+}
+
+.btn-sm {
+ padding: 8px 16px;
+ font-size: 12px;
+ border-radius: var(--r-sm);
+}
+
+.btn-danger-outline {
+ background: transparent;
+ color: var(--rd-brand);
+ border: 1px solid #e1700044;
+ border-radius: var(--r-sm);
+ padding: 8px 16px;
+ font-size: 12px;
+ font-weight: 500;
+ cursor: pointer;
+ font-family: inherit;
+ transition: border-color 0.15s;
+}
+.btn-danger-outline:hover {
+ border-color: var(--rd-brand);
+}
+
+.btn-change {
+ background: transparent;
+ color: var(--rd-brand);
+ border: 1px solid #e1700044;
+ border-radius: var(--r-sm);
+ padding: 9px 18px;
+ font-size: 13px;
+ font-weight: 500;
+ cursor: pointer;
+ font-family: inherit;
+ transition: border-color 0.15s;
+}
+.btn-change:hover {
+ border-color: var(--rd-brand);
+}
+
+/* ─── Cards ──────────────────────────────────────────────────── */
+.card {
+ background: var(--rd-surf);
+ border: 1px solid var(--rd-border);
+ border-radius: var(--r-lg);
+ padding: var(--sp-lg);
+}
+
+.card-sm {
+ background: var(--rd-surf2);
+ border: 1px solid var(--rd-border);
+ border-radius: var(--r-md);
+ padding: var(--sp-md);
+}
+
+/* ─── Inputs ─────────────────────────────────────────────────── */
+.input-label {
+ font-size: 11px;
+ color: var(--rd-muted);
+ text-transform: uppercase;
+ letter-spacing: 0.08em;
+ margin-bottom: var(--sp-sm);
+}
+
+.code-input {
+ background: var(--rd-bg);
+ border: 1.5px solid var(--rd-brand);
+ border-radius: var(--r-md);
+ padding: 14px var(--sp-md);
+ font-size: 22px;
+ font-weight: 500;
+ color: var(--rd-text);
+ letter-spacing: 0.3em;
+ width: 100%;
+ font-family: var(--font-mono);
+ text-align: center;
+ outline: none;
+}
+.code-input::placeholder {
+ color: #2a2a2a;
+ letter-spacing: 0.2em;
+ font-size: 18px;
+}
+
+/* ─── Divider ────────────────────────────────────────────────── */
+.or-divider {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ margin: var(--sp-md) 0;
+}
+.or-line {
+ flex: 1;
+ height: 1px;
+ background: var(--rd-border);
+}
+.or-text {
+ font-size: 12px;
+ color: var(--rd-muted);
+}
+
+/* ─── Answer Options ─────────────────────────────────────────── */
+.answers-grid {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 10px;
+}
+
+.answer-opt {
+ background: var(--rd-surf2);
+ border: 1px solid var(--rd-border);
+ border-radius: var(--r-md);
+ padding: 14px var(--sp-md);
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ cursor: pointer;
+ transition: border-color 0.12s;
+ user-select: none;
+}
+.answer-opt:hover {
+ border-color: var(--rd-muted);
+}
+.answer-opt:active {
+ transform: scale(0.97);
+}
+.answer-opt.selected {
+ border-color: var(--rd-brand);
+ background: var(--rd-sel);
+}
+
+.answer-opt-text {
+ font-size: 14px;
+ color: var(--rd-muted);
+}
+.answer-opt.selected .answer-opt-text {
+ color: var(--rd-text);
+}
+
+.radio {
+ width: 16px;
+ height: 16px;
+ border-radius: 50%;
+ border: 1.5px solid var(--rd-border);
+ flex-shrink: 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: all 0.12s;
+}
+.answer-opt.selected .radio {
+ border-color: var(--rd-brand);
+ background: var(--rd-brand);
+}
+.radio-inner {
+ width: 6px;
+ height: 6px;
+ border-radius: 50%;
+ background: var(--rd-bg);
+ display: none;
+}
+.answer-opt.selected .radio-inner {
+ display: block;
+}
+
+/* ─── Result Bars ────────────────────────────────────────────── */
+.result-row {
+ margin-bottom: 14px;
+}
+.result-row:last-child {
+ margin-bottom: 0;
+}
+.result-meta {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 6px;
+}
+.result-label {
+ font-size: 13px;
+ color: var(--rd-muted);
+}
+.result-pct {
+ font-size: 13px;
+ font-weight: 500;
+}
+.result-track {
+ background: var(--rd-bg);
+ border-radius: 4px;
+ height: 8px;
+ overflow: hidden;
+ border: 1px solid var(--rd-border);
+}
+.result-fill {
+ height: 8px;
+ border-radius: 4px;
+ /* Animated by width change driven by the pct prop */
+ transition: width 0.4s ease;
+}
+
+/* ─── Section label ──────────────────────────────────────────── */
+.section-label {
+ font-size: 10px;
+ color: var(--rd-accent);
+ text-transform: uppercase;
+ letter-spacing: 0.1em;
+ font-weight: 500;
+ margin-bottom: var(--sp-sm);
+}
+
+/* ─── Action row ─────────────────────────────────────────────── */
+.action-row {
+ display: flex;
+ gap: 10px;
+}
+
+/* ─── Waiting card ───────────────────────────────────────────── */
+.waiting-card {
+ background: var(--rd-surf);
+ border: 1px solid var(--rd-border);
+ border-radius: var(--r-lg);
+ padding: 32px var(--sp-lg);
+ text-align: center;
+}
+.waiting-icon {
+ width: 48px;
+ height: 48px;
+ border-radius: 50%;
+ background: #1c0e00;
+ border: 1.5px solid #e1700044;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin: 0 auto var(--sp-md);
+}
+.waiting-dot-row {
+ display: flex;
+ gap: 6px;
+ justify-content: center;
+ margin: var(--sp-md) 0 var(--sp-lg);
+}
+.wdot {
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ background: var(--rd-border);
+}
+.wdot:nth-child(1) {
+ background: var(--rd-brand);
+ animation: pulse 1.5s infinite;
+}
+.wdot:nth-child(2) {
+ background: var(--rd-brand);
+ animation: pulse 1.5s 0.2s infinite;
+}
+.wdot:nth-child(3) {
+ background: var(--rd-brand);
+ animation: pulse 1.5s 0.4s infinite;
+}
+.voted-pill {
+ display: inline-flex;
+ align-items: center;
+ gap: var(--sp-sm);
+ background: var(--rd-sel);
+ border: 1px solid var(--rd-brand);
+ border-radius: var(--r-sm);
+ padding: var(--sp-sm) 14px;
+ margin: 12px 0 20px;
+}
+.voted-pill-dot {
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ background: var(--rd-brand);
+ flex-shrink: 0;
+}
+
+/* ─── Confirm modal ──────────────────────────────────────────── */
+.modal-backdrop {
+ position: fixed;
+ inset: 0;
+ background: rgba(0, 0, 0, 0.7);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 100;
+ padding: var(--sp-md);
+}
+.modal-box {
+ background: var(--rd-surf);
+ border: 1px solid var(--rd-border);
+ border-radius: var(--r-lg);
+ padding: var(--sp-lg);
+ width: 100%;
+ max-width: 400px;
+}
+.modal-title {
+ font-size: 16px;
+ font-weight: 500;
+ color: var(--rd-text);
+ margin-bottom: var(--sp-sm);
+}
+.modal-message {
+ font-size: 13px;
+ color: var(--rd-muted);
+ line-height: 1.6;
+ margin-bottom: var(--sp-lg);
+}
+.modal-actions {
+ display: flex;
+ justify-content: flex-end;
+ gap: var(--sp-sm);
+}
+
+/* ─── Footer ─────────────────────────────────────────────────── */
+.footer {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 20px;
+ padding: var(--sp-lg) var(--sp-xl);
+ margin-top: auto;
+ border-top: 1px solid var(--rd-border);
+ font-size: 12px;
+ color: var(--rd-muted);
+}
+.footer-link {
+ color: var(--rd-muted);
+ text-decoration: none;
+ transition: color 0.15s;
+}
+.footer-link:hover {
+ color: var(--rd-text);
+}
+.footer-icon-link {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+}
+.footer-sep {
+ width: 1px;
+ height: 12px;
+ background: var(--rd-border);
+ display: inline-block;
+}
+
+/* ─── Home page ──────────────────────────────────────────────── */
+.home-wrap {
+ padding: var(--sp-lg) var(--sp-md);
+ max-width: 480px;
+ margin: 0 auto;
+}
+.home-hero {
+ text-align: center;
+ padding: 48px 0 32px;
+}
+.hero-title {
+ font-size: 52px;
+ font-weight: 500;
+ letter-spacing: -1px;
+ line-height: 1;
+}
+.home-card {
+ max-width: 440px;
+ margin: 0 auto;
+}
+
+/* ─── Page content wrapper ───────────────────────────────────── */
+.page-content {
+ padding: var(--sp-2xl) var(--sp-xl);
+}
+
+/* ─── Host layout ────────────────────────────────────────────── */
+.host-grid {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: var(--sp-lg);
+}
+
+/* ─── Participant layout ─────────────────────────────────────── */
+.participant-grid {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: var(--sp-lg);
+ align-items: start;
+}
+
+/* ─── Responsive (mobile-first breakpoint at 700px) ──────────── */
+@media (max-width: 700px) {
+ .navbar {
+ padding: 0 var(--sp-md);
+ }
+ .page-content {
+ padding: var(--sp-lg) var(--sp-md);
+ }
+ .home-hero {
+ padding: 32px 0 24px;
+ }
+ .hero-title {
+ font-size: 36px;
+ }
+ .host-grid,
+ .participant-grid,
+ .answers-grid {
+ grid-template-columns: 1fr;
+ }
+}
diff --git a/apps/client/src/styles/tokens.css b/apps/client/src/styles/tokens.css
new file mode 100644
index 0000000..8a82d95
--- /dev/null
+++ b/apps/client/src/styles/tokens.css
@@ -0,0 +1,54 @@
+/* Clown Fish palette — extracted from the RoastDev reference design */
+:root {
+ /* Brand */
+ --rd-brand: #e17000;
+ --rd-brand2: #f88101;
+ --rd-accent: #f8a800;
+
+ /* Surfaces */
+ --rd-bg: #0c0c0c;
+ --rd-surf: #161616;
+ --rd-surf2: #1e1e1e;
+
+ /* Borders & text */
+ --rd-border: #2a2a2a;
+ --rd-text: #fcfcfc;
+ --rd-muted: #888;
+
+ /* Selected answer background */
+ --rd-sel: #1c0e00;
+
+ /* Spacing */
+ --sp-xs: 4px;
+ --sp-sm: 8px;
+ --sp-md: 16px;
+ --sp-lg: 24px;
+ --sp-xl: 32px;
+ --sp-2xl: 40px;
+
+ /* Border radius */
+ --r-sm: 8px;
+ --r-md: 10px;
+ --r-lg: 14px;
+ --r-full: 9999px;
+
+ /* Typography */
+ --font-base:
+ -apple-system, BlinkMacSystemFont, 'Inter', 'Segoe UI', sans-serif;
+ --font-mono: 'Courier New', monospace;
+}
+
+*,
+*::before,
+*::after {
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+}
+
+body {
+ font-family: var(--font-base);
+ background: var(--rd-bg);
+ color: var(--rd-text);
+ min-height: 100vh;
+}
diff --git a/apps/client/src/tests/Home.test.jsx b/apps/client/src/tests/Home.test.jsx
new file mode 100644
index 0000000..a77a4bd
--- /dev/null
+++ b/apps/client/src/tests/Home.test.jsx
@@ -0,0 +1,118 @@
+import { render, screen, fireEvent, waitFor } from '@testing-library/react';
+import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
+import Home from '../pages/Home.jsx';
+
+// Prevent a real WebSocket from opening — socket is only called on submit
+vi.mock('../socket.js', () => ({
+ default: { on: vi.fn(), off: vi.fn(), emit: vi.fn(), connect: vi.fn() },
+}));
+
+const mockSession = { code: 'XK92PL', status: 'open' };
+
+describe('Home', () => {
+ beforeEach(() => {
+ vi.spyOn(globalThis, 'fetch').mockResolvedValue({
+ ok: true,
+ json: async () => mockSession,
+ });
+ });
+
+ afterEach(() => {
+ vi.restoreAllMocks();
+ });
+
+ it('renders the code input and both action buttons', () => {
+ render( );
+
+ expect(screen.getByPlaceholderText('_ _ _ _ _ _')).toBeTruthy();
+ expect(screen.getByRole('button', { name: /join roast/i })).toBeTruthy();
+ expect(
+ screen.getByRole('button', { name: /host a session/i })
+ ).toBeTruthy();
+ });
+
+ it('coerces typed input to uppercase', () => {
+ render( );
+
+ const input = screen.getByPlaceholderText('_ _ _ _ _ _');
+ fireEvent.change(input, { target: { value: 'abc123' } });
+
+ expect(input.value).toBe('ABC123');
+ });
+
+ it('error slot is always rendered (no layout jump)', () => {
+ render( );
+
+ // The must exist in the DOM even with no error so layout is stable
+ const errorSlot = screen.getByText('', { selector: 'p' });
+ expect(errorSlot).toBeTruthy();
+ expect(errorSlot.style.visibility).toBe('hidden');
+ });
+
+ it('shows an error when the session is closed', async () => {
+ vi.spyOn(globalThis, 'fetch').mockResolvedValue({
+ ok: true,
+ json: async () => ({ code: 'XK92PL', status: 'closed' }),
+ });
+
+ render( );
+
+ fireEvent.change(screen.getByPlaceholderText('_ _ _ _ _ _'), {
+ target: { value: 'XK92PL' },
+ });
+ fireEvent.click(screen.getByRole('button', { name: /join roast/i }));
+
+ await waitFor(() => {
+ const errorSlot = screen.getByText(/closed/i);
+ expect(errorSlot.style.visibility).toBe('visible');
+ });
+ });
+
+ it('shows an error when the session is not found (404)', async () => {
+ vi.spyOn(globalThis, 'fetch').mockResolvedValue({
+ ok: false,
+ json: async () => ({ message: 'Session not found' }),
+ });
+
+ render( );
+
+ fireEvent.change(screen.getByPlaceholderText('_ _ _ _ _ _'), {
+ target: { value: 'ZZZZZZ' },
+ });
+ fireEvent.click(screen.getByRole('button', { name: /join roast/i }));
+
+ await waitFor(() => {
+ expect(screen.getByText(/session not found/i)).toBeTruthy();
+ });
+ });
+
+ it('calls onJoin with the code when join succeeds', async () => {
+ const onJoin = vi.fn();
+ render( );
+
+ fireEvent.change(screen.getByPlaceholderText('_ _ _ _ _ _'), {
+ target: { value: 'XK92PL' },
+ });
+ fireEvent.click(screen.getByRole('button', { name: /join roast/i }));
+
+ await waitFor(() => {
+ expect(onJoin).toHaveBeenCalledWith({ code: 'XK92PL' });
+ });
+ });
+
+ it('calls onHost when host a session succeeds', async () => {
+ vi.spyOn(globalThis, 'fetch').mockResolvedValue({
+ ok: true,
+ json: async () => ({ code: 'NEWCOD', status: 'open' }),
+ });
+
+ const onHost = vi.fn();
+ render( );
+
+ fireEvent.click(screen.getByRole('button', { name: /host a session/i }));
+
+ await waitFor(() => {
+ expect(onHost).toHaveBeenCalledWith({ code: 'NEWCOD' });
+ });
+ });
+});
diff --git a/apps/client/src/tests/Host.test.jsx b/apps/client/src/tests/Host.test.jsx
new file mode 100644
index 0000000..2bc1774
--- /dev/null
+++ b/apps/client/src/tests/Host.test.jsx
@@ -0,0 +1,101 @@
+import { render, screen, fireEvent, act } from '@testing-library/react';
+import { describe, it, expect, vi, beforeEach } from 'vitest';
+import socket from '../socket.js';
+import Host from '../pages/Host.jsx';
+import { getSocketHandler, mockQuestion } from './helpers.js';
+
+// vi.mock must live in this file — Vitest hoists it at parse time.
+vi.mock('../socket.js', () => ({
+ default: { on: vi.fn(), off: vi.fn(), emit: vi.fn(), connect: vi.fn() },
+}));
+
+vi.spyOn(globalThis, 'fetch').mockResolvedValue({
+ ok: true,
+ json: async () => ({}),
+});
+
+describe('Host', () => {
+ beforeEach(() => {
+ vi.clearAllMocks();
+ });
+
+ it('shows a loading state before session_joined fires', () => {
+ render( );
+ expect(screen.getByText('Loading question…')).toBeTruthy();
+ });
+
+ it('displays the question text after session_joined', () => {
+ render( );
+
+ act(() => getSocketHandler('session_joined')({ question: mockQuestion }));
+
+ expect(screen.getByText(mockQuestion.text)).toBeTruthy();
+ });
+
+ it('renders a result bar for each answer', () => {
+ render( );
+
+ act(() => getSocketHandler('session_joined')({ question: mockQuestion }));
+
+ mockQuestion.answers.forEach(({ text }) => {
+ expect(screen.getByText(text)).toBeTruthy();
+ });
+ });
+
+ it('updates percentages when vote_update fires', () => {
+ render( );
+
+ act(() => getSocketHandler('session_joined')({ question: mockQuestion }));
+ act(() =>
+ getSocketHandler('vote_update')({
+ results: [
+ { answerId: 'a1', count: 3 },
+ { answerId: 'a2', count: 1 },
+ ],
+ })
+ );
+
+ expect(screen.getByText('75%')).toBeTruthy();
+ expect(screen.getByText('25%')).toBeTruthy();
+ });
+
+ it('opens the confirm modal when Close session is clicked', () => {
+ render( );
+
+ act(() => getSocketHandler('session_joined')({ question: mockQuestion }));
+
+ fireEvent.click(
+ screen.getAllByRole('button', { name: /close session/i })[0]
+ );
+
+ expect(screen.getByRole('dialog')).toBeTruthy();
+ expect(screen.getByText('Close this session?')).toBeTruthy();
+ });
+
+ it('dismisses the modal when Cancel is clicked', () => {
+ render( );
+
+ act(() => getSocketHandler('session_joined')({ question: mockQuestion }));
+
+ fireEvent.click(
+ screen.getAllByRole('button', { name: /close session/i })[0]
+ );
+ fireEvent.click(screen.getByRole('button', { name: /cancel/i }));
+
+ expect(screen.queryByRole('dialog')).toBeNull();
+ });
+
+ it('calls onClose when session_closed fires', () => {
+ const onClose = vi.fn();
+ render( );
+
+ act(() => getSocketHandler('session_closed')());
+
+ expect(onClose).toHaveBeenCalledOnce();
+ });
+
+ it('emits join_session with the code on mount', () => {
+ render( );
+ expect(socket.emit).toHaveBeenCalledWith('join_session', 'XK92PL');
+ });
+});
diff --git a/apps/client/src/tests/Participant.test.jsx b/apps/client/src/tests/Participant.test.jsx
new file mode 100644
index 0000000..087f0b5
--- /dev/null
+++ b/apps/client/src/tests/Participant.test.jsx
@@ -0,0 +1,159 @@
+import { render, screen, fireEvent, act } from '@testing-library/react';
+import { describe, it, expect, vi, beforeEach } from 'vitest';
+import socket from '../socket.js';
+import Participant from '../pages/Participant.jsx';
+import { getSocketHandler, mockQuestion } from './helpers.js';
+
+// vi.mock must live in this file — Vitest hoists it at parse time.
+vi.mock('../socket.js', () => ({
+ default: { on: vi.fn(), off: vi.fn(), emit: vi.fn(), connect: vi.fn() },
+}));
+
+// canvas-confetti calls the Canvas API which is not available in jsdom
+vi.mock('canvas-confetti', () => ({ default: vi.fn() }));
+
+/** Renders Participant and fires session_joined so the question is set. */
+function renderWithQuestion(props = {}) {
+ const utils = render(
+
+ );
+ act(() => getSocketHandler('session_joined')({ question: mockQuestion }));
+ return utils;
+}
+
+describe('Participant', () => {
+ beforeEach(() => {
+ vi.clearAllMocks();
+ });
+
+ it('shows a loading state before session_joined fires', () => {
+ render( );
+ expect(screen.getByText('Joining session…')).toBeTruthy();
+ });
+
+ it('renders all answer options in the voting phase', () => {
+ renderWithQuestion();
+
+ mockQuestion.answers.forEach(({ text }) => {
+ expect(screen.getByText(text)).toBeTruthy();
+ });
+ });
+
+ it('submit button is disabled before any answer is selected', () => {
+ renderWithQuestion();
+
+ const submitBtn = screen.getByRole('button', { name: /submit vote/i });
+ expect(submitBtn.disabled).toBe(true);
+ });
+
+ it('selecting an answer adds the selected class and enables submit', () => {
+ renderWithQuestion();
+
+ const option = screen
+ .getByText(mockQuestion.answers[0].text)
+ .closest('.answer-opt');
+ fireEvent.click(option);
+
+ expect(option.classList.contains('selected')).toBe(true);
+ expect(screen.getByRole('button', { name: /submit vote/i }).disabled).toBe(
+ false
+ );
+ });
+
+ it('submitting a vote emits submit_vote and transitions to waiting phase', () => {
+ renderWithQuestion();
+
+ fireEvent.click(
+ screen.getByText(mockQuestion.answers[1].text).closest('.answer-opt')
+ );
+ fireEvent.click(screen.getByRole('button', { name: /submit vote/i }));
+
+ expect(socket.emit).toHaveBeenCalledWith('submit_vote', {
+ code: 'XK92PL',
+ answerId: 'a2',
+ });
+ expect(screen.getByText('Vote submitted')).toBeTruthy();
+ expect(screen.getByText('Waiting for others…')).toBeTruthy();
+ });
+
+ it('waiting phase shows the voted answer in the pill', () => {
+ renderWithQuestion();
+
+ fireEvent.click(
+ screen.getByText(mockQuestion.answers[0].text).closest('.answer-opt')
+ );
+ fireEvent.click(screen.getByRole('button', { name: /submit vote/i }));
+
+ // Text appears in both the voted-pill and the result bar label
+ expect(
+ screen.getAllByText(mockQuestion.answers[0].text).length
+ ).toBeGreaterThan(0);
+ });
+
+ it('waiting phase shows live results updated by vote_update', () => {
+ renderWithQuestion();
+
+ fireEvent.click(
+ screen.getByText(mockQuestion.answers[0].text).closest('.answer-opt')
+ );
+ fireEvent.click(screen.getByRole('button', { name: /submit vote/i }));
+
+ act(() =>
+ getSocketHandler('vote_update')({
+ results: [
+ { answerId: 'a1', count: 2 },
+ { answerId: 'a2', count: 2 },
+ ],
+ })
+ );
+
+ // 2/4 = 50% for each
+ const fifties = screen.getAllByText('50%');
+ expect(fifties.length).toBe(2);
+ });
+
+ it('Change my answer returns to the voting phase', () => {
+ renderWithQuestion();
+
+ fireEvent.click(
+ screen.getByText(mockQuestion.answers[0].text).closest('.answer-opt')
+ );
+ fireEvent.click(screen.getByRole('button', { name: /submit vote/i }));
+ fireEvent.click(screen.getByRole('button', { name: /change my answer/i }));
+
+ // Back to voting phase — submit button should be visible again
+ expect(screen.getByRole('button', { name: /submit vote/i })).toBeTruthy();
+ });
+
+ it('previously selected answer stays highlighted after changing mind', () => {
+ renderWithQuestion();
+
+ fireEvent.click(
+ screen.getByText(mockQuestion.answers[0].text).closest('.answer-opt')
+ );
+ fireEvent.click(screen.getByRole('button', { name: /submit vote/i }));
+ fireEvent.click(screen.getByRole('button', { name: /change my answer/i }));
+
+ const option = screen
+ .getByText(mockQuestion.answers[0].text)
+ .closest('.answer-opt');
+ expect(option.classList.contains('selected')).toBe(true);
+ });
+
+ it('calls onClose when session_closed event fires', () => {
+ const onClose = vi.fn();
+ render( );
+
+ act(() => getSocketHandler('session_closed')());
+
+ expect(onClose).toHaveBeenCalledOnce();
+ });
+
+ it('cleans up socket listeners on unmount', () => {
+ const { unmount } = render( );
+ unmount();
+
+ // off() should have been called for each of the 3 registered events
+ expect(socket.off).toHaveBeenCalledTimes(3);
+ });
+});
diff --git a/apps/client/src/tests/helpers.js b/apps/client/src/tests/helpers.js
new file mode 100644
index 0000000..1e8d59a
--- /dev/null
+++ b/apps/client/src/tests/helpers.js
@@ -0,0 +1,36 @@
+/**
+ * Shared test helpers.
+ *
+ * NOTE — vi.mock() calls cannot be extracted here.
+ * Vitest hoists vi.mock() to the top of each file at parse time, so the
+ * factory must be declared in the test file itself. Import this module
+ * after your vi.mock() declarations.
+ */
+import socket from '../socket.js';
+
+/**
+ * Returns the handler function registered for a socket event.
+ *
+ * useSession calls socket.on(event, fn) inside useEffect. After a render,
+ * this helper finds the exact fn so tests can trigger events manually:
+ *
+ * act(() => getSocketHandler('session_joined')({ question: mockQuestion }));
+ */
+export function getSocketHandler(event) {
+ return socket.on.mock.calls.find(([e]) => e === event)?.[1];
+}
+
+/**
+ * Shared question fixture — used by Host and Participant tests.
+ * Matches the shape emitted by the server in session_joined.
+ */
+export const mockQuestion = {
+ id: 'q1',
+ text: 'Deploy en prod le vendredi 17h ?',
+ answers: [
+ { id: 'a1', text: 'Jamais de la vie' },
+ { id: 'a2', text: "Yolo c'est vendredi" },
+ { id: 'a3', text: 'Uniquement hotfix' },
+ { id: 'a4', text: 'Je suis le seul dev' },
+ ],
+};
diff --git a/apps/client/src/utils.js b/apps/client/src/utils.js
new file mode 100644
index 0000000..1ef7559
--- /dev/null
+++ b/apps/client/src/utils.js
@@ -0,0 +1,24 @@
+/**
+ * Bar fill colors indexed by answer position.
+ * Leading answer gets brand orange, second gets gold, rest fall to grey tones.
+ */
+export const BAR_COLORS = [
+ 'var(--rd-brand)',
+ 'var(--rd-accent)',
+ 'var(--rd-muted)',
+ '#444',
+];
+
+/**
+ * Compute the vote percentage for one answer from raw server results.
+ *
+ * The server emits { answerId, count }[] — no percentages.
+ * The client derives them so the display layer stays decoupled from
+ * whatever aggregation the server chooses to send.
+ */
+export function calcPct(results, answerId) {
+ const total = results.reduce((sum, r) => sum + r.count, 0);
+ if (total === 0) return 0;
+ const found = results.find((r) => r.answerId === answerId);
+ return Math.round(((found?.count ?? 0) / total) * 100);
+}
diff --git a/apps/client/vite.config.js b/apps/client/vite.config.js
new file mode 100644
index 0000000..f02a064
--- /dev/null
+++ b/apps/client/vite.config.js
@@ -0,0 +1,11 @@
+///
+import { defineConfig } from 'vite';
+import react from '@vitejs/plugin-react';
+
+export default defineConfig({
+ plugins: [react()],
+ test: {
+ environment: 'jsdom',
+ globals: true,
+ },
+});
diff --git a/apps/server/package.json b/apps/server/package.json
index 7bdabfa..fa02d9b 100644
--- a/apps/server/package.json
+++ b/apps/server/package.json
@@ -12,6 +12,7 @@
"format:check": "prettier --check ."
},
"dependencies": {
+ "cors": "^2.8.6",
"dotenv": "^16.4.5",
"express": "^4.19.2",
"mongoose": "^8.4.1",
diff --git a/apps/server/src/app.js b/apps/server/src/app.js
index 99ef021..90f89f9 100644
--- a/apps/server/src/app.js
+++ b/apps/server/src/app.js
@@ -1,6 +1,7 @@
import express from 'express';
import { createServer } from 'http';
import { Server } from 'socket.io';
+import cors from 'cors';
import { createSessionsRouter } from './routes/sessions.js';
import { initSocket } from './socket/index.js';
@@ -10,6 +11,11 @@ const io = new Server(server, {
cors: { origin: '*' },
});
+// cors() adds Access-Control-Allow-Origin headers to every Express response.
+// Without this, browser fetch() calls from localhost:5173 are blocked by the
+// same-origin policy even though the Socket.io WS upgrade is already allowed.
+// The Socket.io cors option only covers the WebSocket handshake, not REST.
+app.use(cors());
app.use(express.json());
app.use('/sessions', createSessionsRouter(io));
diff --git a/package.json b/package.json
index c6d5fe0..538f278 100644
--- a/package.json
+++ b/package.json
@@ -4,6 +4,7 @@
"version": "0.0.0",
"type": "module",
"scripts": {
+ "dev": "pnpm -r --parallel dev",
"lint": "pnpm -r lint",
"format": "prettier --write .",
"format:check": "prettier --check .",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index f476d64..37a18ff 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -24,8 +24,57 @@ importers:
specifier: ^3.8.2
version: 3.8.2
+ apps/client:
+ dependencies:
+ canvas-confetti:
+ specifier: ^1.9.4
+ version: 1.9.4
+ react:
+ specifier: ^19.2.5
+ version: 19.2.5
+ react-dom:
+ specifier: ^19.2.5
+ version: 19.2.5(react@19.2.5)
+ react-icons:
+ specifier: ^5.6.0
+ version: 5.6.0(react@19.2.5)
+ socket.io-client:
+ specifier: ^4.8.3
+ version: 4.8.3
+ devDependencies:
+ '@testing-library/react':
+ specifier: ^16.3.2
+ version: 16.3.2(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@testing-library/user-event':
+ specifier: ^14.6.1
+ version: 14.6.1(@testing-library/dom@10.4.1)
+ '@vitejs/plugin-react':
+ specifier: ^6.0.1
+ version: 6.0.1(vite@8.0.8(@types/node@25.5.2))
+ '@vitest/coverage-v8':
+ specifier: '4'
+ version: 4.1.4(vitest@4.1.4)
+ eslint-plugin-react-hooks:
+ specifier: ^7.0.1
+ version: 7.0.1(eslint@10.2.0)
+ eslint-plugin-react-refresh:
+ specifier: ^0.5.2
+ version: 0.5.2(eslint@10.2.0)
+ jsdom:
+ specifier: ^29.0.2
+ version: 29.0.2(@noble/hashes@1.8.0)
+ vite:
+ specifier: ^8.0.4
+ version: 8.0.8(@types/node@25.5.2)
+ vitest:
+ specifier: '4'
+ version: 4.1.4(@types/node@25.5.2)(@vitest/coverage-v8@4.1.4)(jsdom@29.0.2(@noble/hashes@1.8.0))(vite@8.0.8(@types/node@25.5.2))
+
apps/server:
dependencies:
+ cors:
+ specifier: ^2.8.6
+ version: 2.8.6
dotenv:
specifier: ^16.4.5
version: 16.6.1
@@ -50,10 +99,145 @@ importers:
version: 7.2.2
vitest:
specifier: ^1.6.0
- version: 1.6.1(@types/node@25.5.2)
+ version: 1.6.1(@types/node@25.5.2)(jsdom@29.0.2(@noble/hashes@1.8.0))(lightningcss@1.32.0)
packages:
+ '@asamuzakjp/css-color@5.1.10':
+ resolution: {integrity: sha512-02OhhkKtgNRuicQ/nF3TRnGsxL9wp0r3Y7VlKWyOHHGmGyvXv03y+PnymU8FKFJMTjIr1Bk8U2g1HWSLrpAHww==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
+
+ '@asamuzakjp/dom-selector@7.0.9':
+ resolution: {integrity: sha512-r3ElRr7y8ucyN2KdICwGsmj19RoN13CLCa/pvGydghWK6ZzeKQ+TcDjVdtEZz2ElpndM5jXw//B9CEee0mWnVg==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
+
+ '@asamuzakjp/nwsapi@2.3.9':
+ resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==}
+
+ '@babel/code-frame@7.29.0':
+ resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/compat-data@7.29.0':
+ resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/core@7.29.0':
+ resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/generator@7.29.1':
+ resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-compilation-targets@7.28.6':
+ resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-globals@7.28.0':
+ resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-module-imports@7.28.6':
+ resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-module-transforms@7.28.6':
+ resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+
+ '@babel/helper-string-parser@7.27.1':
+ resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-validator-identifier@7.28.5':
+ resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-validator-option@7.27.1':
+ resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helpers@7.29.2':
+ resolution: {integrity: sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/parser@7.29.2':
+ resolution: {integrity: sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+
+ '@babel/runtime@7.29.2':
+ resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/template@7.28.6':
+ resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/traverse@7.29.0':
+ resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/types@7.29.0':
+ resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==}
+ engines: {node: '>=6.9.0'}
+
+ '@bcoe/v8-coverage@1.0.2':
+ resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==}
+ engines: {node: '>=18'}
+
+ '@bramus/specificity@2.4.2':
+ resolution: {integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==}
+ hasBin: true
+
+ '@csstools/color-helpers@6.0.2':
+ resolution: {integrity: sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==}
+ engines: {node: '>=20.19.0'}
+
+ '@csstools/css-calc@3.1.1':
+ resolution: {integrity: sha512-HJ26Z/vmsZQqs/o3a6bgKslXGFAungXGbinULZO3eMsOyNJHeBBZfup5FiZInOghgoM4Hwnmw+OgbJCNg1wwUQ==}
+ engines: {node: '>=20.19.0'}
+ peerDependencies:
+ '@csstools/css-parser-algorithms': ^4.0.0
+ '@csstools/css-tokenizer': ^4.0.0
+
+ '@csstools/css-color-parser@4.0.2':
+ resolution: {integrity: sha512-0GEfbBLmTFf0dJlpsNU7zwxRIH0/BGEMuXLTCvFYxuL1tNhqzTbtnFICyJLTNK4a+RechKP75e7w42ClXSnJQw==}
+ engines: {node: '>=20.19.0'}
+ peerDependencies:
+ '@csstools/css-parser-algorithms': ^4.0.0
+ '@csstools/css-tokenizer': ^4.0.0
+
+ '@csstools/css-parser-algorithms@4.0.0':
+ resolution: {integrity: sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==}
+ engines: {node: '>=20.19.0'}
+ peerDependencies:
+ '@csstools/css-tokenizer': ^4.0.0
+
+ '@csstools/css-syntax-patches-for-csstree@1.1.2':
+ resolution: {integrity: sha512-5GkLzz4prTIpoyeUiIu3iV6CSG3Plo7xRVOFPKI7FVEJ3mZ0A8SwK0XU3Gl7xAkiQ+mDyam+NNp875/C5y+jSA==}
+ peerDependencies:
+ css-tree: ^3.2.1
+ peerDependenciesMeta:
+ css-tree:
+ optional: true
+
+ '@csstools/css-tokenizer@4.0.0':
+ resolution: {integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==}
+ engines: {node: '>=20.19.0'}
+
+ '@emnapi/core@1.9.2':
+ resolution: {integrity: sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==}
+
+ '@emnapi/runtime@1.9.2':
+ resolution: {integrity: sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==}
+
+ '@emnapi/wasi-threads@1.2.1':
+ resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==}
+
'@esbuild/aix-ppc64@0.21.5':
resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==}
engines: {node: '>=12'}
@@ -231,6 +415,15 @@ packages:
resolution: {integrity: sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ==}
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
+ '@exodus/bytes@1.15.0':
+ resolution: {integrity: sha512-UY0nlA+feH81UGSHv92sLEPLCeZFjXOuHhrIo0HQydScuQc8s0A7kL/UdgwgDq8g8ilksmuoF35YVTNphV2aBQ==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
+ peerDependencies:
+ '@noble/hashes': ^1.8.0 || ^2.0.0
+ peerDependenciesMeta:
+ '@noble/hashes':
+ optional: true
+
'@humanfs/core@0.19.1':
resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
engines: {node: '>=18.18.0'}
@@ -251,19 +444,142 @@ packages:
resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ '@jridgewell/gen-mapping@0.3.13':
+ resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
+
+ '@jridgewell/remapping@2.3.5':
+ resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==}
+
+ '@jridgewell/resolve-uri@3.1.2':
+ resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
+ engines: {node: '>=6.0.0'}
+
'@jridgewell/sourcemap-codec@1.5.5':
resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
+ '@jridgewell/trace-mapping@0.3.31':
+ resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
+
'@mongodb-js/saslprep@1.4.6':
resolution: {integrity: sha512-y+x3H1xBZd38n10NZF/rEBlvDOOMQ6LKUTHqr8R9VkJ+mmQOYtJFxIlkkK8fZrtOiL6VixbOBWMbZGBdal3Z1g==}
+ '@napi-rs/wasm-runtime@1.1.3':
+ resolution: {integrity: sha512-xK9sGVbJWYb08+mTJt3/YV24WxvxpXcXtP6B172paPZ+Ts69Re9dAr7lKwJoeIx8OoeuimEiRZ7umkiUVClmmQ==}
+ peerDependencies:
+ '@emnapi/core': ^1.7.1
+ '@emnapi/runtime': ^1.7.1
+
'@noble/hashes@1.8.0':
resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==}
engines: {node: ^14.21.3 || >=16}
+ '@oxc-project/types@0.124.0':
+ resolution: {integrity: sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg==}
+
'@paralleldrive/cuid2@2.3.1':
resolution: {integrity: sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==}
+ '@rolldown/binding-android-arm64@1.0.0-rc.15':
+ resolution: {integrity: sha512-YYe6aWruPZDtHNpwu7+qAHEMbQ/yRl6atqb/AhznLTnD3UY99Q1jE7ihLSahNWkF4EqRPVC4SiR4O0UkLK02tA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [android]
+
+ '@rolldown/binding-darwin-arm64@1.0.0-rc.15':
+ resolution: {integrity: sha512-oArR/ig8wNTPYsXL+Mzhs0oxhxfuHRfG7Ikw7jXsw8mYOtk71W0OkF2VEVh699pdmzjPQsTjlD1JIOoHkLP1Fg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@rolldown/binding-darwin-x64@1.0.0-rc.15':
+ resolution: {integrity: sha512-YzeVqOqjPYvUbJSWJ4EDL8ahbmsIXQpgL3JVipmN+MX0XnXMeWomLN3Fb+nwCmP/jfyqte5I3XRSm7OfQrbyxw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [darwin]
+
+ '@rolldown/binding-freebsd-x64@1.0.0-rc.15':
+ resolution: {integrity: sha512-9Erhx956jeQ0nNTyif1+QWAXDRD38ZNjr//bSHrt6wDwB+QkAfl2q6Mn1k6OBPerznjRmbM10lgRb1Pli4xZPw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.15':
+ resolution: {integrity: sha512-cVwk0w8QbZJGTnP/AHQBs5yNwmpgGYStL88t4UIaqcvYJWBfS0s3oqVLZPwsPU6M0zlW4GqjP0Zq5MnAGwFeGA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm]
+ os: [linux]
+
+ '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.15':
+ resolution: {integrity: sha512-eBZ/u8iAK9SoHGanqe/jrPnY0JvBN6iXbVOsbO38mbz+ZJsaobExAm1Iu+rxa4S1l2FjG0qEZn4Rc6X8n+9M+w==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [linux]
+ libc: [glibc]
+
+ '@rolldown/binding-linux-arm64-musl@1.0.0-rc.15':
+ resolution: {integrity: sha512-ZvRYMGrAklV9PEkgt4LQM6MjQX2P58HPAuecwYObY2DhS2t35R0I810bKi0wmaYORt6m/2Sm+Z+nFgb0WhXNcQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [linux]
+ libc: [musl]
+
+ '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.15':
+ resolution: {integrity: sha512-VDpgGBzgfg5hLg+uBpCLoFG5kVvEyafmfxGUV0UHLcL5irxAK7PKNeC2MwClgk6ZAiNhmo9FLhRYgvMmedLtnQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [ppc64]
+ os: [linux]
+ libc: [glibc]
+
+ '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.15':
+ resolution: {integrity: sha512-y1uXY3qQWCzcPgRJATPSOUP4tCemh4uBdY7e3EZbVwCJTY3gLJWnQABgeUetvED+bt1FQ01OeZwvhLS2bpNrAQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [s390x]
+ os: [linux]
+ libc: [glibc]
+
+ '@rolldown/binding-linux-x64-gnu@1.0.0-rc.15':
+ resolution: {integrity: sha512-023bTPBod7J3Y/4fzAN6QtpkSABR0rigtrwaP+qSEabUh5zf6ELr9Nc7GujaROuPY3uwdSIXWrvhn1KxOvurWA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [linux]
+ libc: [glibc]
+
+ '@rolldown/binding-linux-x64-musl@1.0.0-rc.15':
+ resolution: {integrity: sha512-witB2O0/hU4CgfOOKUoeFgQ4GktPi1eEbAhaLAIpgD6+ZnhcPkUtPsoKKHRzmOoWPZue46IThdSgdo4XneOLYw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [linux]
+ libc: [musl]
+
+ '@rolldown/binding-openharmony-arm64@1.0.0-rc.15':
+ resolution: {integrity: sha512-UCL68NJ0Ud5zRipXZE9dF5PmirzJE4E4BCIOOssEnM7wLDsxjc6Qb0sGDxTNRTP53I6MZpygyCpY8Aa8sPfKPg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [openharmony]
+
+ '@rolldown/binding-wasm32-wasi@1.0.0-rc.15':
+ resolution: {integrity: sha512-ApLruZq/ig+nhaE7OJm4lDjayUnOHVUa77zGeqnqZ9pn0ovdVbbNPerVibLXDmWeUZXjIYIT8V3xkT58Rm9u5Q==}
+ engines: {node: '>=14.0.0'}
+ cpu: [wasm32]
+
+ '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.15':
+ resolution: {integrity: sha512-KmoUoU7HnN+Si5YWJigfTws1jz1bKBYDQKdbLspz0UaqjjFkddHsqorgiW1mxcAj88lYUE6NC/zJNwT+SloqtA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [win32]
+
+ '@rolldown/binding-win32-x64-msvc@1.0.0-rc.15':
+ resolution: {integrity: sha512-3P2A8L+x75qavWLe/Dll3EYBJLQmtkJN8rfh+U/eR3MqMgL/h98PhYI+JFfXuDPgPeCB7iZAKiqii5vqOvnA0g==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [win32]
+
+ '@rolldown/pluginutils@1.0.0-rc.15':
+ resolution: {integrity: sha512-UromN0peaE53IaBRe9W7CjrZgXl90fqGpK+mIZbA3qSTeYqg3pqpROBdIPvOG3F5ereDHNwoHBI2e50n1BDr1g==}
+
+ '@rolldown/pluginutils@1.0.0-rc.7':
+ resolution: {integrity: sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==}
+
'@rollup/rollup-android-arm-eabi@4.60.1':
resolution: {integrity: sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA==}
cpu: [arm]
@@ -408,9 +724,49 @@ packages:
'@socket.io/component-emitter@3.1.2':
resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==}
+ '@standard-schema/spec@1.1.0':
+ resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==}
+
+ '@testing-library/dom@10.4.1':
+ resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==}
+ engines: {node: '>=18'}
+
+ '@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
+
+ '@testing-library/user-event@14.6.1':
+ resolution: {integrity: sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==}
+ engines: {node: '>=12', npm: '>=6'}
+ peerDependencies:
+ '@testing-library/dom': '>=7.21.4'
+
+ '@tybys/wasm-util@0.10.1':
+ resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==}
+
+ '@types/aria-query@5.0.4':
+ resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==}
+
+ '@types/chai@5.2.3':
+ resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==}
+
'@types/cors@2.8.19':
resolution: {integrity: sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==}
+ '@types/deep-eql@4.0.2':
+ resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==}
+
'@types/esrecurse@4.3.1':
resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==}
@@ -432,21 +788,72 @@ packages:
'@types/ws@8.18.1':
resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==}
+ '@vitejs/plugin-react@6.0.1':
+ resolution: {integrity: sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ peerDependencies:
+ '@rolldown/plugin-babel': ^0.1.7 || ^0.2.0
+ babel-plugin-react-compiler: ^1.0.0
+ vite: ^8.0.0
+ peerDependenciesMeta:
+ '@rolldown/plugin-babel':
+ optional: true
+ babel-plugin-react-compiler:
+ optional: true
+
+ '@vitest/coverage-v8@4.1.4':
+ resolution: {integrity: sha512-x7FptB5oDruxNPDNY2+S8tCh0pcq7ymCe1gTHcsp733jYjrJl8V1gMUlVysuCD9Kz46Xz9t1akkv08dPcYDs1w==}
+ peerDependencies:
+ '@vitest/browser': 4.1.4
+ vitest: 4.1.4
+ peerDependenciesMeta:
+ '@vitest/browser':
+ optional: true
+
'@vitest/expect@1.6.1':
resolution: {integrity: sha512-jXL+9+ZNIJKruofqXuuTClf44eSpcHlgj3CiuNihUF3Ioujtmc0zIa3UJOW5RjDK1YLBJZnWBlPuqhYycLioog==}
+ '@vitest/expect@4.1.4':
+ resolution: {integrity: sha512-iPBpra+VDuXmBFI3FMKHSFXp3Gx5HfmSCE8X67Dn+bwephCnQCaB7qWK2ldHa+8ncN8hJU8VTMcxjPpyMkUjww==}
+
+ '@vitest/mocker@4.1.4':
+ resolution: {integrity: sha512-R9HTZBhW6yCSGbGQnDnH3QHfJxokKN4KB+Yvk9Q1le7eQNYwiCyKxmLmurSpFy6BzJanSLuEUDrD+j97Q+ZLPg==}
+ peerDependencies:
+ msw: ^2.4.9
+ vite: ^6.0.0 || ^7.0.0 || ^8.0.0
+ peerDependenciesMeta:
+ msw:
+ optional: true
+ vite:
+ optional: true
+
+ '@vitest/pretty-format@4.1.4':
+ resolution: {integrity: sha512-ddmDHU0gjEUyEVLxtZa7xamrpIefdEETu3nZjWtHeZX4QxqJ7tRxSteHVXJOcr8jhiLoGAhkK4WJ3WqBpjx42A==}
+
'@vitest/runner@1.6.1':
resolution: {integrity: sha512-3nSnYXkVkf3mXFfE7vVyPmi3Sazhb/2cfZGGs0JRzFsPFvAMBEcrweV1V1GsrstdXeKCTXlJbvnQwGWgEIHmOA==}
+ '@vitest/runner@4.1.4':
+ resolution: {integrity: sha512-xTp7VZ5aXP5ZJrn15UtJUWlx6qXLnGtF6jNxHepdPHpMfz/aVPx+htHtgcAL2mDXJgKhpoo2e9/hVJsIeFbytQ==}
+
'@vitest/snapshot@1.6.1':
resolution: {integrity: sha512-WvidQuWAzU2p95u8GAKlRMqMyN1yOJkGHnx3M1PL9Raf7AQ1kwLKg04ADlCa3+OXUZE7BceOhVZiuWAbzCKcUQ==}
+ '@vitest/snapshot@4.1.4':
+ resolution: {integrity: sha512-MCjCFgaS8aZz+m5nTcEcgk/xhWv0rEH4Yl53PPlMXOZ1/Ka2VcZU6CJ+MgYCZbcJvzGhQRjVrGQNZqkGPttIKw==}
+
'@vitest/spy@1.6.1':
resolution: {integrity: sha512-MGcMmpGkZebsMZhbQKkAf9CX5zGvjkBTqf8Zx3ApYWXr3wG+QvEu2eXWfnIIWYSJExIp4V9FCKDEeygzkYrXMw==}
+ '@vitest/spy@4.1.4':
+ resolution: {integrity: sha512-XxNdAsKW7C+FLydqFJLb5KhJtl3PGCMmYwFRfhvIgxJvLSXhhVI1zM8f1qD3Zg7RCjTSzDVyct6sghs9UEgBEQ==}
+
'@vitest/utils@1.6.1':
resolution: {integrity: sha512-jOrrUvXM4Av9ZWiG1EajNto0u96kWAhJ1LmPmJhXXQx/32MecEKd10pOLYgS2BQx1TgkGhloPU1ArDW2vvaY6g==}
+ '@vitest/utils@4.1.4':
+ resolution: {integrity: sha512-13QMT+eysM5uVGa1rG4kegGYNp6cnQcsTc67ELFbhNLQO+vgsygtYJx2khvdt4gVQqSSpC/KT5FZZxUpP3Oatw==}
+
accepts@1.3.8:
resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
engines: {node: '>= 0.6'}
@@ -468,6 +875,10 @@ packages:
ajv@6.14.0:
resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==}
+ ansi-regex@5.0.1:
+ resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
+ engines: {node: '>=8'}
+
ansi-styles@5.2.0:
resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==}
engines: {node: '>=10'}
@@ -476,6 +887,9 @@ packages:
resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
engines: {node: '>= 8'}
+ aria-query@5.3.0:
+ resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==}
+
array-flatten@1.1.1:
resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==}
@@ -485,6 +899,13 @@ packages:
assertion-error@1.1.0:
resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==}
+ assertion-error@2.0.1:
+ resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
+ engines: {node: '>=12'}
+
+ ast-v8-to-istanbul@1.0.0:
+ resolution: {integrity: sha512-1fSfIwuDICFA4LKkCzRPO7F0hzFf0B7+Xqrl27ynQaa+Rh0e1Es0v6kWHPott3lU10AyAr7oKHa65OppjLn3Rg==}
+
asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
@@ -496,6 +917,14 @@ packages:
resolution: {integrity: sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==}
engines: {node: ^4.5.0 || >= 5.9}
+ baseline-browser-mapping@2.10.18:
+ resolution: {integrity: sha512-VSnGQAOLtP5mib/DPyg2/t+Tlv65NTBz83BJBJvmLVHHuKJVaDOBvJJykiT5TR++em5nfAySPccDZDa4oSrn8A==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+
+ bidi-js@1.0.3:
+ resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==}
+
binary-extensions@2.3.0:
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
engines: {node: '>=8'}
@@ -512,6 +941,11 @@ packages:
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
engines: {node: '>=8'}
+ browserslist@4.28.2:
+ resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==}
+ engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
+ hasBin: true
+
bson@6.10.4:
resolution: {integrity: sha512-WIsKqkSC0ABoBJuT1LEX+2HEvNmNKKgnTAyd0fL8qzK4SH2i9NXg+t08YtdZp/V9IZ33cxe3iV4yM0qg8lMQng==}
engines: {node: '>=16.20.1'}
@@ -532,10 +966,20 @@ packages:
resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==}
engines: {node: '>= 0.4'}
+ caniuse-lite@1.0.30001787:
+ resolution: {integrity: sha512-mNcrMN9KeI68u7muanUpEejSLghOKlVhRqS/Za2IeyGllJ9I9otGpR9g3nsw7n4W378TE/LyIteA0+/FOZm4Kg==}
+
+ canvas-confetti@1.9.4:
+ resolution: {integrity: sha512-yxQbJkAVrFXWNbTUjPqjF7G+g6pDotOUHGbkZq2NELZUMDpiJ85rIEazVb8GTaAptNW2miJAXbs1BtioA251Pw==}
+
chai@4.5.0:
resolution: {integrity: sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==}
engines: {node: '>=4'}
+ chai@6.2.2:
+ resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==}
+ engines: {node: '>=18'}
+
check-error@1.0.3:
resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==}
@@ -561,6 +1005,9 @@ packages:
resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
engines: {node: '>= 0.6'}
+ convert-source-map@2.0.0:
+ resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
+
cookie-signature@1.0.7:
resolution: {integrity: sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==}
@@ -583,6 +1030,14 @@ packages:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'}
+ css-tree@3.2.1:
+ resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==}
+ engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
+
+ data-urls@7.0.0:
+ resolution: {integrity: sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
+
debug@2.6.9:
resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
peerDependencies:
@@ -600,6 +1055,9 @@ packages:
supports-color:
optional: true
+ decimal.js@10.6.0:
+ resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==}
+
deep-eql@4.1.4:
resolution: {integrity: sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==}
engines: {node: '>=6'}
@@ -615,10 +1073,18 @@ packages:
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
engines: {node: '>= 0.8'}
+ dequal@2.0.3:
+ resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
+ engines: {node: '>=6'}
+
destroy@1.2.0:
resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==}
engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
+ detect-libc@2.1.2:
+ resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
+ engines: {node: '>=8'}
+
dezalgo@1.0.4:
resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==}
@@ -626,6 +1092,9 @@ packages:
resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ dom-accessibility-api@0.5.16:
+ resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==}
+
dotenv@16.6.1:
resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==}
engines: {node: '>=12'}
@@ -637,6 +1106,9 @@ packages:
ee-first@1.1.1:
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
+ electron-to-chromium@1.5.335:
+ resolution: {integrity: sha512-q9n5T4BR4Xwa2cwbrwcsDJtHD/enpQ5S1xF1IAtdqf5AAgqDFmR/aakqH3ChFdqd/QXJhS3rnnXFtexU7rax6Q==}
+
encodeurl@2.0.0:
resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==}
engines: {node: '>= 0.8'}
@@ -652,6 +1124,10 @@ packages:
resolution: {integrity: sha512-U2SN0w3OpjFRVlrc17E6TMDmH58Xl9rai1MblNjAdwWp07Kk+llmzX0hjDpQdrDGzwmvOtgM5yI+meYX6iZ2xA==}
engines: {node: '>=10.2.0'}
+ entities@6.0.1:
+ resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==}
+ engines: {node: '>=0.12'}
+
es-define-property@1.0.1:
resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
engines: {node: '>= 0.4'}
@@ -660,6 +1136,9 @@ packages:
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
engines: {node: '>= 0.4'}
+ es-module-lexer@2.0.0:
+ resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==}
+
es-object-atoms@1.1.1:
resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
engines: {node: '>= 0.4'}
@@ -673,6 +1152,10 @@ packages:
engines: {node: '>=12'}
hasBin: true
+ escalade@3.2.0:
+ resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
+ engines: {node: '>=6'}
+
escape-html@1.0.3:
resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
@@ -686,6 +1169,17 @@ packages:
peerDependencies:
eslint: '>=7.0.0'
+ eslint-plugin-react-hooks@7.0.1:
+ resolution: {integrity: sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0
+
+ eslint-plugin-react-refresh@0.5.2:
+ resolution: {integrity: sha512-hmgTH57GfzoTFjVN0yBwTggnsVUF2tcqi7RJZHqi9lIezSs4eFyAMktA68YD4r5kNw1mxyY4dmkyoFDb3FIqrA==}
+ peerDependencies:
+ eslint: ^9 || ^10
+
eslint-scope@9.1.2:
resolution: {integrity: sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==}
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
@@ -739,6 +1233,10 @@ packages:
resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==}
engines: {node: '>=16.17'}
+ expect-type@1.3.0:
+ resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==}
+ engines: {node: '>=12.0.0'}
+
express@4.22.1:
resolution: {integrity: sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==}
engines: {node: '>= 0.10.0'}
@@ -755,6 +1253,15 @@ packages:
fast-safe-stringify@2.1.1:
resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==}
+ fdir@6.5.0:
+ resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
+ engines: {node: '>=12.0.0'}
+ peerDependencies:
+ picomatch: ^3 || ^4
+ peerDependenciesMeta:
+ picomatch:
+ optional: true
+
file-entry-cache@8.0.0:
resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
engines: {node: '>=16.0.0'}
@@ -802,6 +1309,10 @@ packages:
function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
+ gensync@1.0.0-beta.2:
+ resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
+ engines: {node: '>=6.9.0'}
+
get-func-name@2.0.2:
resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==}
@@ -837,6 +1348,10 @@ packages:
resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
engines: {node: '>=4'}
+ has-flag@4.0.0:
+ resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
+ engines: {node: '>=8'}
+
has-symbols@1.1.0:
resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
engines: {node: '>= 0.4'}
@@ -849,6 +1364,19 @@ packages:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'}
+ hermes-estree@0.25.1:
+ resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==}
+
+ hermes-parser@0.25.1:
+ resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==}
+
+ html-encoding-sniffer@6.0.0:
+ resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
+
+ html-escaper@2.0.2:
+ resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
+
http-errors@2.0.1:
resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==}
engines: {node: '>= 0.8'}
@@ -895,6 +1423,9 @@ packages:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
+ is-potential-custom-element-name@1.0.1:
+ resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
+
is-stream@3.0.0:
resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@@ -902,9 +1433,41 @@ packages:
isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+ istanbul-lib-coverage@3.2.2:
+ resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==}
+ engines: {node: '>=8'}
+
+ istanbul-lib-report@3.0.1:
+ resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==}
+ engines: {node: '>=10'}
+
+ istanbul-reports@3.2.0:
+ resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==}
+ engines: {node: '>=8'}
+
+ js-tokens@10.0.0:
+ resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==}
+
+ js-tokens@4.0.0:
+ resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+
js-tokens@9.0.1:
resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==}
+ jsdom@29.0.2:
+ resolution: {integrity: sha512-9VnGEBosc/ZpwyOsJBCQ/3I5p7Q5ngOY14a9bf5btenAORmZfDse1ZEheMiWcJ3h81+Fv7HmJFdS0szo/waF2w==}
+ engines: {node: ^20.19.0 || ^22.13.0 || >=24.0.0}
+ peerDependencies:
+ canvas: ^3.0.0
+ peerDependenciesMeta:
+ canvas:
+ optional: true
+
+ jsesc@3.1.0:
+ resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
+ engines: {node: '>=6'}
+ hasBin: true
+
json-buffer@3.0.1:
resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
@@ -914,6 +1477,11 @@ packages:
json-stable-stringify-without-jsonify@1.0.1:
resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
+ json5@2.2.3:
+ resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
+ engines: {node: '>=6'}
+ hasBin: true
+
kareem@2.6.3:
resolution: {integrity: sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==}
engines: {node: '>=12.0.0'}
@@ -925,6 +1493,80 @@ packages:
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
engines: {node: '>= 0.8.0'}
+ lightningcss-android-arm64@1.32.0:
+ resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [android]
+
+ lightningcss-darwin-arm64@1.32.0:
+ resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [darwin]
+
+ lightningcss-darwin-x64@1.32.0:
+ resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [darwin]
+
+ lightningcss-freebsd-x64@1.32.0:
+ resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [freebsd]
+
+ lightningcss-linux-arm-gnueabihf@1.32.0:
+ resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm]
+ os: [linux]
+
+ lightningcss-linux-arm64-gnu@1.32.0:
+ resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [linux]
+ libc: [glibc]
+
+ lightningcss-linux-arm64-musl@1.32.0:
+ resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [linux]
+ libc: [musl]
+
+ lightningcss-linux-x64-gnu@1.32.0:
+ resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [linux]
+ libc: [glibc]
+
+ lightningcss-linux-x64-musl@1.32.0:
+ resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [linux]
+ libc: [musl]
+
+ lightningcss-win32-arm64-msvc@1.32.0:
+ resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [win32]
+
+ lightningcss-win32-x64-msvc@1.32.0:
+ resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [win32]
+
+ lightningcss@1.32.0:
+ resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==}
+ engines: {node: '>= 12.0.0'}
+
local-pkg@0.5.1:
resolution: {integrity: sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==}
engines: {node: '>=14'}
@@ -936,13 +1578,34 @@ packages:
loupe@2.3.7:
resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==}
+ lru-cache@11.3.3:
+ resolution: {integrity: sha512-JvNw9Y81y33E+BEYPr0U7omo+U9AySnsMsEiXgwT6yqd31VQWTLNQqmT4ou5eqPFUrTfIDFta2wKhB1hyohtAQ==}
+ engines: {node: 20 || >=22}
+
+ lru-cache@5.1.1:
+ resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+
+ lz-string@1.5.0:
+ resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==}
+ hasBin: true
+
magic-string@0.30.21:
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
+ magicast@0.5.2:
+ resolution: {integrity: sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==}
+
+ make-dir@4.0.0:
+ resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
+ engines: {node: '>=10'}
+
math-intrinsics@1.1.0:
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
engines: {node: '>= 0.4'}
+ mdn-data@2.27.1:
+ resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==}
+
media-typer@0.3.0:
resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
engines: {node: '>= 0.6'}
@@ -1049,6 +1712,9 @@ packages:
resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
engines: {node: '>= 0.6'}
+ node-releases@2.0.37:
+ resolution: {integrity: sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==}
+
nodemon@3.1.14:
resolution: {integrity: sha512-jakjZi93UtB3jHMWsXL68FXSAosbLfY0In5gtKq3niLSkrWznrVBzXFNOEMJUfc9+Ke7SHWoAZsiMkNP3vq6Jw==}
engines: {node: '>=10'}
@@ -1070,6 +1736,9 @@ packages:
resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
engines: {node: '>= 0.4'}
+ obug@2.1.1:
+ resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==}
+
on-finished@2.4.1:
resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
engines: {node: '>= 0.8'}
@@ -1097,6 +1766,9 @@ packages:
resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
engines: {node: '>=10'}
+ parse5@8.0.0:
+ resolution: {integrity: sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==}
+
parseurl@1.3.3:
resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
engines: {node: '>= 0.8'}
@@ -1132,6 +1804,10 @@ packages:
resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==}
engines: {node: '>=8.6'}
+ picomatch@4.0.4:
+ resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==}
+ engines: {node: '>=12'}
+
pkg-types@1.3.1:
resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==}
@@ -1148,6 +1824,10 @@ packages:
engines: {node: '>=14'}
hasBin: true
+ pretty-format@27.5.1:
+ resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==}
+ engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
+
pretty-format@29.7.0:
resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -1179,13 +1859,39 @@ packages:
resolution: {integrity: sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==}
engines: {node: '>= 0.8'}
+ react-dom@19.2.5:
+ resolution: {integrity: sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==}
+ peerDependencies:
+ react: ^19.2.5
+
+ react-icons@5.6.0:
+ resolution: {integrity: sha512-RH93p5ki6LfOiIt0UtDyNg/cee+HLVR6cHHtW3wALfo+eOHTp8RnU2kRkI6E+H19zMIs03DyxUG/GfZMOGvmiA==}
+ peerDependencies:
+ react: '*'
+
+ react-is@17.0.2:
+ resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==}
+
react-is@18.3.1:
resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==}
+ react@19.2.5:
+ resolution: {integrity: sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==}
+ engines: {node: '>=0.10.0'}
+
readdirp@3.6.0:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'}
+ require-from-string@2.0.2:
+ resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
+ engines: {node: '>=0.10.0'}
+
+ rolldown@1.0.0-rc.15:
+ resolution: {integrity: sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ hasBin: true
+
rollup@4.60.1:
resolution: {integrity: sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==}
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
@@ -1197,6 +1903,17 @@ packages:
safer-buffer@2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
+ saxes@6.0.0:
+ resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==}
+ engines: {node: '>=v12.22.7'}
+
+ scheduler@0.27.0:
+ resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==}
+
+ semver@6.3.1:
+ resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
+ hasBin: true
+
semver@7.7.4:
resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==}
engines: {node: '>=10'}
@@ -1283,6 +2000,9 @@ packages:
std-env@3.10.0:
resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==}
+ std-env@4.0.0:
+ resolution: {integrity: sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==}
+
strip-final-newline@3.0.0:
resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==}
engines: {node: '>=12'}
@@ -1302,17 +2022,43 @@ packages:
resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
engines: {node: '>=4'}
+ supports-color@7.2.0:
+ resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
+ engines: {node: '>=8'}
+
+ symbol-tree@3.2.4:
+ resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
+
tinybench@2.9.0:
resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
+ tinyexec@1.1.1:
+ resolution: {integrity: sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==}
+ engines: {node: '>=18'}
+
+ tinyglobby@0.2.16:
+ resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==}
+ engines: {node: '>=12.0.0'}
+
tinypool@0.8.4:
resolution: {integrity: sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==}
engines: {node: '>=14.0.0'}
+ tinyrainbow@3.1.0:
+ resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==}
+ engines: {node: '>=14.0.0'}
+
tinyspy@2.2.1:
resolution: {integrity: sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==}
engines: {node: '>=14.0.0'}
+ tldts-core@7.0.28:
+ resolution: {integrity: sha512-7W5Efjhsc3chVdFhqtaU0KtK32J37Zcr9RKtID54nG+tIpcY79CQK/veYPODxtD/LJ4Lue66jvrQzIX2Z2/pUQ==}
+
+ tldts@7.0.28:
+ resolution: {integrity: sha512-+Zg3vWhRUv8B1maGSTFdev9mjoo8Etn2Ayfs4cnjlD3CsGkxXX4QyW3j2WJ0wdjYcYmy7Lx2RDsZMhgCWafKIw==}
+ hasBin: true
+
to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
@@ -1325,10 +2071,21 @@ packages:
resolution: {integrity: sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==}
hasBin: true
+ tough-cookie@6.0.1:
+ resolution: {integrity: sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==}
+ engines: {node: '>=16'}
+
tr46@5.1.1:
resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==}
engines: {node: '>=18'}
+ tr46@6.0.0:
+ resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==}
+ engines: {node: '>=20'}
+
+ tslib@2.8.1:
+ resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
+
type-check@0.4.0:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'}
@@ -1350,10 +2107,20 @@ packages:
undici-types@7.18.2:
resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==}
+ undici@7.24.7:
+ resolution: {integrity: sha512-H/nlJ/h0ggGC+uRL3ovD+G0i4bqhvsDOpbDv7At5eFLlj2b41L8QliGbnl2H7SnDiYhENphh1tQFJZf+MyfLsQ==}
+ engines: {node: '>=20.18.1'}
+
unpipe@1.0.0:
resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
engines: {node: '>= 0.8'}
+ update-browserslist-db@1.2.3:
+ resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==}
+ hasBin: true
+ peerDependencies:
+ browserslist: '>= 4.21.0'
+
uri-js@4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
@@ -1401,6 +2168,49 @@ packages:
terser:
optional: true
+ vite@8.0.8:
+ resolution: {integrity: sha512-dbU7/iLVa8KZALJyLOBOQ88nOXtNG8vxKuOT4I2mD+Ya70KPceF4IAmDsmU0h1Qsn5bPrvsY9HJstCRh3hG6Uw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ hasBin: true
+ peerDependencies:
+ '@types/node': ^20.19.0 || >=22.12.0
+ '@vitejs/devtools': ^0.1.0
+ esbuild: ^0.27.0 || ^0.28.0
+ jiti: '>=1.21.0'
+ less: ^4.0.0
+ sass: ^1.70.0
+ sass-embedded: ^1.70.0
+ stylus: '>=0.54.8'
+ sugarss: ^5.0.0
+ terser: ^5.16.0
+ tsx: ^4.8.1
+ yaml: ^2.4.2
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+ '@vitejs/devtools':
+ optional: true
+ esbuild:
+ optional: true
+ jiti:
+ optional: true
+ less:
+ optional: true
+ sass:
+ optional: true
+ sass-embedded:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+ tsx:
+ optional: true
+ yaml:
+ optional: true
+
vitest@1.6.1:
resolution: {integrity: sha512-Ljb1cnSJSivGN0LqXd/zmDbWEM0RNNg2t1QW/XUhYl/qPqyu7CsqeWtqQXHVaJsecLPuDoak2oJcZN2QoRIOag==}
engines: {node: ^18.0.0 || >=20.0.0}
@@ -1426,14 +2236,71 @@ packages:
jsdom:
optional: true
+ vitest@4.1.4:
+ resolution: {integrity: sha512-tFuJqTxKb8AvfyqMfnavXdzfy3h3sWZRWwfluGbkeR7n0HUev+FmNgZ8SDrRBTVrVCjgH5cA21qGbCffMNtWvg==}
+ engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0}
+ hasBin: true
+ peerDependencies:
+ '@edge-runtime/vm': '*'
+ '@opentelemetry/api': ^1.9.0
+ '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0
+ '@vitest/browser-playwright': 4.1.4
+ '@vitest/browser-preview': 4.1.4
+ '@vitest/browser-webdriverio': 4.1.4
+ '@vitest/coverage-istanbul': 4.1.4
+ '@vitest/coverage-v8': 4.1.4
+ '@vitest/ui': 4.1.4
+ happy-dom: '*'
+ jsdom: '*'
+ vite: ^6.0.0 || ^7.0.0 || ^8.0.0
+ peerDependenciesMeta:
+ '@edge-runtime/vm':
+ optional: true
+ '@opentelemetry/api':
+ optional: true
+ '@types/node':
+ optional: true
+ '@vitest/browser-playwright':
+ optional: true
+ '@vitest/browser-preview':
+ optional: true
+ '@vitest/browser-webdriverio':
+ optional: true
+ '@vitest/coverage-istanbul':
+ optional: true
+ '@vitest/coverage-v8':
+ optional: true
+ '@vitest/ui':
+ optional: true
+ happy-dom:
+ optional: true
+ jsdom:
+ optional: true
+
+ w3c-xmlserializer@5.0.0:
+ resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==}
+ engines: {node: '>=18'}
+
webidl-conversions@7.0.0:
resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
engines: {node: '>=12'}
+ webidl-conversions@8.0.1:
+ resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==}
+ engines: {node: '>=20'}
+
+ whatwg-mimetype@5.0.0:
+ resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==}
+ engines: {node: '>=20'}
+
whatwg-url@14.2.0:
resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==}
engines: {node: '>=18'}
+ whatwg-url@16.0.1:
+ resolution: {integrity: sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
+
which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'}
@@ -1463,10 +2330,20 @@ packages:
utf-8-validate:
optional: true
+ xml-name-validator@5.0.0:
+ resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==}
+ engines: {node: '>=18'}
+
+ xmlchars@2.2.0:
+ resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
+
xmlhttprequest-ssl@2.1.2:
resolution: {integrity: sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==}
engines: {node: '>=0.4.0'}
+ yallist@3.1.1:
+ resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
+
yocto-queue@0.1.0:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
@@ -1475,8 +2352,181 @@ packages:
resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==}
engines: {node: '>=12.20'}
+ zod-validation-error@4.0.2:
+ resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==}
+ engines: {node: '>=18.0.0'}
+ peerDependencies:
+ zod: ^3.25.0 || ^4.0.0
+
+ zod@4.3.6:
+ resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==}
+
snapshots:
+ '@asamuzakjp/css-color@5.1.10':
+ dependencies:
+ '@csstools/css-calc': 3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)
+ '@csstools/css-color-parser': 4.0.2(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)
+ '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0)
+ '@csstools/css-tokenizer': 4.0.0
+
+ '@asamuzakjp/dom-selector@7.0.9':
+ dependencies:
+ '@asamuzakjp/nwsapi': 2.3.9
+ bidi-js: 1.0.3
+ css-tree: 3.2.1
+ is-potential-custom-element-name: 1.0.1
+
+ '@asamuzakjp/nwsapi@2.3.9': {}
+
+ '@babel/code-frame@7.29.0':
+ dependencies:
+ '@babel/helper-validator-identifier': 7.28.5
+ js-tokens: 4.0.0
+ picocolors: 1.1.1
+
+ '@babel/compat-data@7.29.0': {}
+
+ '@babel/core@7.29.0':
+ dependencies:
+ '@babel/code-frame': 7.29.0
+ '@babel/generator': 7.29.1
+ '@babel/helper-compilation-targets': 7.28.6
+ '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0)
+ '@babel/helpers': 7.29.2
+ '@babel/parser': 7.29.2
+ '@babel/template': 7.28.6
+ '@babel/traverse': 7.29.0
+ '@babel/types': 7.29.0
+ '@jridgewell/remapping': 2.3.5
+ convert-source-map: 2.0.0
+ debug: 4.4.3(supports-color@5.5.0)
+ gensync: 1.0.0-beta.2
+ json5: 2.2.3
+ semver: 6.3.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/generator@7.29.1':
+ dependencies:
+ '@babel/parser': 7.29.2
+ '@babel/types': 7.29.0
+ '@jridgewell/gen-mapping': 0.3.13
+ '@jridgewell/trace-mapping': 0.3.31
+ jsesc: 3.1.0
+
+ '@babel/helper-compilation-targets@7.28.6':
+ dependencies:
+ '@babel/compat-data': 7.29.0
+ '@babel/helper-validator-option': 7.27.1
+ browserslist: 4.28.2
+ lru-cache: 5.1.1
+ semver: 6.3.1
+
+ '@babel/helper-globals@7.28.0': {}
+
+ '@babel/helper-module-imports@7.28.6':
+ dependencies:
+ '@babel/traverse': 7.29.0
+ '@babel/types': 7.29.0
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-module-imports': 7.28.6
+ '@babel/helper-validator-identifier': 7.28.5
+ '@babel/traverse': 7.29.0
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/helper-string-parser@7.27.1': {}
+
+ '@babel/helper-validator-identifier@7.28.5': {}
+
+ '@babel/helper-validator-option@7.27.1': {}
+
+ '@babel/helpers@7.29.2':
+ dependencies:
+ '@babel/template': 7.28.6
+ '@babel/types': 7.29.0
+
+ '@babel/parser@7.29.2':
+ dependencies:
+ '@babel/types': 7.29.0
+
+ '@babel/runtime@7.29.2': {}
+
+ '@babel/template@7.28.6':
+ dependencies:
+ '@babel/code-frame': 7.29.0
+ '@babel/parser': 7.29.2
+ '@babel/types': 7.29.0
+
+ '@babel/traverse@7.29.0':
+ dependencies:
+ '@babel/code-frame': 7.29.0
+ '@babel/generator': 7.29.1
+ '@babel/helper-globals': 7.28.0
+ '@babel/parser': 7.29.2
+ '@babel/template': 7.28.6
+ '@babel/types': 7.29.0
+ debug: 4.4.3(supports-color@5.5.0)
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/types@7.29.0':
+ dependencies:
+ '@babel/helper-string-parser': 7.27.1
+ '@babel/helper-validator-identifier': 7.28.5
+
+ '@bcoe/v8-coverage@1.0.2': {}
+
+ '@bramus/specificity@2.4.2':
+ dependencies:
+ css-tree: 3.2.1
+
+ '@csstools/color-helpers@6.0.2': {}
+
+ '@csstools/css-calc@3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)':
+ dependencies:
+ '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0)
+ '@csstools/css-tokenizer': 4.0.0
+
+ '@csstools/css-color-parser@4.0.2(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)':
+ dependencies:
+ '@csstools/color-helpers': 6.0.2
+ '@csstools/css-calc': 3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)
+ '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0)
+ '@csstools/css-tokenizer': 4.0.0
+
+ '@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0)':
+ dependencies:
+ '@csstools/css-tokenizer': 4.0.0
+
+ '@csstools/css-syntax-patches-for-csstree@1.1.2(css-tree@3.2.1)':
+ optionalDependencies:
+ css-tree: 3.2.1
+
+ '@csstools/css-tokenizer@4.0.0': {}
+
+ '@emnapi/core@1.9.2':
+ dependencies:
+ '@emnapi/wasi-threads': 1.2.1
+ tslib: 2.8.1
+ optional: true
+
+ '@emnapi/runtime@1.9.2':
+ dependencies:
+ tslib: 2.8.1
+ optional: true
+
+ '@emnapi/wasi-threads@1.2.1':
+ dependencies:
+ tslib: 2.8.1
+ optional: true
+
'@esbuild/aix-ppc64@0.21.5':
optional: true
@@ -1580,6 +2630,10 @@ snapshots:
'@eslint/core': 1.2.1
levn: 0.4.1
+ '@exodus/bytes@1.15.0(@noble/hashes@1.8.0)':
+ optionalDependencies:
+ '@noble/hashes': 1.8.0
+
'@humanfs/core@0.19.1': {}
'@humanfs/node@0.16.7':
@@ -1595,18 +2649,97 @@ snapshots:
dependencies:
'@sinclair/typebox': 0.27.10
+ '@jridgewell/gen-mapping@0.3.13':
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.5
+ '@jridgewell/trace-mapping': 0.3.31
+
+ '@jridgewell/remapping@2.3.5':
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.13
+ '@jridgewell/trace-mapping': 0.3.31
+
+ '@jridgewell/resolve-uri@3.1.2': {}
+
'@jridgewell/sourcemap-codec@1.5.5': {}
+ '@jridgewell/trace-mapping@0.3.31':
+ dependencies:
+ '@jridgewell/resolve-uri': 3.1.2
+ '@jridgewell/sourcemap-codec': 1.5.5
+
'@mongodb-js/saslprep@1.4.6':
dependencies:
sparse-bitfield: 3.0.3
+ '@napi-rs/wasm-runtime@1.1.3(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)':
+ dependencies:
+ '@emnapi/core': 1.9.2
+ '@emnapi/runtime': 1.9.2
+ '@tybys/wasm-util': 0.10.1
+ optional: true
+
'@noble/hashes@1.8.0': {}
+ '@oxc-project/types@0.124.0': {}
+
'@paralleldrive/cuid2@2.3.1':
dependencies:
'@noble/hashes': 1.8.0
+ '@rolldown/binding-android-arm64@1.0.0-rc.15':
+ optional: true
+
+ '@rolldown/binding-darwin-arm64@1.0.0-rc.15':
+ optional: true
+
+ '@rolldown/binding-darwin-x64@1.0.0-rc.15':
+ optional: true
+
+ '@rolldown/binding-freebsd-x64@1.0.0-rc.15':
+ optional: true
+
+ '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.15':
+ optional: true
+
+ '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.15':
+ optional: true
+
+ '@rolldown/binding-linux-arm64-musl@1.0.0-rc.15':
+ optional: true
+
+ '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.15':
+ optional: true
+
+ '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.15':
+ optional: true
+
+ '@rolldown/binding-linux-x64-gnu@1.0.0-rc.15':
+ optional: true
+
+ '@rolldown/binding-linux-x64-musl@1.0.0-rc.15':
+ optional: true
+
+ '@rolldown/binding-openharmony-arm64@1.0.0-rc.15':
+ optional: true
+
+ '@rolldown/binding-wasm32-wasi@1.0.0-rc.15':
+ dependencies:
+ '@emnapi/core': 1.9.2
+ '@emnapi/runtime': 1.9.2
+ '@napi-rs/wasm-runtime': 1.1.3(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)
+ optional: true
+
+ '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.15':
+ optional: true
+
+ '@rolldown/binding-win32-x64-msvc@1.0.0-rc.15':
+ optional: true
+
+ '@rolldown/pluginutils@1.0.0-rc.15': {}
+
+ '@rolldown/pluginutils@1.0.0-rc.7': {}
+
'@rollup/rollup-android-arm-eabi@4.60.1':
optional: true
@@ -1686,10 +2819,48 @@ snapshots:
'@socket.io/component-emitter@3.1.2': {}
+ '@standard-schema/spec@1.1.0': {}
+
+ '@testing-library/dom@10.4.1':
+ dependencies:
+ '@babel/code-frame': 7.29.0
+ '@babel/runtime': 7.29.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/react@16.3.2(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@babel/runtime': 7.29.2
+ '@testing-library/dom': 10.4.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@testing-library/user-event@14.6.1(@testing-library/dom@10.4.1)':
+ dependencies:
+ '@testing-library/dom': 10.4.1
+
+ '@tybys/wasm-util@0.10.1':
+ dependencies:
+ tslib: 2.8.1
+ optional: true
+
+ '@types/aria-query@5.0.4': {}
+
+ '@types/chai@5.2.3':
+ dependencies:
+ '@types/deep-eql': 4.0.2
+ assertion-error: 2.0.1
+
'@types/cors@2.8.19':
dependencies:
'@types/node': 25.5.2
+ '@types/deep-eql@4.0.2': {}
+
'@types/esrecurse@4.3.1': {}
'@types/estree@1.0.8': {}
@@ -1710,28 +2881,82 @@ snapshots:
dependencies:
'@types/node': 25.5.2
+ '@vitejs/plugin-react@6.0.1(vite@8.0.8(@types/node@25.5.2))':
+ dependencies:
+ '@rolldown/pluginutils': 1.0.0-rc.7
+ vite: 8.0.8(@types/node@25.5.2)
+
+ '@vitest/coverage-v8@4.1.4(vitest@4.1.4)':
+ dependencies:
+ '@bcoe/v8-coverage': 1.0.2
+ '@vitest/utils': 4.1.4
+ ast-v8-to-istanbul: 1.0.0
+ istanbul-lib-coverage: 3.2.2
+ istanbul-lib-report: 3.0.1
+ istanbul-reports: 3.2.0
+ magicast: 0.5.2
+ obug: 2.1.1
+ std-env: 4.0.0
+ tinyrainbow: 3.1.0
+ vitest: 4.1.4(@types/node@25.5.2)(@vitest/coverage-v8@4.1.4)(jsdom@29.0.2(@noble/hashes@1.8.0))(vite@8.0.8(@types/node@25.5.2))
+
'@vitest/expect@1.6.1':
dependencies:
'@vitest/spy': 1.6.1
'@vitest/utils': 1.6.1
chai: 4.5.0
+ '@vitest/expect@4.1.4':
+ dependencies:
+ '@standard-schema/spec': 1.1.0
+ '@types/chai': 5.2.3
+ '@vitest/spy': 4.1.4
+ '@vitest/utils': 4.1.4
+ chai: 6.2.2
+ tinyrainbow: 3.1.0
+
+ '@vitest/mocker@4.1.4(vite@8.0.8(@types/node@25.5.2))':
+ dependencies:
+ '@vitest/spy': 4.1.4
+ estree-walker: 3.0.3
+ magic-string: 0.30.21
+ optionalDependencies:
+ vite: 8.0.8(@types/node@25.5.2)
+
+ '@vitest/pretty-format@4.1.4':
+ dependencies:
+ tinyrainbow: 3.1.0
+
'@vitest/runner@1.6.1':
dependencies:
'@vitest/utils': 1.6.1
p-limit: 5.0.0
pathe: 1.1.2
+ '@vitest/runner@4.1.4':
+ dependencies:
+ '@vitest/utils': 4.1.4
+ pathe: 2.0.3
+
'@vitest/snapshot@1.6.1':
dependencies:
magic-string: 0.30.21
pathe: 1.1.2
pretty-format: 29.7.0
+ '@vitest/snapshot@4.1.4':
+ dependencies:
+ '@vitest/pretty-format': 4.1.4
+ '@vitest/utils': 4.1.4
+ magic-string: 0.30.21
+ pathe: 2.0.3
+
'@vitest/spy@1.6.1':
dependencies:
tinyspy: 2.2.1
+ '@vitest/spy@4.1.4': {}
+
'@vitest/utils@1.6.1':
dependencies:
diff-sequences: 29.6.3
@@ -1739,6 +2964,12 @@ snapshots:
loupe: 2.3.7
pretty-format: 29.7.0
+ '@vitest/utils@4.1.4':
+ dependencies:
+ '@vitest/pretty-format': 4.1.4
+ convert-source-map: 2.0.0
+ tinyrainbow: 3.1.0
+
accepts@1.3.8:
dependencies:
mime-types: 2.1.35
@@ -1761,6 +2992,8 @@ snapshots:
json-schema-traverse: 0.4.1
uri-js: 4.4.1
+ ansi-regex@5.0.1: {}
+
ansi-styles@5.2.0: {}
anymatch@3.1.3:
@@ -1768,18 +3001,36 @@ snapshots:
normalize-path: 3.0.0
picomatch: 2.3.2
+ aria-query@5.3.0:
+ dependencies:
+ dequal: 2.0.3
+
array-flatten@1.1.1: {}
asap@2.0.6: {}
assertion-error@1.1.0: {}
+ assertion-error@2.0.1: {}
+
+ ast-v8-to-istanbul@1.0.0:
+ dependencies:
+ '@jridgewell/trace-mapping': 0.3.31
+ estree-walker: 3.0.3
+ js-tokens: 10.0.0
+
asynckit@0.4.0: {}
balanced-match@4.0.4: {}
base64id@2.0.0: {}
+ baseline-browser-mapping@2.10.18: {}
+
+ bidi-js@1.0.3:
+ dependencies:
+ require-from-string: 2.0.2
+
binary-extensions@2.3.0: {}
body-parser@1.20.4:
@@ -1807,6 +3058,14 @@ snapshots:
dependencies:
fill-range: 7.1.1
+ browserslist@4.28.2:
+ dependencies:
+ baseline-browser-mapping: 2.10.18
+ caniuse-lite: 1.0.30001787
+ electron-to-chromium: 1.5.335
+ node-releases: 2.0.37
+ update-browserslist-db: 1.2.3(browserslist@4.28.2)
+
bson@6.10.4: {}
bytes@3.1.2: {}
@@ -1823,6 +3082,10 @@ snapshots:
call-bind-apply-helpers: 1.0.2
get-intrinsic: 1.3.0
+ caniuse-lite@1.0.30001787: {}
+
+ canvas-confetti@1.9.4: {}
+
chai@4.5.0:
dependencies:
assertion-error: 1.1.0
@@ -1833,6 +3096,8 @@ snapshots:
pathval: 1.1.1
type-detect: 4.1.0
+ chai@6.2.2: {}
+
check-error@1.0.3:
dependencies:
get-func-name: 2.0.2
@@ -1863,6 +3128,8 @@ snapshots:
content-type@1.0.5: {}
+ convert-source-map@2.0.0: {}
+
cookie-signature@1.0.7: {}
cookie-signature@1.2.2: {}
@@ -1882,6 +3149,18 @@ snapshots:
shebang-command: 2.0.0
which: 2.0.2
+ css-tree@3.2.1:
+ dependencies:
+ mdn-data: 2.27.1
+ source-map-js: 1.2.1
+
+ data-urls@7.0.0(@noble/hashes@1.8.0):
+ dependencies:
+ whatwg-mimetype: 5.0.0
+ whatwg-url: 16.0.1(@noble/hashes@1.8.0)
+ transitivePeerDependencies:
+ - '@noble/hashes'
+
debug@2.6.9:
dependencies:
ms: 2.0.0
@@ -1892,6 +3171,8 @@ snapshots:
optionalDependencies:
supports-color: 5.5.0
+ decimal.js@10.6.0: {}
+
deep-eql@4.1.4:
dependencies:
type-detect: 4.1.0
@@ -1902,8 +3183,12 @@ snapshots:
depd@2.0.0: {}
+ dequal@2.0.3: {}
+
destroy@1.2.0: {}
+ detect-libc@2.1.2: {}
+
dezalgo@1.0.4:
dependencies:
asap: 2.0.6
@@ -1911,6 +3196,8 @@ snapshots:
diff-sequences@29.6.3: {}
+ dom-accessibility-api@0.5.16: {}
+
dotenv@16.6.1: {}
dunder-proto@1.0.1:
@@ -1921,6 +3208,8 @@ snapshots:
ee-first@1.1.1: {}
+ electron-to-chromium@1.5.335: {}
+
encodeurl@2.0.0: {}
engine.io-client@6.6.4:
@@ -1954,10 +3243,14 @@ snapshots:
- supports-color
- utf-8-validate
+ entities@6.0.1: {}
+
es-define-property@1.0.1: {}
es-errors@1.3.0: {}
+ es-module-lexer@2.0.0: {}
+
es-object-atoms@1.1.1:
dependencies:
es-errors: 1.3.0
@@ -1995,6 +3288,8 @@ snapshots:
'@esbuild/win32-ia32': 0.21.5
'@esbuild/win32-x64': 0.21.5
+ escalade@3.2.0: {}
+
escape-html@1.0.3: {}
escape-string-regexp@4.0.0: {}
@@ -2003,6 +3298,21 @@ snapshots:
dependencies:
eslint: 10.2.0
+ eslint-plugin-react-hooks@7.0.1(eslint@10.2.0):
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/parser': 7.29.2
+ eslint: 10.2.0
+ hermes-parser: 0.25.1
+ zod: 4.3.6
+ zod-validation-error: 4.0.2(zod@4.3.6)
+ transitivePeerDependencies:
+ - supports-color
+
+ eslint-plugin-react-refresh@0.5.2(eslint@10.2.0):
+ dependencies:
+ eslint: 10.2.0
+
eslint-scope@9.1.2:
dependencies:
'@types/esrecurse': 4.3.1
@@ -2085,6 +3395,8 @@ snapshots:
signal-exit: 4.1.0
strip-final-newline: 3.0.0
+ expect-type@1.3.0: {}
+
express@4.22.1:
dependencies:
accepts: 1.3.8
@@ -2129,6 +3441,10 @@ snapshots:
fast-safe-stringify@2.1.1: {}
+ fdir@6.5.0(picomatch@4.0.4):
+ optionalDependencies:
+ picomatch: 4.0.4
+
file-entry-cache@8.0.0:
dependencies:
flat-cache: 4.0.1
@@ -2184,6 +3500,8 @@ snapshots:
function-bind@1.1.2: {}
+ gensync@1.0.0-beta.2: {}
+
get-func-name@2.0.2: {}
get-intrinsic@1.3.0:
@@ -2220,6 +3538,8 @@ snapshots:
has-flag@3.0.0: {}
+ has-flag@4.0.0: {}
+
has-symbols@1.1.0: {}
has-tostringtag@1.0.2:
@@ -2230,6 +3550,20 @@ snapshots:
dependencies:
function-bind: 1.1.2
+ hermes-estree@0.25.1: {}
+
+ hermes-parser@0.25.1:
+ dependencies:
+ hermes-estree: 0.25.1
+
+ html-encoding-sniffer@6.0.0(@noble/hashes@1.8.0):
+ dependencies:
+ '@exodus/bytes': 1.15.0(@noble/hashes@1.8.0)
+ transitivePeerDependencies:
+ - '@noble/hashes'
+
+ html-escaper@2.0.2: {}
+
http-errors@2.0.1:
dependencies:
depd: 2.0.0
@@ -2266,18 +3600,67 @@ snapshots:
is-number@7.0.0: {}
+ is-potential-custom-element-name@1.0.1: {}
+
is-stream@3.0.0: {}
isexe@2.0.0: {}
+ istanbul-lib-coverage@3.2.2: {}
+
+ istanbul-lib-report@3.0.1:
+ dependencies:
+ istanbul-lib-coverage: 3.2.2
+ make-dir: 4.0.0
+ supports-color: 7.2.0
+
+ istanbul-reports@3.2.0:
+ dependencies:
+ html-escaper: 2.0.2
+ istanbul-lib-report: 3.0.1
+
+ js-tokens@10.0.0: {}
+
+ js-tokens@4.0.0: {}
+
js-tokens@9.0.1: {}
+ jsdom@29.0.2(@noble/hashes@1.8.0):
+ dependencies:
+ '@asamuzakjp/css-color': 5.1.10
+ '@asamuzakjp/dom-selector': 7.0.9
+ '@bramus/specificity': 2.4.2
+ '@csstools/css-syntax-patches-for-csstree': 1.1.2(css-tree@3.2.1)
+ '@exodus/bytes': 1.15.0(@noble/hashes@1.8.0)
+ css-tree: 3.2.1
+ data-urls: 7.0.0(@noble/hashes@1.8.0)
+ decimal.js: 10.6.0
+ html-encoding-sniffer: 6.0.0(@noble/hashes@1.8.0)
+ is-potential-custom-element-name: 1.0.1
+ lru-cache: 11.3.3
+ parse5: 8.0.0
+ saxes: 6.0.0
+ symbol-tree: 3.2.4
+ tough-cookie: 6.0.1
+ undici: 7.24.7
+ w3c-xmlserializer: 5.0.0
+ webidl-conversions: 8.0.1
+ whatwg-mimetype: 5.0.0
+ whatwg-url: 16.0.1(@noble/hashes@1.8.0)
+ xml-name-validator: 5.0.0
+ transitivePeerDependencies:
+ - '@noble/hashes'
+
+ jsesc@3.1.0: {}
+
json-buffer@3.0.1: {}
json-schema-traverse@0.4.1: {}
json-stable-stringify-without-jsonify@1.0.1: {}
+ json5@2.2.3: {}
+
kareem@2.6.3: {}
keyv@4.5.4:
@@ -2289,6 +3672,55 @@ snapshots:
prelude-ls: 1.2.1
type-check: 0.4.0
+ lightningcss-android-arm64@1.32.0:
+ optional: true
+
+ lightningcss-darwin-arm64@1.32.0:
+ optional: true
+
+ lightningcss-darwin-x64@1.32.0:
+ optional: true
+
+ lightningcss-freebsd-x64@1.32.0:
+ optional: true
+
+ lightningcss-linux-arm-gnueabihf@1.32.0:
+ optional: true
+
+ lightningcss-linux-arm64-gnu@1.32.0:
+ optional: true
+
+ lightningcss-linux-arm64-musl@1.32.0:
+ optional: true
+
+ lightningcss-linux-x64-gnu@1.32.0:
+ optional: true
+
+ lightningcss-linux-x64-musl@1.32.0:
+ optional: true
+
+ lightningcss-win32-arm64-msvc@1.32.0:
+ optional: true
+
+ lightningcss-win32-x64-msvc@1.32.0:
+ optional: true
+
+ lightningcss@1.32.0:
+ dependencies:
+ detect-libc: 2.1.2
+ optionalDependencies:
+ lightningcss-android-arm64: 1.32.0
+ lightningcss-darwin-arm64: 1.32.0
+ lightningcss-darwin-x64: 1.32.0
+ lightningcss-freebsd-x64: 1.32.0
+ lightningcss-linux-arm-gnueabihf: 1.32.0
+ lightningcss-linux-arm64-gnu: 1.32.0
+ lightningcss-linux-arm64-musl: 1.32.0
+ lightningcss-linux-x64-gnu: 1.32.0
+ lightningcss-linux-x64-musl: 1.32.0
+ lightningcss-win32-arm64-msvc: 1.32.0
+ lightningcss-win32-x64-msvc: 1.32.0
+
local-pkg@0.5.1:
dependencies:
mlly: 1.8.2
@@ -2302,12 +3734,32 @@ snapshots:
dependencies:
get-func-name: 2.0.2
+ lru-cache@11.3.3: {}
+
+ lru-cache@5.1.1:
+ dependencies:
+ yallist: 3.1.1
+
+ lz-string@1.5.0: {}
+
magic-string@0.30.21:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
+ magicast@0.5.2:
+ dependencies:
+ '@babel/parser': 7.29.2
+ '@babel/types': 7.29.0
+ source-map-js: 1.2.1
+
+ make-dir@4.0.0:
+ dependencies:
+ semver: 7.7.4
+
math-intrinsics@1.1.0: {}
+ mdn-data@2.27.1: {}
+
media-typer@0.3.0: {}
memory-pager@1.5.0: {}
@@ -2389,6 +3841,8 @@ snapshots:
negotiator@0.6.3: {}
+ node-releases@2.0.37: {}
+
nodemon@3.1.14:
dependencies:
chokidar: 3.6.0
@@ -2412,6 +3866,8 @@ snapshots:
object-inspect@1.13.4: {}
+ obug@2.1.1: {}
+
on-finished@2.4.1:
dependencies:
ee-first: 1.1.1
@@ -2445,6 +3901,10 @@ snapshots:
dependencies:
p-limit: 3.1.0
+ parse5@8.0.0:
+ dependencies:
+ entities: 6.0.1
+
parseurl@1.3.3: {}
path-exists@4.0.0: {}
@@ -2465,6 +3925,8 @@ snapshots:
picomatch@2.3.2: {}
+ picomatch@4.0.4: {}
+
pkg-types@1.3.1:
dependencies:
confbox: 0.1.8
@@ -2481,6 +3943,12 @@ snapshots:
prettier@3.8.2: {}
+ pretty-format@27.5.1:
+ dependencies:
+ ansi-regex: 5.0.1
+ ansi-styles: 5.2.0
+ react-is: 17.0.2
+
pretty-format@29.7.0:
dependencies:
'@jest/schemas': 29.6.3
@@ -2513,12 +3981,48 @@ snapshots:
iconv-lite: 0.4.24
unpipe: 1.0.0
+ react-dom@19.2.5(react@19.2.5):
+ dependencies:
+ react: 19.2.5
+ scheduler: 0.27.0
+
+ react-icons@5.6.0(react@19.2.5):
+ dependencies:
+ react: 19.2.5
+
+ react-is@17.0.2: {}
+
react-is@18.3.1: {}
+ react@19.2.5: {}
+
readdirp@3.6.0:
dependencies:
picomatch: 2.3.2
+ require-from-string@2.0.2: {}
+
+ rolldown@1.0.0-rc.15:
+ dependencies:
+ '@oxc-project/types': 0.124.0
+ '@rolldown/pluginutils': 1.0.0-rc.15
+ optionalDependencies:
+ '@rolldown/binding-android-arm64': 1.0.0-rc.15
+ '@rolldown/binding-darwin-arm64': 1.0.0-rc.15
+ '@rolldown/binding-darwin-x64': 1.0.0-rc.15
+ '@rolldown/binding-freebsd-x64': 1.0.0-rc.15
+ '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.15
+ '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.15
+ '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.15
+ '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.15
+ '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.15
+ '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.15
+ '@rolldown/binding-linux-x64-musl': 1.0.0-rc.15
+ '@rolldown/binding-openharmony-arm64': 1.0.0-rc.15
+ '@rolldown/binding-wasm32-wasi': 1.0.0-rc.15
+ '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.15
+ '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.15
+
rollup@4.60.1:
dependencies:
'@types/estree': 1.0.8
@@ -2554,6 +4058,14 @@ snapshots:
safer-buffer@2.1.2: {}
+ saxes@6.0.0:
+ dependencies:
+ xmlchars: 2.2.0
+
+ scheduler@0.27.0: {}
+
+ semver@6.3.1: {}
+
semver@7.7.4: {}
send@0.19.2:
@@ -2682,6 +4194,8 @@ snapshots:
std-env@3.10.0: {}
+ std-env@4.0.0: {}
+
strip-final-newline@3.0.0: {}
strip-literal@2.1.1:
@@ -2714,12 +4228,33 @@ snapshots:
dependencies:
has-flag: 3.0.0
+ supports-color@7.2.0:
+ dependencies:
+ has-flag: 4.0.0
+
+ symbol-tree@3.2.4: {}
+
tinybench@2.9.0: {}
+ tinyexec@1.1.1: {}
+
+ tinyglobby@0.2.16:
+ dependencies:
+ fdir: 6.5.0(picomatch@4.0.4)
+ picomatch: 4.0.4
+
tinypool@0.8.4: {}
+ tinyrainbow@3.1.0: {}
+
tinyspy@2.2.1: {}
+ tldts-core@7.0.28: {}
+
+ tldts@7.0.28:
+ dependencies:
+ tldts-core: 7.0.28
+
to-regex-range@5.0.1:
dependencies:
is-number: 7.0.0
@@ -2728,10 +4263,21 @@ snapshots:
touch@3.1.1: {}
+ tough-cookie@6.0.1:
+ dependencies:
+ tldts: 7.0.28
+
tr46@5.1.1:
dependencies:
punycode: 2.3.1
+ tr46@6.0.0:
+ dependencies:
+ punycode: 2.3.1
+
+ tslib@2.8.1:
+ optional: true
+
type-check@0.4.0:
dependencies:
prelude-ls: 1.2.1
@@ -2749,8 +4295,16 @@ snapshots:
undici-types@7.18.2: {}
+ undici@7.24.7: {}
+
unpipe@1.0.0: {}
+ update-browserslist-db@1.2.3(browserslist@4.28.2):
+ dependencies:
+ browserslist: 4.28.2
+ escalade: 3.2.0
+ picocolors: 1.1.1
+
uri-js@4.4.1:
dependencies:
punycode: 2.3.1
@@ -2759,13 +4313,13 @@ snapshots:
vary@1.1.2: {}
- vite-node@1.6.1(@types/node@25.5.2):
+ vite-node@1.6.1(@types/node@25.5.2)(lightningcss@1.32.0):
dependencies:
cac: 6.7.14
debug: 4.4.3(supports-color@5.5.0)
pathe: 1.1.2
picocolors: 1.1.1
- vite: 5.4.21(@types/node@25.5.2)
+ vite: 5.4.21(@types/node@25.5.2)(lightningcss@1.32.0)
transitivePeerDependencies:
- '@types/node'
- less
@@ -2777,7 +4331,7 @@ snapshots:
- supports-color
- terser
- vite@5.4.21(@types/node@25.5.2):
+ vite@5.4.21(@types/node@25.5.2)(lightningcss@1.32.0):
dependencies:
esbuild: 0.21.5
postcss: 8.5.9
@@ -2785,8 +4339,20 @@ snapshots:
optionalDependencies:
'@types/node': 25.5.2
fsevents: 2.3.3
+ lightningcss: 1.32.0
+
+ vite@8.0.8(@types/node@25.5.2):
+ dependencies:
+ lightningcss: 1.32.0
+ picomatch: 4.0.4
+ postcss: 8.5.9
+ rolldown: 1.0.0-rc.15
+ tinyglobby: 0.2.16
+ optionalDependencies:
+ '@types/node': 25.5.2
+ fsevents: 2.3.3
- vitest@1.6.1(@types/node@25.5.2):
+ vitest@1.6.1(@types/node@25.5.2)(jsdom@29.0.2(@noble/hashes@1.8.0))(lightningcss@1.32.0):
dependencies:
'@vitest/expect': 1.6.1
'@vitest/runner': 1.6.1
@@ -2805,11 +4371,12 @@ snapshots:
strip-literal: 2.1.1
tinybench: 2.9.0
tinypool: 0.8.4
- vite: 5.4.21(@types/node@25.5.2)
- vite-node: 1.6.1(@types/node@25.5.2)
+ vite: 5.4.21(@types/node@25.5.2)(lightningcss@1.32.0)
+ vite-node: 1.6.1(@types/node@25.5.2)(lightningcss@1.32.0)
why-is-node-running: 2.3.0
optionalDependencies:
'@types/node': 25.5.2
+ jsdom: 29.0.2(@noble/hashes@1.8.0)
transitivePeerDependencies:
- less
- lightningcss
@@ -2820,13 +4387,58 @@ snapshots:
- supports-color
- terser
+ vitest@4.1.4(@types/node@25.5.2)(@vitest/coverage-v8@4.1.4)(jsdom@29.0.2(@noble/hashes@1.8.0))(vite@8.0.8(@types/node@25.5.2)):
+ dependencies:
+ '@vitest/expect': 4.1.4
+ '@vitest/mocker': 4.1.4(vite@8.0.8(@types/node@25.5.2))
+ '@vitest/pretty-format': 4.1.4
+ '@vitest/runner': 4.1.4
+ '@vitest/snapshot': 4.1.4
+ '@vitest/spy': 4.1.4
+ '@vitest/utils': 4.1.4
+ es-module-lexer: 2.0.0
+ expect-type: 1.3.0
+ magic-string: 0.30.21
+ obug: 2.1.1
+ pathe: 2.0.3
+ picomatch: 4.0.4
+ std-env: 4.0.0
+ tinybench: 2.9.0
+ tinyexec: 1.1.1
+ tinyglobby: 0.2.16
+ tinyrainbow: 3.1.0
+ vite: 8.0.8(@types/node@25.5.2)
+ why-is-node-running: 2.3.0
+ optionalDependencies:
+ '@types/node': 25.5.2
+ '@vitest/coverage-v8': 4.1.4(vitest@4.1.4)
+ jsdom: 29.0.2(@noble/hashes@1.8.0)
+ transitivePeerDependencies:
+ - msw
+
+ w3c-xmlserializer@5.0.0:
+ dependencies:
+ xml-name-validator: 5.0.0
+
webidl-conversions@7.0.0: {}
+ webidl-conversions@8.0.1: {}
+
+ whatwg-mimetype@5.0.0: {}
+
whatwg-url@14.2.0:
dependencies:
tr46: 5.1.1
webidl-conversions: 7.0.0
+ whatwg-url@16.0.1(@noble/hashes@1.8.0):
+ dependencies:
+ '@exodus/bytes': 1.15.0(@noble/hashes@1.8.0)
+ tr46: 6.0.0
+ webidl-conversions: 8.0.1
+ transitivePeerDependencies:
+ - '@noble/hashes'
+
which@2.0.2:
dependencies:
isexe: 2.0.0
@@ -2842,8 +4454,20 @@ snapshots:
ws@8.18.3: {}
+ xml-name-validator@5.0.0: {}
+
+ xmlchars@2.2.0: {}
+
xmlhttprequest-ssl@2.1.2: {}
+ yallist@3.1.1: {}
+
yocto-queue@0.1.0: {}
yocto-queue@1.2.2: {}
+
+ zod-validation-error@4.0.2(zod@4.3.6):
+ dependencies:
+ zod: 4.3.6
+
+ zod@4.3.6: {}