From 049632724b865b4b10f0f53164c8a834edaa54d5 Mon Sep 17 00:00:00 2001 From: Jose Cruz Date: Sun, 19 Apr 2026 14:42:04 -0400 Subject: [PATCH 01/52] backend: new endpoints + tests for revamp features Routes: - PATCH/DELETE /api/calendar/assignments/{id} with whitelist, 404s, and empty course_id -> NULL. - GET /api/study-guide list/detail/regenerate already existed; tests now cover cache hit/miss, exam keyword filter, and regenerate delete+insert. - GET /api/admin/{roles,achievements,cosmetics} list endpoints for the new Admin catalog tabs. - GET /api/profile/username/check debounced availability probe with invalid/taken/self reasons. - GET /api/profile/{id}/cosmetics/catalog grouped by type with per-item `owned` flag. - GET /api/profile/{id}/achievements now joins achievement_triggers and enriches each locked non-secret achievement with {progress: {current, target}} via the new public get_user_stat(). - GET /api/social/rooms/{id}/messages accepts before/limit, returns has_more, clamps limit to [1, 200], and serves ascending order. Services: - services/achievement_service.py exposes get_user_stat() as a public wrapper so routes can compute progress without reaching into the underscore-prefixed helper. Tests: - +34 new cases in test_calendar_routes, test_admin_routes, test_profile_routes, plus new test_study_guide_routes and test_social_messages. Full suite: 291 pass / 3 skip / 0 fail. Docs: - migration_cosmetics.sql documents the required `cosmetic-assets` public Storage bucket for admin cosmetic asset uploads. --- backend/db/migration_cosmetics.sql | 10 ++ backend/routes/admin.py | 21 +++ backend/routes/calendar.py | 35 +++++ backend/routes/profile.py | 85 ++++++++++- backend/routes/social.py | 19 ++- backend/services/achievement_service.py | 5 + backend/tests/test_admin_routes.py | 43 ++++++ backend/tests/test_calendar_routes.py | 74 ++++++++++ backend/tests/test_profile_routes.py | 166 +++++++++++++++++++++ backend/tests/test_social_messages.py | 140 ++++++++++++++++++ backend/tests/test_study_guide_routes.py | 180 +++++++++++++++++++++++ 11 files changed, 769 insertions(+), 9 deletions(-) create mode 100644 backend/tests/test_social_messages.py create mode 100644 backend/tests/test_study_guide_routes.py diff --git a/backend/db/migration_cosmetics.sql b/backend/db/migration_cosmetics.sql index 2f4aa2de..0abdc3eb 100644 --- a/backend/db/migration_cosmetics.sql +++ b/backend/db/migration_cosmetics.sql @@ -54,3 +54,13 @@ ALTER TABLE user_settings ALTER TABLE user_settings ADD CONSTRAINT fk_user_settings_featured_role FOREIGN KEY (featured_role_id) REFERENCES roles(id); + +-- Storage: the admin cosmetic creation UI uploads frame/banner assets to a +-- public Supabase Storage bucket named `cosmetic-assets`. Create it once with: +-- +-- INSERT INTO storage.buckets (id, name, public) +-- VALUES ('cosmetic-assets', 'cosmetic-assets', true) +-- ON CONFLICT (id) DO NOTHING; +-- +-- Then add an RLS policy on storage.objects that allows inserts from +-- authenticated admin users (or run the upload via the service key). diff --git a/backend/routes/admin.py b/backend/routes/admin.py index 70dd0d66..fabbbeca 100644 --- a/backend/routes/admin.py +++ b/backend/routes/admin.py @@ -25,6 +25,13 @@ # ── Roles ──────────────────────────────────────────────────────────────────── +@router.get("/roles") +def list_roles(request: Request): + require_admin(request) + rows = table("roles").select("*", order="display_priority.desc") + return {"roles": rows or []} + + @router.post("/roles") def create_role(body: CreateRoleBody, request: Request): require_admin(request) @@ -83,6 +90,13 @@ def delete_role(role_id: str, request: Request): # ── Achievements ───────────────────────────────────────────────────────────── +@router.get("/achievements") +def list_achievements(request: Request): + require_admin(request) + rows = table("achievements").select("*", order="created_at.desc") + return {"achievements": rows or []} + + @router.post("/achievements") def create_achievement(body: CreateAchievementBody, request: Request): require_admin(request) @@ -153,6 +167,13 @@ def create_trigger(body: CreateAchievementTriggerBody, request: Request): # ── Cosmetics ──────────────────────────────────────────────────────────────── +@router.get("/cosmetics") +def list_cosmetics(request: Request): + require_admin(request) + rows = table("cosmetics").select("*", order="type.asc") + return {"cosmetics": rows or []} + + @router.post("/cosmetics") def create_cosmetic(body: CreateCosmeticBody, request: Request): require_admin(request) diff --git a/backend/routes/calendar.py b/backend/routes/calendar.py index a6cf9b57..c2351b3a 100644 --- a/backend/routes/calendar.py +++ b/backend/routes/calendar.py @@ -165,6 +165,41 @@ def get_all_assignments(user_id: str): return {"assignments": assignments} +@router.patch("/assignments/{assignment_id}") +def update_assignment(assignment_id: str, body: dict): + user_id = body.get("user_id") + if not user_id: + raise HTTPException(status_code=400, detail="user_id is required") + + existing = table("assignments").select( + "id", filters={"id": f"eq.{assignment_id}", "user_id": f"eq.{user_id}"}, limit=1, + ) + if not existing: + raise HTTPException(status_code=404, detail="Assignment not found") + + allowed = {"title", "course_id", "due_date", "assignment_type", "notes"} + patch = {k: v for k, v in body.items() if k in allowed} + if not patch: + return {"updated": False} + + if "course_id" in patch and patch["course_id"] == "": + patch["course_id"] = None + + table("assignments").update(patch, filters={"id": f"eq.{assignment_id}"}) + return {"updated": True} + + +@router.delete("/assignments/{assignment_id}") +def delete_assignment(assignment_id: str, user_id: str = Query(...)): + existing = table("assignments").select( + "id", filters={"id": f"eq.{assignment_id}", "user_id": f"eq.{user_id}"}, limit=1, + ) + if not existing: + raise HTTPException(status_code=404, detail="Assignment not found") + table("assignments").delete(filters={"id": f"eq.{assignment_id}"}) + return {"deleted": True} + + @router.post("/suggest-study-blocks") def suggest_study_blocks(body: StudyBlockBody): today = datetime.utcnow().strftime("%Y-%m-%d") diff --git a/backend/routes/profile.py b/backend/routes/profile.py index ebf4ac5a..0ff3b1da 100644 --- a/backend/routes/profile.py +++ b/backend/routes/profile.py @@ -2,7 +2,9 @@ Profile routes — public profiles, settings, cosmetics, achievements, account management. """ +import re from datetime import datetime, timezone +from typing import Optional from fastapi import APIRouter, HTTPException, Request, UploadFile, File, Query @@ -17,6 +19,7 @@ ) from services.auth_guard import require_self, get_session_user_id from services.storage_service import upload_avatar +from services.achievement_service import get_user_stat router = APIRouter() @@ -115,6 +118,24 @@ def _get_user_stats(user_id: str) -> dict: } +# ── Username Availability ──────────────────────────────────────────────────── + +_USERNAME_RE = re.compile(r"^[a-z0-9_]{3,24}$") + + +@router.get("/username/check") +def check_username(username: str = Query(...), user_id: Optional[str] = Query(None)): + name = (username or "").strip().lower() + if not _USERNAME_RE.match(name): + return {"available": False, "reason": "invalid"} + existing = table("users").select("id", filters={"username": f"eq.{name}"}) + if not existing: + return {"available": True} + if user_id and existing[0]["id"] == user_id: + return {"available": True, "reason": "self"} + return {"available": False, "reason": "taken"} + + # ── Public Profile ─────────────────────────────────────────────────────────── @router.get("/{user_id}") @@ -380,6 +401,43 @@ def get_achievements(user_id: str): for r in earned_rows: earned_ids[r["achievement_id"]] = r + # Fetch triggers once and group by achievement_id so we can surface progress. + trigger_rows = table("achievement_triggers").select( + "achievement_id,trigger_type,trigger_threshold", + ) + triggers_by_ach: dict = {} + for t in trigger_rows or []: + triggers_by_ach.setdefault(t["achievement_id"], []).append(t) + + # Cache stat lookups per trigger_type — most achievements share a handful of counters. + stat_cache: dict = {} + + def _progress_for(ach_id: str) -> dict | None: + ts = triggers_by_ach.get(ach_id) + if not ts: + return None + # Pick the tightest gap (lowest current/target ratio) so the UI tracks the leading edge. + best = None + for t in ts: + tt = t["trigger_type"] + if tt == "manual_admin_grant": + continue + target = int(t.get("trigger_threshold") or 0) + if target <= 0: + continue + if tt not in stat_cache: + try: + stat_cache[tt] = get_user_stat(user_id, tt) + except Exception: + stat_cache[tt] = 0 + current = min(stat_cache[tt], target) + ratio = current / target + if best is None or ratio < best["ratio"]: + best = {"current": current, "target": target, "ratio": ratio} + if best is None: + return None + return {"current": best["current"], "target": best["target"]} + earned = [] available = [] @@ -392,7 +450,7 @@ def get_achievements(user_id: str): }) else: if ach.get("is_secret"): - available.append({ + entry = { "id": ach["id"], "name": "Secret Achievement", "slug": ach["slug"], @@ -401,9 +459,11 @@ def get_achievements(user_id: str): "category": ach["category"], "rarity": ach["rarity"], "is_secret": True, - }) + "progress": None, + } else: - available.append(ach) + entry = {**ach, "progress": _progress_for(ach["id"])} + available.append(entry) return {"earned": earned, "available": available} @@ -433,6 +493,25 @@ def get_cosmetics(user_id: str, request: Request): return {"cosmetics": grouped, "equipped": _get_equipped_cosmetics(settings)} +@router.get("/{user_id}/cosmetics/catalog") +def get_cosmetics_catalog(user_id: str, request: Request): + """All cosmetics grouped by type with an `owned` flag per item.""" + require_self(user_id, request) + all_cosmetics = table("cosmetics").select("id,type,name,slug,asset_url,css_value,rarity,unlock_source") + owned_rows = table("user_cosmetics").select( + "cosmetic_id", + filters={"user_id": f"eq.{user_id}"}, + ) + owned_ids = {r["cosmetic_id"] for r in (owned_rows or [])} + + grouped: dict = {"avatar_frame": [], "banner": [], "name_color": [], "title": []} + for c in all_cosmetics or []: + if c.get("type") not in grouped: + continue + grouped[c["type"]].append({**c, "owned": c["id"] in owned_ids}) + return {"catalog": grouped} + + # ── Roles ──────────────────────────────────────────────────────────────────── @router.get("/{user_id}/roles") diff --git a/backend/routes/social.py b/backend/routes/social.py index 0a085734..d557efe2 100644 --- a/backend/routes/social.py +++ b/backend/routes/social.py @@ -229,15 +229,22 @@ def kick_member(room_id: str, member_id: str, requester_id: str = Query(...)): @router.get("/rooms/{room_id}/messages") -def get_room_messages(room_id: str): +def get_room_messages(room_id: str, before: str | None = None, limit: int = 50): + limit = max(1, min(200, limit)) + filters = {"room_id": f"eq.{room_id}"} + if before: + filters["created_at"] = f"lt.{before}" + # Fetch newest-first so the slice covers the page we need, then reverse to ascending. rows = table("room_messages").select( "*", - filters={"room_id": f"eq.{room_id}"}, - order="created_at.asc", - limit=50, + filters=filters, + order="created_at.desc", + limit=limit, ) if not rows: - return {"messages": []} + return {"messages": [], "has_more": False} + rows = list(reversed(rows)) + has_more = len(rows) == limit msg_ids = [r["id"] for r in rows] @@ -278,7 +285,7 @@ def get_room_messages(room_id: str): r["reply_to"] = reply_map.get(r.get("reply_to_id")) if r.get("reply_to_id") else None enriched.append(r) - return {"messages": enriched} + return {"messages": enriched, "has_more": has_more} @router.post("/rooms/{room_id}/messages") diff --git a/backend/services/achievement_service.py b/backend/services/achievement_service.py index 4acd536c..62e75928 100644 --- a/backend/services/achievement_service.py +++ b/backend/services/achievement_service.py @@ -12,6 +12,11 @@ def _count_rows(table_name: str, filters: dict) -> int: return len(rows) if rows else 0 +def get_user_stat(user_id: str, trigger_type: str) -> int: + """Public wrapper around the internal stat lookup.""" + return _get_user_stat(user_id, trigger_type) + + def _get_user_stat(user_id: str, trigger_type: str) -> int: """Evaluate the current value for a trigger type.""" if trigger_type == "login_streak": diff --git a/backend/tests/test_admin_routes.py b/backend/tests/test_admin_routes.py index 8731a36e..fd3b39d4 100644 --- a/backend/tests/test_admin_routes.py +++ b/backend/tests/test_admin_routes.py @@ -171,3 +171,46 @@ def test_approves_user(self): assert r.status_code == 200 assert r.json()["approved"] is True + + +# ── GET /api/admin/roles ─────────────────────────────────────────────────── + +class TestListRoles: + def test_returns_roles_sorted(self): + rows = [{"id": "r1", "name": "Admin", "slug": "admin", "display_priority": 100}] + with _mock_admin(), patch("routes.admin.table") as t: + t.return_value.select.return_value = rows + r = client.get("/api/admin/roles") + assert r.status_code == 200 + assert r.json() == {"roles": rows} + + def test_empty_list(self): + with _mock_admin(), patch("routes.admin.table") as t: + t.return_value.select.return_value = [] + r = client.get("/api/admin/roles") + assert r.status_code == 200 + assert r.json() == {"roles": []} + + +# ── GET /api/admin/achievements ──────────────────────────────────────────── + +class TestListAchievements: + def test_returns_achievements(self): + rows = [{"id": "a1", "name": "First", "slug": "first", "category": "milestone", "rarity": "common", "is_secret": False}] + with _mock_admin(), patch("routes.admin.table") as t: + t.return_value.select.return_value = rows + r = client.get("/api/admin/achievements") + assert r.status_code == 200 + assert r.json() == {"achievements": rows} + + +# ── GET /api/admin/cosmetics ─────────────────────────────────────────────── + +class TestListCosmetics: + def test_returns_cosmetics(self): + rows = [{"id": "c1", "type": "avatar_frame", "name": "Gold Frame", "slug": "gold", "rarity": "rare"}] + with _mock_admin(), patch("routes.admin.table") as t: + t.return_value.select.return_value = rows + r = client.get("/api/admin/cosmetics") + assert r.status_code == 200 + assert r.json() == {"cosmetics": rows} diff --git a/backend/tests/test_calendar_routes.py b/backend/tests/test_calendar_routes.py index 98c84965..dc99621a 100644 --- a/backend/tests/test_calendar_routes.py +++ b/backend/tests/test_calendar_routes.py @@ -189,3 +189,77 @@ def test_deletes_oauth_token_and_returns_disconnected(self): r = client.delete("/api/calendar/disconnect/user_andres") assert r.status_code == 200 assert r.json() == {"disconnected": True} + + +# ── PATCH /api/calendar/assignments/{id} ───────────────────────────────────── + +class TestUpdateAssignment: + def test_updates_whitelisted_fields(self): + with patch("routes.calendar.table") as t: + t.return_value.select.return_value = [{"id": "a1"}] + t.return_value.update.return_value = [{}] + r = client.patch( + "/api/calendar/assignments/a1", + json={"user_id": "u1", "title": "New title", "due_date": "2026-06-01", "ignored": "x"}, + ) + assert r.status_code == 200 + assert r.json() == {"updated": True} + + def test_missing_user_id_returns_400(self): + r = client.patch("/api/calendar/assignments/a1", json={"title": "No user"}) + assert r.status_code == 400 + + def test_unknown_assignment_returns_404(self): + with patch("routes.calendar.table") as t: + t.return_value.select.return_value = [] + r = client.patch( + "/api/calendar/assignments/missing", + json={"user_id": "u1", "title": "x"}, + ) + assert r.status_code == 404 + + def test_empty_course_id_is_nulled(self): + captured = {} + def table_side_effect(name): + m = MagicMock() + m.select.return_value = [{"id": "a1"}] + def _update(patch, filters=None): + captured["patch"] = patch + return [{}] + m.update.side_effect = _update + return m + with patch("routes.calendar.table", side_effect=table_side_effect): + r = client.patch( + "/api/calendar/assignments/a1", + json={"user_id": "u1", "course_id": ""}, + ) + assert r.status_code == 200 + assert captured["patch"]["course_id"] is None + + def test_no_valid_fields_returns_updated_false(self): + with patch("routes.calendar.table") as t: + t.return_value.select.return_value = [{"id": "a1"}] + r = client.patch( + "/api/calendar/assignments/a1", + json={"user_id": "u1", "made_up": "x"}, + ) + assert r.status_code == 200 + assert r.json() == {"updated": False} + + +# ── DELETE /api/calendar/assignments/{id} ──────────────────────────────────── + +class TestDeleteAssignment: + def test_deletes_assignment(self): + with patch("routes.calendar.table") as t: + t.return_value.select.return_value = [{"id": "a1"}] + t.return_value.delete.return_value = [] + r = client.delete("/api/calendar/assignments/a1?user_id=u1") + assert r.status_code == 200 + assert r.json() == {"deleted": True} + + def test_missing_returns_404(self): + with patch("routes.calendar.table") as t: + t.return_value.select.return_value = [] + r = client.delete("/api/calendar/assignments/a1?user_id=u1") + assert r.status_code == 404 diff --git a/backend/tests/test_profile_routes.py b/backend/tests/test_profile_routes.py index 22709a36..f75832ff 100644 --- a/backend/tests/test_profile_routes.py +++ b/backend/tests/test_profile_routes.py @@ -309,3 +309,169 @@ def table_side_effect(name): assert r.status_code == 200 assert len(r.json()["roles"]) == 1 assert r.json()["roles"][0]["role"]["slug"] == "admin" + + +# ── GET /api/profile/username/check ──────────────────────────────────────── + +class TestCheckUsername: + def test_available_when_no_existing_row(self): + with patch("routes.profile.table") as t: + t.return_value.select.return_value = [] + r = client.get("/api/profile/username/check?username=freshname") + assert r.status_code == 200 + assert r.json() == {"available": True} + + def test_taken_when_different_user_holds_it(self): + with patch("routes.profile.table") as t: + t.return_value.select.return_value = [{"id": "other_user"}] + r = client.get("/api/profile/username/check?username=taken") + assert r.status_code == 200 + body = r.json() + assert body["available"] is False + assert body["reason"] == "taken" + + def test_available_when_held_by_self(self): + with patch("routes.profile.table") as t: + t.return_value.select.return_value = [{"id": USER_ID}] + r = client.get(f"/api/profile/username/check?username=mine&user_id={USER_ID}") + assert r.status_code == 200 + body = r.json() + assert body["available"] is True + assert body["reason"] == "self" + + def test_invalid_format_short(self): + r = client.get("/api/profile/username/check?username=ab") + assert r.status_code == 200 + assert r.json() == {"available": False, "reason": "invalid"} + + def test_invalid_format_special_chars(self): + r = client.get("/api/profile/username/check?username=bad-name!") + assert r.status_code == 200 + assert r.json() == {"available": False, "reason": "invalid"} + + +# ── GET /api/profile/{user_id}/cosmetics/catalog ─────────────────────────── + +class TestGetCosmeticsCatalog: + def test_groups_by_type_with_owned_flag(self): + all_cosmetics = [ + {"id": "c1", "type": "avatar_frame", "name": "Gold", "slug": "gold", "rarity": "rare", "unlock_source": "achievement:streak_7"}, + {"id": "c2", "type": "avatar_frame", "name": "Silver", "slug": "silver", "rarity": "common", "unlock_source": None}, + {"id": "c3", "type": "title", "name": "MVP", "slug": "mvp", "rarity": "epic", "unlock_source": "shop"}, + ] + owned = [{"cosmetic_id": "c1"}] + + def table_side_effect(name): + m = MagicMock() + if name == "cosmetics": + m.select.return_value = all_cosmetics + elif name == "user_cosmetics": + m.select.return_value = owned + elif name == "user_settings": + m.select.return_value = [{"user_id": USER_ID}] + else: + m.select.return_value = [] + return m + + with _mock_self(), patch("routes.profile.table", side_effect=table_side_effect): + r = client.get(f"/api/profile/{USER_ID}/cosmetics/catalog?user_id={USER_ID}") + + assert r.status_code == 200 + catalog = r.json()["catalog"] + frames = catalog["avatar_frame"] + by_slug = {c["slug"]: c for c in frames} + assert by_slug["gold"]["owned"] is True + assert by_slug["silver"]["owned"] is False + assert catalog["title"][0]["owned"] is False + # Buckets missing items should still be present as empty arrays. + assert catalog["banner"] == [] + assert catalog["name_color"] == [] + + +# ── GET /api/profile/{user_id}/achievements (progress enrichment) ────────── + +class TestAchievementProgress: + def test_locked_achievement_carries_progress(self): + all_achs = [{ + "id": "a1", "name": "Streak 7", "slug": "streak_7", + "description": "7 day streak", "icon": None, + "category": "activity", "rarity": "uncommon", "is_secret": False, + }] + triggers = [{"achievement_id": "a1", "trigger_type": "login_streak", "trigger_threshold": 7}] + + def table_side_effect(name): + m = MagicMock() + if name == "achievements": + m.select.return_value = all_achs + elif name == "user_achievements": + m.select.return_value = [] # nothing earned yet + elif name == "achievement_triggers": + m.select.return_value = triggers + else: + m.select.return_value = [] + return m + + with patch("routes.profile.table", side_effect=table_side_effect), \ + patch("routes.profile.get_user_stat", return_value=3): + r = client.get(f"/api/profile/{USER_ID}/achievements") + + assert r.status_code == 200 + available = r.json()["available"] + assert len(available) == 1 + assert available[0]["progress"] == {"current": 3, "target": 7} + + def test_progress_clamps_to_target(self): + all_achs = [{ + "id": "a1", "name": "Docs 5", "slug": "documents_5", + "description": "5 docs", "icon": None, + "category": "milestone", "rarity": "common", "is_secret": False, + }] + triggers = [{"achievement_id": "a1", "trigger_type": "documents_uploaded", "trigger_threshold": 5}] + + def table_side_effect(name): + m = MagicMock() + if name == "achievements": + m.select.return_value = all_achs + elif name == "user_achievements": + m.select.return_value = [] + elif name == "achievement_triggers": + m.select.return_value = triggers + else: + m.select.return_value = [] + return m + + with patch("routes.profile.table", side_effect=table_side_effect), \ + patch("routes.profile.get_user_stat", return_value=42): + r = client.get(f"/api/profile/{USER_ID}/achievements") + + assert r.status_code == 200 + assert r.json()["available"][0]["progress"] == {"current": 5, "target": 5} + + def test_secret_locked_has_no_progress(self): + all_achs = [{ + "id": "a1", "name": "Hidden", "slug": "hidden", + "description": "Secret", "icon": None, + "category": "special", "rarity": "rare", "is_secret": True, + }] + triggers = [{"achievement_id": "a1", "trigger_type": "login_streak", "trigger_threshold": 100}] + + def table_side_effect(name): + m = MagicMock() + if name == "achievements": + m.select.return_value = all_achs + elif name == "user_achievements": + m.select.return_value = [] + elif name == "achievement_triggers": + m.select.return_value = triggers + else: + m.select.return_value = [] + return m + + with patch("routes.profile.table", side_effect=table_side_effect), \ + patch("routes.profile.get_user_stat", return_value=1): + r = client.get(f"/api/profile/{USER_ID}/achievements") + + assert r.status_code == 200 + out = r.json()["available"][0] + assert out["name"] == "Secret Achievement" + assert out["progress"] is None diff --git a/backend/tests/test_social_messages.py b/backend/tests/test_social_messages.py new file mode 100644 index 00000000..3a5d486f --- /dev/null +++ b/backend/tests/test_social_messages.py @@ -0,0 +1,140 @@ +""" +Unit tests for routes/social.py message endpoints — focused on the new +pagination behavior (`before` and `limit` query params, `has_more` flag). +""" +from unittest.mock import MagicMock, patch + +from fastapi.testclient import TestClient + +from main import app + +client = TestClient(app) + +ROOM_ID = "room_1" + + +def _mk_msg(i: int, ts: str) -> dict: + return { + "id": f"m{i}", "room_id": ROOM_ID, "user_id": "u1", "user_name": "Alice", + "text": f"msg {i}", "image_url": None, "created_at": ts, + "reply_to_id": None, "is_deleted": False, "edited_at": None, + } + + +class TestGetRoomMessages: + def test_default_limit_returns_ascending(self): + # Route fetches newest-first from the DB, then reverses to ascending. + desc_rows = [_mk_msg(3, "2026-04-03T00:00:00Z"), + _mk_msg(2, "2026-04-02T00:00:00Z"), + _mk_msg(1, "2026-04-01T00:00:00Z")] + def table_side_effect(name): + m = MagicMock() + if name == "room_messages": + m.select.return_value = desc_rows + elif name == "room_reactions": + m.select.return_value = [] + else: + m.select.return_value = [] + return m + + with patch("routes.social.table", side_effect=table_side_effect): + r = client.get(f"/api/social/rooms/{ROOM_ID}/messages") + + assert r.status_code == 200 + body = r.json() + ids = [m["id"] for m in body["messages"]] + assert ids == ["m1", "m2", "m3"] # ascending + assert body["has_more"] is False # fewer than default limit (50) + + def test_has_more_true_when_page_is_full(self): + rows = [_mk_msg(i, f"2026-04-{i:02d}T00:00:00Z") for i in range(1, 6)] # 5 rows + def table_side_effect(name): + m = MagicMock() + if name == "room_messages": + m.select.return_value = list(reversed(rows)) # DB returns desc + elif name == "room_reactions": + m.select.return_value = [] + else: + m.select.return_value = [] + return m + + with patch("routes.social.table", side_effect=table_side_effect): + r = client.get(f"/api/social/rooms/{ROOM_ID}/messages?limit=5") + + body = r.json() + assert body["has_more"] is True + assert len(body["messages"]) == 5 + + def test_before_filter_is_passed_through(self): + captured = {} + def table_side_effect(name): + m = MagicMock() + if name == "room_messages": + def _select(cols, filters=None, order=None, limit=None): + captured["filters"] = filters + captured["order"] = order + captured["limit"] = limit + return [] + m.select.side_effect = _select + elif name == "room_reactions": + m.select.return_value = [] + else: + m.select.return_value = [] + return m + + with patch("routes.social.table", side_effect=table_side_effect): + r = client.get(f"/api/social/rooms/{ROOM_ID}/messages?before=2026-04-02T00:00:00Z&limit=20") + + assert r.status_code == 200 + assert captured["filters"]["created_at"] == "lt.2026-04-02T00:00:00Z" + assert captured["order"] == "created_at.desc" + assert captured["limit"] == 20 + + def test_empty_room_returns_no_more(self): + with patch("routes.social.table") as t: + t.return_value.select.return_value = [] + r = client.get(f"/api/social/rooms/{ROOM_ID}/messages") + assert r.status_code == 200 + assert r.json() == {"messages": [], "has_more": False} + + def test_limit_is_clamped_to_max(self): + captured = {} + def table_side_effect(name): + m = MagicMock() + if name == "room_messages": + def _select(cols, filters=None, order=None, limit=None): + captured["limit"] = limit + return [] + m.select.side_effect = _select + elif name == "room_reactions": + m.select.return_value = [] + else: + m.select.return_value = [] + return m + + with patch("routes.social.table", side_effect=table_side_effect): + r = client.get(f"/api/social/rooms/{ROOM_ID}/messages?limit=9999") + + assert r.status_code == 200 + assert captured["limit"] == 200 # clamped + + def test_limit_floor_is_one(self): + captured = {} + def table_side_effect(name): + m = MagicMock() + if name == "room_messages": + def _select(cols, filters=None, order=None, limit=None): + captured["limit"] = limit + return [] + m.select.side_effect = _select + elif name == "room_reactions": + m.select.return_value = [] + else: + m.select.return_value = [] + return m + + with patch("routes.social.table", side_effect=table_side_effect): + r = client.get(f"/api/social/rooms/{ROOM_ID}/messages?limit=0") + + assert r.status_code == 200 + assert captured["limit"] == 1 diff --git a/backend/tests/test_study_guide_routes.py b/backend/tests/test_study_guide_routes.py new file mode 100644 index 00000000..551a6fbc --- /dev/null +++ b/backend/tests/test_study_guide_routes.py @@ -0,0 +1,180 @@ +""" +Unit tests for routes/study_guide.py + +Covers: + - GET /api/study-guide/{user_id}/exams → get_exams + - GET /api/study-guide/{user_id}/cached → get_cached_guides + - GET /api/study-guide/{user_id}/guide → get_guide (cached + fresh) + - POST /api/study-guide/regenerate → regenerate_guide +""" +from unittest.mock import MagicMock, patch + +from fastapi.testclient import TestClient + +from main import app + +client = TestClient(app) + +USER_ID = "user_test" +COURSE_ID = "course_1" +EXAM_ID = "exam_1" + + +# ── GET /api/study-guide/{user_id}/exams ───────────────────────────────────── + +class TestGetExams: + def test_filters_by_type_and_keywords(self): + all_assignments = [ + {"id": "a1", "title": "Midterm Exam", "due_date": "2026-04-01", "assignment_type": "exam"}, + {"id": "a2", "title": "Homework 3", "due_date": "2026-04-02", "assignment_type": "homework"}, + {"id": "a3", "title": "Reading quiz", "due_date": "2026-04-03", "assignment_type": "other"}, + {"id": "a4", "title": "Project B", "due_date": "2026-04-04", "assignment_type": "project"}, + ] + with patch("routes.study_guide.table") as t: + t.return_value.select.return_value = all_assignments + r = client.get(f"/api/study-guide/{USER_ID}/exams?course_id={COURSE_ID}") + assert r.status_code == 200 + slugs = {e["title"] for e in r.json()["exams"]} + assert "Midterm Exam" in slugs + assert "Reading quiz" in slugs # title contains "quiz" + assert "Homework 3" not in slugs + assert "Project B" not in slugs + + +# ── GET /api/study-guide/{user_id}/cached ──────────────────────────────────── + +class TestGetCachedGuides: + def test_enriches_with_course_name(self): + guides = [{ + "id": "g1", "course_id": "c1", "exam_id": "e1", + "generated_at": "2026-04-01T00:00:00Z", + "content": {"exam": "Midterm", "overview": "Covers ch1-5"}, + }] + + def table_side_effect(name): + m = MagicMock() + if name == "study_guides": + m.select.return_value = guides + elif name == "courses": + m.select.return_value = [{"id": "c1", "course_name": "Calc II"}] + else: + m.select.return_value = [] + return m + + with patch("routes.study_guide.table", side_effect=table_side_effect): + r = client.get(f"/api/study-guide/{USER_ID}/cached") + + assert r.status_code == 200 + out = r.json()["guides"][0] + assert out["course_name"] == "Calc II" + assert out["exam_title"] == "Midterm" + assert out["overview"] == "Covers ch1-5" + + def test_empty_when_no_guides(self): + with patch("routes.study_guide.table") as t: + t.return_value.select.return_value = [] + r = client.get(f"/api/study-guide/{USER_ID}/cached") + assert r.status_code == 200 + assert r.json() == {"guides": []} + + +# ── GET /api/study-guide/{user_id}/guide ───────────────────────────────────── + +class TestGetGuide: + def test_returns_cached_guide_without_calling_gemini(self): + cached_row = { + "id": "g1", "user_id": USER_ID, + "course_id": COURSE_ID, "exam_id": EXAM_ID, + "generated_at": "2026-04-01T00:00:00Z", + "content": {"exam": "Midterm", "topics": []}, + } + with patch("routes.study_guide.table") as t, \ + patch("routes.study_guide.call_gemini_json") as gem: + t.return_value.select.return_value = [cached_row] + r = client.get(f"/api/study-guide/{USER_ID}/guide?course_id={COURSE_ID}&exam_id={EXAM_ID}") + assert r.status_code == 200 + body = r.json() + assert body["cached"] is True + assert body["guide"]["exam"] == "Midterm" + gem.assert_not_called() + + def test_generates_and_inserts_when_not_cached(self): + fresh_content = {"exam": "Final", "topics": [{"name": "Topic 1"}]} + + def table_side_effect(name): + m = MagicMock() + if name == "study_guides": + m.select.return_value = [] # nothing cached + m.insert.return_value = [{}] + elif name == "assignments": + m.select.return_value = [{"title": "Final", "due_date": "2026-05-01"}] + elif name == "documents": + m.select.return_value = [] + else: + m.select.return_value = [] + return m + + with patch("routes.study_guide.table", side_effect=table_side_effect), \ + patch("routes.study_guide.call_gemini_json", return_value=fresh_content) as gem: + r = client.get(f"/api/study-guide/{USER_ID}/guide?course_id={COURSE_ID}&exam_id={EXAM_ID}") + assert r.status_code == 200 + body = r.json() + assert body["cached"] is False + assert body["guide"]["exam"] == "Final" + gem.assert_called_once() + + def test_unknown_exam_returns_404(self): + def table_side_effect(name): + m = MagicMock() + if name == "study_guides": + m.select.return_value = [] + elif name == "assignments": + m.select.return_value = [] # exam not found + else: + m.select.return_value = [] + return m + + with patch("routes.study_guide.table", side_effect=table_side_effect): + r = client.get(f"/api/study-guide/{USER_ID}/guide?course_id={COURSE_ID}&exam_id=nope") + assert r.status_code == 404 + + +# ── POST /api/study-guide/regenerate ───────────────────────────────────────── + +class TestRegenerateGuide: + def test_deletes_cached_and_regenerates(self): + fresh_content = {"exam": "Midterm", "topics": []} + delete_called = {"n": 0} + + def table_side_effect(name): + m = MagicMock() + if name == "study_guides": + m.select.return_value = [] + m.insert.return_value = [{}] + def _delete(filters=None): + delete_called["n"] += 1 + return [] + m.delete.side_effect = _delete + elif name == "assignments": + m.select.return_value = [{"title": "Midterm", "due_date": "2026-04-01"}] + elif name == "documents": + m.select.return_value = [] + else: + m.select.return_value = [] + return m + + with patch("routes.study_guide.table", side_effect=table_side_effect), \ + patch("routes.study_guide.call_gemini_json", return_value=fresh_content): + r = client.post( + "/api/study-guide/regenerate", + json={"user_id": USER_ID, "course_id": COURSE_ID, "exam_id": EXAM_ID}, + ) + assert r.status_code == 200 + body = r.json() + assert body["success"] is True + assert body["guide"]["exam"] == "Midterm" + assert delete_called["n"] == 1 + + def test_missing_fields_returns_400(self): + r = client.post("/api/study-guide/regenerate", json={"user_id": USER_ID}) + assert r.status_code == 400 From 399eae32bf803f9bf990465466b7283ea0a7dd96 Mon Sep 17 00:00:00 2001 From: Jose Cruz Date: Sun, 19 Apr 2026 14:42:31 -0400 Subject: [PATCH 02/52] frontend: ship revamp shell, screens, and API client Removes the legacy Next.js layout, jest harness, Dockerfile, and the old /signin, /privacy, /terms, /about, /careers, /flashcards pages. New app shell under src/app/(shell) with Sidebar + FloatingActions + global feedback flows. New screen components under components/screens for Dashboard, Learn, Tree, Study, Library, Calendar, Social, Achievements, Settings, Admin, plus a new public Profile page at /profile/[userId]. Onboarding and Auth live outside the shell. Milestone coverage: - M7 Study: /study now toggles between Study Guide (course -> exam cascading picker, recent-guides sidebar, per-topic cards, regenerate) and Flashcards (course-scoped generation, topic pills, 3D flip, 1/2/3 rating + Space/1/2/3 keyboard, "Generated using N library docs" chip). - M8 Profile/Settings/Admin/Achievements: public ProfileView, Settings tabs + CustomSelect + username availability + avatar upload (5 MB guard) + preview modal + cosmetics manager with Owned/Catalog toggle, Admin rewritten with Users/Roles/ Achievements/Cosmetics/Analytics tabs and RoleBadge assign/revoke inline, Achievements editable showcase (up to 5, drag-reorder) + progress bars + unlock toast via focus delta. - M9 Polish & a11y: useBodyScrollLock hook threaded through every full-viewport overlay, role="log"+aria-live on ChatPanel, skip-to- content link, prefers-reduced-motion CSS + one-shot d3 settle, KnowledgeGraph `comparison` prop + mastery bars in Social overview. Deferred items resolved: inline assignment edit, room-message pagination (before/limit + scroll preservation), KnowledgeGraph comparison overlay, Dashboard mobile tabs (already present - no change). Client-side housekeeping: local-mode shim handlers for every new endpoint, typed helpers in lib/api.ts, Link-based entry points to the public profile from Social directory, MemberRow, and StudyMatch cards. --- frontend/.dockerignore | 3 - frontend/.env.example | 12 + frontend/.gitignore | 7 + frontend/Dockerfile | 22 - frontend/README.md | 42 +- frontend/eslint.config.mjs | 18 - frontend/jest.config.js | 14 - frontend/jest.setup.js | 5 - frontend/next.config.ts | 24 +- frontend/package-lock.json | 11578 +++++----------- frontend/package.json | 21 +- frontend/postcss.config.mjs | 7 - frontend/public/sapling-icon.svg | 10 - frontend/public/sapling-word-icon.png | Bin 40998 -> 0 bytes frontend/src/__mocks__/rehypeKatex.js | 1 - frontend/src/__mocks__/remarkMath.js | 1 - frontend/src/__mocks__/styleMock.js | 1 - frontend/src/__tests__/README.md | 57 - .../src/__tests__/achievementCard.test.tsx | 80 - frontend/src/__tests__/api.test.ts | 448 - .../__tests__/authAndPrefillWiring.test.ts | 30 - frontend/src/__tests__/chatPanel.test.tsx | 201 - frontend/src/__tests__/dataFetching.test.tsx | 217 - frontend/src/__tests__/graphUtils.test.ts | 297 - frontend/src/__tests__/hydration.test.tsx | 107 - frontend/src/__tests__/roleBadge.test.tsx | 73 - .../src/__tests__/sessionSummary.test.tsx | 168 - frontend/src/__tests__/settings.test.tsx | 118 - .../src/__tests__/signinCallback.test.tsx | 123 - frontend/src/__tests__/userContext.test.tsx | 99 - .../src/app/(shell)/achievements/page.tsx | 5 + frontend/src/app/(shell)/admin/page.tsx | 5 + frontend/src/app/(shell)/calendar/page.tsx | 10 + frontend/src/app/(shell)/dashboard/page.tsx | 10 + frontend/src/app/(shell)/layout.tsx | 26 + frontend/src/app/(shell)/learn/page.tsx | 5 + frontend/src/app/(shell)/library/page.tsx | 5 + .../src/app/(shell)/profile/[userId]/page.tsx | 45 + frontend/src/app/(shell)/settings/page.tsx | 5 + frontend/src/app/(shell)/social/page.tsx | 10 + frontend/src/app/(shell)/study/page.tsx | 5 + frontend/src/app/(shell)/tree/page.tsx | 10 + frontend/src/app/about/page.tsx | 86 - frontend/src/app/achievements/page.tsx | 152 - frontend/src/app/admin/page.tsx | 268 - frontend/src/app/api/auth/session/route.ts | 14 +- .../app/{signin => auth}/callback/page.tsx | 53 +- frontend/src/app/auth/page.tsx | 5 + frontend/src/app/calendar/page.tsx | 519 - frontend/src/app/careers/[slug]/ApplyForm.tsx | 409 - frontend/src/app/careers/[slug]/page.tsx | 12 - frontend/src/app/careers/jobs.ts | 28 - frontend/src/app/careers/page.tsx | 255 - frontend/src/app/dashboard/page.tsx | 1536 -- frontend/src/app/error.tsx | 39 +- frontend/src/app/flashcards/page.tsx | 443 - frontend/src/app/globals.css | 1123 +- frontend/src/app/icon.svg | 10 - frontend/src/app/layout.tsx | 82 +- frontend/src/app/learn/page.tsx | 594 - frontend/src/app/library/page.tsx | 387 - frontend/src/app/onboarding/page.tsx | 5 + frontend/src/app/page.tsx | 954 +- frontend/src/app/pending/page.tsx | 77 +- frontend/src/app/privacy/page.tsx | 180 - frontend/src/app/settings/page.tsx | 1270 -- frontend/src/app/signin/page.tsx | 140 - frontend/src/app/social/page.tsx | 328 - frontend/src/app/study/FlashcardsPanel.tsx | 322 - frontend/src/app/study/StudyClient.tsx | 316 - frontend/src/app/study/page.tsx | 10 - frontend/src/app/terms/page.tsx | 116 - frontend/src/app/tree/page.tsx | 382 - frontend/src/components/AIDisclaimerChip.tsx | 99 +- frontend/src/components/AchievementCard.tsx | 137 - .../src/components/AchievementShowcase.tsx | 78 - .../src/components/AchievementUnlockToast.tsx | 81 - frontend/src/components/AssignmentTable.tsx | 319 - frontend/src/components/Avatar.tsx | 94 +- frontend/src/components/AvatarFrame.tsx | 65 +- frontend/src/components/ChatPanel.tsx | 332 +- frontend/src/components/CosmeticsManager.tsx | 171 - frontend/src/components/CustomSelect.tsx | 334 +- frontend/src/components/DisclaimerModal.tsx | 131 +- .../src/components/DocumentUploadModal.tsx | 872 +- frontend/src/components/ErrorBoundary.tsx | 103 +- frontend/src/components/FeedbackFlow.tsx | 477 +- frontend/src/components/FloatingActions.tsx | 22 + frontend/src/components/HowItWorks.tsx | 652 - frontend/src/components/Icon.tsx | 53 + frontend/src/components/KnowledgeGraph.tsx | 985 +- .../src/components/ManageCoursesModal.tsx | 265 + frontend/src/components/MarkdownChat.tsx | 85 + frontend/src/components/MiniStat.tsx | 31 + frontend/src/components/ModeSelector.tsx | 124 - frontend/src/components/NameColorRenderer.tsx | 48 +- frontend/src/components/Navbar.tsx | 421 - frontend/src/components/OnboardingFlow.tsx | 732 - frontend/src/components/Pill.tsx | 38 + frontend/src/components/ProfileBanner.tsx | 37 - frontend/src/components/ProfileView.tsx | 197 + frontend/src/components/QuizPanel.tsx | 583 +- frontend/src/components/ReportIssueFlow.tsx | 596 +- frontend/src/components/RoleBadge.tsx | 62 +- frontend/src/components/RoomChat.tsx | 677 - frontend/src/components/RoomList.tsx | 278 - frontend/src/components/RoomMembers.tsx | 230 - frontend/src/components/RoomOverview.tsx | 227 - frontend/src/components/SchoolDirectory.tsx | 139 - .../src/components/SessionFeedbackFlow.tsx | 480 +- .../src/components/SessionFeedbackGlobal.tsx | 68 +- frontend/src/components/SessionSummary.tsx | 163 +- .../src/components/SharedContextToggle.tsx | 206 +- frontend/src/components/Sidebar.tsx | 230 + frontend/src/components/SpaceBackground.tsx | 11 - frontend/src/components/Sparkline.tsx | 22 + frontend/src/components/StudyMatch.tsx | 275 - frontend/src/components/TitleFlair.tsx | 63 +- frontend/src/components/ToastProvider.tsx | 221 +- frontend/src/components/TopBar.tsx | 36 + frontend/src/components/UploadZone.tsx | 76 - .../src/components/screens/Achievements.tsx | 304 + frontend/src/components/screens/Admin.tsx | 761 + frontend/src/components/screens/Auth.tsx | 157 + frontend/src/components/screens/Calendar.tsx | 609 + frontend/src/components/screens/Dashboard.tsx | 648 + frontend/src/components/screens/Learn.tsx | 592 + frontend/src/components/screens/Library.tsx | 399 + .../src/components/screens/Onboarding.tsx | 543 + frontend/src/components/screens/Settings.tsx | 777 ++ frontend/src/components/screens/Social.tsx | 1063 ++ frontend/src/components/screens/Study.tsx | 617 + frontend/src/components/screens/Tree.tsx | 393 + frontend/src/context/UserContext.tsx | 31 +- frontend/src/lib/api.ts | 500 +- frontend/src/lib/data.ts | 222 + frontend/src/lib/graphUtils.ts | 185 - frontend/src/lib/localData.ts | 320 +- frontend/src/lib/sessionToken.ts | 2 +- frontend/src/lib/sidebar.tsx | 43 + frontend/src/lib/supabase.ts | 2 - frontend/src/lib/types.ts | 70 +- frontend/src/lib/useBodyScrollLock.ts | 10 + frontend/src/lib/useConfirm.ts | 38 + frontend/src/lib/useIsMobile.ts | 20 + frontend/src/middleware.ts | 66 +- frontend/tsconfig.json | 17 +- 147 files changed, 15192 insertions(+), 28863 deletions(-) delete mode 100644 frontend/.dockerignore create mode 100644 frontend/.env.example create mode 100644 frontend/.gitignore delete mode 100644 frontend/Dockerfile delete mode 100644 frontend/eslint.config.mjs delete mode 100644 frontend/jest.config.js delete mode 100644 frontend/jest.setup.js delete mode 100644 frontend/postcss.config.mjs delete mode 100644 frontend/public/sapling-icon.svg delete mode 100644 frontend/public/sapling-word-icon.png delete mode 100644 frontend/src/__mocks__/rehypeKatex.js delete mode 100644 frontend/src/__mocks__/remarkMath.js delete mode 100644 frontend/src/__mocks__/styleMock.js delete mode 100644 frontend/src/__tests__/README.md delete mode 100644 frontend/src/__tests__/achievementCard.test.tsx delete mode 100644 frontend/src/__tests__/api.test.ts delete mode 100644 frontend/src/__tests__/authAndPrefillWiring.test.ts delete mode 100644 frontend/src/__tests__/chatPanel.test.tsx delete mode 100644 frontend/src/__tests__/dataFetching.test.tsx delete mode 100644 frontend/src/__tests__/graphUtils.test.ts delete mode 100644 frontend/src/__tests__/hydration.test.tsx delete mode 100644 frontend/src/__tests__/roleBadge.test.tsx delete mode 100644 frontend/src/__tests__/sessionSummary.test.tsx delete mode 100644 frontend/src/__tests__/settings.test.tsx delete mode 100644 frontend/src/__tests__/signinCallback.test.tsx delete mode 100644 frontend/src/__tests__/userContext.test.tsx create mode 100644 frontend/src/app/(shell)/achievements/page.tsx create mode 100644 frontend/src/app/(shell)/admin/page.tsx create mode 100644 frontend/src/app/(shell)/calendar/page.tsx create mode 100644 frontend/src/app/(shell)/dashboard/page.tsx create mode 100644 frontend/src/app/(shell)/layout.tsx create mode 100644 frontend/src/app/(shell)/learn/page.tsx create mode 100644 frontend/src/app/(shell)/library/page.tsx create mode 100644 frontend/src/app/(shell)/profile/[userId]/page.tsx create mode 100644 frontend/src/app/(shell)/settings/page.tsx create mode 100644 frontend/src/app/(shell)/social/page.tsx create mode 100644 frontend/src/app/(shell)/study/page.tsx create mode 100644 frontend/src/app/(shell)/tree/page.tsx delete mode 100644 frontend/src/app/about/page.tsx delete mode 100644 frontend/src/app/achievements/page.tsx delete mode 100644 frontend/src/app/admin/page.tsx rename frontend/src/app/{signin => auth}/callback/page.tsx (58%) create mode 100644 frontend/src/app/auth/page.tsx delete mode 100644 frontend/src/app/calendar/page.tsx delete mode 100644 frontend/src/app/careers/[slug]/ApplyForm.tsx delete mode 100644 frontend/src/app/careers/[slug]/page.tsx delete mode 100644 frontend/src/app/careers/jobs.ts delete mode 100644 frontend/src/app/careers/page.tsx delete mode 100644 frontend/src/app/dashboard/page.tsx delete mode 100644 frontend/src/app/flashcards/page.tsx delete mode 100644 frontend/src/app/icon.svg delete mode 100644 frontend/src/app/learn/page.tsx delete mode 100644 frontend/src/app/library/page.tsx create mode 100644 frontend/src/app/onboarding/page.tsx delete mode 100644 frontend/src/app/privacy/page.tsx delete mode 100644 frontend/src/app/settings/page.tsx delete mode 100644 frontend/src/app/signin/page.tsx delete mode 100644 frontend/src/app/social/page.tsx delete mode 100644 frontend/src/app/study/FlashcardsPanel.tsx delete mode 100644 frontend/src/app/study/StudyClient.tsx delete mode 100644 frontend/src/app/study/page.tsx delete mode 100644 frontend/src/app/terms/page.tsx delete mode 100644 frontend/src/app/tree/page.tsx delete mode 100644 frontend/src/components/AchievementCard.tsx delete mode 100644 frontend/src/components/AchievementShowcase.tsx delete mode 100644 frontend/src/components/AchievementUnlockToast.tsx delete mode 100644 frontend/src/components/AssignmentTable.tsx delete mode 100644 frontend/src/components/CosmeticsManager.tsx create mode 100644 frontend/src/components/FloatingActions.tsx delete mode 100644 frontend/src/components/HowItWorks.tsx create mode 100644 frontend/src/components/Icon.tsx create mode 100644 frontend/src/components/ManageCoursesModal.tsx create mode 100644 frontend/src/components/MarkdownChat.tsx create mode 100644 frontend/src/components/MiniStat.tsx delete mode 100644 frontend/src/components/ModeSelector.tsx delete mode 100644 frontend/src/components/Navbar.tsx delete mode 100644 frontend/src/components/OnboardingFlow.tsx create mode 100644 frontend/src/components/Pill.tsx delete mode 100644 frontend/src/components/ProfileBanner.tsx create mode 100644 frontend/src/components/ProfileView.tsx delete mode 100644 frontend/src/components/RoomChat.tsx delete mode 100644 frontend/src/components/RoomList.tsx delete mode 100644 frontend/src/components/RoomMembers.tsx delete mode 100644 frontend/src/components/RoomOverview.tsx delete mode 100644 frontend/src/components/SchoolDirectory.tsx create mode 100644 frontend/src/components/Sidebar.tsx delete mode 100644 frontend/src/components/SpaceBackground.tsx create mode 100644 frontend/src/components/Sparkline.tsx delete mode 100644 frontend/src/components/StudyMatch.tsx create mode 100644 frontend/src/components/TopBar.tsx delete mode 100644 frontend/src/components/UploadZone.tsx create mode 100644 frontend/src/components/screens/Achievements.tsx create mode 100644 frontend/src/components/screens/Admin.tsx create mode 100644 frontend/src/components/screens/Auth.tsx create mode 100644 frontend/src/components/screens/Calendar.tsx create mode 100644 frontend/src/components/screens/Dashboard.tsx create mode 100644 frontend/src/components/screens/Learn.tsx create mode 100644 frontend/src/components/screens/Library.tsx create mode 100644 frontend/src/components/screens/Onboarding.tsx create mode 100644 frontend/src/components/screens/Settings.tsx create mode 100644 frontend/src/components/screens/Social.tsx create mode 100644 frontend/src/components/screens/Study.tsx create mode 100644 frontend/src/components/screens/Tree.tsx create mode 100644 frontend/src/lib/data.ts delete mode 100644 frontend/src/lib/graphUtils.ts create mode 100644 frontend/src/lib/sidebar.tsx create mode 100644 frontend/src/lib/useBodyScrollLock.ts create mode 100644 frontend/src/lib/useConfirm.ts create mode 100644 frontend/src/lib/useIsMobile.ts diff --git a/frontend/.dockerignore b/frontend/.dockerignore deleted file mode 100644 index df3b8463..00000000 --- a/frontend/.dockerignore +++ /dev/null @@ -1,3 +0,0 @@ -.env* -node_modules -.next diff --git a/frontend/.env.example b/frontend/.env.example new file mode 100644 index 00000000..f0e4eeb3 --- /dev/null +++ b/frontend/.env.example @@ -0,0 +1,12 @@ +# Set to "true" for mock-data dev mode (no backend required). +NEXT_PUBLIC_LOCAL_MODE=false + +# Backend URL (used by middleware/server routes for auth checks). +NEXT_PUBLIC_API_URL=http://localhost:5000 + +# HMAC secret (min 32 bytes). Must match backend SESSION_SECRET. +SESSION_SECRET=replace-me-with-at-least-32-bytes-of-random-string + +# Supabase (for realtime chat in /social rooms). +NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co +NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key diff --git a/frontend/.gitignore b/frontend/.gitignore new file mode 100644 index 00000000..754f2ac3 --- /dev/null +++ b/frontend/.gitignore @@ -0,0 +1,7 @@ +node_modules +.next +out +.env*.local +*.log +.DS_Store +tsconfig.tsbuildinfo diff --git a/frontend/Dockerfile b/frontend/Dockerfile deleted file mode 100644 index 762ab50f..00000000 --- a/frontend/Dockerfile +++ /dev/null @@ -1,22 +0,0 @@ -FROM node:20-alpine AS deps -WORKDIR /app -COPY package.json package-lock.json ./ -RUN npm ci - -FROM node:20-alpine AS builder -WORKDIR /app -COPY --from=deps /app/node_modules ./node_modules -COPY . . -ARG BACKEND_URL=http://backend:5000 -ENV BACKEND_URL=$BACKEND_URL -RUN npm run build - -FROM node:20-alpine AS runner -WORKDIR /app -ENV NODE_ENV=production -COPY --from=builder /app/.next/standalone ./ -COPY --from=builder /app/.next/static ./.next/static -COPY --from=builder /app/public ./public - -EXPOSE 3000 -CMD ["node", "server.js"] diff --git a/frontend/README.md b/frontend/README.md index e215bc4c..a2116341 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -1,36 +1,30 @@ -This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). +# Sapling — New Frontend -## Getting Started +A redesigned Next.js frontend for Sapling based on the `Sapling Rebuild` design prototype. -First, run the development server: +Visual system: warm paper neutrals, botanical green accent, serif display (Fraunces) + humanist sans (Inter), JetBrains Mono accents. Supports light/dark, accent themes (sage/forest/moss/ink/terracotta), density (compact/balanced/spacious), typography pairings, and three knowledge graph variants (orb/constellation/organism). + +## Run ```bash -npm run dev -# or -yarn dev -# or -pnpm dev -# or -bun dev +cd new_frontend +npm install +npm run dev # http://localhost:3001 ``` -Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. - -You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. - -This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. - -## Learn More +Backend rewrites go to `http://localhost:5000` by default (override via `BACKEND_URL`). -To learn more about Next.js, take a look at the following resources: +## Layout -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. +- `src/app/` — App Router routes. The shell (sidebar + top bar) wraps every route except `auth` and `onboarding`, which are full-bleed. +- `src/components/` — shared UI primitives and per-screen components. +- `src/lib/data.ts` — mock data mirroring the design bundle. Swap for real API calls when wiring up. +- `src/lib/tweaks.tsx` — runtime design-token context (theme/accent/type/density/layout/graph). -You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! +## Routes -## Deploy on Vercel +`/dashboard` `/learn` `/tree` `/study` `/library` `/calendar` `/social` `/achievements` `/settings` `/admin` — wrapped by the shell layout. -The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. +`/auth` `/onboarding` — full-bleed. -Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. +A floating Tweaks panel (bottom-left) lets you switch themes live. A Report button (bottom-right) opens the feedback modal. diff --git a/frontend/eslint.config.mjs b/frontend/eslint.config.mjs deleted file mode 100644 index 05e726d1..00000000 --- a/frontend/eslint.config.mjs +++ /dev/null @@ -1,18 +0,0 @@ -import { defineConfig, globalIgnores } from "eslint/config"; -import nextVitals from "eslint-config-next/core-web-vitals"; -import nextTs from "eslint-config-next/typescript"; - -const eslintConfig = defineConfig([ - ...nextVitals, - ...nextTs, - // Override default ignores of eslint-config-next. - globalIgnores([ - // Default ignores of eslint-config-next: - ".next/**", - "out/**", - "build/**", - "next-env.d.ts", - ]), -]); - -export default eslintConfig; diff --git a/frontend/jest.config.js b/frontend/jest.config.js deleted file mode 100644 index fc9f7b3b..00000000 --- a/frontend/jest.config.js +++ /dev/null @@ -1,14 +0,0 @@ -const nextJest = require('next/jest'); - -const createJestConfig = nextJest({ dir: './' }); - -module.exports = createJestConfig({ - testEnvironment: 'jest-environment-jsdom', - moduleNameMapper: { - '^@/(.*)$': '/src/$1', - '^remark-math$': '/src/__mocks__/remarkMath.js', - '^rehype-katex$': '/src/__mocks__/rehypeKatex.js', - 'katex/dist/katex.min.css': '/src/__mocks__/styleMock.js', - }, - setupFilesAfterEnv: ['/jest.setup.js'], -}); diff --git a/frontend/jest.setup.js b/frontend/jest.setup.js deleted file mode 100644 index 5b6656d3..00000000 --- a/frontend/jest.setup.js +++ /dev/null @@ -1,5 +0,0 @@ -import '@testing-library/jest-dom'; - -// jsdom doesn't implement scrollIntoView — mock it globally so components -// that call ref.scrollIntoView() don't throw during tests. -window.HTMLElement.prototype.scrollIntoView = jest.fn(); diff --git a/frontend/next.config.ts b/frontend/next.config.ts index c355f215..41dd8c9f 100644 --- a/frontend/next.config.ts +++ b/frontend/next.config.ts @@ -1,23 +1,15 @@ import type { NextConfig } from "next"; -const isStaticExport = process.env.STATIC_EXPORT === "true"; const BACKEND_URL = process.env.BACKEND_URL || "http://localhost:5000"; const nextConfig: NextConfig = { - ...(isStaticExport - ? { output: "export", images: { unoptimized: true } } - : { - output: "standalone", - async rewrites() { - return [ - { - source: "/api/:path*", - destination: `${BACKEND_URL}/api/:path*`, - }, - ]; - }, - }), - reactCompiler: true, + output: "standalone", + async rewrites() { + return [ + { source: "/api/auth/session", destination: "/api/auth/session" }, + { source: "/api/:path*", destination: `${BACKEND_URL}/api/:path*` }, + ]; + }, }; -export default nextConfig; \ No newline at end of file +export default nextConfig; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 2ecf7bdb..51c5f643 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,18 +1,16 @@ { - "name": "frontend", + "name": "sapling-frontend", "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "frontend", + "name": "sapling-frontend", "version": "0.1.0", "dependencies": { "@supabase/supabase-js": "^2.99.3", "d3": "^7.9.0", - "framer-motion": "^12.38.0", - "katex": "^0.16.40", - "lucide-react": "^0.577.0", + "katex": "^0.16.45", "next": "16.1.6", "react": "19.2.3", "react-dom": "19.2.3", @@ -21,66 +19,15 @@ "remark-math": "^6.0.0" }, "devDependencies": { - "@tailwindcss/postcss": "^4", - "@testing-library/jest-dom": "^6.9.1", - "@testing-library/react": "^16.3.2", - "@testing-library/user-event": "^14.6.1", "@types/d3": "^7.4.3", - "@types/jest": "^30.0.0", "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", - "babel-plugin-react-compiler": "1.0.0", "eslint": "^9", "eslint-config-next": "16.1.6", - "jest": "^30.2.0", - "jest-environment-jsdom": "^30.2.0", - "tailwindcss": "^4", - "ts-jest": "^29.4.6", "typescript": "^5" } }, - "node_modules/@adobe/css-tools": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.4.tgz", - "integrity": "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@alloc/quick-lru": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", - "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@asamuzakjp/css-color": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz", - "integrity": "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@csstools/css-calc": "^2.1.3", - "@csstools/css-color-parser": "^3.0.9", - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3", - "lru-cache": "^10.4.3" - } - }, - "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" - }, "node_modules/@babel/code-frame": { "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", @@ -213,21 +160,11 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", - "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-string-parser": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -237,7 +174,7 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -254,23 +191,23 @@ } }, "node_modules/@babel/helpers": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", - "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", + "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/types": "^7.29.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", - "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", "dev": true, "license": "MIT", "dependencies": { @@ -283,625 +220,268 @@ "node": ">=6.0.0" } }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", - "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" } }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", "license": "MIT", + "optional": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "tslib": "^2.4.0" } }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", - "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "tslib": "^2.4.0" } }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "eslint-visitor-keys": "^3.4.3" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "node_modules/@eslint/config-array": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.5" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@eslint/core": "^0.17.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@types/json-schema": "^7.0.15" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "node_modules/@eslint/eslintrc": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", + "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "ajv": "^6.14.0", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.5", + "strip-json-comments": "^3.1.1" }, "engines": { - "node": ">=6.9.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", - "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", + "node_modules/@eslint/js": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", + "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" - }, "engines": { - "node": ">=6.9.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "funding": { + "url": "https://eslint.org/donate" } }, - "node_modules/@babel/runtime": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", - "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "engines": { - "node": ">=6.9.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@babel/template": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", - "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/parser": "^7.28.6", - "@babel/types": "^7.28.6" + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" }, "engines": { - "node": ">=6.9.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@babel/traverse": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", - "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0", - "debug": "^4.3.1" + "@humanfs/types": "^0.15.0" }, "engines": { - "node": ">=6.9.0" + "node": ">=18.18.0" } }, - "node_modules/@babel/types": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", - "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", - "devOptional": true, - "license": "MIT", + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" }, "engines": { - "node": ">=6.9.0" + "node": ">=18.18.0" } }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", "dev": true, - "license": "MIT" - }, - "node_modules/@csstools/color-helpers": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", - "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "engines": { - "node": ">=18" - } - }, - "node_modules/@csstools/css-calc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", - "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" - } - }, - "node_modules/@csstools/css-color-parser": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", - "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "dependencies": { - "@csstools/color-helpers": "^5.1.0", - "@csstools/css-calc": "^2.1.4" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" - } - }, - "node_modules/@csstools/css-parser-algorithms": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", - "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-tokenizer": "^3.0.4" - } - }, - "node_modules/@csstools/css-tokenizer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", - "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/@emnapi/core": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.8.1.tgz", - "integrity": "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.1.0", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", - "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", - "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", - "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", - "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/config-array": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", - "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/object-schema": "^2.1.7", - "debug": "^4.3.1", - "minimatch": "^3.1.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/config-helpers": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", - "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.17.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/core": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", - "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", - "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.1", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/js": { - "version": "9.39.3", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.3.tgz", - "integrity": "sha512-1B1VkCq6FuUNlQvlBYb+1jDu/gV297TIs/OeiaSR9l1H27SVW55ONE1e1Vp16NqP683+xEGzxYtv4XCiDPaQiw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - } - }, - "node_modules/@eslint/object-schema": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", - "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/plugin-kit": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", - "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.17.0", - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node": { - "version": "0.16.7", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", - "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.4.0" - }, - "engines": { - "node": ">=18.18.0" - } + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", @@ -932,9 +512,9 @@ } }, "node_modules/@img/colour": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz", - "integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", "license": "MIT", "optional": true, "engines": { @@ -1397,3924 +977,1451 @@ "url": "https://opencollective.com/libvips" } }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", "dev": true, "license": "MIT", "dependencies": { - "sprintf-js": "~1.0.2" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, "engines": { - "node": ">=8" + "node": ">=6.0.0" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", - "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } + "license": "MIT" }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "dev": true, "license": "MIT", "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.10.0" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "node_modules/@next/env": { + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.6.tgz", + "integrity": "sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==", + "license": "MIT" + }, + "node_modules/@next/eslint-plugin-next": { + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.1.6.tgz", + "integrity": "sha512-/Qq3PTagA6+nYVfryAtQ7/9FEr/6YVyvOtl6rZnGsbReGLf0jZU6gkpr1FuChAQpvV46a78p4cmHOVP8mbfSMQ==", "dev": true, "license": "MIT", "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" + "fast-glob": "3.3.1" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, + "node_modules/@next/swc-darwin-arm64": { + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.6.tgz", + "integrity": "sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw==", + "cpu": [ + "arm64" + ], "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=8" + "node": ">= 10" } }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, + "node_modules/@next/swc-darwin-x64": { + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.6.tgz", + "integrity": "sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ==", + "cpu": [ + "x64" + ], "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=8" + "node": ">= 10" } }, - "node_modules/@jest/console": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.2.0.tgz", - "integrity": "sha512-+O1ifRjkvYIkBqASKWgLxrpEhQAAE7hY77ALLUufSk5717KfOShg6IbqLmdsLMPdUiFvA2kTs0R7YZy+l0IzZQ==", - "dev": true, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.6.tgz", + "integrity": "sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@jest/types": "30.2.0", - "@types/node": "*", - "chalk": "^4.1.2", - "jest-message-util": "30.2.0", - "jest-util": "30.2.0", - "slash": "^3.0.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">= 10" } }, - "node_modules/@jest/core": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.2.0.tgz", - "integrity": "sha512-03W6IhuhjqTlpzh/ojut/pDB2LPRygyWX8ExpgHtQA8H/3K7+1vKmcINx5UzeOX1se6YEsBsOHQ1CRzf3fOwTQ==", - "dev": true, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.6.tgz", + "integrity": "sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@jest/console": "30.2.0", - "@jest/pattern": "30.0.1", - "@jest/reporters": "30.2.0", - "@jest/test-result": "30.2.0", - "@jest/transform": "30.2.0", - "@jest/types": "30.2.0", - "@types/node": "*", - "ansi-escapes": "^4.3.2", - "chalk": "^4.1.2", - "ci-info": "^4.2.0", - "exit-x": "^0.2.2", - "graceful-fs": "^4.2.11", - "jest-changed-files": "30.2.0", - "jest-config": "30.2.0", - "jest-haste-map": "30.2.0", - "jest-message-util": "30.2.0", - "jest-regex-util": "30.0.1", - "jest-resolve": "30.2.0", - "jest-resolve-dependencies": "30.2.0", - "jest-runner": "30.2.0", - "jest-runtime": "30.2.0", - "jest-snapshot": "30.2.0", - "jest-util": "30.2.0", - "jest-validate": "30.2.0", - "jest-watcher": "30.2.0", - "micromatch": "^4.0.8", - "pretty-format": "30.2.0", - "slash": "^3.0.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "node": ">= 10" } }, - "node_modules/@jest/core/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.6.tgz", + "integrity": "sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==", + "cpu": [ + "x64" + ], "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">= 10" } }, - "node_modules/@jest/core/node_modules/jest-config": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.2.0.tgz", - "integrity": "sha512-g4WkyzFQVWHtu6uqGmQR4CQxz/CH3yDSlhzXMWzNjDx843gYjReZnMRanjRCq5XZFuQrGDxgUaiYWE8BRfVckA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.27.4", - "@jest/get-type": "30.1.0", - "@jest/pattern": "30.0.1", - "@jest/test-sequencer": "30.2.0", - "@jest/types": "30.2.0", - "babel-jest": "30.2.0", - "chalk": "^4.1.2", - "ci-info": "^4.2.0", - "deepmerge": "^4.3.1", - "glob": "^10.3.10", - "graceful-fs": "^4.2.11", - "jest-circus": "30.2.0", - "jest-docblock": "30.2.0", - "jest-environment-node": "30.2.0", - "jest-regex-util": "30.0.1", - "jest-resolve": "30.2.0", - "jest-runner": "30.2.0", - "jest-util": "30.2.0", - "jest-validate": "30.2.0", - "micromatch": "^4.0.8", - "parse-json": "^5.2.0", - "pretty-format": "30.2.0", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.6.tgz", + "integrity": "sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "peerDependencies": { - "@types/node": "*", - "esbuild-register": ">=3.4.0", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "esbuild-register": { - "optional": true - }, - "ts-node": { - "optional": true - } + "node": ">= 10" } }, - "node_modules/@jest/core/node_modules/pretty-format": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", - "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", - "dev": true, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.6.tgz", + "integrity": "sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@jest/schemas": "30.0.5", - "ansi-styles": "^5.2.0", - "react-is": "^18.3.1" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">= 10" } }, - "node_modules/@jest/core/node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jest/diff-sequences": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz", - "integrity": "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==", - "dev": true, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.6.tgz", + "integrity": "sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A==", + "cpu": [ + "x64" + ], "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">= 10" } }, - "node_modules/@jest/environment": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.2.0.tgz", - "integrity": "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g==", + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, "license": "MIT", "dependencies": { - "@jest/fake-timers": "30.2.0", - "@jest/types": "30.2.0", - "@types/node": "*", - "jest-mock": "30.2.0" + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">= 8" } }, - "node_modules/@jest/environment-jsdom-abstract": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/environment-jsdom-abstract/-/environment-jsdom-abstract-30.2.0.tgz", - "integrity": "sha512-kazxw2L9IPuZpQ0mEt9lu9Z98SqR74xcagANmMBU16X0lS23yPc0+S6hGLUz8kVRlomZEs/5S/Zlpqwf5yu6OQ==", + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, "license": "MIT", - "dependencies": { - "@jest/environment": "30.2.0", - "@jest/fake-timers": "30.2.0", - "@jest/types": "30.2.0", - "@types/jsdom": "^21.1.7", - "@types/node": "*", - "jest-mock": "30.2.0", - "jest-util": "30.2.0" - }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "peerDependencies": { - "canvas": "^3.0.0", - "jsdom": "*" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } + "node": ">= 8" } }, - "node_modules/@jest/expect": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.2.0.tgz", - "integrity": "sha512-V9yxQK5erfzx99Sf+7LbhBwNWEZ9eZay8qQ9+JSC0TrMR1pMDHLMY+BnVPacWU6Jamrh252/IKo4F1Xn/zfiqA==", + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "license": "MIT", "dependencies": { - "expect": "30.2.0", - "jest-snapshot": "30.2.0" + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">= 8" } }, - "node_modules/@jest/expect-utils": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.2.0.tgz", - "integrity": "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==", + "node_modules/@nolyfill/is-core-module": { + "version": "1.0.39", + "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz", + "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==", "dev": true, "license": "MIT", - "dependencies": { - "@jest/get-type": "30.1.0" - }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=12.4.0" } }, - "node_modules/@jest/fake-timers": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.2.0.tgz", - "integrity": "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw==", + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", "dev": true, + "license": "MIT" + }, + "node_modules/@supabase/auth-js": { + "version": "2.103.3", + "resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.103.3.tgz", + "integrity": "sha512-SMDJ4vg5jLXNEHdhN4J4ujSb203WangbDw1n3VaARH0ZqM51E6lJnoUAHlpQU9N7SzP0hfgghA9IvT8c7tGRfg==", "license": "MIT", "dependencies": { - "@jest/types": "30.2.0", - "@sinonjs/fake-timers": "^13.0.0", - "@types/node": "*", - "jest-message-util": "30.2.0", - "jest-mock": "30.2.0", - "jest-util": "30.2.0" + "tslib": "2.8.1" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@jest/get-type": { - "version": "30.1.0", - "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", - "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=20.0.0" } }, - "node_modules/@jest/globals": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.2.0.tgz", - "integrity": "sha512-b63wmnKPaK+6ZZfpYhz9K61oybvbI1aMcIs80++JI1O1rR1vaxHUCNqo3ITu6NU0d4V34yZFoHMn/uoKr/Rwfw==", - "dev": true, + "node_modules/@supabase/functions-js": { + "version": "2.103.3", + "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.103.3.tgz", + "integrity": "sha512-A2ZHi95GIRRlN9LGOSa/zGEIPg9taR1giDI9Gkfkgrcz0YmKV8ShiAplIrKsHQFdkzKxtsO3maJF0efL+i31mg==", "license": "MIT", "dependencies": { - "@jest/environment": "30.2.0", - "@jest/expect": "30.2.0", - "@jest/types": "30.2.0", - "jest-mock": "30.2.0" + "tslib": "2.8.1" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=20.0.0" } }, - "node_modules/@jest/pattern": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.0.1.tgz", - "integrity": "sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==", - "dev": true, + "node_modules/@supabase/phoenix": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@supabase/phoenix/-/phoenix-0.4.0.tgz", + "integrity": "sha512-RHSx8bHS02xwfHdAbX5Lpbo6PXbgyf7lTaXTlwtFDPwOIw64NnVRwFAXGojHhjtVYI+PEPNSWwkL90f4agN3bw==", + "license": "MIT" + }, + "node_modules/@supabase/postgrest-js": { + "version": "2.103.3", + "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-2.103.3.tgz", + "integrity": "sha512-S0k/9FJVXDeejNfQLCJwRlm4IH8Wet/HEEdBTBpX6/G2o1eU/6CjQop/hJPZIwlQkI6D/zbHH8KymuCsBgy6jA==", "license": "MIT", "dependencies": { - "@types/node": "*", - "jest-regex-util": "30.0.1" + "tslib": "2.8.1" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=20.0.0" } }, - "node_modules/@jest/reporters": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.2.0.tgz", - "integrity": "sha512-DRyW6baWPqKMa9CzeiBjHwjd8XeAyco2Vt8XbcLFjiwCOEKOvy82GJ8QQnJE9ofsxCMPjH4MfH8fCWIHHDKpAQ==", - "dev": true, + "node_modules/@supabase/realtime-js": { + "version": "2.103.3", + "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.103.3.tgz", + "integrity": "sha512-fUvKtSXMUk1BkApVwAurWtHF4Vzbb0UB9aC/fQXrRBek7Ta3Kaora+wHf/fGwFNQs7uRz+mvjIVpzLfpR32VXA==", "license": "MIT", "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "30.2.0", - "@jest/test-result": "30.2.0", - "@jest/transform": "30.2.0", - "@jest/types": "30.2.0", - "@jridgewell/trace-mapping": "^0.3.25", - "@types/node": "*", - "chalk": "^4.1.2", - "collect-v8-coverage": "^1.0.2", - "exit-x": "^0.2.2", - "glob": "^10.3.10", - "graceful-fs": "^4.2.11", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^6.0.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^5.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "30.2.0", - "jest-util": "30.2.0", - "jest-worker": "30.2.0", - "slash": "^3.0.0", - "string-length": "^4.0.2", - "v8-to-istanbul": "^9.0.1" + "@supabase/phoenix": "^0.4.0", + "@types/ws": "^8.18.1", + "tslib": "2.8.1", + "ws": "^8.18.2" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "node": ">=20.0.0" } }, - "node_modules/@jest/schemas": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", - "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", - "dev": true, + "node_modules/@supabase/storage-js": { + "version": "2.103.3", + "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.103.3.tgz", + "integrity": "sha512-5bAIEubrw5keHcdKR2RTois0O1M2Ilx4UYuzOzc07G6mLGCPS/8t1nbC6Vq451pnxR3sK+rmtFHWb9CY/OPjAw==", "license": "MIT", "dependencies": { - "@sinclair/typebox": "^0.34.0" + "iceberg-js": "^0.8.1", + "tslib": "2.8.1" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=20.0.0" } }, - "node_modules/@jest/snapshot-utils": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.2.0.tgz", - "integrity": "sha512-0aVxM3RH6DaiLcjj/b0KrIBZhSX1373Xci4l3cW5xiUWPctZ59zQ7jj4rqcJQ/Z8JuN/4wX3FpJSa3RssVvCug==", - "dev": true, + "node_modules/@supabase/supabase-js": { + "version": "2.103.3", + "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.103.3.tgz", + "integrity": "sha512-DuPiAz5pIJsTAQCt7B6bDZrnLzlq9+/5bta/GWTsgpLn6AkuZQcmYsQHYplv4skQ8U2raKY5HASQOu4KtYq9Qw==", "license": "MIT", "dependencies": { - "@jest/types": "30.2.0", - "chalk": "^4.1.2", - "graceful-fs": "^4.2.11", - "natural-compare": "^1.4.0" + "@supabase/auth-js": "2.103.3", + "@supabase/functions-js": "2.103.3", + "@supabase/postgrest-js": "2.103.3", + "@supabase/realtime-js": "2.103.3", + "@supabase/storage-js": "2.103.3" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=20.0.0" } }, - "node_modules/@jest/source-map": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-30.0.1.tgz", - "integrity": "sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==", - "dev": true, - "license": "MIT", + "node_modules/@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "license": "Apache-2.0", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.25", - "callsites": "^3.1.0", - "graceful-fs": "^4.2.11" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "tslib": "^2.8.0" } }, - "node_modules/@jest/test-result": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.2.0.tgz", - "integrity": "sha512-RF+Z+0CCHkARz5HT9mcQCBulb1wgCP3FBvl9VFokMX27acKphwyQsNuWH3c+ojd1LeWBLoTYoxF0zm6S/66mjg==", + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@jest/console": "30.2.0", - "@jest/types": "30.2.0", - "@types/istanbul-lib-coverage": "^2.0.6", - "collect-v8-coverage": "^1.0.2" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "tslib": "^2.4.0" } }, - "node_modules/@jest/test-sequencer": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.2.0.tgz", - "integrity": "sha512-wXKgU/lk8fKXMu/l5Hog1R61bL4q5GCdT6OJvdAFz1P+QrpoFuLU68eoKuVc4RbrTtNnTL5FByhWdLgOPSph+Q==", + "node_modules/@types/d3": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", + "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==", "dev": true, "license": "MIT", "dependencies": { - "@jest/test-result": "30.2.0", - "graceful-fs": "^4.2.11", - "jest-haste-map": "30.2.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "@types/d3-array": "*", + "@types/d3-axis": "*", + "@types/d3-brush": "*", + "@types/d3-chord": "*", + "@types/d3-color": "*", + "@types/d3-contour": "*", + "@types/d3-delaunay": "*", + "@types/d3-dispatch": "*", + "@types/d3-drag": "*", + "@types/d3-dsv": "*", + "@types/d3-ease": "*", + "@types/d3-fetch": "*", + "@types/d3-force": "*", + "@types/d3-format": "*", + "@types/d3-geo": "*", + "@types/d3-hierarchy": "*", + "@types/d3-interpolate": "*", + "@types/d3-path": "*", + "@types/d3-polygon": "*", + "@types/d3-quadtree": "*", + "@types/d3-random": "*", + "@types/d3-scale": "*", + "@types/d3-scale-chromatic": "*", + "@types/d3-selection": "*", + "@types/d3-shape": "*", + "@types/d3-time": "*", + "@types/d3-time-format": "*", + "@types/d3-timer": "*", + "@types/d3-transition": "*", + "@types/d3-zoom": "*" } }, - "node_modules/@jest/transform": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.2.0.tgz", - "integrity": "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==", + "node_modules/@types/d3-array": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-axis": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz", + "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.27.4", - "@jest/types": "30.2.0", - "@jridgewell/trace-mapping": "^0.3.25", - "babel-plugin-istanbul": "^7.0.1", - "chalk": "^4.1.2", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.11", - "jest-haste-map": "30.2.0", - "jest-regex-util": "30.0.1", - "jest-util": "30.2.0", - "micromatch": "^4.0.8", - "pirates": "^4.0.7", - "slash": "^3.0.0", - "write-file-atomic": "^5.0.1" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "@types/d3-selection": "*" } }, - "node_modules/@jest/types": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz", - "integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==", + "node_modules/@types/d3-brush": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz", + "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==", "dev": true, "license": "MIT", "dependencies": { - "@jest/pattern": "30.0.1", - "@jest/schemas": "30.0.5", - "@types/istanbul-lib-coverage": "^2.0.6", - "@types/istanbul-reports": "^3.0.4", - "@types/node": "*", - "@types/yargs": "^17.0.33", - "chalk": "^4.1.2" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "@types/d3-selection": "*" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "node_modules/@types/d3-chord": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz", + "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-contour": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz", + "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" + "@types/d3-array": "*", + "@types/geojson": "*" } }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "node_modules/@types/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-dispatch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.7.tgz", + "integrity": "sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-drag": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz", + "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" + "@types/d3-selection": "*" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "node_modules/@types/d3-dsv": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", + "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } + "license": "MIT" }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", "dev": true, "license": "MIT" }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "node_modules/@types/d3-fetch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", + "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "@types/d3-dsv": "*" } }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "0.2.12", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", - "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "node_modules/@types/d3-force": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.10.tgz", + "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-format": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz", + "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { - "@emnapi/core": "^1.4.3", - "@emnapi/runtime": "^1.4.3", - "@tybys/wasm-util": "^0.10.0" + "@types/geojson": "*" } }, - "node_modules/@next/env": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.6.tgz", - "integrity": "sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==", + "node_modules/@types/d3-hierarchy": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz", + "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==", + "dev": true, "license": "MIT" }, - "node_modules/@next/eslint-plugin-next": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.1.6.tgz", - "integrity": "sha512-/Qq3PTagA6+nYVfryAtQ7/9FEr/6YVyvOtl6rZnGsbReGLf0jZU6gkpr1FuChAQpvV46a78p4cmHOVP8mbfSMQ==", + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", "dev": true, "license": "MIT", "dependencies": { - "fast-glob": "3.3.1" + "@types/d3-color": "*" } }, - "node_modules/@next/swc-darwin-arm64": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.6.tgz", - "integrity": "sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-darwin-x64": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.6.tgz", - "integrity": "sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-gnu": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.6.tgz", - "integrity": "sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-musl": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.6.tgz", - "integrity": "sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-gnu": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.6.tgz", - "integrity": "sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-musl": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.6.tgz", - "integrity": "sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-arm64-msvc": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.6.tgz", - "integrity": "sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "dev": true, + "license": "MIT" }, - "node_modules/@next/swc-win32-x64-msvc": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.6.tgz", - "integrity": "sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } + "node_modules/@types/d3-polygon": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz", + "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==", + "dev": true, + "license": "MIT" }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "node_modules/@types/d3-quadtree": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz", + "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==", "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } + "license": "MIT" }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "node_modules/@types/d3-random": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz", + "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } + "license": "MIT" }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", "dev": true, "license": "MIT", "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" + "@types/d3-time": "*" } }, - "node_modules/@nolyfill/is-core-module": { - "version": "1.0.39", - "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz", - "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==", + "node_modules/@types/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.4.0" - } + "license": "MIT" }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "node_modules/@types/d3-selection": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz", + "integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==", "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=14" - } + "license": "MIT" }, - "node_modules/@pkgr/core": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", - "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "node_modules/@types/d3-shape": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", + "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", "dev": true, "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/pkgr" + "dependencies": { + "@types/d3-path": "*" } }, - "node_modules/@rtsao/scc": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", - "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", "dev": true, "license": "MIT" }, - "node_modules/@sinclair/typebox": { - "version": "0.34.48", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.48.tgz", - "integrity": "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA==", + "node_modules/@types/d3-time-format": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", + "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==", "dev": true, "license": "MIT" }, - "node_modules/@sinonjs/commons": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "type-detect": "4.0.8" - } + "license": "MIT" }, - "node_modules/@sinonjs/fake-timers": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz", - "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", + "node_modules/@types/d3-transition": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz", + "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", "dependencies": { - "@sinonjs/commons": "^3.0.1" + "@types/d3-selection": "*" } }, - "node_modules/@supabase/auth-js": { - "version": "2.99.3", - "resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.99.3.tgz", - "integrity": "sha512-vMEVLA1kGGYd/kdsJSwtjiFUZM1nGfrz2DWmgMBZtocV48qL+L2+4QpIkueXyBEumMQZFEyhz57i/5zGHjvdBw==", + "node_modules/@types/d3-zoom": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", + "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", + "dev": true, "license": "MIT", "dependencies": { - "tslib": "2.8.1" - }, - "engines": { - "node": ">=20.0.0" + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" } }, - "node_modules/@supabase/functions-js": { - "version": "2.99.3", - "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.99.3.tgz", - "integrity": "sha512-6tk2zrcBkzKaaBXPOG5nshn30uJNFGOH9LxOnE8i850eQmsX+jVm7vql9kTPyvUzEHwU4zdjSOkXS9M+9ukMVA==", + "node_modules/@types/debug": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", + "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", "license": "MIT", "dependencies": { - "tslib": "2.8.1" - }, - "engines": { - "node": ">=20.0.0" + "@types/ms": "*" } }, - "node_modules/@supabase/postgrest-js": { - "version": "2.99.3", - "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-2.99.3.tgz", - "integrity": "sha512-8HxEf+zNycj7Z8+ONhhlu+7J7Ha+L6weyCtdEeK2mN5OWJbh6n4LPU4iuJ5UlCvvNnbSXMoutY7piITEEAgl2g==", + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "license": "MIT" + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", "license": "MIT", "dependencies": { - "tslib": "2.8.1" - }, - "engines": { - "node": ">=20.0.0" + "@types/estree": "*" } }, - "node_modules/@supabase/realtime-js": { - "version": "2.99.3", - "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.99.3.tgz", - "integrity": "sha512-c1azgZ2nZPczbY5k5u5iFrk1InpxN81IvNE+UBAkjrBz3yc5ALLJNkeTQwbJZT4PZBuYXEzqYGLMuh9fdTtTMg==", + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", "license": "MIT", "dependencies": { - "@types/phoenix": "^1.6.6", - "@types/ws": "^8.18.1", - "tslib": "2.8.1", - "ws": "^8.18.2" - }, - "engines": { - "node": ">=20.0.0" + "@types/unist": "*" } }, - "node_modules/@supabase/storage-js": { - "version": "2.99.3", - "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.99.3.tgz", - "integrity": "sha512-lOfIm4hInNcd8x0i1LWphnLKxec42wwbjs+vhaVAvR801Vda0UAMbTooUY6gfqgQb8v29GofqKuQMMTAsl6w/w==", + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/katex": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.8.tgz", + "integrity": "sha512-trgaNyfU+Xh2Tc+ABIb44a5AYUpicB3uwirOioeOkNPPbmgRNtcWyDeeFRzjPZENO9Vq8gvVqfhaaXWLlevVwg==", + "license": "MIT" + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", "license": "MIT", "dependencies": { - "iceberg-js": "^0.8.1", - "tslib": "2.8.1" - }, - "engines": { - "node": ">=20.0.0" + "@types/unist": "*" } }, - "node_modules/@supabase/supabase-js": { - "version": "2.99.3", - "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.99.3.tgz", - "integrity": "sha512-GuPbzoEaI51AkLw9VGhLNvnzw4PHbS3p8j2/JlvLeZNQMKwZw4aEYQIDBRtFwL5Nv7/275n9m4DHtakY8nCvgg==", + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.19.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.39.tgz", + "integrity": "sha512-orrrD74MBUyK8jOAD/r0+lfa1I2MO6I+vAkmAWzMYbCcgrN4lCrmK52gRFQq/JRxfYPfonkr4b0jcY7Olqdqbw==", "license": "MIT", "dependencies": { - "@supabase/auth-js": "2.99.3", - "@supabase/functions-js": "2.99.3", - "@supabase/postgrest-js": "2.99.3", - "@supabase/realtime-js": "2.99.3", - "@supabase/storage-js": "2.99.3" - }, - "engines": { - "node": ">=20.0.0" + "undici-types": "~6.21.0" } }, - "node_modules/@swc/helpers": { - "version": "0.5.15", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", - "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", - "license": "Apache-2.0", + "node_modules/@types/react": { + "version": "19.2.14", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", + "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "license": "MIT", "dependencies": { - "tslib": "^2.8.0" + "csstype": "^3.2.2" } }, - "node_modules/@tailwindcss/node": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.0.tgz", - "integrity": "sha512-Yv+fn/o2OmL5fh/Ir62VXItdShnUxfpkMA4Y7jdeC8O81WPB8Kf6TT6GSHvnqgSwDzlB5iT7kDpeXxLsUS0T6Q==", + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "dev": true, "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "license": "MIT", "dependencies": { - "@jridgewell/remapping": "^2.3.5", - "enhanced-resolve": "^5.19.0", - "jiti": "^2.6.1", - "lightningcss": "1.31.1", - "magic-string": "^0.30.21", - "source-map-js": "^1.2.1", - "tailwindcss": "4.2.0" + "@types/node": "*" } }, - "node_modules/@tailwindcss/oxide": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.0.tgz", - "integrity": "sha512-AZqQzADaj742oqn2xjl5JbIOzZB/DGCYF/7bpvhA8KvjUj9HJkag6bBuwZvH1ps6dfgxNHyuJVlzSr2VpMgdTQ==", + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.58.2.tgz", + "integrity": "sha512-aC2qc5thQahutKjP+cl8cgN9DWe3ZUqVko30CMSZHnFEHyhOYoZSzkGtAI2mcwZ38xeImDucI4dnqsHiOYuuCw==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 20" + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.58.2", + "@typescript-eslint/type-utils": "8.58.2", + "@typescript-eslint/utils": "8.58.2", + "@typescript-eslint/visitor-keys": "8.58.2", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" }, - "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.2.0", - "@tailwindcss/oxide-darwin-arm64": "4.2.0", - "@tailwindcss/oxide-darwin-x64": "4.2.0", - "@tailwindcss/oxide-freebsd-x64": "4.2.0", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.0", - "@tailwindcss/oxide-linux-arm64-gnu": "4.2.0", - "@tailwindcss/oxide-linux-arm64-musl": "4.2.0", - "@tailwindcss/oxide-linux-x64-gnu": "4.2.0", - "@tailwindcss/oxide-linux-x64-musl": "4.2.0", - "@tailwindcss/oxide-wasm32-wasi": "4.2.0", - "@tailwindcss/oxide-win32-arm64-msvc": "4.2.0", - "@tailwindcss/oxide-win32-x64-msvc": "4.2.0" - } - }, - "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.0.tgz", - "integrity": "sha512-F0QkHAVaW/JNBWl4CEKWdZ9PMb0khw5DCELAOnu+RtjAfx5Zgw+gqCHFvqg3AirU1IAd181fwOtJQ5I8Yx5wtw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], "engines": { - "node": ">= 20" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.58.2", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.0.tgz", - "integrity": "sha512-I0QylkXsBsJMZ4nkUNSR04p6+UptjcwhcVo3Zu828ikiEqHjVmQL9RuQ6uT/cVIiKpvtVA25msu/eRV97JeNSA==", - "cpu": [ - "arm64" - ], + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], "engines": { - "node": ">= 20" + "node": ">= 4" } }, - "node_modules/@tailwindcss/oxide-darwin-x64": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.0.tgz", - "integrity": "sha512-6TmQIn4p09PBrmnkvbYQ0wbZhLtbaksCDx7Y7R3FYYx0yxNA7xg5KP7dowmQ3d2JVdabIHvs3Hx4K3d5uCf8xg==", - "cpu": [ - "x64" - ], + "node_modules/@typescript-eslint/parser": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.58.2.tgz", + "integrity": "sha512-/Zb/xaIDfxeJnvishjGdcR4jmr7S+bda8PKNhRGdljDM+elXhlvN0FyPSsMnLmJUrVG9aPO6dof80wjMawsASg==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "dependencies": { + "@typescript-eslint/scope-manager": "8.58.2", + "@typescript-eslint/types": "8.58.2", + "@typescript-eslint/typescript-estree": "8.58.2", + "@typescript-eslint/visitor-keys": "8.58.2", + "debug": "^4.4.3" + }, "engines": { - "node": ">= 20" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@tailwindcss/oxide-freebsd-x64": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.0.tgz", - "integrity": "sha512-qBudxDvAa2QwGlq9y7VIzhTvp2mLJ6nD/G8/tI70DCDoneaUeLWBJaPcbfzqRIWraj+o969aDQKvKW9dvkUizw==", - "cpu": [ - "x64" - ], + "node_modules/@typescript-eslint/project-service": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.58.2.tgz", + "integrity": "sha512-Cq6UfpZZk15+r87BkIh5rDpi38W4b+Sjnb8wQCPPDDweS/LRCFjCyViEbzHk5Ck3f2QDfgmlxqSa7S7clDtlfg==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.58.2", + "@typescript-eslint/types": "^8.58.2", + "debug": "^4.4.3" + }, "engines": { - "node": ">= 20" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.0.tgz", - "integrity": "sha512-7XKkitpy5NIjFZNUQPeUyNJNJn1CJeV7rmMR+exHfTuOsg8rxIO9eNV5TSEnqRcaOK77zQpsyUkBWmPy8FgdSg==", - "cpu": [ - "arm" - ], + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.58.2.tgz", + "integrity": "sha512-SgmyvDPexWETQek+qzZnrG6844IaO02UVyOLhI4wpo82dpZJY9+6YZCKAMFzXb7qhx37mFK1QcPQ18tud+vo6Q==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@typescript-eslint/types": "8.58.2", + "@typescript-eslint/visitor-keys": "8.58.2" + }, "engines": { - "node": ">= 20" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.0.tgz", - "integrity": "sha512-Mff5a5Q3WoQR01pGU1gr29hHM1N93xYrKkGXfPw/aRtK4bOc331Ho4Tgfsm5WDGvpevqMpdlkCojT3qlCQbCpA==", - "cpu": [ - "arm64" - ], + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.58.2.tgz", + "integrity": "sha512-3SR+RukipDvkkKp/d0jP0dyzuls3DbGmwDpVEc5wqk5f38KFThakqAAO0XMirWAE+kT00oTauTbzMFGPoAzB0A==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">= 20" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.0.tgz", - "integrity": "sha512-XKcSStleEVnbH6W/9DHzZv1YhjE4eSS6zOu2eRtYAIh7aV4o3vIBs+t/B15xlqoxt6ef/0uiqJVB6hkHjWD/0A==", - "cpu": [ - "arm64" - ], + "node_modules/@typescript-eslint/type-utils": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.58.2.tgz", + "integrity": "sha512-Z7EloNR/B389FvabdGeTo2XMs4W9TjtPiO9DAsmT0yom0bwlPyRjkJ1uCdW1DvrrrYP50AJZ9Xc3sByZA9+dcg==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@typescript-eslint/types": "8.58.2", + "@typescript-eslint/typescript-estree": "8.58.2", + "@typescript-eslint/utils": "8.58.2", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, "engines": { - "node": ">= 20" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.0.tgz", - "integrity": "sha512-/hlXCBqn9K6fi7eAM0RsobHwJYa5V/xzWspVTzxnX+Ft9v6n+30Pz8+RxCn7sQL/vRHHLS30iQPrHQunu6/vJA==", - "cpu": [ - "x64" - ], + "node_modules/@typescript-eslint/types": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.58.2.tgz", + "integrity": "sha512-9TukXyATBQf/Jq9AMQXfvurk+G5R2MwfqQGDR2GzGz28HvY/lXNKGhkY+6IOubwcquikWk5cjlgPvD2uAA7htQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">= 20" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@tailwindcss/oxide-linux-x64-musl": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.0.tgz", - "integrity": "sha512-lKUaygq4G7sWkhQbfdRRBkaq4LY39IriqBQ+Gk6l5nKq6Ay2M2ZZb1tlIyRNgZKS8cbErTwuYSor0IIULC0SHw==", - "cpu": [ - "x64" - ], + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.58.2.tgz", + "integrity": "sha512-ELGuoofuhhoCvNbQjFFiobFcGgcDCEm0ThWdmO4Z0UzLqPXS3KFvnEZ+SHewwOYHjM09tkzOWXNTv9u6Gqtyuw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-wasm32-wasi": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.0.tgz", - "integrity": "sha512-xuDjhAsFdUuFP5W9Ze4k/o4AskUtI8bcAGU4puTYprr89QaYFmhYOPfP+d1pH+k9ets6RoE23BXZM1X1jJqoyw==", - "bundleDependencies": [ - "@napi-rs/wasm-runtime", - "@emnapi/core", - "@emnapi/runtime", - "@tybys/wasm-util", - "@emnapi/wasi-threads", - "tslib" - ], - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, "dependencies": { - "@emnapi/core": "^1.8.1", - "@emnapi/runtime": "^1.8.1", - "@emnapi/wasi-threads": "^1.1.0", - "@napi-rs/wasm-runtime": "^1.1.1", - "@tybys/wasm-util": "^0.10.1", - "tslib": "^2.8.1" + "@typescript-eslint/project-service": "8.58.2", + "@typescript-eslint/tsconfig-utils": "8.58.2", + "@typescript-eslint/types": "8.58.2", + "@typescript-eslint/visitor-keys": "8.58.2", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" }, "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.0.tgz", - "integrity": "sha512-2UU/15y1sWDEDNJXxEIrfWKC2Yb4YgIW5Xz2fKFqGzFWfoMHWFlfa1EJlGO2Xzjkq/tvSarh9ZTjvbxqWvLLXA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 20" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.0.tgz", - "integrity": "sha512-CrFadmFoc+z76EV6LPG1jx6XceDsaCG3lFhyLNo/bV9ByPrE+FnBPckXQVP4XRkN76h3Fjt/a+5Er/oA/nCBvQ==", - "cpu": [ - "x64" - ], + "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ], "engines": { - "node": ">= 20" + "node": "18 || 20 || >=22" } }, - "node_modules/@tailwindcss/postcss": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.2.0.tgz", - "integrity": "sha512-u6YBacGpOm/ixPfKqfgrJEjMfrYmPD7gEFRoygS/hnQaRtV0VCBdpkx5Ouw9pnaLRwwlgGCuJw8xLpaR0hOrQg==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", "dev": true, "license": "MIT", "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "@tailwindcss/node": "4.2.0", - "@tailwindcss/oxide": "4.2.0", - "postcss": "^8.5.6", - "tailwindcss": "4.2.0" + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" } }, - "node_modules/@testing-library/dom": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", - "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", "dev": true, - "license": "MIT", - "peer": true, + "license": "BlueOak-1.0.0", "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "5.3.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.5.0", - "picocolors": "1.1.1", - "pretty-format": "^27.0.2" + "brace-expansion": "^5.0.5" }, "engines": { - "node": ">=18" + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@testing-library/dom/node_modules/aria-query": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", - "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "dequal": "^2.0.3" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, - "node_modules/@testing-library/jest-dom": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.9.1.tgz", - "integrity": "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==", + "node_modules/@typescript-eslint/utils": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.58.2.tgz", + "integrity": "sha512-QZfjHNEzPY8+l0+fIXMvuQ2sJlplB4zgDZvA+NmvZsZv3EQwOcc1DuIU1VJUTWZ/RKouBMhDyNaBMx4sWvrzRA==", "dev": true, "license": "MIT", "dependencies": { - "@adobe/css-tools": "^4.4.0", - "aria-query": "^5.0.0", - "css.escape": "^1.5.1", - "dom-accessibility-api": "^0.6.3", - "picocolors": "^1.1.1", - "redent": "^3.0.0" + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.58.2", + "@typescript-eslint/types": "8.58.2", + "@typescript-eslint/typescript-estree": "8.58.2" }, "engines": { - "node": ">=14", - "npm": ">=6", - "yarn": ">=1" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", - "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@testing-library/react": { - "version": "16.3.2", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.2.tgz", - "integrity": "sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==", + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.58.2.tgz", + "integrity": "sha512-f1WO2Lx8a9t8DARmcWAUPJbu0G20bJlj8L4z72K00TMeJAoyLr/tHhI/pzYBLrR4dXWkcxO1cWYZEOX8DKHTqA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/runtime": "^7.12.5" + "@typescript-eslint/types": "8.58.2", + "eslint-visitor-keys": "^5.0.0" }, "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" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@testing-library/user-event": { - "version": "14.6.1", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.1.tgz", - "integrity": "sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==", + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "engines": { - "node": ">=12", - "npm": ">=6" + "node": "^20.19.0 || ^22.13.0 || >=24" }, - "peerDependencies": { - "@testing-library/dom": ">=7.21.4" + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@tybys/wasm-util": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", - "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "license": "ISC" + }, + "node_modules/@unrs/resolver-binding-android-arm-eabi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", + "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } + "os": [ + "android" + ] }, - "node_modules/@types/aria-query": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", - "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "node_modules/@unrs/resolver-binding-android-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz", + "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "peer": true + "optional": true, + "os": [ + "android" + ] }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "node_modules/@unrs/resolver-binding-darwin-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz", + "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@types/babel__generator": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", - "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz", + "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/types": "^7.0.0" - } + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz", + "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } + "optional": true, + "os": [ + "freebsd" + ] }, - "node_modules/@types/babel__traverse": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", - "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz", + "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.2" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@types/d3": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", - "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==", + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz", + "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", - "dependencies": { - "@types/d3-array": "*", - "@types/d3-axis": "*", - "@types/d3-brush": "*", - "@types/d3-chord": "*", - "@types/d3-color": "*", - "@types/d3-contour": "*", - "@types/d3-delaunay": "*", - "@types/d3-dispatch": "*", - "@types/d3-drag": "*", - "@types/d3-dsv": "*", - "@types/d3-ease": "*", - "@types/d3-fetch": "*", - "@types/d3-force": "*", - "@types/d3-format": "*", - "@types/d3-geo": "*", - "@types/d3-hierarchy": "*", - "@types/d3-interpolate": "*", - "@types/d3-path": "*", - "@types/d3-polygon": "*", - "@types/d3-quadtree": "*", - "@types/d3-random": "*", - "@types/d3-scale": "*", - "@types/d3-scale-chromatic": "*", - "@types/d3-selection": "*", - "@types/d3-shape": "*", - "@types/d3-time": "*", - "@types/d3-time-format": "*", - "@types/d3-timer": "*", - "@types/d3-transition": "*", - "@types/d3-zoom": "*" - } - }, - "node_modules/@types/d3-array": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", - "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", - "dev": true, - "license": "MIT" + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@types/d3-axis": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz", - "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==", + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz", + "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@types/d3-selection": "*" - } - }, - "node_modules/@types/d3-brush": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz", - "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/d3-selection": "*" - } - }, - "node_modules/@types/d3-chord": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz", - "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/d3-color": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", - "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", - "dev": true, - "license": "MIT" + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@types/d3-contour": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz", - "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==", + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz", + "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@types/d3-array": "*", - "@types/geojson": "*" - } - }, - "node_modules/@types/d3-delaunay": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", - "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/d3-dispatch": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.7.tgz", - "integrity": "sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==", - "dev": true, - "license": "MIT" + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@types/d3-drag": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz", - "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz", + "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==", + "cpu": [ + "ppc64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@types/d3-selection": "*" - } - }, - "node_modules/@types/d3-dsv": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", - "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/d3-ease": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", - "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", - "dev": true, - "license": "MIT" + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@types/d3-fetch": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", - "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz", + "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==", + "cpu": [ + "riscv64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@types/d3-dsv": "*" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@types/d3-force": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.10.tgz", - "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==", + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz", + "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==", + "cpu": [ + "riscv64" + ], "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@types/d3-format": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz", - "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==", + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz", + "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==", + "cpu": [ + "s390x" + ], "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@types/d3-geo": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", - "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz", + "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@types/geojson": "*" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@types/d3-hierarchy": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz", - "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==", + "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz", + "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@types/d3-interpolate": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", - "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "node_modules/@unrs/resolver-binding-wasm32-wasi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz", + "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==", + "cpu": [ + "wasm32" + ], "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@types/d3-color": "*" + "@napi-rs/wasm-runtime": "^0.2.11" + }, + "engines": { + "node": ">=14.0.0" } }, - "node_modules/@types/d3-path": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", - "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/d3-polygon": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz", - "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/d3-quadtree": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz", - "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/d3-random": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz", - "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==", + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz", + "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/@types/d3-scale": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", - "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz", + "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==", + "cpu": [ + "ia32" + ], "dev": true, "license": "MIT", - "dependencies": { - "@types/d3-time": "*" - } + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/@types/d3-scale-chromatic": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", - "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/d3-selection": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz", - "integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/d3-shape": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", - "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/d3-path": "*" - } - }, - "node_modules/@types/d3-time": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", - "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/d3-time-format": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", - "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/d3-timer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", - "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/d3-transition": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz", - "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/d3-selection": "*" - } - }, - "node_modules/@types/d3-zoom": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", - "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/d3-interpolate": "*", - "@types/d3-selection": "*" - } - }, - "node_modules/@types/debug": { - "version": "4.1.12", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", - "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", - "license": "MIT", - "dependencies": { - "@types/ms": "*" - } - }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "license": "MIT" - }, - "node_modules/@types/estree-jsx": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", - "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", - "license": "MIT", - "dependencies": { - "@types/estree": "*" - } - }, - "node_modules/@types/geojson": { - "version": "7946.0.16", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", - "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "license": "MIT", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", - "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", - "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", - "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/jest": { - "version": "30.0.0", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-30.0.0.tgz", - "integrity": "sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==", - "dev": true, - "license": "MIT", - "dependencies": { - "expect": "^30.0.0", - "pretty-format": "^30.0.0" - } - }, - "node_modules/@types/jest/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@types/jest/node_modules/pretty-format": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", - "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/schemas": "30.0.5", - "ansi-styles": "^5.2.0", - "react-is": "^18.3.1" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@types/jest/node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/jsdom": { - "version": "21.1.7", - "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-21.1.7.tgz", - "integrity": "sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "@types/tough-cookie": "*", - "parse5": "^7.0.0" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/katex": { - "version": "0.16.8", - "resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.8.tgz", - "integrity": "sha512-trgaNyfU+Xh2Tc+ABIb44a5AYUpicB3uwirOioeOkNPPbmgRNtcWyDeeFRzjPZENO9Vq8gvVqfhaaXWLlevVwg==", - "license": "MIT" - }, - "node_modules/@types/mdast": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", - "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", - "license": "MIT", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/@types/ms": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", - "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "20.19.33", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.33.tgz", - "integrity": "sha512-Rs1bVAIdBs5gbTIKza/tgpMuG1k3U/UMJLWecIMxNdJFDMzcM5LOiLVRYh3PilWEYDIeUDv7bpiHPLPsbydGcw==", - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/@types/phoenix": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.7.tgz", - "integrity": "sha512-oN9ive//QSBkf19rfDv45M7eZPi0eEXylht2OLEXicu5b4KoQ1OzXIw+xDSGWxSxe1JmepRR/ZH283vsu518/Q==", - "license": "MIT" - }, - "node_modules/@types/react": { - "version": "19.2.14", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", - "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", - "license": "MIT", - "dependencies": { - "csstype": "^3.2.2" - } - }, - "node_modules/@types/react-dom": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", - "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@types/react": "^19.2.0" - } - }, - "node_modules/@types/stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/tough-cookie": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", - "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "license": "MIT" - }, - "node_modules/@types/ws": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", - "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/yargs": { - "version": "17.0.35", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", - "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", - "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.0.tgz", - "integrity": "sha512-lRyPDLzNCuae71A3t9NEINBiTn7swyOhvUj3MyUOxb8x6g6vPEFoOU+ZRmGMusNC3X3YMhqMIX7i8ShqhT74Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.56.0", - "@typescript-eslint/type-utils": "8.56.0", - "@typescript-eslint/utils": "8.56.0", - "@typescript-eslint/visitor-keys": "8.56.0", - "ignore": "^7.0.5", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.4.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.56.0", - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.0.tgz", - "integrity": "sha512-IgSWvLobTDOjnaxAfDTIHaECbkNlAlKv2j5SjpB2v7QHKv1FIfjwMy8FsDbVfDX/KjmCmYICcw7uGaXLhtsLNg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/scope-manager": "8.56.0", - "@typescript-eslint/types": "8.56.0", - "@typescript-eslint/typescript-estree": "8.56.0", - "@typescript-eslint/visitor-keys": "8.56.0", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/project-service": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.0.tgz", - "integrity": "sha512-M3rnyL1vIQOMeWxTWIW096/TtVP+8W3p/XnaFflhmcFp+U4zlxUxWj4XwNs6HbDeTtN4yun0GNTTDBw/SvufKg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.56.0", - "@typescript-eslint/types": "^8.56.0", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.0.tgz", - "integrity": "sha512-7UiO/XwMHquH+ZzfVCfUNkIXlp/yQjjnlYUyYz7pfvlK3/EyyN6BK+emDmGNyQLBtLGaYrTAI6KOw8tFucWL2w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.56.0", - "@typescript-eslint/visitor-keys": "8.56.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.0.tgz", - "integrity": "sha512-bSJoIIt4o3lKXD3xmDh9chZcjCz5Lk8xS7Rxn+6l5/pKrDpkCwtQNQQwZ2qRPk7TkUYhrq3WPIHXOXlbXP0itg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.0.tgz", - "integrity": "sha512-qX2L3HWOU2nuDs6GzglBeuFXviDODreS58tLY/BALPC7iu3Fa+J7EOTwnX9PdNBxUI7Uh0ntP0YWGnxCkXzmfA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.56.0", - "@typescript-eslint/typescript-estree": "8.56.0", - "@typescript-eslint/utils": "8.56.0", - "debug": "^4.4.3", - "ts-api-utils": "^2.4.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.0.tgz", - "integrity": "sha512-DBsLPs3GsWhX5HylbP9HNG15U0bnwut55Lx12bHB9MpXxQ+R5GC8MwQe+N1UFXxAeQDvEsEDY6ZYwX03K7Z6HQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.0.tgz", - "integrity": "sha512-ex1nTUMWrseMltXUHmR2GAQ4d+WjkZCT4f+4bVsps8QEdh0vlBsaCokKTPlnqBFqqGaxilDNJG7b8dolW2m43Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.56.0", - "@typescript-eslint/tsconfig-utils": "8.56.0", - "@typescript-eslint/types": "8.56.0", - "@typescript-eslint/visitor-keys": "8.56.0", - "debug": "^4.4.3", - "minimatch": "^9.0.5", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.4.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.0.tgz", - "integrity": "sha512-RZ3Qsmi2nFGsS+n+kjLAYDPVlrzf7UhTffrDIKr+h2yzAlYP/y5ZulU0yeDEPItos2Ph46JAL5P/On3pe7kDIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.56.0", - "@typescript-eslint/types": "8.56.0", - "@typescript-eslint/typescript-estree": "8.56.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.0.tgz", - "integrity": "sha512-q+SL+b+05Ud6LbEE35qe4A99P+htKTKVbyiNEe45eCbJFyh/HVK9QXwlrbz+Q4L8SOW4roxSVwXYj4DMBT7Ieg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.56.0", - "eslint-visitor-keys": "^5.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", - "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@ungap/structured-clone": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", - "license": "ISC" - }, - "node_modules/@unrs/resolver-binding-android-arm-eabi": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", - "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@unrs/resolver-binding-android-arm64": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz", - "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@unrs/resolver-binding-darwin-arm64": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz", - "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@unrs/resolver-binding-darwin-x64": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz", - "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@unrs/resolver-binding-freebsd-x64": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz", - "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz", - "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz", - "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz", - "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-arm64-musl": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz", - "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz", - "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz", - "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz", - "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz", - "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-x64-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz", - "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-x64-musl": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz", - "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-wasm32-wasi": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz", - "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==", - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@napi-rs/wasm-runtime": "^0.2.11" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz", - "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz", - "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@unrs/resolver-binding-win32-x64-msvc": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz", - "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/acorn": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", - "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/aria-query": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", - "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", - "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "is-array-buffer": "^3.0.5" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-includes": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", - "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.24.0", - "es-object-atoms": "^1.1.1", - "get-intrinsic": "^1.3.0", - "is-string": "^1.1.1", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.findlast": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", - "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.findlastindex": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", - "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.9", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "es-shim-unscopables": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", - "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", - "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.tosorted": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", - "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.3", - "es-errors": "^1.3.0", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", - "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "is-array-buffer": "^3.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/ast-types-flow": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", - "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/async-function": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", - "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/axe-core": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.11.1.tgz", - "integrity": "sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A==", - "dev": true, - "license": "MPL-2.0", - "engines": { - "node": ">=4" - } - }, - "node_modules/axobject-query": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", - "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/babel-jest": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.2.0.tgz", - "integrity": "sha512-0YiBEOxWqKkSQWL9nNGGEgndoeL0ZpWrbLMNL5u/Kaxrli3Eaxlt3ZtIDktEvXt4L/R9r3ODr2zKwGM/2BjxVw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/transform": "30.2.0", - "@types/babel__core": "^7.20.5", - "babel-plugin-istanbul": "^7.0.1", - "babel-preset-jest": "30.2.0", - "chalk": "^4.1.2", - "graceful-fs": "^4.2.11", - "slash": "^3.0.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.11.0 || ^8.0.0-0" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz", - "integrity": "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==", - "dev": true, - "license": "BSD-3-Clause", - "workspaces": [ - "test/babel-8" - ], - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.3", - "istanbul-lib-instrument": "^6.0.2", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/babel-plugin-jest-hoist": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.2.0.tgz", - "integrity": "sha512-ftzhzSGMUnOzcCXd6WHdBGMyuwy15Wnn0iyyWGKgBDLxf9/s5ABuraCSpBX2uG0jUg4rqJnxsLc5+oYBqoxVaA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/babel__core": "^7.20.5" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/babel-plugin-react-compiler": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-react-compiler/-/babel-plugin-react-compiler-1.0.0.tgz", - "integrity": "sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.26.0" - } - }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", - "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-import-attributes": "^7.24.7", - "@babel/plugin-syntax-import-meta": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5" - }, - "peerDependencies": { - "@babel/core": "^7.0.0 || ^8.0.0-0" - } - }, - "node_modules/babel-preset-jest": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.2.0.tgz", - "integrity": "sha512-US4Z3NOieAQumwFnYdUWKvUKh8+YSnS/gB3t6YBiz0bskpu7Pine8pPCheNxlPEW4wnUkma2a94YuW2q3guvCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "babel-plugin-jest-hoist": "30.2.0", - "babel-preset-current-node-syntax": "^1.2.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.11.0 || ^8.0.0-beta.1" - } - }, - "node_modules/bail": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", - "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/baseline-browser-mapping": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", - "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.cjs" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.28.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", - "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "baseline-browser-mapping": "^2.9.0", - "caniuse-lite": "^1.0.30001759", - "electron-to-chromium": "^1.5.263", - "node-releases": "^2.0.27", - "update-browserslist-db": "^1.2.0" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-json-stable-stringify": "2.x" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "node-int64": "^0.4.0" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/call-bind": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", - "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.0", - "es-define-property": "^1.0.0", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001770", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001770.tgz", - "integrity": "sha512-x/2CLQ1jHENRbHg5PSId2sXq1CIO1CISvwWAj027ltMVG2UNgW+w9oH2+HzgEIRFembL8bUlXtfbBHR1fCg2xw==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/ccount": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", - "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/character-entities": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", - "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/character-entities-html4": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", - "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/character-entities-legacy": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", - "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/character-reference-invalid": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", - "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/ci-info": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", - "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/cjs-module-lexer": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.2.0.tgz", - "integrity": "sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/client-only": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", - "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", - "license": "MIT" - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/cliui/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/cliui/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/collect-v8-coverage": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", - "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", - "dev": true, - "license": "MIT" - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/comma-separated-tokens": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", - "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "license": "MIT", - "engines": { - "node": ">= 10" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/css.escape": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", - "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", - "dev": true, - "license": "MIT" - }, - "node_modules/cssstyle": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.6.0.tgz", - "integrity": "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@asamuzakjp/css-color": "^3.2.0", - "rrweb-cssom": "^0.8.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "license": "MIT" - }, - "node_modules/d3": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", - "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==", - "license": "ISC", - "dependencies": { - "d3-array": "3", - "d3-axis": "3", - "d3-brush": "3", - "d3-chord": "3", - "d3-color": "3", - "d3-contour": "4", - "d3-delaunay": "6", - "d3-dispatch": "3", - "d3-drag": "3", - "d3-dsv": "3", - "d3-ease": "3", - "d3-fetch": "3", - "d3-force": "3", - "d3-format": "3", - "d3-geo": "3", - "d3-hierarchy": "3", - "d3-interpolate": "3", - "d3-path": "3", - "d3-polygon": "3", - "d3-quadtree": "3", - "d3-random": "3", - "d3-scale": "4", - "d3-scale-chromatic": "3", - "d3-selection": "3", - "d3-shape": "3", - "d3-time": "3", - "d3-time-format": "4", - "d3-timer": "3", - "d3-transition": "3", - "d3-zoom": "3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-array": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", - "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", - "license": "ISC", - "dependencies": { - "internmap": "1 - 2" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-axis": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", - "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-brush": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", - "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", - "license": "ISC", - "dependencies": { - "d3-dispatch": "1 - 3", - "d3-drag": "2 - 3", - "d3-interpolate": "1 - 3", - "d3-selection": "3", - "d3-transition": "3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-chord": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", - "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", - "license": "ISC", - "dependencies": { - "d3-path": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-color": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", - "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-contour": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", - "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", - "license": "ISC", - "dependencies": { - "d3-array": "^3.2.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-delaunay": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", - "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", - "license": "ISC", - "dependencies": { - "delaunator": "5" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-dispatch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", - "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-drag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", - "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", - "license": "ISC", - "dependencies": { - "d3-dispatch": "1 - 3", - "d3-selection": "3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-dsv": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", - "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", - "license": "ISC", - "dependencies": { - "commander": "7", - "iconv-lite": "0.6", - "rw": "1" - }, - "bin": { - "csv2json": "bin/dsv2json.js", - "csv2tsv": "bin/dsv2dsv.js", - "dsv2dsv": "bin/dsv2dsv.js", - "dsv2json": "bin/dsv2json.js", - "json2csv": "bin/json2dsv.js", - "json2dsv": "bin/json2dsv.js", - "json2tsv": "bin/json2dsv.js", - "tsv2csv": "bin/dsv2dsv.js", - "tsv2json": "bin/dsv2json.js" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-ease": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", - "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-fetch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", - "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", - "license": "ISC", - "dependencies": { - "d3-dsv": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-force": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", - "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", - "license": "ISC", - "dependencies": { - "d3-dispatch": "1 - 3", - "d3-quadtree": "1 - 3", - "d3-timer": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-format": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", - "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-geo": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", - "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", - "license": "ISC", - "dependencies": { - "d3-array": "2.5.0 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-hierarchy": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", - "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-interpolate": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", - "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", - "license": "ISC", - "dependencies": { - "d3-color": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-path": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", - "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-polygon": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", - "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-quadtree": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", - "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-random": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", - "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-scale": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", - "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", - "license": "ISC", - "dependencies": { - "d3-array": "2.10.0 - 3", - "d3-format": "1 - 3", - "d3-interpolate": "1.2.0 - 3", - "d3-time": "2.1.1 - 3", - "d3-time-format": "2 - 4" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-scale-chromatic": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", - "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", - "license": "ISC", - "dependencies": { - "d3-color": "1 - 3", - "d3-interpolate": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-selection": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", - "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-shape": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", - "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", - "license": "ISC", - "dependencies": { - "d3-path": "^3.1.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-time": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", - "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", - "license": "ISC", - "dependencies": { - "d3-array": "2 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-time-format": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", - "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", - "license": "ISC", - "dependencies": { - "d3-time": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-timer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", - "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-transition": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", - "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", - "license": "ISC", - "dependencies": { - "d3-color": "1 - 3", - "d3-dispatch": "1 - 3", - "d3-ease": "1 - 3", - "d3-interpolate": "1 - 3", - "d3-timer": "1 - 3" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "d3-selection": "2 - 3" - } + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz", + "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/d3-zoom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", - "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", - "license": "ISC", - "dependencies": { - "d3-dispatch": "1 - 3", - "d3-drag": "2 - 3", - "d3-interpolate": "1 - 3", - "d3-selection": "2 - 3", - "d3-transition": "2 - 3" + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" }, "engines": { - "node": ">=12" + "node": ">=0.4.0" } }, - "node_modules/damerau-levenshtein": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", - "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, - "license": "BSD-2-Clause" + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } }, - "node_modules/data-urls": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", - "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "dev": true, "license": "MIT", "dependencies": { - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^14.0.0" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" }, - "engines": { - "node": ">=18" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/data-view-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", - "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" + "color-convert": "^2.0.1" }, "engines": { - "node": ">= 0.4" + "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/data-view-byte-length": { + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/array-buffer-byte-length": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", - "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" + "is-array-buffer": "^3.0.5" }, "engines": { "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/inspect-js" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/data-view-byte-offset": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", - "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "node_modules/array-includes": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", + "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "get-intrinsic": "^1.3.0", + "is-string": "^1.1.1", + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -5323,85 +2430,41 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, "license": "MIT", "dependencies": { - "ms": "^2.1.3" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decimal.js": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", - "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", - "dev": true, - "license": "MIT" - }, - "node_modules/decode-named-character-reference": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", - "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", - "license": "MIT", - "dependencies": { - "character-entities": "^2.0.0" + "node": ">= 0.4" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/dedent": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.1.tgz", - "integrity": "sha512-9JmrhGZpOlEgOLdQgSm0zxFaYoQon408V1v49aqTWuXENVlnCuY9JBZcXZiCsZQWDjTm5Qf/nIvAy77mXDAjEg==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "babel-plugin-macros": "^3.1.0" - }, - "peerDependenciesMeta": { - "babel-plugin-macros": { - "optional": true - } - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "node_modules/array.prototype.findlastindex": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", + "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", "dev": true, "license": "MIT", "dependencies": { - "es-define-property": "^1.0.0", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", "es-errors": "^1.3.0", - "gopd": "^1.0.1" + "es-object-atoms": "^1.1.1", + "es-shim-unscopables": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -5410,16 +2473,17 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "node_modules/array.prototype.flat": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", "dev": true, "license": "MIT", "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -5428,332 +2492,246 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/delaunator": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", - "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", - "license": "ISC", - "dependencies": { - "robust-predicates": "^3.0.2" - } - }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "devOptional": true, - "license": "Apache-2.0", - "engines": { - "node": ">=8" - } - }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", "dev": true, "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/devlop": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", - "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", - "license": "MIT", "dependencies": { - "dequal": "^2.0.0" + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "esutils": "^2.0.2" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" } }, - "node_modules/dom-accessibility-api": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", - "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.1", + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", "es-errors": "^1.3.0", - "gopd": "^1.2.0" + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "node_modules/ast-types-flow": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", "dev": true, "license": "MIT" }, - "node_modules/electron-to-chromium": { - "version": "1.5.302", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.302.tgz", - "integrity": "sha512-sM6HAN2LyK82IyPBpznDRqlTQAtuSaO+ShzFiWTvoMJLHyZ+Y39r8VMfHzwbU8MVBzQ4Wdn85+wlZl2TLGIlwg==", - "dev": true, - "license": "ISC" - }, - "node_modules/emittery": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", - "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", "dev": true, "license": "MIT", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" + "node": ">= 0.4" } }, - "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, - "license": "MIT" - }, - "node_modules/enhanced-resolve": { - "version": "5.19.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz", - "integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==", + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", "dev": true, "license": "MIT", "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.3.0" + "possible-typed-array-names": "^1.0.0" }, "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/error-ex": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", - "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "node_modules/axe-core": { + "version": "4.11.3", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.11.3.tgz", + "integrity": "sha512-zBQouZixDTbo3jMGqHKyePxYxr1e5W8UdTmBQ7sNtaA9M2bE32daxxPLS/jojhKOHxQ7LWwPjfiwf/fhaJWzlg==", "dev": true, - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.2.1" + "license": "MPL-2.0", + "engines": { + "node": ">=4" } }, - "node_modules/es-abstract": { - "version": "1.24.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz", - "integrity": "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==", + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", "dev": true, - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.2", - "arraybuffer.prototype.slice": "^1.0.4", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "data-view-buffer": "^1.0.2", - "data-view-byte-length": "^1.0.2", - "data-view-byte-offset": "^1.0.1", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "es-set-tostringtag": "^2.1.0", - "es-to-primitive": "^1.3.0", - "function.prototype.name": "^1.1.8", - "get-intrinsic": "^1.3.0", - "get-proto": "^1.0.1", - "get-symbol-description": "^1.1.0", - "globalthis": "^1.0.4", - "gopd": "^1.2.0", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "internal-slot": "^1.1.0", - "is-array-buffer": "^3.0.5", - "is-callable": "^1.2.7", - "is-data-view": "^1.0.2", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.2.1", - "is-set": "^2.0.3", - "is-shared-array-buffer": "^1.0.4", - "is-string": "^1.1.1", - "is-typed-array": "^1.1.15", - "is-weakref": "^1.1.1", - "math-intrinsics": "^1.1.0", - "object-inspect": "^1.13.4", - "object-keys": "^1.1.1", - "object.assign": "^4.1.7", - "own-keys": "^1.0.1", - "regexp.prototype.flags": "^1.5.4", - "safe-array-concat": "^1.1.3", - "safe-push-apply": "^1.0.0", - "safe-regex-test": "^1.1.0", - "set-proto": "^1.0.0", - "stop-iteration-iterator": "^1.1.0", - "string.prototype.trim": "^1.2.10", - "string.prototype.trimend": "^1.0.9", - "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.3", - "typed-array-byte-length": "^1.0.3", - "typed-array-byte-offset": "^1.0.4", - "typed-array-length": "^1.0.7", - "unbox-primitive": "^1.1.0", - "which-typed-array": "^1.1.19" - }, + "license": "Apache-2.0", "engines": { "node": ">= 0.4" - }, + } + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true, - "license": "MIT", + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.20", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.20.tgz", + "integrity": "sha512-1AaXxEPfXT+GvTBJFuy4yXVHWJBXa4OdbIebGN/wX5DlsIkU0+wzGnd2lOzokSk51d5LUmqjgBLRLlypLUqInQ==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, "engines": { - "node": ">= 0.4" + "node": ">=6.0.0" } }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 0.4" + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/es-iterator-helpers": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.2.tgz", - "integrity": "sha512-BrUQ0cPTB/IwXj23HtwHjS9n7O4h9FX94b4xc5zlTHxeLgTAdzYUDyy6KdExAl9lbN5rtfe44xpjpmj9grxs5w==", + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.24.1", - "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.1.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.3.0", - "globalthis": "^1.0.4", - "gopd": "^1.2.0", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.2.0", - "has-symbols": "^1.1.0", - "internal-slot": "^1.1.0", - "iterator.prototype": "^1.1.5", - "safe-array-concat": "^1.1.3" + "fill-range": "^7.1.1" }, "engines": { - "node": ">= 0.4" + "node": ">=8" } }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "node_modules/browserslist": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", "dependencies": { - "es-errors": "^1.3.0" + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" }, "engines": { - "node": ">= 0.4" + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "node_modules/call-bind": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", + "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", "dev": true, "license": "MIT", "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "get-intrinsic": "^1.3.0", + "set-function-length": "^1.2.2" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/es-shim-unscopables": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", - "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "dev": true, "license": "MIT", "dependencies": { - "hasown": "^2.0.2" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" }, "engines": { "node": ">= 0.4" } }, - "node_modules/es-to-primitive": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", - "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "dev": true, "license": "MIT", "dependencies": { - "is-callable": "^1.2.7", - "is-date-object": "^1.0.5", - "is-symbol": "^1.0.4" + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" }, "engines": { "node": ">= 0.4" @@ -5762,853 +2740,601 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, "license": "MIT", "engines": { "node": ">=6" } }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, + "node_modules/caniuse-lite": { + "version": "1.0.30001788", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001788.tgz", + "integrity": "sha512-6q8HFp+lOQtcf7wBK+uEenxymVWkGKkjFpCvw5W25cmMwEDU45p1xQFBQv8JDlMMry7eNxyBaR+qxgmTUZkIRQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", "license": "MIT", - "engines": { - "node": ">=10" - }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/eslint": { - "version": "9.39.3", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.3.tgz", - "integrity": "sha512-VmQ+sifHUbI/IcSopBCF/HO3YiHQx/AVd3UVyYL6weuwW+HvON9VYn5l6Zl1WZzPWXPNZrSQpxwkkZ/VuvJZzg==", + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.1", - "@eslint/config-helpers": "^0.4.2", - "@eslint/core": "^0.17.0", - "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.39.3", - "@eslint/plugin-kit": "^0.4.1", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.4.0", - "eslint-visitor-keys": "^4.2.1", - "espree": "^10.4.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, - "bin": { - "eslint": "bin/eslint.js" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=10" }, "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "node_modules/eslint-config-next": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.1.6.tgz", - "integrity": "sha512-vKq40io2B0XtkkNDYyleATwblNt8xuh3FWp8SpSz3pt7P01OkBFlKsJZ2mWt5WsCySlDQLckb1zMY9yE9Qy0LA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@next/eslint-plugin-next": "16.1.6", - "eslint-import-resolver-node": "^0.3.6", - "eslint-import-resolver-typescript": "^3.5.2", - "eslint-plugin-import": "^2.32.0", - "eslint-plugin-jsx-a11y": "^6.10.0", - "eslint-plugin-react": "^7.37.0", - "eslint-plugin-react-hooks": "^7.0.0", - "globals": "16.4.0", - "typescript-eslint": "^8.46.0" - }, - "peerDependencies": { - "eslint": ">=9.0.0", - "typescript": ">=3.3.1" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/eslint-config-next/node_modules/globals": { - "version": "16.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz", - "integrity": "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==", - "dev": true, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", "license": "MIT", - "engines": { - "node": ">=18" - }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", - "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", - "dev": true, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", "license": "MIT", - "dependencies": { - "debug": "^3.2.7", - "is-core-module": "^2.13.0", - "resolve": "^1.22.4" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", "license": "MIT", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-import-resolver-typescript": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz", - "integrity": "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "@nolyfill/is-core-module": "1.0.39", - "debug": "^4.4.0", - "get-tsconfig": "^4.10.0", - "is-bun-module": "^2.0.0", - "stable-hash": "^0.0.5", - "tinyglobby": "^0.2.13", - "unrs-resolver": "^1.6.2" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, "funding": { - "url": "https://opencollective.com/eslint-import-resolver-typescript" - }, - "peerDependencies": { - "eslint": "*", - "eslint-plugin-import": "*", - "eslint-plugin-import-x": "*" - }, - "peerDependenciesMeta": { - "eslint-plugin-import": { - "optional": true - }, - "eslint-plugin-import-x": { - "optional": true - } + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/eslint-module-utils": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz", - "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==", - "dev": true, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", "license": "MIT", - "dependencies": { - "debug": "^3.2.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" - } + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" }, - "node_modules/eslint-plugin-import": { - "version": "2.32.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", - "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "license": "MIT", "dependencies": { - "@rtsao/scc": "^1.1.0", - "array-includes": "^3.1.9", - "array.prototype.findlastindex": "^1.2.6", - "array.prototype.flat": "^1.3.3", - "array.prototype.flatmap": "^1.3.3", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.12.1", - "hasown": "^2.0.2", - "is-core-module": "^2.16.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.8", - "object.groupby": "^1.0.3", - "object.values": "^1.2.1", - "semver": "^6.3.1", - "string.prototype.trimend": "^1.0.9", - "tsconfig-paths": "^3.15.0" + "color-name": "~1.1.4" }, "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" + "node": ">=7.0.0" } }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true, + "license": "MIT" + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", "license": "MIT", - "dependencies": { - "ms": "^2.1.1" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/eslint-plugin-jsx-a11y": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz", - "integrity": "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==", - "dev": true, + "node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", "license": "MIT", - "dependencies": { - "aria-query": "^5.3.2", - "array-includes": "^3.1.8", - "array.prototype.flatmap": "^1.3.2", - "ast-types-flow": "^0.0.8", - "axe-core": "^4.10.0", - "axobject-query": "^4.1.0", - "damerau-levenshtein": "^1.0.8", - "emoji-regex": "^9.2.2", - "hasown": "^2.0.2", - "jsx-ast-utils": "^3.3.5", - "language-tags": "^1.0.9", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.8", - "safe-regex-test": "^1.0.3", - "string.prototype.includes": "^2.0.1" - }, "engines": { - "node": ">=4.0" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" + "node": ">= 10" } }, - "node_modules/eslint-plugin-react": { - "version": "7.37.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", - "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true, - "license": "MIT", - "dependencies": { - "array-includes": "^3.1.8", - "array.prototype.findlast": "^1.2.5", - "array.prototype.flatmap": "^1.3.3", - "array.prototype.tosorted": "^1.1.4", - "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.2.1", - "estraverse": "^5.3.0", - "hasown": "^2.0.2", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.9", - "object.fromentries": "^2.0.8", - "object.values": "^1.2.1", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.5", - "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.12", - "string.prototype.repeat": "^1.0.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" - } + "license": "MIT" }, - "node_modules/eslint-plugin-react-hooks": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.1.tgz", - "integrity": "sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==", + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.24.4", - "@babel/parser": "^7.24.4", - "hermes-parser": "^0.25.1", - "zod": "^3.25.0 || ^4.0.0", - "zod-validation-error": "^3.5.0 || ^4.0.0" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" }, "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" + "node": ">= 8" } }, - "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.6", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.6.tgz", - "integrity": "sha512-3JmVl5hMGtJ3kMmB3zi3DL25KfkCEyy3Tw7Gmw7z5w8M9WlwoPFnIvwChzu1+cF3iaK3sp18hhPz8ANeimdJfA==", - "dev": true, - "license": "MIT", + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/d3": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", + "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==", + "license": "ISC", "dependencies": { - "es-errors": "^1.3.0", - "is-core-module": "^2.16.1", - "node-exports-info": "^1.6.0", - "object-keys": "^1.1.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=12" } }, - "node_modules/eslint-scope": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", - "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "internmap": "1 - 2" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=12" } }, - "node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "dev": true, - "license": "Apache-2.0", + "node_modules/d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "license": "ISC", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=12" } }, - "node_modules/espree": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "license": "ISC", "dependencies": { - "acorn": "^8.15.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.1" + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=12" } }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" + "node_modules/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "license": "ISC", + "dependencies": { + "d3-path": "1 - 3" }, "engines": { - "node": ">=4" + "node": ">=12" } }, - "node_modules/esquery": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", - "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-contour": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", + "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "license": "ISC", "dependencies": { - "estraverse": "^5.1.0" + "d3-array": "^3.2.0" }, "engines": { - "node": ">=0.10" + "node": ">=12" } }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "license": "ISC", "dependencies": { - "estraverse": "^5.2.0" + "delaunator": "5" }, "engines": { - "node": ">=4.0" + "node": ">=12" } }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "license": "ISC", "engines": { - "node": ">=4.0" + "node": ">=12" } }, - "node_modules/estree-util-is-identifier-name": { + "node_modules/d3-drag": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", - "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "license": "BSD-2-Clause", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, "engines": { - "node": ">=0.10.0" + "node": ">=12" } }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "license": "MIT", + "node_modules/d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "license": "ISC", "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" }, - "engines": { - "node": ">=10" + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" + "engines": { + "node": ">=12" } }, - "node_modules/execa/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/exit-x": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/exit-x/-/exit-x-0.2.2.tgz", - "integrity": "sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==", - "dev": true, - "license": "MIT", + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", "engines": { - "node": ">= 0.8.0" + "node": ">=12" } }, - "node_modules/expect": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-30.2.0.tgz", - "integrity": "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==", - "dev": true, - "license": "MIT", + "node_modules/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "license": "ISC", "dependencies": { - "@jest/expect-utils": "30.2.0", - "@jest/get-type": "30.1.0", - "jest-matcher-utils": "30.2.0", - "jest-message-util": "30.2.0", - "jest-mock": "30.2.0", - "jest-util": "30.2.0" + "d3-dsv": "1 - 3" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=12" } }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "license": "MIT" - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-glob": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", - "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", - "dev": true, - "license": "MIT", + "node_modules/d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "license": "ISC", "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" }, "engines": { - "node": ">=8.6.0" + "node": ">=12" } }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, + "node_modules/d3-format": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", + "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", "license": "ISC", "dependencies": { - "is-glob": "^4.0.1" + "d3-array": "2.5.0 - 3" }, "engines": { - "node": ">= 6" + "node": ">=12" } }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, - "license": "MIT" + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "license": "ISC", + "engines": { + "node": ">=12" + } }, - "node_modules/fastq": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", - "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", - "dev": true, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", "license": "ISC", "dependencies": { - "reusify": "^1.0.4" + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" } }, - "node_modules/fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "bser": "2.1.1" + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "license": "ISC", + "engines": { + "node": ">=12" } }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^4.0.0" - }, + "node_modules/d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "license": "ISC", "engines": { - "node": ">=16.0.0" + "node": ">=12" } }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, + "node_modules/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "license": "ISC", "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "license": "MIT", + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=12" } }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "license": "MIT", + "node_modules/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "license": "ISC", "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" }, "engines": { - "node": ">=16" + "node": ">=12" } }, - "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", - "dev": true, - "license": "ISC" + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } }, - "node_modules/for-each": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", - "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", - "dev": true, - "license": "MIT", + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", "dependencies": { - "is-callable": "^1.2.7" + "d3-path": "^3.1.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=12" } }, - "node_modules/foreground-child": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", - "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", - "dev": true, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", "license": "ISC", "dependencies": { - "cross-spawn": "^7.0.6", - "signal-exit": "^4.0.1" + "d3-array": "2 - 3" }, "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=12" } }, - "node_modules/framer-motion": { - "version": "12.38.0", - "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.38.0.tgz", - "integrity": "sha512-rFYkY/pigbcswl1XQSb7q424kSTQ8q6eAC+YUsSKooHQYuLdzdHjrt6uxUC+PRAO++q5IS7+TamgIw1AphxR+g==", - "license": "MIT", + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", "dependencies": { - "motion-dom": "^12.38.0", - "motion-utils": "^12.36.0", - "tslib": "^2.4.0" - }, - "peerDependencies": { - "@emotion/is-prop-valid": "*", - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" + "d3-time": "1 - 3" }, - "peerDependenciesMeta": { - "@emotion/is-prop-valid": { - "optional": true - }, - "react": { - "optional": true - }, - "react-dom": { - "optional": true - } - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "node": ">=12" } }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" } }, - "node_modules/function.prototype.name": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", - "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", - "dev": true, - "license": "MIT", + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "license": "ISC", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "functions-have-names": "^1.2.3", - "hasown": "^2.0.2", - "is-callable": "^1.2.7" + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" }, "engines": { - "node": ">= 0.4" + "node": ">=12" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/generator-function": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", - "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" + "peerDependencies": { + "d3-selection": "2 - 3" } }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "license": "MIT", + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, "engines": { - "node": ">=6.9.0" + "node": ">=12" } }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", "dev": true, - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } + "license": "BSD-2-Clause" }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", "dev": true, "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -6617,53 +3343,89 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", "dev": true, "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, "engines": { - "node": ">=8.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" } }, - "node_modules/get-proto": { + "node_modules/data-view-byte-offset": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", "dev": true, "license": "MIT", "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, "engines": { - "node": ">=10" + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decode-named-character-reference": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", + "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/get-symbol-description": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", - "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3", + "es-define-property": "^1.0.0", "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6" + "gopd": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -6672,171 +3434,181 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-tsconfig": { - "version": "4.13.6", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", - "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "dev": true, "license": "MIT", "dependencies": { - "resolve-pkg-maps": "^1.0.0" - }, - "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" - } - }, - "node_modules/glob": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", - "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "dev": true, - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" }, - "bin": { - "glob": "dist/esm/bin.mjs" + "engines": { + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, + "node_modules/delaunator": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.1.0.tgz", + "integrity": "sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==", "license": "ISC", "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" + "robust-predicates": "^3.0.2" } }, - "node_modules/glob/node_modules/balanced-match": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.3.tgz", - "integrity": "sha512-1pHv8LX9CpKut1Zp4EXey7Z8OfH11ONNH6Dhi2WDUt31VVZFXZzKwXcysBgqSumFCmR+0dqjMK5v5JiFHzi0+g==", - "dev": true, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", "license": "MIT", "engines": { - "node": "20 || >=22" + "node": ">=6" } }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.2.tgz", - "integrity": "sha512-Pdk8c9poy+YhOgVWw1JNN22/HcivgKWwpxKq04M/jTmHyCZn12WPJebZxdjSa5TmBqISrUSgNYU3eRORljfCCw==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "optional": true, "engines": { - "node": "20 || >=22" + "node": ">=8" } }, - "node_modules/glob/node_modules/minimatch": { - "version": "9.0.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.6.tgz", - "integrity": "sha512-kQAVowdR33euIqeA0+VZTDqU+qo1IeVY+hrKYtZMio3Pg0P0vuh/kwRylLUddJhB6pf3q/botcOvRtx4IN1wqQ==", - "dev": true, - "license": "ISC", + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", "dependencies": { - "brace-expansion": "^5.0.2" - }, - "engines": { - "node": ">=16 || 14 >=14.17" + "dequal": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/globalthis": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", - "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "dev": true, "license": "MIT", "dependencies": { - "define-properties": "^1.2.1", - "gopd": "^1.0.1" + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" }, "engines": { "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "node_modules/electron-to-chromium": { + "version": "1.5.340", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.340.tgz", + "integrity": "sha512-908qahOGocRMinT2nM3ajCEM99H4iPdv84eagPP3FfZy/1ZGeOy2CZYzjhms81ckOPCXPlW7LkY4XpxD8r1DrA==", "dev": true, - "license": "MIT", + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "license": "BSD-2-Clause", "engines": { - "node": ">= 0.4" + "node": ">=0.12" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/handlebars": { - "version": "4.7.8", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", - "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "node_modules/es-abstract": { + "version": "1.24.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.2.tgz", + "integrity": "sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==", "dev": true, "license": "MIT", "dependencies": { - "minimist": "^1.2.5", - "neo-async": "^2.6.2", - "source-map": "^0.6.1", - "wordwrap": "^1.0.0" - }, - "bin": { - "handlebars": "bin/handlebars" - }, - "engines": { - "node": ">=0.4.7" + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" }, - "optionalDependencies": { - "uglify-js": "^3.1.4" - } - }, - "node_modules/has-bigints": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", - "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", - "dev": true, - "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -6844,694 +3616,692 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 0.4" } }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "dev": true, "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">= 0.4" } }, - "node_modules/has-proto": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", - "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "node_modules/es-iterator-helpers": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.3.2.tgz", + "integrity": "sha512-HVLACW1TppGYjJ8H6/jqH/pqOtKRw6wMlrB23xfExmFWxFquAIWCmwoLsOyN96K4a5KbmOf5At9ZUO3GZbetAw==", "dev": true, "license": "MIT", "dependencies": { - "dunder-proto": "^1.0.0" + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.2", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.1.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.3.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "iterator.prototype": "^1.1.5", + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "dev": true, "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, "engines": { "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", "dev": true, "license": "MIT", "dependencies": { - "has-symbols": "^1.0.3" + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "node_modules/es-shim-unscopables": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", "dev": true, "license": "MIT", "dependencies": { - "function-bind": "^1.1.2" + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" } }, - "node_modules/hast-util-from-dom": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/hast-util-from-dom/-/hast-util-from-dom-5.0.1.tgz", - "integrity": "sha512-N+LqofjR2zuzTjCPzyDUdSshy4Ma6li7p/c3pA78uTwzFgENbgbUrm2ugwsOdcjI1muO+o6Dgzp9p8WHtn/39Q==", - "license": "ISC", - "dependencies": { - "@types/hast": "^3.0.0", - "hastscript": "^9.0.0", - "web-namespaces": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-from-html": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz", - "integrity": "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "devlop": "^1.1.0", - "hast-util-from-parse5": "^8.0.0", - "parse5": "^7.0.0", - "vfile": "^6.0.0", - "vfile-message": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-from-html-isomorphic": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hast-util-from-html-isomorphic/-/hast-util-from-html-isomorphic-2.0.0.tgz", - "integrity": "sha512-zJfpXq44yff2hmE0XmwEOzdWin5xwH+QIhMLOScpX91e/NSGPsAzNCvLQDIEPyO2TXi+lBmU6hjLIhV8MwP2kw==", + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "dev": true, "license": "MIT", "dependencies": { - "@types/hast": "^3.0.0", - "hast-util-from-dom": "^5.0.0", - "hast-util-from-html": "^2.0.0", - "unist-util-remove-position": "^5.0.0" + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-from-parse5": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz", - "integrity": "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/unist": "^3.0.0", - "devlop": "^1.0.0", - "hastscript": "^9.0.0", - "property-information": "^7.0.0", - "vfile": "^6.0.0", - "vfile-location": "^5.0.0", - "web-namespaces": "^2.0.0" + "engines": { + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/hast-util-is-element": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", - "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=6" } }, - "node_modules/hast-util-parse-selector": { + "node_modules/escape-string-regexp": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", - "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0" + "engines": { + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/hast-util-to-jsx-runtime": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", - "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", + "node_modules/eslint": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", + "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", + "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/unist": "^3.0.0", - "comma-separated-tokens": "^2.0.0", - "devlop": "^1.0.0", - "estree-util-is-identifier-name": "^3.0.0", - "hast-util-whitespace": "^3.0.0", - "mdast-util-mdx-expression": "^2.0.0", - "mdast-util-mdx-jsx": "^3.0.0", - "mdast-util-mdxjs-esm": "^2.0.0", - "property-information": "^7.0.0", - "space-separated-tokens": "^2.0.0", - "style-to-js": "^1.0.0", - "unist-util-position": "^5.0.0", - "vfile-message": "^4.0.0" + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.2", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.5", + "@eslint/js": "9.39.4", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.5", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, - "node_modules/hast-util-to-text": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz", - "integrity": "sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==", + "node_modules/eslint-config-next": { + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.1.6.tgz", + "integrity": "sha512-vKq40io2B0XtkkNDYyleATwblNt8xuh3FWp8SpSz3pt7P01OkBFlKsJZ2mWt5WsCySlDQLckb1zMY9yE9Qy0LA==", + "dev": true, "license": "MIT", "dependencies": { - "@types/hast": "^3.0.0", - "@types/unist": "^3.0.0", - "hast-util-is-element": "^3.0.0", - "unist-util-find-after": "^5.0.0" + "@next/eslint-plugin-next": "16.1.6", + "eslint-import-resolver-node": "^0.3.6", + "eslint-import-resolver-typescript": "^3.5.2", + "eslint-plugin-import": "^2.32.0", + "eslint-plugin-jsx-a11y": "^6.10.0", + "eslint-plugin-react": "^7.37.0", + "eslint-plugin-react-hooks": "^7.0.0", + "globals": "16.4.0", + "typescript-eslint": "^8.46.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "peerDependencies": { + "eslint": ">=9.0.0", + "typescript": ">=3.3.1" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/hast-util-whitespace": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", - "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "node_modules/eslint-config-next/node_modules/globals": { + "version": "16.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz", + "integrity": "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==", + "dev": true, "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0" + "engines": { + "node": ">=18" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/hastscript": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", - "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", + "node_modules/eslint-import-resolver-node": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.10.tgz", + "integrity": "sha512-tRrKqFyCaKict5hOd244sL6EQFNycnMQnBe+j8uqGNXYzsImGbGUU4ibtoaBmv5FLwJwcFJNeg1GeVjQfbMrDQ==", + "dev": true, "license": "MIT", "dependencies": { - "@types/hast": "^3.0.0", - "comma-separated-tokens": "^2.0.0", - "hast-util-parse-selector": "^4.0.0", - "property-information": "^7.0.0", - "space-separated-tokens": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "debug": "^3.2.7", + "is-core-module": "^2.16.1", + "resolve": "^2.0.0-next.6" } }, - "node_modules/hermes-estree": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", - "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", - "dev": true, - "license": "MIT" - }, - "node_modules/hermes-parser": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", - "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "license": "MIT", "dependencies": { - "hermes-estree": "0.25.1" + "ms": "^2.1.1" } }, - "node_modules/html-encoding-sniffer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", - "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "node_modules/eslint-import-resolver-typescript": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz", + "integrity": "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "whatwg-encoding": "^3.1.1" + "@nolyfill/is-core-module": "1.0.39", + "debug": "^4.4.0", + "get-tsconfig": "^4.10.0", + "is-bun-module": "^2.0.0", + "stable-hash": "^0.0.5", + "tinyglobby": "^0.2.13", + "unrs-resolver": "^1.6.2" }, "engines": { - "node": ">=18" + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-import-resolver-typescript" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*", + "eslint-plugin-import-x": "*" + }, + "peerDependenciesMeta": { + "eslint-plugin-import": { + "optional": true + }, + "eslint-plugin-import-x": { + "optional": true + } } }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "node_modules/eslint-module-utils": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz", + "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==", "dev": true, - "license": "MIT" - }, - "node_modules/html-url-attributes": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz", - "integrity": "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==", "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } } }, - "node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "license": "MIT", "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" + "ms": "^2.1.1" } }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "node_modules/eslint-plugin-import": { + "version": "2.32.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", + "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.9", + "array.prototype.findlastindex": "^1.2.6", + "array.prototype.flat": "^1.3.3", + "array.prototype.flatmap": "^1.3.3", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.12.1", + "hasown": "^2.0.2", + "is-core-module": "^2.16.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.1", + "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.9", + "tsconfig-paths": "^3.15.0" }, "engines": { - "node": ">= 14" + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" } }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10.17.0" + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" } }, - "node_modules/iceberg-js": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/iceberg-js/-/iceberg-js-0.8.1.tgz", - "integrity": "sha512-1dhVQZXhcHje7798IVM+xoo/1ZdVfzOMIc8/rgVSijRK38EDqOJoGula9N/8ZI5RD8QTxNQtK/Gozpr+qUqRRA==", + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz", + "integrity": "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==", + "dev": true, "license": "MIT", + "dependencies": { + "aria-query": "^5.3.2", + "array-includes": "^3.1.8", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "^4.10.0", + "axobject-query": "^4.1.0", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "hasown": "^2.0.2", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "safe-regex-test": "^1.0.3", + "string.prototype.includes": "^2.0.1" + }, "engines": { - "node": ">=20.0.0" + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" } }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "node_modules/eslint-plugin-react": { + "version": "7.37.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", + "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", + "dev": true, "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.3", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.2.1", + "estraverse": "^5.3.0", + "hasown": "^2.0.2", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.9", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.1", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.12", + "string.prototype.repeat": "^1.0.0" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "node_modules/eslint-plugin-react-hooks": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.1.1.tgz", + "integrity": "sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==", "dev": true, "license": "MIT", "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "hermes-parser": "^0.25.1", + "zod": "^3.25.0 || ^4.0.0", + "zod-validation-error": "^3.5.0 || ^4.0.0" }, "engines": { - "node": ">=6" + "node": ">=18" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0" } }, - "node_modules/import-local": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", - "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" }, "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/eslint" } }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "engines": { - "node": ">=0.8.19" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", "dev": true, - "license": "ISC", + "license": "BSD-3-Clause", "dependencies": { - "once": "^1.3.0", - "wrappy": "1" + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" } }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/inline-style-parser": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz", - "integrity": "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==", - "license": "MIT" - }, - "node_modules/internal-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", - "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.2", - "side-channel": "^1.1.0" + "estraverse": "^5.2.0" }, "engines": { - "node": ">= 0.4" + "node": ">=4.0" } }, - "node_modules/internmap": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", - "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", - "license": "ISC", + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", "engines": { - "node": ">=12" - } - }, - "node_modules/is-alphabetical": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", - "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node": ">=4.0" } }, - "node_modules/is-alphanumerical": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", - "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", "license": "MIT", - "dependencies": { - "is-alphabetical": "^2.0.0", - "is-decimal": "^2.0.0" - }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/is-array-buffer": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", - "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" - }, + "license": "BSD-2-Clause", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10.0" } }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "license": "MIT" }, - "node_modules/is-async-function": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", - "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true, - "license": "MIT", - "dependencies": { - "async-function": "^1.0.0", - "call-bound": "^1.0.3", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "license": "MIT" }, - "node_modules/is-bigint": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", - "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "node_modules/fast-glob": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", "dev": true, "license": "MIT", "dependencies": { - "has-bigints": "^1.0.2" + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8.6.0" } }, - "node_modules/is-boolean-object": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", - "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" + "is-glob": "^4.0.1" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 6" } }, - "node_modules/is-bun-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz", - "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==", + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.7.1" - } + "license": "MIT" }, - "node_modules/is-bun-module/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", "dev": true, "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" + "dependencies": { + "reusify": "^1.0.4" } }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 0.4" + "dependencies": { + "flat-cache": "^4.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=16.0.0" } }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "license": "MIT", "dependencies": { - "hasown": "^2.0.2" + "to-regex-range": "^5.0.1" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/is-data-view": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", - "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", - "is-typed-array": "^1.1.13" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-date-object": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", - "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.2", - "has-tostringtag": "^1.0.2" + "flatted": "^3.2.9", + "keyv": "^4.5.4" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-decimal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", - "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node": ">=16" } }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } + "license": "ISC" }, - "node_modules/is-finalizationregistry": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", - "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3" + "is-callable": "^1.2.7" }, "engines": { "node": ">= 0.4" @@ -7540,114 +4310,84 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/is-generator-function": { + "node_modules/function-bind": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", - "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, "license": "MIT", - "dependencies": { - "call-bound": "^1.0.4", - "generator-function": "^2.0.0", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", "dev": true, "license": "MIT", "dependencies": { - "is-extglob": "^2.1.1" + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-hexadecimal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", - "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", - "license": "MIT", + "node": ">= 0.4" + }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", - "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 0.4" - }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-negative-zero": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.12.0" + "node": ">=6.9.0" } }, - "node_modules/is-number-object": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", - "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -7656,36 +4396,30 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-plain-obj": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, "license": "MIT", - "engines": { - "node": ">=12" + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">= 0.4" } }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/is-regex": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", - "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" }, "engines": { "node": ">= 0.4" @@ -7694,57 +4428,54 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-set": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", - "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "node_modules/get-tsconfig": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz", + "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 0.4" + "dependencies": { + "resolve-pkg-maps": "^1.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", - "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "call-bound": "^1.0.3" + "is-glob": "^4.0.3" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=10.13.0" } }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-string": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", - "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" + "define-properties": "^1.2.1", + "gopd": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -7753,17 +4484,12 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-symbol": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", - "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "dev": true, "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "has-symbols": "^1.1.0", - "safe-regex-test": "^1.1.0" - }, "engines": { "node": ">= 0.4" }, @@ -7771,15 +4497,12 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", - "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", "dev": true, "license": "MIT", - "dependencies": { - "which-typed-array": "^1.1.16" - }, "engines": { "node": ">= 0.4" }, @@ -7787,44 +4510,37 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-weakmap": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", - "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/is-weakref": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", - "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" + "es-define-property": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-weakset": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", - "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" + "dunder-proto": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -7833,1102 +4549,832 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true, - "license": "MIT" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/istanbul-lib-instrument": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", - "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", "dependencies": { - "@babel/core": "^7.23.9", - "@babel/parser": "^7.23.9", - "@istanbuljs/schema": "^0.1.3", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^7.5.4" + "has-symbols": "^1.0.3" }, "engines": { - "node": ">=10" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "node_modules/hasown": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", + "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" }, "engines": { - "node": ">=10" + "node": ">= 0.4" } }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/hast-util-from-dom": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/hast-util-from-dom/-/hast-util-from-dom-5.0.1.tgz", + "integrity": "sha512-N+LqofjR2zuzTjCPzyDUdSshy4Ma6li7p/c3pA78uTwzFgENbgbUrm2ugwsOdcjI1muO+o6Dgzp9p8WHtn/39Q==", + "license": "ISC", "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" + "@types/hast": "^3.0.0", + "hastscript": "^9.0.0", + "web-namespaces": "^2.0.0" }, - "engines": { - "node": ">=10" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/istanbul-lib-source-maps": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", - "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/hast-util-from-html": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz", + "integrity": "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==", + "license": "MIT", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.23", - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0" + "@types/hast": "^3.0.0", + "devlop": "^1.1.0", + "hast-util-from-parse5": "^8.0.0", + "parse5": "^7.0.0", + "vfile": "^6.0.0", + "vfile-message": "^4.0.0" }, - "engines": { - "node": ">=10" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/istanbul-reports": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", - "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/hast-util-from-html-isomorphic": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hast-util-from-html-isomorphic/-/hast-util-from-html-isomorphic-2.0.0.tgz", + "integrity": "sha512-zJfpXq44yff2hmE0XmwEOzdWin5xwH+QIhMLOScpX91e/NSGPsAzNCvLQDIEPyO2TXi+lBmU6hjLIhV8MwP2kw==", + "license": "MIT", "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" + "@types/hast": "^3.0.0", + "hast-util-from-dom": "^5.0.0", + "hast-util-from-html": "^2.0.0", + "unist-util-remove-position": "^5.0.0" }, - "engines": { - "node": ">=8" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/iterator.prototype": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", - "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", - "dev": true, + "node_modules/hast-util-from-parse5": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz", + "integrity": "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==", "license": "MIT", "dependencies": { - "define-data-property": "^1.1.4", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.6", - "get-proto": "^1.0.0", - "has-symbols": "^1.1.0", - "set-function-name": "^2.0.2" + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "hastscript": "^9.0.0", + "property-information": "^7.0.0", + "vfile": "^6.0.0", + "vfile-location": "^5.0.0", + "web-namespaces": "^2.0.0" }, - "engines": { - "node": ">= 0.4" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "dev": true, - "license": "BlueOak-1.0.0", + "node_modules/hast-util-is-element": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", + "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", + "license": "MIT", "dependencies": { - "@isaacs/cliui": "^8.0.2" + "@types/hast": "^3.0.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/jest": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-30.2.0.tgz", - "integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==", - "dev": true, + "node_modules/hast-util-parse-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", "license": "MIT", "dependencies": { - "@jest/core": "30.2.0", - "@jest/types": "30.2.0", - "import-local": "^3.2.0", - "jest-cli": "30.2.0" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + "@types/hast": "^3.0.0" }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/jest-changed-files": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.2.0.tgz", - "integrity": "sha512-L8lR1ChrRnSdfeOvTrwZMlnWV8G/LLjQ0nG9MBclwWZidA2N5FviRki0Bvh20WRMOX31/JYvzdqTJrk5oBdydQ==", - "dev": true, + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", + "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", "license": "MIT", "dependencies": { - "execa": "^5.1.1", - "jest-util": "30.2.0", - "p-limit": "^3.1.0" + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/jest-circus": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.2.0.tgz", - "integrity": "sha512-Fh0096NC3ZkFx05EP2OXCxJAREVxj1BcW/i6EWqqymcgYKWjyyDpral3fMxVcHXg6oZM7iULer9wGRFvfpl+Tg==", - "dev": true, + "node_modules/hast-util-to-text": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz", + "integrity": "sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==", "license": "MIT", "dependencies": { - "@jest/environment": "30.2.0", - "@jest/expect": "30.2.0", - "@jest/test-result": "30.2.0", - "@jest/types": "30.2.0", - "@types/node": "*", - "chalk": "^4.1.2", - "co": "^4.6.0", - "dedent": "^1.6.0", - "is-generator-fn": "^2.1.0", - "jest-each": "30.2.0", - "jest-matcher-utils": "30.2.0", - "jest-message-util": "30.2.0", - "jest-runtime": "30.2.0", - "jest-snapshot": "30.2.0", - "jest-util": "30.2.0", - "p-limit": "^3.1.0", - "pretty-format": "30.2.0", - "pure-rand": "^7.0.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.6" + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "hast-util-is-element": "^3.0.0", + "unist-util-find-after": "^5.0.0" }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/jest-circus/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", "license": "MIT", - "engines": { - "node": ">=10" + "dependencies": { + "@types/hast": "^3.0.0" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/jest-circus/node_modules/pretty-format": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", - "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", - "dev": true, + "node_modules/hastscript": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", + "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", "license": "MIT", "dependencies": { - "@jest/schemas": "30.0.5", - "ansi-styles": "^5.2.0", - "react-is": "^18.3.1" + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0" }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/jest-circus/node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "node_modules/hermes-estree": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", "dev": true, "license": "MIT" }, - "node_modules/jest-cli": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.2.0.tgz", - "integrity": "sha512-Os9ukIvADX/A9sLt6Zse3+nmHtHaE6hqOsjQtNiugFTbKRHYIYtZXNGNK9NChseXy7djFPjndX1tL0sCTlfpAA==", + "node_modules/hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/core": "30.2.0", - "@jest/test-result": "30.2.0", - "@jest/types": "30.2.0", - "chalk": "^4.1.2", - "exit-x": "^0.2.2", - "import-local": "^3.2.0", - "jest-config": "30.2.0", - "jest-util": "30.2.0", - "jest-validate": "30.2.0", - "yargs": "^17.7.2" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "hermes-estree": "0.25.1" } }, - "node_modules/jest-cli/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, + "node_modules/html-url-attributes": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz", + "integrity": "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==", "license": "MIT", - "engines": { - "node": ">=10" - }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/jest-cli/node_modules/jest-config": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.2.0.tgz", - "integrity": "sha512-g4WkyzFQVWHtu6uqGmQR4CQxz/CH3yDSlhzXMWzNjDx843gYjReZnMRanjRCq5XZFuQrGDxgUaiYWE8BRfVckA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.27.4", - "@jest/get-type": "30.1.0", - "@jest/pattern": "30.0.1", - "@jest/test-sequencer": "30.2.0", - "@jest/types": "30.2.0", - "babel-jest": "30.2.0", - "chalk": "^4.1.2", - "ci-info": "^4.2.0", - "deepmerge": "^4.3.1", - "glob": "^10.3.10", - "graceful-fs": "^4.2.11", - "jest-circus": "30.2.0", - "jest-docblock": "30.2.0", - "jest-environment-node": "30.2.0", - "jest-regex-util": "30.0.1", - "jest-resolve": "30.2.0", - "jest-runner": "30.2.0", - "jest-util": "30.2.0", - "jest-validate": "30.2.0", - "micromatch": "^4.0.8", - "parse-json": "^5.2.0", - "pretty-format": "30.2.0", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, + "node_modules/iceberg-js": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/iceberg-js/-/iceberg-js-0.8.1.tgz", + "integrity": "sha512-1dhVQZXhcHje7798IVM+xoo/1ZdVfzOMIc8/rgVSijRK38EDqOJoGula9N/8ZI5RD8QTxNQtK/Gozpr+qUqRRA==", + "license": "MIT", "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "peerDependencies": { - "@types/node": "*", - "esbuild-register": ">=3.4.0", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "esbuild-register": { - "optional": true - }, - "ts-node": { - "optional": true - } + "node": ">=20.0.0" } }, - "node_modules/jest-cli/node_modules/pretty-format": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", - "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", - "dev": true, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "license": "MIT", "dependencies": { - "@jest/schemas": "30.0.5", - "ansi-styles": "^5.2.0", - "react-is": "^18.3.1" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=0.10.0" } }, - "node_modules/jest-cli/node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true, - "license": "MIT" - }, - "node_modules/jest-diff": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz", - "integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==", + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "license": "MIT", - "dependencies": { - "@jest/diff-sequences": "30.0.1", - "@jest/get-type": "30.1.0", - "chalk": "^4.1.2", - "pretty-format": "30.2.0" - }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">= 4" } }, - "node_modules/jest-diff/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, "engines": { - "node": ">=10" + "node": ">=6" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-diff/node_modules/pretty-format": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", - "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, "license": "MIT", - "dependencies": { - "@jest/schemas": "30.0.5", - "ansi-styles": "^5.2.0", - "react-is": "^18.3.1" - }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=0.8.19" } }, - "node_modules/jest-diff/node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true, + "node_modules/inline-style-parser": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz", + "integrity": "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==", "license": "MIT" }, - "node_modules/jest-docblock": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.2.0.tgz", - "integrity": "sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==", + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", "dev": true, "license": "MIT", "dependencies": { - "detect-newline": "^3.1.0" + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">= 0.4" } }, - "node_modules/jest-each": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.2.0.tgz", - "integrity": "sha512-lpWlJlM7bCUf1mfmuqTA8+j2lNURW9eNafOy99knBM01i5CQeY5UH1vZjgT9071nDJac1M4XsbyI44oNOdhlDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/get-type": "30.1.0", - "@jest/types": "30.2.0", - "chalk": "^4.1.2", - "jest-util": "30.2.0", - "pretty-format": "30.2.0" - }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=12" } }, - "node_modules/jest-each/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", "license": "MIT", - "engines": { - "node": ">=10" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "license": "MIT", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/jest-each/node_modules/pretty-format": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", - "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", "dev": true, "license": "MIT", "dependencies": { - "@jest/schemas": "30.0.5", - "ansi-styles": "^5.2.0", - "react-is": "^18.3.1" + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-each/node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true, - "license": "MIT" - }, - "node_modules/jest-environment-jsdom": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-30.2.0.tgz", - "integrity": "sha512-zbBTiqr2Vl78pKp/laGBREYzbZx9ZtqPjOK4++lL4BNDhxRnahg51HtoDrk9/VjIy9IthNEWdKVd7H5bqBhiWQ==", + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/environment": "30.2.0", - "@jest/environment-jsdom-abstract": "30.2.0", - "@types/jsdom": "^21.1.7", - "@types/node": "*", - "jsdom": "^26.1.0" + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "peerDependencies": { - "canvas": "^3.0.0" + "node": ">= 0.4" }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-environment-node": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.2.0.tgz", - "integrity": "sha512-ElU8v92QJ9UrYsKrxDIKCxu6PfNj4Hdcktcn0JX12zqNdqWHB0N+hwOnnBBXvjLd2vApZtuLUGs1QSY+MsXoNA==", + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/environment": "30.2.0", - "@jest/fake-timers": "30.2.0", - "@jest/types": "30.2.0", - "@types/node": "*", - "jest-mock": "30.2.0", - "jest-util": "30.2.0", - "jest-validate": "30.2.0" + "has-bigints": "^1.0.2" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-haste-map": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.2.0.tgz", - "integrity": "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw==", + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.2.0", - "@types/node": "*", - "anymatch": "^3.1.3", - "fb-watchman": "^2.0.2", - "graceful-fs": "^4.2.11", - "jest-regex-util": "30.0.1", - "jest-util": "30.2.0", - "jest-worker": "30.2.0", - "micromatch": "^4.0.8", - "walker": "^1.0.8" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">= 0.4" }, - "optionalDependencies": { - "fsevents": "^2.3.3" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-leak-detector": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.2.0.tgz", - "integrity": "sha512-M6jKAjyzjHG0SrQgwhgZGy9hFazcudwCNovY/9HPIicmNSBuockPSedAP9vlPK6ONFJ1zfyH/M2/YYJxOz5cdQ==", + "node_modules/is-bun-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz", + "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/get-type": "30.1.0", - "pretty-format": "30.2.0" + "semver": "^7.7.1" + } + }, + "node_modules/is-bun-module/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=10" } }, - "node_modules/jest-leak-detector/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, "license": "MIT", "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-leak-detector/node_modules/pretty-format": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", - "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "dev": true, "license": "MIT", "dependencies": { - "@jest/schemas": "30.0.5", - "ansi-styles": "^5.2.0", - "react-is": "^18.3.1" + "hasown": "^2.0.2" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-leak-detector/node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true, - "license": "MIT" - }, - "node_modules/jest-matcher-utils": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz", - "integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==", + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/get-type": "30.1.0", - "chalk": "^4.1.2", - "jest-diff": "30.2.0", - "pretty-format": "30.2.0" + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/jest-matcher-utils/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-matcher-utils/node_modules/pretty-format": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", - "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", "dev": true, "license": "MIT", "dependencies": { - "@jest/schemas": "30.0.5", - "ansi-styles": "^5.2.0", - "react-is": "^18.3.1" + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-matcher-utils/node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true, - "license": "MIT" + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } }, - "node_modules/jest-message-util": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", - "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@jest/types": "30.2.0", - "@types/stack-utils": "^2.0.3", - "chalk": "^4.1.2", - "graceful-fs": "^4.2.11", - "micromatch": "^4.0.8", - "pretty-format": "30.2.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.6" - }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=0.10.0" } }, - "node_modules/jest-message-util/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", "dev": true, "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-message-util/node_modules/pretty-format": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", - "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/schemas": "30.0.5", - "ansi-styles": "^5.2.0", - "react-is": "^18.3.1" + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-message-util/node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true, - "license": "MIT" - }, - "node_modules/jest-mock": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.2.0.tgz", - "integrity": "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw==", + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.2.0", - "@types/node": "*", - "jest-util": "30.2.0" + "is-extglob": "^2.1.1" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=0.10.0" } }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "dev": true, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", "license": "MIT", - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/jest-regex-util": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz", - "integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==", + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", "dev": true, "license": "MIT", "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/jest-resolve": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.2.0.tgz", - "integrity": "sha512-TCrHSxPlx3tBY3hWNtRQKbtgLhsXa1WmbJEqBlTBrGafd5fiQFByy2GNCEoGR+Tns8d15GaL9cxEzKOO3GEb2A==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.1.2", - "graceful-fs": "^4.2.11", - "jest-haste-map": "30.2.0", - "jest-pnp-resolver": "^1.2.3", - "jest-util": "30.2.0", - "jest-validate": "30.2.0", - "slash": "^3.0.0", - "unrs-resolver": "^1.7.11" + "node": ">= 0.4" }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-resolve-dependencies": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.2.0.tgz", - "integrity": "sha512-xTOIGug/0RmIe3mmCqCT95yO0vj6JURrn1TKWlNbhiAefJRWINNPgwVkrVgt/YaerPzY3iItufd80v3lOrFJ2w==", + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", "dev": true, "license": "MIT", - "dependencies": { - "jest-regex-util": "30.0.1", - "jest-snapshot": "30.2.0" - }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-runner": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.2.0.tgz", - "integrity": "sha512-PqvZ2B2XEyPEbclp+gV6KO/F1FIFSbIwewRgmROCMBo/aZ6J1w8Qypoj2pEOcg3G2HzLlaP6VUtvwCI8dM3oqQ==", + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, "license": "MIT", - "dependencies": { - "@jest/console": "30.2.0", - "@jest/environment": "30.2.0", - "@jest/test-result": "30.2.0", - "@jest/transform": "30.2.0", - "@jest/types": "30.2.0", - "@types/node": "*", - "chalk": "^4.1.2", - "emittery": "^0.13.1", - "exit-x": "^0.2.2", - "graceful-fs": "^4.2.11", - "jest-docblock": "30.2.0", - "jest-environment-node": "30.2.0", - "jest-haste-map": "30.2.0", - "jest-leak-detector": "30.2.0", - "jest-message-util": "30.2.0", - "jest-resolve": "30.2.0", - "jest-runtime": "30.2.0", - "jest-util": "30.2.0", - "jest-watcher": "30.2.0", - "jest-worker": "30.2.0", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=0.12.0" } }, - "node_modules/jest-runtime": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.2.0.tgz", - "integrity": "sha512-p1+GVX/PJqTucvsmERPMgCPvQJpFt4hFbM+VN3n8TMo47decMUcJbt+rgzwrEme0MQUA/R+1de2axftTHkKckg==", + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/environment": "30.2.0", - "@jest/fake-timers": "30.2.0", - "@jest/globals": "30.2.0", - "@jest/source-map": "30.0.1", - "@jest/test-result": "30.2.0", - "@jest/transform": "30.2.0", - "@jest/types": "30.2.0", - "@types/node": "*", - "chalk": "^4.1.2", - "cjs-module-lexer": "^2.1.0", - "collect-v8-coverage": "^1.0.2", - "glob": "^10.3.10", - "graceful-fs": "^4.2.11", - "jest-haste-map": "30.2.0", - "jest-message-util": "30.2.0", - "jest-mock": "30.2.0", - "jest-regex-util": "30.0.1", - "jest-resolve": "30.2.0", - "jest-snapshot": "30.2.0", - "jest-util": "30.2.0", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-runtime/node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-snapshot": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.2.0.tgz", - "integrity": "sha512-5WEtTy2jXPFypadKNpbNkZ72puZCa6UjSr/7djeecHWOu7iYhSXSnHScT8wBz3Rn8Ena5d5RYRcsyKIeqG1IyA==", + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.27.4", - "@babel/generator": "^7.27.5", - "@babel/plugin-syntax-jsx": "^7.27.1", - "@babel/plugin-syntax-typescript": "^7.27.1", - "@babel/types": "^7.27.3", - "@jest/expect-utils": "30.2.0", - "@jest/get-type": "30.1.0", - "@jest/snapshot-utils": "30.2.0", - "@jest/transform": "30.2.0", - "@jest/types": "30.2.0", - "babel-preset-current-node-syntax": "^1.2.0", - "chalk": "^4.1.2", - "expect": "30.2.0", - "graceful-fs": "^4.2.11", - "jest-diff": "30.2.0", - "jest-matcher-utils": "30.2.0", - "jest-message-util": "30.2.0", - "jest-util": "30.2.0", - "pretty-format": "30.2.0", - "semver": "^7.7.2", - "synckit": "^0.11.8" + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-snapshot/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", "dev": true, "license": "MIT", "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-snapshot/node_modules/pretty-format": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", - "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", "dev": true, "license": "MIT", "dependencies": { - "@jest/schemas": "30.0.5", - "ansi-styles": "^5.2.0", - "react-is": "^18.3.1" + "call-bound": "^1.0.3" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true, - "license": "MIT" - }, - "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "node": ">= 0.4" }, - "engines": { - "node": ">=10" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-util": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", - "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.2.0", - "@types/node": "*", - "chalk": "^4.1.2", - "ci-info": "^4.2.0", - "graceful-fs": "^4.2.11", - "picomatch": "^4.0.2" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-util/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", "dev": true, "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, "engines": { - "node": ">=12" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-validate": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.2.0.tgz", - "integrity": "sha512-FBGWi7dP2hpdi8nBoWxSsLvBFewKAg0+uSQwBaof4Y4DPgBabXgpSYC5/lR7VmnIlSpASmCi/ntRWPbv7089Pw==", + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/get-type": "30.1.0", - "@jest/types": "30.2.0", - "camelcase": "^6.3.0", - "chalk": "^4.1.2", - "leven": "^3.1.0", - "pretty-format": "30.2.0" + "which-typed-array": "^1.1.16" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-validate/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", "dev": true, "license": "MIT", "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", "dev": true, "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-validate/node_modules/pretty-format": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", - "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/schemas": "30.0.5", - "ansi-styles": "^5.2.0", - "react-is": "^18.3.1" + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-validate/node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", "dev": true, "license": "MIT" }, - "node_modules/jest-watcher": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.2.0.tgz", - "integrity": "sha512-PYxa28dxJ9g777pGm/7PrbnMeA0Jr7osHP9bS7eJy9DuAjMgdGtxgf0uKMyoIsTWAkIbUW5hSDdJ3urmgXBqxg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/test-result": "30.2.0", - "@jest/types": "30.2.0", - "@types/node": "*", - "ansi-escapes": "^4.3.2", - "chalk": "^4.1.2", - "emittery": "^0.13.1", - "jest-util": "30.2.0", - "string-length": "^4.0.2" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/jest-worker": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.2.0.tgz", - "integrity": "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g==", + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "@ungap/structured-clone": "^1.3.0", - "jest-util": "30.2.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.1.1" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } + "license": "ISC" }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "node_modules/iterator.prototype": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", + "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", "dev": true, "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "define-data-property": "^1.1.4", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "get-proto": "^1.0.0", + "has-symbols": "^1.1.0", + "set-function-name": "^2.0.2" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/jiti": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", - "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", - "dev": true, - "license": "MIT", - "bin": { - "jiti": "lib/jiti-cli.mjs" + "node": ">= 0.4" } }, "node_modules/js-tokens": { @@ -8951,46 +5397,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jsdom": { - "version": "26.1.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-26.1.0.tgz", - "integrity": "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cssstyle": "^4.2.1", - "data-urls": "^5.0.0", - "decimal.js": "^10.5.0", - "html-encoding-sniffer": "^4.0.0", - "http-proxy-agent": "^7.0.2", - "https-proxy-agent": "^7.0.6", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.16", - "parse5": "^7.2.1", - "rrweb-cssom": "^0.8.0", - "saxes": "^6.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^5.1.1", - "w3c-xmlserializer": "^5.0.0", - "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^3.1.1", - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^14.1.1", - "ws": "^8.18.0", - "xml-name-validator": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "canvas": "^3.0.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, "node_modules/jsesc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", @@ -9011,13 +5417,6 @@ "dev": true, "license": "MIT" }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true, - "license": "MIT" - }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -9026,388 +5425,110 @@ "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsx-ast-utils": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", - "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "object.assign": "^4.1.4", - "object.values": "^1.1.6" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/katex": { - "version": "0.16.40", - "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.40.tgz", - "integrity": "sha512-1DJcK/L05k1Y9Gf7wMcyuqFOL6BiY3vY0CFcAM/LPRN04NALxcl6u7lOWNsp3f/bCHWxigzQl6FbR95XJ4R84Q==", - "funding": [ - "https://opencollective.com/katex", - "https://github.com/sponsors/katex" - ], - "license": "MIT", - "dependencies": { - "commander": "^8.3.0" - }, - "bin": { - "katex": "cli.js" - } - }, - "node_modules/katex/node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/language-subtag-registry": { - "version": "0.3.23", - "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", - "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", - "dev": true, - "license": "CC0-1.0" - }, - "node_modules/language-tags": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", - "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", - "dev": true, - "license": "MIT", - "dependencies": { - "language-subtag-registry": "^0.3.20" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lightningcss": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.31.1.tgz", - "integrity": "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "detect-libc": "^2.0.3" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-android-arm64": "1.31.1", - "lightningcss-darwin-arm64": "1.31.1", - "lightningcss-darwin-x64": "1.31.1", - "lightningcss-freebsd-x64": "1.31.1", - "lightningcss-linux-arm-gnueabihf": "1.31.1", - "lightningcss-linux-arm64-gnu": "1.31.1", - "lightningcss-linux-arm64-musl": "1.31.1", - "lightningcss-linux-x64-gnu": "1.31.1", - "lightningcss-linux-x64-musl": "1.31.1", - "lightningcss-win32-arm64-msvc": "1.31.1", - "lightningcss-win32-x64-msvc": "1.31.1" - } - }, - "node_modules/lightningcss-android-arm64": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.31.1.tgz", - "integrity": "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.31.1.tgz", - "integrity": "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.31.1.tgz", - "integrity": "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==", - "cpu": [ - "x64" - ], + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } + "license": "MIT" }, - "node_modules/lightningcss-freebsd-x64": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.31.1.tgz", - "integrity": "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==", - "cpu": [ - "x64" - ], + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 12.0.0" + "license": "MIT", + "bin": { + "json5": "lib/cli.js" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "engines": { + "node": ">=6" } }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.31.1.tgz", - "integrity": "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==", - "cpu": [ - "arm" - ], + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "engines": { + "node": ">=4.0" } }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.31.1.tgz", - "integrity": "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" + "node_modules/katex": { + "version": "0.16.45", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.45.tgz", + "integrity": "sha512-pQpZbdBu7wCTmQUh7ufPmLr0pFoObnGUoL/yhtwJDgmmQpbkg/0HSVti25Fu4rmd1oCR6NGWe9vqTWuWv3GcNA==", + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" ], - "engines": { - "node": ">= 12.0.0" + "license": "MIT", + "dependencies": { + "commander": "^8.3.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "bin": { + "katex": "cli.js" } }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.31.1.tgz", - "integrity": "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], + "node_modules/katex/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "license": "MIT", "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">= 12" } }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.31.1.tgz", - "integrity": "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==", - "cpu": [ - "x64" - ], + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" } }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.31.1.tgz", - "integrity": "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==", - "cpu": [ - "x64" - ], + "node_modules/language-subtag-registry": { + "version": "0.3.23", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", + "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } + "license": "CC0-1.0" }, - "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.31.1.tgz", - "integrity": "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==", - "cpu": [ - "arm64" - ], + "node_modules/language-tags": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" + "license": "MIT", + "dependencies": { + "language-subtag-registry": "^0.3.20" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "engines": { + "node": ">=0.10" } }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.31.1.tgz", - "integrity": "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==", - "cpu": [ - "x64" - ], + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "engines": { + "node": ">= 0.8.0" } }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true, - "license": "MIT" - }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -9424,13 +5545,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true, - "license": "MIT" - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -9471,82 +5585,6 @@ "yallist": "^3.0.2" } }, - "node_modules/lucide-react": { - "version": "0.577.0", - "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.577.0.tgz", - "integrity": "sha512-4LjoFv2eEPwYDPg/CUdBJQSDfPyzXCRrVW1X7jrx/trgxnxkHFjnVZINbzvzxjN70dxychOfg+FTYwBiS3pQ5A==", - "license": "ISC", - "peerDependencies": { - "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/lz-string": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", - "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", - "dev": true, - "license": "MIT", - "peer": true, - "bin": { - "lz-string": "bin/bin.js" - } - }, - "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true, - "license": "ISC" - }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "tmpl": "1.0.5" - } - }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -9729,13 +5767,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true, - "license": "MIT" - }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -10215,36 +6246,16 @@ "license": "MIT", "dependencies": { "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "dev": true, - "license": "MIT", + "picomatch": "^2.3.1" + }, "engines": { - "node": ">=4" + "node": ">=8.6" } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -10264,31 +6275,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/minipass": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", - "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/motion-dom": { - "version": "12.38.0", - "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.38.0.tgz", - "integrity": "sha512-pdkHLD8QYRp8VfiNLb8xIBJis1byQ9gPT3Jnh2jqfFtAsWUA3dEepDlsWe/xMpO8McV+VdpKVcp+E+TGJEtOoA==", - "license": "MIT", - "dependencies": { - "motion-utils": "^12.36.0" - } - }, - "node_modules/motion-utils": { - "version": "12.36.0", - "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.36.0.tgz", - "integrity": "sha512-eHWisygbiwVvf6PZ1vhaHCLamvkSbPIeAYxWUuL3a2PD/TROgE7FvfHWTIH4vMl798QLfMw15nRqIaRDXTlYRg==", - "license": "MIT" - }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -10336,13 +6322,6 @@ "dev": true, "license": "MIT" }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true, - "license": "MIT" - }, "node_modules/next": { "version": "16.1.6", "resolved": "https://registry.npmjs.org/next/-/next-16.1.6.tgz", @@ -10396,34 +6375,6 @@ } } }, - "node_modules/next/node_modules/postcss": { - "version": "8.4.31", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", - "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, "node_modules/node-exports-info": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/node-exports-info/-/node-exports-info-1.6.0.tgz", @@ -10443,47 +6394,10 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true, - "license": "MIT" - }, "node_modules/node-releases": { - "version": "2.0.27", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", - "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nwsapi": { - "version": "2.2.23", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.23.tgz", - "integrity": "sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==", + "version": "2.0.37", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.37.tgz", + "integrity": "sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==", "dev": true, "license": "MIT" }, @@ -10610,32 +6524,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -10704,23 +6592,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "dev": true, - "license": "BlueOak-1.0.0" - }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -10759,25 +6630,6 @@ "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", "license": "MIT" }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/parse5": { "version": "7.3.0", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", @@ -10800,16 +6652,6 @@ "node": ">=8" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -10827,30 +6669,6 @@ "dev": true, "license": "MIT" }, - "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" - }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -10858,9 +6676,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "dev": true, "license": "MIT", "engines": { @@ -10870,85 +6688,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pirates": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", - "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/possible-typed-array-names": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", @@ -10960,10 +6699,9 @@ } }, "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "dev": true, + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", "funding": [ { "type": "opencollective", @@ -10980,9 +6718,9 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" }, "engines": { "node": "^10 || ^12 || >=14" @@ -10998,44 +6736,6 @@ "node": ">= 0.8.0" } }, - "node_modules/pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/pretty-format/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -11068,23 +6768,6 @@ "node": ">=6" } }, - "node_modules/pure-rand": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", - "integrity": "sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ], - "license": "MIT" - }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -11161,20 +6844,6 @@ "react": ">=18" } }, - "node_modules/redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", - "dev": true, - "license": "MIT", - "dependencies": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/reflect.getprototypeof": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", @@ -11287,58 +6956,28 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "version": "2.0.0-next.6", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.6.tgz", + "integrity": "sha512-3JmVl5hMGtJ3kMmB3zi3DL25KfkCEyy3Tw7Gmw7z5w8M9WlwoPFnIvwChzu1+cF3iaK3sp18hhPz8ANeimdJfA==", "dev": true, "license": "MIT", "dependencies": { + "es-errors": "^1.3.0", "is-core-module": "^2.16.1", + "node-exports-info": "^1.6.0", + "object-keys": "^1.1.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "resolve-from": "^5.0.0" + "bin": { + "resolve": "bin/resolve" }, "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-cwd/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/resolve-from": { @@ -11373,18 +7012,11 @@ } }, "node_modules/robust-predicates": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", - "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.3.tgz", + "integrity": "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==", "license": "Unlicense" }, - "node_modules/rrweb-cssom": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", - "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", - "dev": true, - "license": "MIT" - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -11476,19 +7108,6 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT" }, - "node_modules/saxes": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", - "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", - "dev": true, - "license": "ISC", - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=v12.22.7" - } - }, "node_modules/scheduler": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", @@ -11656,14 +7275,14 @@ } }, "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" + "object-inspect": "^1.13.4" }, "engines": { "node": ">= 0.4" @@ -11711,39 +7330,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -11753,17 +7339,6 @@ "node": ">=0.10.0" } }, - "node_modules/source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, "node_modules/space-separated-tokens": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", @@ -11774,13 +7349,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true, - "license": "BSD-3-Clause" - }, "node_modules/stable-hash": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz", @@ -11788,29 +7356,6 @@ "dev": true, "license": "MIT" }, - "node_modules/stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/stop-iteration-iterator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", @@ -11825,87 +7370,6 @@ "node": ">= 0.4" } }, - "node_modules/string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/string-length/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/string-width-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/string.prototype.includes": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", @@ -12033,49 +7497,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, "node_modules/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", @@ -12086,29 +7507,6 @@ "node": ">=4" } }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "min-indent": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -12189,96 +7587,15 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true, - "license": "MIT" - }, - "node_modules/synckit": { - "version": "0.11.12", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz", - "integrity": "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@pkgr/core": "^0.2.9" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/synckit" - } - }, - "node_modules/tailwindcss": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.0.tgz", - "integrity": "sha512-yYzTZ4++b7fNYxFfpnberEEKu43w44aqDMNM9MHMmcKuCH7lL8jJ4yJ7LGHv7rSwiqM0nkiobF9I6cLlpS2P7Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/tapable": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", - "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "license": "ISC", - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/test-exclude/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", - "picomatch": "^4.0.3" + "picomatch": "^4.0.4" }, "engines": { "node": ">=12.0.0" @@ -12306,82 +7623,29 @@ } }, "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "engines": { "node": ">=12" }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/tldts": { - "version": "6.1.86", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz", - "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "tldts-core": "^6.1.86" - }, - "bin": { - "tldts": "bin/cli.js" - } - }, - "node_modules/tldts-core": { - "version": "6.1.86", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz", - "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==", - "dev": true, - "license": "MIT" - }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tough-cookie": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", - "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "tldts": "^6.1.32" - }, - "engines": { - "node": ">=16" + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/tr46": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", - "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "license": "MIT", "dependencies": { - "punycode": "^2.3.1" + "is-number": "^7.0.0" }, "engines": { - "node": ">=18" + "node": ">=8.0" } }, "node_modules/trim-lines": { @@ -12405,9 +7669,9 @@ } }, "node_modules/ts-api-utils": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", - "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", "dev": true, "license": "MIT", "engines": { @@ -12417,85 +7681,6 @@ "typescript": ">=4.8.4" } }, - "node_modules/ts-jest": { - "version": "29.4.6", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.6.tgz", - "integrity": "sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA==", - "dev": true, - "license": "MIT", - "dependencies": { - "bs-logger": "^0.2.6", - "fast-json-stable-stringify": "^2.1.0", - "handlebars": "^4.7.8", - "json5": "^2.2.3", - "lodash.memoize": "^4.1.2", - "make-error": "^1.3.6", - "semver": "^7.7.3", - "type-fest": "^4.41.0", - "yargs-parser": "^21.1.1" - }, - "bin": { - "ts-jest": "cli.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" - }, - "peerDependencies": { - "@babel/core": ">=7.0.0-beta.0 <8", - "@jest/transform": "^29.0.0 || ^30.0.0", - "@jest/types": "^29.0.0 || ^30.0.0", - "babel-jest": "^29.0.0 || ^30.0.0", - "jest": "^29.0.0 || ^30.0.0", - "jest-util": "^29.0.0 || ^30.0.0", - "typescript": ">=4.3 <6" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "@jest/transform": { - "optional": true - }, - "@jest/types": { - "optional": true - }, - "babel-jest": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "jest-util": { - "optional": true - } - } - }, - "node_modules/ts-jest/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ts-jest/node_modules/type-fest": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", - "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/tsconfig-paths": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", @@ -12541,29 +7726,6 @@ "node": ">= 0.8.0" } }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/typed-array-buffer": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", @@ -12657,16 +7819,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.56.0.tgz", - "integrity": "sha512-c7toRLrotJ9oixgdW7liukZpsnq5CZ7PuKztubGYlNppuTqhIoWfhgHo/7EU0v06gS2l/x0i2NEFK1qMIf0rIg==", + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.58.2.tgz", + "integrity": "sha512-V8iSng9mRbdZjl54VJ9NKr6ZB+dW0J3TzRXRGcSbLIej9jV86ZRtlYeTKDR/QLxXykocJ5icNzbsl2+5TzIvcQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.56.0", - "@typescript-eslint/parser": "8.56.0", - "@typescript-eslint/typescript-estree": "8.56.0", - "@typescript-eslint/utils": "8.56.0" + "@typescript-eslint/eslint-plugin": "8.58.2", + "@typescript-eslint/parser": "8.58.2", + "@typescript-eslint/typescript-estree": "8.58.2", + "@typescript-eslint/utils": "8.58.2" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -12677,21 +7839,7 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/uglify-js": { - "version": "3.19.3", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", - "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", - "dev": true, - "license": "BSD-2-Clause", - "optional": true, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/unbox-primitive": { @@ -12910,21 +8058,6 @@ "punycode": "^2.1.0" } }, - "node_modules/v8-to-istanbul": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", - "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", - "dev": true, - "license": "ISC", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^2.0.0" - }, - "engines": { - "node": ">=10.12.0" - } - }, "node_modules/vfile": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", @@ -12967,29 +8100,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/w3c-xmlserializer": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", - "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "xml-name-validator": "^5.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "makeerror": "1.0.12" - } - }, "node_modules/web-namespaces": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", @@ -13000,54 +8110,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-encoding": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", - "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", - "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", - "dev": true, - "license": "MIT", - "dependencies": { - "iconv-lite": "0.6.3" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/whatwg-mimetype": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", - "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/whatwg-url": { - "version": "14.2.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", - "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", - "dev": true, - "license": "MIT", - "dependencies": { - "tr46": "^5.1.0", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -13163,123 +8225,10 @@ "node": ">=0.10.0" } }, - "node_modules/wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/wrap-ansi-cjs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/write-file-atomic": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", - "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", - "dev": true, - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/ws": { - "version": "8.19.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", - "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", + "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -13297,33 +8246,6 @@ } } }, - "node_modules/xml-name-validator": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", - "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18" - } - }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true, - "license": "MIT" - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", @@ -13331,70 +8253,6 @@ "dev": true, "license": "ISC" }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/yargs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 75347ebf..991a0fc0 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,21 +1,18 @@ { - "name": "frontend", + "name": "sapling-frontend", "version": "0.1.0", "private": true, "scripts": { "dev": "next dev", "build": "next build", "start": "next start", - "lint": "eslint", - "test": "jest", - "test:watch": "jest --watch" + "lint": "next lint", + "typecheck": "tsc --noEmit" }, "dependencies": { "@supabase/supabase-js": "^2.99.3", "d3": "^7.9.0", - "framer-motion": "^12.38.0", - "katex": "^0.16.40", - "lucide-react": "^0.577.0", + "katex": "^0.16.45", "next": "16.1.6", "react": "19.2.3", "react-dom": "19.2.3", @@ -24,22 +21,12 @@ "remark-math": "^6.0.0" }, "devDependencies": { - "@tailwindcss/postcss": "^4", - "@testing-library/jest-dom": "^6.9.1", - "@testing-library/react": "^16.3.2", - "@testing-library/user-event": "^14.6.1", "@types/d3": "^7.4.3", - "@types/jest": "^30.0.0", "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", - "babel-plugin-react-compiler": "1.0.0", "eslint": "^9", "eslint-config-next": "16.1.6", - "jest": "^30.2.0", - "jest-environment-jsdom": "^30.2.0", - "tailwindcss": "^4", - "ts-jest": "^29.4.6", "typescript": "^5" } } diff --git a/frontend/postcss.config.mjs b/frontend/postcss.config.mjs deleted file mode 100644 index 61e36849..00000000 --- a/frontend/postcss.config.mjs +++ /dev/null @@ -1,7 +0,0 @@ -const config = { - plugins: { - "@tailwindcss/postcss": {}, - }, -}; - -export default config; diff --git a/frontend/public/sapling-icon.svg b/frontend/public/sapling-icon.svg deleted file mode 100644 index 361b5a78..00000000 --- a/frontend/public/sapling-icon.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/frontend/public/sapling-word-icon.png b/frontend/public/sapling-word-icon.png deleted file mode 100644 index 54bfd903f33d5d9fe722b4f972e5398d8bd935df..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40998 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 Yk+LXsHptOPM`}=1l{J-W70ko_2T06#!vFvP diff --git a/frontend/src/__mocks__/rehypeKatex.js b/frontend/src/__mocks__/rehypeKatex.js deleted file mode 100644 index cc40a464..00000000 --- a/frontend/src/__mocks__/rehypeKatex.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = () => {}; diff --git a/frontend/src/__mocks__/remarkMath.js b/frontend/src/__mocks__/remarkMath.js deleted file mode 100644 index cc40a464..00000000 --- a/frontend/src/__mocks__/remarkMath.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = () => {}; diff --git a/frontend/src/__mocks__/styleMock.js b/frontend/src/__mocks__/styleMock.js deleted file mode 100644 index f053ebf7..00000000 --- a/frontend/src/__mocks__/styleMock.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = {}; diff --git a/frontend/src/__tests__/README.md b/frontend/src/__tests__/README.md deleted file mode 100644 index 60d47f2f..00000000 --- a/frontend/src/__tests__/README.md +++ /dev/null @@ -1,57 +0,0 @@ -# Sapling Frontend — Test Suite - -All frontend tests live in `src/__tests__/`. Tests use **Jest** + **React Testing Library** and run fully offline (no backend required). - ---- - -## Quick start - -```bash -# From the frontend/ directory -cd frontend -npm test # run all tests once -npm run test:watch # watch mode — re-runs on file save -``` - ---- - -## Test files - -| File | What it covers | -|---|---| -| `graphUtils.test.ts` | All pure utility functions in `lib/graphUtils.ts` — colour mapping, mastery labels, radius, edge filtering, graph diffing, date formatting | -| `api.test.ts` | Every function in `lib/api.ts` — verifies correct URL, HTTP method, and request body; tests error handling when the server returns a non-OK status | -| `chatPanel.test.tsx` | `ChatPanel` component — message rendering, send button state, Enter-key submission, hint/confused/skip actions, loading indicator | -| `sessionSummary.test.tsx` | `SessionSummary` component — concepts covered, mastery change deltas, time spent (singular/plural), recommended next, button callbacks | -| `dataFetching.test.tsx` | useEffect fetch guards — ensures pages don't fetch before `userReady`, and re-fetch when `userId` changes | -| `hydration.test.tsx` | Next.js hydration and SearchParams safety | -| `userContext.test.tsx` | `UserContext` provider — user list loading, active user switching | - ---- - -## Adding new tests - -- **Pure functions** (utilities, helpers) → `graphUtils.test.ts` or a new `*.test.ts` -- **API calls** → `api.test.ts` — mock `global.fetch`, assert on URL/method/body -- **Components** → new `componentName.test.tsx` — use `@testing-library/react`, query by role/text, avoid testing implementation details - -### Mocking fetch - -```ts -beforeEach(() => { - global.fetch = jest.fn().mockResolvedValue({ - ok: true, - json: () => Promise.resolve({ your: 'data' }), - text: () => Promise.resolve(''), - }) as jest.Mock; -}); -afterEach(() => jest.resetAllMocks()); -``` - -### Mocking the API module - -```ts -jest.mock('@/lib/api', () => ({ - getGraph: jest.fn(() => Promise.resolve({ nodes: [], edges: [], stats: {} })), -})); -``` diff --git a/frontend/src/__tests__/achievementCard.test.tsx b/frontend/src/__tests__/achievementCard.test.tsx deleted file mode 100644 index 956172ef..00000000 --- a/frontend/src/__tests__/achievementCard.test.tsx +++ /dev/null @@ -1,80 +0,0 @@ -/** - * Tests for components/AchievementCard.tsx - * - * Covers: earned vs locked rendering, secret achievement masking, - * compact mode, progress bar, click handler. - */ -import React from 'react'; -import { render, screen, fireEvent } from '@testing-library/react'; -import AchievementCard from '@/components/AchievementCard'; -import type { Achievement } from '@/lib/types'; - -const baseAchievement: Achievement = { - id: 'a1', - name: 'First Login', - slug: 'first_login', - description: 'Log in for the first time', - icon: null, - category: 'activity', - rarity: 'common', - is_secret: false, -}; - -afterEach(() => jest.clearAllMocks()); - -describe('AchievementCard', () => { - it('renders earned achievement name', () => { - render(); - expect(screen.getByText('First Login')).toBeInTheDocument(); - }); - - it('renders description when not compact', () => { - render(); - expect(screen.getByText('Log in for the first time')).toBeInTheDocument(); - }); - - it('hides description in compact mode', () => { - render(); - expect(screen.queryByText('Log in for the first time')).not.toBeInTheDocument(); - }); - - it('shows rarity label', () => { - render(); - expect(screen.getByText('common')).toBeInTheDocument(); - }); - - it('masks secret unearned achievement', () => { - render(); - expect(screen.getByText('Secret Achievement')).toBeInTheDocument(); - expect(screen.queryByText('First Login')).not.toBeInTheDocument(); - }); - - it('shows secret description placeholder when locked', () => { - render(); - expect(screen.getByText(/keep exploring/i)).toBeInTheDocument(); - }); - - it('does not mask secret achievement when earned', () => { - render(); - expect(screen.getByText('First Login')).toBeInTheDocument(); - expect(screen.queryByText('Secret Achievement')).not.toBeInTheDocument(); - }); - - it('renders earned date when provided and not compact', () => { - render(); - expect(screen.getByText(/earned/i)).toBeInTheDocument(); - }); - - it('fires onPress callback', () => { - const onPress = jest.fn(); - render(); - fireEvent.click(screen.getByText('First Login').closest('div')!); - expect(onPress).toHaveBeenCalledTimes(1); - }); - - it('renders different rarity tiers', () => { - const legendary: Achievement = { ...baseAchievement, rarity: 'legendary' }; - render(); - expect(screen.getByText('legendary')).toBeInTheDocument(); - }); -}); diff --git a/frontend/src/__tests__/api.test.ts b/frontend/src/__tests__/api.test.ts deleted file mode 100644 index 00465aad..00000000 --- a/frontend/src/__tests__/api.test.ts +++ /dev/null @@ -1,448 +0,0 @@ -/** - * Tests for lib/api.ts - * - * Verifies that each exported function calls the correct URL, HTTP method, - * and request body, and that errors from the server are surfaced correctly. - * `global.fetch` is mocked — no real network traffic. - */ - -// Silence Next.js build warnings about NEXT_PUBLIC_ env in test -process.env.NEXT_PUBLIC_API_URL = ''; - -import { - getUsers, - getGraph, - getRecommendations, - getCourses, - addCourse, - updateCourseColor, - deleteCourse, - startSession, - sendChat, - sendAction, - endSession, - getSessions, - generateQuiz, - submitQuiz, - getUpcomingAssignments, - extractSyllabus, - saveAssignments, - getCalendarStatus, - syncToGoogleCalendar, - exportToGoogleCalendar, - importGoogleEvents, - disconnectGoogleCalendar, - getDocuments, - deleteDocument, - updateDocument, - uploadDocument, -} from '@/lib/api'; - -// ── helpers ─────────────────────────────────────────────────────────────────── - -function mockFetch(data: unknown, ok = true, status = 200) { - global.fetch = jest.fn().mockResolvedValue({ - ok, - status, - json: () => Promise.resolve(data), - text: () => Promise.resolve(ok ? '' : JSON.stringify(data)), - }) as jest.Mock; -} - -function lastCall() { - return (global.fetch as jest.Mock).mock.calls[0] as [string, RequestInit | undefined]; -} - -afterEach(() => jest.resetAllMocks()); - -// ── fetchJSON error handling ────────────────────────────────────────────────── - -describe('fetchJSON error handling', () => { - it('throws when server returns a non-OK status', async () => { - mockFetch('Not found', false, 404); - await expect(getGraph('u1')).rejects.toThrow(); - }); - - it('includes the status code in the error message when body is empty', async () => { - global.fetch = jest.fn().mockResolvedValue({ - ok: false, - status: 502, - json: () => Promise.resolve({}), - text: () => Promise.resolve(''), - }) as jest.Mock; - await expect(getGraph('u1')).rejects.toThrow('HTTP 502'); - }); -}); - -// ── Users ───────────────────────────────────────────────────────────────────── - -describe('getUsers', () => { - it('GET /api/users', async () => { - mockFetch({ users: [] }); - await getUsers(); - const [url, opts] = lastCall(); - expect(url).toBe('/api/users'); - expect(opts?.method).toBeUndefined(); // default GET - }); -}); - -// ── Graph ───────────────────────────────────────────────────────────────────── - -describe('getGraph', () => { - it('GET /api/graph/:userId', async () => { - mockFetch({ nodes: [], edges: [], stats: {} }); - await getGraph('user_andres'); - expect(lastCall()[0]).toBe('/api/graph/user_andres'); - }); -}); - -describe('getRecommendations', () => { - it('GET /api/graph/:userId/recommendations', async () => { - mockFetch({ recommendations: [] }); - await getRecommendations('user_andres'); - expect(lastCall()[0]).toBe('/api/graph/user_andres/recommendations'); - }); -}); - -describe('getCourses', () => { - it('GET /api/graph/:userId/courses', async () => { - mockFetch({ courses: [] }); - await getCourses('user_andres'); - expect(lastCall()[0]).toBe('/api/graph/user_andres/courses'); - }); -}); - -describe('addCourse', () => { - it('POST /api/graph/:userId/courses with course_id', async () => { - mockFetch({ course_id: 'Math', already_existed: false }); - await addCourse('user_andres', 'Math'); - const [url, opts] = lastCall(); - expect(url).toBe('/api/graph/user_andres/courses'); - expect(opts?.method).toBe('POST'); - expect(JSON.parse(opts?.body as string)).toMatchObject({ course_id: 'Math' }); - }); - - it('includes color when provided', async () => { - mockFetch({ course_id: 'Math', already_existed: false }); - await addCourse('user_andres', 'Math', '#ff0000'); - const body = JSON.parse(lastCall()[1]?.body as string); - expect(body.color).toBe('#ff0000'); - }); -}); - -describe('updateCourseColor', () => { - it('PATCH /api/graph/:userId/courses/:name/color', async () => { - mockFetch({ updated: true }); - await updateCourseColor('user_andres', 'Math', '#123456'); - const [url, opts] = lastCall(); - expect(url).toBe('/api/graph/user_andres/courses/Math/color'); - expect(opts?.method).toBe('PATCH'); - expect(JSON.parse(opts?.body as string)).toEqual({ color: '#123456' }); - }); - - it('URL-encodes course names with spaces', async () => { - mockFetch({ updated: true }); - await updateCourseColor('user_andres', 'Linear Algebra', '#fff'); - expect(lastCall()[0]).toBe('/api/graph/user_andres/courses/Linear%20Algebra/color'); - }); -}); - -describe('deleteCourse', () => { - it('DELETE /api/graph/:userId/courses/:name', async () => { - mockFetch({ deleted: true }); - await deleteCourse('user_andres', 'Math'); - const [url, opts] = lastCall(); - expect(url).toBe('/api/graph/user_andres/courses/Math'); - expect(opts?.method).toBe('DELETE'); - }); -}); - -// ── Learn ───────────────────────────────────────────────────────────────────── - -describe('startSession', () => { - it('POST /api/learn/start-session with correct body', async () => { - mockFetch({ session_id: 's1', initial_message: 'Hi', graph_state: {} }); - await startSession('user_andres', 'Recursion', 'socratic'); - const [url, opts] = lastCall(); - expect(url).toBe('/api/learn/start-session'); - expect(opts?.method).toBe('POST'); - const body = JSON.parse(opts?.body as string); - expect(body).toMatchObject({ user_id: 'user_andres', topic: 'Recursion', mode: 'socratic' }); - }); -}); - -describe('sendChat', () => { - it('POST /api/learn/chat with session_id and message', async () => { - mockFetch({ reply: 'Hello', graph_update: {}, mastery_changes: [] }); - await sendChat('s1', 'user_andres', 'Hello?', 'socratic'); - const [url, opts] = lastCall(); - expect(url).toBe('/api/learn/chat'); - const body = JSON.parse(opts?.body as string); - expect(body).toMatchObject({ session_id: 's1', user_id: 'user_andres', message: 'Hello?' }); - }); -}); - -describe('sendAction', () => { - it('POST /api/learn/action with action_type', async () => { - mockFetch({ reply: 'Here is a hint', graph_update: {} }); - await sendAction('s1', 'user_andres', 'hint', 'socratic'); - const body = JSON.parse(lastCall()[1]?.body as string); - expect(body).toMatchObject({ session_id: 's1', action_type: 'hint' }); - }); -}); - -describe('endSession', () => { - it('POST /api/learn/end-session with session_id and user_id', async () => { - mockFetch({ summary: {} }); - await endSession('s1', 'user_andres'); - const [url, opts] = lastCall(); - expect(url).toBe('/api/learn/end-session'); - expect(JSON.parse(opts?.body as string)).toEqual({ session_id: 's1', user_id: 'user_andres' }); - }); -}); - -describe('getSessions', () => { - it('GET /api/learn/sessions/:userId?limit=N', async () => { - mockFetch({ sessions: [] }); - await getSessions('user_andres', 5); - expect(lastCall()[0]).toBe('/api/learn/sessions/user_andres?limit=5'); - }); - - it('defaults to limit=10', async () => { - mockFetch({ sessions: [] }); - await getSessions('user_andres'); - expect(lastCall()[0]).toContain('limit=10'); - }); -}); - -// ── Quiz ────────────────────────────────────────────────────────────────────── - -describe('generateQuiz', () => { - it('POST /api/quiz/generate with correct body', async () => { - mockFetch({ quiz_id: 'q1', questions: [] }); - await generateQuiz('user_andres', 'node1', 5, 'medium'); - const [url, opts] = lastCall(); - expect(url).toBe('/api/quiz/generate'); - const body = JSON.parse(opts?.body as string); - expect(body).toMatchObject({ - user_id: 'user_andres', - concept_node_id: 'node1', - num_questions: 5, - difficulty: 'medium', - }); - }); -}); - -describe('submitQuiz', () => { - it('POST /api/quiz/submit with quiz_id and answers', async () => { - mockFetch({ score: 4, total: 5, mastery_before: 0.5, mastery_after: 0.62, results: [] }); - const answers = [{ question_id: 1, selected_label: 'A' }]; - await submitQuiz('q1', answers); - const [url, opts] = lastCall(); - expect(url).toBe('/api/quiz/submit'); - const body = JSON.parse(opts?.body as string); - expect(body).toEqual({ quiz_id: 'q1', answers }); - }); -}); - -// ── Calendar ────────────────────────────────────────────────────────────────── - -describe('getUpcomingAssignments', () => { - it('GET /api/calendar/upcoming/:userId', async () => { - mockFetch({ assignments: [] }); - await getUpcomingAssignments('user_andres'); - expect(lastCall()[0]).toBe('/api/calendar/upcoming/user_andres'); - }); -}); - -describe('extractSyllabus', () => { - it('POST /api/calendar/extract with FormData and returns JSON on success', async () => { - mockFetch({ assignments: [], warnings: [] }); - const fd = new FormData(); - fd.append('file', new Blob(['x'], { type: 'application/pdf' }), 's.pdf'); - const res = await extractSyllabus(fd, 'user_andres'); - expect(lastCall()[0]).toBe('/api/calendar/extract'); - expect(lastCall()[1]?.method).toBe('POST'); - expect(res.assignments).toEqual([]); - }); - - it('throws with detail message when response is not OK', async () => { - mockFetch({ detail: 'Invalid file' }, false, 400); - const fd = new FormData(); - await expect(extractSyllabus(fd)).rejects.toThrow('Invalid file'); - }); - - it('throws with HTTP status when body has no detail', async () => { - mockFetch({}, false, 502); - const fd = new FormData(); - await expect(extractSyllabus(fd)).rejects.toThrow('Request failed (HTTP 502).'); - }); - - it('throws joining FastAPI validation detail array', async () => { - mockFetch( - { detail: [{ msg: 'field required' }, { msg: 'invalid type' }] }, - false, - 422 - ); - const fd = new FormData(); - await expect(extractSyllabus(fd)).rejects.toThrow('field required; invalid type'); - }); -}); - -describe('saveAssignments', () => { - it('POST /api/calendar/save with user_id and assignments', async () => { - mockFetch({ saved_count: 2 }); - const assignments = [{ title: 'HW1', due_date: '2026-03-01', assignment_type: 'homework', course_id: 'c1' }]; - await saveAssignments('user_andres', assignments); - const [url, opts] = lastCall(); - expect(url).toBe('/api/calendar/save'); - const body = JSON.parse(opts?.body as string); - expect(body).toMatchObject({ user_id: 'user_andres', assignments }); - }); -}); - -describe('getCalendarStatus', () => { - it('GET /api/calendar/status/:userId', async () => { - mockFetch({ connected: false }); - await getCalendarStatus('user_andres'); - expect(lastCall()[0]).toBe('/api/calendar/status/user_andres'); - }); -}); - -describe('syncToGoogleCalendar', () => { - it('POST /api/calendar/sync with user_id', async () => { - mockFetch({ synced_count: 3 }); - await syncToGoogleCalendar('user_andres'); - const [url, opts] = lastCall(); - expect(url).toBe('/api/calendar/sync'); - expect(JSON.parse(opts?.body as string)).toEqual({ user_id: 'user_andres' }); - }); -}); - -describe('exportToGoogleCalendar', () => { - it('POST /api/calendar/export with user_id and assignment_ids', async () => { - mockFetch({ exported_count: 1, skipped_count: 0 }); - await exportToGoogleCalendar('user_andres', ['a1', 'a2']); - const body = JSON.parse(lastCall()[1]?.body as string); - expect(body).toEqual({ user_id: 'user_andres', assignment_ids: ['a1', 'a2'] }); - }); -}); - -describe('importGoogleEvents', () => { - it('GET /api/calendar/import/:userId?days_ahead=N', async () => { - mockFetch({ events: [], count: 0 }); - await importGoogleEvents('user_andres', 14); - expect(lastCall()[0]).toBe('/api/calendar/import/user_andres?days_ahead=14'); - }); - - it('defaults to days_ahead=30', async () => { - mockFetch({ events: [], count: 0 }); - await importGoogleEvents('user_andres'); - expect(lastCall()[0]).toContain('days_ahead=30'); - }); -}); - -describe('disconnectGoogleCalendar', () => { - it('DELETE /api/calendar/disconnect/:userId', async () => { - mockFetch({ disconnected: true }); - await disconnectGoogleCalendar('user_andres'); - const [url, opts] = lastCall(); - expect(url).toBe('/api/calendar/disconnect/user_andres'); - expect(opts?.method).toBe('DELETE'); - }); -}); - -// ── Documents ───────────────────────────────────────────────────────────────── - -describe('getDocuments', () => { - it('GET /api/documents/user/:userId', async () => { - mockFetch({ documents: [] }); - await getDocuments('user_andres'); - expect(lastCall()[0]).toBe('/api/documents/user/user_andres'); - }); - - it('returns documents array from response', async () => { - const docs = [{ id: 'd1', file_name: 'notes.pdf', category: 'lecture_notes' }]; - mockFetch({ documents: docs }); - const result = await getDocuments('user_andres'); - expect(result.documents).toEqual(docs); - }); -}); - -describe('deleteDocument', () => { - it('DELETE /api/documents/doc/:documentId', async () => { - mockFetch({ deleted: true }); - await deleteDocument('doc-uuid-123'); - const [url, opts] = lastCall(); - expect(url).toBe('/api/documents/doc/doc-uuid-123'); - expect(opts?.method).toBe('DELETE'); - }); - - it('includes user_id query param when provided', async () => { - mockFetch({ deleted: true }); - await deleteDocument('doc-uuid-123', 'user_andres'); - const [url] = lastCall(); - expect(url).toBe('/api/documents/doc/doc-uuid-123?user_id=user_andres'); - }); - - it('throws on server error', async () => { - mockFetch('Not found', false, 404); - await expect(deleteDocument('bad-id')).rejects.toThrow(); - }); -}); - -describe('updateDocument', () => { - it('PATCH /api/documents/doc/:documentId with body', async () => { - mockFetch({ id: 'd1', category: 'slides' }); - await updateDocument('d1', { category: 'slides', user_id: 'u1' }); - const [url, opts] = lastCall(); - expect(url).toBe('/api/documents/doc/d1'); - expect(opts?.method).toBe('PATCH'); - expect(JSON.parse(opts?.body as string)).toEqual({ category: 'slides', user_id: 'u1' }); - }); -}); - -describe('uploadDocument', () => { - it('POST /api/documents/upload with FormData', async () => { - const mockDoc = { id: 'd1', file_name: 'notes.pdf', category: 'lecture_notes' }; - global.fetch = jest.fn().mockResolvedValue({ - ok: true, - status: 200, - json: () => Promise.resolve(mockDoc), - }) as jest.Mock; - - const fd = new FormData(); - fd.append('file', new Blob(['content'], { type: 'application/pdf' }), 'notes.pdf'); - fd.append('course_id', 'c1'); - fd.append('user_id', 'user_andres'); - - const result = await uploadDocument(fd); - const [url, opts] = lastCall(); - expect(url).toBe('/api/documents/upload'); - expect(opts?.method).toBe('POST'); - expect(opts?.body).toBe(fd); - expect(result.id).toBe('d1'); - }); - - it('throws when server returns non-OK status', async () => { - global.fetch = jest.fn().mockResolvedValue({ - ok: false, - status: 400, - text: () => Promise.resolve('Unsupported file type'), - }) as jest.Mock; - - const fd = new FormData(); - await expect(uploadDocument(fd)).rejects.toThrow('Unsupported file type'); - }); - - it('throws with HTTP status when body is empty', async () => { - global.fetch = jest.fn().mockResolvedValue({ - ok: false, - status: 413, - text: () => Promise.resolve(''), - }) as jest.Mock; - - const fd = new FormData(); - await expect(uploadDocument(fd)).rejects.toThrow('HTTP 413'); - }); -}); diff --git a/frontend/src/__tests__/authAndPrefillWiring.test.ts b/frontend/src/__tests__/authAndPrefillWiring.test.ts deleted file mode 100644 index 0db714b3..00000000 --- a/frontend/src/__tests__/authAndPrefillWiring.test.ts +++ /dev/null @@ -1,30 +0,0 @@ -import fs from 'fs'; -import path from 'path'; - -const SRC = path.resolve(__dirname, '../../src'); - -function readSrc(rel: string) { - return fs.readFileSync(path.join(SRC, rel), 'utf8'); -} - -describe('Navbar auth guard', () => { - const src = readSrc('components/Navbar.tsx'); - - test('reads userReady from useUser', () => { - expect(src).toMatch(/useUser\(\)/); - expect(src).toMatch(/userReady/); - }); - - test('gates signin redirect on userReady', () => { - // Redirect must wait until localStorage hydration has completed. - expect(src).toMatch(/if\s*\(\s*userReady\s*&&\s*!isAuthenticated/); - }); -}); - -describe('Learn page prefill wiring', () => { - const src = readSrc('app/learn/page.tsx'); - - test('passes prefillInput prop to ChatPanel', () => { - expect(src).toMatch(/ so we can assert -// on text content without worrying about markdown parsing in jsdom. -jest.mock('react-markdown', () => ({ children }: { children: React.ReactNode }) =>
{children}
); - -// ── helpers ─────────────────────────────────────────────────────────────────── - -function makeMsg(id: string, role: 'user' | 'assistant', content: string): ChatMessage { - return { id, role, content, timestamp: new Date().toISOString() }; -} - -const defaultProps = { - messages: [] as ChatMessage[], - onSend: jest.fn(), - onAction: jest.fn(), - onEndSession: jest.fn(), - loading: false, - mode: 'socratic' as TeachingMode, -}; - -function renderPanel(overrides: Partial = {}) { - return render(); -} - -afterEach(() => jest.clearAllMocks()); - -// ── mode description ────────────────────────────────────────────────────────── - -describe('mode description', () => { - it('shows socratic description', () => { - renderPanel({ mode: 'socratic' }); - expect(screen.getByText(/asking questions/i)).toBeInTheDocument(); - }); - - it('shows expository description', () => { - renderPanel({ mode: 'expository' }); - expect(screen.getByText(/explaining/i)).toBeInTheDocument(); - }); - - it('shows teachback description', () => { - renderPanel({ mode: 'teachback' }); - expect(screen.getByText(/you teach me/i)).toBeInTheDocument(); - }); -}); - -// ── message rendering ───────────────────────────────────────────────────────── - -describe('message rendering', () => { - it('renders no messages when list is empty', () => { - renderPanel(); - expect(screen.queryByRole('textbox')).toBeInTheDocument(); // textarea should still exist - }); - - it('renders user messages', () => { - renderPanel({ messages: [makeMsg('1', 'user', 'What is recursion?')] }); - expect(screen.getByText('What is recursion?')).toBeInTheDocument(); - }); - - it('renders assistant messages', () => { - renderPanel({ messages: [makeMsg('1', 'assistant', 'Recursion is self-reference.')] }); - expect(screen.getByText('Recursion is self-reference.')).toBeInTheDocument(); - }); - - it('renders multiple messages in order', () => { - const messages = [ - makeMsg('1', 'user', 'First message'), - makeMsg('2', 'assistant', 'Second message'), - makeMsg('3', 'user', 'Third message'), - ]; - renderPanel({ messages }); - const items = screen.getAllByText(/First|Second|Third/); - expect(items).toHaveLength(3); - }); -}); - -// ── loading indicator ───────────────────────────────────────────────────────── - -describe('loading indicator', () => { - it('shows typing indicator when loading=true', () => { - renderPanel({ loading: true }); - expect(screen.getByText('···')).toBeInTheDocument(); - }); - - it('hides typing indicator when loading=false', () => { - renderPanel({ loading: false }); - expect(screen.queryByText('···')).not.toBeInTheDocument(); - }); -}); - -// ── send button ─────────────────────────────────────────────────────────────── - -describe('send button', () => { - it('is disabled when input is empty', () => { - renderPanel(); - expect(screen.getByRole('button', { name: /send/i })).toBeDisabled(); - }); - - it('is disabled when loading=true even with text typed', () => { - renderPanel({ loading: true }); - const textarea = screen.getByRole('textbox'); - fireEvent.change(textarea, { target: { value: 'Hello' } }); - expect(screen.getByRole('button', { name: /send/i })).toBeDisabled(); - }); - - it('is enabled when there is text and not loading', () => { - renderPanel(); - const textarea = screen.getByRole('textbox'); - fireEvent.change(textarea, { target: { value: 'Hello' } }); - expect(screen.getByRole('button', { name: /send/i })).not.toBeDisabled(); - }); - - it('calls onSend with trimmed message when clicked', () => { - const onSend = jest.fn(); - renderPanel({ onSend }); - const textarea = screen.getByRole('textbox'); - fireEvent.change(textarea, { target: { value: ' hello world ' } }); - fireEvent.click(screen.getByRole('button', { name: /send/i })); - expect(onSend).toHaveBeenCalledWith('hello world'); - }); - - it('clears the input after sending', () => { - renderPanel(); - const textarea = screen.getByRole('textbox') as HTMLTextAreaElement; - fireEvent.change(textarea, { target: { value: 'Hello' } }); - fireEvent.click(screen.getByRole('button', { name: /send/i })); - expect(textarea.value).toBe(''); - }); - - it('does not call onSend when input is whitespace only', () => { - const onSend = jest.fn(); - renderPanel({ onSend }); - const textarea = screen.getByRole('textbox'); - fireEvent.change(textarea, { target: { value: ' ' } }); - fireEvent.click(screen.getByRole('button', { name: /send/i })); - expect(onSend).not.toHaveBeenCalled(); - }); -}); - -// ── Enter key ───────────────────────────────────────────────────────────────── - -describe('Enter key behaviour', () => { - it('sends on Enter without shift', () => { - const onSend = jest.fn(); - renderPanel({ onSend }); - const textarea = screen.getByRole('textbox'); - fireEvent.change(textarea, { target: { value: 'hi' } }); - fireEvent.keyDown(textarea, { key: 'Enter', shiftKey: false }); - expect(onSend).toHaveBeenCalledWith('hi'); - }); - - it('does not send on Shift+Enter', () => { - const onSend = jest.fn(); - renderPanel({ onSend }); - const textarea = screen.getByRole('textbox'); - fireEvent.change(textarea, { target: { value: 'hi' } }); - fireEvent.keyDown(textarea, { key: 'Enter', shiftKey: true }); - expect(onSend).not.toHaveBeenCalled(); - }); -}); - -// ── action buttons ──────────────────────────────────────────────────────────── - -describe('action buttons', () => { - it.each(['hint', 'confused', 'skip'] as const)( - 'calls onAction with "%s" when clicked', - (action) => { - const onAction = jest.fn(); - renderPanel({ onAction }); - fireEvent.click(screen.getByRole('button', { name: new RegExp(action, 'i') })); - expect(onAction).toHaveBeenCalledWith(action); - } - ); - - it('action buttons are disabled while loading', () => { - renderPanel({ loading: true }); - const hintBtn = screen.getByRole('button', { name: /hint/i }); - expect(hintBtn).toBeDisabled(); - }); -}); - -// ── End Session ─────────────────────────────────────────────────────────────── - -describe('End Session button', () => { - it('calls onEndSession when clicked', () => { - const onEndSession = jest.fn(); - renderPanel({ onEndSession }); - fireEvent.click(screen.getByRole('button', { name: /end session/i })); - expect(onEndSession).toHaveBeenCalledTimes(1); - }); -}); diff --git a/frontend/src/__tests__/dataFetching.test.tsx b/frontend/src/__tests__/dataFetching.test.tsx deleted file mode 100644 index 5a1f10cf..00000000 --- a/frontend/src/__tests__/dataFetching.test.tsx +++ /dev/null @@ -1,217 +0,0 @@ -/** - * Tests that each page's data-fetching useEffect: - * 1. Does NOT fire before userReady is true (prevents fetching with wrong default userId) - * 2. DOES fire once userReady becomes true with the correct userId - * 3. Re-fires when userId changes (so switching users always loads fresh data) - * - * We mock the API module and the UserContext so tests are fully isolated. - */ -import React, { useEffect, useState } from 'react'; -import { render, act, waitFor } from '@testing-library/react'; -import { UserContext } from '@/context/UserContext'; - -// ─── helpers ──────────────────────────────────────────────────────────────── - -type ContextValue = { - userId: string; - userName: string; - users: never[]; - userReady: boolean; - setActiveUser: () => void; -}; - -function makeContext(overrides: Partial): ContextValue { - return { - userId: 'user_andres', - userName: 'Andres Lopez', - users: [], - userReady: false, - setActiveUser: () => {}, - ...overrides, - }; -} - -// Minimal wrapper that lets us swap context values mid-test -function ContextWrapper({ - value, - children, -}: { - value: ContextValue; - children: React.ReactNode; -}) { - return ( - {children} - ); -} - -// ─── Dashboard (page.tsx) ──────────────────────────────────────────────────── - -jest.mock('@/lib/api', () => ({ - getGraph: jest.fn(() => Promise.resolve({ nodes: [], edges: [], stats: {} })), - getRecommendations: jest.fn(() => Promise.resolve({ recommendations: [] })), - getUpcomingAssignments: jest.fn(() => Promise.resolve({ assignments: [] })), - getSessions: jest.fn(() => Promise.resolve({ sessions: [] })), - getUserRooms: jest.fn(() => Promise.resolve({ rooms: [] })), -})); - -import * as api from '@/lib/api'; - -afterEach(() => jest.clearAllMocks()); - -// ─── Isolated hook that mirrors the Dashboard fetch logic ──────────────────── - -function useDashboardData(userId: string, userReady: boolean) { - const [fetched, setFetched] = useState(false); - useEffect(() => { - if (!userReady) return; - (api.getGraph as jest.Mock)(userId).then(() => setFetched(true)); - }, [userId, userReady]); - return fetched; -} - -function DashboardHookHarness({ - userId, - userReady, -}: { - userId: string; - userReady: boolean; -}) { - const fetched = useDashboardData(userId, userReady); - return
{String(fetched)}
; -} - -test('dashboard: does not fetch when userReady is false', () => { - render(); - expect(api.getGraph).not.toHaveBeenCalled(); -}); - -test('dashboard: fetches once userReady becomes true', async () => { - const { rerender } = render( - - ); - expect(api.getGraph).not.toHaveBeenCalled(); - - rerender(); - await waitFor(() => expect(api.getGraph).toHaveBeenCalledWith('user_jose')); -}); - -test('dashboard: re-fetches when userId changes', async () => { - const { rerender } = render( - - ); - await waitFor(() => expect(api.getGraph).toHaveBeenCalledWith('user_andres')); - - rerender(); - await waitFor(() => expect(api.getGraph).toHaveBeenCalledWith('user_jose')); - expect(api.getGraph).toHaveBeenCalledTimes(2); -}); - -// ─── Isolated hook that mirrors the Tree page fetch logic ──────────────────── - -function useTreeData(userId: string, userReady: boolean) { - const [fetched, setFetched] = useState(false); - useEffect(() => { - if (!userReady) return; - (api.getGraph as jest.Mock)(userId).then(() => setFetched(true)); - }, [userId, userReady]); - return fetched; -} - -function TreeHookHarness({ userId, userReady }: { userId: string; userReady: boolean }) { - useTreeData(userId, userReady); - return null; -} - -test('tree: does not fetch when userReady is false', () => { - render(); - expect(api.getGraph).not.toHaveBeenCalled(); -}); - -test('tree: re-fetches when userId changes after userReady', async () => { - const { rerender } = render(); - await waitFor(() => expect(api.getGraph).toHaveBeenCalledWith('user_a')); - - rerender(); - await waitFor(() => expect(api.getGraph).toHaveBeenCalledWith('user_b')); - expect(api.getGraph).toHaveBeenCalledTimes(2); -}); - -// ─── Isolated hook that mirrors the Learn page fetch logic ─────────────────── - -function useLearnData(userId: string, userReady: boolean) { - const [fetched, setFetched] = useState(false); - useEffect(() => { - if (!userReady) return; - Promise.all([ - (api.getGraph as jest.Mock)(userId), - (api.getSessions as jest.Mock)(userId, 10), - ]).then(() => setFetched(true)); - }, [userId, userReady]); - return fetched; -} - -function LearnHookHarness({ userId, userReady }: { userId: string; userReady: boolean }) { - useLearnData(userId, userReady); - return null; -} - -test('learn: does not fetch graph/sessions when userReady is false', () => { - render(); - expect(api.getGraph).not.toHaveBeenCalled(); - expect(api.getSessions).not.toHaveBeenCalled(); -}); - -test('learn: fetches graph and sessions for correct user once ready', async () => { - render(); - await waitFor(() => { - expect(api.getGraph).toHaveBeenCalledWith('user_jose'); - expect(api.getSessions).toHaveBeenCalledWith('user_jose', 10); - }); -}); - -test('learn: re-fetches both graph and sessions when userId changes', async () => { - const { rerender } = render(); - await waitFor(() => expect(api.getGraph).toHaveBeenCalledWith('user_a')); - - rerender(); - await waitFor(() => expect(api.getGraph).toHaveBeenCalledWith('user_b')); - expect(api.getGraph).toHaveBeenCalledTimes(2); - expect(api.getSessions).toHaveBeenCalledTimes(2); -}); - -// ─── Isolated hook that mirrors the Social page fetch logic ────────────────── - -function useSocialData(userId: string, userReady: boolean) { - const [fetched, setFetched] = useState(false); - useEffect(() => { - if (!userReady) return; - (api.getUserRooms as jest.Mock)(userId).then(() => setFetched(true)); - }, [userId, userReady]); - return fetched; -} - -function SocialHookHarness({ userId, userReady }: { userId: string; userReady: boolean }) { - useSocialData(userId, userReady); - return null; -} - -test('social: does not fetch rooms when userReady is false', () => { - render(); - expect(api.getUserRooms).not.toHaveBeenCalled(); -}); - -test('social: fetches rooms for correct user once ready', async () => { - render(); - await waitFor(() => - expect(api.getUserRooms).toHaveBeenCalledWith('user_jose') - ); -}); - -test('social: re-fetches rooms when userId changes', async () => { - const { rerender } = render(); - await waitFor(() => expect(api.getUserRooms).toHaveBeenCalledWith('user_a')); - - rerender(); - await waitFor(() => expect(api.getUserRooms).toHaveBeenCalledWith('user_b')); - expect(api.getUserRooms).toHaveBeenCalledTimes(2); -}); diff --git a/frontend/src/__tests__/graphUtils.test.ts b/frontend/src/__tests__/graphUtils.test.ts deleted file mode 100644 index c9687419..00000000 --- a/frontend/src/__tests__/graphUtils.test.ts +++ /dev/null @@ -1,297 +0,0 @@ -/** - * Tests for lib/graphUtils.ts — all exported pure utility functions. - * No component rendering, no API calls, no mocks needed. - */ -import { - hexToCourseColor, - getCourseColor, - getMasteryColor, - getMasteryHighlightColor, - getMasteryLabel, - getNodeRadius, - filterCrossSubjectEdges, - computeGraphDiff, - formatRelativeTime, - formatDueDate, - daysUntil, - PRESET_COURSE_COLORS, -} from '@/lib/graphUtils'; -import type { GraphNode, GraphEdge } from '@/lib/types'; - -// ── hexToCourseColor ────────────────────────────────────────────────────────── - -describe('hexToCourseColor', () => { - it('builds correct rgba values from a valid hex', () => { - const result = hexToCourseColor('#ff0000'); - expect(result.fill).toBe('#ff0000'); - expect(result.bg).toMatch(/^rgba\(255,0,0,/); - expect(result.border).toMatch(/^rgba\(255,0,0,/); - }); - - it('returns the first palette colour for an invalid hex', () => { - const fallback = hexToCourseColor('not-a-hex'); - expect(fallback.fill).toBe(PRESET_COURSE_COLORS[0]); - }); - - it('returns the first palette colour for a 3-digit hex shorthand', () => { - // Our implementation requires 6-digit hex - const fallback = hexToCourseColor('#fff'); - expect(fallback.fill).toBe(PRESET_COURSE_COLORS[0]); - }); -}); - -// ── getCourseColor ──────────────────────────────────────────────────────────── - -describe('getCourseColor', () => { - it('returns a colour object with required shape', () => { - const result = getCourseColor('Mathematics'); - expect(result).toHaveProperty('fill'); - expect(result).toHaveProperty('bg'); - expect(result).toHaveProperty('text'); - expect(result).toHaveProperty('border'); - }); - - it('is deterministic — same input always yields same colour', () => { - expect(getCourseColor('CS101')).toEqual(getCourseColor('CS101')); - }); - - it('maps different subjects to palette colours (may differ)', () => { - // Two sufficiently different strings should hash to different indices at least sometimes - const colours = new Set( - ['Alpha', 'Beta', 'Gamma', 'Delta', 'Epsilon', 'Zeta'].map(s => getCourseColor(s).fill) - ); - expect(colours.size).toBeGreaterThan(1); - }); - - it('returns first palette colour for empty string', () => { - expect(getCourseColor('').fill).toBe(PRESET_COURSE_COLORS[0]); - }); - - it('respects a valid overrideHex', () => { - const result = getCourseColor('Math', '#123456'); - expect(result.fill).toBe('#123456'); - }); - - it('ignores an invalid overrideHex and falls back to hash', () => { - const withOverride = getCourseColor('Math', 'not-a-hex'); - const withoutOverride = getCourseColor('Math'); - expect(withOverride).toEqual(withoutOverride); - }); -}); - -// ── getMasteryColor / getMasteryHighlightColor ──────────────────────────────── - -describe('getMasteryColor', () => { - it.each([ - ['mastered', '#16a34a'], - ['learning', '#d97706'], - ['struggling', '#dc2626'], - ['unexplored', '#6b7280'], - ['subject_root', '#7c3aed'], - ])('returns correct colour for %s', (tier, expected) => { - expect(getMasteryColor(tier)).toBe(expected); - }); - - it('returns fallback for unknown tier', () => { - expect(getMasteryColor('invented_tier')).toBe('#475569'); - }); -}); - -describe('getMasteryHighlightColor', () => { - it('returns a highlight for mastered', () => { - expect(getMasteryHighlightColor('mastered')).toBe('#86efac'); - }); - - it('returns fallback for unknown tier', () => { - expect(getMasteryHighlightColor('???')).toBe('#94a3b8'); - }); -}); - -// ── getMasteryLabel ─────────────────────────────────────────────────────────── - -describe('getMasteryLabel', () => { - it('formats 0.0 as 0%', () => { - expect(getMasteryLabel(0.0)).toBe('0%'); - }); - - it('formats 1.0 as 100%', () => { - expect(getMasteryLabel(1.0)).toBe('100%'); - }); - - it('rounds to nearest integer', () => { - expect(getMasteryLabel(0.456)).toBe('46%'); - expect(getMasteryLabel(0.754)).toBe('75%'); - }); -}); - -// ── getNodeRadius ───────────────────────────────────────────────────────────── - -describe('getNodeRadius', () => { - it('returns minimum radius (7) at mastery 0', () => { - expect(getNodeRadius(0)).toBe(7); - }); - - it('returns maximum radius (14) at mastery 1', () => { - expect(getNodeRadius(1)).toBe(14); - }); - - it('scales linearly between 0 and 1', () => { - expect(getNodeRadius(0.5)).toBe(10.5); - }); -}); - -// ── filterCrossSubjectEdges ─────────────────────────────────────────────────── - -function makeNode(id: string, subject: string): GraphNode { - return { id, concept_name: id, mastery_score: 0.5, mastery_tier: 'learning', times_studied: 0, last_studied_at: null, subject }; -} - -function makeEdge(id: string, source: string, target: string): GraphEdge { - return { id, source, target, strength: 0.7 }; -} - -describe('filterCrossSubjectEdges', () => { - it('keeps edges within the same subject', () => { - const nodes = [makeNode('a', 'Math'), makeNode('b', 'Math')]; - const edges = [makeEdge('e1', 'a', 'b')]; - expect(filterCrossSubjectEdges(nodes, edges)).toHaveLength(1); - }); - - it('removes edges that cross subject boundaries', () => { - const nodes = [makeNode('a', 'Math'), makeNode('b', 'CS')]; - const edges = [makeEdge('e1', 'a', 'b')]; - expect(filterCrossSubjectEdges(nodes, edges)).toHaveLength(0); - }); - - it('always keeps subject_root__ edges regardless of subjects', () => { - const nodes = [makeNode('a', 'Math'), makeNode('subject_root__CS', 'CS')]; - const edges = [makeEdge('e1', 'subject_root__CS', 'a')]; - expect(filterCrossSubjectEdges(nodes, edges)).toHaveLength(1); - }); - - it('returns empty array when no edges', () => { - const nodes = [makeNode('a', 'Math')]; - expect(filterCrossSubjectEdges(nodes, [])).toHaveLength(0); - }); -}); - -// ── computeGraphDiff ────────────────────────────────────────────────────────── - -describe('computeGraphDiff', () => { - it('detects new nodes', () => { - const prev: GraphNode[] = []; - const next = [makeNode('n1', 'Math')]; - const { newNodeIds } = computeGraphDiff(prev, next, [], []); - expect(newNodeIds.has('n1')).toBe(true); - }); - - it('detects mastery tier changes as updated nodes', () => { - const prev = [{ ...makeNode('n1', 'Math'), mastery_tier: 'learning' as const }]; - const next = [{ ...makeNode('n1', 'Math'), mastery_tier: 'mastered' as const }]; - const { updatedNodeIds } = computeGraphDiff(prev, next, [], []); - expect(updatedNodeIds.has('n1')).toBe(true); - }); - - it('does not flag a node as updated when mastery tier is unchanged', () => { - const node = makeNode('n1', 'Math'); - const { updatedNodeIds } = computeGraphDiff([node], [node], [], []); - expect(updatedNodeIds.has('n1')).toBe(false); - }); - - it('detects new edges', () => { - const newEdge = makeEdge('e1', 'a', 'b'); - const { newEdgeIds } = computeGraphDiff([], [], [], [newEdge]); - expect(newEdgeIds.has('e1')).toBe(true); - }); - - it('does not flag an existing edge as new', () => { - const edge = makeEdge('e1', 'a', 'b'); - const { newEdgeIds } = computeGraphDiff([], [], [edge], [edge]); - expect(newEdgeIds.has('e1')).toBe(false); - }); - - it('returns all empty sets when nothing changed', () => { - const node = makeNode('n1', 'Math'); - const edge = makeEdge('e1', 'a', 'b'); - const { newNodeIds, updatedNodeIds, newEdgeIds } = computeGraphDiff([node], [node], [edge], [edge]); - expect(newNodeIds.size).toBe(0); - expect(updatedNodeIds.size).toBe(0); - expect(newEdgeIds.size).toBe(0); - }); -}); - -// ── formatRelativeTime ──────────────────────────────────────────────────────── - -describe('formatRelativeTime', () => { - const now = Date.now(); - - it('returns "Never" for null', () => { - expect(formatRelativeTime(null)).toBe('Never'); - }); - - it('returns "Just now" for less than 1 minute ago', () => { - const thirtySecondsAgo = new Date(now - 30_000).toISOString(); - expect(formatRelativeTime(thirtySecondsAgo)).toBe('Just now'); - }); - - it('returns minutes for < 1 hour ago', () => { - const tenMinutesAgo = new Date(now - 10 * 60_000).toISOString(); - expect(formatRelativeTime(tenMinutesAgo)).toBe('10m ago'); - }); - - it('returns hours for < 24 hours ago', () => { - const threeHoursAgo = new Date(now - 3 * 3_600_000).toISOString(); - expect(formatRelativeTime(threeHoursAgo)).toBe('3h ago'); - }); - - it('returns days for >= 24 hours ago', () => { - const twoDaysAgo = new Date(now - 2 * 86_400_000).toISOString(); - expect(formatRelativeTime(twoDaysAgo)).toBe('2d ago'); - }); -}); - -// ── formatDueDate ───────────────────────────────────────────────────────────── - -describe('formatDueDate', () => { - it('formats a date as "Mon DD"', () => { - // '2026-03-15' → "Mar 15" - const result = formatDueDate('2026-03-15'); - expect(result).toBe('Mar 15'); - }); - - it('formats January correctly', () => { - expect(formatDueDate('2026-01-01')).toBe('Jan 1'); - }); - - it('formats December correctly', () => { - expect(formatDueDate('2026-12-31')).toBe('Dec 31'); - }); -}); - -// ── daysUntil ───────────────────────────────────────────────────────────────── - -/** Build a YYYY-MM-DD string in LOCAL time to match how daysUntil parses dates. */ -function localDateStr(d: Date): string { - const y = d.getFullYear(); - const m = String(d.getMonth() + 1).padStart(2, '0'); - const day = String(d.getDate()).padStart(2, '0'); - return `${y}-${m}-${day}`; -} - -describe('daysUntil', () => { - it('returns 0 for today', () => { - expect(daysUntil(localDateStr(new Date()))).toBe(0); - }); - - it('returns positive number for a future date', () => { - const future = new Date(); - future.setDate(future.getDate() + 3); - expect(daysUntil(localDateStr(future))).toBe(3); - }); - - it('returns negative number for a past date', () => { - const past = new Date(); - past.setDate(past.getDate() - 2); - expect(daysUntil(localDateStr(past))).toBe(-2); - }); -}); diff --git a/frontend/src/__tests__/hydration.test.tsx b/frontend/src/__tests__/hydration.test.tsx deleted file mode 100644 index f95caedb..00000000 --- a/frontend/src/__tests__/hydration.test.tsx +++ /dev/null @@ -1,107 +0,0 @@ -/** - * Hydration safety tests — verifies that no render-time calls to - * Math.random() or Date-dependent state initializers produce mismatches - * between the server and client renders. - * - * Strategy: read the source file text and assert on the patterns we know - * are dangerous, so a future regression is caught immediately. - */ -import fs from 'fs'; -import path from 'path'; - -const SRC = path.resolve(__dirname, '../../src'); - -function readSrc(rel: string) { - return fs.readFileSync(path.join(SRC, rel), 'utf8'); -} - -// ─── page.tsx (Dashboard) ──────────────────────────────────────────────────── - -describe('page.tsx hydration safety', () => { - const src = readSrc('app/page.tsx'); - - test('quote is NOT initialised with Math.random() inside useState()', () => { - // The dangerous pattern: useState(() => ... Math.random() ...) - // After the fix the quote starts as '' and is set in useEffect - expect(src).not.toMatch(/useState\s*\(\s*\(\s*\)\s*=>\s*[^)]*Math\.random/); - }); - - test('quote state starts as an empty string', () => { - expect(src).toMatch(/useState\s*\(\s*['"]{2}\s*\)/); - }); - -}); - -// ─── calendar/page.tsx ─────────────────────────────────────────────────────── - -describe('calendar/page.tsx hydration safety', () => { - const src = readSrc('app/calendar/page.tsx'); - - test('CalendarGrid current state is NOT initialised with new Date() directly', () => { - // Dangerous pattern: useState(() => new Date()) or useState(new Date()) - // After the fix it starts as null and is set in useEffect - expect(src).not.toMatch(/useState\s*\(\s*\(\s*\)\s*=>\s*new Date\s*\(\s*\)\s*\)/); - expect(src).not.toMatch(/useState\s*\(\s*new Date\s*\(\s*\)\s*\)/); - }); - - test('today string is derived from state, not from a bare new Date() call during render', () => { - // After the fix, today is set via setToday() inside a useEffect - expect(src).toMatch(/setToday\s*\(/); - // There should be no top-level `const today = toISO(new Date())` in render - expect(src).not.toMatch(/const today\s*=\s*toISO\s*\(\s*new Date\s*\(\s*\)\s*\)/); - }); -}); - -// ─── UserContext.tsx ───────────────────────────────────────────────────────── - -describe('UserContext.tsx', () => { - const src = readSrc('context/UserContext.tsx'); - - test('exposes userReady in the context interface', () => { - expect(src).toMatch(/userReady\s*:\s*boolean/); - }); - - test('sets userReady to true inside a useEffect (not synchronously)', () => { - // Verify setUserReady(true) exists and only appears inside a useEffect block, - // not as a bare top-level statement. We do this by checking that every line - // containing setUserReady(true) is preceded by a useEffect opening in the file. - expect(src).toMatch(/setUserReady\s*\(\s*true\s*\)/); - // The call must be indented (inside a callback), not at column 0 - const lines = src.split('\n'); - const callLines = lines.filter(l => /setUserReady\s*\(\s*true\s*\)/.test(l)); - expect(callLines.length).toBeGreaterThan(0); - callLines.forEach(line => { - // Each call must be indented — confirming it's inside a block, not top-level - expect(line).toMatch(/^\s+setUserReady/); - }); - // And useEffect must also appear in the file (the call is inside one) - expect(src).toMatch(/useEffect/); - }); - - test('context value is memoised with useMemo', () => { - expect(src).toMatch(/useMemo\s*\(/); - }); -}); - -// ─── All data-fetching pages guard on userReady ────────────────────────────── - -describe('pages guard data fetches behind userReady', () => { - const pages = [ - 'app/tree/page.tsx', - 'app/learn/page.tsx', - 'app/social/page.tsx', - 'app/calendar/page.tsx', - ]; - - for (const page of pages) { - test(`${page} has "if (!userReady) return" guard`, () => { - const src = readSrc(page); - expect(src).toMatch(/if\s*\(\s*!userReady\s*\)\s*return/); - }); - - test(`${page} includes userReady in a useEffect dependency array`, () => { - const src = readSrc(page); - expect(src).toMatch(/\[\s*[^\]]*userReady[^\]]*\]/); - }); - } -}); diff --git a/frontend/src/__tests__/roleBadge.test.tsx b/frontend/src/__tests__/roleBadge.test.tsx deleted file mode 100644 index e14832e9..00000000 --- a/frontend/src/__tests__/roleBadge.test.tsx +++ /dev/null @@ -1,73 +0,0 @@ -/** - * Tests for components/RoleBadge.tsx - * - * Covers: name rendering, size variants, icon rendering, - * description tooltip, color styling. - */ -import React from 'react'; -import { render, screen } from '@testing-library/react'; -import RoleBadge from '@/components/RoleBadge'; -import type { Role } from '@/lib/types'; - -const baseRole: Role = { - id: 'r1', - name: 'Admin', - slug: 'admin', - color: '#ff0000', - icon: null, - description: 'Administrator role', - is_staff_assigned: true, - is_earnable: false, - display_priority: 100, -}; - -afterEach(() => jest.clearAllMocks()); - -describe('RoleBadge', () => { - it('renders role name', () => { - render(); - expect(screen.getByText('Admin')).toBeInTheDocument(); - }); - - it('sets title attribute from description', () => { - render(); - expect(screen.getByText('Admin').closest('span')).toHaveAttribute('title', 'Administrator role'); - }); - - it('does not set title when no description', () => { - const role = { ...baseRole, description: '' }; - render(); - const span = screen.getByText('Admin').closest('span'); - expect(span?.getAttribute('title')).toBeFalsy(); - }); - - it('renders icon when present', () => { - const role = { ...baseRole, icon: 'https://example.com/icon.png' }; - render(); - const img = screen.getByRole('presentation'); - expect(img).toHaveAttribute('src', 'https://example.com/icon.png'); - }); - - it('does not render img when no icon', () => { - render(); - expect(screen.queryByRole('presentation')).not.toBeInTheDocument(); - }); - - it('uses smaller font for sm size', () => { - const { container } = render(); - const span = container.querySelector('span')!; - expect(span.style.fontSize).toBe('10px'); - }); - - it('uses default md size font', () => { - const { container } = render(); - const span = container.querySelector('span')!; - expect(span.style.fontSize).toBe('11px'); - }); - - it('applies role color to text', () => { - const { container } = render(); - const span = container.querySelector('span')!; - expect(span.style.color).toBe('rgb(255, 0, 0)'); - }); -}); diff --git a/frontend/src/__tests__/sessionSummary.test.tsx b/frontend/src/__tests__/sessionSummary.test.tsx deleted file mode 100644 index ad4bc004..00000000 --- a/frontend/src/__tests__/sessionSummary.test.tsx +++ /dev/null @@ -1,168 +0,0 @@ -/** - * Tests for components/SessionSummary.tsx - * - * Covers: concepts covered (list vs empty state), mastery change delta - * formatting (+/-), time spent (singular/plural), recommended next, - * and both button callbacks. - */ -import React from 'react'; -import { render, screen, fireEvent } from '@testing-library/react'; -import SessionSummary from '@/components/SessionSummary'; -import type { SessionSummary as SessionSummaryType } from '@/lib/types'; - -// ── helpers ─────────────────────────────────────────────────────────────────── - -function makeSummary(overrides: Partial = {}): SessionSummaryType { - return { - concepts_covered: [], - mastery_changes: [], - new_connections: [], - time_spent_minutes: 0, - recommended_next: [], - ...overrides, - }; -} - -const noop = jest.fn(); - -afterEach(() => jest.clearAllMocks()); - -// ── concepts covered ────────────────────────────────────────────────────────── - -describe('concepts covered', () => { - it('renders each concept as a chip', () => { - const summary = makeSummary({ concepts_covered: ['Recursion', 'Loops', 'Functions'] }); - render(); - expect(screen.getByText('Recursion')).toBeInTheDocument(); - expect(screen.getByText('Loops')).toBeInTheDocument(); - expect(screen.getByText('Functions')).toBeInTheDocument(); - }); - - it('shows fallback text when no concepts were covered', () => { - render(); - expect(screen.getByText(/no concepts recorded/i)).toBeInTheDocument(); - }); -}); - -// ── mastery changes ─────────────────────────────────────────────────────────── - -describe('mastery changes', () => { - it('does not render the section when there are no mastery changes', () => { - render(); - expect(screen.queryByText(/mastery changes/i)).not.toBeInTheDocument(); - }); - - it('shows concept name and positive delta', () => { - const summary = makeSummary({ - mastery_changes: [{ concept: 'Recursion', before: 0.4, after: 0.65 }], - }); - render(); - expect(screen.getByText('Recursion')).toBeInTheDocument(); - expect(screen.getByText('+25%')).toBeInTheDocument(); - }); - - it('shows negative delta without extra minus sign', () => { - const summary = makeSummary({ - mastery_changes: [{ concept: 'Pointers', before: 0.5, after: 0.4 }], - }); - render(); - expect(screen.getByText('-10%')).toBeInTheDocument(); - }); - - it('shows +0% when mastery did not change', () => { - const summary = makeSummary({ - mastery_changes: [{ concept: 'X', before: 0.5, after: 0.5 }], - }); - render(); - expect(screen.getByText('+0%')).toBeInTheDocument(); - }); - - it('renders multiple mastery change rows', () => { - const summary = makeSummary({ - mastery_changes: [ - { concept: 'A', before: 0.2, after: 0.5 }, - { concept: 'B', before: 0.7, after: 0.8 }, - ], - }); - render(); - expect(screen.getByText('A')).toBeInTheDocument(); - expect(screen.getByText('B')).toBeInTheDocument(); - expect(screen.getByText('+30%')).toBeInTheDocument(); - expect(screen.getByText('+10%')).toBeInTheDocument(); - }); -}); - -// ── time spent ──────────────────────────────────────────────────────────────── - -describe('time spent', () => { - it('uses singular "minute" for 1 minute', () => { - render( - - ); - expect(screen.getByText(/1 minute$/)).toBeInTheDocument(); - }); - - it('uses plural "minutes" for 0 minutes', () => { - render( - - ); - expect(screen.getByText(/0 minutes/)).toBeInTheDocument(); - }); - - it('uses plural "minutes" for more than 1 minute', () => { - render( - - ); - expect(screen.getByText(/25 minutes/)).toBeInTheDocument(); - }); -}); - -// ── recommended next ────────────────────────────────────────────────────────── - -describe('recommended next', () => { - it('does not render the section when list is empty', () => { - render(); - expect(screen.queryByText(/recommended next/i)).not.toBeInTheDocument(); - }); - - it('renders recommended concepts when present', () => { - const summary = makeSummary({ recommended_next: ['Linked Lists', 'Trees'] }); - render(); - expect(screen.getByText('Linked Lists')).toBeInTheDocument(); - expect(screen.getByText('Trees')).toBeInTheDocument(); - }); -}); - -// ── buttons ─────────────────────────────────────────────────────────────────── - -describe('buttons', () => { - it('calls onDashboard when Dashboard button is clicked', () => { - const onDashboard = jest.fn(); - render( - - ); - fireEvent.click(screen.getByRole('button', { name: /dashboard/i })); - expect(onDashboard).toHaveBeenCalledTimes(1); - }); - - it('calls onNewSession when New Session button is clicked', () => { - const onNewSession = jest.fn(); - render( - - ); - fireEvent.click(screen.getByRole('button', { name: /new session/i })); - expect(onNewSession).toHaveBeenCalledTimes(1); - }); -}); diff --git a/frontend/src/__tests__/settings.test.tsx b/frontend/src/__tests__/settings.test.tsx deleted file mode 100644 index a29042ec..00000000 --- a/frontend/src/__tests__/settings.test.tsx +++ /dev/null @@ -1,118 +0,0 @@ -/** - * Tests for app/settings/page.tsx - * - * Covers: section navigation, loading state, profile form rendering, - * section switching. - */ -import React from 'react'; -import { render, screen, fireEvent, waitFor } from '@testing-library/react'; - -// Mock next/navigation -jest.mock('next/navigation', () => ({ - useRouter: () => ({ push: jest.fn(), replace: jest.fn() }), - usePathname: () => '/settings', -})); - -// Mock UserContext -jest.mock('@/context/UserContext', () => ({ - useUser: () => ({ - userId: 'user_1', - userName: 'Test User', - avatarUrl: '', - equippedCosmetics: {}, - isAdmin: false, - roles: [], - refreshProfile: jest.fn(), - }), -})); - -// Mock ToastProvider -jest.mock('@/components/ToastProvider', () => ({ - useToast: () => ({ showToast: jest.fn() }), -})); - -// Mock api module -const mockFetchSettings = jest.fn(); -const mockUpdateSettings = jest.fn(); -const mockUpdateProfile = jest.fn(); -const mockUploadAvatar = jest.fn(); -const mockExportData = jest.fn(); -const mockDeleteAccount = jest.fn(); -jest.mock('@/lib/api', () => ({ - fetchSettings: (...args: any[]) => mockFetchSettings(...args), - updateSettings: (...args: any[]) => mockUpdateSettings(...args), - updateProfile: (...args: any[]) => mockUpdateProfile(...args), - uploadAvatar: (...args: any[]) => mockUploadAvatar(...args), - exportData: (...args: any[]) => mockExportData(...args), - deleteAccount: (...args: any[]) => mockDeleteAccount(...args), -})); - -// Mock components -jest.mock('@/components/CosmeticsManager', () => () =>
); -jest.mock('@/components/AvatarFrame', () => (props: any) =>
); - -import SettingsPage from '@/app/settings/page'; - -afterEach(() => jest.clearAllMocks()); - -const mockSettings = { - user_id: 'user_1', - profile_visibility: 'public', - activity_status_visible: true, - notification_email: true, - notification_push: false, - notification_in_app: true, - theme: 'light', - font_size: 'md', - accent_color: null, -}; - -describe('SettingsPage', () => { - beforeEach(() => { - mockFetchSettings.mockResolvedValue(mockSettings); - }); - - it('renders section navigation', async () => { - render(); - await waitFor(() => { - expect(screen.getAllByText('Profile').length).toBeGreaterThanOrEqual(1); - }); - expect(screen.getByText('Account')).toBeInTheDocument(); - expect(screen.getByText('Notifications')).toBeInTheDocument(); - expect(screen.getByText('Appearance')).toBeInTheDocument(); - expect(screen.getByText('Privacy')).toBeInTheDocument(); - expect(screen.getByText('Cosmetics')).toBeInTheDocument(); - expect(screen.getByText('Danger Zone')).toBeInTheDocument(); - }); - - it('shows profile section by default', async () => { - render(); - await waitFor(() => { - expect(screen.getByText(/display name/i)).toBeInTheDocument(); - }); - }); - - it('switches to danger zone section on click', async () => { - render(); - await waitFor(() => { - expect(screen.getByText('Danger Zone')).toBeInTheDocument(); - }); - - fireEvent.click(screen.getByText('Danger Zone')); - await waitFor(() => { - expect(screen.getAllByText(/delete account/i).length).toBeGreaterThanOrEqual(1); - }); - }); - - it('switches to notifications section', async () => { - render(); - await waitFor(() => { - expect(screen.getByText('Notifications')).toBeInTheDocument(); - }); - - fireEvent.click(screen.getByText('Notifications')); - await waitFor(() => { - expect(screen.getByText(/email notifications/i)).toBeInTheDocument(); - }); - }); -}); diff --git a/frontend/src/__tests__/signinCallback.test.tsx b/frontend/src/__tests__/signinCallback.test.tsx deleted file mode 100644 index 5446badc..00000000 --- a/frontend/src/__tests__/signinCallback.test.tsx +++ /dev/null @@ -1,123 +0,0 @@ -/** - * Tests for app/signin/callback/page.tsx - * - * Covers the new error branches added to the OAuth callback handler: - * - Successful session → redirect to /dashboard - * - 403 from session API → redirect to /pending - * - Other failures from session API → inline error - * - Network errors → inline error - * - Missing user_id/name params → inline error - * - Missing is_approved param → inline error (not a /pending redirect) - * - Explicit is_approved=false → /pending redirect - */ -import React from 'react'; -import { render, screen, waitFor } from '@testing-library/react'; - -const replace = jest.fn(); -const setActiveUser = jest.fn(); -const confirmApproved = jest.fn(); -let searchParams = new URLSearchParams(); - -jest.mock('next/navigation', () => ({ - useRouter: () => ({ replace }), - useSearchParams: () => searchParams, -})); - -jest.mock('@/context/UserContext', () => ({ - useUser: () => ({ setActiveUser, confirmApproved }), -})); - -import CallbackPage from '@/app/signin/callback/page'; - -beforeEach(() => { - jest.clearAllMocks(); - searchParams = new URLSearchParams(); - global.fetch = jest.fn(); -}); - -afterEach(() => { - // @ts-expect-error allow cleanup - delete global.fetch; -}); - -function setParams(params: Record) { - searchParams = new URLSearchParams(params); -} - -describe('signin/callback page', () => { - it('redirects to /dashboard on a successful session', async () => { - setParams({ user_id: 'u1', name: 'Ada', is_approved: 'true' }); - (global.fetch as jest.Mock).mockResolvedValue({ ok: true, status: 200 }); - - render(); - - await waitFor(() => expect(replace).toHaveBeenCalledWith('/dashboard')); - expect(setActiveUser).toHaveBeenCalledWith('u1', 'Ada', ''); - expect(confirmApproved).toHaveBeenCalled(); - }); - - it('redirects to /pending when session API returns 403', async () => { - setParams({ user_id: 'u1', name: 'Ada', is_approved: 'true' }); - (global.fetch as jest.Mock).mockResolvedValue({ ok: false, status: 403 }); - - render(); - - await waitFor(() => expect(replace).toHaveBeenCalledWith('/signin?error=not_approved')); - expect(confirmApproved).not.toHaveBeenCalled(); - }); - - it('shows an inline error when session API returns a non-403 failure', async () => { - setParams({ user_id: 'u1', name: 'Ada', is_approved: 'true' }); - (global.fetch as jest.Mock).mockResolvedValue({ ok: false, status: 500 }); - - render(); - - expect(await screen.findByText(/unable to complete sign-in/i)).toBeInTheDocument(); - expect(replace).not.toHaveBeenCalled(); - }); - - it('shows an inline error when the session fetch rejects', async () => { - setParams({ user_id: 'u1', name: 'Ada', is_approved: 'true' }); - (global.fetch as jest.Mock).mockRejectedValue(new Error('network down')); - - render(); - - expect(await screen.findByText(/unable to reach the server/i)).toBeInTheDocument(); - expect(replace).not.toHaveBeenCalled(); - }); - - it('shows an inline error when user_id is missing', async () => { - setParams({ name: 'Ada', is_approved: 'true' }); - - render(); - - expect(await screen.findByText(/sign-in failed/i)).toBeInTheDocument(); - expect(global.fetch).not.toHaveBeenCalled(); - expect(replace).not.toHaveBeenCalled(); - }); - - it('shows an inline error when is_approved is missing entirely', async () => { - setParams({ user_id: 'u1', name: 'Ada' }); - - render(); - - expect(await screen.findByText(/sign-in failed/i)).toBeInTheDocument(); - expect(replace).not.toHaveBeenCalled(); - }); - - it('redirects to /pending when is_approved is explicitly "false"', async () => { - setParams({ user_id: 'u1', name: 'Ada', is_approved: 'false' }); - - render(); - - await waitFor(() => expect(replace).toHaveBeenCalledWith('/signin?error=not_approved')); - }); - - it('redirects to /pending when error=not_approved is set', async () => { - setParams({ error: 'not_approved' }); - - render(); - - await waitFor(() => expect(replace).toHaveBeenCalledWith('/signin?error=not_approved')); - }); -}); diff --git a/frontend/src/__tests__/userContext.test.tsx b/frontend/src/__tests__/userContext.test.tsx deleted file mode 100644 index 079cbf43..00000000 --- a/frontend/src/__tests__/userContext.test.tsx +++ /dev/null @@ -1,99 +0,0 @@ -/** - * Tests for UserContext — verifies localStorage restoration and the - * userReady gate that prevents pages from fetching with the wrong default user. - */ -import React from 'react'; -import { render, screen, act, waitFor } from '@testing-library/react'; -import { UserProvider, useUser } from '@/context/UserContext'; - -// Stub the /api/users fetch so tests don't hit the network -beforeEach(() => { - global.fetch = jest.fn(() => - Promise.resolve({ json: () => Promise.resolve({ users: [] }) } as Response) - ); -}); - -afterEach(() => { - localStorage.clear(); - jest.clearAllMocks(); -}); - -function DisplayUser() { - const { userId, userName, userReady } = useUser(); - return ( -
- {userId} - {userName} - {String(userReady)} -
- ); -} - -test('starts with userReady=false before localStorage is read', () => { - // Render without waiting for effects — userReady should be false initially - let readyOnFirstRender = ''; - function Probe() { - const { userReady } = useUser(); - if (readyOnFirstRender === '') readyOnFirstRender = String(userReady); - return null; - } - render(); - expect(readyOnFirstRender).toBe('false'); -}); - -test('sets userReady=true after mount even if no localStorage entry exists', async () => { - render(); - await waitFor(() => { - expect(screen.getByTestId('ready').textContent).toBe('true'); - }); -}); - -test('restores userId and userName from localStorage on mount', async () => { - localStorage.setItem( - 'sapling_user', - JSON.stringify({ id: 'user_jose', name: 'Jose Cruz' }) - ); - render(); - await waitFor(() => { - expect(screen.getByTestId('userId').textContent).toBe('user_jose'); - expect(screen.getByTestId('userName').textContent).toBe('Jose Cruz'); - expect(screen.getByTestId('ready').textContent).toBe('true'); - }); -}); - -test('has empty userId when localStorage is empty', async () => { - render(); - await waitFor(() => { - expect(screen.getByTestId('userId').textContent).toBe(''); - expect(screen.getByTestId('ready').textContent).toBe('true'); - }); -}); - -test('setActiveUser updates userId and persists to localStorage', async () => { - function SwitchUser() { - const { userId, setActiveUser, userReady } = useUser(); - return ( -
- {userId} - {String(userReady)} - -
- ); - } - - render(); - await waitFor(() => - expect(screen.getByTestId('ready').textContent).toBe('true') - ); - - act(() => { - screen.getByRole('button', { name: 'Switch' }).click(); - }); - - expect(screen.getByTestId('userId').textContent).toBe('user_gael'); - const stored = JSON.parse(localStorage.getItem('sapling_user') ?? '{}'); - expect(stored.id).toBe('user_gael'); - expect(stored.name).toBe('Gael Lopez'); -}); diff --git a/frontend/src/app/(shell)/achievements/page.tsx b/frontend/src/app/(shell)/achievements/page.tsx new file mode 100644 index 00000000..ed2e15d8 --- /dev/null +++ b/frontend/src/app/(shell)/achievements/page.tsx @@ -0,0 +1,5 @@ +import { Achievements } from "@/components/screens/Achievements"; + +export default function AchievementsPage() { + return ; +} diff --git a/frontend/src/app/(shell)/admin/page.tsx b/frontend/src/app/(shell)/admin/page.tsx new file mode 100644 index 00000000..09c407d7 --- /dev/null +++ b/frontend/src/app/(shell)/admin/page.tsx @@ -0,0 +1,5 @@ +import { Admin } from "@/components/screens/Admin"; + +export default function AdminPage() { + return ; +} diff --git a/frontend/src/app/(shell)/calendar/page.tsx b/frontend/src/app/(shell)/calendar/page.tsx new file mode 100644 index 00000000..5d1f9465 --- /dev/null +++ b/frontend/src/app/(shell)/calendar/page.tsx @@ -0,0 +1,10 @@ +import { Suspense } from "react"; +import { Calendar } from "@/components/screens/Calendar"; + +export default function CalendarPage() { + return ( + + + + ); +} diff --git a/frontend/src/app/(shell)/dashboard/page.tsx b/frontend/src/app/(shell)/dashboard/page.tsx new file mode 100644 index 00000000..f5f148df --- /dev/null +++ b/frontend/src/app/(shell)/dashboard/page.tsx @@ -0,0 +1,10 @@ +import { Suspense } from "react"; +import { Dashboard } from "@/components/screens/Dashboard"; + +export default function DashboardPage() { + return ( + + + + ); +} diff --git a/frontend/src/app/(shell)/layout.tsx b/frontend/src/app/(shell)/layout.tsx new file mode 100644 index 00000000..954f618b --- /dev/null +++ b/frontend/src/app/(shell)/layout.tsx @@ -0,0 +1,26 @@ +import React, { Suspense } from "react"; +import { Sidebar } from "@/components/Sidebar"; +import { FloatingActions } from "@/components/FloatingActions"; +import { FeedbackFlow } from "@/components/FeedbackFlow"; +import { SessionFeedbackGlobal } from "@/components/SessionFeedbackGlobal"; + +export default function ShellLayout({ children }: { children: React.ReactNode }) { + return ( +
+ Skip to content + +
+ {children} +
+ + + + + +
+ ); +} diff --git a/frontend/src/app/(shell)/learn/page.tsx b/frontend/src/app/(shell)/learn/page.tsx new file mode 100644 index 00000000..5deb5ca9 --- /dev/null +++ b/frontend/src/app/(shell)/learn/page.tsx @@ -0,0 +1,5 @@ +import { Learn } from "@/components/screens/Learn"; + +export default function LearnPage() { + return ; +} diff --git a/frontend/src/app/(shell)/library/page.tsx b/frontend/src/app/(shell)/library/page.tsx new file mode 100644 index 00000000..abf95dfc --- /dev/null +++ b/frontend/src/app/(shell)/library/page.tsx @@ -0,0 +1,5 @@ +import { Library } from "@/components/screens/Library"; + +export default function LibraryPage() { + return ; +} diff --git a/frontend/src/app/(shell)/profile/[userId]/page.tsx b/frontend/src/app/(shell)/profile/[userId]/page.tsx new file mode 100644 index 00000000..c0e6070b --- /dev/null +++ b/frontend/src/app/(shell)/profile/[userId]/page.tsx @@ -0,0 +1,45 @@ +"use client"; +import React from "react"; +import { useParams } from "next/navigation"; +import { TopBar } from "@/components/TopBar"; +import { ProfileView } from "@/components/ProfileView"; +import { fetchPublicProfile } from "@/lib/api"; +import type { UserProfile } from "@/lib/types"; + +export default function PublicProfilePage() { + const params = useParams<{ userId: string }>(); + const userId = params?.userId; + const [profile, setProfile] = React.useState(null); + const [loading, setLoading] = React.useState(true); + const [error, setError] = React.useState(null); + + React.useEffect(() => { + if (!userId) return; + setLoading(true); + fetchPublicProfile(userId) + .then(p => { setProfile(p); setError(null); }) + .catch(err => setError(String(err))) + .finally(() => setLoading(false)); + }, [userId]); + + return ( +
+ +
+ {loading && ( +
Loading profile…
+ )} + {error && !loading && ( +
+ Couldn't load this profile. {error} +
+ )} + {!loading && !error && profile && } +
+
+ ); +} diff --git a/frontend/src/app/(shell)/settings/page.tsx b/frontend/src/app/(shell)/settings/page.tsx new file mode 100644 index 00000000..3c3af691 --- /dev/null +++ b/frontend/src/app/(shell)/settings/page.tsx @@ -0,0 +1,5 @@ +import { Settings } from "@/components/screens/Settings"; + +export default function SettingsPage() { + return ; +} diff --git a/frontend/src/app/(shell)/social/page.tsx b/frontend/src/app/(shell)/social/page.tsx new file mode 100644 index 00000000..95490093 --- /dev/null +++ b/frontend/src/app/(shell)/social/page.tsx @@ -0,0 +1,10 @@ +import { Suspense } from "react"; +import { Social } from "@/components/screens/Social"; + +export default function SocialPage() { + return ( + + + + ); +} diff --git a/frontend/src/app/(shell)/study/page.tsx b/frontend/src/app/(shell)/study/page.tsx new file mode 100644 index 00000000..c0d0a35d --- /dev/null +++ b/frontend/src/app/(shell)/study/page.tsx @@ -0,0 +1,5 @@ +import { Study } from "@/components/screens/Study"; + +export default function StudyPage() { + return ; +} diff --git a/frontend/src/app/(shell)/tree/page.tsx b/frontend/src/app/(shell)/tree/page.tsx new file mode 100644 index 00000000..4be79f06 --- /dev/null +++ b/frontend/src/app/(shell)/tree/page.tsx @@ -0,0 +1,10 @@ +import { Suspense } from "react"; +import { Tree } from "@/components/screens/Tree"; + +export default function TreePage() { + return ( + + + + ); +} diff --git a/frontend/src/app/about/page.tsx b/frontend/src/app/about/page.tsx deleted file mode 100644 index f09053ee..00000000 --- a/frontend/src/app/about/page.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import Link from "next/link"; - -export default function AboutPage() { - return ( -
-
-
- - ← Back to Sapling - -
- -

About Sapling

- -
-

- Sapling is an AI-powered study companion built by students, for students. We believe that learning shouldn't be passive. It should adapt to you, challenge you, and show you exactly where you stand. -

- -

- At its core, Sapling maps your understanding as a live knowledge graph that grows with every session, quiz, and document you interact with. Paired with an AI tutor that can reason with you Socratically, explain concepts directly, or flip the table and have you teach back, Sapling meets you wherever you are in your learning journey. -

- -

- Sapling was born out of a hackathon and built by a team of four students who were frustrated with static study tools that don't actually know what you know. We wanted something that feels less like a flashcard app and more like a study partner who's always prepared. -

- -
-

What makes Sapling different:

-
    - {[ - "Your knowledge graph is yours. It updates in real time based on your actual performance, not just what you've clicked through.", - "Three distinct teaching modes mean you're never locked into one way of learning.", - "Study rooms let you learn alongside classmates and see how your mastery compares, anonymously and collaboratively.", - "Everything from syllabus tracking to exam study guides is powered by Gemini, so the busywork of getting organized is handled for you.", - ].map((item, i) => ( -
  • - - {item} -
  • - ))} -
-
- -

- Sapling is actively developed and we're always building. If something's broken or you have an idea, there's a feedback button in the navbar and we actually read those. -

-
- - {/* Awards */} -
-

Recognition

-
-
-

Best AI Tutor in Education

-

Boston University Civic Hacks 2026 · BU Spark! & Wheelock College of Education

-

- Recognized among competing teams at BU's annual civic hackathon for building the most impactful AI-driven learning experience. Sapling was awarded for its approach to personalized, student-centered tutoring, bridging the gap between artificial intelligence and meaningful education. -

-
- -
-

Code & Tell Winner

-

BU Spark!

-

- Selected by BU Spark! as a standout project at their Code & Tell showcase, where student builders present real-world applications to faculty, mentors, and industry judges. Sapling was chosen for its technical depth and its vision for the future of how students learn. -

-
-
-
- -
- Built by Andres Lopez, Jack He, Luke Cooper, and Jose Gael Cruz-Lopez © 2026 -
-
- -
-
- About - Terms of Service - Privacy Policy -
-
-
- ); -} diff --git a/frontend/src/app/achievements/page.tsx b/frontend/src/app/achievements/page.tsx deleted file mode 100644 index 1436af35..00000000 --- a/frontend/src/app/achievements/page.tsx +++ /dev/null @@ -1,152 +0,0 @@ -'use client'; - -import { useEffect, useState } from 'react'; -import { useUser } from '@/context/UserContext'; -import { fetchAchievements } from '@/lib/api'; -import type { Achievement, UserAchievement, AchievementCategory } from '@/lib/types'; -import AchievementCard from '@/components/AchievementCard'; - -const UI_FONT = "var(--font-dm-sans), 'DM Sans', sans-serif"; - -const CATEGORIES: { key: AchievementCategory | 'all'; label: string }[] = [ - { key: 'all', label: 'All' }, - { key: 'activity', label: 'Activity' }, - { key: 'social', label: 'Social' }, - { key: 'milestone', label: 'Milestone' }, - { key: 'special', label: 'Special' }, -]; - -export default function AchievementsPage() { - const { userId } = useUser(); - const [earned, setEarned] = useState([]); - const [available, setAvailable] = useState([]); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(''); - const [filter, setFilter] = useState('all'); - const [expandedId, setExpandedId] = useState(null); - - useEffect(() => { - if (!userId) return; - setLoading(true); - fetchAchievements(userId) - .then(data => { - setEarned(data.earned || []); - setAvailable(data.available || []); - setLoading(false); - }) - .catch(e => { - setError(e.message); - setLoading(false); - }); - }, [userId]); - - const filterFn = (category: string) => - filter === 'all' || category === filter; - - const filteredEarned = earned.filter(ua => filterFn(ua.achievement.category)); - const filteredAvailable = available.filter(a => filterFn(a.category)); - - if (loading) { - return ( -
-
Loading achievements...
-
- ); - } - - if (error) { - return ( -
-
{error}
-
- ); - } - - return ( -
-

Achievements

-

- Track your progress and unlock achievements as you learn. -

- - {/* Category filters */} -
- {CATEGORIES.map(cat => ( - - ))} -
- - {/* Earned achievements */} - {filteredEarned.length > 0 && ( -
-
Earned ({filteredEarned.length})
-
- {filteredEarned.map(ua => ( -
- setExpandedId(expandedId === ua.achievement.id ? null : ua.achievement.id)} - /> - {expandedId === ua.achievement.id && ( -
-
{ua.achievement.description}
-
- Rarity: {ua.achievement.rarity} | Earned: {new Date(ua.earned_at).toLocaleDateString()} -
-
- )} -
- ))} -
-
- )} - - {/* Locked achievements */} - {filteredAvailable.length > 0 && ( -
-
Locked ({filteredAvailable.length})
-
- {filteredAvailable.map(ach => ( - - ))} -
-
- )} - - {filteredEarned.length === 0 && filteredAvailable.length === 0 && ( -
- No achievements found in this category. -
- )} -
- ); -} diff --git a/frontend/src/app/admin/page.tsx b/frontend/src/app/admin/page.tsx deleted file mode 100644 index b3ca8f4a..00000000 --- a/frontend/src/app/admin/page.tsx +++ /dev/null @@ -1,268 +0,0 @@ -'use client'; - -import { useEffect, useState } from 'react'; -import { useRouter } from 'next/navigation'; -import { useUser } from '@/context/UserContext'; -import { useToast } from '@/components/ToastProvider'; -import { - adminFetchUsers, adminApproveUser, adminAssignRole, adminRevokeRole, - adminCreateRole, adminCreateAchievement, adminGrantAchievement, adminCreateCosmetic, -} from '@/lib/api'; -import RoleBadge from '@/components/RoleBadge'; - -const UI_FONT = "var(--font-dm-sans), 'DM Sans', sans-serif"; - -const TABS = ['Users', 'Roles', 'Achievements', 'Cosmetics']; - -export default function AdminPage() { - const { isAdmin, userId } = useUser(); - const router = useRouter(); - const { showToast } = useToast(); - const [activeTab, setActiveTab] = useState('Users'); - const [users, setUsers] = useState([]); - const [loading, setLoading] = useState(true); - - // Role creation form - const [roleName, setRoleName] = useState(''); - const [roleSlug, setRoleSlug] = useState(''); - const [roleColor, setRoleColor] = useState('#3b82f6'); - - // Achievement creation form - const [achName, setAchName] = useState(''); - const [achSlug, setAchSlug] = useState(''); - const [achCategory, setAchCategory] = useState('milestone'); - const [achRarity, setAchRarity] = useState('common'); - - // Cosmetic creation form - const [cosName, setCosName] = useState(''); - const [cosSlug, setCosSlug] = useState(''); - const [cosType, setCosType] = useState('avatar_frame'); - const [cosRarity, setCosRarity] = useState('common'); - - // Grant form - const [grantUserId, setGrantUserId] = useState(''); - const [grantAchId, setGrantAchId] = useState(''); - - useEffect(() => { - if (!isAdmin) { - router.push('/dashboard'); - return; - } - setLoading(true); - adminFetchUsers() - .then(data => { - setUsers(data.users || []); - setLoading(false); - }) - .catch(() => setLoading(false)); - }, [isAdmin, router]); - - if (!isAdmin) return null; - - const handleApprove = async (uid: string) => { - try { - await adminApproveUser(uid); - setUsers(prev => prev.map(u => u.id === uid ? { ...u, is_approved: true } : u)); - showToast('User approved'); - } catch (e: any) { - showToast(e.message); - } - }; - - const handleCreateRole = async () => { - if (!roleName || !roleSlug) return; - try { - await adminCreateRole({ name: roleName, slug: roleSlug, color: roleColor }); - showToast('Role created'); - setRoleName(''); setRoleSlug(''); - } catch (e: any) { - showToast(e.message); - } - }; - - const handleCreateAchievement = async () => { - if (!achName || !achSlug) return; - try { - await adminCreateAchievement({ name: achName, slug: achSlug, category: achCategory, rarity: achRarity }); - showToast('Achievement created'); - setAchName(''); setAchSlug(''); - } catch (e: any) { - showToast(e.message); - } - }; - - const handleGrantAchievement = async () => { - if (!grantUserId || !grantAchId) return; - try { - await adminGrantAchievement(grantUserId, grantAchId); - showToast('Achievement granted'); - setGrantUserId(''); setGrantAchId(''); - } catch (e: any) { - showToast(e.message); - } - }; - - const handleCreateCosmetic = async () => { - if (!cosName || !cosSlug) return; - try { - await adminCreateCosmetic({ type: cosType, name: cosName, slug: cosSlug, rarity: cosRarity }); - showToast('Cosmetic created'); - setCosName(''); setCosSlug(''); - } catch (e: any) { - showToast(e.message); - } - }; - - const inputStyle: React.CSSProperties = { - background: 'var(--bg-input)', - color: 'var(--text)', - border: '1px solid var(--border)', - borderRadius: 'var(--radius-sm)', - padding: '6px 10px', - fontSize: '13px', - fontFamily: 'inherit', - outline: 'none', - }; - - return ( -
-

Admin

- - {/* Tabs */} -
- {TABS.map(tab => ( - - ))} -
- - {/* Users tab */} - {activeTab === 'Users' && ( -
- {loading ? ( -
Loading users...
- ) : ( - - - - - - - - - - - - {users.map(user => ( - - - - - - - - ))} - -
NameEmailStatusRolesActions
{user.name}{user.email} - {user.is_approved ? ( - Approved - ) : ( - Pending - )} - -
- {(user.roles || []).map((r: any) => ( - - ))} -
-
- {!user.is_approved && ( - - )} -
- )} -
- )} - - {/* Roles tab */} - {activeTab === 'Roles' && ( -
-
Create Role
-
- setRoleName(e.target.value)} /> - setRoleSlug(e.target.value)} /> - setRoleColor(e.target.value)} style={{ width: '36px', height: '32px', border: 'none', cursor: 'pointer' }} /> - -
-
- )} - - {/* Achievements tab */} - {activeTab === 'Achievements' && ( -
-
-
Create Achievement
-
- setAchName(e.target.value)} /> - setAchSlug(e.target.value)} /> - - - -
-
-
-
Grant Achievement
-
- setGrantUserId(e.target.value)} /> - setGrantAchId(e.target.value)} /> - -
-
-
- )} - - {/* Cosmetics tab */} - {activeTab === 'Cosmetics' && ( -
-
Create Cosmetic
-
- setCosName(e.target.value)} /> - setCosSlug(e.target.value)} /> - - - -
-
- )} -
- ); -} diff --git a/frontend/src/app/api/auth/session/route.ts b/frontend/src/app/api/auth/session/route.ts index 703bf541..4411c394 100644 --- a/frontend/src/app/api/auth/session/route.ts +++ b/frontend/src/app/api/auth/session/route.ts @@ -4,8 +4,6 @@ import { signSession, SESSION_MAX_AGE } from '@/lib/sessionToken'; const API_URL = process.env.NEXT_PUBLIC_API_URL; const SESSION_SECRET = process.env.SESSION_SECRET; -// Verify an HMAC token produced by the backend's OAuth callback. -// Returns the userId if valid and unexpired, otherwise null. async function verifyAuthToken(token: string): Promise { if (!SESSION_SECRET) return null; const dot = token.lastIndexOf('.'); @@ -13,8 +11,6 @@ async function verifyAuthToken(token: string): Promise { const payloadB64 = token.slice(0, dot); const sigB64 = token.slice(dot + 1); try { - // Re-pad base64url and convert to bytes for sig comparison. - // Returns Uint8Array (concrete) so it satisfies BufferSource. function b64urlToBytes(s: string): Uint8Array { const padded = s.replace(/-/g, '+').replace(/_/g, '/'); const pad = '='.repeat((4 - (padded.length % 4)) % 4); @@ -55,14 +51,12 @@ export async function POST(request: NextRequest) { let verifiedUserId: string | null = null; - // Fast path: verify the backend-signed token (no round-trip needed). if (authToken) { verifiedUserId = await verifyAuthToken(authToken); if (!verifiedUserId) { return NextResponse.json({ error: 'Invalid or expired auth token' }, { status: 401 }); } } else { - // Fallback: call backend to verify (used when SESSION_SECRET not shared yet). if (!API_URL) { return NextResponse.json({ error: 'NEXT_PUBLIC_API_URL not configured' }, { status: 500 }); } @@ -78,13 +72,9 @@ export async function POST(request: NextRequest) { } finally { clearTimeout(timeout); } - if (!res.ok) { - return NextResponse.json({ error: 'User not found' }, { status: 401 }); - } + if (!res.ok) return NextResponse.json({ error: 'User not found' }, { status: 401 }); const data = await res.json(); - if (data.is_approved !== true) { - return NextResponse.json({ error: 'Not approved' }, { status: 403 }); - } + if (data.is_approved !== true) return NextResponse.json({ error: 'Not approved' }, { status: 403 }); verifiedUserId = userId; } catch { return NextResponse.json({ error: 'Backend unreachable' }, { status: 502 }); diff --git a/frontend/src/app/signin/callback/page.tsx b/frontend/src/app/auth/callback/page.tsx similarity index 58% rename from frontend/src/app/signin/callback/page.tsx rename to frontend/src/app/auth/callback/page.tsx index 3275a06a..e6cb371d 100644 --- a/frontend/src/app/signin/callback/page.tsx +++ b/frontend/src/app/auth/callback/page.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useEffect, Suspense } from 'react'; +import { Suspense, useEffect } from 'react'; import { useSearchParams, useRouter } from 'next/navigation'; import { useUser } from '@/context/UserContext'; @@ -18,66 +18,53 @@ function CallbackInner() { const error = searchParams.get('error'); if (error === 'not_approved' || approvedParam === 'false') { - router.replace('/signin?error=not_approved'); + router.replace('/auth?error=not_approved'); return; } - if (approvedParam !== 'true' || !userId || !name) { - router.replace('/signin?error=signin_failed'); + router.replace('/auth?error=signin_failed'); return; } setActiveUser(userId, name, avatar || ''); confirmApproved(); - // Try to set the session cookie; redirect regardless. fetch('/api/auth/session', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ userId, ...(authToken ? { authToken } : {}) }), }).catch(() => {}); - const onboardingPending = sessionStorage.getItem('sapling_onboarding_pending'); - if (onboardingPending) { - router.replace('/'); - return; - } - - // Check if user has completed onboarding; if not, send them through it const API_URL = process.env.NEXT_PUBLIC_API_URL ?? 'http://localhost:5000'; fetch(`${API_URL}/api/auth/me?user_id=${encodeURIComponent(userId)}`) .then(r => r.json()) .then(data => { - if (data.onboarding_completed) { - router.replace('/dashboard'); - } else { - sessionStorage.setItem('sapling_onboarding_pending', 'true'); - router.replace('/'); - } + router.replace(data.onboarding_completed ? '/dashboard' : '/onboarding'); }) - .catch(() => { - router.replace('/dashboard'); - }); - }, []); // eslint-disable-line react-hooks/exhaustive-deps + .catch(() => router.replace('/dashboard')); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); return ( -
- Signing you in... +
+ Signing you in…
); } export default function CallbackPage() { return ( - }> + }> ); diff --git a/frontend/src/app/auth/page.tsx b/frontend/src/app/auth/page.tsx new file mode 100644 index 00000000..f2bf14f5 --- /dev/null +++ b/frontend/src/app/auth/page.tsx @@ -0,0 +1,5 @@ +import { Auth } from "@/components/screens/Auth"; + +export default function AuthPage() { + return ; +} diff --git a/frontend/src/app/calendar/page.tsx b/frontend/src/app/calendar/page.tsx deleted file mode 100644 index 3391b7de..00000000 --- a/frontend/src/app/calendar/page.tsx +++ /dev/null @@ -1,519 +0,0 @@ -'use client'; - -import { useEffect, useState, Suspense } from 'react'; -import { useSearchParams } from 'next/navigation'; -import AssignmentTable from '@/components/AssignmentTable'; -import DocumentUploadModal, { type UploadedDoc } from '@/components/DocumentUploadModal'; -import { Assignment } from '@/lib/types'; -import { - getAllAssignments, - getCalendarStatus, - syncToGoogleCalendar, - importGoogleEvents, - disconnectGoogleCalendar, - getCourses, - type EnrolledCourse, -} from '@/lib/api'; -import { useUser } from '@/context/UserContext'; - -const UI_FONT = "var(--font-dm-sans), 'DM Sans', sans-serif"; - -type CalendarView = 'month' | 'week' | 'day'; - -const TYPE_COLORS: Record = { - exam: { bg: 'rgba(220,38,38,0.08)', text: '#b91c1c', border: 'rgba(220,38,38,0.2)' }, - project: { bg: 'rgba(234,88,12,0.08)', text: '#c2410c', border: 'rgba(234,88,12,0.2)' }, - homework: { bg: 'rgba(107,114,128,0.1)', text: '#374151', border: 'rgba(107,114,128,0.2)' }, - quiz: { bg: 'rgba(161,98,7,0.08)', text: '#92400e', border: 'rgba(161,98,7,0.2)' }, - reading: { bg: 'rgba(29,78,216,0.08)', text: '#1e40af', border: 'rgba(29,78,216,0.2)' }, - other: { bg: 'rgba(107,114,128,0.08)', text: '#6b7280', border: 'rgba(107,114,128,0.15)' }, -}; - -function AssignmentChip({ a, isMobile }: { a: Assignment; isMobile?: boolean }) { - const c = TYPE_COLORS[a.assignment_type ?? 'other'] ?? TYPE_COLORS.other; - return ( -
- {a.title} -
- ); -} - -function useIsMobile(breakpoint = 768) { - const [isMobile, setIsMobile] = useState(false); - useEffect(() => { - const mql = window.matchMedia(`(max-width: ${breakpoint}px)`); - setIsMobile(mql.matches); - const handler = (e: MediaQueryListEvent) => setIsMobile(e.matches); - mql.addEventListener('change', handler); - return () => mql.removeEventListener('change', handler); - }, [breakpoint]); - return isMobile; -} - -function CalendarGrid({ assignments }: { assignments: Assignment[] }) { - const isMobile = useIsMobile(); - const [view, setView] = useState('month'); - // Initialize to null so server and client agree on the first render, - // then set to the real Date on the client after mount (avoids hydration mismatch). - const [current, setCurrent] = useState(null); - const [today, setToday] = useState(''); - - useEffect(() => { - const now = new Date(); - setCurrent(now); - const y = now.getFullYear(); - const m = String(now.getMonth() + 1).padStart(2, '0'); - const day = String(now.getDate()).padStart(2, '0'); - setToday(`${y}-${m}-${day}`); - }, []); - - const toISO = (d: Date) => { - const y = d.getFullYear(); - const m = String(d.getMonth() + 1).padStart(2, '0'); - const day = String(d.getDate()).padStart(2, '0'); - return `${y}-${m}-${day}`; - }; - - // Don't render until the client has set the real date - if (!current) { - return ( -
- ); - } - - const byDate: Record = {}; - for (const a of assignments) { - if (!a.due_date) continue; - if (!byDate[a.due_date]) byDate[a.due_date] = []; - byDate[a.due_date].push(a); - } - - const navigate = (dir: -1 | 1) => { - if (view === 'month') { - setCurrent(c => c ? new Date(c.getFullYear(), c.getMonth() + dir, 1) : c); - } else if (view === 'week') { - setCurrent(c => c ? new Date(c.getTime() + dir * 7 * 86400000) : c); - } else { - setCurrent(c => c ? new Date(c.getTime() + dir * 86400000) : c); - } - }; - - const headerLabel = () => { - if (view === 'month') { - return current.toLocaleDateString('en-US', { month: 'long', year: 'numeric' }); - } - if (view === 'week') { - const start = new Date(current); - start.setDate(start.getDate() - start.getDay()); - const end = new Date(start); - end.setDate(end.getDate() + 6); - const s = start.toLocaleDateString('en-US', { month: 'short', day: 'numeric' }); - const e = end.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' }); - return `${s} – ${e}`; - } - return current.toLocaleDateString('en-US', { weekday: 'long', month: 'long', day: 'numeric', year: 'numeric' }); - }; - - // ── Month View ──────────────────────────────────────────────────────────── - const renderMonth = () => { - const year = current.getFullYear(); - const monthIdx = current.getMonth(); - const firstDay = new Date(year, monthIdx, 1).getDay(); - const daysInMonth = new Date(year, monthIdx + 1, 0).getDate(); - const DAY_NAMES = isMobile ? ['S', 'M', 'T', 'W', 'T', 'F', 'S'] : ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; - - return ( -
- {DAY_NAMES.map((d, i) => ( -
- {d} -
- ))} - {Array.from({ length: firstDay }, (_, i) => ( -
- ))} - {Array.from({ length: daysInMonth }, (_, i) => { - const day = i + 1; - const iso = `${year}-${String(monthIdx + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`; - const dayAssignments = byDate[iso] ?? []; - const isToday = iso === today; - return ( -
-
- - {day} - -
-
- {dayAssignments.slice(0, 3).map(a => )} - {dayAssignments.length > 3 && ( - +{dayAssignments.length - 3} more - )} -
-
- ); - })} -
- ); - }; - - // ── Week View ───────────────────────────────────────────────────────────── - const renderWeek = () => { - const start = new Date(current); - start.setDate(start.getDate() - start.getDay()); - const days = Array.from({ length: 7 }, (_, i) => { - const d = new Date(start); - d.setDate(d.getDate() + i); - return d; - }); - const DAY_NAMES = isMobile ? ['S', 'M', 'T', 'W', 'T', 'F', 'S'] : ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; - - return ( -
- {days.map((d, i) => { - const iso = toISO(d); - const isToday = iso === today; - return ( -
-
{DAY_NAMES[i]}
-
- - {d.getDate()} - -
-
- ); - })} - {days.map((d, i) => { - const iso = toISO(d); - const dayAssignments = byDate[iso] ?? []; - const isToday = iso === today; - return ( -
- {dayAssignments.map(a => )} -
- ); - })} -
- ); - }; - - // ── Day View ────────────────────────────────────────────────────────────── - const renderDay = () => { - const iso = toISO(current); - const dayAssignments = byDate[iso] ?? []; - return ( -
- {dayAssignments.length === 0 ? ( -

No assignments due on this day.

- ) : ( -
- {dayAssignments.map(a => { - const c = TYPE_COLORS[a.assignment_type ?? 'other'] ?? TYPE_COLORS.other; - return ( -
- {a.title} -
- {a.course_name && {a.course_name}} - {a.assignment_type} - {a.notes && {a.notes}} -
-
- ); - })} -
- )} -
- ); - }; - - const viewBtnStyle = (v: CalendarView): React.CSSProperties => ({ - padding: '5px 14px', - fontSize: '12px', - border: view === v ? '1px solid rgba(26,92,42,0.35)' : '1px solid rgba(107,114,128,0.18)', - borderRadius: '5px', - cursor: 'pointer', - background: view === v ? 'rgba(26,92,42,0.08)' : 'transparent', - color: view === v ? '#1a5c2a' : '#6b7280', - fontWeight: view === v ? 600 : 400, - transition: 'all 0.1s', - }); - - return ( -
- {/* Header */} -
-
- - - -
- {headerLabel()} -
- {(['day', 'week', 'month'] as CalendarView[]).map(v => ( - - ))} -
-
- - {view === 'month' && renderMonth()} - {view === 'week' && renderWeek()} - {view === 'day' && renderDay()} -
- ); -} - - -function normalizeAssignments(items: any[]): Assignment[] { - return (items ?? []).map((a: any, index: number) => ({ - id: a.id ?? `missing-id-${index}`, - title: a.title ?? '', - course_name: a.course_name ?? '', - course_code: a.course_code ?? '', - course_id: a.course_id ?? '', - due_date: a.due_date ?? '', - assignment_type: a.assignment_type ?? 'other', - notes: a.notes ?? null, - google_event_id: a.google_event_id ?? null, - })); -} - -function CalendarInner() { - const { userId: USER_ID, userReady } = useUser(); - const searchParams = useSearchParams(); - const isMobile = useIsMobile(); - - const [assignments, setAssignments] = useState([]); - const [syncing, setSyncing] = useState(false); - const [syncedCount, setSyncedCount] = useState(null); - const [googleConnected, setGoogleConnected] = useState(false); - const [googleEvents, setGoogleEvents] = useState([]); - const [importingGoogle, setImportingGoogle] = useState(false); - const [courses, setCourses] = useState([]); - const [showUpload, setShowUpload] = useState(false); - - // Fetch data once when user is ready — does NOT depend on searchParams to - // prevent repeated fetches every time Next.js reconstructs the search params object - useEffect(() => { - if (!userReady) return; - getAllAssignments(USER_ID) - .then(data => setAssignments(normalizeAssignments(data.assignments ?? []))) - .catch(console.error); - getCalendarStatus(USER_ID) - .then(res => setGoogleConnected(res.connected)) - .catch(() => {}); - getCourses(USER_ID) - .then(data => setCourses(data.courses ?? [])) - .catch(console.error); - }, [USER_ID, userReady]); - - // Handle OAuth redirect (?connected=true) once on mount, independently - useEffect(() => { - if (searchParams.get('connected') === 'true') { - setGoogleConnected(true); - } - }, []); // eslint-disable-line react-hooks/exhaustive-deps - - const refreshAssignments = () => - getAllAssignments(USER_ID) - .then(data => setAssignments(normalizeAssignments(data.assignments ?? []))) - .catch(console.error); - - const handleUploadClose = (uploaded: UploadedDoc[]) => { - setShowUpload(false); - if (uploaded.some(d => d.category === 'syllabus')) { - refreshAssignments(); - // Assignment inserts can race with the response — resync once more shortly. - window.setTimeout(() => { refreshAssignments(); }, 1500); - } - }; - - const handleDisconnectGoogle = async () => { - if (!window.confirm('Disconnect from Google Calendar? Synced events will not be removed.')) return; - try { - await disconnectGoogleCalendar(USER_ID); - setGoogleConnected(false); - setGoogleEvents([]); - setSyncedCount(null); - } catch (e: any) { - alert(e.message || 'Failed to disconnect.'); - } - }; - - const handleSync = async () => { - setSyncing(true); - setSyncedCount(null); - try { - const res = await syncToGoogleCalendar(USER_ID); - setSyncedCount(res.synced_count); - // Refresh so google_event_id values are up to date - refreshAssignments(); - } catch (e: any) { - alert(e.message); - } finally { - setSyncing(false); - } - }; - - const handleImportGoogle = async () => { - setImportingGoogle(true); - try { - const res = await importGoogleEvents(USER_ID, 60); - setGoogleEvents(res.events); - } catch (e: any) { - alert(e.message || 'Failed to import Google Calendar events.'); - } finally { - setImportingGoogle(false); - } - }; - - return ( -
-
-

Calendar

- -
- - {/* Calendar grid — full width, prominent */} -
- -
- - {/* All assignments */} -
-

- All Assignments -

- {assignments.length === 0 ? ( -

No assignments yet. Import a syllabus to get started.

- ) : ( - - )} -
- - {/* Google Calendar panel */} -
- {googleConnected ? ( - <> -
- ● Connected to Google Calendar - - - - - - {syncedCount !== null && ( - - {syncedCount === 0 ? 'All assignments already synced' : `Synced ${syncedCount} assignment${syncedCount !== 1 ? 's' : ''}`} - - )} - - -
- - {/* Imported Google events preview */} - {googleEvents.length > 0 && ( -
-

- Upcoming Google Events ({googleEvents.length}) -

- {googleEvents.map(ev => ( -
- {ev.title} - {ev.start_date} -
- ))} -
- )} - - ) : ( -

- Sign in with Google to enable calendar sync. -

- )} -
- - -
- ); -} - -export default function CalendarPage() { - return ( - Loading...
}> - - - ); -} diff --git a/frontend/src/app/careers/[slug]/ApplyForm.tsx b/frontend/src/app/careers/[slug]/ApplyForm.tsx deleted file mode 100644 index d94c9d29..00000000 --- a/frontend/src/app/careers/[slug]/ApplyForm.tsx +++ /dev/null @@ -1,409 +0,0 @@ -'use client'; - -import { useState, useRef } from 'react'; -import Link from 'next/link'; -import { type Job, DEPT_COLORS } from '../jobs'; -import { submitJobApplication } from '@/lib/api'; - -const UI_FONT = "var(--font-dm-sans), 'DM Sans', sans-serif"; - -const PANEL: React.CSSProperties = { - background: '#ffffff', - border: '1px solid rgba(107, 114, 128, 0.15)', - borderRadius: '12px', - boxShadow: '0 2px 10px rgba(26, 92, 42, 0.07), 0 1px 3px rgba(26, 92, 42, 0.04)', -}; - -const INPUT: React.CSSProperties = { - width: '100%', - background: '#f8fbf8', - border: '1px solid rgba(107, 114, 128, 0.18)', - borderRadius: '8px', - padding: '10px 14px', - fontSize: '14px', - color: '#111827', - fontFamily: UI_FONT, - outline: 'none', - boxSizing: 'border-box', - transition: 'border-color 0.15s', -}; - -const LABEL: React.CSSProperties = { - display: 'block', - fontSize: '13px', - fontWeight: 500, - color: '#374151', - marginBottom: '6px', -}; - -export default function ApplyForm({ job }: { job: Job | null }) { - const [form, setForm] = useState({ name: '', email: '', phone: '', linkedin: '', portfolio: '' }); - const [resumeFile, setResumeFile] = useState(null); - const [dragging, setDragging] = useState(false); - const [submitted, setSubmitted] = useState(false); - const [submitting, setSubmitting] = useState(false); - const [submitError, setSubmitError] = useState(null); - const [agreedToPrivacy, setAgreedToPrivacy] = useState(false); - const fileInputRef = useRef(null); - - if (!job) { - return ( -
-
-

Role not found.

- ← Back to opportunities -
-
- ); - } - - const dept = DEPT_COLORS[job.department]; - - const handleDrop = (e: React.DragEvent) => { - e.preventDefault(); - setDragging(false); - const file = e.dataTransfer.files[0]; - if (file) setResumeFile(file); - }; - - const handleFileChange = (e: React.ChangeEvent) => { - const file = e.target.files?.[0]; - if (file) setResumeFile(file); - }; - - const handleSubmit = async (e: React.SyntheticEvent) => { - e.preventDefault(); - if (!resumeFile) { - setSubmitError('Please attach your resume (PDF) before submitting.'); - return; - } - setSubmitting(true); - setSubmitError(null); - try { - await submitJobApplication({ - position: job.slug, - full_name: form.name, - email: form.email, - phone: form.phone, - linkedin_url: form.linkedin, - portfolio_link: form.portfolio || undefined, - resume: resumeFile, - }); - setSubmitted(true); - } catch (err) { - setSubmitError(err instanceof Error ? err.message : 'Something went wrong. Please try again.'); - } finally { - setSubmitting(false); - } - }; - - return ( -
- - {/* ── Header ── */} -
-
- - Sapling - - Sapling - - - (e.currentTarget.style.color = '#111827')} - onMouseLeave={e => (e.currentTarget.style.color = '#6b7280')} - > - ← Back to opportunities - -
-
- - {/* ── Content ── */} -
- - {/* Job context */} -
-
-

- {job.title} -

- {dept && ( - - {job.department} - - )} -
-

- {job.location} · {job.type} -

-
- - {/* Form panel */} -
- {submitted ? ( -
-
- - - -
-

- Application submitted -

-

- Thanks for applying to Sapling. We'll review your application and reach out soon. -

- - ← Back to opportunities - -
- ) : ( -
-
- - {/* Full Name */} -
- - setForm(f => ({ ...f, name: e.target.value }))} - style={INPUT} - onFocus={e => (e.currentTarget.style.borderColor = 'rgba(26,92,42,0.4)')} - onBlur={e => (e.currentTarget.style.borderColor = 'rgba(107,114,128,0.18)')} - /> -
- - {/* Email */} -
- - setForm(f => ({ ...f, email: e.target.value }))} - style={INPUT} - onFocus={e => (e.currentTarget.style.borderColor = 'rgba(26,92,42,0.4)')} - onBlur={e => (e.currentTarget.style.borderColor = 'rgba(107,114,128,0.18)')} - /> -
- - {/* Phone */} -
- - setForm(f => ({ ...f, phone: e.target.value }))} - style={INPUT} - onFocus={e => (e.currentTarget.style.borderColor = 'rgba(26,92,42,0.4)')} - onBlur={e => (e.currentTarget.style.borderColor = 'rgba(107,114,128,0.18)')} - /> -
- - {/* LinkedIn */} -
- - setForm(f => ({ ...f, linkedin: e.target.value }))} - style={INPUT} - onFocus={e => (e.currentTarget.style.borderColor = 'rgba(26,92,42,0.4)')} - onBlur={e => (e.currentTarget.style.borderColor = 'rgba(107,114,128,0.18)')} - /> -
- - {/* Portfolio */} -
- - setForm(f => ({ ...f, portfolio: e.target.value }))} - style={INPUT} - onFocus={e => (e.currentTarget.style.borderColor = 'rgba(26,92,42,0.4)')} - onBlur={e => (e.currentTarget.style.borderColor = 'rgba(107,114,128,0.18)')} - /> -
- - {/* Resume */} -
- -
fileInputRef.current?.click()} - onDragOver={e => { e.preventDefault(); setDragging(true); }} - onDragLeave={() => setDragging(false)} - onDrop={handleDrop} - style={{ - border: `1.5px dashed ${dragging ? 'rgba(26,92,42,0.5)' : 'rgba(107,114,128,0.25)'}`, - borderRadius: '8px', - padding: '28px 20px', - textAlign: 'center', - cursor: 'pointer', - background: dragging ? 'rgba(26,92,42,0.03)' : '#f8fbf8', - transition: 'all 0.15s', - }} - > - {resumeFile ? ( -
- - - - {resumeFile.name} - -
- ) : ( - <> - - - -

- Click to upload or drag and drop -

-

PDF only

- - )} - -
-
- -
- - {/* Privacy consent */} -
- setAgreedToPrivacy(e.target.checked)} - style={{ marginTop: '2px', accentColor: '#1a5c2a', cursor: 'pointer', flexShrink: 0 }} - /> - -
- - {/* Submit */} -
- {submitError && ( -

- {submitError} -

- )} - -

- Fields marked * are required -

-
-
- )} -
-
- - {/* ── Footer ── */} -
-
-
- Sapling - Sapling · © 2026 -
-
- {[ - { label: 'Home', href: '/' }, - { label: 'About', href: '/about' }, - { label: 'Careers', href: '/careers' }, - { label: 'Terms of Service', href: '/terms' }, - { label: 'Privacy Policy', href: '/privacy' }, - ].map(({ label, href }) => ( - (e.currentTarget.style.color = '#111827')} - onMouseLeave={e => (e.currentTarget.style.color = '#6b7280')} - > - {label} - - ))} -
-
-
-

- © 2026 Andres Lopez, Jack He, Luke Cooper, and Jose Gael Cruz-Lopez. All Rights Reserved. -

-
-
-
- ); -} diff --git a/frontend/src/app/careers/[slug]/page.tsx b/frontend/src/app/careers/[slug]/page.tsx deleted file mode 100644 index 086a35a1..00000000 --- a/frontend/src/app/careers/[slug]/page.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { JOBS } from '../jobs'; -import ApplyForm from './ApplyForm'; - -export function generateStaticParams() { - return JOBS.map(job => ({ slug: job.slug })); -} - -export default async function ApplyPage({ params }: { params: Promise<{ slug: string }> }) { - const { slug } = await params; - const job = JOBS.find(j => j.slug === slug) ?? null; - return ; -} diff --git a/frontend/src/app/careers/jobs.ts b/frontend/src/app/careers/jobs.ts deleted file mode 100644 index 96f3155a..00000000 --- a/frontend/src/app/careers/jobs.ts +++ /dev/null @@ -1,28 +0,0 @@ -export interface Job { - id: number; - slug: string; - title: string; - department: string; - location: string; - type: string; - description: string; - tags: string[]; -} - -export const JOBS: Job[] = [ - { - id: 1, - slug: 'marketing-intern', - title: 'Marketing Intern', - department: 'Growth', - location: 'Hybrid', - type: 'Internship', - description: - "Help Sapling reach more students. You'll run social campaigns, create content, build relationships with student organizations, and help shape our brand voice from the ground up. On the video side, you'll produce and render short-form clips, professional product trailers, and feature update videos with consistent branding. Experience in marketing or advertising is preferred. Having some knowledge in software or tech is also a plus. Great fit for someone who loves learning and wants real ownership from day one.", - tags: ['Branding', 'Video Production', 'Content Creation', 'Social Media', 'Community', 'Business', 'Analytics', 'AI Fluency'], - }, -]; - -export const DEPT_COLORS: Record = { - Growth: { bg: 'rgba(217,119,6,0.07)', text: '#b45309', border: 'rgba(217,119,6,0.18)' }, -}; diff --git a/frontend/src/app/careers/page.tsx b/frontend/src/app/careers/page.tsx deleted file mode 100644 index c5ba85a0..00000000 --- a/frontend/src/app/careers/page.tsx +++ /dev/null @@ -1,255 +0,0 @@ -'use client'; - -import { useState } from 'react'; -import Link from 'next/link'; -import { JOBS, DEPT_COLORS } from './jobs'; - -const GLASS: React.CSSProperties = { - background: '#ffffff', - border: '1px solid rgba(107, 114, 128, 0.15)', - borderRadius: '10px', - boxShadow: '0 2px 10px rgba(26, 92, 42, 0.07), 0 1px 3px rgba(26, 92, 42, 0.04)', -}; - -const GLASS_STRONG: React.CSSProperties = { - background: 'rgba(255, 255, 255, 0.72)', - backdropFilter: 'blur(40px) saturate(1.8)', - WebkitBackdropFilter: 'blur(40px) saturate(1.8)', - border: '1px solid rgba(255, 255, 255, 0.6)', - borderRadius: '16px', - boxShadow: '0 8px 32px rgba(26, 92, 42, 0.10), 0 2px 8px rgba(26, 92, 42, 0.06)', -}; - -const UI_FONT = "var(--font-dm-sans), 'DM Sans', sans-serif"; - - -export default function CareersPage() { - const [expandedId, setExpandedId] = useState(null); - - return ( -
- - {/* ── Header ── */} -
-
- - Sapling - - Sapling - - - (e.currentTarget.style.color = '#111827')} - onMouseLeave={e => (e.currentTarget.style.color = '#6b7280')} - > - ← Back to home - -
-
- - {/* ── Hero ── */} -
-
- - - We're hiring - -
- -

- Opportunities -

- -

- We're a small team building tools that help students learn better. - If that sounds like work worth doing, we'd love to meet you. -

-
- - {/* ── Job Listings ── */} -
-
- {JOBS.map((job) => { - const dept = DEPT_COLORS[job.department] ?? DEPT_COLORS.Engineering; - const isOpen = expandedId === job.id; - - return ( -
- {/* Toggle row — native button for keyboard/a11y */} - - - {/* Expanded content */} -
-

- {job.description} -

-
- {job.tags.map(tag => ( - - {tag} - - ))} -
- (e.currentTarget.style.background = '#155A35')} - onMouseLeave={e => (e.currentTarget.style.background = '#1B6C42')} - > - Apply for this role - - - - -
-
- ); - })} -
- - {/* General Application */} - -
- - {/* ── Footer ── */} -
-
-
- Sapling - Sapling · © 2026 -
-
- {[ - { label: 'Home', href: '/' }, - { label: 'About', href: '/about' }, - { label: 'Careers', href: '/careers' }, - { label: 'Terms of Service', href: '/terms' }, - { label: 'Privacy Policy', href: '/privacy' }, - ].map(({ label, href }) => ( - (e.currentTarget.style.color = '#111827')} - onMouseLeave={e => (e.currentTarget.style.color = '#6b7280')} - > - {label} - - ))} -
-
-
-

- © 2026 Andres Lopez, Jack He, Luke Cooper, and Jose Gael Cruz-Lopez. All Rights Reserved. -

-
-
-
- ); -} diff --git a/frontend/src/app/dashboard/page.tsx b/frontend/src/app/dashboard/page.tsx deleted file mode 100644 index d048f8e9..00000000 --- a/frontend/src/app/dashboard/page.tsx +++ /dev/null @@ -1,1536 +0,0 @@ -'use client'; - -import { useEffect, useLayoutEffect, useState, useRef, useMemo, useCallback, Suspense } from 'react'; -import { createPortal } from 'react-dom'; -import { useRouter, useSearchParams } from 'next/navigation'; -import KnowledgeGraph from '@/components/KnowledgeGraph'; -import { GraphNode, GraphStats, Recommendation, Assignment } from '@/lib/types'; -import { - getGraph, - getRecommendations, - getUpcomingAssignments, - getCourses, - addCourse, - deleteCourse, - updateCourseColor, - type EnrolledCourse, -} from '@/lib/api'; -import { getMasteryColor, getMasteryLabel, formatDueDate, formatRelativeTime, getCourseColor, PRESET_COURSE_COLORS, RAINBOW_COLORS } from '@/lib/graphUtils'; -import { useUser } from '@/context/UserContext'; -import Link from 'next/link'; -import { Maximize2, Minimize2 } from 'lucide-react'; - -const API_URL = process.env.NEXT_PUBLIC_API_URL ?? 'http://localhost:5000'; - -interface CourseCatalogOption { - id: string; - course_code: string; - course_name: string; -} - -const STATS_LABELS: Record = { - mastered: 'Mastered', - learning: 'Learning', - struggling: 'Struggling', - unexplored: 'Unexplored', -}; - -const GLASS: React.CSSProperties = { - background: '#ffffff', - border: '1px solid rgba(107, 114, 128, 0.15)', - borderRadius: '10px', -}; - -const UI_FONT = "var(--font-dm-sans), 'DM Sans', sans-serif"; - -const QUOTES = [ - '"The more that you read, the more things you will know." — Dr. Seuss', - '"Live as if you were to die tomorrow. Learn as if you were to live forever." — Gandhi', - '"The beautiful thing about learning is that no one can take it away from you." — B.B. King', - '"Education is not the filling of a pail, but the lighting of a fire." — W.B. Yeats', - '"An investment in knowledge pays the best interest." — Benjamin Franklin', - '"Tell me and I forget. Teach me and I remember. Involve me and I learn." — Benjamin Franklin', - '"The capacity to learn is a gift; the ability to learn is a skill; the willingness to learn is a choice." — Brian Herbert', - 'Fun fact: The human brain can store roughly 2.5 petabytes of information.', - 'Fun fact: Spaced repetition can boost long-term retention by up to 80%.', - 'Fun fact: Teaching others is one of the most effective ways to solidify your own knowledge.', - 'Fun fact: Your brain consolidates memories during sleep — rest is part of learning.', - 'Fun fact: Taking short breaks during study sessions can improve focus and retention.', - 'Fun fact: Handwriting notes activates more areas of the brain than typing them.', -]; - -function getTimeGreeting(): string { - const hour = new Date().getHours(); - if (hour >= 5 && hour < 12) return 'Good Morning'; - if (hour >= 12 && hour < 17) return 'Good Afternoon'; - return 'Good Evening'; -} - -function useIsMobile(breakpoint = 768) { - const [isMobile, setIsMobile] = useState(false); - useEffect(() => { - const mql = window.matchMedia(`(max-width: ${breakpoint}px)`); - setIsMobile(mql.matches); - const handler = (e: MediaQueryListEvent) => setIsMobile(e.matches); - mql.addEventListener('change', handler); - return () => mql.removeEventListener('change', handler); - }, [breakpoint]); - return isMobile; -} - -function DashboardInner() { - const router = useRouter(); - const searchParams = useSearchParams(); - const { userId, userName, userReady } = useUser(); - const isMobile = useIsMobile(); - - // Suggested concept from Navbar "What should I learn next?" button - const suggestConcept = searchParams.get('suggest') ?? ''; - const containerRef = useRef(null); - const fullscreenGraphRef = useRef(null); - const [graphDimensions, setGraphDimensions] = useState({ width: 0, height: 0 }); - const [graphFullscreen, setGraphFullscreen] = useState(false); - const [fullscreenGraphDimensions, setFullscreenGraphDimensions] = useState({ width: 0, height: 0 }); - const hasDimensionsRef = useRef(false); - - const [nodes, setNodes] = useState([]); - const [edges, setEdges] = useState([]); - const [stats, setStats] = useState(null); - const [recommendations, setRecommendations] = useState([]); - // All upcoming assignments — used by course panel and upcoming strip - const [allAssignments, setAllAssignments] = useState([]); - const [loading, setLoading] = useState(true); - const [fetchError, setFetchError] = useState(null); - - // Mobile: which sidebar tab is expanded - const [mobileSidebarTab, setMobileSidebarTab] = useState<'courses' | 'stats' | null>(null); - - // Greeting animation - const [displayedGreeting, setDisplayedGreeting] = useState(''); - const [greetingDone, setGreetingDone] = useState(false); - const [cursorVisible, setCursorVisible] = useState(true); - const [quote, setQuote] = useState(''); - // Collapsed courses state (set of subject names that are collapsed) - const [collapsedCourses, setCollapsedCourses] = useState>(new Set()); - - const toggleCourse = (subject: string) => { - setCollapsedCourses(prev => { - const next = new Set(prev); - if (next.has(subject)) next.delete(subject); - else next.add(subject); - return next; - }); - }; - - // Courses panel state - const [showCourses, setShowCourses] = useState(false); - const [courseList, setCourseList] = useState([]); - const [courseColorMap, setCourseColorMap] = useState>({}); - const [courseSearchInput, setCourseSearchInput] = useState(''); - const [courseSuggestions, setCourseSuggestions] = useState([]); - const [courseSearchFocused, setCourseSearchFocused] = useState(false); - const [courseInputRect, setCourseInputRect] = useState(null); - const courseInputRef = useRef(null); - const courseDebounceRef = useRef(null); - const [courseAdding, setCourseAdding] = useState(false); - const [courseDeleting, setCourseDeleting] = useState(null); - const [courseError, setCourseError] = useState(''); - // Inline color picker state - const [editingColorFor, setEditingColorFor] = useState(null); - const [colorHexInput, setColorHexInput] = useState(''); - const [confirmDeleteCourse, setConfirmDeleteCourse] = useState(null); - - - // Mon–Sun dates for the current week (computed once on mount) - const weekInfo = useMemo(() => { - const today = new Date(); - today.setHours(0, 0, 0, 0); - const todayISO = today.toISOString().split('T')[0]; - const dow = today.getDay(); // 0=Sun … 6=Sat - const daysFromMon = dow === 0 ? 6 : dow - 1; - const monday = new Date(today); - monday.setDate(today.getDate() - daysFromMon); - const LABELS = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']; - const dates = LABELS.map((label, i) => { - const d = new Date(monday); - d.setDate(monday.getDate() + i); - const iso = d.toISOString().split('T')[0]; - return { label, iso, isToday: iso === todayISO, isFuture: iso > todayISO }; - }); - return { todayISO, dates }; - }, []); - - // Which days this week had any study activity (derived from node last_studied_at) - const activeDaysThisWeek = useMemo(() => { - const set = new Set(); - const weekIsos = new Set(weekInfo.dates.map(d => d.iso)); - for (const n of nodes) { - if (n.last_studied_at) { - const iso = n.last_studied_at.split('T')[0]; - if (weekIsos.has(iso)) set.add(iso); - } - } - return set; - }, [nodes, weekInfo]); - - - // Filter out edges that cross subject boundaries so each course cluster stays separate. - // Subject-root edges (subject_root__*) are always kept; only same-subject concept edges are kept. - const filteredEdges = useMemo(() => { - const nodeSubjectMap = new Map(nodes.map(n => [n.id, n.subject])); - return edges.filter(e => { - const srcId = e.source as string; - const tgtId = e.target as string; - if (srcId.startsWith('subject_root__') || tgtId.startsWith('subject_root__')) return true; - const srcSubj = nodeSubjectMap.get(srcId); - const tgtSubj = nodeSubjectMap.get(tgtId); - return !srcSubj || !tgtSubj || srcSubj === tgtSubj; - }); - }, [nodes, edges]); - - // Node matching the Navbar's "learn next" suggestion - const suggestNode = useMemo( - () => (suggestConcept ? nodes.find(n => n.concept_name === suggestConcept) ?? null : null), - [nodes, suggestConcept] - ); - - useEffect(() => { - if (!userReady || !userId) return; - async function load() { - try { - const [graphData, recData, assignData, courseData] = await Promise.all([ - getGraph(userId), - getRecommendations(userId), - getUpcomingAssignments(userId), - getCourses(userId), - ]); - setNodes(graphData.nodes); - setEdges(graphData.edges); - setStats(graphData.stats); - setRecommendations(recData.recommendations.slice(0, 3)); - setAllAssignments(assignData.assignments); - setCourseList(courseData.courses); - const colorMap: Record = {}; - courseData.courses.forEach(c => { if (c.color) colorMap[c.course_name] = c.color; }); - setCourseColorMap(colorMap); - } catch (e: any) { - console.error(e); - setFetchError(e.message || 'Failed to load dashboard data.'); - } finally { - setLoading(false); - } - } - load(); - }, [userId, userReady]); - - // Pick a random quote on the client only (avoids SSR/client hydration mismatch) - useEffect(() => { - setQuote(QUOTES[Math.floor(Math.random() * QUOTES.length)]); - }, []); - - useEffect(() => () => { - if (courseDebounceRef.current) clearTimeout(courseDebounceRef.current); - }, []); - - // Track the search input's viewport rect so the portal dropdown stays pinned - // to it as the modal scrolls or the window resizes. - useLayoutEffect(() => { - const open = showCourses && courseSearchFocused && courseSuggestions.length > 0; - if (!open) { - setCourseInputRect(null); - return; - } - const update = () => { - if (courseInputRef.current) { - setCourseInputRect(courseInputRef.current.getBoundingClientRect()); - } - }; - update(); - window.addEventListener('resize', update); - window.addEventListener('scroll', update, true); - return () => { - window.removeEventListener('resize', update); - window.removeEventListener('scroll', update, true); - }; - }, [showCourses, courseSearchFocused, courseSuggestions.length]); - - // Typing animation for greeting - useEffect(() => { - const firstName = userName.split(' ')[0]; - const greeting = `${getTimeGreeting()}, ${firstName}.`; - let i = 0; - setDisplayedGreeting(''); - setGreetingDone(false); - setCursorVisible(true); - const interval = setInterval(() => { - i++; - setDisplayedGreeting(greeting.slice(0, i)); - if (i >= greeting.length) { - clearInterval(interval); - setTimeout(() => setGreetingDone(true), 300); - } - }, 55); - return () => clearInterval(interval); - }, [userName]); - - // Blinking cursor while typing - useEffect(() => { - if (greetingDone) { - setCursorVisible(false); - return; - } - const blink = setInterval(() => setCursorVisible(v => !v), 530); - return () => clearInterval(blink); - }, [greetingDone]); - - useEffect(() => { - const el = containerRef.current; - if (!el) return; - let timer: ReturnType; - const obs = new ResizeObserver(entries => { - const entry = entries[0]; - if (!entry) return; - const { width, height } = entry.contentRect; - if (!hasDimensionsRef.current) { - hasDimensionsRef.current = true; - setGraphDimensions({ width, height }); - } else { - clearTimeout(timer); - timer = setTimeout(() => setGraphDimensions(prev => { - if (Math.abs(prev.width - width) < 5 && Math.abs(prev.height - height) < 5) return prev; - return { width, height }; - }), 250); - } - }); - obs.observe(el); - return () => { obs.disconnect(); clearTimeout(timer); }; - }, [loading]); - - // Fullscreen graph (#24): measure overlay pane; Escape exits - useLayoutEffect(() => { - if (!graphFullscreen) return; - const el = fullscreenGraphRef.current; - if (!el) return; - const ro = new ResizeObserver(entries => { - const cr = entries[0]?.contentRect; - if (cr && cr.width > 0 && cr.height > 0) { - setFullscreenGraphDimensions({ width: cr.width, height: cr.height }); - } - }); - ro.observe(el); - const onKey = (e: KeyboardEvent) => { - if (e.key === 'Escape') setGraphFullscreen(false); - }; - window.addEventListener('keydown', onKey); - const prevOverflow = document.body.style.overflow; - document.body.style.overflow = 'hidden'; - return () => { - ro.disconnect(); - window.removeEventListener('keydown', onKey); - document.body.style.overflow = prevOverflow; - }; - }, [graphFullscreen]); - - const handleNodeClick = useCallback((node: GraphNode) => { - router.push(`/learn?topic=${encodeURIComponent(node.concept_name)}`); - }, [router]); - - - const handleCourseSearchInput = (value: string) => { - setCourseSearchInput(value); - setCourseError(''); - if (courseDebounceRef.current) clearTimeout(courseDebounceRef.current); - if (value.trim().length < 1) { setCourseSuggestions([]); return; } - courseDebounceRef.current = setTimeout(async () => { - try { - const res = await fetch(`${API_URL}/api/onboarding/courses?q=${encodeURIComponent(value)}`); - const data: { courses: CourseCatalogOption[] } = await res.json(); - const enrolledIds = new Set(courseList.map(c => c.course_id)); - setCourseSuggestions(data.courses.filter(c => !enrolledIds.has(c.id)).slice(0, 5)); - } catch { - setCourseSuggestions([]); - } finally { - courseDebounceRef.current = null; - } - }, 200); - }; - - const handleAddCourseFromCatalog = async (course: CourseCatalogOption) => { - setCourseError(''); - setCourseAdding(true); - try { - const usedColors = new Set(Object.values(courseColorMap)); - const pickedColor = PRESET_COURSE_COLORS.find(c => !usedColors.has(c)) ?? PRESET_COURSE_COLORS[0]; - const res = await addCourse(userId, course.id, pickedColor); - if (res.already_existed) { - setCourseError(`"${course.course_code}" is already in your course list.`); - } else if (res.error) { - setCourseError(res.error); - } else { - setCourseSearchInput(''); - setCourseSuggestions([]); - const updated = await getCourses(userId); - setCourseList(updated.courses); - const colorMap: Record = {}; - updated.courses.forEach(c => { if (c.color) colorMap[c.course_name] = c.color; }); - setCourseColorMap(colorMap); - const graphData = await getGraph(userId); - setNodes(graphData.nodes); - setEdges(graphData.edges); - } - } catch (e: any) { - let msg = e.message || 'Failed to add course.'; - try { - const j = JSON.parse(msg); - if (j.detail) msg = typeof j.detail === 'string' ? j.detail : JSON.stringify(j.detail); - } catch { /* keep msg */ } - setCourseError(msg); - } finally { - setCourseAdding(false); - } - }; - - const handleColorChange = async (courseId: string, courseName: string, newHex: string) => { - if (!/^#[0-9a-fA-F]{6}$/.test(newHex)) return; - try { - await updateCourseColor(userId, courseId, newHex); - setCourseList(prev => prev.map(c => (c.course_id === courseId ? { ...c, color: newHex } : c))); - setCourseColorMap(prev => ({ ...prev, [courseName]: newHex })); - setEditingColorFor(null); - // Refresh graph so nodes carry the updated course_color - const graphData = await getGraph(userId); - setNodes(graphData.nodes); - setEdges(graphData.edges); - } catch (e) { - console.error(e); - } - }; - - const handleDeleteCourse = async (courseId: string) => { - setCourseDeleting(courseId); - try { - await deleteCourse(userId, courseId); - setCourseList(prev => prev.filter(c => c.course_id !== courseId)); - // Refresh graph so the removed subject-root node disappears - const graphData = await getGraph(userId); - setNodes(graphData.nodes); - setEdges(graphData.edges); - } catch (e) { - console.error(e); - } finally { - setCourseDeleting(null); - } - }; - - if (loading) { - return ( -
- Loading your dashboard... -
- ); - } - - if (fetchError) { - return ( -
-

Failed to load dashboard

-

{fetchError}

- -
- ); - } - - return ( - <> -
- - {/* ── Left panel: Course list ─────────────────────────────────────── */} - {!isMobile && ( -
-

- Courses -

- - {loading ? ( -
Loading…
- ) : courseList.length === 0 ? ( -
No courses yet
- ) : ( - courseList.map(course => { - const subject = course.course_name; - const c = getCourseColor(subject, course.color); - const conceptNodes = nodes.filter(n => n.subject === subject && !n.is_subject_root && n.mastery_tier !== 'subject_root'); - const avgMastery = conceptNodes.length > 0 - ? conceptNodes.reduce((s, n) => s + n.mastery_score, 0) / conceptNodes.length - : 0; - const pct = Math.round(avgMastery * 100); - - // 5 soonest upcoming assignments for this course (case-insensitive match) - const courseAssignments = allAssignments - .filter(a => a.course_name?.toLowerCase() === subject.toLowerCase() && a.due_date) - .sort((a, b) => a.due_date.localeCompare(b.due_date)) - .slice(0, 5); - - const isCollapsed = collapsedCourses.has(subject); - - return ( -
- {/* Course name row — clickable to collapse */} - - - {/* Progress bar */} -
-
-
- - {pct}% mastery - - - {/* Upcoming assignments — always rendered, collapsed via maxHeight */} -
-
- {courseAssignments.length === 0 ? ( - No upcoming assignments - ) : courseAssignments.map(a => ( -
- {/* Assignment title in course color */} -
- {a.title} -
- {/* Category / type + due date */} -
- - {a.assignment_type} - - {formatDueDate(a.due_date)} -
-
- ))} -
-
-
- ); - }) - )} -
- )} - - {/* ── Center: Greeting + Graph + Upcoming ────────────────────────── */} -
- - {/* Header: Typed Greeting + Quote + Action Buttons */} -
-

- {displayedGreeting} - - | - -

- -

- {quote} -

- -
- - Start Learning - - - Upload Assignments - - -
-
- - {/* Knowledge Graph */} -
- {!loading && graphDimensions.width > 0 && !isMobile && ( - - )} - {loading || graphDimensions.width === 0 ? ( -
- Loading graph… -
- ) : ( - - )} - - {/* AI "learn next" suggestion popup */} - {suggestConcept && suggestNode && ( -
-
- -
-

- AI Recommendation -

-

- {suggestConcept} -

-

- Based on your knowledge graph, this concept will have the highest impact on your mastery. -

-
-
-
- - -
-
- )} -
- - {graphFullscreen && !isMobile && ( -
-
- Knowledge graph - -
-
- -
-
- )} - - {/* Upcoming assignments strip */} -
-
-

- Upcoming -

- - View Calendar - -
- {allAssignments.length === 0 ? ( -

No upcoming assignments

- ) : ( -
- {allAssignments.slice(0, 4).map(a => { - const cn = a.course_name ?? ''; - const c = getCourseColor(cn, courseColorMap[cn]); - return ( -
- - {formatDueDate(a.due_date)} - - - {a.course_name} - - {a.title} -
- ); - })} -
- )} -
-
- - {/* ── Mobile: Courses & Stats toggle tabs ─────────────────────────── */} - {isMobile && ( -
- - -
- )} - - {/* ── Mobile: Courses panel (collapsible) ─────────────────────────── */} - {isMobile && mobileSidebarTab === 'courses' && ( -
- {loading ? ( -
Loading…
- ) : courseList.length === 0 ? ( -
No courses yet
- ) : ( - courseList.map(course => { - const subject = course.course_name; - const c = getCourseColor(subject, course.color); - const conceptNodes = nodes.filter(n => n.subject === subject && !n.is_subject_root && n.mastery_tier !== 'subject_root'); - const avgMastery = conceptNodes.length > 0 - ? conceptNodes.reduce((s, n) => s + n.mastery_score, 0) / conceptNodes.length - : 0; - const pct = Math.round(avgMastery * 100); - return ( -
- {subject} -
-
-
- {pct}% mastery -
- ); - }) - )} -
- )} - - {/* ── Right: Sidebar (desktop) / Stats section (mobile) ───────────── */} -
- - {/* User header + streak */} -
-

{userName}

- - {/* Streak count */} -
- - {stats?.streak ?? 0} - - day streak -
- - {/* 7-day week strip */} -
- {weekInfo.dates.map(({ label, iso, isToday, isFuture }) => { - const isActive = activeDaysThisWeek.has(iso); - return ( -
- {/* Day label */} - - {label} - - {/* Fire or empty ring */} - {isActive ? ( - 🔥 - ) : ( -
- )} -
- ); - })} -
-
- - {/* Stats */} - {stats && ( -
-

- Knowledge -

- {(['mastered', 'learning', 'struggling', 'unexplored'] as const).map(tier => ( -
-
- - {stats[tier]} {STATS_LABELS[tier]} - -
- ))} -
- )} - - {/* Recommendations */} - {recommendations.length > 0 && ( -
-

- Learn Next -

- {recommendations.map(rec => { - const node = nodes.find(n => n.concept_name === rec.concept_name); - return ( - - {rec.concept_name} - - {node ? getMasteryLabel(node.mastery_score) : '0%'} - - - ); - })} -
- )} - - {/* Actions */} -
- - Quick Quiz - - - Study Room - -
- - {/* Recent activity */} - {nodes.length > 0 && ( -
-

- Recent Activity -

- {nodes - .filter(n => n.last_studied_at) - .sort((a, b) => (b.last_studied_at ?? '').localeCompare(a.last_studied_at ?? '')) - .slice(0, 4) - .map(n => ( -
- - {n.concept_name} — {getMasteryLabel(n.mastery_score)} - - - {formatRelativeTime(n.last_studied_at)} - -
- ))} -
- )} -
-
- - - {/* ── Courses Modal ───────────────────────────────────────────────────── */} - {showCourses && ( -
{ if (e.target === e.currentTarget) { setShowCourses(false); setCourseError(''); setCourseSearchInput(''); setCourseSuggestions([]); setEditingColorFor(null); } }} - > -
- {/* Close */} - - -

- My Courses -

-

- Courses appear as large hub nodes on your knowledge tree. Deleting a course removes all its concept nodes. -

- - {/* Course list */} -
- {courseList.length === 0 ? ( -

No courses added yet.

- ) : ( - courseList.map(c => { - const color = getCourseColor(c.course_name, c.color); - const isDeleting = courseDeleting === c.course_id; - const isEditingColor = editingColorFor === c.course_id; - return ( -
- {/* Main row */} -
-
- {/* Color swatch — click to open picker */} -
- {confirmDeleteCourse === c.course_id ? ( -
- - -
- ) : ( - - )} -
- - {/* Inline color picker (animated via maxHeight) */} -
-
- {/* Preset swatches */} -

- Colours -

-
- {RAINBOW_COLORS.map(hex => ( -
- {/* Color wheel + hex input */} -

- Custom colour -

-
- setColorHexInput(e.target.value)} - style={{ - width: '32px', height: '28px', border: '1px solid rgba(107,114,128,0.25)', - borderRadius: '4px', cursor: 'pointer', padding: '1px', background: 'none', - }} - /> - setColorHexInput(e.target.value)} - onKeyDown={e => { if (e.key === 'Enter') handleColorChange(c.course_id, c.course_name, colorHexInput); }} - placeholder="#2563eb" - style={{ - flex: 1, padding: '4px 8px', border: '1px solid rgba(107,114,128,0.25)', - borderRadius: '4px', fontSize: '12px', fontFamily: 'monospace', - outline: 'none', color: '#111827', - }} - /> - -
-
-
-
- ); - }) - )} -
- - {/* Divider */} -
- - {/* Add new course */} -

- Add a Course -

-
- handleCourseSearchInput(e.target.value)} - onFocus={() => setCourseSearchFocused(true)} - onBlur={() => setTimeout(() => setCourseSearchFocused(false), 150)} - placeholder="Search courses…" - disabled={courseAdding} - style={{ - width: '100%', - padding: '8px 12px', - border: '1px solid rgba(107,114,128,0.25)', - borderRadius: '6px', - fontSize: '13px', - outline: 'none', - fontFamily: 'inherit', - color: '#111827', - opacity: courseAdding ? 0.6 : 1, - }} - /> -
- {courseSearchFocused && courseSuggestions.length > 0 && courseInputRect && typeof document !== 'undefined' && createPortal( -
- {courseSuggestions.map((c, i) => ( - - ))} -
, - document.body - )} - {courseAdding && ( -

Adding…

- )} - {courseError && ( -

{courseError}

- )} -
-
- )} - - ); -} - -export default function Dashboard() { - return ( - - - - ); -} diff --git a/frontend/src/app/error.tsx b/frontend/src/app/error.tsx index 75b49cf6..82bd5c42 100644 --- a/frontend/src/app/error.tsx +++ b/frontend/src/app/error.tsx @@ -1,38 +1,7 @@ -'use client'; +"use client"; + +import { ErrorFallback } from "@/components/ErrorBoundary"; export default function GlobalError({ error, reset }: { error: Error & { digest?: string }; reset: () => void }) { - return ( -
-

- Something went wrong -

-

- {error.message || 'An unexpected error occurred. Please try again.'} -

- -
- ); + return ; } diff --git a/frontend/src/app/flashcards/page.tsx b/frontend/src/app/flashcards/page.tsx deleted file mode 100644 index 8241a260..00000000 --- a/frontend/src/app/flashcards/page.tsx +++ /dev/null @@ -1,443 +0,0 @@ -'use client'; - -import { useState, useEffect } from 'react'; -import { useUser } from '@/context/UserContext'; -import { generateFlashcards, getFlashcards, rateFlashcard, deleteFlashcard, getCourses } from '@/lib/api'; -import Link from 'next/link'; -import AIDisclaimerChip from '@/components/AIDisclaimerChip'; - -interface Flashcard { - id: string; - topic: string; - front: string; - back: string; - times_reviewed: number; - last_rating: number | null; -} - -function useIsMobile(breakpoint = 768) { - const [isMobile, setIsMobile] = useState(false); - useEffect(() => { - const mql = window.matchMedia(`(max-width: ${breakpoint}px)`); - setIsMobile(mql.matches); - const handler = (e: MediaQueryListEvent) => setIsMobile(e.matches); - mql.addEventListener('change', handler); - return () => mql.removeEventListener('change', handler); - }, [breakpoint]); - return isMobile; -} - -export default function FlashcardsPage() { - const { userId: USER_ID, userReady } = useUser(); - const isMobile = useIsMobile(); - const [mobileTab, setMobileTab] = useState<'generate' | 'cards'>('cards'); - - const [cards, setCards] = useState([]); - const [courses, setCourses] = useState([]); - const [topic, setTopic] = useState(''); - const [generating, setGenerating] = useState(false); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(null); - const [filterTopic, setFilterTopic] = useState(''); - - // Study mode - const [studyMode, setStudyMode] = useState(false); - const [studyIndex, setStudyIndex] = useState(0); - const [flipped, setFlipped] = useState(false); - const [studyCards, setStudyCards] = useState([]); - - useEffect(() => { - if (!userReady || !USER_ID) return; - setLoading(true); - Promise.all([ - getFlashcards(USER_ID), - getCourses(USER_ID), - ]).then(([cardData, courseData]) => { - setCards(cardData.flashcards ?? []); - setCourses(courseData.courses.map((c: any) => c.course_name)); - }).catch(err => { - console.error('Failed to load flashcards:', err); - setCards([]); - }).finally(() => setLoading(false)); - }, [USER_ID, userReady]); - - const [lastContextUsed, setLastContextUsed] = useState<{ documents_found: number; weak_concepts_found: number } | null>(null); - - const handleGenerate = async (selectedTopic: string) => { - if (!selectedTopic.trim()) return; - setTopic(selectedTopic); - setGenerating(true); - setError(null); - setLastContextUsed(null); - try { - const res = await generateFlashcards(USER_ID, selectedTopic.trim(), 10); - setCards(prev => [...res.flashcards, ...prev]); - if (res.context_used) setLastContextUsed(res.context_used); - } catch (e: any) { - setError(e?.message || 'Failed to generate flashcards.'); - } finally { - setGenerating(false); - } - }; - - const handleRate = async (cardId: string, rating: number) => { - try { - await rateFlashcard(USER_ID, cardId, rating); - setCards(prev => prev.map(c => - c.id === cardId ? { ...c, last_rating: rating, times_reviewed: c.times_reviewed + 1 } : c - )); - if (studyMode) { - setTimeout(() => { - setFlipped(false); - if (studyIndex < studyCards.length - 1) { - setStudyIndex(i => i + 1); - } else { - setStudyMode(false); - } - }, 300); - } - } catch (e) { console.error(e); } - }; - - const handleDelete = async (cardId: string) => { - try { - await deleteFlashcard(USER_ID, cardId); - setCards(prev => prev.filter(c => c.id !== cardId)); - } catch (e) { console.error(e); } - }; - - const startStudy = (topicFilter?: string) => { - const filtered = topicFilter ? cards.filter(c => c.topic === topicFilter) : cards; - if (filtered.length === 0) return; - setStudyCards(filtered); - setStudyIndex(0); - setFlipped(false); - setStudyMode(true); - }; - - const ratingMeta = (r: number | null) => { - if (r === 1) return { label: 'Forgot', color: '#dc2626' }; - if (r === 2) return { label: 'Hard', color: '#d97706' }; - if (r === 3) return { label: 'Easy', color: '#16a34a' }; - return null; - }; - - const topics = [...new Set(cards.map(c => c.topic))].sort(); - const filteredCards = filterTopic ? cards.filter(c => c.topic === filterTopic) : cards; - const currentCard = studyCards[studyIndex]; - - // ── Study Mode ─────────────────────────────────────────────────────────────── - if (studyMode && currentCard) { - const progress = (studyIndex / studyCards.length) * 100; - return ( -
-
- - {currentCard.topic} - {studyIndex + 1} / {studyCards.length} -
-
-
-
- -
- - -
setFlipped(f => !f)} - style={{ width: '100%', maxWidth: '600px', minHeight: '280px', position: 'relative' }} - > -
- {/* Front */} -
- - Question - -

- {currentCard.front} -

- tap to reveal -
- {/* Back */} -
- - Answer - -

- {currentCard.back} -

-
-
-
- - {flipped && ( -
- {[ - { rating: 1, label: 'Forgot', bg: '#fef2f2', color: '#dc2626', border: '#fca5a5' }, - { rating: 2, label: 'Hard', bg: '#fffbeb', color: '#d97706', border: '#fcd34d' }, - { rating: 3, label: 'Easy', bg: '#f0fdf4', color: '#16a34a', border: '#86efac' }, - ].map(({ rating, label, bg, color, border }) => ( - - ))} -
- )} - - -
-
- ); - } - - // ── Main View ──────────────────────────────────────────────────────────────── - return ( -
- {/* Top bar */} -
- ← - Flashcards -
-
- -
- {isMobile && ( -
- - -
- )} - - {/* Left panel */} -
-
-

Generate flashcards

- -
- - {courses.length > 0 ? ( -
- {courses.map(c => ( - - ))} -
- ) : ( -

- No courses found. Add courses in the Dashboard first. -

- )} -
- - {error &&

{error}

} - - {lastContextUsed && ( -
- ✦ Generated using{' '} - {lastContextUsed.documents_found > 0 - ? `${lastContextUsed.documents_found} library doc${lastContextUsed.documents_found > 1 ? 's' : ''}` - : 'no library docs'} - {lastContextUsed.weak_concepts_found > 0 - ? ` · focused on ${lastContextUsed.weak_concepts_found} weak concept${lastContextUsed.weak_concepts_found > 1 ? 's' : ''}` - : ''} -
- )} -
- - {/* Study by topic */} - {topics.length > 0 && ( -
-

Study by topic

-
- - {topics.map(t => ( - - ))} -
-
- )} -
- - {/* Right panel — card grid */} -
- {topics.length > 1 && ( -
- {['', ...topics].map(t => ( - - ))} -
- )} - - {loading &&

Loading…

} - - {!loading && filteredCards.length === 0 && ( -
-

🃏

-

No flashcards yet

-

Generate some using the panel on the left.

-
- )} - -
- {filteredCards.map(card => { - const rating = ratingMeta(card.last_rating); - return ( -
-
- {card.topic} - {rating && {rating.label}} -
- -
-

Q

-

{card.front}

-
- -
- -
-

A

-

{card.back}

-
- -
- - {card.times_reviewed > 0 ? `Reviewed ${card.times_reviewed}×` : 'Not reviewed'} - - -
-
- ); - })} -
-
-
-
- ); -} \ No newline at end of file diff --git a/frontend/src/app/globals.css b/frontend/src/app/globals.css index 03175313..d89b1c30 100644 --- a/frontend/src/app/globals.css +++ b/frontend/src/app/globals.css @@ -1,911 +1,262 @@ -@import "tailwindcss"; - -/* ── Design Tokens ─────────────────────────────────────────────── */ +/* Sapling — design tokens */ :root { - /* Brand mesh (landing reference palette) */ - --brand-primary: #2e7d52; - --brand-success: #22c55e; - --brand-progress: #e8a33a; - --brand-teal: #2b8c96; - --brand-struggle: #e85d4a; - --brand-text1: #1a1a1a; - --brand-text2: #4b5563; - --bg-mesh: #f0f4f2; - - /* Backgrounds */ - --bg: var(--bg-mesh); - --bg-panel: #f8fbf8; - --bg-sidebar: #dfe8df; - --bg-topbar: #dce6dc; - --bg-input: #f8fbf8; - --bg-subtle: #e9efe9; - --bg-space: var(--bg-mesh); - --bg-glass: rgba(255, 255, 255, 0.35); - - /* Forest green accent */ - --accent: #1a5c2a; - --accent-hover: #144a21; - --accent-dim: rgba(26, 92, 42, 0.08); - --accent-border: rgba(26, 92, 42, 0.3); - --accent-active: rgba(26, 92, 42, 0.7); - --accent-glow: rgba(26, 92, 42, 0.12); - - /* Text */ - --text: #111827; - --text-primary: #111827; - --text-secondary: #374151; - --text-muted: #4b5563; - --text-dim: #6b7280; - --text-placeholder: #9ca3af; - - /* Borders */ - --border: rgba(107, 114, 128, 0.18); - --border-light: rgba(107, 114, 128, 0.10); - --border-mid: rgba(107, 114, 128, 0.25); - --border-glass: rgba(107, 114, 128, 0.15); - - /* Shadows */ - --shadow-sm: 0 1px 3px rgba(15, 23, 42, 0.06), 0 1px 2px rgba(15, 23, 42, 0.04); - --shadow-md: 0 4px 12px rgba(15, 23, 42, 0.08), 0 2px 4px rgba(15, 23, 42, 0.04); - --shadow-lg: 0 12px 32px rgba(15, 23, 42, 0.10), 0 4px 8px rgba(15, 23, 42, 0.06); - - /* Radius */ - --radius-sm: 6px; - --radius-md: 10px; - --radius-lg: 16px; - --radius-full: 9999px; - - /* Motion */ - --ease-out: cubic-bezier(0.16, 1, 0.3, 1); - --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1); - --dur-fast: 120ms; - --dur-base: 200ms; - --dur-slow: 350ms; -} - -/* Library upload modal — reliable spinner (avoid inline - -
setFlipped(f => !f)} style={{ width: '100%', maxWidth: '600px', minHeight: '280px', position: 'relative' }}> -
-
- Question -

{currentCard.front}

- tap to reveal -
-
- Answer -

{currentCard.back}

-
-
-
- - {flipped && ( -
- {[ - { rating: 1, label: 'Forgot', bg: '#fef2f2', color: '#dc2626', border: '#fca5a5' }, - { rating: 2, label: 'Hard', bg: '#fffbeb', color: '#d97706', border: '#fcd34d' }, - { rating: 3, label: 'Easy', bg: '#f0fdf4', color: '#16a34a', border: '#86efac' }, - ].map(({ rating, label, bg, color, border }) => ( - - ))} -
- )} - - -
-
- ); - } - - // ── Main view ───────────────────────────────────────────────────────────────── - return ( -
- {/* Left panel */} -
-
-

Generate flashcards

-
- - {courses.length > 0 ? ( -
- {courses.map(c => ( - - ))} -
- ) : ( -

No courses found. Add courses in the Dashboard first.

- )} -
- {error &&

{error}

} - {lastContextUsed && ( -
- ✦ Generated using{' '} - {lastContextUsed.documents_found > 0 ? `${lastContextUsed.documents_found} library doc${lastContextUsed.documents_found > 1 ? 's' : ''}` : 'no library docs'} - {lastContextUsed.weak_concepts_found > 0 ? ` · focused on ${lastContextUsed.weak_concepts_found} weak concept${lastContextUsed.weak_concepts_found > 1 ? 's' : ''}` : ''} -
- )} -
- - {topics.length > 0 && ( -
-

Study by topic

-
- - {topics.map(t => ( - - ))} -
-
- )} -
- - {/* Right panel — card grid */} -
- {topics.length > 1 && ( -
- {['', ...topics].map(t => ( - - ))} -
- )} - - {loading &&

Loading…

} - - {!loading && filteredCards.length === 0 && ( -
-

🃏

-

No flashcards yet

-

Generate some using the panel on the left.

-
- )} - -
- {filteredCards.map(card => { - const rating = ratingMeta(card.last_rating); - return ( -
-
- {card.topic} - {rating && {rating.label}} -
-
-

Q

-

{card.front}

-
-
-
-

A

-

{card.back}

-
-
- {card.times_reviewed > 0 ? `Reviewed ${card.times_reviewed}×` : 'Not reviewed'} - -
-
- ); - })} -
-
-
- ); -} diff --git a/frontend/src/app/study/StudyClient.tsx b/frontend/src/app/study/StudyClient.tsx deleted file mode 100644 index e7dbb2bf..00000000 --- a/frontend/src/app/study/StudyClient.tsx +++ /dev/null @@ -1,316 +0,0 @@ -'use client'; - -import { useState, useEffect } from 'react'; -import { useUser } from '@/context/UserContext'; -import CustomSelect, { SelectOption } from '@/components/CustomSelect'; -import FlashcardsPanel from './FlashcardsPanel'; - -const API_URL = process.env.NEXT_PUBLIC_API_URL ?? ''; - -async function fetchJSON(path: string, options?: RequestInit): Promise { - const res = await fetch(`${API_URL}${path}`, { - headers: { 'Content-Type': 'application/json', ...options?.headers }, - ...options, - }); - if (!res.ok) { - const err = await res.text(); - throw new Error(err || `HTTP ${res.status}`); - } - return res.json(); -} - -interface Course { id: string; course_name: string; color: string | null; } -interface Exam { id: string; title: string; due_date: string; assignment_type: string; } -interface StudyTopic { name: string; importance: string; concepts: string[]; } -interface StudyGuide { exam: string; due_date: string; overview: string; topics: StudyTopic[]; } -interface CachedGuide { id: string; course_id: string; exam_id: string; course_name: string; exam_title: string; overview: string; generated_at: string; } - -type Mode = 'flashcards' | 'study-guide'; -type GuideState = 'selection' | 'loading' | 'guide'; - -function useIsMobile(breakpoint = 768) { - const [isMobile, setIsMobile] = useState(false); - useEffect(() => { - const mql = window.matchMedia(`(max-width: ${breakpoint}px)`); - setIsMobile(mql.matches); - const handler = (e: MediaQueryListEvent) => setIsMobile(e.matches); - mql.addEventListener('change', handler); - return () => mql.removeEventListener('change', handler); - }, [breakpoint]); - return isMobile; -} - -export default function StudyClient() { - const { userId, userReady } = useUser(); - const isMobile = useIsMobile(); - - const [mode, setMode] = useState('study-guide'); - const [flashcardStudyMode, setFlashcardStudyMode] = useState(false); - - const [guideState, setGuideState] = useState('selection'); - const [courses, setCourses] = useState([]); - const [exams, setExams] = useState([]); - const [cachedGuides, setCachedGuides] = useState([]); - const [selectedCourseId, setSelectedCourseId] = useState(''); - const [selectedExamId, setSelectedExamId] = useState(''); - const [guide, setGuide] = useState(null); - const [generatedAt, setGeneratedAt] = useState(''); - const [error, setError] = useState(null); - const [regenerating, setRegenerating] = useState(false); - - const loadCached = () => { - if (!userId) return; - fetchJSON<{ guides: CachedGuide[] }>(`/api/study-guide/${userId}/cached`) - .then(data => setCachedGuides(data.guides ?? [])) - .catch(console.error); - }; - - useEffect(() => { - if (!userReady || !userId) return; - fetchJSON<{ courses: Course[] }>(`/api/study-guide/${userId}/courses`) - .then(data => setCourses(data.courses ?? [])) - .catch(console.error); - loadCached(); - }, [userId, userReady]); // eslint-disable-line react-hooks/exhaustive-deps - - useEffect(() => { - if (!selectedCourseId || !userId) return; - setSelectedExamId(''); - setExams([]); - fetchJSON<{ exams: Exam[] }>(`/api/study-guide/${userId}/exams?course_id=${selectedCourseId}`) - .then(data => setExams(data.exams ?? [])) - .catch(console.error); - }, [selectedCourseId, userId]); - - const handleGenerate = async () => { - if (!selectedCourseId || !selectedExamId) return; - setGuideState('loading'); - setError(null); - try { - const data = await fetchJSON<{ guide: StudyGuide; generated_at: string }>( - `/api/study-guide/${userId}/guide?course_id=${selectedCourseId}&exam_id=${selectedExamId}` - ); - setGuide(data.guide); - setGeneratedAt(data.generated_at); - setGuideState('guide'); - loadCached(); - } catch (e: unknown) { - setError(e instanceof Error ? e.message : 'Failed to generate study guide.'); - setGuideState('selection'); - } - }; - - const handleOpenCached = (cached: CachedGuide) => { - setSelectedCourseId(cached.course_id); - setSelectedExamId(cached.exam_id); - setGuideState('loading'); - setError(null); - fetchJSON<{ guide: StudyGuide; generated_at: string }>( - `/api/study-guide/${userId}/guide?course_id=${cached.course_id}&exam_id=${cached.exam_id}` - ).then(data => { - setGuide(data.guide); - setGeneratedAt(data.generated_at); - setGuideState('guide'); - }).catch(e => { - setError(e instanceof Error ? e.message : 'Failed to load guide.'); - setGuideState('selection'); - }); - }; - - const handleRegenerate = async () => { - if (!selectedCourseId || !selectedExamId) return; - setRegenerating(true); - setError(null); - try { - const data = await fetchJSON<{ guide: StudyGuide; generated_at: string }>( - '/api/study-guide/regenerate', - { method: 'POST', body: JSON.stringify({ user_id: userId, course_id: selectedCourseId, exam_id: selectedExamId }) } - ); - setGuide(data.guide); - setGeneratedAt(data.generated_at); - loadCached(); - } catch (e: unknown) { - setError(e instanceof Error ? e.message : 'Failed to regenerate study guide.'); - } finally { - setRegenerating(false); - } - }; - - const courseOptions: SelectOption[] = courses.map(c => ({ value: c.id, label: c.course_name })); - const examOptions: SelectOption[] = exams.map(e => ({ value: e.id, label: e.title })); - const selectedExam = exams.find(e => e.id === selectedExamId); - const font = "var(--font-dm-sans), 'DM Sans', sans-serif"; - - const ModeToggle = () => ( -
-
- {(['study-guide', 'flashcards'] as Mode[]).map(m => ( - - ))} -
-
- ); - - // ── Guide display (full takeover) ───────────────────────────────────────────── - if (mode === 'study-guide' && guideState === 'guide' && guide) { - const fmtDate = guide.due_date ? new Date(guide.due_date + 'T00:00:00').toLocaleDateString(undefined, { year: 'numeric', month: 'long', day: 'numeric' }) : ''; - const fmtGen = generatedAt ? new Date(generatedAt).toLocaleString(undefined, { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' }) : ''; - return ( -
-
- - Study Guide - {guide.exam} -
- -
-
-
-
- {error &&
{error}
} -
-

Exam

-

{guide.exam}

- {fmtDate &&

Due {fmtDate}

} -

{guide.overview}

-
- {guide.topics.map((topic, i) => ( -
-

{topic.name}

-

{topic.importance}

-
    - {topic.concepts.map((c, j) =>
  • {c}
  • )} -
-
- ))} -

Generated at {fmtGen}

-
-
-
- ); - } - - // ── Loading (full takeover) ─────────────────────────────────────────────────── - if (mode === 'study-guide' && guideState === 'loading') { - return ( -
- -
-
-
- -

Generating your study guide...

-
-
-
- ); - } - - // ── Main layout — FlashcardsPanel always mounted for caching ────────────────── - return ( -
- {!flashcardStudyMode && } - - {/* FlashcardsPanel — always mounted, hidden when not active */} -
- -
- - {/* Study guide selection */} - {mode === 'study-guide' && ( -
- {/* Left — generator */} -
-

Generate study guide

- {error &&
{error}
} -
- - -
-
- - -
- {selectedExam?.due_date && ( -

- Due {new Date(selectedExam.due_date + 'T00:00:00').toLocaleDateString(undefined, { year: 'numeric', month: 'long', day: 'numeric' })} -

- )} - -
- - {/* Right — recent guides (no background, matches flashcard right panel) */} -
-

Recent guides

- {cachedGuides.length === 0 ? ( -
-

No guides yet

-

Generate your first study guide on the left.

-
- ) : ( -
- {cachedGuides.map(g => { - const ts = new Date(g.generated_at).toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' }); - return ( - - ); - })} -
- )} -
-
- )} -
- ); -} diff --git a/frontend/src/app/study/page.tsx b/frontend/src/app/study/page.tsx deleted file mode 100644 index fddc9b42..00000000 --- a/frontend/src/app/study/page.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { Suspense } from 'react'; -import StudyClient from './StudyClient'; - -export default function StudyPage() { - return ( - Loading...
}> - - - ); -} diff --git a/frontend/src/app/terms/page.tsx b/frontend/src/app/terms/page.tsx deleted file mode 100644 index 93a1ba26..00000000 --- a/frontend/src/app/terms/page.tsx +++ /dev/null @@ -1,116 +0,0 @@ -import Link from "next/link"; - -const sections = [ - { - title: "1. Eligibility", - body: "Sapling is intended for use by students and individuals for personal educational purposes. By using the Service, you represent that you are at least 13 years of age. If you are under 18, you should have parental or guardian consent.", - }, - { - title: "2. Your Account", - body: "You are responsible for maintaining the confidentiality of your account credentials. You agree not to share your account with others or use another person's account. You are responsible for all activity that occurs under your account.", - }, - { - title: "3. Acceptable Use", - body: "You agree to use Sapling only for lawful, educational purposes. You may not:", - list: [ - "Upload content you do not have the right to share (e.g., copyrighted course materials you are not permitted to distribute)", - "Attempt to reverse-engineer, scrape, or abuse the Service's APIs", - "Use the Service to harass, impersonate, or harm other users", - "Attempt to circumvent any security or authentication measures", - ], - }, - { - title: "4. User Content", - body: "You retain ownership of any content you upload, including documents, syllabi, and notes. By uploading content to Sapling, you grant us a limited license to process and analyze that content solely for the purpose of providing the Service to you. We do not use your uploaded materials to train AI models.", - }, - { - title: "5. AI-Generated Content", - body: "Sapling uses Google Gemini to generate tutoring responses, quizzes, flashcards, and study guides. AI-generated content may occasionally be inaccurate or incomplete. You should not rely on it as a substitute for official course materials, instructors, or academic advisors. We make no guarantees about the accuracy of AI outputs.", - }, - { - title: "6. Study Rooms and Social Features", - body: "Study rooms are shared spaces. You are responsible for the messages you send and the conduct you engage in within rooms. We reserve the right to remove users who violate these terms.", - }, - { - title: "7. Intellectual Property", - body: "Sapling's software, branding, and design are the intellectual property of the Sapling team. You may not copy, reproduce, or distribute any part of the Service without explicit permission.", - }, - { - title: "8. Termination", - body: "We reserve the right to suspend or terminate your access to Sapling at any time, for any reason, including violation of these Terms.", - }, - { - title: "9. Disclaimer of Warranties", - body: 'The Service is provided "as is" without warranties of any kind. We do not guarantee uninterrupted access, error-free operation, or that the Service will meet your specific academic needs.', - }, - { - title: "10. Limitation of Liability", - body: "To the fullest extent permitted by law, the Sapling team shall not be liable for any indirect, incidental, or consequential damages arising from your use of the Service.", - }, - { - title: "11. Changes to These Terms", - body: "We may update these Terms from time to time. Continued use of the Service after changes are posted constitutes acceptance of the revised Terms.", - }, - { - title: "12. Contact", - body: "For questions about these Terms, please email us at ", - link: { label: "careers@saplinglearn.com", href: "mailto:careers@saplinglearn.com" }, - }, -]; - -export default function TermsPage() { - return ( -
-
-
- - ← Back to Sapling - -
- -

Terms of Service

-

Last updated: March 27, 2026

- -

- By accessing or using Sapling ("the Service"), you agree to be bound by these Terms of Service. If you do not agree, please do not use the Service. -

- -
- {sections.map((section, i) => ( -
-

{section.title}

-

- {section.body} - {section.link && ( - {section.link.label} - )} -

- {section.list && ( -
    - {section.list.map((item, i) => ( -
  • - - {item} -
  • - ))} -
- )} -
- ))} -
- -
- © 2026 Andres Lopez, Jack He, Luke Cooper, and Jose Gael Cruz-Lopez. All Rights Reserved. -
-
- -
-
- About - Terms of Service - Privacy Policy -
-
-
- ); -} diff --git a/frontend/src/app/tree/page.tsx b/frontend/src/app/tree/page.tsx deleted file mode 100644 index 135e8f64..00000000 --- a/frontend/src/app/tree/page.tsx +++ /dev/null @@ -1,382 +0,0 @@ -'use client'; - -import { useEffect, useState, useRef, useMemo, Suspense } from 'react'; -import { useRouter, useSearchParams } from 'next/navigation'; -import KnowledgeGraph from '@/components/KnowledgeGraph'; -import { GraphNode, GraphEdge } from '@/lib/types'; -import { getGraph, getCourses } from '@/lib/api'; -import { getMasteryColor, getMasteryLabel, formatRelativeTime, getCourseColor } from '@/lib/graphUtils'; -import { useUser } from '@/context/UserContext'; - -type Filter = 'all' | 'mastered' | 'learning' | 'struggling' | 'unexplored'; - -const GLASS = { - background: '#ffffff', - border: '1px solid rgba(107, 114, 128, 0.15)', -} as const; - -function useIsMobile(breakpoint = 768) { - const [isMobile, setIsMobile] = useState(false); - useEffect(() => { - const mql = window.matchMedia(`(max-width: ${breakpoint}px)`); - setIsMobile(mql.matches); - const handler = (e: MediaQueryListEvent) => setIsMobile(e.matches); - mql.addEventListener('change', handler); - return () => mql.removeEventListener('change', handler); - }, [breakpoint]); - return isMobile; -} - -function TreePageInner() { - const router = useRouter(); - const searchParams = useSearchParams(); - const { userId, userReady } = useUser(); - const [allNodes, setAllNodes] = useState([]); - const [allEdges, setAllEdges] = useState([]); - const [filter, setFilter] = useState('all'); - const [search, setSearch] = useState(''); - const [selectedNode, setSelectedNode] = useState(null); - const [dimensions, setDimensions] = useState({ width: 1200, height: 700 }); - const [courseColorMap, setCourseColorMap] = useState>({}); - const containerRef = useRef(null); - - const suggestConcept = searchParams.get('suggest') ?? ''; - - useEffect(() => { - if (!userReady) return; - getGraph(userId).then(data => { - setAllNodes(data.nodes); - setAllEdges(data.edges); - }).catch(console.error); - getCourses(userId).then(data => { - const colorMap: Record = {}; - (data.courses ?? []).forEach(c => { if (c.color) colorMap[c.course_name] = c.color; }); - setCourseColorMap(colorMap); - }).catch(console.error); - }, [userId, userReady]); - - useEffect(() => { - setDimensions({ width: window.innerWidth, height: window.innerHeight - 48 }); - const handleResize = () => setDimensions({ width: window.innerWidth, height: window.innerHeight - 48 }); - window.addEventListener('resize', handleResize); - return () => window.removeEventListener('resize', handleResize); - }, []); - - const suggestNode = useMemo( - () => (suggestConcept ? allNodes.find(n => n.concept_name === suggestConcept) ?? null : null), - [allNodes, suggestConcept] - ); - - const filteredNodes = allNodes.filter(n => { - const matchesFilter = filter === 'all' || n.mastery_tier === filter; - const matchesSearch = !search || n.concept_name.toLowerCase().includes(search.toLowerCase()); - return matchesFilter && matchesSearch; - }); - - const filteredNodeIds = new Set(filteredNodes.map(n => n.id)); - const nodeSubjectMap = new Map(allNodes.map(n => [n.id, n.subject])); - const filteredEdges = allEdges.filter(e => { - const srcId = e.source as string; - const tgtId = e.target as string; - if (!filteredNodeIds.has(srcId) || !filteredNodeIds.has(tgtId)) return false; - if (srcId.startsWith('subject_root__') || tgtId.startsWith('subject_root__')) return true; - const srcSubj = nodeSubjectMap.get(srcId); - const tgtSubj = nodeSubjectMap.get(tgtId); - return !srcSubj || !tgtSubj || srcSubj === tgtSubj; - }); - - const isMobile = useIsMobile(); - - const FILTERS: { value: Filter; label: string }[] = [ - { value: 'all', label: 'All' }, - { value: 'mastered', label: 'Mastered' }, - { value: 'learning', label: 'Learning' }, - { value: 'struggling', label: 'Struggling' }, - { value: 'unexplored', label: 'Unexplored' }, - ]; - - return ( -
- - - {/* Floating search + filter bar */} -
- setSearch(e.target.value)} - placeholder="Search concepts…" - style={{ - padding: '5px 10px', - border: '1px solid rgba(148,163,184,0.15)', - borderRadius: '5px', - fontSize: '13px', - outline: 'none', - width: isMobile ? '100%' : '180px', - background: '#ffffff', - color: '#111827', - }} - /> -
- {FILTERS.map(f => { - const active = filter === f.value; - return ( - - ); - })} -
- {filteredNodes.length} nodes -
- - {/* AI "learn next" suggestion popup */} - {suggestConcept && suggestNode && ( -
-
- -
-

- AI Recommendation -

-

- {suggestConcept} -

-

- This concept will have the highest impact on your mastery. -

-
-
-
- - -
-
- )} - - {/* Node detail panel */} - {selectedNode && ( -
-
-

- {selectedNode.concept_name} -

- -
- -
-

Subject

-
- -

{selectedNode.subject}

-
-
- -
-
-

Mastery

- - {getMasteryLabel(selectedNode.mastery_score)} - -
-
-
-
-
- -
-
- Last studied - {formatRelativeTime(selectedNode.last_studied_at)} -
-
- Times studied - {selectedNode.times_studied} -
-
- -
-

Connected to

-
- {allEdges - .filter(e => e.source === selectedNode.id || e.target === selectedNode.id) - .map(e => { - const otherId = e.source === selectedNode.id ? e.target : e.source; - const other = allNodes.find(n => n.id === otherId); - return other ? ( - - ) : null; - }) - .filter(Boolean)} -
-
- -
- - -
-
- )} -
- ); -} - -export default function TreePage() { - return ( - - - - ); -} diff --git a/frontend/src/components/AIDisclaimerChip.tsx b/frontend/src/components/AIDisclaimerChip.tsx index 9ce8ece6..f9704ce3 100644 --- a/frontend/src/components/AIDisclaimerChip.tsx +++ b/frontend/src/components/AIDisclaimerChip.tsx @@ -1,87 +1,22 @@ -'use client'; +"use client"; -import { useState, useEffect } from 'react'; -import DisclaimerModal from './DisclaimerModal'; - -const STORAGE_KEY = 'sapling_disclaimer_ack'; - -export default function AIDisclaimerChip() { - const [tooltipVisible, setTooltipVisible] = useState(false); - const [modalOpen, setModalOpen] = useState(false); - - // Show on first visit automatically - useEffect(() => { - if (!localStorage.getItem(STORAGE_KEY)) setModalOpen(true); - }, []); - - const openModal = () => setModalOpen(true); - const closeModal = () => { - localStorage.setItem(STORAGE_KEY, '1'); - setModalOpen(false); - }; +import React from "react"; +export function AIDisclaimerChip({ compact = false }: { compact?: boolean }) { return ( - <> -
setTooltipVisible(true)} - onMouseLeave={() => setTooltipVisible(false)} - > - - - {tooltipVisible && ( -
- - AI powered learning - -

- Sapling uses Google Gemini to tutor, quiz, and track your progress. - Responses may not always be accurate. Verify with your course materials. -

-
-

- Do not share passwords or sensitive personal data. Use Sapling as a study - aid, not a substitute for your own work. Click to review full guidelines. -

-
-
- )} -
- - {modalOpen && } - + + + AI + ); } diff --git a/frontend/src/components/AchievementCard.tsx b/frontend/src/components/AchievementCard.tsx deleted file mode 100644 index d78d8d13..00000000 --- a/frontend/src/components/AchievementCard.tsx +++ /dev/null @@ -1,137 +0,0 @@ -'use client'; - -import type { Achievement, RarityTier } from '@/lib/types'; - -interface Props { - achievement: Achievement; - earned: boolean; - earnedAt?: string; - progress?: number; - isSecret?: boolean; - compact?: boolean; - onPress?: () => void; -} - -const RARITY_BORDER: Record = { - common: 'var(--rarity-common)', - uncommon: 'var(--rarity-uncommon)', - rare: 'var(--rarity-rare)', - epic: 'var(--rarity-epic)', - legendary: 'var(--rarity-legendary)', -}; - -const RARITY_BG: Record = { - common: 'var(--rarity-common-bg)', - uncommon: 'var(--rarity-uncommon-bg)', - rare: 'var(--rarity-rare-bg)', - epic: 'var(--rarity-epic-bg)', - legendary: 'var(--rarity-legendary-bg)', -}; - -export default function AchievementCard({ achievement, earned, earnedAt, progress, isSecret, compact, onPress }: Props) { - const isLocked = !earned; - const showSecret = isSecret && isLocked; - - return ( -
- {/* Icon */} -
- {showSecret ? ( - - - ? - - ) : achievement.icon ? ( - - ) : ( - - - - - )} -
- - {/* Name */} -
- {showSecret ? 'Secret Achievement' : achievement.name} -
- - {/* Description (not in compact mode) */} - {!compact && ( -
- {showSecret ? 'Keep exploring to discover this achievement' : achievement.description} -
- )} - - {/* Rarity label */} -
- {achievement.rarity} -
- - {/* Progress bar (locked, non-compact only) */} - {isLocked && !compact && progress !== undefined && progress > 0 && ( -
-
-
- )} - - {/* Earned date */} - {earned && earnedAt && !compact && ( -
- Earned {new Date(earnedAt).toLocaleDateString()} -
- )} -
- ); -} diff --git a/frontend/src/components/AchievementShowcase.tsx b/frontend/src/components/AchievementShowcase.tsx deleted file mode 100644 index 5115b449..00000000 --- a/frontend/src/components/AchievementShowcase.tsx +++ /dev/null @@ -1,78 +0,0 @@ -'use client'; - -import type { UserAchievement } from '@/lib/types'; -import AchievementCard from '@/components/AchievementCard'; - -interface Props { - achievements: UserAchievement[]; - isOwnProfile: boolean; - onEditShowcase?: () => void; -} - -export default function AchievementShowcase({ achievements, isOwnProfile, onEditShowcase }: Props) { - const slots = 5; - const items = achievements.slice(0, slots); - - return ( -
-
- - Featured Achievements - - {isOwnProfile && onEditShowcase && ( - - )} -
- -
- {items.map(ua => ( - - ))} - {/* Empty placeholder slots */} - {Array.from({ length: slots - items.length }).map((_, i) => ( -
- ))} -
-
- ); -} diff --git a/frontend/src/components/AchievementUnlockToast.tsx b/frontend/src/components/AchievementUnlockToast.tsx deleted file mode 100644 index 6b2e8512..00000000 --- a/frontend/src/components/AchievementUnlockToast.tsx +++ /dev/null @@ -1,81 +0,0 @@ -'use client'; - -import type { RarityTier } from '@/lib/types'; - -interface Props { - achievement: { - name: string; - icon: string | null; - rarity: RarityTier; - }; -} - -const RARITY_VAR: Record = { - common: 'var(--rarity-common)', - uncommon: 'var(--rarity-uncommon)', - rare: 'var(--rarity-rare)', - epic: 'var(--rarity-epic)', - legendary: 'var(--rarity-legendary)', -}; - -export default function AchievementUnlockToast({ achievement }: Props) { - const borderColor = RARITY_VAR[achievement.rarity] || RARITY_VAR.common; - - return ( -
-
- {achievement.icon ? ( - - ) : ( - - - - - )} -
-
-
- Achievement unlocked -
-
- {achievement.name} -
-
-
- {achievement.rarity} -
-
- ); -} diff --git a/frontend/src/components/AssignmentTable.tsx b/frontend/src/components/AssignmentTable.tsx deleted file mode 100644 index c15d46cb..00000000 --- a/frontend/src/components/AssignmentTable.tsx +++ /dev/null @@ -1,319 +0,0 @@ -'use client'; - -import { useMemo, useState } from 'react'; -import { Assignment } from '@/lib/types'; -import CustomSelect from '@/components/CustomSelect'; - -interface Props { - assignments: Assignment[]; - onChange: (assignments: Assignment[]) => void; - selectedIds?: string[]; - onToggleSelect?: (id: string) => void; -} - -const TYPES = ['homework', 'exam', 'reading', 'project', 'quiz', 'other']; -type SortKey = 'custom' | 'due_date' | 'course_name' | 'title' | 'assignment_type'; - -const SORT_OPTIONS: { value: SortKey; label: string }[] = [ - { value: 'custom', label: 'Manual order' }, - { value: 'due_date', label: 'Due date' }, - { value: 'course_name', label: 'Course' }, - { value: 'title', label: 'Title' }, - { value: 'assignment_type', label: 'Type' }, -]; - -const isDueSoon = (dueDate?: string | null) => { - if (!dueDate) return false; - const due = new Date(`${dueDate}T23:59:59`); - if (Number.isNaN(due.getTime())) return false; - const now = new Date(); - const diff = due.getTime() - now.getTime(); - return diff >= 0 && diff <= 86400000; -}; - -export default function AssignmentTable({ assignments, onChange, selectedIds, onToggleSelect }: Props) { - const [sortKey, setSortKey] = useState('custom'); - const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('asc'); - const [draggingIndex, setDraggingIndex] = useState(null); - const canReorder = sortKey === 'custom'; - - const update = (index: number, field: keyof Assignment, value: string) => { - const updated = assignments.map((a, i) => (i === index ? { ...a, [field]: value } : a)); - onChange(updated); - }; - - const remove = (index: number) => { - onChange(assignments.filter((_, i) => i !== index)); - }; - - const handleDragStart = (position: number) => { - if (!canReorder) return; - setDraggingIndex(position); - }; - - const handleDrop = (position: number) => { - if (!canReorder || draggingIndex === null) { - setDraggingIndex(null); - return; - } - const from = draggingIndex; - const to = position; - if (from === to) { - setDraggingIndex(null); - return; - } - const reordered = [...assignments]; - const [item] = reordered.splice(from, 1); - reordered.splice(to, 0, item); - onChange(reordered); - setDraggingIndex(null); - }; - - const add = () => { - const newA: Assignment = { - id: `temp_${Date.now()}`, - title: '', - course_name: '', - course_code: '', - course_id: '', - due_date: '', - assignment_type: 'homework', - notes: null, - google_event_id: null, - }; - onChange([...assignments, newA]); - }; - - const inputStyle = { - width: '100%', - padding: '4px 6px', - border: '1px solid transparent', - borderRadius: '4px', - fontSize: '13px', - color: 'var(--text)' as string, - background: 'transparent', - outline: 'none', - fontFamily: 'inherit', - }; - - const headerStyle = { - fontSize: '11px', - fontWeight: 500 as const, - color: 'var(--text-dim)' as string, - textTransform: 'uppercase' as const, - letterSpacing: '0.05em', - padding: '8px 10px', - textAlign: 'left' as const, - borderBottom: '1px solid var(--border-light)' as string, - }; - - const rows = useMemo(() => { - const base = assignments.map((assignment, index) => ({ assignment, index })); - if (sortKey === 'custom') return base; - - const compare = (a: Assignment, b: Assignment) => { - const normalize = (value: string | null | undefined) => (value ?? '').toString().toLowerCase(); - if (sortKey === 'due_date') { - const valA = a.due_date ? new Date(`${a.due_date}T00:00:00`).getTime() : Number.MAX_SAFE_INTEGER; - const valB = b.due_date ? new Date(`${b.due_date}T00:00:00`).getTime() : Number.MAX_SAFE_INTEGER; - return valA - valB; - } - if (sortKey === 'course_name') { - return normalize(a.course_name).localeCompare(normalize(b.course_name)); - } - if (sortKey === 'title') { - return normalize(a.title).localeCompare(normalize(b.title)); - } - if (sortKey === 'assignment_type') { - return normalize(a.assignment_type).localeCompare(normalize(b.assignment_type)); - } - return 0; - }; - - const sorted = [...base].sort((a, b) => { - const value = compare(a.assignment, b.assignment); - if (value === 0) return 0; - return sortDirection === 'asc' ? value : -value; - }); - return sorted; - }, [assignments, sortKey, sortDirection]); - - return ( -
-
-
- - setSortKey(val as SortKey)} - options={SORT_OPTIONS} - style={{ minWidth: '160px' }} - /> - {sortKey !== 'custom' && ( - - )} -
-
- -
- - - - {onToggleSelect && } - - - - - - - - - - {rows.map(({ assignment: a, index }, rowPosition) => { - const dueSoon = isDueSoon(a.due_date); - return ( - handleDragStart(rowPosition)} - onDragOver={e => { - if (!canReorder) return; - e.preventDefault(); - }} - onDrop={() => handleDrop(rowPosition)} - onDragEnd={() => setDraggingIndex(null)} - style={{ - borderBottom: rowPosition < rows.length - 1 ? '1px solid var(--border-light)' : 'none', - background: selectedIds?.includes(a.id) - ? 'rgba(22,163,74,0.08)' - : draggingIndex === rowPosition - ? 'rgba(217,119,6,0.08)' - : 'var(--bg-panel)', - cursor: canReorder ? 'grab' : 'default', - }} - > - {onToggleSelect && ( - - )} - - - - - - - - ); - })} - -
DateCourseTitleTypeNotes
- onToggleSelect(a.id)} - /> - -
- {dueSoon && ( - - ! - - )} - update(index, 'due_date', e.target.value)} - style={{ ...inputStyle, width: '110px' }} - /> -
-
- update(index, 'course_name', e.target.value)} - placeholder="Course" - style={inputStyle} - onFocus={e => (e.target.style.borderColor = 'var(--border-mid)')} - onBlur={e => (e.target.style.borderColor = 'transparent')} - /> - - update(index, 'title', e.target.value)} - placeholder="Title" - style={inputStyle} - onFocus={e => (e.target.style.borderColor = 'var(--border-mid)')} - onBlur={e => (e.target.style.borderColor = 'transparent')} - /> - - update(index, 'assignment_type', val)} - options={TYPES.map(t => ({ value: t, label: t }))} - compact - style={{ width: '100%' }} - /> - - update(index, 'notes' as any, e.target.value)} - placeholder="Notes" - style={inputStyle} - onFocus={e => (e.target.style.borderColor = 'var(--border-mid)')} - onBlur={e => (e.target.style.borderColor = 'transparent')} - /> - - -
-
- - -
- ); -} diff --git a/frontend/src/components/Avatar.tsx b/frontend/src/components/Avatar.tsx index 9a29a1ab..e6e2d75c 100644 --- a/frontend/src/components/Avatar.tsx +++ b/frontend/src/components/Avatar.tsx @@ -1,45 +1,69 @@ -import { getInitials, getAvatarColor } from '@/lib/avatarUtils'; +"use client"; +import React from "react"; -interface Props { - userId: string; +const palette = ["#4e873c", "#3e6f8a", "#a8456b", "#b4862c", "#7b4b99", "#b4562c"]; + +export function Avatar({ + name, + size = 28, + color, + img, + frame, +}: { name: string; size?: number; - avatarUrl?: string; - className?: string; -} - -export default function Avatar({ userId, name, size = 32, avatarUrl, className }: Props) { - if (avatarUrl) { - return ( - {name} s[0]) + .join("") + .slice(0, 2) + .toUpperCase(); + const bg = color || palette[name.charCodeAt(0) % palette.length]; + return ( +
+
- ); - } - return ( -
- {getInitials(name)} + > + {img ? ( + + ) : ( + initials + )} +
+ {frame && ( +
+ )}
); } diff --git a/frontend/src/components/AvatarFrame.tsx b/frontend/src/components/AvatarFrame.tsx index b97347c4..8e4392ba 100644 --- a/frontend/src/components/AvatarFrame.tsx +++ b/frontend/src/components/AvatarFrame.tsx @@ -1,45 +1,40 @@ -'use client'; +"use client"; -import Avatar from '@/components/Avatar'; +import React from "react"; +import type { Cosmetic } from "@/lib/types"; +import { Avatar } from "@/components/Avatar"; -interface Props { - frameUrl?: string; - frameSlug?: string; - userId: string; +interface AvatarFrameProps { name: string; size?: number; - avatarUrl?: string; - className?: string; + img?: string; + color?: string; + frame?: Cosmetic | null; } -export default function AvatarFrame({ frameUrl, frameSlug, userId, name, size = 32, avatarUrl, className }: Props) { - if (!frameUrl) { - return ; - } - +export function AvatarFrame({ name, size = 48, img, color, frame }: AvatarFrameProps) { + const overlay = size * 0.25; return ( -
- - +
+
+ +
+ {frame?.asset_url && ( + + )}
); } diff --git a/frontend/src/components/ChatPanel.tsx b/frontend/src/components/ChatPanel.tsx index f25d9e33..5d25dcdd 100644 --- a/frontend/src/components/ChatPanel.tsx +++ b/frontend/src/components/ChatPanel.tsx @@ -1,189 +1,199 @@ -'use client'; +"use client"; -import { useState, useRef, useEffect } from 'react'; -import ReactMarkdown from 'react-markdown'; -import remarkMath from 'remark-math'; -import rehypeKatex from 'rehype-katex'; -import 'katex/dist/katex.min.css'; -import { ChatMessage, TeachingMode } from '@/lib/types'; +import React, { useEffect, useRef } from "react"; +import { Icon } from "./Icon"; +import { MarkdownChat } from "./MarkdownChat"; +import { AIDisclaimerChip } from "./AIDisclaimerChip"; -interface Props { - messages: ChatMessage[]; - onSend: (message: string) => void; - onAction: (action: 'hint' | 'confused' | 'skip') => void; - onEndSession: () => void; - loading: boolean; - mode: TeachingMode; - prefillInput?: string; +export type ChatRole = "user" | "assistant"; +export interface ChatMsg { + id: string; + role: ChatRole; + content: string; + loading?: boolean; } -const MODE_DESCRIPTIONS: Record = { - socratic: 'Asking questions to guide your thinking', - expository: 'Explaining, then checking understanding', - teachback: "You teach me — I'll play confused", -}; - -export default function ChatPanel({ messages, onSend, onAction, onEndSession, loading, mode, prefillInput }: Props) { - const [input, setInput] = useState(''); - const messagesContainerRef = useRef(null); +interface ChatPanelProps { + messages: ChatMsg[]; + input: string; + onInputChange: (v: string) => void; + onSend: () => void; + onAction?: (action: "hint" | "confused" | "skip") => void; + disabled?: boolean; + placeholder?: string; + header?: React.ReactNode; +} - useEffect(() => { - if (prefillInput) setInput(prefillInput); - }, [prefillInput]); +export function ChatPanel({ + messages, + input, + onInputChange, + onSend, + onAction, + disabled, + placeholder = "Ask or respond…", + header, +}: ChatPanelProps) { + const scrollRef = useRef(null); useEffect(() => { - const container = messagesContainerRef.current; - if (container) { - container.scrollTop = container.scrollHeight; - } - }, [messages, loading]); - - const send = () => { - const trimmed = input.trim(); - if (!trimmed || loading) return; - onSend(trimmed); - setInput(''); - }; - - const handleKey = (e: React.KeyboardEvent) => { - if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); send(); } - }; + const el = scrollRef.current; + if (!el) return; + el.scrollTop = el.scrollHeight; + }, [messages]); return ( -
- {/* Mode description */} -
- {MODE_DESCRIPTIONS[mode]} +
+ {header &&
{header}
} +
+ {messages.map(m => )}
- {/* Messages */} -
- {messages.map(msg => ( -
-
- {msg.role === 'user' ? msg.content : ( -

{children}

, - ul: ({ children }) =>
    {children}
, - ol: ({ children }) =>
    {children}
, - li: ({ children }) =>
  • {children}
  • , - code: ({ children }) => ( - - {children} - - ), - pre: ({ children }) => ( -
    -                        {children}
    -                      
    - ), - strong: ({ children }) => {children}, - }} - > - {msg.content} -
    - )} -
    -
    - ))} - - {loading && ( -
    -
    - ··· -
    +
    + {onAction && ( +
    + + +
    )} -
    - - {/* Input area */} -
    -
    +