From fb759c0f308628778904dbb5d17bcd0e81f777b9 Mon Sep 17 00:00:00 2001 From: qin-se-and-ming-1128 <15331865+qin-se-and-ming-1128@user.noreply.gitee.com> Date: Mon, 6 Oct 2025 01:34:41 +0800 Subject: [PATCH 1/2] feat: enhance tracing with HTTP client instrumentation and UI improvements This commit introduces three major improvements to the tracing system: 1. **HTTP Client Instrumentation** - Add automatic tracing for outbound HTTP requests - Support for requests, httpx (sync/async), and aiohttp clients - Capture HTTP method, URL, host, status code, and response size - Automatic span creation and error tracking for HTTP calls 2. **Tracing UI Localization** - Add complete i18n support for TracesList component - Translate search placeholder, status filters, time ranges - Translate error messages and empty states - Support both English and Chinese languages 3. **Search Functionality** - Add search parameter to /api/traces endpoint - Enable filtering traces by operation name (ILIKE) - Wire up search input in frontend to backend API - Update TypeScript client with search parameter support Technical changes: - Instrument HTTP clients via monkey-patching in tracing.py - Refactor get_waterfall_data to use session factory pattern - Fix DuckDB transaction conflicts in trace detail endpoints --- .gitignore | 4 + fastapi_radar/api.py | 146 +++++--- fastapi_radar/dashboard/src/api/client.ts | 2 + .../dashboard/src/components/TracesList.tsx | 39 ++- .../dashboard/src/i18n/translations.ts | 51 +++ fastapi_radar/radar.py | 11 +- fastapi_radar/tracing.py | 329 +++++++++++++++--- tests/test_async_radar.py | 3 + 8 files changed, 472 insertions(+), 113 deletions(-) diff --git a/.gitignore b/.gitignore index aeb91a2..f5d2f95 100644 --- a/.gitignore +++ b/.gitignore @@ -55,6 +55,10 @@ coverage.xml *.cover .hypothesis/ +# Claude Code & Serena +.claude/ +.serena/ + # FastAPI Radar specific radar.db example.db diff --git a/fastapi_radar/api.py b/fastapi_radar/api.py index fa4a20b..b72cca8 100644 --- a/fastapi_radar/api.py +++ b/fastapi_radar/api.py @@ -120,14 +120,14 @@ class TraceDetail(BaseModel): spans: List[WaterfallSpan] -def create_api_router(get_session_context) -> APIRouter: +def create_api_router(get_session_context,get_session_local_context) -> APIRouter: router = APIRouter(prefix="/__radar/api", tags=["radar"]) def get_db(): """Dependency function for FastAPI to get database session.""" with get_session_context() as session: yield session - + @router.get("/requests", response_model=List[RequestSummary]) async def get_requests( limit: int = Query(100, ge=1, le=1000), @@ -300,21 +300,24 @@ async def get_exceptions( async def get_stats( hours: int = Query(1, ge=1, le=720), # Allow up to 30 days slow_threshold: int = Query(100), - session: Session = Depends(get_db), + ): since = datetime.now(timezone.utc) - timedelta(hours=hours) - + SessionLocal = get_session_local_context() # 获取SessionLocal (sessionmaker) + requests_session = SessionLocal() # 创建实际的session实例 + queries_session = SessionLocal() # 创建实际的session实例 + exceptions_session = SessionLocal() # 创建实际的session实例 requests = ( - session.query( + requests_session.query( func.count().label("total_requests"), func.avg(CapturedRequest.duration_ms).label("avg_response_time"), ) .filter(CapturedRequest.created_at >= since) .one() ) - + requests_session.close() queries = ( - session.query( + queries_session.query( func.count().label("total_queries"), func.avg(CapturedQuery.duration_ms).label("avg_query_time"), func.sum( @@ -324,13 +327,15 @@ async def get_stats( .filter(CapturedQuery.created_at >= since) .one() ) - + queries_session.close() exceptions = ( - session.query(func.count().label("total_exceptions")) + exceptions_session.query(func.count().label("total_exceptions")) .filter(CapturedException.created_at >= since) .one() ) + exceptions_session.close() + total_requests = requests.total_requests avg_response_time = requests.avg_response_time @@ -377,6 +382,7 @@ async def get_traces( service_name: Optional[str] = Query(None), min_duration_ms: Optional[float] = Query(None), hours: int = Query(24, ge=1, le=720), + search: Optional[str] = Query(None), session: Session = Depends(get_db), ): """List traces.""" @@ -389,6 +395,8 @@ async def get_traces( query = query.filter(Trace.service_name == service_name) if min_duration_ms: query = query.filter(Trace.duration_ms >= min_duration_ms) + if search: + query = query.filter(Trace.operation_name.ilike(f"%{search}%")) traces = ( query.order_by(desc(Trace.start_time)).offset(offset).limit(limit).all() @@ -412,56 +420,90 @@ async def get_traces( @router.get("/traces/{trace_id}", response_model=TraceDetail) async def get_trace_detail( trace_id: str, - session: Session = Depends(get_db), ): """Get trace details.""" - trace = session.query(Trace).filter(Trace.trace_id == trace_id).first() - if not trace: - raise HTTPException(status_code=404, detail="Trace not found") - - # Fetch waterfall data - tracing_manager = TracingManager(lambda: get_session_context()) - waterfall_spans = tracing_manager.get_waterfall_data(trace_id) - - return TraceDetail( - trace_id=trace.trace_id, - service_name=trace.service_name, - operation_name=trace.operation_name, - start_time=trace.start_time, - end_time=trace.end_time, - duration_ms=round_float(trace.duration_ms), - span_count=trace.span_count, - status=trace.status, - tags=trace.tags, - created_at=trace.created_at, - spans=[WaterfallSpan(**span) for span in waterfall_spans], - ) - + import traceback + SessionLocal = get_session_local_context() # 获取SessionLocal (sessionmaker) + session = SessionLocal() # 创建实际的session实例 + try: + #print(f"[DEBUG] Getting trace detail for trace_id: {trace_id}") + trace = session.query(Trace).filter(Trace.trace_id == trace_id).first() + # 不需要 commit,因为这是 SELECT 查询 + if not trace: + #print(f"[DEBUG] Trace not found for trace_id: {trace_id}") + raise HTTPException(status_code=404, detail="Trace not found") + + #print(f"[DEBUG] Trace found, fetching waterfall data...") + # Fetch waterfall data + session.close() + waterfall_spans = TracingManager.get_waterfall_data(get_session_local_context, trace_id) + #print(f"[DEBUG] Waterfall data fetched, {len(waterfall_spans)} spans") + + return TraceDetail( + trace_id=trace.trace_id, + service_name=trace.service_name, + operation_name=trace.operation_name, + start_time=trace.start_time, + end_time=trace.end_time, + duration_ms=round_float(trace.duration_ms), + span_count=trace.span_count, + status=trace.status, + tags=trace.tags, + created_at=trace.created_at, + spans=[WaterfallSpan(**span) for span in waterfall_spans], + ) + except HTTPException: + raise # 直接抛出 HTTPException + except Exception as e: + print(f"[ERROR] Exception in get_trace_detail: {str(e)}") + print(f"[ERROR] Traceback: {traceback.format_exc()}") + session.rollback() + raise HTTPException(status_code=500, detail=str(e)) + finally: + session.close() + @router.get("/traces/{trace_id}/waterfall") async def get_trace_waterfall( trace_id: str, - session: Session = Depends(get_db), ): """Get optimized waterfall data for a trace.""" - # Ensure the trace exists - trace = session.query(Trace).filter(Trace.trace_id == trace_id).first() - if not trace: - raise HTTPException(status_code=404, detail="Trace not found") - - tracing_manager = TracingManager(lambda: get_session_context()) - waterfall_data = tracing_manager.get_waterfall_data(trace_id) - - return { - "trace_id": trace_id, - "spans": waterfall_data, - "trace_info": { - "service_name": trace.service_name, - "operation_name": trace.operation_name, - "total_duration_ms": trace.duration_ms, - "span_count": trace.span_count, - "status": trace.status, - }, - } + import traceback + SessionLocal = get_session_local_context() # 获取SessionLocal (sessionmaker) + session = SessionLocal() # 创建实际的session实例 + try: + #print(f"[DEBUG] Getting waterfall for trace_id: {trace_id}") + # Ensure the trace exists + trace = session.query(Trace).filter(Trace.trace_id == trace_id).first() + # 不需要 commit,因为这是 SELECT 查询 + if not trace: + #print(f"[DEBUG] Trace not found for trace_id: {trace_id}") + raise HTTPException(status_code=404, detail="Trace not found") + + #print(f"[DEBUG] Trace found, fetching waterfall data...") + session.close() + waterfall_data = TracingManager.get_waterfall_data(get_session_local_context, trace_id) + #print(f"[DEBUG] Waterfall data fetched, {len(waterfall_data)} spans") + + return { + "trace_id": trace_id, + "spans": waterfall_data, + "trace_info": { + "service_name": trace.service_name, + "operation_name": trace.operation_name, + "total_duration_ms": trace.duration_ms, + "span_count": trace.span_count, + "status": trace.status, + }, + } + except HTTPException: + raise # 直接抛出 HTTPException + except Exception as e: + print(f"[ERROR] Exception in get_trace_waterfall: {str(e)}") + print(f"[ERROR] Traceback: {traceback.format_exc()}") + session.rollback() + raise HTTPException(status_code=500, detail=str(e)) + finally: + session.close() @router.get("/spans/{span_id}") async def get_span_detail( diff --git a/fastapi_radar/dashboard/src/api/client.ts b/fastapi_radar/dashboard/src/api/client.ts index 4230f6e..79fa284 100644 --- a/fastapi_radar/dashboard/src/api/client.ts +++ b/fastapi_radar/dashboard/src/api/client.ts @@ -213,6 +213,7 @@ class APIClient { service_name?: string; min_duration_ms?: number; hours?: number; + search?: string; }): Promise { const queryParams = new URLSearchParams(); if (params?.limit) queryParams.append("limit", params.limit.toString()); @@ -223,6 +224,7 @@ class APIClient { if (params?.min_duration_ms) queryParams.append("min_duration_ms", params.min_duration_ms.toString()); if (params?.hours) queryParams.append("hours", params.hours.toString()); + if (params?.search) queryParams.append("search", params.search); const response = await fetch(`${this.baseUrl}/traces?${queryParams}`); return response.json(); diff --git a/fastapi_radar/dashboard/src/components/TracesList.tsx b/fastapi_radar/dashboard/src/components/TracesList.tsx index a769dba..97dc7b9 100644 --- a/fastapi_radar/dashboard/src/components/TracesList.tsx +++ b/fastapi_radar/dashboard/src/components/TracesList.tsx @@ -13,6 +13,7 @@ import { SelectValue, } from "@/components/ui/select"; import { useDetailDrawer } from "@/context/DetailDrawerContext"; +import { useT } from "@/i18n"; import { formatDistanceToNow } from "date-fns"; import { Search, @@ -64,6 +65,7 @@ function getStatusVariant( export function TracesList({ className }: TracesListProps) { const { openDetail } = useDetailDrawer(); + const t = useT(); const [filters, setFilters] = useState({ search: "", @@ -91,6 +93,7 @@ export function TracesList({ className }: TracesListProps) { service_name: filters.service || undefined, min_duration_ms: filters.minDuration || undefined, hours: filters.hours, + search: filters.search || undefined, }), refetchInterval: 30000, }); @@ -106,14 +109,14 @@ export function TracesList({ className }: TracesListProps) {

- Failed to load traces + {t("pages.tracing.failedToLoad")}

- There was an error loading the trace data. + {t("pages.tracing.failedToLoadMessage")}

@@ -131,7 +134,7 @@ export function TracesList({ className }: TracesListProps) {
setFilters({ ...filters, search: e.target.value }) @@ -148,12 +151,12 @@ export function TracesList({ className }: TracesListProps) { } > - + - All statuses - Success - Error + {t("pages.tracing.allStatuses")} + {t("pages.tracing.success")} + {t("pages.tracing.error")} @@ -167,16 +170,16 @@ export function TracesList({ className }: TracesListProps) { - Last hour - Last 6 hours - Last 24 hours - Last week + {t("pages.tracing.lastHour")} + {t("pages.tracing.last6Hours")} + {t("pages.tracing.last24Hours")} + {t("pages.tracing.lastWeek")}
@@ -198,7 +201,7 @@ export function TracesList({ className }: TracesListProps) { ) : traces.length === 0 ? (
-

No traces found matching your criteria.

+

{t("pages.tracing.noTracesFound")}

) : (
@@ -224,10 +227,10 @@ export function TracesList({ className }: TracesListProps) {
- Service: {trace.service_name || "Unknown"} - Spans: {trace.span_count} + {t("pages.tracing.service")}: {trace.service_name || "Unknown"} + {t("pages.tracing.spans")}: {trace.span_count} - Duration: {formatDuration(trace.duration_ms)} + {t("pages.tracing.duration")}: {formatDuration(trace.duration_ms)}
@@ -252,7 +255,7 @@ export function TracesList({ className }: TracesListProps) { {traces.length === pageSize && (
)} diff --git a/fastapi_radar/dashboard/src/i18n/translations.ts b/fastapi_radar/dashboard/src/i18n/translations.ts index 7daa2db..82a66f9 100644 --- a/fastapi_radar/dashboard/src/i18n/translations.ts +++ b/fastapi_radar/dashboard/src/i18n/translations.ts @@ -40,6 +40,23 @@ export interface Translations { tracesCardDescription: string; noTraces: string; viewTrace: string; + searchPlaceholder: string; + allStatuses: string; + success: string; + error: string; + lastHour: string; + last6Hours: string; + last24Hours: string; + lastWeek: string; + refresh: string; + failedToLoad: string; + failedToLoadMessage: string; + tryAgain: string; + noTracesFound: string; + loadMore: string; + service: string; + spans: string; + duration: string; }; database: { title: string; @@ -421,6 +438,23 @@ const en: Translations = { "Browse all distributed tracing data and open detailed waterfall views", noTraces: "No trace data available", viewTrace: "View trace", + searchPlaceholder: "Search by operation name...", + allStatuses: "All statuses", + success: "Success", + error: "Error", + lastHour: "Last hour", + last6Hours: "Last 6 hours", + last24Hours: "Last 24 hours", + lastWeek: "Last week", + refresh: "Refresh", + failedToLoad: "Failed to load traces", + failedToLoadMessage: "There was an error loading the trace data.", + tryAgain: "Try again", + noTracesFound: "No traces found matching your criteria.", + loadMore: "Load more", + service: "Service", + spans: "Spans", + duration: "Duration", }, database: { title: "Database", @@ -794,6 +828,23 @@ const zh: Translations = { tracesCardDescription: "浏览所有链路追踪数据,点击查看详细的瀑布流图", noTraces: "暂无追踪数据", viewTrace: "查看追踪详情", + searchPlaceholder: "按操作名称搜索...", + allStatuses: "所有状态", + success: "成功", + error: "错误", + lastHour: "最近1小时", + last6Hours: "最近6小时", + last24Hours: "最近24小时", + lastWeek: "最近一周", + refresh: "刷新", + failedToLoad: "加载追踪失败", + failedToLoadMessage: "加载追踪数据时出错。", + tryAgain: "重试", + noTracesFound: "未找到符合条件的追踪记录。", + loadMore: "加载更多", + service: "服务", + spans: "Spans", + duration: "持续时间", }, database: { title: "数据库监控", diff --git a/fastapi_radar/radar.py b/fastapi_radar/radar.py index e036184..76fe3f6 100644 --- a/fastapi_radar/radar.py +++ b/fastapi_radar/radar.py @@ -17,6 +17,7 @@ from .capture import QueryCapture from .middleware import RadarMiddleware from .models import Base +from .tracing import instrument_outbound_http_clients def is_reload_worker() -> bool: @@ -149,6 +150,8 @@ def __init__( self.SessionLocal = sessionmaker( autocommit=False, autoflush=False, bind=self.storage_engine ) + if self.enable_tracing: + instrument_outbound_http_clients() self._setup_middleware() @@ -157,7 +160,7 @@ def __init__( self._setup_api(include_in_schema=include_in_schema) self._setup_dashboard(include_in_schema=include_in_schema) - + @contextmanager def get_session(self) -> Session: """Get a database session for radar storage.""" @@ -179,6 +182,10 @@ def _setup_middleware(self) -> None: service_name=self.service_name, ) + def get_session_factory(self): + """Return the SessionLocal factory for creating independent sessions.""" + return self.SessionLocal + def _setup_query_capture(self) -> None: """Setup SQLAlchemy query capture.""" assert ( @@ -194,7 +201,7 @@ def _setup_query_capture(self) -> None: def _setup_api(self, include_in_schema: bool) -> None: """Mount API endpoints.""" - api_router = create_api_router(self.get_session) + api_router = create_api_router(self.get_session,self.get_session_factory) self.app.include_router(api_router, include_in_schema=include_in_schema) def _setup_dashboard(self, include_in_schema: bool) -> None: diff --git a/fastapi_radar/tracing.py b/fastapi_radar/tracing.py index 235a3b4..63c3baf 100644 --- a/fastapi_radar/tracing.py +++ b/fastapi_radar/tracing.py @@ -1,11 +1,16 @@ """Tracing core functionality module.""" +"""Tracing core functionality module.""" +import functools import uuid from datetime import datetime, timezone -from typing import Optional, Dict, Any, List +from typing import Optional, Dict, Any, List, Tuple from contextvars import ContextVar +from urllib.parse import urlsplit from sqlalchemy.orm import Session - +import traceback +# Query optimized for DuckDB +from sqlalchemy import text from .models import Trace, Span, SpanRelation # Trace context for the current request @@ -186,60 +191,302 @@ def calculate_depth( ) session.add(relation) - def get_waterfall_data(self, trace_id: str) -> List[Dict[str, Any]]: - """Return data for the waterfall view.""" - with self.get_session() as session: - # Query optimized for DuckDB - from sqlalchemy import text - - waterfall_query = text( - """ - WITH span_timeline AS ( - SELECT - s.span_id, - s.parent_span_id, - s.operation_name, - s.service_name, - s.start_time, - s.end_time, - s.duration_ms, - s.status, - s.tags, - COALESCE(r.depth, 0) as depth, - -- Offset relative to trace start - EXTRACT(EPOCH FROM ( - s.start_time - MIN(s.start_time) - OVER (PARTITION BY s.trace_id) - )) * 1000 as offset_ms - FROM radar_spans s - LEFT JOIN radar_span_relations r ON s.span_id = r.child_span_id - WHERE s.trace_id = :trace_id - ) - SELECT * FROM span_timeline - ORDER BY offset_ms, depth + @classmethod + def get_waterfall_data( + cls, session_local, trace_id: str + ) -> List[Dict[str, Any]]: + """Return data for the waterfall view using the provided session.""" + + + #print(f"[DEBUG] get_waterfall_data called with trace_id: {trace_id}") + + waterfall_query = text( """ + WITH span_timeline AS ( + SELECT + s.span_id, + s.parent_span_id, + s.operation_name, + s.service_name, + s.start_time, + s.end_time, + s.duration_ms, + s.status, + s.tags, + COALESCE(r.depth, 0) as depth, + -- Offset relative to trace start + EXTRACT(EPOCH FROM ( + s.start_time - MIN(s.start_time) + OVER (PARTITION BY s.trace_id) + )) * 1000 as offset_ms + FROM radar_spans s + LEFT JOIN radar_span_relations r ON s.span_id = r.child_span_id + WHERE s.trace_id = :trace_id ) + SELECT * FROM span_timeline + ORDER BY offset_ms, depth + """ + ) + + #print(f"[DEBUG] Getting SessionLocal from session_local function") + SessionLocal = session_local() # 获取SessionLocal (sessionmaker) + #print(f"[DEBUG] SessionLocal type: {type(SessionLocal)}") + + session = SessionLocal() # 创建实际的session实例 + #print(f"[DEBUG] Session created, type: {type(session)}") + try: + #print(f"[DEBUG] Executing waterfall query for trace_id: {trace_id}") result = session.execute(waterfall_query, {"trace_id": trace_id}) + #print(f"[DEBUG] Query executed successfully") - return [ - { + # 不需要 commit,因为这是 SELECT 查询 + rows = [] + for row in result: + rows.append({ "span_id": row.span_id, "parent_span_id": row.parent_span_id, "operation_name": row.operation_name, "service_name": row.service_name, - "start_time": ( - row.start_time.isoformat() if row.start_time else None - ), + "start_time": row.start_time.isoformat() if row.start_time else None, "end_time": row.end_time.isoformat() if row.end_time else None, "duration_ms": row.duration_ms, "status": row.status, "tags": row.tags, "depth": row.depth, "offset_ms": float(row.offset_ms) if row.offset_ms else 0.0, - } - for row in result - ] + }) + + #print(f"[DEBUG] Processed {len(rows)} rows from query result") + return rows + + except Exception as e: + print(f"[ERROR] Exception in get_waterfall_data: {str(e)}") + print(f"[ERROR] Traceback: {traceback.format_exc()}") + session.rollback() + raise + finally: + #print(f"[DEBUG] Closing session") + session.close() + + +def _extract_http_host(url: Optional[str]) -> Optional[str]: + if not url: + return None + + try: + parsed = urlsplit(url) + return parsed.netloc or None + except Exception: + return None + + +def _create_http_span( + method: Optional[str], url: Optional[str] +) -> Tuple[Optional["TraceContext"], Optional[str]]: + trace_ctx = get_current_trace_context() + if not trace_ctx: + return None, None + + method_name = str(method).upper() if method else "GET" + url_value = str(url) if url is not None else "" + tags: Dict[str, Any] = { + "component": "http", + "http.method": method_name, + "http.url": url_value, + } + + host = _extract_http_host(url_value) + if host: + tags["http.host"] = host + + span_id = trace_ctx.create_span( + operation_name=f"HTTP {method_name}", + span_kind="client", + tags=tags, + ) + + return trace_ctx, span_id + + +def _extract_status_code(response: Any) -> Optional[int]: + for attr in ("status_code", "status"): + value = getattr(response, attr, None) + if value is not None: + try: + return int(value) + except (TypeError, ValueError): + return None + return None + + +def _extract_content_length(response: Any) -> Optional[str]: + headers = getattr(response, "headers", None) + if not headers: + return None + + try: + return headers.get("content-length") + except Exception: + return None + + +def _finish_http_span( + trace_ctx: Optional["TraceContext"], + span_id: Optional[str], + response: Any = None, + error: Optional[BaseException] = None, +) -> None: + if not trace_ctx or not span_id: + return + + tags: Dict[str, Any] = {} + status = "ok" + + if response is not None: + status_code = _extract_status_code(response) + if status_code is not None: + tags["http.status_code"] = status_code + + content_length = _extract_content_length(response) + if content_length: + tags["http.response_content_length"] = content_length + + if error is not None: + status = "error" + tags["error.type"] = type(error).__name__ + tags["error.message"] = str(error) + trace_ctx.add_span_log( + span_id, + f"HTTP request failed: {error}", + level="error", + exception_type=type(error).__name__, + ) + + trace_ctx.finish_span(span_id, status=status, tags=tags if tags else None) + + +def _instrument_requests() -> None: + try: + import requests # type: ignore[import-not-found] + except ImportError: + return + + session_cls = requests.sessions.Session + original_request = session_cls.request + if getattr(original_request, "_radar_instrumented", False): + return + + @functools.wraps(original_request) + def wrapped_request(self, method, url, *args, **kwargs): + trace_ctx, span_id = _create_http_span(method, url) + try: + response = original_request(self, method, url, *args, **kwargs) + _finish_http_span(trace_ctx, span_id, response=response) + return response + except Exception as exc: + _finish_http_span(trace_ctx, span_id, error=exc) + raise + + wrapped_request._radar_instrumented = True # type: ignore[attr-defined] + wrapped_request._radar_original = original_request # type: ignore[attr-defined] + session_cls.request = wrapped_request + + +def _instrument_httpx() -> None: + try: + import httpx # type: ignore[import-not-found] + except ImportError: + return + + if hasattr(httpx, "Client"): + original_client_request = httpx.Client.request + if not getattr(original_client_request, "_radar_instrumented", False): + + @functools.wraps(original_client_request) + def client_request(self, method, url, *args, **kwargs): + trace_ctx, span_id = _create_http_span(method, url) + try: + response = original_client_request(self, method, url, *args, **kwargs) + _finish_http_span(trace_ctx, span_id, response=response) + return response + except Exception as exc: + _finish_http_span(trace_ctx, span_id, error=exc) + raise + + client_request._radar_instrumented = True # type: ignore[attr-defined] + client_request._radar_original = original_client_request # type: ignore[attr-defined] + httpx.Client.request = client_request + + if hasattr(httpx, "AsyncClient"): + original_async_request = httpx.AsyncClient.request + if not getattr(original_async_request, "_radar_instrumented", False): + + @functools.wraps(original_async_request) + async def async_client_request(self, method, url, *args, **kwargs): + trace_ctx, span_id = _create_http_span(method, url) + try: + response = await original_async_request(self, method, url, *args, **kwargs) + _finish_http_span(trace_ctx, span_id, response=response) + return response + except Exception as exc: + _finish_http_span(trace_ctx, span_id, error=exc) + raise + + async_client_request._radar_instrumented = True # type: ignore[attr-defined] + async_client_request._radar_original = original_async_request # type: ignore[attr-defined] + httpx.AsyncClient.request = async_client_request + + if hasattr(httpx, "request"): + original_module_request = httpx.request + if not getattr(original_module_request, "_radar_instrumented", False): + + @functools.wraps(original_module_request) + def module_request(method, url, *args, **kwargs): + trace_ctx, span_id = _create_http_span(method, url) + try: + response = original_module_request(method, url, *args, **kwargs) + _finish_http_span(trace_ctx, span_id, response=response) + return response + except Exception as exc: + _finish_http_span(trace_ctx, span_id, error=exc) + raise + + module_request._radar_instrumented = True # type: ignore[attr-defined] + module_request._radar_original = original_module_request # type: ignore[attr-defined] + httpx.request = module_request + + +def _instrument_aiohttp() -> None: + try: + import aiohttp # type: ignore[import-not-found] + except ImportError: + return + + original_request = aiohttp.ClientSession._request + if getattr(original_request, "_radar_instrumented", False): + return + + @functools.wraps(original_request) + async def wrapped_request(self, method, url, *args, **kwargs): + trace_ctx, span_id = _create_http_span(method, url) + try: + response = await original_request(self, method, url, *args, **kwargs) + _finish_http_span(trace_ctx, span_id, response=response) + return response + except Exception as exc: + _finish_http_span(trace_ctx, span_id, error=exc) + raise + + wrapped_request._radar_instrumented = True # type: ignore[attr-defined] + wrapped_request._radar_original = original_request # type: ignore[attr-defined] + aiohttp.ClientSession._request = wrapped_request + + +def instrument_outbound_http_clients() -> None: + _instrument_requests() + _instrument_httpx() + _instrument_aiohttp() def get_current_trace_context() -> Optional[TraceContext]: diff --git a/tests/test_async_radar.py b/tests/test_async_radar.py index e95a700..532d15b 100644 --- a/tests/test_async_radar.py +++ b/tests/test_async_radar.py @@ -46,6 +46,9 @@ async def get_users(): async with async_session() as session: result = await session.execute(select(users_table)) rows = result.mappings().all() + import httpx,requests + res1 = httpx.get("http://www.baidu.com") + res2 = requests.get("http://www.baidu.com") return {"users": [dict(row) for row in rows]} From 426ede3c9957a1c622625f8496670d5a1e2e579e Mon Sep 17 00:00:00 2001 From: qin-se-and-ming-1128 <15331865+qin-se-and-ming-1128@user.noreply.gitee.com> Date: Sun, 12 Oct 2025 00:06:51 +0800 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=90=8E?= =?UTF-8?q?=E5=8F=B0=E4=BB=BB=E5=8A=A1=E7=9B=91=E6=8E=A7=E5=92=8CWebSocket?= =?UTF-8?q?=E5=AE=9E=E6=97=B6=E6=9B=B4=E6=96=B0=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fastapi_radar/api.py | 113 +++-- fastapi_radar/background_tasks/__init__.py | 15 + fastapi_radar/background_tasks/tracker.py | 342 ++++++++++++++ .../dashboard/dist/assets/index-31zorKsE.js | 313 ------------- .../dashboard/dist/assets/index-BGkXmlWs.js | 323 +++++++++++++ .../dashboard/dist/assets/index-DAzKSDtu.css | 1 + .../dashboard/dist/assets/index-XlGcZj49.css | 1 - fastapi_radar/dashboard/dist/index.html | 26 +- fastapi_radar/dashboard/src/App.tsx | 2 + fastapi_radar/dashboard/src/api/client.ts | 42 +- .../dashboard/src/components/Sidebar.tsx | 7 + .../dashboard/src/i18n/translations.ts | 102 +++++ .../src/pages/BackgroundTasksPage.tsx | 433 ++++++++++++++++++ fastapi_radar/radar.py | 31 +- tests/test_async_radar.py | 14 +- tests/test_radar.py | 50 +- 16 files changed, 1453 insertions(+), 362 deletions(-) create mode 100644 fastapi_radar/background_tasks/__init__.py create mode 100644 fastapi_radar/background_tasks/tracker.py delete mode 100644 fastapi_radar/dashboard/dist/assets/index-31zorKsE.js create mode 100644 fastapi_radar/dashboard/dist/assets/index-BGkXmlWs.js create mode 100644 fastapi_radar/dashboard/dist/assets/index-DAzKSDtu.css delete mode 100644 fastapi_radar/dashboard/dist/assets/index-XlGcZj49.css create mode 100644 fastapi_radar/dashboard/src/pages/BackgroundTasksPage.tsx diff --git a/fastapi_radar/api.py b/fastapi_radar/api.py index b72cca8..9a4bbe0 100644 --- a/fastapi_radar/api.py +++ b/fastapi_radar/api.py @@ -1,7 +1,7 @@ """API endpoints for FastAPI Radar dashboard.""" from datetime import datetime, timedelta, timezone -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Optional, Union, TYPE_CHECKING from fastapi import APIRouter, Depends, HTTPException, Query from pydantic import BaseModel @@ -11,6 +11,9 @@ from .models import CapturedRequest, CapturedQuery, CapturedException, Trace, Span from .tracing import TracingManager +if TYPE_CHECKING: + from .background_tasks import BackgroundTaskTracker + def round_float(value: Optional[float], decimals: int = 2) -> Optional[float]: """Round a float value to specified decimal places.""" @@ -119,14 +122,65 @@ class TraceDetail(BaseModel): created_at: datetime spans: List[WaterfallSpan] +class BackgroundTaskParams(BaseModel): + args: List[Any] + kwargs: Dict[str, Any] + + +class BackgroundTaskInfo(BaseModel): + id: str + function_key: str + function_name: str + status: str + queued_at: datetime + started_at: Optional[datetime] + ended_at: Optional[datetime] + duration_ms: Optional[float] + params: BackgroundTaskParams + error_message: Optional[str] + error_trace: Optional[str] + -def create_api_router(get_session_context,get_session_local_context) -> APIRouter: +def create_api_router( + get_session_context, + get_session_local_context, + task_tracker: Optional["BackgroundTaskTracker"] = None, +) -> APIRouter: router = APIRouter(prefix="/__radar/api", tags=["radar"]) def get_db(): """Dependency function for FastAPI to get database session.""" with get_session_context() as session: yield session + + if task_tracker is not None: + + @router.get( + "/background-tasks", + response_model=List[BackgroundTaskInfo], + tags=["radar-tasks"], + ) + async def get_background_tasks() -> List[BackgroundTaskInfo]: + return task_tracker.list_tasks() + + @router.delete( + "/background-tasks", + tags=["radar-tasks"], + ) + async def clear_background_tasks() -> Dict[str, bool]: + task_tracker.clear() + return {"ok": True} + + @router.post( + "/background-tasks/{task_id}/rerun", + tags=["radar-tasks"], + ) + async def rerun_background_task(task_id: str) -> Dict[str, bool]: + try: + task_tracker.rerun(task_id) + except KeyError: + raise HTTPException(status_code=404, detail="Task not found") + return {"ok": True} @router.get("/requests", response_model=List[RequestSummary]) async def get_requests( @@ -304,37 +358,36 @@ async def get_stats( ): since = datetime.now(timezone.utc) - timedelta(hours=hours) SessionLocal = get_session_local_context() # 获取SessionLocal (sessionmaker) - requests_session = SessionLocal() # 创建实际的session实例 - queries_session = SessionLocal() # 创建实际的session实例 - exceptions_session = SessionLocal() # 创建实际的session实例 - requests = ( - requests_session.query( - func.count().label("total_requests"), - func.avg(CapturedRequest.duration_ms).label("avg_response_time"), + + with SessionLocal() as requests_session: + requests = ( + requests_session.query( + func.count().label("total_requests"), + func.avg(CapturedRequest.duration_ms).label("avg_response_time"), + ) + .filter(CapturedRequest.created_at >= since) + .one() ) - .filter(CapturedRequest.created_at >= since) - .one() - ) - requests_session.close() - queries = ( - queries_session.query( - func.count().label("total_queries"), - func.avg(CapturedQuery.duration_ms).label("avg_query_time"), - func.sum( - case((CapturedQuery.duration_ms >= slow_threshold, 1), else_=0) - ).label("slow_queries"), + + with SessionLocal() as queries_session: + queries = ( + queries_session.query( + func.count().label("total_queries"), + func.avg(CapturedQuery.duration_ms).label("avg_query_time"), + func.sum( + case((CapturedQuery.duration_ms >= slow_threshold, 1), else_=0) + ).label("slow_queries"), + ) + .filter(CapturedQuery.created_at >= since) + .one() ) - .filter(CapturedQuery.created_at >= since) - .one() - ) - queries_session.close() - exceptions = ( - exceptions_session.query(func.count().label("total_exceptions")) - .filter(CapturedException.created_at >= since) - .one() - ) - exceptions_session.close() + with SessionLocal() as exceptions_session: + exceptions = ( + exceptions_session.query(func.count().label("total_exceptions")) + .filter(CapturedException.created_at >= since) + .one() + ) total_requests = requests.total_requests avg_response_time = requests.avg_response_time diff --git a/fastapi_radar/background_tasks/__init__.py b/fastapi_radar/background_tasks/__init__.py new file mode 100644 index 0000000..b84164d --- /dev/null +++ b/fastapi_radar/background_tasks/__init__.py @@ -0,0 +1,15 @@ +"""Background task monitoring utilities for FastAPI Radar.""" + +from .tracker import ( + BackgroundTaskTracker, + create_tasks_websocket_router, + get_background_task_tracker, + install_background_task_tracker, +) + +__all__ = [ + "BackgroundTaskTracker", + "create_tasks_websocket_router", + "get_background_task_tracker", + "install_background_task_tracker", +] diff --git a/fastapi_radar/background_tasks/tracker.py b/fastapi_radar/background_tasks/tracker.py new file mode 100644 index 0000000..aa92add --- /dev/null +++ b/fastapi_radar/background_tasks/tracker.py @@ -0,0 +1,342 @@ +from __future__ import annotations + +import asyncio +import inspect +import threading +import traceback +import uuid +from dataclasses import dataclass, field +from datetime import datetime, timezone +from typing import Any, Callable, Dict, Iterable, List, Optional, Set, Tuple + +from fastapi import APIRouter, WebSocket +from fastapi.websockets import WebSocketDisconnect +from starlette.websockets import WebSocketState + +TrackedArgs = Tuple[Any, ...] +TrackedKwargs = Dict[str, Any] + + +def _now() -> datetime: + return datetime.now(timezone.utc) + + +def _to_serializable(value: Any) -> Any: + if value is None or isinstance(value, (str, int, float, bool)): + return value + if isinstance(value, datetime): + return value.isoformat() + if isinstance(value, (list, tuple, set)): + return [_to_serializable(item) for item in value] + if isinstance(value, dict): + return {str(key): _to_serializable(val) for key, val in value.items()} + return repr(value) + + +def _function_key(func: Callable[..., Any]) -> str: + module = getattr(func, "__module__", "unknown") + qualname = getattr(func, "__qualname__", getattr(func, "__name__", "callable")) + return f"{module}:{qualname}" + + +@dataclass +class TrackedTask: + """Represents a background task lifecycle.""" + + id: str + function_key: str + function_name: str + queued_at: datetime + status: str = "queued" + started_at: Optional[datetime] = None + ended_at: Optional[datetime] = None + args_serialized: List[Any] = field(default_factory=list) + kwargs_serialized: Dict[str, Any] = field(default_factory=dict) + error_message: Optional[str] = None + error_trace: Optional[str] = None + _args: TrackedArgs = field(default_factory=tuple, repr=False) + _kwargs: TrackedKwargs = field(default_factory=dict, repr=False) + + def duration_ms(self) -> Optional[float]: + if self.started_at is None or self.ended_at is None: + return None + delta = self.ended_at - self.started_at + return round(delta.total_seconds() * 1000.0, 2) + + def to_dict(self) -> Dict[str, Any]: + return { + "id": self.id, + "function_key": self.function_key, + "function_name": self.function_name, + "status": self.status, + "queued_at": self.queued_at.isoformat(), + "started_at": self.started_at.isoformat() if self.started_at else None, + "ended_at": self.ended_at.isoformat() if self.ended_at else None, + "duration_ms": self.duration_ms(), + "params": { + "args": self.args_serialized, + "kwargs": self.kwargs_serialized, + }, + "error_message": self.error_message, + "error_trace": self.error_trace, + } + + +class BackgroundTaskTracker: + """Track FastAPI background task execution and provide live updates.""" + + def __init__(self, max_tasks: int = 10000) -> None: + self._max_tasks = max_tasks + self._tasks: Dict[str, TrackedTask] = {} + self._functions: Dict[str, Callable[..., Any]] = {} + self._lock = threading.Lock() + self._connections: Set[WebSocket] = set() + self._connections_lock = threading.Lock() + + # ------------------------------------------------------------------ # + # Public API # + # ------------------------------------------------------------------ # + def wrap(self, func: Callable[..., Any], *args: Any, **kwargs: Any) -> Callable[[], None]: + """Wrap a callable so we can observe its lifecycle.""" + task_id = str(uuid.uuid4()) + func_key = _function_key(func) + queued_at = _now() + + serialized_args, serialized_kwargs = self._serialize_call_arguments(func, args, kwargs) + + tracked = TrackedTask( + id=task_id, + function_key=func_key, + function_name=getattr(func, "__name__", func_key), + queued_at=queued_at, + args_serialized=serialized_args, + kwargs_serialized=serialized_kwargs, + _args=args, + _kwargs=kwargs, + ) + + with self._lock: + self._tasks[task_id] = tracked + self._functions[func_key] = func + self._enforce_limit_locked() + + self._broadcast_snapshot() + + def runner() -> None: + self._mark_running(task_id) + try: + result = func(*args, **kwargs) + if inspect.isawaitable(result): + self._await_async_callable(result) + self._mark_finished(task_id) + except Exception as exc: # pragma: no cover - defensive + self._mark_failed(task_id, exc) + finally: + self._finalize(task_id) + + return runner + + def list_tasks(self) -> List[Dict[str, Any]]: + with self._lock: + tasks = list(self._tasks.values()) + tasks.sort(key=lambda task: task.queued_at, reverse=True) + return [task.to_dict() for task in tasks] + + def clear(self) -> None: + with self._lock: + self._tasks.clear() + self._functions.clear() + self._broadcast_snapshot() + + def rerun(self, task_id: str) -> None: + with self._lock: + task = self._tasks.get(task_id) + if not task: + raise KeyError(task_id) + func = self._functions.get(task.function_key) + if not func: + raise KeyError(task.function_key) + args = task._args + kwargs = task._kwargs + + runner = self.wrap(func, *args, **kwargs) + thread = threading.Thread(target=runner, daemon=True) + thread.start() + + async def handle_websocket(self, websocket: WebSocket) -> None: + await websocket.accept() + self._add_connection(websocket) + try: + await websocket.send_json({"tasks": self.list_tasks()}) + while True: + await websocket.receive_text() + except WebSocketDisconnect: + pass + finally: + self._remove_connection(websocket) + + # ------------------------------------------------------------------ # + # Internal helpers # + # ------------------------------------------------------------------ # + def _add_connection(self, websocket: WebSocket) -> None: + with self._connections_lock: + self._connections.add(websocket) + + def _remove_connection(self, websocket: WebSocket) -> None: + with self._connections_lock: + self._connections.discard(websocket) + + def _serialize_call_arguments( + self, + func: Callable[..., Any], + args: Iterable[Any], + kwargs: Dict[str, Any], + ) -> Tuple[List[Any], Dict[str, Any]]: + serialized_args = [_to_serializable(item) for item in args] + serialized_kwargs = {key: _to_serializable(val) for key, val in kwargs.items()} + + if not kwargs: + try: + signature = inspect.signature(func) + bound = signature.bind_partial(*args) + bound.apply_defaults() + serialized_kwargs = { + key: _to_serializable(val) for key, val in bound.arguments.items() + } + serialized_args = [] + except Exception: + # Fall back to positional rendering; best effort only. + pass + + return serialized_args, serialized_kwargs + + def _await_async_callable(self, awaitable: Any) -> None: + try: + loop = asyncio.get_running_loop() + except RuntimeError: + asyncio.run(awaitable) + return + + future = asyncio.run_coroutine_threadsafe(awaitable, loop) + future.result() + + def _mark_running(self, task_id: str) -> None: + with self._lock: + task = self._tasks.get(task_id) + if not task: + return + task.status = "running" + task.started_at = _now() + self._broadcast_snapshot() + + def _mark_finished(self, task_id: str) -> None: + with self._lock: + task = self._tasks.get(task_id) + if not task: + return + task.status = "finished" + self._broadcast_snapshot() + + def _mark_failed(self, task_id: str, exc: Exception) -> None: + formatted_trace = traceback.format_exc() + with self._lock: + task = self._tasks.get(task_id) + if not task: + return + task.status = "failed" + task.error_message = str(exc) + task.error_trace = formatted_trace + self._broadcast_snapshot() + + def _finalize(self, task_id: str) -> None: + with self._lock: + task = self._tasks.get(task_id) + if not task: + return + task.ended_at = _now() + self._enforce_limit_locked() + self._broadcast_snapshot() + + def _enforce_limit_locked(self) -> None: + if len(self._tasks) <= self._max_tasks: + return + tasks = sorted( + self._tasks.values(), + key=lambda task: ( + task.ended_at or datetime.max.replace(tzinfo=timezone.utc), + task.started_at or datetime.max.replace(tzinfo=timezone.utc), + task.queued_at, + ), + ) + excess = len(self._tasks) - self._max_tasks + for i in range(excess): + to_remove = tasks[i] + self._tasks.pop(to_remove.id, None) + + def _broadcast_snapshot(self) -> None: + snapshot = {"tasks": self.list_tasks()} + + async def _send() -> None: + to_remove: List[WebSocket] = [] + with self._connections_lock: + connections = list(self._connections) + for websocket in connections: + if websocket.client_state != WebSocketState.CONNECTED: + to_remove.append(websocket) + continue + try: + await websocket.send_json(snapshot) + except Exception: + to_remove.append(websocket) + if to_remove: + with self._connections_lock: + for websocket in to_remove: + self._connections.discard(websocket) + + try: + loop = asyncio.get_running_loop() + except RuntimeError: + asyncio.run(_send()) + else: + loop.create_task(_send()) + + +_ACTIVE_TRACKER: Optional[BackgroundTaskTracker] = None +_ORIGINAL_ADD_TASK: Optional[Callable[..., Any]] = None +_PATCH_LOCK = threading.Lock() + + +def get_background_task_tracker() -> Optional[BackgroundTaskTracker]: + return _ACTIVE_TRACKER + + +def install_background_task_tracker(tracker: BackgroundTaskTracker) -> None: + from fastapi import BackgroundTasks + + global _ACTIVE_TRACKER, _ORIGINAL_ADD_TASK + + with _PATCH_LOCK: + _ACTIVE_TRACKER = tracker + if _ORIGINAL_ADD_TASK is not None: + return + + _ORIGINAL_ADD_TASK = BackgroundTasks.add_task + + def patched_add_task(self: BackgroundTasks, func: Callable[..., Any], *args: Any, **kwargs: Any) -> None: + active = get_background_task_tracker() + if active is None: + return _ORIGINAL_ADD_TASK(self, func, *args, **kwargs) + wrapped = active.wrap(func, *args, **kwargs) + return _ORIGINAL_ADD_TASK(self, wrapped) + + BackgroundTasks.add_task = patched_add_task # type: ignore[assignment] + + +def create_tasks_websocket_router(tracker: BackgroundTaskTracker) -> APIRouter: + router = APIRouter() + + @router.websocket("/ws/background-tasks") + async def background_tasks_socket(websocket: WebSocket) -> None: + await tracker.handle_websocket(websocket) + + return router diff --git a/fastapi_radar/dashboard/dist/assets/index-31zorKsE.js b/fastapi_radar/dashboard/dist/assets/index-31zorKsE.js deleted file mode 100644 index a62b008..0000000 --- a/fastapi_radar/dashboard/dist/assets/index-31zorKsE.js +++ /dev/null @@ -1,313 +0,0 @@ -var FR=Object.defineProperty;var lb=e=>{throw TypeError(e)};var zR=(e,t,r)=>t in e?FR(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r;var Eu=(e,t,r)=>zR(e,typeof t!="symbol"?t+"":t,r),Gp=(e,t,r)=>t.has(e)||lb("Cannot "+r);var O=(e,t,r)=>(Gp(e,t,"read from private field"),r?r.call(e):t.get(e)),ee=(e,t,r)=>t.has(e)?lb("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(e):t.set(e,r),U=(e,t,r,n)=>(Gp(e,t,"write to private field"),n?n.call(e,r):t.set(e,r),r),ce=(e,t,r)=>(Gp(e,t,"access private method"),r);var Cu=(e,t,r,n)=>({set _(i){U(e,t,i,r)},get _(){return O(e,t,n)}});function BR(e,t){for(var r=0;rn[i]})}}}return Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const i of document.querySelectorAll('link[rel="modulepreload"]'))n(i);new MutationObserver(i=>{for(const a of i)if(a.type==="childList")for(const o of a.addedNodes)o.tagName==="LINK"&&o.rel==="modulepreload"&&n(o)}).observe(document,{childList:!0,subtree:!0});function r(i){const a={};return i.integrity&&(a.integrity=i.integrity),i.referrerPolicy&&(a.referrerPolicy=i.referrerPolicy),i.crossOrigin==="use-credentials"?a.credentials="include":i.crossOrigin==="anonymous"?a.credentials="omit":a.credentials="same-origin",a}function n(i){if(i.ep)return;i.ep=!0;const a=r(i);fetch(i.href,a)}})();function In(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var wE={exports:{}},dh={},bE={exports:{}},oe={};/** - * @license React - * react.production.min.js - * - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */var Bc=Symbol.for("react.element"),WR=Symbol.for("react.portal"),UR=Symbol.for("react.fragment"),qR=Symbol.for("react.strict_mode"),HR=Symbol.for("react.profiler"),KR=Symbol.for("react.provider"),VR=Symbol.for("react.context"),YR=Symbol.for("react.forward_ref"),QR=Symbol.for("react.suspense"),GR=Symbol.for("react.memo"),XR=Symbol.for("react.lazy"),cb=Symbol.iterator;function ZR(e){return e===null||typeof e!="object"?null:(e=cb&&e[cb]||e["@@iterator"],typeof e=="function"?e:null)}var SE={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},PE=Object.assign,jE={};function qs(e,t,r){this.props=e,this.context=t,this.refs=jE,this.updater=r||SE}qs.prototype.isReactComponent={};qs.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};qs.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function EE(){}EE.prototype=qs.prototype;function Cy(e,t,r){this.props=e,this.context=t,this.refs=jE,this.updater=r||SE}var Oy=Cy.prototype=new EE;Oy.constructor=Cy;PE(Oy,qs.prototype);Oy.isPureReactComponent=!0;var ub=Array.isArray,CE=Object.prototype.hasOwnProperty,ky={current:null},OE={key:!0,ref:!0,__self:!0,__source:!0};function kE(e,t,r){var n,i={},a=null,o=null;if(t!=null)for(n in t.ref!==void 0&&(o=t.ref),t.key!==void 0&&(a=""+t.key),t)CE.call(t,n)&&!OE.hasOwnProperty(n)&&(i[n]=t[n]);var s=arguments.length-2;if(s===1)i.children=r;else if(1>>1,Y=D[te];if(0>>1;tei(Be,W))bti(J,Be)?(D[te]=J,D[bt]=W,te=bt):(D[te]=Be,D[Xe]=W,te=Xe);else if(bti(J,W))D[te]=J,D[bt]=W,te=bt;else break e}}return I}function i(D,I){var W=D.sortIndex-I.sortIndex;return W!==0?W:D.id-I.id}if(typeof performance=="object"&&typeof performance.now=="function"){var a=performance;e.unstable_now=function(){return a.now()}}else{var o=Date,s=o.now();e.unstable_now=function(){return o.now()-s}}var l=[],c=[],u=1,d=null,h=3,m=!1,g=!1,v=!1,x=typeof setTimeout=="function"?setTimeout:null,w=typeof clearTimeout=="function"?clearTimeout:null,y=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function b(D){for(var I=r(c);I!==null;){if(I.callback===null)n(c);else if(I.startTime<=D)n(c),I.sortIndex=I.expirationTime,t(l,I);else break;I=r(c)}}function S(D){if(v=!1,b(D),!g)if(r(l)!==null)g=!0,F(P);else{var I=r(c);I!==null&&B(S,I.startTime-D)}}function P(D,I){g=!1,v&&(v=!1,w(C),C=-1),m=!0;var W=h;try{for(b(I),d=r(l);d!==null&&(!(d.expirationTime>I)||D&&!A());){var te=d.callback;if(typeof te=="function"){d.callback=null,h=d.priorityLevel;var Y=te(d.expirationTime<=I);I=e.unstable_now(),typeof Y=="function"?d.callback=Y:d===r(l)&&n(l),b(I)}else n(l);d=r(l)}if(d!==null)var Qt=!0;else{var Xe=r(c);Xe!==null&&B(S,Xe.startTime-I),Qt=!1}return Qt}finally{d=null,h=W,m=!1}}var j=!1,E=null,C=-1,N=5,k=-1;function A(){return!(e.unstable_now()-kD||125te?(D.sortIndex=W,t(c,D),r(l)===null&&D===r(c)&&(v?(w(C),C=-1):v=!0,B(S,W-te))):(D.sortIndex=Y,t(l,D),g||m||(g=!0,F(P))),D},e.unstable_shouldYield=A,e.unstable_wrapCallback=function(D){var I=h;return function(){var W=h;h=I;try{return D.apply(this,arguments)}finally{h=W}}}})(DE);_E.exports=DE;var cI=_E.exports;/** - * @license React - * react-dom.production.min.js - * - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */var uI=p,Sr=cI;function $(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,r=1;r"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),cv=Object.prototype.hasOwnProperty,dI=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,fb={},hb={};function fI(e){return cv.call(hb,e)?!0:cv.call(fb,e)?!1:dI.test(e)?hb[e]=!0:(fb[e]=!0,!1)}function hI(e,t,r,n){if(r!==null&&r.type===0)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return n?!1:r!==null?!r.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function pI(e,t,r,n){if(t===null||typeof t>"u"||hI(e,t,r,n))return!0;if(n)return!1;if(r!==null)switch(r.type){case 3:return!t;case 4:return t===!1;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}function Yt(e,t,r,n,i,a,o){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=n,this.attributeNamespace=i,this.mustUseProperty=r,this.propertyName=e,this.type=t,this.sanitizeURL=a,this.removeEmptyString=o}var kt={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){kt[e]=new Yt(e,0,!1,e,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];kt[t]=new Yt(t,1,!1,e[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(e){kt[e]=new Yt(e,2,!1,e.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){kt[e]=new Yt(e,2,!1,e,null,!1,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){kt[e]=new Yt(e,3,!1,e.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(e){kt[e]=new Yt(e,3,!0,e,null,!1,!1)});["capture","download"].forEach(function(e){kt[e]=new Yt(e,4,!1,e,null,!1,!1)});["cols","rows","size","span"].forEach(function(e){kt[e]=new Yt(e,6,!1,e,null,!1,!1)});["rowSpan","start"].forEach(function(e){kt[e]=new Yt(e,5,!1,e.toLowerCase(),null,!1,!1)});var Ty=/[\-:]([a-z])/g;function _y(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(Ty,_y);kt[t]=new Yt(t,1,!1,e,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(Ty,_y);kt[t]=new Yt(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(Ty,_y);kt[t]=new Yt(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(e){kt[e]=new Yt(e,1,!1,e.toLowerCase(),null,!1,!1)});kt.xlinkHref=new Yt("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(e){kt[e]=new Yt(e,1,!1,e.toLowerCase(),null,!0,!0)});function Dy(e,t,r,n){var i=kt.hasOwnProperty(t)?kt[t]:null;(i!==null?i.type!==0:n||!(2s||i[o]!==a[s]){var l=` -`+i[o].replace(" at new "," at ");return e.displayName&&l.includes("")&&(l=l.replace("",e.displayName)),l}while(1<=o&&0<=s);break}}}finally{Jp=!1,Error.prepareStackTrace=r}return(e=e?e.displayName||e.name:"")?_l(e):""}function mI(e){switch(e.tag){case 5:return _l(e.type);case 16:return _l("Lazy");case 13:return _l("Suspense");case 19:return _l("SuspenseList");case 0:case 2:case 15:return e=em(e.type,!1),e;case 11:return e=em(e.type.render,!1),e;case 1:return e=em(e.type,!0),e;default:return""}}function hv(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case Fo:return"Fragment";case $o:return"Portal";case uv:return"Profiler";case My:return"StrictMode";case dv:return"Suspense";case fv:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case IE:return(e.displayName||"Context")+".Consumer";case RE:return(e._context.displayName||"Context")+".Provider";case Ry:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case Iy:return t=e.displayName||null,t!==null?t:hv(e.type)||"Memo";case Ii:t=e._payload,e=e._init;try{return hv(e(t))}catch{}}return null}function vI(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=t.render,e=e.displayName||e.name||"",t.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return hv(t);case 8:return t===My?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t=="function")return t.displayName||t.name||null;if(typeof t=="string")return t}return null}function ua(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function $E(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function gI(e){var t=$E(e)?"checked":"value",r=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),n=""+e[t];if(!e.hasOwnProperty(t)&&typeof r<"u"&&typeof r.get=="function"&&typeof r.set=="function"){var i=r.get,a=r.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return i.call(this)},set:function(o){n=""+o,a.call(this,o)}}),Object.defineProperty(e,t,{enumerable:r.enumerable}),{getValue:function(){return n},setValue:function(o){n=""+o},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function Nu(e){e._valueTracker||(e._valueTracker=gI(e))}function FE(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var r=t.getValue(),n="";return e&&(n=$E(e)?e.checked?"true":"false":e.value),e=n,e!==r?(t.setValue(e),!0):!1}function Fd(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function pv(e,t){var r=t.checked;return qe({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:r??e._wrapperState.initialChecked})}function mb(e,t){var r=t.defaultValue==null?"":t.defaultValue,n=t.checked!=null?t.checked:t.defaultChecked;r=ua(t.value!=null?t.value:r),e._wrapperState={initialChecked:n,initialValue:r,controlled:t.type==="checkbox"||t.type==="radio"?t.checked!=null:t.value!=null}}function zE(e,t){t=t.checked,t!=null&&Dy(e,"checked",t,!1)}function mv(e,t){zE(e,t);var r=ua(t.value),n=t.type;if(r!=null)n==="number"?(r===0&&e.value===""||e.value!=r)&&(e.value=""+r):e.value!==""+r&&(e.value=""+r);else if(n==="submit"||n==="reset"){e.removeAttribute("value");return}t.hasOwnProperty("value")?vv(e,t.type,r):t.hasOwnProperty("defaultValue")&&vv(e,t.type,ua(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function vb(e,t,r){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var n=t.type;if(!(n!=="submit"&&n!=="reset"||t.value!==void 0&&t.value!==null))return;t=""+e._wrapperState.initialValue,r||t===e.value||(e.value=t),e.defaultValue=t}r=e.name,r!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,r!==""&&(e.name=r)}function vv(e,t,r){(t!=="number"||Fd(e.ownerDocument)!==e)&&(r==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+r&&(e.defaultValue=""+r))}var Dl=Array.isArray;function Zo(e,t,r,n){if(e=e.options,t){t={};for(var i=0;i"+t.valueOf().toString()+"",t=Au.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}});function Jl(e,t){if(t){var r=e.firstChild;if(r&&r===e.lastChild&&r.nodeType===3){r.nodeValue=t;return}}e.textContent=t}var zl={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},yI=["Webkit","ms","Moz","O"];Object.keys(zl).forEach(function(e){yI.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),zl[t]=zl[e]})});function qE(e,t,r){return t==null||typeof t=="boolean"||t===""?"":r||typeof t!="number"||t===0||zl.hasOwnProperty(e)&&zl[e]?(""+t).trim():t+"px"}function HE(e,t){e=e.style;for(var r in t)if(t.hasOwnProperty(r)){var n=r.indexOf("--")===0,i=qE(r,t[r],n);r==="float"&&(r="cssFloat"),n?e.setProperty(r,i):e[r]=i}}var xI=qe({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function xv(e,t){if(t){if(xI[e]&&(t.children!=null||t.dangerouslySetInnerHTML!=null))throw Error($(137,e));if(t.dangerouslySetInnerHTML!=null){if(t.children!=null)throw Error($(60));if(typeof t.dangerouslySetInnerHTML!="object"||!("__html"in t.dangerouslySetInnerHTML))throw Error($(61))}if(t.style!=null&&typeof t.style!="object")throw Error($(62))}}function wv(e,t){if(e.indexOf("-")===-1)return typeof t.is=="string";switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var bv=null;function Ly(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var Sv=null,Jo=null,es=null;function xb(e){if(e=qc(e)){if(typeof Sv!="function")throw Error($(280));var t=e.stateNode;t&&(t=vh(t),Sv(e.stateNode,e.type,t))}}function KE(e){Jo?es?es.push(e):es=[e]:Jo=e}function VE(){if(Jo){var e=Jo,t=es;if(es=Jo=null,xb(e),t)for(e=0;e>>=0,e===0?32:31-(AI(e)/TI|0)|0}var Tu=64,_u=4194304;function Ml(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return e&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function Ud(e,t){var r=e.pendingLanes;if(r===0)return 0;var n=0,i=e.suspendedLanes,a=e.pingedLanes,o=r&268435455;if(o!==0){var s=o&~i;s!==0?n=Ml(s):(a&=o,a!==0&&(n=Ml(a)))}else o=r&~i,o!==0?n=Ml(o):a!==0&&(n=Ml(a));if(n===0)return 0;if(t!==0&&t!==n&&!(t&i)&&(i=n&-n,a=t&-t,i>=a||i===16&&(a&4194240)!==0))return t;if(n&4&&(n|=r&16),t=e.entangledLanes,t!==0)for(e=e.entanglements,t&=n;0r;r++)t.push(e);return t}function Wc(e,t,r){e.pendingLanes|=t,t!==536870912&&(e.suspendedLanes=0,e.pingedLanes=0),e=e.eventTimes,t=31-an(t),e[t]=r}function RI(e,t){var r=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var n=e.eventTimes;for(e=e.expirationTimes;0=Wl),kb=" ",Nb=!1;function hC(e,t){switch(e){case"keyup":return cL.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function pC(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var zo=!1;function dL(e,t){switch(e){case"compositionend":return pC(t);case"keypress":return t.which!==32?null:(Nb=!0,kb);case"textInput":return e=t.data,e===kb&&Nb?null:e;default:return null}}function fL(e,t){if(zo)return e==="compositionend"||!Hy&&hC(e,t)?(e=dC(),wd=Wy=Xi=null,zo=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:r,offset:t-e};e=n}e:{for(;r;){if(r.nextSibling){r=r.nextSibling;break e}r=r.parentNode}r=void 0}r=Db(r)}}function yC(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?yC(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function xC(){for(var e=window,t=Fd();t instanceof e.HTMLIFrameElement;){try{var r=typeof t.contentWindow.location.href=="string"}catch{r=!1}if(r)e=t.contentWindow;else break;t=Fd(e.document)}return t}function Ky(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}function bL(e){var t=xC(),r=e.focusedElem,n=e.selectionRange;if(t!==r&&r&&r.ownerDocument&&yC(r.ownerDocument.documentElement,r)){if(n!==null&&Ky(r)){if(t=n.start,e=n.end,e===void 0&&(e=t),"selectionStart"in r)r.selectionStart=t,r.selectionEnd=Math.min(e,r.value.length);else if(e=(t=r.ownerDocument||document)&&t.defaultView||window,e.getSelection){e=e.getSelection();var i=r.textContent.length,a=Math.min(n.start,i);n=n.end===void 0?a:Math.min(n.end,i),!e.extend&&a>n&&(i=n,n=a,a=i),i=Mb(r,a);var o=Mb(r,n);i&&o&&(e.rangeCount!==1||e.anchorNode!==i.node||e.anchorOffset!==i.offset||e.focusNode!==o.node||e.focusOffset!==o.offset)&&(t=t.createRange(),t.setStart(i.node,i.offset),e.removeAllRanges(),a>n?(e.addRange(t),e.extend(o.node,o.offset)):(t.setEnd(o.node,o.offset),e.addRange(t)))}}for(t=[],e=r;e=e.parentNode;)e.nodeType===1&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(typeof r.focus=="function"&&r.focus(),r=0;r=document.documentMode,Bo=null,kv=null,ql=null,Nv=!1;function Rb(e,t,r){var n=r.window===r?r.document:r.nodeType===9?r:r.ownerDocument;Nv||Bo==null||Bo!==Fd(n)||(n=Bo,"selectionStart"in n&&Ky(n)?n={start:n.selectionStart,end:n.selectionEnd}:(n=(n.ownerDocument&&n.ownerDocument.defaultView||window).getSelection(),n={anchorNode:n.anchorNode,anchorOffset:n.anchorOffset,focusNode:n.focusNode,focusOffset:n.focusOffset}),ql&&ac(ql,n)||(ql=n,n=Kd(kv,"onSelect"),0qo||(e.current=Rv[qo],Rv[qo]=null,qo--)}function _e(e,t){qo++,Rv[qo]=e.current,e.current=t}var da={},It=ya(da),ar=ya(!1),io=da;function Ps(e,t){var r=e.type.contextTypes;if(!r)return da;var n=e.stateNode;if(n&&n.__reactInternalMemoizedUnmaskedChildContext===t)return n.__reactInternalMemoizedMaskedChildContext;var i={},a;for(a in r)i[a]=t[a];return n&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=i),i}function or(e){return e=e.childContextTypes,e!=null}function Yd(){Ie(ar),Ie(It)}function Wb(e,t,r){if(It.current!==da)throw Error($(168));_e(It,t),_e(ar,r)}function kC(e,t,r){var n=e.stateNode;if(t=t.childContextTypes,typeof n.getChildContext!="function")return r;n=n.getChildContext();for(var i in n)if(!(i in t))throw Error($(108,vI(e)||"Unknown",i));return qe({},r,n)}function Qd(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||da,io=It.current,_e(It,e),_e(ar,ar.current),!0}function Ub(e,t,r){var n=e.stateNode;if(!n)throw Error($(169));r?(e=kC(e,t,io),n.__reactInternalMemoizedMergedChildContext=e,Ie(ar),Ie(It),_e(It,e)):Ie(ar),_e(ar,r)}var Yn=null,gh=!1,pm=!1;function NC(e){Yn===null?Yn=[e]:Yn.push(e)}function DL(e){gh=!0,NC(e)}function xa(){if(!pm&&Yn!==null){pm=!0;var e=0,t=Pe;try{var r=Yn;for(Pe=1;e>=o,i-=o,Jn=1<<32-an(t)+i|r<C?(N=E,E=null):N=E.sibling;var k=h(w,E,b[C],S);if(k===null){E===null&&(E=N);break}e&&E&&k.alternate===null&&t(w,E),y=a(k,y,C),j===null?P=k:j.sibling=k,j=k,E=N}if(C===b.length)return r(w,E),$e&&Na(w,C),P;if(E===null){for(;CC?(N=E,E=null):N=E.sibling;var A=h(w,E,k.value,S);if(A===null){E===null&&(E=N);break}e&&E&&A.alternate===null&&t(w,E),y=a(A,y,C),j===null?P=A:j.sibling=A,j=A,E=N}if(k.done)return r(w,E),$e&&Na(w,C),P;if(E===null){for(;!k.done;C++,k=b.next())k=d(w,k.value,S),k!==null&&(y=a(k,y,C),j===null?P=k:j.sibling=k,j=k);return $e&&Na(w,C),P}for(E=n(w,E);!k.done;C++,k=b.next())k=m(E,w,C,k.value,S),k!==null&&(e&&k.alternate!==null&&E.delete(k.key===null?C:k.key),y=a(k,y,C),j===null?P=k:j.sibling=k,j=k);return e&&E.forEach(function(T){return t(w,T)}),$e&&Na(w,C),P}function x(w,y,b,S){if(typeof b=="object"&&b!==null&&b.type===Fo&&b.key===null&&(b=b.props.children),typeof b=="object"&&b!==null){switch(b.$$typeof){case ku:e:{for(var P=b.key,j=y;j!==null;){if(j.key===P){if(P=b.type,P===Fo){if(j.tag===7){r(w,j.sibling),y=i(j,b.props.children),y.return=w,w=y;break e}}else if(j.elementType===P||typeof P=="object"&&P!==null&&P.$$typeof===Ii&&Kb(P)===j.type){r(w,j.sibling),y=i(j,b.props),y.ref=vl(w,j,b),y.return=w,w=y;break e}r(w,j);break}else t(w,j);j=j.sibling}b.type===Fo?(y=Ja(b.props.children,w.mode,S,b.key),y.return=w,w=y):(S=kd(b.type,b.key,b.props,null,w.mode,S),S.ref=vl(w,y,b),S.return=w,w=S)}return o(w);case $o:e:{for(j=b.key;y!==null;){if(y.key===j)if(y.tag===4&&y.stateNode.containerInfo===b.containerInfo&&y.stateNode.implementation===b.implementation){r(w,y.sibling),y=i(y,b.children||[]),y.return=w,w=y;break e}else{r(w,y);break}else t(w,y);y=y.sibling}y=Sm(b,w.mode,S),y.return=w,w=y}return o(w);case Ii:return j=b._init,x(w,y,j(b._payload),S)}if(Dl(b))return g(w,y,b,S);if(dl(b))return v(w,y,b,S);Fu(w,b)}return typeof b=="string"&&b!==""||typeof b=="number"?(b=""+b,y!==null&&y.tag===6?(r(w,y.sibling),y=i(y,b),y.return=w,w=y):(r(w,y),y=bm(b,w.mode,S),y.return=w,w=y),o(w)):r(w,y)}return x}var Es=DC(!0),MC=DC(!1),Zd=ya(null),Jd=null,Vo=null,Gy=null;function Xy(){Gy=Vo=Jd=null}function Zy(e){var t=Zd.current;Ie(Zd),e._currentValue=t}function $v(e,t,r){for(;e!==null;){var n=e.alternate;if((e.childLanes&t)!==t?(e.childLanes|=t,n!==null&&(n.childLanes|=t)):n!==null&&(n.childLanes&t)!==t&&(n.childLanes|=t),e===r)break;e=e.return}}function rs(e,t){Jd=e,Gy=Vo=null,e=e.dependencies,e!==null&&e.firstContext!==null&&(e.lanes&t&&(rr=!0),e.firstContext=null)}function Fr(e){var t=e._currentValue;if(Gy!==e)if(e={context:e,memoizedValue:t,next:null},Vo===null){if(Jd===null)throw Error($(308));Vo=e,Jd.dependencies={lanes:0,firstContext:e}}else Vo=Vo.next=e;return t}var Ia=null;function Jy(e){Ia===null?Ia=[e]:Ia.push(e)}function RC(e,t,r,n){var i=t.interleaved;return i===null?(r.next=r,Jy(t)):(r.next=i.next,i.next=r),t.interleaved=r,fi(e,n)}function fi(e,t){e.lanes|=t;var r=e.alternate;for(r!==null&&(r.lanes|=t),r=e,e=e.return;e!==null;)e.childLanes|=t,r=e.alternate,r!==null&&(r.childLanes|=t),r=e,e=e.return;return r.tag===3?r.stateNode:null}var Li=!1;function ex(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function IC(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function ii(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function ia(e,t,r){var n=e.updateQueue;if(n===null)return null;if(n=n.shared,fe&2){var i=n.pending;return i===null?t.next=t:(t.next=i.next,i.next=t),n.pending=t,fi(e,r)}return i=n.interleaved,i===null?(t.next=t,Jy(n)):(t.next=i.next,i.next=t),n.interleaved=t,fi(e,r)}function Sd(e,t,r){if(t=t.updateQueue,t!==null&&(t=t.shared,(r&4194240)!==0)){var n=t.lanes;n&=e.pendingLanes,r|=n,t.lanes=r,Fy(e,r)}}function Vb(e,t){var r=e.updateQueue,n=e.alternate;if(n!==null&&(n=n.updateQueue,r===n)){var i=null,a=null;if(r=r.firstBaseUpdate,r!==null){do{var o={eventTime:r.eventTime,lane:r.lane,tag:r.tag,payload:r.payload,callback:r.callback,next:null};a===null?i=a=o:a=a.next=o,r=r.next}while(r!==null);a===null?i=a=t:a=a.next=t}else i=a=t;r={baseState:n.baseState,firstBaseUpdate:i,lastBaseUpdate:a,shared:n.shared,effects:n.effects},e.updateQueue=r;return}e=r.lastBaseUpdate,e===null?r.firstBaseUpdate=t:e.next=t,r.lastBaseUpdate=t}function ef(e,t,r,n){var i=e.updateQueue;Li=!1;var a=i.firstBaseUpdate,o=i.lastBaseUpdate,s=i.shared.pending;if(s!==null){i.shared.pending=null;var l=s,c=l.next;l.next=null,o===null?a=c:o.next=c,o=l;var u=e.alternate;u!==null&&(u=u.updateQueue,s=u.lastBaseUpdate,s!==o&&(s===null?u.firstBaseUpdate=c:s.next=c,u.lastBaseUpdate=l))}if(a!==null){var d=i.baseState;o=0,u=c=l=null,s=a;do{var h=s.lane,m=s.eventTime;if((n&h)===h){u!==null&&(u=u.next={eventTime:m,lane:0,tag:s.tag,payload:s.payload,callback:s.callback,next:null});e:{var g=e,v=s;switch(h=t,m=r,v.tag){case 1:if(g=v.payload,typeof g=="function"){d=g.call(m,d,h);break e}d=g;break e;case 3:g.flags=g.flags&-65537|128;case 0:if(g=v.payload,h=typeof g=="function"?g.call(m,d,h):g,h==null)break e;d=qe({},d,h);break e;case 2:Li=!0}}s.callback!==null&&s.lane!==0&&(e.flags|=64,h=i.effects,h===null?i.effects=[s]:h.push(s))}else m={eventTime:m,lane:h,tag:s.tag,payload:s.payload,callback:s.callback,next:null},u===null?(c=u=m,l=d):u=u.next=m,o|=h;if(s=s.next,s===null){if(s=i.shared.pending,s===null)break;h=s,s=h.next,h.next=null,i.lastBaseUpdate=h,i.shared.pending=null}}while(!0);if(u===null&&(l=d),i.baseState=l,i.firstBaseUpdate=c,i.lastBaseUpdate=u,t=i.shared.interleaved,t!==null){i=t;do o|=i.lane,i=i.next;while(i!==t)}else a===null&&(i.shared.lanes=0);so|=o,e.lanes=o,e.memoizedState=d}}function Yb(e,t,r){if(e=t.effects,t.effects=null,e!==null)for(t=0;tr?r:4,e(!0);var n=vm.transition;vm.transition={};try{e(!1),t()}finally{Pe=r,vm.transition=n}}function JC(){return zr().memoizedState}function LL(e,t,r){var n=oa(e);if(r={lane:n,action:r,hasEagerState:!1,eagerState:null,next:null},eO(e))tO(t,r);else if(r=RC(e,t,r,n),r!==null){var i=Kt();on(r,e,n,i),rO(r,t,n)}}function $L(e,t,r){var n=oa(e),i={lane:n,action:r,hasEagerState:!1,eagerState:null,next:null};if(eO(e))tO(t,i);else{var a=e.alternate;if(e.lanes===0&&(a===null||a.lanes===0)&&(a=t.lastRenderedReducer,a!==null))try{var o=t.lastRenderedState,s=a(o,r);if(i.hasEagerState=!0,i.eagerState=s,sn(s,o)){var l=t.interleaved;l===null?(i.next=i,Jy(t)):(i.next=l.next,l.next=i),t.interleaved=i;return}}catch{}finally{}r=RC(e,t,i,n),r!==null&&(i=Kt(),on(r,e,n,i),rO(r,t,n))}}function eO(e){var t=e.alternate;return e===Ue||t!==null&&t===Ue}function tO(e,t){Hl=rf=!0;var r=e.pending;r===null?t.next=t:(t.next=r.next,r.next=t),e.pending=t}function rO(e,t,r){if(r&4194240){var n=t.lanes;n&=e.pendingLanes,r|=n,t.lanes=r,Fy(e,r)}}var nf={readContext:Fr,useCallback:Tt,useContext:Tt,useEffect:Tt,useImperativeHandle:Tt,useInsertionEffect:Tt,useLayoutEffect:Tt,useMemo:Tt,useReducer:Tt,useRef:Tt,useState:Tt,useDebugValue:Tt,useDeferredValue:Tt,useTransition:Tt,useMutableSource:Tt,useSyncExternalStore:Tt,useId:Tt,unstable_isNewReconciler:!1},FL={readContext:Fr,useCallback:function(e,t){return xn().memoizedState=[e,t===void 0?null:t],e},useContext:Fr,useEffect:Gb,useImperativeHandle:function(e,t,r){return r=r!=null?r.concat([e]):null,jd(4194308,4,YC.bind(null,t,e),r)},useLayoutEffect:function(e,t){return jd(4194308,4,e,t)},useInsertionEffect:function(e,t){return jd(4,2,e,t)},useMemo:function(e,t){var r=xn();return t=t===void 0?null:t,e=e(),r.memoizedState=[e,t],e},useReducer:function(e,t,r){var n=xn();return t=r!==void 0?r(t):t,n.memoizedState=n.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},n.queue=e,e=e.dispatch=LL.bind(null,Ue,e),[n.memoizedState,e]},useRef:function(e){var t=xn();return e={current:e},t.memoizedState=e},useState:Qb,useDebugValue:lx,useDeferredValue:function(e){return xn().memoizedState=e},useTransition:function(){var e=Qb(!1),t=e[0];return e=IL.bind(null,e[1]),xn().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,r){var n=Ue,i=xn();if($e){if(r===void 0)throw Error($(407));r=r()}else{if(r=t(),vt===null)throw Error($(349));oo&30||zC(n,t,r)}i.memoizedState=r;var a={value:r,getSnapshot:t};return i.queue=a,Gb(WC.bind(null,n,a,e),[e]),n.flags|=2048,hc(9,BC.bind(null,n,a,r,t),void 0,null),r},useId:function(){var e=xn(),t=vt.identifierPrefix;if($e){var r=ei,n=Jn;r=(n&~(1<<32-an(n)-1)).toString(32)+r,t=":"+t+"R"+r,r=dc++,0<\/script>",e=e.removeChild(e.firstChild)):typeof n.is=="string"?e=o.createElement(r,{is:n.is}):(e=o.createElement(r),r==="select"&&(o=e,n.multiple?o.multiple=!0:n.size&&(o.size=n.size))):e=o.createElementNS(e,r),e[Pn]=t,e[lc]=n,fO(e,t,!1,!1),t.stateNode=e;e:{switch(o=wv(r,n),r){case"dialog":Me("cancel",e),Me("close",e),i=n;break;case"iframe":case"object":case"embed":Me("load",e),i=n;break;case"video":case"audio":for(i=0;iks&&(t.flags|=128,n=!0,gl(a,!1),t.lanes=4194304)}else{if(!n)if(e=tf(o),e!==null){if(t.flags|=128,n=!0,r=e.updateQueue,r!==null&&(t.updateQueue=r,t.flags|=4),gl(a,!0),a.tail===null&&a.tailMode==="hidden"&&!o.alternate&&!$e)return _t(t),null}else 2*Qe()-a.renderingStartTime>ks&&r!==1073741824&&(t.flags|=128,n=!0,gl(a,!1),t.lanes=4194304);a.isBackwards?(o.sibling=t.child,t.child=o):(r=a.last,r!==null?r.sibling=o:t.child=o,a.last=o)}return a.tail!==null?(t=a.tail,a.rendering=t,a.tail=t.sibling,a.renderingStartTime=Qe(),t.sibling=null,r=We.current,_e(We,n?r&1|2:r&1),t):(_t(t),null);case 22:case 23:return px(),n=t.memoizedState!==null,e!==null&&e.memoizedState!==null!==n&&(t.flags|=8192),n&&t.mode&1?hr&1073741824&&(_t(t),t.subtreeFlags&6&&(t.flags|=8192)):_t(t),null;case 24:return null;case 25:return null}throw Error($(156,t.tag))}function VL(e,t){switch(Yy(t),t.tag){case 1:return or(t.type)&&Yd(),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return Cs(),Ie(ar),Ie(It),nx(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 5:return rx(t),null;case 13:if(Ie(We),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error($(340));js()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return Ie(We),null;case 4:return Cs(),null;case 10:return Zy(t.type._context),null;case 22:case 23:return px(),null;case 24:return null;default:return null}}var Bu=!1,Mt=!1,YL=typeof WeakSet=="function"?WeakSet:Set,H=null;function Yo(e,t){var r=e.ref;if(r!==null)if(typeof r=="function")try{r(null)}catch(n){Ve(e,t,n)}else r.current=null}function Vv(e,t,r){try{r()}catch(n){Ve(e,t,n)}}var s1=!1;function QL(e,t){if(Av=qd,e=xC(),Ky(e)){if("selectionStart"in e)var r={start:e.selectionStart,end:e.selectionEnd};else e:{r=(r=e.ownerDocument)&&r.defaultView||window;var n=r.getSelection&&r.getSelection();if(n&&n.rangeCount!==0){r=n.anchorNode;var i=n.anchorOffset,a=n.focusNode;n=n.focusOffset;try{r.nodeType,a.nodeType}catch{r=null;break e}var o=0,s=-1,l=-1,c=0,u=0,d=e,h=null;t:for(;;){for(var m;d!==r||i!==0&&d.nodeType!==3||(s=o+i),d!==a||n!==0&&d.nodeType!==3||(l=o+n),d.nodeType===3&&(o+=d.nodeValue.length),(m=d.firstChild)!==null;)h=d,d=m;for(;;){if(d===e)break t;if(h===r&&++c===i&&(s=o),h===a&&++u===n&&(l=o),(m=d.nextSibling)!==null)break;d=h,h=d.parentNode}d=m}r=s===-1||l===-1?null:{start:s,end:l}}else r=null}r=r||{start:0,end:0}}else r=null;for(Tv={focusedElem:e,selectionRange:r},qd=!1,H=t;H!==null;)if(t=H,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,H=e;else for(;H!==null;){t=H;try{var g=t.alternate;if(t.flags&1024)switch(t.tag){case 0:case 11:case 15:break;case 1:if(g!==null){var v=g.memoizedProps,x=g.memoizedState,w=t.stateNode,y=w.getSnapshotBeforeUpdate(t.elementType===t.type?v:Yr(t.type,v),x);w.__reactInternalSnapshotBeforeUpdate=y}break;case 3:var b=t.stateNode.containerInfo;b.nodeType===1?b.textContent="":b.nodeType===9&&b.documentElement&&b.removeChild(b.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error($(163))}}catch(S){Ve(t,t.return,S)}if(e=t.sibling,e!==null){e.return=t.return,H=e;break}H=t.return}return g=s1,s1=!1,g}function Kl(e,t,r){var n=t.updateQueue;if(n=n!==null?n.lastEffect:null,n!==null){var i=n=n.next;do{if((i.tag&e)===e){var a=i.destroy;i.destroy=void 0,a!==void 0&&Vv(t,r,a)}i=i.next}while(i!==n)}}function wh(e,t){if(t=t.updateQueue,t=t!==null?t.lastEffect:null,t!==null){var r=t=t.next;do{if((r.tag&e)===e){var n=r.create;r.destroy=n()}r=r.next}while(r!==t)}}function Yv(e){var t=e.ref;if(t!==null){var r=e.stateNode;switch(e.tag){case 5:e=r;break;default:e=r}typeof t=="function"?t(e):t.current=e}}function mO(e){var t=e.alternate;t!==null&&(e.alternate=null,mO(t)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(t=e.stateNode,t!==null&&(delete t[Pn],delete t[lc],delete t[Mv],delete t[TL],delete t[_L])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function vO(e){return e.tag===5||e.tag===3||e.tag===4}function l1(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||vO(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Qv(e,t,r){var n=e.tag;if(n===5||n===6)e=e.stateNode,t?r.nodeType===8?r.parentNode.insertBefore(e,t):r.insertBefore(e,t):(r.nodeType===8?(t=r.parentNode,t.insertBefore(e,r)):(t=r,t.appendChild(e)),r=r._reactRootContainer,r!=null||t.onclick!==null||(t.onclick=Vd));else if(n!==4&&(e=e.child,e!==null))for(Qv(e,t,r),e=e.sibling;e!==null;)Qv(e,t,r),e=e.sibling}function Gv(e,t,r){var n=e.tag;if(n===5||n===6)e=e.stateNode,t?r.insertBefore(e,t):r.appendChild(e);else if(n!==4&&(e=e.child,e!==null))for(Gv(e,t,r),e=e.sibling;e!==null;)Gv(e,t,r),e=e.sibling}var Pt=null,Xr=!1;function Ai(e,t,r){for(r=r.child;r!==null;)gO(e,t,r),r=r.sibling}function gO(e,t,r){if(On&&typeof On.onCommitFiberUnmount=="function")try{On.onCommitFiberUnmount(fh,r)}catch{}switch(r.tag){case 5:Mt||Yo(r,t);case 6:var n=Pt,i=Xr;Pt=null,Ai(e,t,r),Pt=n,Xr=i,Pt!==null&&(Xr?(e=Pt,r=r.stateNode,e.nodeType===8?e.parentNode.removeChild(r):e.removeChild(r)):Pt.removeChild(r.stateNode));break;case 18:Pt!==null&&(Xr?(e=Pt,r=r.stateNode,e.nodeType===8?hm(e.parentNode,r):e.nodeType===1&&hm(e,r),nc(e)):hm(Pt,r.stateNode));break;case 4:n=Pt,i=Xr,Pt=r.stateNode.containerInfo,Xr=!0,Ai(e,t,r),Pt=n,Xr=i;break;case 0:case 11:case 14:case 15:if(!Mt&&(n=r.updateQueue,n!==null&&(n=n.lastEffect,n!==null))){i=n=n.next;do{var a=i,o=a.destroy;a=a.tag,o!==void 0&&(a&2||a&4)&&Vv(r,t,o),i=i.next}while(i!==n)}Ai(e,t,r);break;case 1:if(!Mt&&(Yo(r,t),n=r.stateNode,typeof n.componentWillUnmount=="function"))try{n.props=r.memoizedProps,n.state=r.memoizedState,n.componentWillUnmount()}catch(s){Ve(r,t,s)}Ai(e,t,r);break;case 21:Ai(e,t,r);break;case 22:r.mode&1?(Mt=(n=Mt)||r.memoizedState!==null,Ai(e,t,r),Mt=n):Ai(e,t,r);break;default:Ai(e,t,r)}}function c1(e){var t=e.updateQueue;if(t!==null){e.updateQueue=null;var r=e.stateNode;r===null&&(r=e.stateNode=new YL),t.forEach(function(n){var i=i$.bind(null,e,n);r.has(n)||(r.add(n),n.then(i,i))})}}function Kr(e,t){var r=t.deletions;if(r!==null)for(var n=0;ni&&(i=o),n&=~a}if(n=i,n=Qe()-n,n=(120>n?120:480>n?480:1080>n?1080:1920>n?1920:3e3>n?3e3:4320>n?4320:1960*XL(n/1960))-n,10e?16:e,Zi===null)var n=!1;else{if(e=Zi,Zi=null,sf=0,fe&6)throw Error($(331));var i=fe;for(fe|=4,H=e.current;H!==null;){var a=H,o=a.child;if(H.flags&16){var s=a.deletions;if(s!==null){for(var l=0;lQe()-fx?Za(e,0):dx|=r),sr(e,t)}function EO(e,t){t===0&&(e.mode&1?(t=_u,_u<<=1,!(_u&130023424)&&(_u=4194304)):t=1);var r=Kt();e=fi(e,t),e!==null&&(Wc(e,t,r),sr(e,r))}function n$(e){var t=e.memoizedState,r=0;t!==null&&(r=t.retryLane),EO(e,r)}function i$(e,t){var r=0;switch(e.tag){case 13:var n=e.stateNode,i=e.memoizedState;i!==null&&(r=i.retryLane);break;case 19:n=e.stateNode;break;default:throw Error($(314))}n!==null&&n.delete(t),EO(e,r)}var CO;CO=function(e,t,r){if(e!==null)if(e.memoizedProps!==t.pendingProps||ar.current)rr=!0;else{if(!(e.lanes&r)&&!(t.flags&128))return rr=!1,HL(e,t,r);rr=!!(e.flags&131072)}else rr=!1,$e&&t.flags&1048576&&AC(t,Xd,t.index);switch(t.lanes=0,t.tag){case 2:var n=t.type;Ed(e,t),e=t.pendingProps;var i=Ps(t,It.current);rs(t,r),i=ax(null,t,n,e,i,r);var a=ox();return t.flags|=1,typeof i=="object"&&i!==null&&typeof i.render=="function"&&i.$$typeof===void 0?(t.tag=1,t.memoizedState=null,t.updateQueue=null,or(n)?(a=!0,Qd(t)):a=!1,t.memoizedState=i.state!==null&&i.state!==void 0?i.state:null,ex(t),i.updater=xh,t.stateNode=i,i._reactInternals=t,zv(t,n,e,r),t=Uv(null,t,n,!0,a,r)):(t.tag=0,$e&&a&&Vy(t),Wt(null,t,i,r),t=t.child),t;case 16:n=t.elementType;e:{switch(Ed(e,t),e=t.pendingProps,i=n._init,n=i(n._payload),t.type=n,i=t.tag=o$(n),e=Yr(n,e),i){case 0:t=Wv(null,t,n,e,r);break e;case 1:t=i1(null,t,n,e,r);break e;case 11:t=r1(null,t,n,e,r);break e;case 14:t=n1(null,t,n,Yr(n.type,e),r);break e}throw Error($(306,n,""))}return t;case 0:return n=t.type,i=t.pendingProps,i=t.elementType===n?i:Yr(n,i),Wv(e,t,n,i,r);case 1:return n=t.type,i=t.pendingProps,i=t.elementType===n?i:Yr(n,i),i1(e,t,n,i,r);case 3:e:{if(cO(t),e===null)throw Error($(387));n=t.pendingProps,a=t.memoizedState,i=a.element,IC(e,t),ef(t,n,null,r);var o=t.memoizedState;if(n=o.element,a.isDehydrated)if(a={element:n,isDehydrated:!1,cache:o.cache,pendingSuspenseBoundaries:o.pendingSuspenseBoundaries,transitions:o.transitions},t.updateQueue.baseState=a,t.memoizedState=a,t.flags&256){i=Os(Error($(423)),t),t=a1(e,t,n,r,i);break e}else if(n!==i){i=Os(Error($(424)),t),t=a1(e,t,n,r,i);break e}else for(yr=na(t.stateNode.containerInfo.firstChild),xr=t,$e=!0,Jr=null,r=MC(t,null,n,r),t.child=r;r;)r.flags=r.flags&-3|4096,r=r.sibling;else{if(js(),n===i){t=hi(e,t,r);break e}Wt(e,t,n,r)}t=t.child}return t;case 5:return LC(t),e===null&&Lv(t),n=t.type,i=t.pendingProps,a=e!==null?e.memoizedProps:null,o=i.children,_v(n,i)?o=null:a!==null&&_v(n,a)&&(t.flags|=32),lO(e,t),Wt(e,t,o,r),t.child;case 6:return e===null&&Lv(t),null;case 13:return uO(e,t,r);case 4:return tx(t,t.stateNode.containerInfo),n=t.pendingProps,e===null?t.child=Es(t,null,n,r):Wt(e,t,n,r),t.child;case 11:return n=t.type,i=t.pendingProps,i=t.elementType===n?i:Yr(n,i),r1(e,t,n,i,r);case 7:return Wt(e,t,t.pendingProps,r),t.child;case 8:return Wt(e,t,t.pendingProps.children,r),t.child;case 12:return Wt(e,t,t.pendingProps.children,r),t.child;case 10:e:{if(n=t.type._context,i=t.pendingProps,a=t.memoizedProps,o=i.value,_e(Zd,n._currentValue),n._currentValue=o,a!==null)if(sn(a.value,o)){if(a.children===i.children&&!ar.current){t=hi(e,t,r);break e}}else for(a=t.child,a!==null&&(a.return=t);a!==null;){var s=a.dependencies;if(s!==null){o=a.child;for(var l=s.firstContext;l!==null;){if(l.context===n){if(a.tag===1){l=ii(-1,r&-r),l.tag=2;var c=a.updateQueue;if(c!==null){c=c.shared;var u=c.pending;u===null?l.next=l:(l.next=u.next,u.next=l),c.pending=l}}a.lanes|=r,l=a.alternate,l!==null&&(l.lanes|=r),$v(a.return,r,t),s.lanes|=r;break}l=l.next}}else if(a.tag===10)o=a.type===t.type?null:a.child;else if(a.tag===18){if(o=a.return,o===null)throw Error($(341));o.lanes|=r,s=o.alternate,s!==null&&(s.lanes|=r),$v(o,r,t),o=a.sibling}else o=a.child;if(o!==null)o.return=a;else for(o=a;o!==null;){if(o===t){o=null;break}if(a=o.sibling,a!==null){a.return=o.return,o=a;break}o=o.return}a=o}Wt(e,t,i.children,r),t=t.child}return t;case 9:return i=t.type,n=t.pendingProps.children,rs(t,r),i=Fr(i),n=n(i),t.flags|=1,Wt(e,t,n,r),t.child;case 14:return n=t.type,i=Yr(n,t.pendingProps),i=Yr(n.type,i),n1(e,t,n,i,r);case 15:return oO(e,t,t.type,t.pendingProps,r);case 17:return n=t.type,i=t.pendingProps,i=t.elementType===n?i:Yr(n,i),Ed(e,t),t.tag=1,or(n)?(e=!0,Qd(t)):e=!1,rs(t,r),nO(t,n,i),zv(t,n,i,r),Uv(null,t,n,!0,e,r);case 19:return dO(e,t,r);case 22:return sO(e,t,r)}throw Error($(156,t.tag))};function OO(e,t){return eC(e,t)}function a$(e,t,r,n){this.tag=e,this.key=r,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=n,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function Ir(e,t,r,n){return new a$(e,t,r,n)}function vx(e){return e=e.prototype,!(!e||!e.isReactComponent)}function o$(e){if(typeof e=="function")return vx(e)?1:0;if(e!=null){if(e=e.$$typeof,e===Ry)return 11;if(e===Iy)return 14}return 2}function sa(e,t){var r=e.alternate;return r===null?(r=Ir(e.tag,t,e.key,e.mode),r.elementType=e.elementType,r.type=e.type,r.stateNode=e.stateNode,r.alternate=e,e.alternate=r):(r.pendingProps=t,r.type=e.type,r.flags=0,r.subtreeFlags=0,r.deletions=null),r.flags=e.flags&14680064,r.childLanes=e.childLanes,r.lanes=e.lanes,r.child=e.child,r.memoizedProps=e.memoizedProps,r.memoizedState=e.memoizedState,r.updateQueue=e.updateQueue,t=e.dependencies,r.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext},r.sibling=e.sibling,r.index=e.index,r.ref=e.ref,r}function kd(e,t,r,n,i,a){var o=2;if(n=e,typeof e=="function")vx(e)&&(o=1);else if(typeof e=="string")o=5;else e:switch(e){case Fo:return Ja(r.children,i,a,t);case My:o=8,i|=8;break;case uv:return e=Ir(12,r,t,i|2),e.elementType=uv,e.lanes=a,e;case dv:return e=Ir(13,r,t,i),e.elementType=dv,e.lanes=a,e;case fv:return e=Ir(19,r,t,i),e.elementType=fv,e.lanes=a,e;case LE:return Sh(r,i,a,t);default:if(typeof e=="object"&&e!==null)switch(e.$$typeof){case RE:o=10;break e;case IE:o=9;break e;case Ry:o=11;break e;case Iy:o=14;break e;case Ii:o=16,n=null;break e}throw Error($(130,e==null?e:typeof e,""))}return t=Ir(o,r,t,i),t.elementType=e,t.type=n,t.lanes=a,t}function Ja(e,t,r,n){return e=Ir(7,e,n,t),e.lanes=r,e}function Sh(e,t,r,n){return e=Ir(22,e,n,t),e.elementType=LE,e.lanes=r,e.stateNode={isHidden:!1},e}function bm(e,t,r){return e=Ir(6,e,null,t),e.lanes=r,e}function Sm(e,t,r){return t=Ir(4,e.children!==null?e.children:[],e.key,t),t.lanes=r,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function s$(e,t,r,n,i){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=rm(0),this.expirationTimes=rm(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=rm(0),this.identifierPrefix=n,this.onRecoverableError=i,this.mutableSourceEagerHydrationData=null}function gx(e,t,r,n,i,a,o,s,l){return e=new s$(e,t,r,s,l),t===1?(t=1,a===!0&&(t|=8)):t=0,a=Ir(3,null,null,t),e.current=a,a.stateNode=e,a.memoizedState={element:n,isDehydrated:r,cache:null,transitions:null,pendingSuspenseBoundaries:null},ex(a),e}function l$(e,t,r){var n=3"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(TO)}catch(e){console.error(e)}}TO(),TE.exports=jr;var wa=TE.exports;const h$=In(wa);var g1=wa;lv.createRoot=g1.createRoot,lv.hydrateRoot=g1.hydrateRoot;var Kc=class{constructor(){this.listeners=new Set,this.subscribe=this.subscribe.bind(this)}subscribe(e){return this.listeners.add(e),this.onSubscribe(),()=>{this.listeners.delete(e),this.onUnsubscribe()}}hasListeners(){return this.listeners.size>0}onSubscribe(){}onUnsubscribe(){}},p$={setTimeout:(e,t)=>setTimeout(e,t),clearTimeout:e=>clearTimeout(e),setInterval:(e,t)=>setInterval(e,t),clearInterval:e=>clearInterval(e)},Ui,Ey,uE,m$=(uE=class{constructor(){ee(this,Ui,p$);ee(this,Ey,!1)}setTimeoutProvider(e){U(this,Ui,e)}setTimeout(e,t){return O(this,Ui).setTimeout(e,t)}clearTimeout(e){O(this,Ui).clearTimeout(e)}setInterval(e,t){return O(this,Ui).setInterval(e,t)}clearInterval(e){O(this,Ui).clearInterval(e)}},Ui=new WeakMap,Ey=new WeakMap,uE),$a=new m$;function v$(e){setTimeout(e,0)}var co=typeof window>"u"||"Deno"in globalThis;function Zt(){}function g$(e,t){return typeof e=="function"?e(t):e}function tg(e){return typeof e=="number"&&e>=0&&e!==1/0}function _O(e,t){return Math.max(e+(t||0)-Date.now(),0)}function la(e,t){return typeof e=="function"?e(t):e}function _r(e,t){return typeof e=="function"?e(t):e}function y1(e,t){const{type:r="all",exact:n,fetchStatus:i,predicate:a,queryKey:o,stale:s}=e;if(o){if(n){if(t.queryHash!==bx(o,t.options))return!1}else if(!vc(t.queryKey,o))return!1}if(r!=="all"){const l=t.isActive();if(r==="active"&&!l||r==="inactive"&&l)return!1}return!(typeof s=="boolean"&&t.isStale()!==s||i&&i!==t.state.fetchStatus||a&&!a(t))}function x1(e,t){const{exact:r,status:n,predicate:i,mutationKey:a}=e;if(a){if(!t.options.mutationKey)return!1;if(r){if(mc(t.options.mutationKey)!==mc(a))return!1}else if(!vc(t.options.mutationKey,a))return!1}return!(n&&t.state.status!==n||i&&!i(t))}function bx(e,t){return((t==null?void 0:t.queryKeyHashFn)||mc)(e)}function mc(e){return JSON.stringify(e,(t,r)=>ng(r)?Object.keys(r).sort().reduce((n,i)=>(n[i]=r[i],n),{}):r)}function vc(e,t){return e===t?!0:typeof e!=typeof t?!1:e&&t&&typeof e=="object"&&typeof t=="object"?Object.keys(t).every(r=>vc(e[r],t[r])):!1}var y$=Object.prototype.hasOwnProperty;function DO(e,t){if(e===t)return e;const r=w1(e)&&w1(t);if(!r&&!(ng(e)&&ng(t)))return t;const i=(r?e:Object.keys(e)).length,a=r?t:Object.keys(t),o=a.length,s=r?new Array(o):{};let l=0;for(let c=0;c{$a.setTimeout(t,e)})}function ig(e,t,r){return typeof r.structuralSharing=="function"?r.structuralSharing(e,t):r.structuralSharing!==!1?DO(e,t):t}function w$(e,t,r=0){const n=[...e,t];return r&&n.length>r?n.slice(1):n}function b$(e,t,r=0){const n=[t,...e];return r&&n.length>r?n.slice(0,-1):n}var Sx=Symbol();function MO(e,t){return!e.queryFn&&(t!=null&&t.initialPromise)?()=>t.initialPromise:!e.queryFn||e.queryFn===Sx?()=>Promise.reject(new Error(`Missing queryFn: '${e.queryHash}'`)):e.queryFn}function S$(e,t){return typeof e=="function"?e(...t):!!e}var Ua,qi,us,dE,P$=(dE=class extends Kc{constructor(){super();ee(this,Ua);ee(this,qi);ee(this,us);U(this,us,t=>{if(!co&&window.addEventListener){const r=()=>t();return window.addEventListener("visibilitychange",r,!1),()=>{window.removeEventListener("visibilitychange",r)}}})}onSubscribe(){O(this,qi)||this.setEventListener(O(this,us))}onUnsubscribe(){var t;this.hasListeners()||((t=O(this,qi))==null||t.call(this),U(this,qi,void 0))}setEventListener(t){var r;U(this,us,t),(r=O(this,qi))==null||r.call(this),U(this,qi,t(n=>{typeof n=="boolean"?this.setFocused(n):this.onFocus()}))}setFocused(t){O(this,Ua)!==t&&(U(this,Ua,t),this.onFocus())}onFocus(){const t=this.isFocused();this.listeners.forEach(r=>{r(t)})}isFocused(){var t;return typeof O(this,Ua)=="boolean"?O(this,Ua):((t=globalThis.document)==null?void 0:t.visibilityState)!=="hidden"}},Ua=new WeakMap,qi=new WeakMap,us=new WeakMap,dE),Px=new P$;function ag(){let e,t;const r=new Promise((i,a)=>{e=i,t=a});r.status="pending",r.catch(()=>{});function n(i){Object.assign(r,i),delete r.resolve,delete r.reject}return r.resolve=i=>{n({status:"fulfilled",value:i}),e(i)},r.reject=i=>{n({status:"rejected",reason:i}),t(i)},r}var j$=v$;function E$(){let e=[],t=0,r=s=>{s()},n=s=>{s()},i=j$;const a=s=>{t?e.push(s):i(()=>{r(s)})},o=()=>{const s=e;e=[],s.length&&i(()=>{n(()=>{s.forEach(l=>{r(l)})})})};return{batch:s=>{let l;t++;try{l=s()}finally{t--,t||o()}return l},batchCalls:s=>(...l)=>{a(()=>{s(...l)})},schedule:a,setNotifyFunction:s=>{r=s},setBatchNotifyFunction:s=>{n=s},setScheduler:s=>{i=s}}}var Et=E$(),ds,Hi,fs,fE,C$=(fE=class extends Kc{constructor(){super();ee(this,ds,!0);ee(this,Hi);ee(this,fs);U(this,fs,t=>{if(!co&&window.addEventListener){const r=()=>t(!0),n=()=>t(!1);return window.addEventListener("online",r,!1),window.addEventListener("offline",n,!1),()=>{window.removeEventListener("online",r),window.removeEventListener("offline",n)}}})}onSubscribe(){O(this,Hi)||this.setEventListener(O(this,fs))}onUnsubscribe(){var t;this.hasListeners()||((t=O(this,Hi))==null||t.call(this),U(this,Hi,void 0))}setEventListener(t){var r;U(this,fs,t),(r=O(this,Hi))==null||r.call(this),U(this,Hi,t(this.setOnline.bind(this)))}setOnline(t){O(this,ds)!==t&&(U(this,ds,t),this.listeners.forEach(n=>{n(t)}))}isOnline(){return O(this,ds)}},ds=new WeakMap,Hi=new WeakMap,fs=new WeakMap,fE),uf=new C$;function O$(e){return Math.min(1e3*2**e,3e4)}function RO(e){return(e??"online")==="online"?uf.isOnline():!0}var og=class extends Error{constructor(e){super("CancelledError"),this.revert=e==null?void 0:e.revert,this.silent=e==null?void 0:e.silent}};function IO(e){let t=!1,r=0,n;const i=ag(),a=()=>i.status!=="pending",o=v=>{var x;if(!a()){const w=new og(v);h(w),(x=e.onCancel)==null||x.call(e,w)}},s=()=>{t=!0},l=()=>{t=!1},c=()=>Px.isFocused()&&(e.networkMode==="always"||uf.isOnline())&&e.canRun(),u=()=>RO(e.networkMode)&&e.canRun(),d=v=>{a()||(n==null||n(),i.resolve(v))},h=v=>{a()||(n==null||n(),i.reject(v))},m=()=>new Promise(v=>{var x;n=w=>{(a()||c())&&v(w)},(x=e.onPause)==null||x.call(e)}).then(()=>{var v;n=void 0,a()||(v=e.onContinue)==null||v.call(e)}),g=()=>{if(a())return;let v;const x=r===0?e.initialPromise:void 0;try{v=x??e.fn()}catch(w){v=Promise.reject(w)}Promise.resolve(v).then(d).catch(w=>{var j;if(a())return;const y=e.retry??(co?0:3),b=e.retryDelay??O$,S=typeof b=="function"?b(r,w):b,P=y===!0||typeof y=="number"&&rc()?void 0:m()).then(()=>{t?h(w):g()})})};return{promise:i,status:()=>i.status,cancel:o,continue:()=>(n==null||n(),i),cancelRetry:s,continueRetry:l,canStart:u,start:()=>(u()?g():m().then(g),i)}}var qa,hE,LO=(hE=class{constructor(){ee(this,qa)}destroy(){this.clearGcTimeout()}scheduleGc(){this.clearGcTimeout(),tg(this.gcTime)&&U(this,qa,$a.setTimeout(()=>{this.optionalRemove()},this.gcTime))}updateGcTime(e){this.gcTime=Math.max(this.gcTime||0,e??(co?1/0:5*60*1e3))}clearGcTimeout(){O(this,qa)&&($a.clearTimeout(O(this,qa)),U(this,qa,void 0))}},qa=new WeakMap,hE),Ha,hs,Tr,Ka,dt,Ic,Va,Qr,qn,pE,k$=(pE=class extends LO{constructor(t){super();ee(this,Qr);ee(this,Ha);ee(this,hs);ee(this,Tr);ee(this,Ka);ee(this,dt);ee(this,Ic);ee(this,Va);U(this,Va,!1),U(this,Ic,t.defaultOptions),this.setOptions(t.options),this.observers=[],U(this,Ka,t.client),U(this,Tr,O(this,Ka).getQueryCache()),this.queryKey=t.queryKey,this.queryHash=t.queryHash,U(this,Ha,S1(this.options)),this.state=t.state??O(this,Ha),this.scheduleGc()}get meta(){return this.options.meta}get promise(){var t;return(t=O(this,dt))==null?void 0:t.promise}setOptions(t){if(this.options={...O(this,Ic),...t},this.updateGcTime(this.options.gcTime),this.state&&this.state.data===void 0){const r=S1(this.options);r.data!==void 0&&(this.setData(r.data,{updatedAt:r.dataUpdatedAt,manual:!0}),U(this,Ha,r))}}optionalRemove(){!this.observers.length&&this.state.fetchStatus==="idle"&&O(this,Tr).remove(this)}setData(t,r){const n=ig(this.state.data,t,this.options);return ce(this,Qr,qn).call(this,{data:n,type:"success",dataUpdatedAt:r==null?void 0:r.updatedAt,manual:r==null?void 0:r.manual}),n}setState(t,r){ce(this,Qr,qn).call(this,{type:"setState",state:t,setStateOptions:r})}cancel(t){var n,i;const r=(n=O(this,dt))==null?void 0:n.promise;return(i=O(this,dt))==null||i.cancel(t),r?r.then(Zt).catch(Zt):Promise.resolve()}destroy(){super.destroy(),this.cancel({silent:!0})}reset(){this.destroy(),this.setState(O(this,Ha))}isActive(){return this.observers.some(t=>_r(t.options.enabled,this)!==!1)}isDisabled(){return this.getObserversCount()>0?!this.isActive():this.options.queryFn===Sx||this.state.dataUpdateCount+this.state.errorUpdateCount===0}isStatic(){return this.getObserversCount()>0?this.observers.some(t=>la(t.options.staleTime,this)==="static"):!1}isStale(){return this.getObserversCount()>0?this.observers.some(t=>t.getCurrentResult().isStale):this.state.data===void 0||this.state.isInvalidated}isStaleByTime(t=0){return this.state.data===void 0?!0:t==="static"?!1:this.state.isInvalidated?!0:!_O(this.state.dataUpdatedAt,t)}onFocus(){var r;const t=this.observers.find(n=>n.shouldFetchOnWindowFocus());t==null||t.refetch({cancelRefetch:!1}),(r=O(this,dt))==null||r.continue()}onOnline(){var r;const t=this.observers.find(n=>n.shouldFetchOnReconnect());t==null||t.refetch({cancelRefetch:!1}),(r=O(this,dt))==null||r.continue()}addObserver(t){this.observers.includes(t)||(this.observers.push(t),this.clearGcTimeout(),O(this,Tr).notify({type:"observerAdded",query:this,observer:t}))}removeObserver(t){this.observers.includes(t)&&(this.observers=this.observers.filter(r=>r!==t),this.observers.length||(O(this,dt)&&(O(this,Va)?O(this,dt).cancel({revert:!0}):O(this,dt).cancelRetry()),this.scheduleGc()),O(this,Tr).notify({type:"observerRemoved",query:this,observer:t}))}getObserversCount(){return this.observers.length}invalidate(){this.state.isInvalidated||ce(this,Qr,qn).call(this,{type:"invalidate"})}async fetch(t,r){var l,c,u,d,h,m,g,v,x,w,y,b;if(this.state.fetchStatus!=="idle"&&((l=O(this,dt))==null?void 0:l.status())!=="rejected"){if(this.state.data!==void 0&&(r!=null&&r.cancelRefetch))this.cancel({silent:!0});else if(O(this,dt))return O(this,dt).continueRetry(),O(this,dt).promise}if(t&&this.setOptions(t),!this.options.queryFn){const S=this.observers.find(P=>P.options.queryFn);S&&this.setOptions(S.options)}const n=new AbortController,i=S=>{Object.defineProperty(S,"signal",{enumerable:!0,get:()=>(U(this,Va,!0),n.signal)})},a=()=>{const S=MO(this.options,r),j=(()=>{const E={client:O(this,Ka),queryKey:this.queryKey,meta:this.meta};return i(E),E})();return U(this,Va,!1),this.options.persister?this.options.persister(S,j,this):S(j)},s=(()=>{const S={fetchOptions:r,options:this.options,queryKey:this.queryKey,client:O(this,Ka),state:this.state,fetchFn:a};return i(S),S})();(c=this.options.behavior)==null||c.onFetch(s,this),U(this,hs,this.state),(this.state.fetchStatus==="idle"||this.state.fetchMeta!==((u=s.fetchOptions)==null?void 0:u.meta))&&ce(this,Qr,qn).call(this,{type:"fetch",meta:(d=s.fetchOptions)==null?void 0:d.meta}),U(this,dt,IO({initialPromise:r==null?void 0:r.initialPromise,fn:s.fetchFn,onCancel:S=>{S instanceof og&&S.revert&&this.setState({...O(this,hs),fetchStatus:"idle"}),n.abort()},onFail:(S,P)=>{ce(this,Qr,qn).call(this,{type:"failed",failureCount:S,error:P})},onPause:()=>{ce(this,Qr,qn).call(this,{type:"pause"})},onContinue:()=>{ce(this,Qr,qn).call(this,{type:"continue"})},retry:s.options.retry,retryDelay:s.options.retryDelay,networkMode:s.options.networkMode,canRun:()=>!0}));try{const S=await O(this,dt).start();if(S===void 0)throw new Error(`${this.queryHash} data is undefined`);return this.setData(S),(m=(h=O(this,Tr).config).onSuccess)==null||m.call(h,S,this),(v=(g=O(this,Tr).config).onSettled)==null||v.call(g,S,this.state.error,this),S}catch(S){if(S instanceof og){if(S.silent)return O(this,dt).promise;if(S.revert){if(this.state.data===void 0)throw S;return this.state.data}}throw ce(this,Qr,qn).call(this,{type:"error",error:S}),(w=(x=O(this,Tr).config).onError)==null||w.call(x,S,this),(b=(y=O(this,Tr).config).onSettled)==null||b.call(y,this.state.data,S,this),S}finally{this.scheduleGc()}}},Ha=new WeakMap,hs=new WeakMap,Tr=new WeakMap,Ka=new WeakMap,dt=new WeakMap,Ic=new WeakMap,Va=new WeakMap,Qr=new WeakSet,qn=function(t){const r=n=>{switch(t.type){case"failed":return{...n,fetchFailureCount:t.failureCount,fetchFailureReason:t.error};case"pause":return{...n,fetchStatus:"paused"};case"continue":return{...n,fetchStatus:"fetching"};case"fetch":return{...n,...$O(n.data,this.options),fetchMeta:t.meta??null};case"success":const i={...n,data:t.data,dataUpdateCount:n.dataUpdateCount+1,dataUpdatedAt:t.dataUpdatedAt??Date.now(),error:null,isInvalidated:!1,status:"success",...!t.manual&&{fetchStatus:"idle",fetchFailureCount:0,fetchFailureReason:null}};return U(this,hs,t.manual?i:void 0),i;case"error":const a=t.error;return{...n,error:a,errorUpdateCount:n.errorUpdateCount+1,errorUpdatedAt:Date.now(),fetchFailureCount:n.fetchFailureCount+1,fetchFailureReason:a,fetchStatus:"idle",status:"error"};case"invalidate":return{...n,isInvalidated:!0};case"setState":return{...n,...t.state}}};this.state=r(this.state),Et.batch(()=>{this.observers.forEach(n=>{n.onQueryUpdate()}),O(this,Tr).notify({query:this,type:"updated",action:t})})},pE);function $O(e,t){return{fetchFailureCount:0,fetchFailureReason:null,fetchStatus:RO(t.networkMode)?"fetching":"paused",...e===void 0&&{error:null,status:"pending"}}}function S1(e){const t=typeof e.initialData=="function"?e.initialData():e.initialData,r=t!==void 0,n=r?typeof e.initialDataUpdatedAt=="function"?e.initialDataUpdatedAt():e.initialDataUpdatedAt:0;return{data:t,dataUpdateCount:0,dataUpdatedAt:r?n??Date.now():0,error:null,errorUpdateCount:0,errorUpdatedAt:0,fetchFailureCount:0,fetchFailureReason:null,fetchMeta:null,isInvalidated:!1,status:r?"success":"pending",fetchStatus:"idle"}}var Gt,ue,Lc,zt,Ya,ps,Qn,Ki,$c,ms,vs,Qa,Ga,Vi,gs,xe,Il,sg,lg,cg,ug,dg,fg,hg,FO,mE,N$=(mE=class extends Kc{constructor(t,r){super();ee(this,xe);ee(this,Gt);ee(this,ue);ee(this,Lc);ee(this,zt);ee(this,Ya);ee(this,ps);ee(this,Qn);ee(this,Ki);ee(this,$c);ee(this,ms);ee(this,vs);ee(this,Qa);ee(this,Ga);ee(this,Vi);ee(this,gs,new Set);this.options=r,U(this,Gt,t),U(this,Ki,null),U(this,Qn,ag()),this.bindMethods(),this.setOptions(r)}bindMethods(){this.refetch=this.refetch.bind(this)}onSubscribe(){this.listeners.size===1&&(O(this,ue).addObserver(this),P1(O(this,ue),this.options)?ce(this,xe,Il).call(this):this.updateResult(),ce(this,xe,ug).call(this))}onUnsubscribe(){this.hasListeners()||this.destroy()}shouldFetchOnReconnect(){return pg(O(this,ue),this.options,this.options.refetchOnReconnect)}shouldFetchOnWindowFocus(){return pg(O(this,ue),this.options,this.options.refetchOnWindowFocus)}destroy(){this.listeners=new Set,ce(this,xe,dg).call(this),ce(this,xe,fg).call(this),O(this,ue).removeObserver(this)}setOptions(t){const r=this.options,n=O(this,ue);if(this.options=O(this,Gt).defaultQueryOptions(t),this.options.enabled!==void 0&&typeof this.options.enabled!="boolean"&&typeof this.options.enabled!="function"&&typeof _r(this.options.enabled,O(this,ue))!="boolean")throw new Error("Expected enabled to be a boolean or a callback that returns a boolean");ce(this,xe,hg).call(this),O(this,ue).setOptions(this.options),r._defaulted&&!rg(this.options,r)&&O(this,Gt).getQueryCache().notify({type:"observerOptionsUpdated",query:O(this,ue),observer:this});const i=this.hasListeners();i&&j1(O(this,ue),n,this.options,r)&&ce(this,xe,Il).call(this),this.updateResult(),i&&(O(this,ue)!==n||_r(this.options.enabled,O(this,ue))!==_r(r.enabled,O(this,ue))||la(this.options.staleTime,O(this,ue))!==la(r.staleTime,O(this,ue)))&&ce(this,xe,sg).call(this);const a=ce(this,xe,lg).call(this);i&&(O(this,ue)!==n||_r(this.options.enabled,O(this,ue))!==_r(r.enabled,O(this,ue))||a!==O(this,Vi))&&ce(this,xe,cg).call(this,a)}getOptimisticResult(t){const r=O(this,Gt).getQueryCache().build(O(this,Gt),t),n=this.createResult(r,t);return T$(this,n)&&(U(this,zt,n),U(this,ps,this.options),U(this,Ya,O(this,ue).state)),n}getCurrentResult(){return O(this,zt)}trackResult(t,r){return new Proxy(t,{get:(n,i)=>(this.trackProp(i),r==null||r(i),i==="promise"&&!this.options.experimental_prefetchInRender&&O(this,Qn).status==="pending"&&O(this,Qn).reject(new Error("experimental_prefetchInRender feature flag is not enabled")),Reflect.get(n,i))})}trackProp(t){O(this,gs).add(t)}getCurrentQuery(){return O(this,ue)}refetch({...t}={}){return this.fetch({...t})}fetchOptimistic(t){const r=O(this,Gt).defaultQueryOptions(t),n=O(this,Gt).getQueryCache().build(O(this,Gt),r);return n.fetch().then(()=>this.createResult(n,r))}fetch(t){return ce(this,xe,Il).call(this,{...t,cancelRefetch:t.cancelRefetch??!0}).then(()=>(this.updateResult(),O(this,zt)))}createResult(t,r){var N;const n=O(this,ue),i=this.options,a=O(this,zt),o=O(this,Ya),s=O(this,ps),c=t!==n?t.state:O(this,Lc),{state:u}=t;let d={...u},h=!1,m;if(r._optimisticResults){const k=this.hasListeners(),A=!k&&P1(t,r),T=k&&j1(t,n,r,i);(A||T)&&(d={...d,...$O(u.data,t.options)}),r._optimisticResults==="isRestoring"&&(d.fetchStatus="idle")}let{error:g,errorUpdatedAt:v,status:x}=d;m=d.data;let w=!1;if(r.placeholderData!==void 0&&m===void 0&&x==="pending"){let k;a!=null&&a.isPlaceholderData&&r.placeholderData===(s==null?void 0:s.placeholderData)?(k=a.data,w=!0):k=typeof r.placeholderData=="function"?r.placeholderData((N=O(this,vs))==null?void 0:N.state.data,O(this,vs)):r.placeholderData,k!==void 0&&(x="success",m=ig(a==null?void 0:a.data,k,r),h=!0)}if(r.select&&m!==void 0&&!w)if(a&&m===(o==null?void 0:o.data)&&r.select===O(this,$c))m=O(this,ms);else try{U(this,$c,r.select),m=r.select(m),m=ig(a==null?void 0:a.data,m,r),U(this,ms,m),U(this,Ki,null)}catch(k){U(this,Ki,k)}O(this,Ki)&&(g=O(this,Ki),m=O(this,ms),v=Date.now(),x="error");const y=d.fetchStatus==="fetching",b=x==="pending",S=x==="error",P=b&&y,j=m!==void 0,C={status:x,fetchStatus:d.fetchStatus,isPending:b,isSuccess:x==="success",isError:S,isInitialLoading:P,isLoading:P,data:m,dataUpdatedAt:d.dataUpdatedAt,error:g,errorUpdatedAt:v,failureCount:d.fetchFailureCount,failureReason:d.fetchFailureReason,errorUpdateCount:d.errorUpdateCount,isFetched:d.dataUpdateCount>0||d.errorUpdateCount>0,isFetchedAfterMount:d.dataUpdateCount>c.dataUpdateCount||d.errorUpdateCount>c.errorUpdateCount,isFetching:y,isRefetching:y&&!b,isLoadingError:S&&!j,isPaused:d.fetchStatus==="paused",isPlaceholderData:h,isRefetchError:S&&j,isStale:jx(t,r),refetch:this.refetch,promise:O(this,Qn),isEnabled:_r(r.enabled,t)!==!1};if(this.options.experimental_prefetchInRender){const k=R=>{C.status==="error"?R.reject(C.error):C.data!==void 0&&R.resolve(C.data)},A=()=>{const R=U(this,Qn,C.promise=ag());k(R)},T=O(this,Qn);switch(T.status){case"pending":t.queryHash===n.queryHash&&k(T);break;case"fulfilled":(C.status==="error"||C.data!==T.value)&&A();break;case"rejected":(C.status!=="error"||C.error!==T.reason)&&A();break}}return C}updateResult(){const t=O(this,zt),r=this.createResult(O(this,ue),this.options);if(U(this,Ya,O(this,ue).state),U(this,ps,this.options),O(this,Ya).data!==void 0&&U(this,vs,O(this,ue)),rg(r,t))return;U(this,zt,r);const n=()=>{if(!t)return!0;const{notifyOnChangeProps:i}=this.options,a=typeof i=="function"?i():i;if(a==="all"||!a&&!O(this,gs).size)return!0;const o=new Set(a??O(this,gs));return this.options.throwOnError&&o.add("error"),Object.keys(O(this,zt)).some(s=>{const l=s;return O(this,zt)[l]!==t[l]&&o.has(l)})};ce(this,xe,FO).call(this,{listeners:n()})}onQueryUpdate(){this.updateResult(),this.hasListeners()&&ce(this,xe,ug).call(this)}},Gt=new WeakMap,ue=new WeakMap,Lc=new WeakMap,zt=new WeakMap,Ya=new WeakMap,ps=new WeakMap,Qn=new WeakMap,Ki=new WeakMap,$c=new WeakMap,ms=new WeakMap,vs=new WeakMap,Qa=new WeakMap,Ga=new WeakMap,Vi=new WeakMap,gs=new WeakMap,xe=new WeakSet,Il=function(t){ce(this,xe,hg).call(this);let r=O(this,ue).fetch(this.options,t);return t!=null&&t.throwOnError||(r=r.catch(Zt)),r},sg=function(){ce(this,xe,dg).call(this);const t=la(this.options.staleTime,O(this,ue));if(co||O(this,zt).isStale||!tg(t))return;const n=_O(O(this,zt).dataUpdatedAt,t)+1;U(this,Qa,$a.setTimeout(()=>{O(this,zt).isStale||this.updateResult()},n))},lg=function(){return(typeof this.options.refetchInterval=="function"?this.options.refetchInterval(O(this,ue)):this.options.refetchInterval)??!1},cg=function(t){ce(this,xe,fg).call(this),U(this,Vi,t),!(co||_r(this.options.enabled,O(this,ue))===!1||!tg(O(this,Vi))||O(this,Vi)===0)&&U(this,Ga,$a.setInterval(()=>{(this.options.refetchIntervalInBackground||Px.isFocused())&&ce(this,xe,Il).call(this)},O(this,Vi)))},ug=function(){ce(this,xe,sg).call(this),ce(this,xe,cg).call(this,ce(this,xe,lg).call(this))},dg=function(){O(this,Qa)&&($a.clearTimeout(O(this,Qa)),U(this,Qa,void 0))},fg=function(){O(this,Ga)&&($a.clearInterval(O(this,Ga)),U(this,Ga,void 0))},hg=function(){const t=O(this,Gt).getQueryCache().build(O(this,Gt),this.options);if(t===O(this,ue))return;const r=O(this,ue);U(this,ue,t),U(this,Lc,t.state),this.hasListeners()&&(r==null||r.removeObserver(this),t.addObserver(this))},FO=function(t){Et.batch(()=>{t.listeners&&this.listeners.forEach(r=>{r(O(this,zt))}),O(this,Gt).getQueryCache().notify({query:O(this,ue),type:"observerResultsUpdated"})})},mE);function A$(e,t){return _r(t.enabled,e)!==!1&&e.state.data===void 0&&!(e.state.status==="error"&&t.retryOnMount===!1)}function P1(e,t){return A$(e,t)||e.state.data!==void 0&&pg(e,t,t.refetchOnMount)}function pg(e,t,r){if(_r(t.enabled,e)!==!1&&la(t.staleTime,e)!=="static"){const n=typeof r=="function"?r(e):r;return n==="always"||n!==!1&&jx(e,t)}return!1}function j1(e,t,r,n){return(e!==t||_r(n.enabled,e)===!1)&&(!r.suspense||e.state.status!=="error")&&jx(e,r)}function jx(e,t){return _r(t.enabled,e)!==!1&&e.isStaleByTime(la(t.staleTime,e))}function T$(e,t){return!rg(e.getCurrentResult(),t)}function E1(e){return{onFetch:(t,r)=>{var u,d,h,m,g;const n=t.options,i=(h=(d=(u=t.fetchOptions)==null?void 0:u.meta)==null?void 0:d.fetchMore)==null?void 0:h.direction,a=((m=t.state.data)==null?void 0:m.pages)||[],o=((g=t.state.data)==null?void 0:g.pageParams)||[];let s={pages:[],pageParams:[]},l=0;const c=async()=>{let v=!1;const x=b=>{Object.defineProperty(b,"signal",{enumerable:!0,get:()=>(t.signal.aborted?v=!0:t.signal.addEventListener("abort",()=>{v=!0}),t.signal)})},w=MO(t.options,t.fetchOptions),y=async(b,S,P)=>{if(v)return Promise.reject();if(S==null&&b.pages.length)return Promise.resolve(b);const E=(()=>{const A={client:t.client,queryKey:t.queryKey,pageParam:S,direction:P?"backward":"forward",meta:t.options.meta};return x(A),A})(),C=await w(E),{maxPages:N}=t.options,k=P?b$:w$;return{pages:k(b.pages,C,N),pageParams:k(b.pageParams,S,N)}};if(i&&a.length){const b=i==="backward",S=b?_$:C1,P={pages:a,pageParams:o},j=S(n,P);s=await y(P,j,b)}else{const b=e??a.length;do{const S=l===0?o[0]??n.initialPageParam:C1(n,s);if(l>0&&S==null)break;s=await y(s,S),l++}while(l{var v,x;return(x=(v=t.options).persister)==null?void 0:x.call(v,c,{client:t.client,queryKey:t.queryKey,meta:t.options.meta,signal:t.signal},r)}:t.fetchFn=c}}}function C1(e,{pages:t,pageParams:r}){const n=t.length-1;return t.length>0?e.getNextPageParam(t[n],t,r[n],r):void 0}function _$(e,{pages:t,pageParams:r}){var n;return t.length>0?(n=e.getPreviousPageParam)==null?void 0:n.call(e,t[0],t,r[0],r):void 0}var Fc,wn,Bt,Xa,bn,Mi,vE,D$=(vE=class extends LO{constructor(t){super();ee(this,bn);ee(this,Fc);ee(this,wn);ee(this,Bt);ee(this,Xa);U(this,Fc,t.client),this.mutationId=t.mutationId,U(this,Bt,t.mutationCache),U(this,wn,[]),this.state=t.state||M$(),this.setOptions(t.options),this.scheduleGc()}setOptions(t){this.options=t,this.updateGcTime(this.options.gcTime)}get meta(){return this.options.meta}addObserver(t){O(this,wn).includes(t)||(O(this,wn).push(t),this.clearGcTimeout(),O(this,Bt).notify({type:"observerAdded",mutation:this,observer:t}))}removeObserver(t){U(this,wn,O(this,wn).filter(r=>r!==t)),this.scheduleGc(),O(this,Bt).notify({type:"observerRemoved",mutation:this,observer:t})}optionalRemove(){O(this,wn).length||(this.state.status==="pending"?this.scheduleGc():O(this,Bt).remove(this))}continue(){var t;return((t=O(this,Xa))==null?void 0:t.continue())??this.execute(this.state.variables)}async execute(t){var o,s,l,c,u,d,h,m,g,v,x,w,y,b,S,P,j,E,C,N;const r=()=>{ce(this,bn,Mi).call(this,{type:"continue"})},n={client:O(this,Fc),meta:this.options.meta,mutationKey:this.options.mutationKey};U(this,Xa,IO({fn:()=>this.options.mutationFn?this.options.mutationFn(t,n):Promise.reject(new Error("No mutationFn found")),onFail:(k,A)=>{ce(this,bn,Mi).call(this,{type:"failed",failureCount:k,error:A})},onPause:()=>{ce(this,bn,Mi).call(this,{type:"pause"})},onContinue:r,retry:this.options.retry??0,retryDelay:this.options.retryDelay,networkMode:this.options.networkMode,canRun:()=>O(this,Bt).canRun(this)}));const i=this.state.status==="pending",a=!O(this,Xa).canStart();try{if(i)r();else{ce(this,bn,Mi).call(this,{type:"pending",variables:t,isPaused:a}),await((s=(o=O(this,Bt).config).onMutate)==null?void 0:s.call(o,t,this,n));const A=await((c=(l=this.options).onMutate)==null?void 0:c.call(l,t,n));A!==this.state.context&&ce(this,bn,Mi).call(this,{type:"pending",context:A,variables:t,isPaused:a})}const k=await O(this,Xa).start();return await((d=(u=O(this,Bt).config).onSuccess)==null?void 0:d.call(u,k,t,this.state.context,this,n)),await((m=(h=this.options).onSuccess)==null?void 0:m.call(h,k,t,this.state.context,n)),await((v=(g=O(this,Bt).config).onSettled)==null?void 0:v.call(g,k,null,this.state.variables,this.state.context,this,n)),await((w=(x=this.options).onSettled)==null?void 0:w.call(x,k,null,t,this.state.context,n)),ce(this,bn,Mi).call(this,{type:"success",data:k}),k}catch(k){try{throw await((b=(y=O(this,Bt).config).onError)==null?void 0:b.call(y,k,t,this.state.context,this,n)),await((P=(S=this.options).onError)==null?void 0:P.call(S,k,t,this.state.context,n)),await((E=(j=O(this,Bt).config).onSettled)==null?void 0:E.call(j,void 0,k,this.state.variables,this.state.context,this,n)),await((N=(C=this.options).onSettled)==null?void 0:N.call(C,void 0,k,t,this.state.context,n)),k}finally{ce(this,bn,Mi).call(this,{type:"error",error:k})}}finally{O(this,Bt).runNext(this)}}},Fc=new WeakMap,wn=new WeakMap,Bt=new WeakMap,Xa=new WeakMap,bn=new WeakSet,Mi=function(t){const r=n=>{switch(t.type){case"failed":return{...n,failureCount:t.failureCount,failureReason:t.error};case"pause":return{...n,isPaused:!0};case"continue":return{...n,isPaused:!1};case"pending":return{...n,context:t.context,data:void 0,failureCount:0,failureReason:null,error:null,isPaused:t.isPaused,status:"pending",variables:t.variables,submittedAt:Date.now()};case"success":return{...n,data:t.data,failureCount:0,failureReason:null,error:null,status:"success",isPaused:!1};case"error":return{...n,data:void 0,error:t.error,failureCount:n.failureCount+1,failureReason:t.error,isPaused:!1,status:"error"}}};this.state=r(this.state),Et.batch(()=>{O(this,wn).forEach(n=>{n.onMutationUpdate(t)}),O(this,Bt).notify({mutation:this,type:"updated",action:t})})},vE);function M$(){return{context:void 0,data:void 0,error:null,failureCount:0,failureReason:null,isPaused:!1,status:"idle",variables:void 0,submittedAt:0}}var Gn,Gr,zc,gE,R$=(gE=class extends Kc{constructor(t={}){super();ee(this,Gn);ee(this,Gr);ee(this,zc);this.config=t,U(this,Gn,new Set),U(this,Gr,new Map),U(this,zc,0)}build(t,r,n){const i=new D$({client:t,mutationCache:this,mutationId:++Cu(this,zc)._,options:t.defaultMutationOptions(r),state:n});return this.add(i),i}add(t){O(this,Gn).add(t);const r=qu(t);if(typeof r=="string"){const n=O(this,Gr).get(r);n?n.push(t):O(this,Gr).set(r,[t])}this.notify({type:"added",mutation:t})}remove(t){if(O(this,Gn).delete(t)){const r=qu(t);if(typeof r=="string"){const n=O(this,Gr).get(r);if(n)if(n.length>1){const i=n.indexOf(t);i!==-1&&n.splice(i,1)}else n[0]===t&&O(this,Gr).delete(r)}}this.notify({type:"removed",mutation:t})}canRun(t){const r=qu(t);if(typeof r=="string"){const n=O(this,Gr).get(r),i=n==null?void 0:n.find(a=>a.state.status==="pending");return!i||i===t}else return!0}runNext(t){var n;const r=qu(t);if(typeof r=="string"){const i=(n=O(this,Gr).get(r))==null?void 0:n.find(a=>a!==t&&a.state.isPaused);return(i==null?void 0:i.continue())??Promise.resolve()}else return Promise.resolve()}clear(){Et.batch(()=>{O(this,Gn).forEach(t=>{this.notify({type:"removed",mutation:t})}),O(this,Gn).clear(),O(this,Gr).clear()})}getAll(){return Array.from(O(this,Gn))}find(t){const r={exact:!0,...t};return this.getAll().find(n=>x1(r,n))}findAll(t={}){return this.getAll().filter(r=>x1(t,r))}notify(t){Et.batch(()=>{this.listeners.forEach(r=>{r(t)})})}resumePausedMutations(){const t=this.getAll().filter(r=>r.state.isPaused);return Et.batch(()=>Promise.all(t.map(r=>r.continue().catch(Zt))))}},Gn=new WeakMap,Gr=new WeakMap,zc=new WeakMap,gE);function qu(e){var t;return(t=e.options.scope)==null?void 0:t.id}var Sn,yE,I$=(yE=class extends Kc{constructor(t={}){super();ee(this,Sn);this.config=t,U(this,Sn,new Map)}build(t,r,n){const i=r.queryKey,a=r.queryHash??bx(i,r);let o=this.get(a);return o||(o=new k$({client:t,queryKey:i,queryHash:a,options:t.defaultQueryOptions(r),state:n,defaultOptions:t.getQueryDefaults(i)}),this.add(o)),o}add(t){O(this,Sn).has(t.queryHash)||(O(this,Sn).set(t.queryHash,t),this.notify({type:"added",query:t}))}remove(t){const r=O(this,Sn).get(t.queryHash);r&&(t.destroy(),r===t&&O(this,Sn).delete(t.queryHash),this.notify({type:"removed",query:t}))}clear(){Et.batch(()=>{this.getAll().forEach(t=>{this.remove(t)})})}get(t){return O(this,Sn).get(t)}getAll(){return[...O(this,Sn).values()]}find(t){const r={exact:!0,...t};return this.getAll().find(n=>y1(r,n))}findAll(t={}){const r=this.getAll();return Object.keys(t).length>0?r.filter(n=>y1(t,n)):r}notify(t){Et.batch(()=>{this.listeners.forEach(r=>{r(t)})})}onFocus(){Et.batch(()=>{this.getAll().forEach(t=>{t.onFocus()})})}onOnline(){Et.batch(()=>{this.getAll().forEach(t=>{t.onOnline()})})}},Sn=new WeakMap,yE),Ke,Yi,Qi,ys,xs,Gi,ws,bs,xE,L$=(xE=class{constructor(e={}){ee(this,Ke);ee(this,Yi);ee(this,Qi);ee(this,ys);ee(this,xs);ee(this,Gi);ee(this,ws);ee(this,bs);U(this,Ke,e.queryCache||new I$),U(this,Yi,e.mutationCache||new R$),U(this,Qi,e.defaultOptions||{}),U(this,ys,new Map),U(this,xs,new Map),U(this,Gi,0)}mount(){Cu(this,Gi)._++,O(this,Gi)===1&&(U(this,ws,Px.subscribe(async e=>{e&&(await this.resumePausedMutations(),O(this,Ke).onFocus())})),U(this,bs,uf.subscribe(async e=>{e&&(await this.resumePausedMutations(),O(this,Ke).onOnline())})))}unmount(){var e,t;Cu(this,Gi)._--,O(this,Gi)===0&&((e=O(this,ws))==null||e.call(this),U(this,ws,void 0),(t=O(this,bs))==null||t.call(this),U(this,bs,void 0))}isFetching(e){return O(this,Ke).findAll({...e,fetchStatus:"fetching"}).length}isMutating(e){return O(this,Yi).findAll({...e,status:"pending"}).length}getQueryData(e){var r;const t=this.defaultQueryOptions({queryKey:e});return(r=O(this,Ke).get(t.queryHash))==null?void 0:r.state.data}ensureQueryData(e){const t=this.defaultQueryOptions(e),r=O(this,Ke).build(this,t),n=r.state.data;return n===void 0?this.fetchQuery(e):(e.revalidateIfStale&&r.isStaleByTime(la(t.staleTime,r))&&this.prefetchQuery(t),Promise.resolve(n))}getQueriesData(e){return O(this,Ke).findAll(e).map(({queryKey:t,state:r})=>{const n=r.data;return[t,n]})}setQueryData(e,t,r){const n=this.defaultQueryOptions({queryKey:e}),i=O(this,Ke).get(n.queryHash),a=i==null?void 0:i.state.data,o=g$(t,a);if(o!==void 0)return O(this,Ke).build(this,n).setData(o,{...r,manual:!0})}setQueriesData(e,t,r){return Et.batch(()=>O(this,Ke).findAll(e).map(({queryKey:n})=>[n,this.setQueryData(n,t,r)]))}getQueryState(e){var r;const t=this.defaultQueryOptions({queryKey:e});return(r=O(this,Ke).get(t.queryHash))==null?void 0:r.state}removeQueries(e){const t=O(this,Ke);Et.batch(()=>{t.findAll(e).forEach(r=>{t.remove(r)})})}resetQueries(e,t){const r=O(this,Ke);return Et.batch(()=>(r.findAll(e).forEach(n=>{n.reset()}),this.refetchQueries({type:"active",...e},t)))}cancelQueries(e,t={}){const r={revert:!0,...t},n=Et.batch(()=>O(this,Ke).findAll(e).map(i=>i.cancel(r)));return Promise.all(n).then(Zt).catch(Zt)}invalidateQueries(e,t={}){return Et.batch(()=>(O(this,Ke).findAll(e).forEach(r=>{r.invalidate()}),(e==null?void 0:e.refetchType)==="none"?Promise.resolve():this.refetchQueries({...e,type:(e==null?void 0:e.refetchType)??(e==null?void 0:e.type)??"active"},t)))}refetchQueries(e,t={}){const r={...t,cancelRefetch:t.cancelRefetch??!0},n=Et.batch(()=>O(this,Ke).findAll(e).filter(i=>!i.isDisabled()&&!i.isStatic()).map(i=>{let a=i.fetch(void 0,r);return r.throwOnError||(a=a.catch(Zt)),i.state.fetchStatus==="paused"?Promise.resolve():a}));return Promise.all(n).then(Zt)}fetchQuery(e){const t=this.defaultQueryOptions(e);t.retry===void 0&&(t.retry=!1);const r=O(this,Ke).build(this,t);return r.isStaleByTime(la(t.staleTime,r))?r.fetch(t):Promise.resolve(r.state.data)}prefetchQuery(e){return this.fetchQuery(e).then(Zt).catch(Zt)}fetchInfiniteQuery(e){return e.behavior=E1(e.pages),this.fetchQuery(e)}prefetchInfiniteQuery(e){return this.fetchInfiniteQuery(e).then(Zt).catch(Zt)}ensureInfiniteQueryData(e){return e.behavior=E1(e.pages),this.ensureQueryData(e)}resumePausedMutations(){return uf.isOnline()?O(this,Yi).resumePausedMutations():Promise.resolve()}getQueryCache(){return O(this,Ke)}getMutationCache(){return O(this,Yi)}getDefaultOptions(){return O(this,Qi)}setDefaultOptions(e){U(this,Qi,e)}setQueryDefaults(e,t){O(this,ys).set(mc(e),{queryKey:e,defaultOptions:t})}getQueryDefaults(e){const t=[...O(this,ys).values()],r={};return t.forEach(n=>{vc(e,n.queryKey)&&Object.assign(r,n.defaultOptions)}),r}setMutationDefaults(e,t){O(this,xs).set(mc(e),{mutationKey:e,defaultOptions:t})}getMutationDefaults(e){const t=[...O(this,xs).values()],r={};return t.forEach(n=>{vc(e,n.mutationKey)&&Object.assign(r,n.defaultOptions)}),r}defaultQueryOptions(e){if(e._defaulted)return e;const t={...O(this,Qi).queries,...this.getQueryDefaults(e.queryKey),...e,_defaulted:!0};return t.queryHash||(t.queryHash=bx(t.queryKey,t)),t.refetchOnReconnect===void 0&&(t.refetchOnReconnect=t.networkMode!=="always"),t.throwOnError===void 0&&(t.throwOnError=!!t.suspense),!t.networkMode&&t.persister&&(t.networkMode="offlineFirst"),t.queryFn===Sx&&(t.enabled=!1),t}defaultMutationOptions(e){return e!=null&&e._defaulted?e:{...O(this,Qi).mutations,...(e==null?void 0:e.mutationKey)&&this.getMutationDefaults(e.mutationKey),...e,_defaulted:!0}}clear(){O(this,Ke).clear(),O(this,Yi).clear()}},Ke=new WeakMap,Yi=new WeakMap,Qi=new WeakMap,ys=new WeakMap,xs=new WeakMap,Gi=new WeakMap,ws=new WeakMap,bs=new WeakMap,xE),zO=p.createContext(void 0),$$=e=>{const t=p.useContext(zO);if(!t)throw new Error("No QueryClient set, use QueryClientProvider to set one");return t},F$=({client:e,children:t})=>(p.useEffect(()=>(e.mount(),()=>{e.unmount()}),[e]),f.jsx(zO.Provider,{value:e,children:t})),BO=p.createContext(!1),z$=()=>p.useContext(BO);BO.Provider;function B$(){let e=!1;return{clearReset:()=>{e=!1},reset:()=>{e=!0},isReset:()=>e}}var W$=p.createContext(B$()),U$=()=>p.useContext(W$),q$=(e,t)=>{(e.suspense||e.throwOnError||e.experimental_prefetchInRender)&&(t.isReset()||(e.retryOnMount=!1))},H$=e=>{p.useEffect(()=>{e.clearReset()},[e])},K$=({result:e,errorResetBoundary:t,throwOnError:r,query:n,suspense:i})=>e.isError&&!t.isReset()&&!e.isFetching&&n&&(i&&e.data===void 0||S$(r,[e.error,n])),V$=e=>{if(e.suspense){const r=i=>i==="static"?i:Math.max(i??1e3,1e3),n=e.staleTime;e.staleTime=typeof n=="function"?(...i)=>r(n(...i)):r(n),typeof e.gcTime=="number"&&(e.gcTime=Math.max(e.gcTime,1e3))}},Y$=(e,t)=>e.isLoading&&e.isFetching&&!t,Q$=(e,t)=>(e==null?void 0:e.suspense)&&t.isPending,O1=(e,t,r)=>t.fetchOptimistic(e).catch(()=>{r.clearReset()});function G$(e,t,r){var d,h,m,g,v;const n=z$(),i=U$(),a=$$(),o=a.defaultQueryOptions(e);(h=(d=a.getDefaultOptions().queries)==null?void 0:d._experimental_beforeQuery)==null||h.call(d,o),o._optimisticResults=n?"isRestoring":"optimistic",V$(o),q$(o,i),H$(i);const s=!a.getQueryCache().get(o.queryHash),[l]=p.useState(()=>new t(a,o)),c=l.getOptimisticResult(o),u=!n&&e.subscribed!==!1;if(p.useSyncExternalStore(p.useCallback(x=>{const w=u?l.subscribe(Et.batchCalls(x)):Zt;return l.updateResult(),w},[l,u]),()=>l.getCurrentResult(),()=>l.getCurrentResult()),p.useEffect(()=>{l.setOptions(o)},[o,l]),Q$(o,c))throw O1(o,l,i);if(K$({result:c,errorResetBoundary:i,throwOnError:o.throwOnError,query:a.getQueryCache().get(o.queryHash),suspense:o.suspense}))throw c.error;if((g=(m=a.getDefaultOptions().queries)==null?void 0:m._experimental_afterQuery)==null||g.call(m,o,c),o.experimental_prefetchInRender&&!co&&Y$(c,n)){const x=s?O1(o,l,i):(v=a.getQueryCache().get(o.queryHash))==null?void 0:v.promise;x==null||x.catch(Zt).finally(()=>{l.updateResult()})}return o.notifyOnChangeProps?c:l.trackResult(c)}function mt(e,t){return G$(e,N$)}/** - * react-router v7.9.1 - * - * Copyright (c) Remix Software Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE.md file in the root directory of this source tree. - * - * @license MIT - */var k1="popstate";function X$(e={}){function t(n,i){let{pathname:a,search:o,hash:s}=n.location;return mg("",{pathname:a,search:o,hash:s},i.state&&i.state.usr||null,i.state&&i.state.key||"default")}function r(n,i){return typeof i=="string"?i:gc(i)}return J$(t,r,null,e)}function ze(e,t){if(e===!1||e===null||typeof e>"u")throw new Error(t)}function ln(e,t){if(!e){typeof console<"u"&&console.warn(t);try{throw new Error(t)}catch{}}}function Z$(){return Math.random().toString(36).substring(2,10)}function N1(e,t){return{usr:e.state,key:e.key,idx:t}}function mg(e,t,r=null,n){return{pathname:typeof e=="string"?e:e.pathname,search:"",hash:"",...typeof t=="string"?Vs(t):t,state:r,key:t&&t.key||n||Z$()}}function gc({pathname:e="/",search:t="",hash:r=""}){return t&&t!=="?"&&(e+=t.charAt(0)==="?"?t:"?"+t),r&&r!=="#"&&(e+=r.charAt(0)==="#"?r:"#"+r),e}function Vs(e){let t={};if(e){let r=e.indexOf("#");r>=0&&(t.hash=e.substring(r),e=e.substring(0,r));let n=e.indexOf("?");n>=0&&(t.search=e.substring(n),e=e.substring(0,n)),e&&(t.pathname=e)}return t}function J$(e,t,r,n={}){let{window:i=document.defaultView,v5Compat:a=!1}=n,o=i.history,s="POP",l=null,c=u();c==null&&(c=0,o.replaceState({...o.state,idx:c},""));function u(){return(o.state||{idx:null}).idx}function d(){s="POP";let x=u(),w=x==null?null:x-c;c=x,l&&l({action:s,location:v.location,delta:w})}function h(x,w){s="PUSH";let y=mg(v.location,x,w);c=u()+1;let b=N1(y,c),S=v.createHref(y);try{o.pushState(b,"",S)}catch(P){if(P instanceof DOMException&&P.name==="DataCloneError")throw P;i.location.assign(S)}a&&l&&l({action:s,location:v.location,delta:1})}function m(x,w){s="REPLACE";let y=mg(v.location,x,w);c=u();let b=N1(y,c),S=v.createHref(y);o.replaceState(b,"",S),a&&l&&l({action:s,location:v.location,delta:0})}function g(x){return e3(x)}let v={get action(){return s},get location(){return e(i,o)},listen(x){if(l)throw new Error("A history only accepts one active listener");return i.addEventListener(k1,d),l=x,()=>{i.removeEventListener(k1,d),l=null}},createHref(x){return t(i,x)},createURL:g,encodeLocation(x){let w=g(x);return{pathname:w.pathname,search:w.search,hash:w.hash}},push:h,replace:m,go(x){return o.go(x)}};return v}function e3(e,t=!1){let r="http://localhost";typeof window<"u"&&(r=window.location.origin!=="null"?window.location.origin:window.location.href),ze(r,"No window.location.(origin|href) available to create URL");let n=typeof e=="string"?e:gc(e);return n=n.replace(/ $/,"%20"),!t&&n.startsWith("//")&&(n=r+n),new URL(n,r)}function WO(e,t,r="/"){return t3(e,t,r,!1)}function t3(e,t,r,n){let i=typeof t=="string"?Vs(t):t,a=pi(i.pathname||"/",r);if(a==null)return null;let o=UO(e);r3(o);let s=null;for(let l=0;s==null&&l{let u={relativePath:c===void 0?o.path||"":c,caseSensitive:o.caseSensitive===!0,childrenIndex:s,route:o};if(u.relativePath.startsWith("/")){if(!u.relativePath.startsWith(n)&&l)return;ze(u.relativePath.startsWith(n),`Absolute route path "${u.relativePath}" nested under path "${n}" is not valid. An absolute child route path must start with the combined path of all its parent routes.`),u.relativePath=u.relativePath.slice(n.length)}let d=ai([n,u.relativePath]),h=r.concat(u);o.children&&o.children.length>0&&(ze(o.index!==!0,`Index routes must not have child routes. Please remove all child routes from route path "${d}".`),UO(o.children,t,h,d,l)),!(o.path==null&&!o.index)&&t.push({path:d,score:c3(d,o.index),routesMeta:h})};return e.forEach((o,s)=>{var l;if(o.path===""||!((l=o.path)!=null&&l.includes("?")))a(o,s);else for(let c of qO(o.path))a(o,s,!0,c)}),t}function qO(e){let t=e.split("/");if(t.length===0)return[];let[r,...n]=t,i=r.endsWith("?"),a=r.replace(/\?$/,"");if(n.length===0)return i?[a,""]:[a];let o=qO(n.join("/")),s=[];return s.push(...o.map(l=>l===""?a:[a,l].join("/"))),i&&s.push(...o),s.map(l=>e.startsWith("/")&&l===""?"/":l)}function r3(e){e.sort((t,r)=>t.score!==r.score?r.score-t.score:u3(t.routesMeta.map(n=>n.childrenIndex),r.routesMeta.map(n=>n.childrenIndex)))}var n3=/^:[\w-]+$/,i3=3,a3=2,o3=1,s3=10,l3=-2,A1=e=>e==="*";function c3(e,t){let r=e.split("/"),n=r.length;return r.some(A1)&&(n+=l3),t&&(n+=a3),r.filter(i=>!A1(i)).reduce((i,a)=>i+(n3.test(a)?i3:a===""?o3:s3),n)}function u3(e,t){return e.length===t.length&&e.slice(0,-1).every((n,i)=>n===t[i])?e[e.length-1]-t[t.length-1]:0}function d3(e,t,r=!1){let{routesMeta:n}=e,i={},a="/",o=[];for(let s=0;s{if(u==="*"){let g=s[h]||"";o=a.slice(0,a.length-g.length).replace(/(.)\/+$/,"$1")}const m=s[h];return d&&!m?c[u]=void 0:c[u]=(m||"").replace(/%2F/g,"/"),c},{}),pathname:a,pathnameBase:o,pattern:e}}function f3(e,t=!1,r=!0){ln(e==="*"||!e.endsWith("*")||e.endsWith("/*"),`Route path "${e}" will be treated as if it were "${e.replace(/\*$/,"/*")}" because the \`*\` character must always follow a \`/\` in the pattern. To get rid of this warning, please change the route path to "${e.replace(/\*$/,"/*")}".`);let n=[],i="^"+e.replace(/\/*\*?$/,"").replace(/^\/*/,"/").replace(/[\\.*+^${}|()[\]]/g,"\\$&").replace(/\/:([\w-]+)(\?)?/g,(o,s,l)=>(n.push({paramName:s,isOptional:l!=null}),l?"/?([^\\/]+)?":"/([^\\/]+)")).replace(/\/([\w-]+)\?(\/|$)/g,"(/$1)?$2");return e.endsWith("*")?(n.push({paramName:"*"}),i+=e==="*"||e==="/*"?"(.*)$":"(?:\\/(.+)|\\/*)$"):r?i+="\\/*$":e!==""&&e!=="/"&&(i+="(?:(?=\\/|$))"),[new RegExp(i,t?void 0:"i"),n]}function h3(e){try{return e.split("/").map(t=>decodeURIComponent(t).replace(/\//g,"%2F")).join("/")}catch(t){return ln(!1,`The URL path "${e}" could not be decoded because it is a malformed URL segment. This is probably due to a bad percent encoding (${t}).`),e}}function pi(e,t){if(t==="/")return e;if(!e.toLowerCase().startsWith(t.toLowerCase()))return null;let r=t.endsWith("/")?t.length-1:t.length,n=e.charAt(r);return n&&n!=="/"?null:e.slice(r)||"/"}function p3(e,t="/"){let{pathname:r,search:n="",hash:i=""}=typeof e=="string"?Vs(e):e;return{pathname:r?r.startsWith("/")?r:m3(r,t):t,search:y3(n),hash:x3(i)}}function m3(e,t){let r=t.replace(/\/+$/,"").split("/");return e.split("/").forEach(i=>{i===".."?r.length>1&&r.pop():i!=="."&&r.push(i)}),r.length>1?r.join("/"):"/"}function Pm(e,t,r,n){return`Cannot include a '${e}' character in a manually specified \`to.${t}\` field [${JSON.stringify(n)}]. Please separate it out to the \`to.${r}\` field. Alternatively you may provide the full path as a string in and the router will parse it for you.`}function v3(e){return e.filter((t,r)=>r===0||t.route.path&&t.route.path.length>0)}function Ex(e){let t=v3(e);return t.map((r,n)=>n===t.length-1?r.pathname:r.pathnameBase)}function Cx(e,t,r,n=!1){let i;typeof e=="string"?i=Vs(e):(i={...e},ze(!i.pathname||!i.pathname.includes("?"),Pm("?","pathname","search",i)),ze(!i.pathname||!i.pathname.includes("#"),Pm("#","pathname","hash",i)),ze(!i.search||!i.search.includes("#"),Pm("#","search","hash",i)));let a=e===""||i.pathname==="",o=a?"/":i.pathname,s;if(o==null)s=r;else{let d=t.length-1;if(!n&&o.startsWith("..")){let h=o.split("/");for(;h[0]==="..";)h.shift(),d-=1;i.pathname=h.join("/")}s=d>=0?t[d]:"/"}let l=p3(i,s),c=o&&o!=="/"&&o.endsWith("/"),u=(a||o===".")&&r.endsWith("/");return!l.pathname.endsWith("/")&&(c||u)&&(l.pathname+="/"),l}var ai=e=>e.join("/").replace(/\/\/+/g,"/"),g3=e=>e.replace(/\/+$/,"").replace(/^\/*/,"/"),y3=e=>!e||e==="?"?"":e.startsWith("?")?e:"?"+e,x3=e=>!e||e==="#"?"":e.startsWith("#")?e:"#"+e;function w3(e){return e!=null&&typeof e.status=="number"&&typeof e.statusText=="string"&&typeof e.internal=="boolean"&&"data"in e}var HO=["POST","PUT","PATCH","DELETE"];new Set(HO);var b3=["GET",...HO];new Set(b3);var Ys=p.createContext(null);Ys.displayName="DataRouter";var Oh=p.createContext(null);Oh.displayName="DataRouterState";p.createContext(!1);var KO=p.createContext({isTransitioning:!1});KO.displayName="ViewTransition";var S3=p.createContext(new Map);S3.displayName="Fetchers";var P3=p.createContext(null);P3.displayName="Await";var fn=p.createContext(null);fn.displayName="Navigation";var Vc=p.createContext(null);Vc.displayName="Location";var hn=p.createContext({outlet:null,matches:[],isDataRoute:!1});hn.displayName="Route";var Ox=p.createContext(null);Ox.displayName="RouteError";function j3(e,{relative:t}={}){ze(Qs(),"useHref() may be used only in the context of a component.");let{basename:r,navigator:n}=p.useContext(fn),{hash:i,pathname:a,search:o}=Yc(e,{relative:t}),s=a;return r!=="/"&&(s=a==="/"?r:ai([r,a])),n.createHref({pathname:s,search:o,hash:i})}function Qs(){return p.useContext(Vc)!=null}function Pi(){return ze(Qs(),"useLocation() may be used only in the context of a component."),p.useContext(Vc).location}var VO="You should call navigate() in a React.useEffect(), not when your component is first rendered.";function YO(e){p.useContext(fn).static||p.useLayoutEffect(e)}function QO(){let{isDataRoute:e}=p.useContext(hn);return e?F3():E3()}function E3(){ze(Qs(),"useNavigate() may be used only in the context of a component.");let e=p.useContext(Ys),{basename:t,navigator:r}=p.useContext(fn),{matches:n}=p.useContext(hn),{pathname:i}=Pi(),a=JSON.stringify(Ex(n)),o=p.useRef(!1);return YO(()=>{o.current=!0}),p.useCallback((l,c={})=>{if(ln(o.current,VO),!o.current)return;if(typeof l=="number"){r.go(l);return}let u=Cx(l,JSON.parse(a),i,c.relative==="path");e==null&&t!=="/"&&(u.pathname=u.pathname==="/"?t:ai([t,u.pathname])),(c.replace?r.replace:r.push)(u,c.state,c)},[t,r,a,i,e])}var C3=p.createContext(null);function O3(e){let t=p.useContext(hn).outlet;return t&&p.createElement(C3.Provider,{value:e},t)}function Yc(e,{relative:t}={}){let{matches:r}=p.useContext(hn),{pathname:n}=Pi(),i=JSON.stringify(Ex(r));return p.useMemo(()=>Cx(e,JSON.parse(i),n,t==="path"),[e,i,n,t])}function k3(e,t){return GO(e,t)}function GO(e,t,r,n,i){var y;ze(Qs(),"useRoutes() may be used only in the context of a component.");let{navigator:a}=p.useContext(fn),{matches:o}=p.useContext(hn),s=o[o.length-1],l=s?s.params:{},c=s?s.pathname:"/",u=s?s.pathnameBase:"/",d=s&&s.route;{let b=d&&d.path||"";XO(c,!d||b.endsWith("*")||b.endsWith("*?"),`You rendered descendant (or called \`useRoutes()\`) at "${c}" (under ) but the parent route path has no trailing "*". This means if you navigate deeper, the parent won't match anymore and therefore the child routes will never render. - -Please change the parent to .`)}let h=Pi(),m;if(t){let b=typeof t=="string"?Vs(t):t;ze(u==="/"||((y=b.pathname)==null?void 0:y.startsWith(u)),`When overriding the location using \`\` or \`useRoutes(routes, location)\`, the location pathname must begin with the portion of the URL pathname that was matched by all parent routes. The current pathname base is "${u}" but pathname "${b.pathname}" was given in the \`location\` prop.`),m=b}else m=h;let g=m.pathname||"/",v=g;if(u!=="/"){let b=u.replace(/^\//,"").split("/");v="/"+g.replace(/^\//,"").split("/").slice(b.length).join("/")}let x=WO(e,{pathname:v});ln(d||x!=null,`No routes matched location "${m.pathname}${m.search}${m.hash}" `),ln(x==null||x[x.length-1].route.element!==void 0||x[x.length-1].route.Component!==void 0||x[x.length-1].route.lazy!==void 0,`Matched leaf route at location "${m.pathname}${m.search}${m.hash}" does not have an element or Component. This means it will render an with a null value by default resulting in an "empty" page.`);let w=D3(x&&x.map(b=>Object.assign({},b,{params:Object.assign({},l,b.params),pathname:ai([u,a.encodeLocation?a.encodeLocation(b.pathname).pathname:b.pathname]),pathnameBase:b.pathnameBase==="/"?u:ai([u,a.encodeLocation?a.encodeLocation(b.pathnameBase).pathname:b.pathnameBase])})),o,r,n,i);return t&&w?p.createElement(Vc.Provider,{value:{location:{pathname:"/",search:"",hash:"",state:null,key:"default",...m},navigationType:"POP"}},w):w}function N3(){let e=$3(),t=w3(e)?`${e.status} ${e.statusText}`:e instanceof Error?e.message:JSON.stringify(e),r=e instanceof Error?e.stack:null,n="rgba(200,200,200, 0.5)",i={padding:"0.5rem",backgroundColor:n},a={padding:"2px 4px",backgroundColor:n},o=null;return console.error("Error handled by React Router default ErrorBoundary:",e),o=p.createElement(p.Fragment,null,p.createElement("p",null,"💿 Hey developer 👋"),p.createElement("p",null,"You can provide a way better UX than this when your app throws errors by providing your own ",p.createElement("code",{style:a},"ErrorBoundary")," or"," ",p.createElement("code",{style:a},"errorElement")," prop on your route.")),p.createElement(p.Fragment,null,p.createElement("h2",null,"Unexpected Application Error!"),p.createElement("h3",{style:{fontStyle:"italic"}},t),r?p.createElement("pre",{style:i},r):null,o)}var A3=p.createElement(N3,null),T3=class extends p.Component{constructor(e){super(e),this.state={location:e.location,revalidation:e.revalidation,error:e.error}}static getDerivedStateFromError(e){return{error:e}}static getDerivedStateFromProps(e,t){return t.location!==e.location||t.revalidation!=="idle"&&e.revalidation==="idle"?{error:e.error,location:e.location,revalidation:e.revalidation}:{error:e.error!==void 0?e.error:t.error,location:t.location,revalidation:e.revalidation||t.revalidation}}componentDidCatch(e,t){this.props.unstable_onError?this.props.unstable_onError(e,t):console.error("React Router caught the following error during render",e)}render(){return this.state.error!==void 0?p.createElement(hn.Provider,{value:this.props.routeContext},p.createElement(Ox.Provider,{value:this.state.error,children:this.props.component})):this.props.children}};function _3({routeContext:e,match:t,children:r}){let n=p.useContext(Ys);return n&&n.static&&n.staticContext&&(t.route.errorElement||t.route.ErrorBoundary)&&(n.staticContext._deepestRenderedBoundaryId=t.route.id),p.createElement(hn.Provider,{value:e},r)}function D3(e,t=[],r=null,n=null,i=null){if(e==null){if(!r)return null;if(r.errors)e=r.matches;else if(t.length===0&&!r.initialized&&r.matches.length>0)e=r.matches;else return null}let a=e,o=r==null?void 0:r.errors;if(o!=null){let c=a.findIndex(u=>u.route.id&&(o==null?void 0:o[u.route.id])!==void 0);ze(c>=0,`Could not find a matching route for errors on route IDs: ${Object.keys(o).join(",")}`),a=a.slice(0,Math.min(a.length,c+1))}let s=!1,l=-1;if(r)for(let c=0;c=0?a=a.slice(0,l+1):a=[a[0]];break}}}return a.reduceRight((c,u,d)=>{let h,m=!1,g=null,v=null;r&&(h=o&&u.route.id?o[u.route.id]:void 0,g=u.route.errorElement||A3,s&&(l<0&&d===0?(XO("route-fallback",!1,"No `HydrateFallback` element provided to render during initial hydration"),m=!0,v=null):l===d&&(m=!0,v=u.route.hydrateFallbackElement||null)));let x=t.concat(a.slice(0,d+1)),w=()=>{let y;return h?y=g:m?y=v:u.route.Component?y=p.createElement(u.route.Component,null):u.route.element?y=u.route.element:y=c,p.createElement(_3,{match:u,routeContext:{outlet:c,matches:x,isDataRoute:r!=null},children:y})};return r&&(u.route.ErrorBoundary||u.route.errorElement||d===0)?p.createElement(T3,{location:r.location,revalidation:r.revalidation,component:g,error:h,children:w(),routeContext:{outlet:null,matches:x,isDataRoute:!0},unstable_onError:n}):w()},null)}function kx(e){return`${e} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`}function M3(e){let t=p.useContext(Ys);return ze(t,kx(e)),t}function R3(e){let t=p.useContext(Oh);return ze(t,kx(e)),t}function I3(e){let t=p.useContext(hn);return ze(t,kx(e)),t}function Nx(e){let t=I3(e),r=t.matches[t.matches.length-1];return ze(r.route.id,`${e} can only be used on routes that contain a unique "id"`),r.route.id}function L3(){return Nx("useRouteId")}function $3(){var n;let e=p.useContext(Ox),t=R3("useRouteError"),r=Nx("useRouteError");return e!==void 0?e:(n=t.errors)==null?void 0:n[r]}function F3(){let{router:e}=M3("useNavigate"),t=Nx("useNavigate"),r=p.useRef(!1);return YO(()=>{r.current=!0}),p.useCallback(async(i,a={})=>{ln(r.current,VO),r.current&&(typeof i=="number"?e.navigate(i):await e.navigate(i,{fromRouteId:t,...a}))},[e,t])}var T1={};function XO(e,t,r){!t&&!T1[e]&&(T1[e]=!0,ln(!1,r))}p.memo(z3);function z3({routes:e,future:t,state:r,unstable_onError:n}){return GO(e,void 0,r,n,t)}function B3({to:e,replace:t,state:r,relative:n}){ze(Qs()," may be used only in the context of a component.");let{static:i}=p.useContext(fn);ln(!i," must not be used on the initial render in a . This is a no-op, but you should modify your code so the is only ever rendered in response to some user interaction or state change.");let{matches:a}=p.useContext(hn),{pathname:o}=Pi(),s=QO(),l=Cx(e,Ex(a),o,n==="path"),c=JSON.stringify(l);return p.useEffect(()=>{s(JSON.parse(c),{replace:t,state:r,relative:n})},[s,c,n,t,r]),null}function W3(e){return O3(e.context)}function yn(e){ze(!1,"A is only ever to be used as the child of element, never rendered directly. Please wrap your in a .")}function U3({basename:e="/",children:t=null,location:r,navigationType:n="POP",navigator:i,static:a=!1}){ze(!Qs(),"You cannot render a inside another . You should never have more than one in your app.");let o=e.replace(/^\/*/,"/"),s=p.useMemo(()=>({basename:o,navigator:i,static:a,future:{}}),[o,i,a]);typeof r=="string"&&(r=Vs(r));let{pathname:l="/",search:c="",hash:u="",state:d=null,key:h="default"}=r,m=p.useMemo(()=>{let g=pi(l,o);return g==null?null:{location:{pathname:g,search:c,hash:u,state:d,key:h},navigationType:n}},[o,l,c,u,d,h,n]);return ln(m!=null,` is not able to match the URL "${l}${c}${u}" because it does not start with the basename, so the won't render anything.`),m==null?null:p.createElement(fn.Provider,{value:s},p.createElement(Vc.Provider,{children:t,value:m}))}function q3({children:e,location:t}){return k3(vg(e),t)}function vg(e,t=[]){let r=[];return p.Children.forEach(e,(n,i)=>{if(!p.isValidElement(n))return;let a=[...t,i];if(n.type===p.Fragment){r.push.apply(r,vg(n.props.children,a));return}ze(n.type===yn,`[${typeof n.type=="string"?n.type:n.type.name}] is not a component. All component children of must be a or `),ze(!n.props.index||!n.props.children,"An index route cannot have child routes.");let o={id:n.props.id||a.join("-"),caseSensitive:n.props.caseSensitive,element:n.props.element,Component:n.props.Component,index:n.props.index,path:n.props.path,loader:n.props.loader,action:n.props.action,hydrateFallbackElement:n.props.hydrateFallbackElement,HydrateFallback:n.props.HydrateFallback,errorElement:n.props.errorElement,ErrorBoundary:n.props.ErrorBoundary,hasErrorBoundary:n.props.hasErrorBoundary===!0||n.props.ErrorBoundary!=null||n.props.errorElement!=null,shouldRevalidate:n.props.shouldRevalidate,handle:n.props.handle,lazy:n.props.lazy};n.props.children&&(o.children=vg(n.props.children,a)),r.push(o)}),r}var Nd="get",Ad="application/x-www-form-urlencoded";function kh(e){return e!=null&&typeof e.tagName=="string"}function H3(e){return kh(e)&&e.tagName.toLowerCase()==="button"}function K3(e){return kh(e)&&e.tagName.toLowerCase()==="form"}function V3(e){return kh(e)&&e.tagName.toLowerCase()==="input"}function Y3(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}function Q3(e,t){return e.button===0&&(!t||t==="_self")&&!Y3(e)}var Hu=null;function G3(){if(Hu===null)try{new FormData(document.createElement("form"),0),Hu=!1}catch{Hu=!0}return Hu}var X3=new Set(["application/x-www-form-urlencoded","multipart/form-data","text/plain"]);function jm(e){return e!=null&&!X3.has(e)?(ln(!1,`"${e}" is not a valid \`encType\` for \`
\`/\`\` and will default to "${Ad}"`),null):e}function Z3(e,t){let r,n,i,a,o;if(K3(e)){let s=e.getAttribute("action");n=s?pi(s,t):null,r=e.getAttribute("method")||Nd,i=jm(e.getAttribute("enctype"))||Ad,a=new FormData(e)}else if(H3(e)||V3(e)&&(e.type==="submit"||e.type==="image")){let s=e.form;if(s==null)throw new Error('Cannot submit a + + + + + {errorMessage && ( +
+ {errorMessage} +
+ )} + {tasks.length === 0 ? ( +
+ {t("backgroundTasks.empty")} +
+ ) : ( + + + + + + + + + + + + + + + + {tasks.map((task) => { + const status = normalizeStatus(task.status); + const isRerunning = rerunning.has(task.id); + const canRerun = status !== "running"; + const paramsPreview = getParamsPreview(task); + + return ( + + + + + + + + + + + ); + })} + +
+ {t("backgroundTasks.fields.id")} + + {t("backgroundTasks.fields.function")} + + {t("backgroundTasks.fields.status")} + + {t("backgroundTasks.fields.queuedAt")} + + {t("backgroundTasks.fields.startedAt")} + + {t("backgroundTasks.fields.finishedAt")} + + {t("backgroundTasks.fields.duration")} + + {t("backgroundTasks.fields.actions")} +
+
{task.id}
+ {paramsPreview && ( +
+                              {paramsPreview}
+                            
+ )} +
+
+ {task.function_name} +
+
+ {task.function_key} +
+
+ + {t(`backgroundTasks.status.${status}`)} + + {task.error_message && ( +
+ {task.error_message} +
+ )} +
+ {formatTimestamp(task.queued_at)} + + {formatTimestamp(task.started_at)} + + {formatTimestamp(task.ended_at)} + + {formatDuration(task.duration_ms)} + +
+ +
+
+
+ )} +
+ + + ); +} diff --git a/fastapi_radar/radar.py b/fastapi_radar/radar.py index 76fe3f6..5d29677 100644 --- a/fastapi_radar/radar.py +++ b/fastapi_radar/radar.py @@ -14,6 +14,11 @@ from sqlalchemy.pool import StaticPool from .api import create_api_router +from .background_tasks import ( + BackgroundTaskTracker, + create_tasks_websocket_router, + install_background_task_tracker, +) from .capture import QueryCapture from .middleware import RadarMiddleware from .models import Base @@ -57,6 +62,8 @@ def __init__( exclude_paths: Optional[List[str]] = None, theme: str = "auto", enable_tracing: bool = True, + enable_background_tasks: bool = True, + max_background_tasks: int = 1000, service_name: str = "fastapi-app", include_in_schema: bool = True, db_path: Optional[str] = None, @@ -71,9 +78,12 @@ def __init__( self.exclude_paths = exclude_paths or [] self.theme = theme self.enable_tracing = enable_tracing + self.enable_background_tasks = enable_background_tasks + self.max_background_tasks = max_background_tasks self.service_name = service_name self.db_path = db_path self.query_capture = None + self.background_task_tracker: Optional[BackgroundTaskTracker] = None if dashboard_path not in self.exclude_paths: self.exclude_paths.append(dashboard_path) @@ -155,6 +165,9 @@ def __init__( self._setup_middleware() + if self.enable_background_tasks: + self._setup_background_tasks() + if self.db_engine: self._setup_query_capture() @@ -201,9 +214,25 @@ def _setup_query_capture(self) -> None: def _setup_api(self, include_in_schema: bool) -> None: """Mount API endpoints.""" - api_router = create_api_router(self.get_session,self.get_session_factory) + api_router = create_api_router( + self.get_session, + self.get_session_factory, + task_tracker=self.background_task_tracker, + ) self.app.include_router(api_router, include_in_schema=include_in_schema) + def _setup_background_tasks(self) -> None: + tracker = BackgroundTaskTracker(max_tasks=self.max_background_tasks) + install_background_task_tracker(tracker) + self.background_task_tracker = tracker + + websocket_router = create_tasks_websocket_router(tracker) + self.app.include_router( + websocket_router, + prefix=self.dashboard_path, + include_in_schema=False, + ) + def _setup_dashboard(self, include_in_schema: bool) -> None: """Mount dashboard static files.""" from fastapi import Request diff --git a/tests/test_async_radar.py b/tests/test_async_radar.py index 532d15b..d35aa26 100644 --- a/tests/test_async_radar.py +++ b/tests/test_async_radar.py @@ -1,4 +1,4 @@ -from fastapi import FastAPI +from fastapi import BackgroundTasks, FastAPI from fastapi_radar import Radar from sqlalchemy import Column, Integer, MetaData, String, Table, select from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine @@ -53,6 +53,18 @@ async def get_users(): return {"users": [dict(row) for row in rows]} +@app.get("/simulate-task") +async def simulate_task(background_tasks: BackgroundTasks): + """用于测试的后台任务接口,触发一个简单的后台任务。""" + + def sample_task() -> None: + # 这里没有实际工作,仅用于验证后台任务监控逻辑 + print("后台任务") + + background_tasks.add_task(sample_task) + return {"ok": True} + + if __name__ == "__main__": import uvicorn diff --git a/tests/test_radar.py b/tests/test_radar.py index e8e9d39..4297510 100644 --- a/tests/test_radar.py +++ b/tests/test_radar.py @@ -1,6 +1,8 @@ """Test suite for FastAPI Radar.""" -from fastapi import FastAPI +import time + +from fastapi import BackgroundTasks, FastAPI from fastapi.testclient import TestClient from sqlalchemy import create_engine @@ -73,3 +75,49 @@ async def test_endpoint(): assert response.status_code == 200 assert response.json() == {"message": "test"} + + +def test_background_tasks_api(): + """Background task tracker should expose task lifecycle endpoints.""" + app = FastAPI() + engine = create_engine("sqlite:///:memory:") + storage_engine = create_engine("sqlite:///:memory:") + + radar = Radar(app, db_engine=engine, storage_engine=storage_engine) + radar.create_tables() + + execution_log = [] + + def sample_task(): + execution_log.append("ran") + + @app.post("/trigger-task") + async def trigger_task(background_tasks: BackgroundTasks): + background_tasks.add_task(sample_task) + return {"ok": True} + + client = TestClient(app) + trigger_response = client.post("/trigger-task") + assert trigger_response.status_code == 200 + time.sleep(0.05) + assert execution_log, "background task should have executed at least once" + + tasks_response = client.get("/__radar/api/background-tasks") + assert tasks_response.status_code == 200 + tasks = tasks_response.json() + assert isinstance(tasks, list) + assert tasks, "expected at least one tracked task" + + task_id = tasks[0]["id"] + rerun_response = client.post( + f"/__radar/api/background-tasks/{task_id}/rerun", + ) + assert rerun_response.status_code == 200 + time.sleep(0.05) + assert len(execution_log) >= 2, "rerun should execute the task again" + + clear_response = client.delete("/__radar/api/background-tasks") + assert clear_response.status_code == 200 + + cleared_tasks = client.get("/__radar/api/background-tasks").json() + assert cleared_tasks == []