diff --git a/docs/security-review-2026-06.md b/docs/security-review-2026-06.md new file mode 100644 index 0000000..70d8d97 --- /dev/null +++ b/docs/security-review-2026-06.md @@ -0,0 +1,332 @@ +# berth — Security Review (June 2026) + +Reviewer: automated security review on branch `claude/repo-security-review-dn8gpl`. +Scope: full repository — auth & secrets, HTTP API surface, container/exec layer, +persistence/CLI/packaging/CI, and the web UI. + +## Executive summary + +berth's security posture is, on the whole, strong and clearly built with intent. +The high-value controls are present and correct: API keys are HMAC-SHA256 hashed +with a random on-disk pepper, tokens are 256-bit `secrets`-generated, there is no +`shell=True` anywhere (all container launches use exec-form argv), dangerous +deploy options are opt-in behind a config flag, the cluster uses real mTLS with +per-connection fingerprint checks against the node DB, SQL is fully parameterized, +serialization is `yaml.safe_load`/JSON only (no pickle/eval), the web UI has zero +XSS sinks with a no-`unsafe-inline` script CSP, and CI is exemplary (every action +SHA-pinned, default-deny permissions, no `pull_request_target`, secret scanning). + +No **Critical** issues were found. The findings below are one **High** (a real +local credential leak in the VPS installer), a cluster of **Medium** items +(mostly hardening and lateral-movement reduction), and several **Low/Info** +defense-in-depth notes. + +## Findings by severity + +| # | Severity | Area | Finding | +|---|----------|------|---------| +| 1 | **High** | Packaging | Admin API key written to world-readable `/var/log/berth-install.log` | +| 2 | Medium | API/Auth | `/metrics` readable by any tenant key; leaks internal engine addresses & cluster topology | +| 3 | Medium | API/Auth | Admin routes mounted on the public TCP listener; auth bypass keyed on a fragile `scope["client"] is None` heuristic | +| 4 | Medium | Container | Engine images pinned by mutable tag, not digest | +| 5 | Medium | Container | Engine containers run with `ipc_mode: "host"` | +| 6 | Medium | API | SSRF: proxy/adapter/metrics dial `container_address` with no host validation for adopted endpoints | +| 7 | Medium | Auth | Per-key token-rate limits are advisory/post-hoc; non-`/v1` routes unmetered | +| 8 | Low | UI/Auth | Admin API key persisted in browser `localStorage` | +| 9 | Low | API/Auth | Stream ticket transmitted in URL query string (lands in proxy/access logs) | +| 10 | Low | API | Docker log-stream endpoint has no client-disconnect handling (privileged DoS) | +| 11 | Low | Docs | Examples/docs teach `curl -k` while sending Bearer tokens | +| 12 | Low | CLI | `berth wipe --home` guard allows wiping an entire user home dir | +| 13 | Low | CLI | Enrollment token / secrets exposed via argv and shell history | +| 14 | Low | CLI/Backup | Backup hot-snapshot created with default umask | +| 15 | Low | API | Verbose `{e}` / `response.text[:200]` exception echoes to authenticated clients | +| 16 | Info | Container | Cluster mTLS listener uses `CERT_OPTIONAL` rather than `CERT_REQUIRED` | +| 17 | Info | Packaging | Shipped `berth.service` far less hardened than the installer-generated unit | +| 18 | Info | Packaging | curl-pipe-bash install chain; uv installer unpinned | + +--- + +## Detailed findings + +### 1. HIGH — Admin API key leaks into world-readable install log +**File:** `scripts/setup-leader-vps.sh` — `LOG` at line 96, `step` harness line 158, +`do_bootstrap` lines 293–298, invocation line 559, log creation line 525. + +The `step` harness redirects each step's output to `$LOG` +(`/var/log/berth-install.log`) via `( ... ) >>"$LOG" 2>&1`. The bootstrap step +mints the admin-tier API key and `tee`s it to a carefully-protected temp file +(`$BOOTSTRAP_OUT`, `chmod 0600`, deleted on EXIT) — but `tee`'s stdout still flows +into `$LOG`. `$LOG` is created with `: > "$LOG"` under root's default umask +(typically **0644, world-readable**), is never cleaned up, and is advertised in +the install summary. + +**Impact:** any local unprivileged user on the leader VPS can read the admin-tier +key (`sk-…`) and gain full control of the `/admin/*` API — mint keys, deploy +containers, enroll nodes. The contrast with the meticulous `$BOOTSTRAP_OUT` +handling shows the risk was understood; the log path was just missed. + +**Fix:** create the log private — `install -m 0600 /dev/null "$LOG"` or `umask 077` +at the top of the script — and/or redact `sk-[A-Za-z0-9_-]+` from logged output. + +### 2. MEDIUM — `/metrics` readable by any tenant key, leaks cluster internals +**Files:** `src/berth/daemon/metrics_router.py:22-65`, `src/berth/auth/middleware.py:78-102` + +`require_metrics_key` accepts any non-revoked key, including the lowest `trial` +tier. `/metrics` exposes deployment inventory, engine URLs +(`http://{container_address}:{port}`), per-node labels, and active key counts, with +no per-key rate limit. A low-tier tenant can scrape it to map internal container +addresses/ports and cluster topology for lateral-movement reconnaissance. + +**Fix:** require `admin` tier (or a dedicated metrics scope) for `/metrics`, or +strip internal engine addresses from the tenant-visible output. + +### 3. MEDIUM — Admin routes on the public listener gated by a fragile heuristic +**Files:** `src/berth/daemon/app.py:389`, `src/berth/daemon/admin.py:25-36`, +`src/berth/auth/middleware.py:13-17` + +`admin_router` is mounted on the public TCP app, so the full `/admin/*` surface is +externally reachable, gated by `require_admin_key`. That guard bypasses auth when +`_is_uds_request()` is true, which keys on `request.scope.get("client") is None`. +This is correct for stock uvicorn TCP today (peer is always populated), but it is a +single load-bearing implicit check with no defense in depth. berth supports +reverse-proxy mode where proxy-header middleware rewrites `scope["client"]`; any +present or future middleware/listener wiring that leaves `client` unset on a TCP +listener silently turns full admin auth **off**. + +**Fix:** rely solely on the explicit per-app `local_control_surface` flag (set only +on the UDS app); drop the `client is None` clause. Consider not mounting +`admin_router` on the public listener at all if remote admin isn't required. + +### 4. MEDIUM — Engine images pinned by mutable tag, not digest +**Files:** `src/berth/backends/backends.yaml`, `src/berth/lifecycle/docker_client.py:167-168`, `:46-56` + +Images are referenced as `image:tag` (e.g. `vllm/vllm-openai:v0.20.2`) and +pulled/run by tag with no digest pin or verification. Tags are mutable; a registry +compromise or upstream re-tag would launch a substituted image with full GPU access +on every host (including remote agents). The resulting image id is recorded +post-launch but never compared to an expected value. + +**Fix:** pin `@sha256:…` digests per engine and pull/run by digest, or verify the +resolved `container.image.id` against a pinned digest before marking ready. + +### 5. MEDIUM — Engine containers run with host IPC namespace +**File:** `src/berth/backends/base.py:104-119` (`ipc_mode: "host"`, `shm_size: "2g"`) + +`ipc_mode="host"` places engine containers in the host's IPC namespace (shared +SysV shm/semaphores), weakening isolation between container and host and between +co-located engines — a useful primitive in an escape chain, especially given +TRT-LLM's `--trust_remote_code`. The explicit `shm_size: 2g` already provides a +private `/dev/shm`, so host IPC is likely unnecessary for the common case. + +**Fix:** drop `ipc_mode: "host"` unless a specific tensor-parallel/NCCL path needs +it; if so, scope it to those deployments only. + +### 6. MEDIUM — SSRF via unvalidated `container_address` for adopted endpoints +**Files:** `src/berth/daemon/dispatch.py:131-133`, `admin_adapters.py:310-319`/`362-368`, `metrics_router.py:54` + +Upstream URLs are built by interpolating `container_address`/`container_port`. For +managed local containers this comes from the Docker bridge, but for *adopted* +deployments and agent-reported handles it is populated from registration input. A +compromised enrolled agent (or an attacker-influenced adopted endpoint) can set it +to an arbitrary internal host/port, which the leader then dials on the inference +hot path and on adapter load/unload. The `"tunnel"` sentinel correctly blocks +direct-dial for remote deployments — local/adopted addresses are dialed verbatim. + +**Fix:** validate `container_address` is within the expected Docker network range +(or a resolvable container name on the managed network) before dialing; reject +loopback/link-local/metadata addresses for adopted endpoints. + +### 7. MEDIUM — Token-rate limits are advisory; non-`/v1` routes unmetered +**Files:** `src/berth/auth/middleware.py:60-75`, `auth/limiter.py:54-68`, `store/key_usage.py:41-59` + +The usage event is recorded only for `/v1/*` paths, so other authenticated routes +consume no quota. Token-per-window limits (`tpm`/`tpd`) are evaluated against +previously-completed requests because a request's own token cost isn't known at +admission — so a single request can exceed a token budget. Request limits are +enforced correctly; token ceilings are soft by design. + +**Fix:** document token limits as advisory/post-hoc; if hard ceilings are required, +reserve an estimate at admission. Confirm non-`/v1` routes are intended unmetered. + +### 8. LOW — Admin API key persisted in browser `localStorage` +**Files:** `ui/src/api.ts:1-13`, `ui/src/components/TokenGate.tsx:39-51` + +The raw long-lived admin key is stored in `localStorage` (readable by any JS on the +origin, survives restarts). Theft requires XSS or a malicious extension — and the +UI has no XSS sinks today — but the blast radius is total, permanent admin +compromise. Most operators never sign out. + +**Fix:** keep the key in memory (re-prompt per session) or use `sessionStorage`; +longer term, exchange it server-side for a short-lived session token. + +### 9. LOW — Stream ticket transmitted in URL query string +**Files:** `ui/src/api.ts:43-50`, `src/berth/daemon/admin.py:54-86`, `src/berth/auth/stream_tokens.py` + +SSE auth uses a `?stream_token=` ticket because `EventSource` can't set headers. +The ticket is strong (`token_urlsafe(32)`, 60s TTL, single-use, path-bound, minted +only via authenticated POST) and `Referrer-Policy: no-referrer` blocks referrer +leak — but query strings persist in reverse-proxy/access logs. An attacker with log +read access could replay an unconsumed ticket within 60s to read admin event/log +streams. *(Flagged independently by three of the five audits.)* + +**Fix:** deliver the ticket via a short-lived cookie or header rather than the URL, +or document that `forwarded_allow_ips` proxies must not log query strings. + +### 10. LOW — Docker log-stream endpoint lacks disconnect handling +**File:** `src/berth/daemon/admin_runtime.py:135-156` + +`/admin/deployments/current/logs` is a synchronous `follow=True` generator with no +`await request.is_disconnected()` check (unlike the sibling SSE handlers). Abandoned +connections leave blocking log streams attached, tying up threads/Docker attach +handles. Admin-gated, so it's a privileged-DoS/cleanup issue. + +**Fix:** add disconnect detection and an upper bound, mirroring `stream_engine_logs_sse`. + +### 11. LOW — Docs/examples teach `curl -k` with Bearer tokens +**Files:** `examples/README.md:18,23`, `docs/troubleshooting.md:203` + +`curl -k … -H "Authorization: Bearer $BERTH_TOKEN"` sends admin/API tokens over TLS +with verification disabled — an on-path attacker with any cert captures the token. +berth ships its own CA and prints its fingerprint, so the pattern should be +`curl --cacert ~/.berth/ca/ca.crt …`. (Using `-k` solely to fetch the unauthenticated +`/admin/ca.pem` as a TOFU step is acceptable.) + +**Fix:** update docs to pin the CA; reserve `-k` for unauthenticated endpoints. + +### 12. LOW — `berth wipe --home` can wipe an entire user home +**File:** `src/berth/cli/wipe_cmd.py:18-36,112-122` + +`_validated_home` rejects a denylist and paths with `< 3` parts, but `/home/alice` +(exactly 3 parts) passes, after which `_wipe_home` deletes everything in it — not +just berth state. There is a confirm prompt (skippable with `-y`), and the wrapper +auto-escalates `wipe` to root via sudo, compounding the blast radius. + +**Fix:** require a marker (only wipe dirs containing `db.sqlite`/`config.toml`, or +named `.berth`/matching `BERTH_HOME`) and delete only known berth artifacts. + +### 13. LOW — Enrollment token / secrets exposed via argv +**Files:** `src/berth/cli/agent_cmd.py:387-408`, `nodes_cmd.py:81-86` + +`berth agent register --uri 'berth://enroll?…&token=…'` puts the enrollment token +into shell history and `ps`. Mitigations are good (single-use, 10-min expiry, CA +pin), so impact is a narrow race. + +**Fix:** offer reading the URI from stdin / `typer.prompt(hide_input=True)`. + +### 14. LOW — Backup hot-snapshot created with umask permissions +**File:** `src/berth/cli/backup_cmd.py:40-50` + +`sqlite3.connect(snapshot_path)` creates the intermediate snapshot with default +umask (often 0644); the dest dir is `mkdir`ed with default perms. Shielded by +`BERTH_DIR` being 0700 and unlinked in `finally`, so exposure is conditional. The +tarball itself is correctly `0o600`. *(`backup restore` is advertised but not +implemented — no tar-extraction traversal surface exists today; if added, use +`tarfile.extractall(filter="data")`.)* + +**Fix:** pre-create the snapshot via `os.open(..., 0o600)` and `mkdir(mode=0o700)`. + +### 15. LOW — Verbose exception echoes to authenticated clients +**Files:** `src/berth/daemon/admin_workloads.py:385`, `admin_adapters.py:157/321/324`, +`admin_runtime.py:196`, `openai_proxy.py:351/370-371`, `admin_cluster.py:151` + +Several handlers surface raw `{e}` / `response.text[:200]` in HTTP responses, +leaking internal paths, hostnames, and engine internals to authenticated principals. + +**Fix:** log full detail server-side; return generic messages to clients. + +### 16–18. INFO — hardening notes +- **16** `src/berth/daemon/__main__.py:204-212`: cluster mTLS listener uses + `ssl.CERT_OPTIONAL`. The app layer rejects certless connections (`leader_hub.py`), + so not exploitable, but `CERT_REQUIRED` would reject anonymous TLS at the handshake. +- **17** `packaging/berth.service` has only basic sandboxing + (`NoNewPrivileges`, `PrivateTmp`, `ProtectSystem=full`, `ProtectHome`) while the + installer-generated unit adds `ProtectSystem=strict`, `CapabilityBoundingSet=`, + `SystemCallFilter=@system-service`, `UMask=0077`, etc. Sync the sample to the + hardened profile. (Inherent: `ReadWritePaths=/var/run/docker.sock` makes the berth + user root-equivalent on the host — document it.) +- **18** `scripts/install.sh:7-8,87`: curl-pipe-bash usage and an unpinned + `astral.sh/uv/install.sh | sh`. Consider pinning a uv version + checksum and + publishing the outer script's SHA. + +--- + +## Verified-sound practices (checked and found correct) + +- **API-key hashing:** HMAC-SHA256 with a 32-byte random pepper (`secrets.token_bytes`, + file mode 0600, race-guarded init); keys are `sk-` + 256-bit `token_urlsafe`. The + documented rationale for not using `hmac.compare_digest` post-DB is correct (the + secret is hashed to fixed length before an equality `WHERE key_hash=?` lookup). +- **No `shell=True` / no string-interpolated commands** anywhere; container launches + use docker-py exec-form argv; `extra_args` appended as discrete list items. +- **Dangerous deploy options opt-in:** custom image tags, raw `extra_args`, and the + `trust_remote_code` TRT-LLM path are disabled unless `allow_unsafe_deploy_options`. +- **Input sanitization:** `model_name`/adapter/node-label regex-constrained; + model/adapter paths guarded with `resolve().relative_to(models_dir)`; model cache + mounted read-only. +- **No HF_TOKEN leakage** into engine containers; downloads happen host-side, only + resolved weights are mounted ro. +- **Anti-SSRF tunnel sentinel** for remote deployments; **real mTLS** with + per-connection peer-cert fingerprint checks against the node DB (not header-trust); + heartbeat metrics size-capped. +- **SQL fully parameterized;** the only SQL f-strings interpolate program constants. + No pickle/marshal/eval; `yaml.safe_load`/`safe_dump` throughout; malformed + `allowed_models` JSON fails closed to deny-all. +- **No sensitive data persisted:** request metrics store only model/route/status/ + latency; prompts and Authorization headers are never written; the request tracer is + in-memory only. +- **IPC auth:** CLI→daemon is a 0600 Unix socket inside a 0700 dir; no unauthenticated + TCP control channel; TCP always requires Bearer, admin tier enforced on `/admin/*`. +- **File permissions:** `write_private_file` uses `O_NOFOLLOW` + `fchmod(0600)` before + write (no TOCTOU); CA dir 0700, keys 0600. +- **Web UI:** zero XSS sinks (no `dangerouslySetInnerHTML`/`innerHTML`/`eval`, no + markdown renderer); `script-src 'self'` with no `unsafe-inline`/`unsafe-eval`; + `frame-ancestors 'none'` + `X-Frame-Options: DENY`; cookie-free bearer auth (no + CSRF); no source maps or secrets in the bundle; `ignore-scripts=true`; only three + runtime deps, all integrity-hashed. +- **Upstream proxy hardening:** request/response header allowlists strip the client + Authorization and any engine-injected `Set-Cookie`/CORS headers; per-key model + allowlist enforced on the *requested* name before alias resolution (no aliasing + bypass); body-size cap on the public listener. +- **CI exemplary:** all actions SHA-pinned, default-deny `permissions`, no + `pull_request_target`, no untrusted `${{ }}` in `run:`, `npm ci --ignore-scripts`, + bandit + pip-audit + npm audit + gitleaks, provenance + SBOM on releases, + weekly Dependabot + `uv lock --upgrade`. Dependencies current. + +## Remediation status (this branch) + +All actionable findings were addressed on `claude/repo-security-review-dn8gpl`: + +| # | Severity | Status | Where | +|---|----------|--------|-------| +| 1 | High | **Fixed** | `scripts/setup-leader-vps.sh` — log created `install -m 0600`; `sk-…` redaction filter on all logged output | +| 2 | Medium | **Fixed** | `auth/middleware.py` — `/metrics` now requires admin tier (`require_metrics_key`); tests updated | +| 3 | Medium | **Fixed** | `daemon/admin.py`, `auth/middleware.py` — auth bypass now keys solely on the explicit `local_control_surface` flag (dropped the `client is None` heuristic) | +| 4 | Medium | **Fixed** | `lifecycle/docker_client.py` (`verify_image_digest`) + `backends/base.py` (`pinned_digest`) + enforced at launch in `lifecycle/manager.py`; `backends.yaml` documents pinning | +| 5 | Medium | **Fixed** | `backends/base.py` — removed default `ipc_mode: "host"`; relies on private `shm_size` | +| 6 | Medium | **Fixed** | new `berth/net_guard.py` applied in `dispatch.py` + `admin_adapters.py` — adopted endpoints can't dial link-local/metadata/multicast | +| 7 | Medium | **Documented** | `auth/middleware.py` — token-window limits documented as advisory/post-hoc; non-`/v1` routes intentionally unmetered | +| 8 | Low | **Fixed** | `ui/src/api.ts` — admin token moved from `localStorage` to `sessionStorage` | +| 9 | Low | **Documented + mitigated** | `ui/src/api.ts` — rationale + operator proxy-logging note; full fix (fetch-SSE) flagged as follow-up | +| 10 | Low | **Fixed** | `daemon/admin_runtime.py` — `/deployments/current/logs` now async with disconnect detection + stream close | +| 11 | Low | **Fixed** | `examples/README.md`, `docs/troubleshooting.md` — authenticated `curl` uses `--cacert` | +| 12 | Low | **Fixed** | `cli/wipe_cmd.py` — refuses to wipe a dir without a berth marker | +| 13 | Low | **Fixed** | `cli/agent_cmd.py` — enrollment URI via hidden prompt / `BERTH_ENROLL_URI`, off argv | +| 14 | Low | **Fixed** | `cli/backup_cmd.py` — snapshot pre-created `0600`, dest dir `0700` | +| 15 | Low | **Fixed (high-value part)** | `admin_adapters.py` — engine `response.text` no longer echoed to clients (logged server-side); remaining `{e}` echoes are admin-tier-only operational detail, left intentionally | +| 16 | Info | **Won't fix — by design** | The cluster listener also serves the certless enrollment/CA endpoints, so `CERT_REQUIRED` would break agent bootstrap. The app layer already rejects certless WS connections via fingerprint check, so `CERT_OPTIONAL` is correct. | +| 17 | Info | **Fixed** | `packaging/berth.service` — hardening synced to the installer-generated unit; docker.sock note added | +| 18 | Info | **Fixed** | `scripts/install.sh` — uv installer pinned to `UV_VERSION` | + +New regression tests: `tests/unit/test_net_guard.py`, `tests/unit/test_image_digest_pin.py`, +plus updated `test_metrics_auth.py`, `test_wipe_cmd.py`, `test_backup_cmd.py`, +`test_cli_agent_register.py`, and the engine-backend kwargs tests. + +## Recommended remediation order + +1. **Finding 1** (High) — fix the install-log key leak; smallest change, highest impact. +2. **Findings 2, 3** — `/metrics` tier gate and the explicit UDS-flag auth check; + both are small, high-value reductions of admin/recon exposure. +3. **Findings 4, 5, 6** — image digest pinning, drop host IPC, validate + `container_address`; reduce container/lateral-movement risk. +4. **Findings 8–15** — UI token storage, stream-ticket delivery, and the CLI/docs + hardening items as a follow-up batch. diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 2336447..791f257 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -200,7 +200,10 @@ The secret is printed once. Then point a client at it: ```bash export BERTH_TOKEN=sk-... export BERTH_URL=https://127.0.0.1:11500 -curl -k "$BERTH_URL/v1/models" -H "Authorization: Bearer $BERTH_TOKEN" +# The token is a secret, so verify TLS by pinning berth's CA rather than using +# `-k` (which would leak the Bearer token to a MITM). +curl --cacert ~/.berth/ca/ca.crt "$BERTH_URL/v1/models" \ + -H "Authorization: Bearer $BERTH_TOKEN" ``` If a key that used to work suddenly fails everywhere, check that diff --git a/examples/README.md b/examples/README.md index aeba665..515e2d8 100644 --- a/examples/README.md +++ b/examples/README.md @@ -14,13 +14,17 @@ couple of POSTs. They're here so you don't have to write the JSON from scratch. To apply the profile and its route, point `$BERTH_URL` and `$BERTH_TOKEN` at your daemon and POST the two files: +These requests carry an admin Bearer token, so verify TLS — pin berth's CA with +`--cacert` instead of disabling verification with `-k` (which would expose the +token to any MITM). Adjust the path if your CA lives elsewhere. + ```bash -curl -k -X POST "$BERTH_URL/admin/service-profiles" \ +curl --cacert ~/.berth/ca/ca.crt -X POST "$BERTH_URL/admin/service-profiles" \ -H "Authorization: Bearer $BERTH_TOKEN" \ -H "Content-Type: application/json" \ --data @examples/service-profile-qwen.json -curl -k -X POST "$BERTH_URL/admin/routes" \ +curl --cacert ~/.berth/ca/ca.crt -X POST "$BERTH_URL/admin/routes" \ -H "Authorization: Bearer $BERTH_TOKEN" \ -H "Content-Type: application/json" \ --data @examples/service-route-chat.json diff --git a/packaging/berth.service b/packaging/berth.service index 4a59a30..72e0289 100644 --- a/packaging/berth.service +++ b/packaging/berth.service @@ -34,12 +34,41 @@ RestartSec=5 StandardOutput=journal StandardError=journal -# Modest hardening. Loosen these if your deployments need additional -# capabilities (e.g. ReadWritePaths if model weights live elsewhere). +# Process hardening (kept in sync with the installer-generated unit in +# scripts/setup-leader-vps.sh). The daemon listens on high ports and talks to +# Docker over /var/run/docker.sock; it never needs kernel modules, devices, +# raw sockets, or capabilities of any kind. Loosen these only if a deployment +# genuinely requires extra access (e.g. add a ReadWritePaths entry if model +# weights live elsewhere). NoNewPrivileges=true PrivateTmp=true -ProtectSystem=full +PrivateDevices=true +ProtectSystem=strict ProtectHome=true +ProtectKernelTunables=true +ProtectKernelModules=true +ProtectKernelLogs=true +ProtectControlGroups=true +ProtectClock=true +ProtectHostname=true +ProtectProc=invisible +ProcSubset=pid +RestrictNamespaces=true +RestrictRealtime=true +RestrictSUIDSGID=true +LockPersonality=true +RemoveIPC=true +RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 +SystemCallArchitectures=native +SystemCallFilter=@system-service +SystemCallFilter=~@privileged @resources +CapabilityBoundingSet= +AmbientCapabilities= +UMask=0077 +# NOTE: granting write access to /var/run/docker.sock makes the `berth` service +# user effectively root-equivalent on the host (the Docker API can mount the +# host filesystem and launch privileged containers). Drop this entry if the +# daemon does not need to manage Docker on this node. ReadWritePaths=/var/lib/berth /var/run/docker.sock [Install] diff --git a/scripts/install.sh b/scripts/install.sh index 447983f..7b1ec4b 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -8,7 +8,9 @@ set -euo pipefail # curl -fsSL https://example.com/install.sh | bash -s -- --verbose # # What it does: -# 1. Installs `uv` if missing (https://docs.astral.sh/uv/). +# 1. Installs `uv` if missing (https://docs.astral.sh/uv/), pinned to +# $UV_VERSION below. Operators should review this script before piping it +# into a shell, and may override the pin via UV_VERSION=x.y.z. # 2. `uv tool install` the `berth` package (or editable, if run in a checkout). # 3. Runs `berth doctor`. # 4. Prints next steps. @@ -18,6 +20,10 @@ case "${1:-}" in -v|--verbose) VERBOSE=1 ;; esac +# Pin the uv installer to a known version rather than tracking latest. The +# astral installer honours UV_INSTALL_VERSION; operators may override this. +UV_VERSION="${UV_VERSION:-0.5.11}" + # ── output harness ────────────────────────────────────────────────────────── # Unlike the leader installer, steps run in the *current* shell (no subshell): # installing uv mutates PATH for the install-berth step that follows, so the @@ -84,7 +90,9 @@ fi ensure_uv() { command -v uv >/dev/null 2>&1 && return 0 - curl -LsSf https://astral.sh/uv/install.sh | sh || return 1 + # Pin to $UV_VERSION; the installer reads UV_INSTALL_VERSION from the env. + curl -LsSf "https://astral.sh/uv/${UV_VERSION}/install.sh" \ + | env UV_INSTALL_VERSION="$UV_VERSION" sh || return 1 # shellcheck source=/dev/null [ -f "$HOME/.local/share/uv/env" ] && . "$HOME/.local/share/uv/env" export PATH="$HOME/.local/bin:$PATH" diff --git a/scripts/setup-leader-vps.sh b/scripts/setup-leader-vps.sh index b061ead..33550ed 100755 --- a/scripts/setup-leader-vps.sh +++ b/scripts/setup-leader-vps.sh @@ -139,6 +139,11 @@ _fail() { exit 1 } +_redact_secrets() { + # Mask minted API keys (sk-...) so they never persist in $LOG. + sed 's/sk-[A-Za-z0-9_-]\{8,\}/sk-***REDACTED***/g' +} + step() { local label="$1"; shift _step_n=$(( _step_n + 1 )) @@ -150,13 +155,18 @@ step() { # a mid-step failure would slip through. `step` is always called as a plain # statement, which keeps -e honoured all the way down. set +e + # Defense in depth: redact any sk-... secret before it reaches $LOG so the + # admin key never lands on disk even if the file's perms are loosened later. + # (The operator-facing one-time display reads $BOOTSTRAP_OUT, which is 0600 + # and removed on EXIT, so it is unaffected.) if [[ $VERBOSE == 1 ]]; then printf '\n' - ( set -eo pipefail; "$@" ) 2>&1 | tee -a "$LOG" + ( set -eo pipefail; "$@" ) 2>&1 \ + | tee >(_redact_secrets >>"$LOG") rc=${PIPESTATUS[0]} else - ( set -eo pipefail; "$@" ) >>"$LOG" 2>&1 - rc=$? + ( set -eo pipefail; "$@" ) 2>&1 | _redact_secrets >>"$LOG" + rc=${PIPESTATUS[0]} fi set -e (( rc == 0 )) || _fail @@ -522,7 +532,9 @@ do_start_services() { } print_header() { - : > "$LOG" + # Create the log private (0600). The bootstrap step's stdout carries the + # freshly minted sk-... admin key; a world-readable log would leak it. + install -m 0600 /dev/null "$LOG" printf '\n %sberth%s leader installer %s%s%s\n' \ "$_c_accent" "$_c_off" "$_c_dim" "$BASE_DOMAIN" "$_c_off" _rule diff --git a/src/berth/auth/middleware.py b/src/berth/auth/middleware.py index 71742a9..c495016 100644 --- a/src/berth/auth/middleware.py +++ b/src/berth/auth/middleware.py @@ -11,9 +11,11 @@ def _is_local_control_request(request: Request) -> bool: - return request.scope.get("client") is None or bool( - getattr(request.app.state, "local_control_surface", False) - ) + # Trust the explicit per-app flag only (set True solely on the UDS app). + # Inferring locality from ``scope['client'] is None`` is a fragile, + # silently-failing heuristic that could disable auth on a TCP listener; + # the explicit flag fails closed. See _is_uds_request in daemon/admin.py. + return bool(getattr(request.app.state, "local_control_surface", False)) def _extract_bearer(authorization: str | None) -> str | None: @@ -57,6 +59,14 @@ def require_auth_dep(request: Request) -> api_keys.ApiKey | None: tier_cfg: dict[str, Limits] = request.app.state.tier_cfg usage_event_id: int | None = None + # Rate-limit semantics: request-per-window limits (rpm/rpd) are enforced + # hard at admission. Token-per-window limits (tpm/tpd) are necessarily + # *advisory / post-hoc*: a request's own token cost is unknown at admission + # and is backfilled later via key_usage.set_tokens, so the check evaluates + # only previously-completed requests. A single request can therefore exceed + # a token budget; the budget reasserts on the next request. Only /v1/* calls + # record a usage event, so other authenticated routes are intentionally + # unmetered (admin/control traffic is not billed against tenant quotas). with db.locked(conn): decision = limiter.check(conn, key=key, tier_cfg=tier_cfg) if isinstance(decision, limiter.Denied): @@ -76,12 +86,15 @@ def require_auth_dep(request: Request) -> api_keys.ApiKey | None: def require_metrics_key(request: Request) -> api_keys.ApiKey | None: - """Light-weight bearer-auth for /metrics on the public listener. - - Any non-revoked key (no tier requirement) is accepted — the only goal - is to keep the deployment inventory / engine URLs / key counts off - public scrapers. UDS callers bypass (so local control commands over the - local socket still works). + """Bearer-auth for /metrics on the public listener — admin tier only. + + /metrics exposes the deployment inventory, scraped engine metrics, active + key counts, and per-node cluster topology/labels. That is operational + detail useful for reconnaissance, so it is restricted to admin-tier keys + rather than any valid tenant key — a low-tier tenant must not be able to + map internal deployments/nodes. Point Prometheus (etc.) at an admin key. + UDS callers bypass (so local control commands over the local socket still + work). """ if _is_local_control_request(request): return None # UDS — operator surface @@ -99,4 +112,9 @@ def require_metrics_key(request: Request) -> api_keys.ApiKey | None: status.HTTP_401_UNAUTHORIZED, detail="invalid or revoked API key", ) + if key.tier != "admin": + raise HTTPException( + status.HTTP_403_FORBIDDEN, + detail="admin tier required for /metrics", + ) return key diff --git a/src/berth/backends/backends.yaml b/src/berth/backends/backends.yaml index 198b7a6..c8312b7 100644 --- a/src/berth/backends/backends.yaml +++ b/src/berth/backends/backends.yaml @@ -1,9 +1,21 @@ # Pinned engine images. Update via `berth update-engines` or # `berth config set engine..image `. +# +# Optional digest pinning (defense against mutable tags): add a +# `pinned_digest: sha256:<64-hex>` field to any backend below to require the +# launched container's image to match that immutable content digest. When set, +# DockerClient.verify_image_digest enforces it at launch and refuses to mark the +# deployment ready on mismatch. Resolve the digest for a tag with, e.g.: +# docker pull vllm/vllm-openai:v0.20.2 +# docker inspect --format '{{index .RepoDigests 0}}' vllm/vllm-openai:v0.20.2 +# # or, to pin the local image id: +# docker inspect --format '{{.Id}}' vllm/vllm-openai:v0.20.2 +# Left unset by default, so behavior is unchanged until an operator pins one. vllm: image: vllm/vllm-openai pinned_tag: v0.20.2 + # pinned_digest: sha256:... # optional; see header comment above health_path: /health openai_base: /v1 metrics_path: /metrics diff --git a/src/berth/backends/base.py b/src/berth/backends/base.py index 0bf2daa..5eecd3b 100644 --- a/src/berth/backends/base.py +++ b/src/berth/backends/base.py @@ -1,13 +1,34 @@ from __future__ import annotations +from importlib.resources import files from typing import ClassVar, Protocol +import yaml from docker.types import Ulimit # type: ignore[import-untyped] from berth.backends.manifest import EngineManifest, Headroom, load_manifest from berth.lifecycle.plan import DeploymentPlan +def _load_pinned_digest(name: str) -> str | None: + """Read the optional `pinned_digest` for a backend from backends.yaml. + + The shipped manifest leaves this unset; operators add it to pin an image + to an immutable digest. Kept here (rather than on EngineManifest) so the + digest-pin feature lives entirely within the backends layer. Best-effort: + a malformed/missing file yields None (no enforcement) rather than blocking + a deployment on parse failure. + """ + try: + text = files("berth.backends").joinpath("backends.yaml").read_text() + raw = yaml.safe_load(text) or {} + entry = raw.get(name) or {} + digest = entry.get("pinned_digest") + return str(digest) if digest else None + except Exception: + return None + + class Backend(Protocol): @property def name(self) -> str: ... @@ -21,6 +42,8 @@ def adapter_unload_path(self) -> str: ... @property def image_default(self) -> str: ... @property + def pinned_digest(self) -> str | None: ... + @property def health_path(self) -> str: ... @property def openai_base(self) -> str: ... @@ -62,6 +85,19 @@ def __init__(self, manifest: EngineManifest | None = None): def image_default(self) -> str: return self.manifest.image_default + @property + def pinned_digest(self) -> str | None: + """Optional content-addressable digest (`sha256:...`) an operator has + pinned for this engine image in backends.yaml. When set, the running + container's image id is verified against it at launch (see + DockerClient.verify_image_digest) and a mismatch refuses the load. + + `EngineManifest` intentionally does not carry this field, so it is read + from the raw backends.yaml here. Returns None (no enforcement) when + absent - the default - keeping behavior unchanged until pinned. + """ + return _load_pinned_digest(self.name) + @property def health_path(self) -> str: return self.manifest.health_path @@ -105,6 +141,12 @@ def container_env(self, plan: DeploymentPlan) -> dict[str, str]: return {} def container_kwargs(self, plan: DeploymentPlan) -> dict[str, object]: + # No `ipc_mode: host`: host IPC weakens container/host isolation + # (a compromised engine could reach other processes' SysV/POSIX shm). + # The explicit private `shm_size` below covers the single-container + # case, which is what we run. If a future tensor-parallel path needs + # shared-memory IPC across separate containers, make host IPC opt-in + # rather than the unconditional default. return { "device_requests": [ { @@ -113,7 +155,6 @@ def container_kwargs(self, plan: DeploymentPlan) -> dict[str, object]: "Capabilities": [["gpu"]], } ], - "ipc_mode": "host", "shm_size": "2g", "ulimits": [Ulimit(name="memlock", soft=-1, hard=-1)], } diff --git a/src/berth/cli/agent_cmd.py b/src/berth/cli/agent_cmd.py index 7e7da7c..05f5bce 100644 --- a/src/berth/cli/agent_cmd.py +++ b/src/berth/cli/agent_cmd.py @@ -386,10 +386,12 @@ def install_service( @agent_app.command("register") def register( - uri: str = typer.Option( - ..., "--uri", + uri: str | None = typer.Option( + None, "--uri", help="Single-paste enrollment URI from `berth nodes enroll` " - "(format: berth://enroll?leader=...&token=...&ca_fp=...).", + "(format: berth://enroll?leader=...&token=...&ca_fp=...). " + "Omit to be prompted (hidden input) or read from BERTH_ENROLL_URI; " + "this keeps the embedded token out of argv and shell history.", ), reachable_as: str | None = typer.Option( None, "--reachable-as", @@ -399,7 +401,15 @@ def register( """Exchange a one-time enrollment token for a durable agent certificate. The URI bundles the leader URL, token, and CA fingerprint so the - agent can detect a swapped CA during bootstrap.""" + agent can detect a swapped CA during bootstrap. + + The token is a secret, so prefer not to pass it on the command line where it + lands in argv and shell history. Omit ``--uri`` to paste it at a hidden + prompt, or supply it via the ``BERTH_ENROLL_URI`` environment variable.""" + if uri is None: + uri = os.environ.get("BERTH_ENROLL_URI") or typer.prompt( + "Enrollment URI", hide_input=True, + ) leader_url, token_val, ca_fp = parse_enrollment_uri(uri) ca_pem = _fetch_ca_pinned(leader_url, ca_fp) _do_register( diff --git a/src/berth/cli/backup_cmd.py b/src/berth/cli/backup_cmd.py index 4eb51f2..bf46236 100644 --- a/src/berth/cli/backup_cmd.py +++ b/src/berth/cli/backup_cmd.py @@ -33,13 +33,19 @@ def create_backup( ) -> None: """Tarball db.sqlite (consistent .backup snapshot), ca/, key_pepper, config.toml.""" dest_path = Path(dest) - dest_path.parent.mkdir(parents=True, exist_ok=True) + # The backup parent may hold the snapshot and the final tarball, both of + # which contain CA keys / pepper. Create it private (0700) so a freshly + # made backup dir is never world-traversable. + dest_path.parent.mkdir(parents=True, exist_ok=True, mode=0o700) # Take a hot-snapshot of the sqlite file. Using .backup avoids the # well-known WAL-tail truncation bug of a naive `cp db.sqlite`. snapshot_path = ( config.BERTH_DIR / f".db-backup-{int(time.time())}.sqlite" ) + # Pre-create the snapshot file with 0600 before sqlite opens it, so the + # intermediate DB copy is never world-readable under the process umask. + os.close(os.open(snapshot_path, os.O_CREAT | os.O_WRONLY | os.O_TRUNC, 0o600)) src = sqlite3.connect(config.DB_PATH) dst = sqlite3.connect(snapshot_path) try: diff --git a/src/berth/cli/wipe_cmd.py b/src/berth/cli/wipe_cmd.py index 16248c8..aa3065d 100644 --- a/src/berth/cli/wipe_cmd.py +++ b/src/berth/cli/wipe_cmd.py @@ -27,12 +27,39 @@ } +# Files/dirs that mark a directory as a genuine berth state directory. We +# refuse to wipe anything that doesn't look like one, so `--home /home/alice` +# can't be turned into a `rm -rf` of a real user home. +_BERTH_MARKERS = ("db.sqlite", "config.toml", "key_pepper", "ca", "agent.yaml") + + +def _is_berth_home(resolved: Path) -> bool: + """A directory counts as a berth home if it carries a berth marker, is + named `.berth`, or is the configured BERTH_DIR/BERTH_HOME.""" + if resolved.name == ".berth": + return True + try: + configured = config.BERTH_DIR.expanduser().resolve(strict=False) + except Exception: + configured = None + if configured is not None and resolved == configured: + return True + return any((resolved / marker).exists() for marker in _BERTH_MARKERS) + + def _validated_home(home: Path) -> Path: resolved = home.expanduser().resolve(strict=False) if resolved in _DANGEROUS_HOMES or len(resolved.parts) < 3: raise typer.BadParameter(f"refusing to wipe broad path: {resolved}") if resolved.exists() and resolved.is_symlink(): raise typer.BadParameter(f"refusing to wipe symlink: {resolved}") + if resolved.exists() and not _is_berth_home(resolved): + raise typer.BadParameter( + f"refusing to wipe {resolved}: it does not look like a berth home " + "(no db.sqlite/config.toml/ca/key_pepper marker, not named .berth, " + "and not the configured BERTH_HOME). Point --home at the berth " + "state directory." + ) return resolved diff --git a/src/berth/daemon/admin.py b/src/berth/daemon/admin.py index 98e2682..6735aca 100644 --- a/src/berth/daemon/admin.py +++ b/src/berth/daemon/admin.py @@ -23,17 +23,18 @@ def _is_uds_request(request: Request) -> bool: - """True when the request arrived over the Unix domain socket, not TCP. - - Uvicorn's UDS server reports scope['client'] as None (no remote address) - whereas TCP delivers a (host, port) tuple. We use 'client' rather than - 'server' because uvicorn fills 'server' with the listening address even - on UDS (e.g. ('', 0)). + """True when the request arrived over the local control surface (UDS). + + Trust is decided solely by the explicit ``local_control_surface`` flag, + which is set True only on the Unix-domain-socket app (build_apps) and + defaults False on the public/cluster TCP apps. We deliberately do NOT + infer locality from ``scope['client'] is None``: that heuristic is a + single load-bearing check whose failure mode is silent (any future + listener wiring, ASGI middleware, or proxy integration that leaves + 'client' unset on a TCP listener would otherwise disable admin auth + entirely). The explicit per-app flag fails closed instead. """ - client = request.scope.get("client") - return client is None or bool( - getattr(request.app.state, "local_control_surface", False) - ) + return bool(getattr(request.app.state, "local_control_surface", False)) def _is_stream_ticket_path(path: str) -> bool: diff --git a/src/berth/daemon/admin_adapters.py b/src/berth/daemon/admin_adapters.py index 7983c03..26a3a82 100644 --- a/src/berth/daemon/admin_adapters.py +++ b/src/berth/daemon/admin_adapters.py @@ -1,6 +1,7 @@ from __future__ import annotations import asyncio +import logging import re import shutil import sqlite3 @@ -13,10 +14,13 @@ from berth.backends.base import Backend from berth.daemon.admin import get_backends, get_conn, get_manager, router from berth.lifecycle.manager import LifecycleManager +from berth.net_guard import assert_dialable_engine from berth.store import adapters as ad_store from berth.store import deployment_adapters as da_store from berth.store import deployments as dep_store +logger = logging.getLogger("berth.adapters") + _ADAPTER_NAME_RE = re.compile(r"[a-zA-Z0-9_-]+") @@ -307,6 +311,10 @@ async def hot_load_adapter( "model cache; re-register the adapter", ) from e container_path = "/cache/" + str(rel_adapter_path) + try: + assert_dialable_engine(dep) + except ValueError as e: + raise HTTPException(502, str(e)) from e url = ( f"http://{dep.container_address}:{dep.container_port}" f"{backend.adapter_load_path}" @@ -320,8 +328,13 @@ async def hot_load_adapter( except httpx.HTTPError as e: raise HTTPException(502, f"engine adapter load failed: {e}") from e if response.status_code >= 400: + logger.warning( + "adapter load: engine %s returned %s: %s", + dep.id, response.status_code, response.text[:200], + ) raise HTTPException( - 502, f"engine returned {response.status_code}: {response.text[:200]}", + 502, + f"engine rejected adapter load (HTTP {response.status_code})", ) da_store.attach(conn, dep.id, adapter.id) return { @@ -359,6 +372,10 @@ async def hot_unload_adapter( async def _engine_unload_adapter(backend: Backend, dep, adapter_name: str) -> None: if dep.container_address == "tunnel": return # remote — no direct-dial unload path + try: + assert_dialable_engine(dep) + except ValueError: + return # adopted endpoint at an unsafe address — skip the dial url = ( f"http://{dep.container_address}:{dep.container_port}" f"{backend.adapter_unload_path}" diff --git a/src/berth/daemon/admin_runtime.py b/src/berth/daemon/admin_runtime.py index 3f7c512..a629536 100644 --- a/src/berth/daemon/admin_runtime.py +++ b/src/berth/daemon/admin_runtime.py @@ -133,7 +133,7 @@ def metrics_history( @router.get("/deployments/current/logs") -def stream_current_logs(request: Request): +async def stream_current_logs(request: Request): conn: sqlite3.Connection = request.app.state.conn docker_client = request.app.state.manager._docker active = dep_store.find_active(conn) @@ -146,12 +146,25 @@ def stream_current_logs(request: Request): "logs endpoint (which routes through the agent tunnel) instead", ) - def gen(): - for chunk in docker_client.stream_logs(active.container_id, follow=True): - if isinstance(chunk, bytes): - yield chunk - else: - yield chunk.encode() + async def gen(): + # Pull from the blocking follow-stream in a thread so the event loop + # keeps running, and stop as soon as the client disconnects. A purely + # synchronous generator here would pin a threadpool worker and leave + # the Docker attach open after the client walks away. + sync_iter = docker_client.stream_logs(active.container_id, follow=True) + sentinel = object() + try: + while True: + if await request.is_disconnected(): + return + chunk = await asyncio.to_thread(next, sync_iter, sentinel) + if chunk is sentinel: + return + yield chunk if isinstance(chunk, bytes) else chunk.encode() + finally: + close = getattr(sync_iter, "close", None) + if callable(close): + close() return StreamingResponse(gen(), media_type="text/plain") diff --git a/src/berth/daemon/dispatch.py b/src/berth/daemon/dispatch.py index e8b8172..e6c26cc 100644 --- a/src/berth/daemon/dispatch.py +++ b/src/berth/daemon/dispatch.py @@ -128,6 +128,10 @@ async def _open_local( *, engine_client_factory: Callable[[str], httpx.AsyncClient] | None = None, ) -> UpstreamOpen: + # Adopted deployments carry an operator/agent-supplied address; refuse + # to direct-dial known-dangerous SSRF targets (link-local/metadata/etc). + from berth.net_guard import assert_dialable_engine + assert_dialable_engine(deployment) base = ( f"http://{deployment.container_address}:{deployment.container_port}" ) diff --git a/src/berth/lifecycle/docker_client.py b/src/berth/lifecycle/docker_client.py index efcff8b..bace51c 100644 --- a/src/berth/lifecycle/docker_client.py +++ b/src/berth/lifecycle/docker_client.py @@ -12,6 +12,11 @@ log = logging.getLogger(__name__) +class ImageDigestMismatch(RuntimeError): + """Raised when a running container's image does not match the + operator-pinned `pinned_digest`. Refuses to mark the deployment ready.""" + + @dataclass(frozen=True) class ContainerHandle: id: str @@ -129,6 +134,45 @@ def container_image_id(self, container_id: str) -> str | None: return None return getattr(image, "id", None) + def verify_image_digest(self, container_id: str, pinned_digest: str) -> None: + """Verify the running container's image matches the operator-pinned + content-addressable digest, raising `ImageDigestMismatch` on mismatch. + + Tags (``vllm/vllm-openai:vX.Y.Z``) are mutable: upstream can retag the + same name to a different image. When a backend pins a `pinned_digest` + (`sha256:...`) in backends.yaml, we refuse to mark the deployment ready + unless the image actually launched matches that digest. + + The container's image id is taken from `container.image.id` + (see `container_image_id`); `RepoDigests` are also accepted so an + operator may pin either the local image id or a registry repo-digest. + A missing container or unresolvable image id is itself a mismatch - + we cannot prove the running image is the pinned one, so we refuse. + """ + actual_id = self.container_image_id(container_id) + candidates: set[str] = set() + if actual_id: + candidates.add(actual_id) + # Also accept registry repo-digests when present (e.g. when the operator + # pinned the digest as published by the registry rather than the local id). + try: + c = self._client.containers.get(container_id) + image = getattr(c, "image", None) + repo_digests = (getattr(image, "attrs", {}) or {}).get("RepoDigests") or [] + for rd in repo_digests: + # RepoDigests look like "repo@sha256:..."; pin may be the bare digest. + if "@" in rd: + candidates.add(rd.split("@", 1)[1]) + candidates.add(rd) + except NotFound: + pass + if pinned_digest not in candidates: + raise ImageDigestMismatch( + f"image digest mismatch for container {container_id}: " + f"pinned {pinned_digest!r} but running image is " + f"{actual_id!r} (refusing to mark ready)" + ) + def container_pids(self, container_id: str) -> list[int]: """All host-side PIDs running inside the container, including children spawned by the entrypoint (e.g. vLLM EngineCore subprocs). diff --git a/src/berth/lifecycle/manager.py b/src/berth/lifecycle/manager.py index 39ad0be..e2aed89 100644 --- a/src/berth/lifecycle/manager.py +++ b/src/berth/lifecycle/manager.py @@ -13,7 +13,7 @@ from berth.backends.base import Backend from berth.cluster.agent_link import StartedContainer from berth.cluster.agent_registry import AgentRegistry -from berth.lifecycle.docker_client import DockerClient +from berth.lifecycle.docker_client import DockerClient, ImageDigestMismatch from berth.lifecycle.downloader import download_model from berth.lifecycle.kv_estimator import ( KVEstimateInput, @@ -612,6 +612,23 @@ async def load(self, plan: DeploymentPlan): image_digest = None if isinstance(image_digest, str) and image_digest: dep_store.set_image_digest(self._conn, dep.id, image_digest) + # Enforce a content-addressable digest pin when the backend + # declares one. Tags are mutable; if a backend pins `pinned_digest` + # in backends.yaml we refuse to mark the deployment ready unless the + # image that actually launched matches it (registry-substitution / + # retag defense). No-op when unpinned (default). + pinned_digest = getattr(backend, "pinned_digest", None) + if pinned_digest: + try: + self._docker.verify_image_digest(handle.id, pinned_digest) + except ImageDigestMismatch as e: + self._docker.stop(handle.id, timeout=10, remove=True) + msg = str(e) + dep_store.update_status( + self._conn, dep.id, "failed", last_error=msg, + ) + await self._emit("deployment.failed", dep_id=dep.id, error=msg) + raise RuntimeError(msg) from e await self._emit("deployment.spawned", dep_id=dep.id, container_id=handle.id) health_url = f"http://{handle.address}:{handle.port}{backend.health_path}" diff --git a/src/berth/net_guard.py b/src/berth/net_guard.py new file mode 100644 index 0000000..63dfa03 --- /dev/null +++ b/src/berth/net_guard.py @@ -0,0 +1,63 @@ +"""Guards for dialing engine endpoints whose address may be untrusted. + +Managed deployments get their ``container_address`` from berth's own Docker +launch, so it is trusted. *Adopted* deployments (and, transitively, handles +reported by enrolled agents) carry an operator/agent-supplied address that +berth then dials on the inference hot path and for adapter load/unload. That +is an SSRF primitive: a malicious agent or an attacker-influenced adopt +definition could point the leader at an internal service. + +The highest-value SSRF target is the cloud metadata endpoint +(169.254.169.254, inside the link-local range). We block that class of +address for adopted endpoints while deliberately *allowing* loopback and +ordinary private/public addresses — adopting an engine running on localhost +or a LAN host is a legitimate workflow. Non-IP hostnames pass through; the +operator owns their DNS. +""" +from __future__ import annotations + +from ipaddress import ip_address + +# The "tunnel" sentinel means a remote deployment reachable only via the +# agent WS tunnel; it is never direct-dialed (callers special-case it). +TUNNEL_SENTINEL = "tunnel" + + +def is_blocked_adopted_address(address: str | None) -> bool: + """True when an adopted deployment's address is an unsafe SSRF target. + + Only IP-literal addresses are inspected. We block link-local + (169.254.0.0/16 — includes the 169.254.169.254 cloud metadata + endpoint), multicast, reserved, and the unspecified address. Loopback + and ordinary private/public addresses are allowed (legitimate + adopt-localhost / adopt-LAN). Non-IP hostnames return False — the + operator is trusted for their own DNS. + """ + if not address or address == TUNNEL_SENTINEL: + return False + try: + ip = ip_address(address) + except ValueError: + return False + return ( + ip.is_link_local + or ip.is_multicast + or ip.is_reserved + or ip.is_unspecified + ) + + +def assert_dialable_engine(deployment) -> None: + """Raise ValueError if an adopted deployment points at an unsafe address. + + No-op for managed deployments (trusted address) and for the tunnel + sentinel (never direct-dialed). + """ + if getattr(deployment, "source", "managed") != "adopted": + return + address = getattr(deployment, "container_address", None) + if is_blocked_adopted_address(address): + raise ValueError( + f"refusing to dial adopted engine at unsafe address {address!r} " + "(link-local/metadata/multicast addresses are blocked)" + ) diff --git a/src/berth/ui/assets/index-BCvkwgrI.js b/src/berth/ui/assets/index-CtxOWras.js similarity index 83% rename from src/berth/ui/assets/index-BCvkwgrI.js rename to src/berth/ui/assets/index-CtxOWras.js index e10d9e2..58e1890 100644 --- a/src/berth/ui/assets/index-BCvkwgrI.js +++ b/src/berth/ui/assets/index-CtxOWras.js @@ -6,6 +6,6 @@ var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r= `+c[r].replace(` at new `,` at `);return e.displayName&&u.includes(``)&&(u=u.replace(``,e.displayName)),u}while(1<=r&&0<=i);break}}}finally{Ee=!1,Error.prepareStackTrace=n}return(n=e?e.displayName||e.name:``)?Te(n):``}function Oe(e,t){switch(e.tag){case 26:case 27:case 5:return Te(e.type);case 16:return Te(`Lazy`);case 13:return e.child!==t&&t!==null?Te(`Suspense Fallback`):Te(`Suspense`);case 19:return Te(`SuspenseList`);case 0:case 15:return De(e.type,!1);case 11:return De(e.type.render,!1);case 1:return De(e.type,!0);case 31:return Te(`Activity`);default:return``}}function ke(e){try{var t=``,n=null;do t+=Oe(e,n),n=e,e=e.return;while(e);return t}catch(e){return` Error generating stack: `+e.message+` `+e.stack}}var Ae=Object.prototype.hasOwnProperty,je=t.unstable_scheduleCallback,Me=t.unstable_cancelCallback,Ne=t.unstable_shouldYield,Pe=t.unstable_requestPaint,Fe=t.unstable_now,Ie=t.unstable_getCurrentPriorityLevel,Le=t.unstable_ImmediatePriority,Re=t.unstable_UserBlockingPriority,ze=t.unstable_NormalPriority,Be=t.unstable_LowPriority,Ve=t.unstable_IdlePriority,He=t.log,Ue=t.unstable_setDisableYieldValue,We=null,Ge=null;function Ke(e){if(typeof He==`function`&&Ue(e),Ge&&typeof Ge.setStrictMode==`function`)try{Ge.setStrictMode(We,e)}catch{}}var qe=Math.clz32?Math.clz32:Xe,Je=Math.log,Ye=Math.LN2;function Xe(e){return e>>>=0,e===0?32:31-(Je(e)/Ye|0)|0}var Ze=256,Qe=262144,$e=4194304;function et(e){var t=e&42;if(t!==0)return t;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:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&261888;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function tt(e,t,n){var r=e.pendingLanes;if(r===0)return 0;var i=0,a=e.suspendedLanes,o=e.pingedLanes;e=e.warmLanes;var s=r&134217727;return s===0?(s=r&~a,s===0?o===0?n||(n=r&~e,n!==0&&(i=et(n))):i=et(o):i=et(s)):(r=s&~a,r===0?(o&=s,o===0?n||(n=s&~e,n!==0&&(i=et(n))):i=et(o)):i=et(r)),i===0?0:t!==0&&t!==i&&(t&a)===0&&(a=i&-i,n=t&-t,a>=n||a===32&&n&4194048)?t:i}function k(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function A(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32: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 t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function nt(){var e=$e;return $e<<=1,!($e&62914560)&&($e=4194304),e}function rt(e){for(var t=[],n=0;31>n;n++)t.push(e);return t}function it(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function at(e,t,n,r,i,a){var o=e.pendingLanes;e.pendingLanes=n,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=n,e.entangledLanes&=n,e.errorRecoveryDisabledLanes&=n,e.shellSuspendCounter=0;var s=e.entanglements,c=e.expirationTimes,l=e.hiddenUpdates;for(n=o&~n;0`u`||window.document===void 0||window.document.createElement===void 0),mn=!1;if(pn)try{var hn={};Object.defineProperty(hn,"passive",{get:function(){mn=!0}}),window.addEventListener(`test`,hn,hn),window.removeEventListener(`test`,hn,hn)}catch{mn=!1}var gn=null,_n=null,vn=null;function yn(){if(vn)return vn;var e,t=_n,n=t.length,r,i=`value`in gn?gn.value:gn.textContent,a=i.length;for(e=0;e=Zn),er=` `,tr=!1;function nr(e,t){switch(e){case`keyup`:return Yn.indexOf(t.keyCode)!==-1;case`keydown`:return t.keyCode!==229;case`keypress`:case`mousedown`:case`focusout`:return!0;default:return!1}}function rr(e){return e=e.detail,typeof e==`object`&&`data`in e?e.data:null}var ir=!1;function ar(e,t){switch(e){case`compositionend`:return rr(t);case`keypress`:return t.which===32?(tr=!0,er):null;case`textInput`:return e=t.data,e===er&&tr?null:e;default:return null}}function or(e,t){if(ir)return e===`compositionend`||!Xn&&nr(e,t)?(e=yn(),vn=_n=gn=null,ir=!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:n,offset:t-e};e=r}a:{for(;n;){if(n.nextSibling){n=n.nextSibling;break a}n=n.parentNode}n=void 0}n=Or(n)}}function Ar(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Ar(e,t.parentNode):`contains`in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function jr(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var t=Bt(e.document);t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href==`string`}catch{n=!1}if(n)e=t.contentWindow;else break;t=Bt(e.document)}return t}function Mr(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`)}var Nr=pn&&`documentMode`in document&&11>=document.documentMode,Pr=null,Fr=null,Ir=null,Lr=!1;function Rr(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;Lr||Pr==null||Pr!==Bt(r)||(r=Pr,`selectionStart`in r&&Mr(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),Ir&&Dr(Ir,r)||(Ir=r,r=Ed(Fr,`onSelect`),0>=o,i-=o,Ai=1<<32-qe(t)+i|n<h?(g=d,d=null):g=d.sibling;var _=p(i,d,s[h],c);if(_===null){d===null&&(d=g);break}e&&d&&_.alternate===null&&t(i,d),a=o(_,a,h),u===null?l=_:u.sibling=_,u=_,d=g}if(h===s.length)return n(i,d),I&&Mi(i,h),l;if(d===null){for(;hg?(_=h,h=null):_=h.sibling;var y=p(a,h,v.value,l);if(y===null){h===null&&(h=_);break}e&&h&&y.alternate===null&&t(a,h),s=o(y,s,g),d===null?u=y:d.sibling=y,d=y,h=_}if(v.done)return n(a,h),I&&Mi(a,g),u;if(h===null){for(;!v.done;g++,v=c.next())v=f(a,v.value,l),v!==null&&(s=o(v,s,g),d===null?u=v:d.sibling=v,d=v);return I&&Mi(a,g),u}for(h=r(h);!v.done;g++,v=c.next())v=m(h,a,g,v.value,l),v!==null&&(e&&v.alternate!==null&&h.delete(v.key===null?g:v.key),s=o(v,s,g),d===null?u=v:d.sibling=v,d=v);return e&&h.forEach(function(e){return t(a,e)}),I&&Mi(a,g),u}function b(e,r,o,c){if(typeof o==`object`&&o&&o.type===y&&o.key===null&&(o=o.props.children),typeof o==`object`&&o){switch(o.$$typeof){case _:a:{for(var l=o.key;r!==null;){if(r.key===l){if(l=o.type,l===y){if(r.tag===7){n(e,r.sibling),c=a(r,o.props.children),c.return=e,e=c;break a}}else if(r.elementType===l||typeof l==`object`&&l&&l.$$typeof===w&&Aa(l)===r.type){n(e,r.sibling),c=a(r,o.props),La(c,o),c.return=e,e=c;break a}n(e,r);break}else t(e,r);r=r.sibling}o.type===y?(c=_i(o.props.children,e.mode,c,o.key),c.return=e,e=c):(c=gi(o.type,o.key,o.props,null,e.mode,c),La(c,o),c.return=e,e=c)}return s(e);case v:a:{for(l=o.key;r!==null;){if(r.key===l)if(r.tag===4&&r.stateNode.containerInfo===o.containerInfo&&r.stateNode.implementation===o.implementation){n(e,r.sibling),c=a(r,o.children||[]),c.return=e,e=c;break a}else{n(e,r);break}else t(e,r);r=r.sibling}c=bi(o,e.mode,c),c.return=e,e=c}return s(e);case w:return o=Aa(o),b(e,r,o,c)}if(ue(o))return h(e,r,o,c);if(se(o)){if(l=se(o),typeof l!=`function`)throw Error(i(150));return o=l.call(o),g(e,r,o,c)}if(typeof o.then==`function`)return b(e,r,Ia(o),c);if(o.$$typeof===S)return b(e,r,aa(e,o),c);Ra(e,o)}return typeof o==`string`&&o!==``||typeof o==`number`||typeof o==`bigint`?(o=``+o,r!==null&&r.tag===6?(n(e,r.sibling),c=a(r,o),c.return=e,e=c):(n(e,r),c=vi(o,e.mode,c),c.return=e,e=c),s(e)):n(e,r)}return function(e,t,n,r){try{Fa=0;var i=b(e,t,n,r);return Pa=null,i}catch(t){if(t===wa||t===Ea)throw t;var a=fi(29,t,null,e.mode);return a.lanes=r,a.return=e,a}}}var Ba=za(!0),Va=za(!1),Ha=!1;function Ua(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function Wa(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,callbacks:null})}function Ga(e){return{lane:e,tag:0,payload:null,callback:null,next:null}}function Ka(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,G&2){var i=r.pending;return i===null?t.next=t:(t.next=i.next,i.next=t),r.pending=t,t=li(e),ci(e,null,n),t}return ai(e,r,t,n),li(e)}function qa(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,n&4194048)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,st(e,n)}}function Ja(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var i=null,a=null;if(n=n.firstBaseUpdate,n!==null){do{var o={lane:n.lane,tag:n.tag,payload:n.payload,callback:null,next:null};a===null?i=a=o:a=a.next=o,n=n.next}while(n!==null);a===null?i=a=t:a=a.next=t}else i=a=t;n={baseState:r.baseState,firstBaseUpdate:i,lastBaseUpdate:a,shared:r.shared,callbacks:r.callbacks},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}var Ya=!1;function Xa(){if(Ya){var e=ha;if(e!==null)throw e}}function Za(e,t,n,r){Ya=!1;var i=e.updateQueue;Ha=!1;var a=i.firstBaseUpdate,o=i.lastBaseUpdate,s=i.shared.pending;if(s!==null){i.shared.pending=null;var c=s,l=c.next;c.next=null,o===null?a=l:o.next=l,o=c;var u=e.alternate;u!==null&&(u=u.updateQueue,s=u.lastBaseUpdate,s!==o&&(s===null?u.firstBaseUpdate=l:s.next=l,u.lastBaseUpdate=c))}if(a!==null){var d=i.baseState;o=0,u=l=c=null,s=a;do{var f=s.lane&-536870913,p=f!==s.lane;if(p?(J&f)===f:(r&f)===f){f!==0&&f===ma&&(Ya=!0),u!==null&&(u=u.next={lane:0,tag:s.tag,payload:s.payload,callback:null,next:null});a:{var m=e,g=s;f=t;var _=n;switch(g.tag){case 1:if(m=g.payload,typeof m==`function`){d=m.call(_,d,f);break a}d=m;break a;case 3:m.flags=m.flags&-65537|128;case 0:if(m=g.payload,f=typeof m==`function`?m.call(_,d,f):m,f==null)break a;d=h({},d,f);break a;case 2:Ha=!0}}f=s.callback,f!==null&&(e.flags|=64,p&&(e.flags|=8192),p=i.callbacks,p===null?i.callbacks=[f]:p.push(f))}else p={lane:f,tag:s.tag,payload:s.payload,callback:s.callback,next:null},u===null?(l=u=p,c=d):u=u.next=p,o|=f;if(s=s.next,s===null){if(s=i.shared.pending,s===null)break;p=s,s=p.next,p.next=null,i.lastBaseUpdate=p,i.shared.pending=null}}while(1);u===null&&(c=d),i.baseState=c,i.firstBaseUpdate=l,i.lastBaseUpdate=u,a===null&&(i.shared.lanes=0),Gl|=o,e.lanes=o,e.memoizedState=d}}function Qa(e,t){if(typeof e!=`function`)throw Error(i(191,e));e.call(t)}function $a(e,t){var n=e.callbacks;if(n!==null)for(e.callbacks=null,e=0;ea?a:8;var o=T.T,s={};T.T=s,Fs(e,!1,t,n);try{var c=i(),l=T.S;l!==null&&l(s,c),typeof c==`object`&&c&&typeof c.then==`function`?Ps(e,t,va(c,r),pu(e)):Ps(e,t,r,pu(e))}catch(n){Ps(e,t,{then:function(){},status:`rejected`,reason:n},pu())}finally{E.p=a,o!==null&&s.types!==null&&(o.types=s.types),T.T=o}}function ws(){}function Ts(e,t,n,r){if(e.tag!==5)throw Error(i(476));var a=Es(e).queue;Cs(e,a,t,de,n===null?ws:function(){return Ds(e),n(r)})}function Es(e){var t=e.memoizedState;if(t!==null)return t;t={memoizedState:de,baseState:de,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Io,lastRenderedState:de},next:null};var n={};return t.next={memoizedState:n,baseState:n,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Io,lastRenderedState:n},next:null},e.memoizedState=t,e=e.alternate,e!==null&&(e.memoizedState=t),t}function Ds(e){var t=Es(e);t.next===null&&(t=e.alternate.memoizedState),Ps(e,t.next.queue,{},pu())}function Os(){return ia(Qf)}function ks(){return H().memoizedState}function As(){return H().memoizedState}function js(e){for(var t=e.return;t!==null;){switch(t.tag){case 24:case 3:var n=pu();e=Ga(n);var r=Ka(t,e,n);r!==null&&(hu(r,t,n),qa(r,t,n)),t={cache:ua()},e.payload=t;return}t=t.return}}function Ms(e,t,n){var r=pu();n={lane:r,revertLane:0,gesture:null,action:n,hasEagerState:!1,eagerState:null,next:null},Is(e)?Ls(t,n):(n=oi(e,t,n,r),n!==null&&(hu(n,e,r),Rs(n,t,r)))}function Ns(e,t,n){Ps(e,t,n,pu())}function Ps(e,t,n,r){var i={lane:r,revertLane:0,gesture:null,action:n,hasEagerState:!1,eagerState:null,next:null};if(Is(e))Ls(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,n);if(i.hasEagerState=!0,i.eagerState=s,Er(s,o))return ai(e,t,i,0),K===null&&ii(),!1}catch{}if(n=oi(e,t,i,r),n!==null)return hu(n,e,r),Rs(n,t,r),!0}return!1}function Fs(e,t,n,r){if(r={lane:2,revertLane:dd(),gesture:null,action:r,hasEagerState:!1,eagerState:null,next:null},Is(e)){if(t)throw Error(i(479))}else t=oi(e,n,r,2),t!==null&&hu(t,e,2)}function Is(e){var t=e.alternate;return e===z||t!==null&&t===z}function Ls(e,t){_o=go=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Rs(e,t,n){if(n&4194048){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,st(e,n)}}var zs={readContext:ia,use:Po,useCallback:V,useContext:V,useEffect:V,useImperativeHandle:V,useLayoutEffect:V,useInsertionEffect:V,useMemo:V,useReducer:V,useRef:V,useState:V,useDebugValue:V,useDeferredValue:V,useTransition:V,useSyncExternalStore:V,useId:V,useHostTransitionStatus:V,useFormState:V,useActionState:V,useOptimistic:V,useMemoCache:V,useCacheRefresh:V};zs.useEffectEvent=V;var Bs={readContext:ia,use:Po,useCallback:function(e,t){return jo().memoizedState=[e,t===void 0?null:t],e},useContext:ia,useEffect:us,useImperativeHandle:function(e,t,n){n=n==null?null:n.concat([e]),cs(4194308,4,gs.bind(null,t,e),n)},useLayoutEffect:function(e,t){return cs(4194308,4,e,t)},useInsertionEffect:function(e,t){cs(4,2,e,t)},useMemo:function(e,t){var n=jo();t=t===void 0?null:t;var r=e();if(vo){Ke(!0);try{e()}finally{Ke(!1)}}return n.memoizedState=[r,t],r},useReducer:function(e,t,n){var r=jo();if(n!==void 0){var i=n(t);if(vo){Ke(!0);try{n(t)}finally{Ke(!1)}}}else i=t;return r.memoizedState=r.baseState=i,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:i},r.queue=e,e=e.dispatch=Ms.bind(null,z,e),[r.memoizedState,e]},useRef:function(e){var t=jo();return e={current:e},t.memoizedState=e},useState:function(e){e=Ko(e);var t=e.queue,n=Ns.bind(null,z,t);return t.dispatch=n,[e.memoizedState,n]},useDebugValue:vs,useDeferredValue:function(e,t){return xs(jo(),e,t)},useTransition:function(){var e=Ko(!1);return e=Cs.bind(null,z,e.queue,!0,!1),jo().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,t,n){var r=z,a=jo();if(I){if(n===void 0)throw Error(i(407));n=n()}else{if(n=t(),K===null)throw Error(i(349));J&127||Vo(r,t,n)}a.memoizedState=n;var o={value:n,getSnapshot:t};return a.queue=o,us(Uo.bind(null,r,o,e),[e]),r.flags|=2048,os(9,{destroy:void 0},Ho.bind(null,r,o,n,t),null),n},useId:function(){var e=jo(),t=K.identifierPrefix;if(I){var n=ji,r=Ai;n=(r&~(1<<32-qe(r)-1)).toString(32)+n,t=`_`+t+`R_`+n,n=yo++,0<\/script>`,o=o.removeChild(o.firstChild);break;case`select`:o=typeof r.is==`string`?s.createElement(`select`,{is:r.is}):s.createElement(`select`),r.multiple?o.multiple=!0:r.size&&(o.size=r.size);break;default:o=typeof r.is==`string`?s.createElement(a,{is:r.is}):s.createElement(a)}}o[mt]=t,o[ht]=r;a:for(s=t.child;s!==null;){if(s.tag===5||s.tag===6)o.appendChild(s.stateNode);else if(s.tag!==4&&s.tag!==27&&s.child!==null){s.child.return=s,s=s.child;continue}if(s===t)break a;for(;s.sibling===null;){if(s.return===null||s.return===t)break a;s=s.return}s.sibling.return=s.return,s=s.sibling}t.stateNode=o;a:switch(Pd(o,a,r),a){case`button`:case`input`:case`select`:case`textarea`:r=!!r.autoFocus;break a;case`img`:r=!0;break a;default:r=!1}r&&Pc(t)}}return U(t),Fc(t,t.type,e===null?null:e.memoizedProps,t.pendingProps,n),null;case 6:if(e&&t.stateNode!=null)e.memoizedProps!==r&&Pc(t);else{if(typeof r!=`string`&&t.stateNode===null)throw Error(i(166));if(e=ve.current,Wi(t)){if(e=t.stateNode,n=t.memoizedProps,r=null,a=Li,a!==null)switch(a.tag){case 27:case 5:r=a.memoizedProps}e[mt]=t,e=!!(e.nodeValue===n||r!==null&&!0===r.suppressHydrationWarning||Md(e.nodeValue,n)),e||Vi(t,!0)}else e=Bd(e).createTextNode(r),e[mt]=t,t.stateNode=e}return U(t),null;case 31:if(n=t.memoizedState,e===null||e.memoizedState!==null){if(r=Wi(t),n!==null){if(e===null){if(!r)throw Error(i(318));if(e=t.memoizedState,e=e===null?null:e.dehydrated,!e)throw Error(i(557));e[mt]=t}else Gi(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;U(t),e=!1}else n=Ki(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=n),e=!0;if(!e)return t.flags&256?(fo(t),t):(fo(t),null);if(t.flags&128)throw Error(i(558))}return U(t),null;case 13:if(r=t.memoizedState,e===null||e.memoizedState!==null&&e.memoizedState.dehydrated!==null){if(a=Wi(t),r!==null&&r.dehydrated!==null){if(e===null){if(!a)throw Error(i(318));if(a=t.memoizedState,a=a===null?null:a.dehydrated,!a)throw Error(i(317));a[mt]=t}else Gi(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;U(t),a=!1}else a=Ki(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=a),a=!0;if(!a)return t.flags&256?(fo(t),t):(fo(t),null)}return fo(t),t.flags&128?(t.lanes=n,t):(n=r!==null,e=e!==null&&e.memoizedState!==null,n&&(r=t.child,a=null,r.alternate!==null&&r.alternate.memoizedState!==null&&r.alternate.memoizedState.cachePool!==null&&(a=r.alternate.memoizedState.cachePool.pool),o=null,r.memoizedState!==null&&r.memoizedState.cachePool!==null&&(o=r.memoizedState.cachePool.pool),o!==a&&(r.flags|=2048)),n!==e&&n&&(t.child.flags|=8192),Lc(t,t.updateQueue),U(t),null);case 4:return xe(),e===null&&Sd(t.stateNode.containerInfo),U(t),null;case 10:return Qi(t.type),U(t),null;case 19:if(he(R),r=t.memoizedState,r===null)return U(t),null;if(a=(t.flags&128)!=0,o=r.rendering,o===null)if(a)Rc(r,!1);else{if(X!==0||e!==null&&e.flags&128)for(e=t.child;e!==null;){if(o=po(e),o!==null){for(t.flags|=128,Rc(r,!1),e=o.updateQueue,t.updateQueue=e,Lc(t,e),t.subtreeFlags=0,e=n,n=t.child;n!==null;)hi(n,e),n=n.sibling;return D(R,R.current&1|2),I&&Mi(t,r.treeForkCount),t.child}e=e.sibling}r.tail!==null&&Fe()>tu&&(t.flags|=128,a=!0,Rc(r,!1),t.lanes=4194304)}else{if(!a)if(e=po(o),e!==null){if(t.flags|=128,a=!0,e=e.updateQueue,t.updateQueue=e,Lc(t,e),Rc(r,!0),r.tail===null&&r.tailMode===`hidden`&&!o.alternate&&!I)return U(t),null}else 2*Fe()-r.renderingStartTime>tu&&n!==536870912&&(t.flags|=128,a=!0,Rc(r,!1),t.lanes=4194304);r.isBackwards?(o.sibling=t.child,t.child=o):(e=r.last,e===null?t.child=o:e.sibling=o,r.last=o)}return r.tail===null?(U(t),null):(e=r.tail,r.rendering=e,r.tail=e.sibling,r.renderingStartTime=Fe(),e.sibling=null,n=R.current,D(R,a?n&1|2:n&1),I&&Mi(t,r.treeForkCount),e);case 22:case 23:return fo(t),io(),r=t.memoizedState!==null,e===null?r&&(t.flags|=8192):e.memoizedState!==null!==r&&(t.flags|=8192),r?n&536870912&&!(t.flags&128)&&(U(t),t.subtreeFlags&6&&(t.flags|=8192)):U(t),n=t.updateQueue,n!==null&&Lc(t,n.retryQueue),n=null,e!==null&&e.memoizedState!==null&&e.memoizedState.cachePool!==null&&(n=e.memoizedState.cachePool.pool),r=null,t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(r=t.memoizedState.cachePool.pool),r!==n&&(t.flags|=2048),e!==null&&he(ba),null;case 24:return n=null,e!==null&&(n=e.memoizedState.cache),t.memoizedState.cache!==n&&(t.flags|=2048),Qi(L),U(t),null;case 25:return null;case 30:return null}throw Error(i(156,t.tag))}function Bc(e,t){switch(Fi(t),t.tag){case 1:return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return Qi(L),xe(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 26:case 27:case 5:return Ce(t),null;case 31:if(t.memoizedState!==null){if(fo(t),t.alternate===null)throw Error(i(340));Gi()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 13:if(fo(t),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(i(340));Gi()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return he(R),null;case 4:return xe(),null;case 10:return Qi(t.type),null;case 22:case 23:return fo(t),io(),e!==null&&he(ba),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 24:return Qi(L),null;case 25:return null;default:return null}}function Vc(e,t){switch(Fi(t),t.tag){case 3:Qi(L),xe();break;case 26:case 27:case 5:Ce(t);break;case 4:xe();break;case 31:t.memoizedState!==null&&fo(t);break;case 13:fo(t);break;case 19:he(R);break;case 10:Qi(t.type);break;case 22:case 23:fo(t),io(),e!==null&&he(ba);break;case 24:Qi(L)}}function Hc(e,t){try{var n=t.updateQueue,r=n===null?null:n.lastEffect;if(r!==null){var i=r.next;n=i;do{if((n.tag&e)===e){r=void 0;var a=n.create,o=n.inst;r=a(),o.destroy=r}n=n.next}while(n!==i)}}catch(e){Z(t,t.return,e)}}function Uc(e,t,n){try{var r=t.updateQueue,i=r===null?null:r.lastEffect;if(i!==null){var a=i.next;r=a;do{if((r.tag&e)===e){var o=r.inst,s=o.destroy;if(s!==void 0){o.destroy=void 0,i=t;var c=n,l=s;try{l()}catch(e){Z(i,c,e)}}}r=r.next}while(r!==a)}}catch(e){Z(t,t.return,e)}}function Wc(e){var t=e.updateQueue;if(t!==null){var n=e.stateNode;try{$a(t,n)}catch(t){Z(e,e.return,t)}}}function Gc(e,t,n){n.props=qs(e.type,e.memoizedProps),n.state=e.memoizedState;try{n.componentWillUnmount()}catch(n){Z(e,t,n)}}function Kc(e,t){try{var n=e.ref;if(n!==null){switch(e.tag){case 26:case 27:case 5:var r=e.stateNode;break;case 30:r=e.stateNode;break;default:r=e.stateNode}typeof n==`function`?e.refCleanup=n(r):n.current=r}}catch(n){Z(e,t,n)}}function qc(e,t){var n=e.ref,r=e.refCleanup;if(n!==null)if(typeof r==`function`)try{r()}catch(n){Z(e,t,n)}finally{e.refCleanup=null,e=e.alternate,e!=null&&(e.refCleanup=null)}else if(typeof n==`function`)try{n(null)}catch(n){Z(e,t,n)}else n.current=null}function Jc(e){var t=e.type,n=e.memoizedProps,r=e.stateNode;try{a:switch(t){case`button`:case`input`:case`select`:case`textarea`:n.autoFocus&&r.focus();break a;case`img`:n.src?r.src=n.src:n.srcSet&&(r.srcset=n.srcSet)}}catch(t){Z(e,e.return,t)}}function Yc(e,t,n){try{var r=e.stateNode;Fd(r,e.type,n,t),r[ht]=t}catch(t){Z(e,e.return,t)}}function Xc(e){return e.tag===5||e.tag===3||e.tag===26||e.tag===27&&Zd(e.type)||e.tag===4}function Zc(e){a:for(;;){for(;e.sibling===null;){if(e.return===null||Xc(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.tag===27&&Zd(e.type)||e.flags&2||e.child===null||e.tag===4)continue a;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Qc(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?(n.nodeType===9?n.body:n.nodeName===`HTML`?n.ownerDocument.body:n).insertBefore(e,t):(t=n.nodeType===9?n.body:n.nodeName===`HTML`?n.ownerDocument.body:n,t.appendChild(e),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=rn));else if(r!==4&&(r===27&&Zd(e.type)&&(n=e.stateNode,t=null),e=e.child,e!==null))for(Qc(e,t,n),e=e.sibling;e!==null;)Qc(e,t,n),e=e.sibling}function $c(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(r===27&&Zd(e.type)&&(n=e.stateNode),e=e.child,e!==null))for($c(e,t,n),e=e.sibling;e!==null;)$c(e,t,n),e=e.sibling}function el(e){var t=e.stateNode,n=e.memoizedProps;try{for(var r=e.type,i=t.attributes;i.length;)t.removeAttributeNode(i[0]);Pd(t,r,n),t[mt]=e,t[ht]=n}catch(t){Z(e,e.return,t)}}var tl=!1,nl=!1,rl=!1,il=typeof WeakSet==`function`?WeakSet:Set,al=null;function ol(e,t){if(e=e.containerInfo,Rd=sp,e=jr(e),Mr(e)){if(`selectionStart`in e)var n={start:e.selectionStart,end:e.selectionEnd};else a:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var a=r.anchorOffset,o=r.focusNode;r=r.focusOffset;try{n.nodeType,o.nodeType}catch{n=null;break a}var s=0,c=-1,l=-1,u=0,d=0,f=e,p=null;b:for(;;){for(var m;f!==n||a!==0&&f.nodeType!==3||(c=s+a),f!==o||r!==0&&f.nodeType!==3||(l=s+r),f.nodeType===3&&(s+=f.nodeValue.length),(m=f.firstChild)!==null;)p=f,f=m;for(;;){if(f===e)break b;if(p===n&&++u===a&&(c=s),p===o&&++d===r&&(l=s),(m=f.nextSibling)!==null)break;f=p,p=f.parentNode}f=m}n=c===-1||l===-1?null:{start:c,end:l}}else n=null}n||={start:0,end:0}}else n=null;for(zd={focusedElem:e,selectionRange:n},sp=!1,al=t;al!==null;)if(t=al,e=t.child,t.subtreeFlags&1028&&e!==null)e.return=t,al=e;else for(;al!==null;){switch(t=al,o=t.alternate,e=t.flags,t.tag){case 0:if(e&4&&(e=t.updateQueue,e=e===null?null:e.events,e!==null))for(n=0;n title`))),Pd(o,r,n),o[mt]=e,Tt(o),r=o;break a;case`link`:var s=Vf(`link`,`href`,a).get(r+(n.href||``));if(s){for(var c=0;cg&&(o=g,g=h,h=o);var _=kr(s,h),v=kr(s,g);if(_&&v&&(p.rangeCount!==1||p.anchorNode!==_.node||p.anchorOffset!==_.offset||p.focusNode!==v.node||p.focusOffset!==v.offset)){var y=d.createRange();y.setStart(_.node,_.offset),p.removeAllRanges(),h>g?(p.addRange(y),p.extend(v.node,v.offset)):(y.setEnd(v.node,v.offset),p.addRange(y))}}}}for(d=[],p=s;p=p.parentNode;)p.nodeType===1&&d.push({element:p,left:p.scrollLeft,top:p.scrollTop});for(typeof s.focus==`function`&&s.focus(),s=0;sn?32:n,T.T=null,n=lu,lu=null;var o=au,s=su;if(iu=0,ou=au=null,su=0,G&6)throw Error(i(331));var c=G;if(G|=4,Fl(o.current),Dl(o,o.current,s,n),G=c,id(0,!1),Ge&&typeof Ge.onPostCommitFiberRoot==`function`)try{Ge.onPostCommitFiberRoot(We,o)}catch{}return!0}finally{E.p=a,T.T=r,Vu(e,t)}}function Wu(e,t,n){t=Si(n,t),t=$s(e.stateNode,t,2),e=Ka(e,t,2),e!==null&&(it(e,2),rd(e))}function Z(e,t,n){if(e.tag===3)Wu(e,e,n);else for(;t!==null;){if(t.tag===3){Wu(t,e,n);break}else if(t.tag===1){var r=t.stateNode;if(typeof t.type.getDerivedStateFromError==`function`||typeof r.componentDidCatch==`function`&&(ru===null||!ru.has(r))){e=Si(n,e),n=ec(2),r=Ka(t,n,2),r!==null&&(tc(n,r,t,e),it(r,2),rd(r));break}}t=t.return}}function Gu(e,t,n){var r=e.pingCache;if(r===null){r=e.pingCache=new zl;var i=new Set;r.set(t,i)}else i=r.get(t),i===void 0&&(i=new Set,r.set(t,i));i.has(n)||(Ul=!0,i.add(n),e=Ku.bind(null,e,t,n),t.then(e,e))}function Ku(e,t,n){var r=e.pingCache;r!==null&&r.delete(t),e.pingedLanes|=e.suspendedLanes&n,e.warmLanes&=~n,K===e&&(J&n)===n&&(X===4||X===3&&(J&62914560)===J&&300>Fe()-$l?!(G&2)&&Su(e,0):ql|=n,Yl===J&&(Yl=0)),rd(e)}function qu(e,t){t===0&&(t=nt()),e=si(e,t),e!==null&&(it(e,t),rd(e))}function Ju(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),qu(e,n)}function Yu(e,t){var n=0;switch(e.tag){case 31:case 13:var r=e.stateNode,a=e.memoizedState;a!==null&&(n=a.retryLane);break;case 19:r=e.stateNode;break;case 22:r=e.stateNode._retryCache;break;default:throw Error(i(314))}r!==null&&r.delete(t),qu(e,n)}function Xu(e,t){return je(e,t)}var Zu=null,Qu=null,$u=!1,ed=!1,td=!1,nd=0;function rd(e){e!==Qu&&e.next===null&&(Qu===null?Zu=Qu=e:Qu=Qu.next=e),ed=!0,$u||($u=!0,ud())}function id(e,t){if(!td&&ed){td=!0;do for(var n=!1,r=Zu;r!==null;){if(!t)if(e!==0){var i=r.pendingLanes;if(i===0)var a=0;else{var o=r.suspendedLanes,s=r.pingedLanes;a=(1<<31-qe(42|e)+1)-1,a&=i&~(o&~s),a=a&201326741?a&201326741|1:a?a|2:0}a!==0&&(n=!0,ld(r,a))}else a=J,a=tt(r,r===K?a:0,r.cancelPendingCommit!==null||r.timeoutHandle!==-1),!(a&3)||k(r,a)||(n=!0,ld(r,a));r=r.next}while(n);td=!1}}function ad(){od()}function od(){ed=$u=!1;var e=0;nd!==0&&Gd()&&(e=nd);for(var t=Fe(),n=null,r=Zu;r!==null;){var i=r.next,a=sd(r,t);a===0?(r.next=null,n===null?Zu=i:n.next=i,i===null&&(Qu=n)):(n=r,(e!==0||a&3)&&(ed=!0)),r=i}iu!==0&&iu!==5||id(e,!1),nd!==0&&(nd=0)}function sd(e,t){for(var n=e.suspendedLanes,r=e.pingedLanes,i=e.expirationTimes,a=e.pendingLanes&-62914561;0s)break;var u=c.transferSize,d=c.initiatorType;u&&Id(d)&&(c=c.responseEnd,o+=u*(c`u`?null:document;function xf(e,t,n){var r=bf;if(r&&typeof t==`string`&&t){var i=Ht(t);i=`link[rel="`+e+`"][href="`+i+`"]`,typeof n==`string`&&(i+=`[crossorigin="`+n+`"]`),hf.has(i)||(hf.add(i),e={rel:e,crossOrigin:n,href:t},r.querySelector(i)===null&&(t=r.createElement(`link`),Pd(t,`link`,e),Tt(t),r.head.appendChild(t)))}}function Sf(e){_f.D(e),xf(`dns-prefetch`,e,null)}function Cf(e,t){_f.C(e,t),xf(`preconnect`,e,t)}function wf(e,t,n){_f.L(e,t,n);var r=bf;if(r&&e&&t){var i=`link[rel="preload"][as="`+Ht(t)+`"]`;t===`image`&&n&&n.imageSrcSet?(i+=`[imagesrcset="`+Ht(n.imageSrcSet)+`"]`,typeof n.imageSizes==`string`&&(i+=`[imagesizes="`+Ht(n.imageSizes)+`"]`)):i+=`[href="`+Ht(e)+`"]`;var a=i;switch(t){case`style`:a=Af(e);break;case`script`:a=Pf(e)}mf.has(a)||(e=h({rel:`preload`,href:t===`image`&&n&&n.imageSrcSet?void 0:e,as:t},n),mf.set(a,e),r.querySelector(i)!==null||t===`style`&&r.querySelector(jf(a))||t===`script`&&r.querySelector(Ff(a))||(t=r.createElement(`link`),Pd(t,`link`,e),Tt(t),r.head.appendChild(t)))}}function Tf(e,t){_f.m(e,t);var n=bf;if(n&&e){var r=t&&typeof t.as==`string`?t.as:`script`,i=`link[rel="modulepreload"][as="`+Ht(r)+`"][href="`+Ht(e)+`"]`,a=i;switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:a=Pf(e)}if(!mf.has(a)&&(e=h({rel:`modulepreload`,href:e},t),mf.set(a,e),n.querySelector(i)===null)){switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:if(n.querySelector(Ff(a)))return}r=n.createElement(`link`),Pd(r,`link`,e),Tt(r),n.head.appendChild(r)}}}function Ef(e,t,n){_f.S(e,t,n);var r=bf;if(r&&e){var i=M(r).hoistableStyles,a=Af(e);t||=`default`;var o=i.get(a);if(!o){var s={loading:0,preload:null};if(o=r.querySelector(jf(a)))s.loading=5;else{e=h({rel:`stylesheet`,href:e,"data-precedence":t},n),(n=mf.get(a))&&Rf(e,n);var c=o=r.createElement(`link`);Tt(c),Pd(c,`link`,e),c._p=new Promise(function(e,t){c.onload=e,c.onerror=t}),c.addEventListener(`load`,function(){s.loading|=1}),c.addEventListener(`error`,function(){s.loading|=2}),s.loading|=4,Lf(o,t,r)}o={type:`stylesheet`,instance:o,count:1,state:s},i.set(a,o)}}}function Df(e,t){_f.X(e,t);var n=bf;if(n&&e){var r=M(n).hoistableScripts,i=Pf(e),a=r.get(i);a||(a=n.querySelector(Ff(i)),a||(e=h({src:e,async:!0},t),(t=mf.get(i))&&zf(e,t),a=n.createElement(`script`),Tt(a),Pd(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function Of(e,t){_f.M(e,t);var n=bf;if(n&&e){var r=M(n).hoistableScripts,i=Pf(e),a=r.get(i);a||(a=n.querySelector(Ff(i)),a||(e=h({src:e,async:!0,type:`module`},t),(t=mf.get(i))&&zf(e,t),a=n.createElement(`script`),Tt(a),Pd(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function kf(e,t,n,r){var a=(a=ve.current)?gf(a):null;if(!a)throw Error(i(446));switch(e){case`meta`:case`title`:return null;case`style`:return typeof n.precedence==`string`&&typeof n.href==`string`?(t=Af(n.href),n=M(a).hoistableStyles,r=n.get(t),r||(r={type:`style`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};case`link`:if(n.rel===`stylesheet`&&typeof n.href==`string`&&typeof n.precedence==`string`){e=Af(n.href);var o=M(a).hoistableStyles,s=o.get(e);if(s||(a=a.ownerDocument||a,s={type:`stylesheet`,instance:null,count:0,state:{loading:0,preload:null}},o.set(e,s),(o=a.querySelector(jf(e)))&&!o._p&&(s.instance=o,s.state.loading=5),mf.has(e)||(n={rel:`preload`,as:`style`,href:n.href,crossOrigin:n.crossOrigin,integrity:n.integrity,media:n.media,hrefLang:n.hrefLang,referrerPolicy:n.referrerPolicy},mf.set(e,n),o||Nf(a,e,n,s.state))),t&&r===null)throw Error(i(528,``));return s}if(t&&r!==null)throw Error(i(529,``));return null;case`script`:return t=n.async,n=n.src,typeof n==`string`&&t&&typeof t!=`function`&&typeof t!=`symbol`?(t=Pf(n),n=M(a).hoistableScripts,r=n.get(t),r||(r={type:`script`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};default:throw Error(i(444,e))}}function Af(e){return`href="`+Ht(e)+`"`}function jf(e){return`link[rel="stylesheet"][`+e+`]`}function Mf(e){return h({},e,{"data-precedence":e.precedence,precedence:null})}function Nf(e,t,n,r){e.querySelector(`link[rel="preload"][as="style"][`+t+`]`)?r.loading=1:(t=e.createElement(`link`),r.preload=t,t.addEventListener(`load`,function(){return r.loading|=1}),t.addEventListener(`error`,function(){return r.loading|=2}),Pd(t,`link`,n),Tt(t),e.head.appendChild(t))}function Pf(e){return`[src="`+Ht(e)+`"]`}function Ff(e){return`script[async]`+e}function If(e,t,n){if(t.count++,t.instance===null)switch(t.type){case`style`:var r=e.querySelector(`style[data-href~="`+Ht(n.href)+`"]`);if(r)return t.instance=r,Tt(r),r;var a=h({},n,{"data-href":n.href,"data-precedence":n.precedence,href:null,precedence:null});return r=(e.ownerDocument||e).createElement(`style`),Tt(r),Pd(r,`style`,a),Lf(r,n.precedence,e),t.instance=r;case`stylesheet`:a=Af(n.href);var o=e.querySelector(jf(a));if(o)return t.state.loading|=4,t.instance=o,Tt(o),o;r=Mf(n),(a=mf.get(a))&&Rf(r,a),o=(e.ownerDocument||e).createElement(`link`),Tt(o);var s=o;return s._p=new Promise(function(e,t){s.onload=e,s.onerror=t}),Pd(o,`link`,r),t.state.loading|=4,Lf(o,n.precedence,e),t.instance=o;case`script`:return o=Pf(n.src),(a=e.querySelector(Ff(o)))?(t.instance=a,Tt(a),a):(r=n,(a=mf.get(o))&&(r=h({},n),zf(r,a)),e=e.ownerDocument||e,a=e.createElement(`script`),Tt(a),Pd(a,`link`,r),e.head.appendChild(a),t.instance=a);case`void`:return null;default:throw Error(i(443,t.type))}else t.type===`stylesheet`&&!(t.state.loading&4)&&(r=t.instance,t.state.loading|=4,Lf(r,n.precedence,e));return t.instance}function Lf(e,t,n){for(var r=n.querySelectorAll(`link[rel="stylesheet"][data-precedence],style[data-precedence]`),i=r.length?r[r.length-1]:null,a=i,o=0;o title`):null)}function Uf(e,t,n){if(n===1||t.itemProp!=null)return!1;switch(e){case`meta`:case`title`:return!0;case`style`:if(typeof t.precedence!=`string`||typeof t.href!=`string`||t.href===``)break;return!0;case`link`:if(typeof t.rel!=`string`||typeof t.href!=`string`||t.href===``||t.onLoad||t.onError)break;switch(t.rel){case`stylesheet`:return e=t.disabled,typeof t.precedence==`string`&&e==null;default:return!0}case`script`:if(t.async&&typeof t.async!=`function`&&typeof t.async!=`symbol`&&!t.onLoad&&!t.onError&&t.src&&typeof t.src==`string`)return!0}return!1}function Wf(e){return!(e.type===`stylesheet`&&!(e.state.loading&3))}function Gf(e,t,n,r){if(n.type===`stylesheet`&&(typeof r.media!=`string`||!1!==matchMedia(r.media).matches)&&!(n.state.loading&4)){if(n.instance===null){var i=Af(r.href),a=t.querySelector(jf(i));if(a){t=a._p,typeof t==`object`&&t&&typeof t.then==`function`&&(e.count++,e=Jf.bind(e),t.then(e,e)),n.state.loading|=4,n.instance=a,Tt(a);return}a=t.ownerDocument||t,r=Mf(r),(i=mf.get(i))&&Rf(r,i),a=a.createElement(`link`),Tt(a);var o=a;o._p=new Promise(function(e,t){o.onload=e,o.onerror=t}),Pd(a,`link`,r),n.instance=a}e.stylesheets===null&&(e.stylesheets=new Map),e.stylesheets.set(n,t),(t=n.state.preload)&&!(n.state.loading&3)&&(e.count++,n=Jf.bind(e),t.addEventListener(`load`,n),t.addEventListener(`error`,n))}}var Kf=0;function qf(e,t){return e.stylesheets&&e.count===0&&Xf(e,e.stylesheets),0Kf?50:800)+t);return e.unsuspend=n,function(){e.unsuspend=null,clearTimeout(r),clearTimeout(i)}}:null}function Jf(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)Xf(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var Yf=null;function Xf(e,t){e.stylesheets=null,e.unsuspend!==null&&(e.count++,Yf=new Map,t.forEach(Zf,e),Yf=null,Jf.call(e))}function Zf(e,t){if(!(t.state.loading&4)){var n=Yf.get(e);if(n)var r=n.get(null);else{n=new Map,Yf.set(e,n);for(var i=e.querySelectorAll(`link[data-precedence],style[data-precedence]`),a=0;a{function n(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>`u`||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=`function`))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}n(),t.exports=h()})),_=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(){}},v=new class extends _{#e;#t;#n;constructor(){super(),this.#n=e=>{if(typeof window<`u`&&window.addEventListener){let t=()=>e();return window.addEventListener(`visibilitychange`,t,!1),()=>{window.removeEventListener(`visibilitychange`,t)}}}}onSubscribe(){this.#t||this.setEventListener(this.#n)}onUnsubscribe(){this.hasListeners()||(this.#t?.(),this.#t=void 0)}setEventListener(e){this.#n=e,this.#t?.(),this.#t=e(e=>{typeof e==`boolean`?this.setFocused(e):this.onFocus()})}setFocused(e){this.#e!==e&&(this.#e=e,this.onFocus())}onFocus(){let e=this.isFocused();this.listeners.forEach(t=>{t(e)})}isFocused(){return typeof this.#e==`boolean`?this.#e:globalThis.document?.visibilityState!==`hidden`}},y={setTimeout:(e,t)=>setTimeout(e,t),clearTimeout:e=>clearTimeout(e),setInterval:(e,t)=>setInterval(e,t),clearInterval:e=>clearInterval(e)},b=new class{#e=y;setTimeoutProvider(e){this.#e=e}setTimeout(e,t){return this.#e.setTimeout(e,t)}clearTimeout(e){this.#e.clearTimeout(e)}setInterval(e,t){return this.#e.setInterval(e,t)}clearInterval(e){this.#e.clearInterval(e)}};function x(e){setTimeout(e,0)}var ee=typeof window>`u`||`Deno`in globalThis;function S(){}function C(e,t){return typeof e==`function`?e(t):e}function te(e){return typeof e==`number`&&e>=0&&e!==1/0}function ne(e,t){return Math.max(e+(t||0)-Date.now(),0)}function re(e,t){return typeof e==`function`?e(t):e}function w(e,t){return typeof e==`function`?e(t):e}function ie(e,t){let{type:n=`all`,exact:r,fetchStatus:i,predicate:a,queryKey:o,stale:s}=e;if(o){if(r){if(t.queryHash!==oe(o,t.options))return!1}else if(!ce(t.queryKey,o))return!1}if(n!==`all`){let e=t.isActive();if(n===`active`&&!e||n===`inactive`&&e)return!1}return!(typeof s==`boolean`&&t.isStale()!==s||i&&i!==t.state.fetchStatus||a&&!a(t))}function ae(e,t){let{exact:n,status:r,predicate:i,mutationKey:a}=e;if(a){if(!t.options.mutationKey)return!1;if(n){if(se(t.options.mutationKey)!==se(a))return!1}else if(!ce(t.options.mutationKey,a))return!1}return!(r&&t.state.status!==r||i&&!i(t))}function oe(e,t){return(t?.queryKeyHashFn||se)(e)}function se(e){return JSON.stringify(e,(e,t)=>de(t)?Object.keys(t).sort().reduce((e,n)=>(e[n]=t[n],e),{}):t)}function ce(e,t){return e===t?!0:typeof e==typeof t&&e&&t&&typeof e==`object`&&typeof t==`object`?Object.keys(t).every(n=>ce(e[n],t[n])):!1}var le=Object.prototype.hasOwnProperty;function ue(e,t,n=0){if(e===t)return e;if(n>500)return t;let r=E(e)&&E(t);if(!r&&!(de(e)&&de(t)))return t;let i=(r?e:Object.keys(e)).length,a=r?t:Object.keys(t),o=a.length,s=r?Array(o):{},c=0;for(let l=0;l{b.setTimeout(t,e)})}function me(e,t,n){return typeof n.structuralSharing==`function`?n.structuralSharing(e,t):n.structuralSharing===!1?t:ue(e,t)}function he(e,t,n=0){let r=[...e,t];return n&&r.length>n?r.slice(1):r}function D(e,t,n=0){let r=[t,...e];return n&&r.length>n?r.slice(0,-1):r}var ge=Symbol();function _e(e,t){return!e.queryFn&&t?.initialPromise?()=>t.initialPromise:!e.queryFn||e.queryFn===ge?()=>Promise.reject(Error(`Missing queryFn: '${e.queryHash}'`)):e.queryFn}function ve(e,t){return typeof e==`function`?e(...t):!!e}function ye(e,t,n){let r=!1,i;return Object.defineProperty(e,"signal",{enumerable:!0,get:()=>(i??=t(),r?i:(r=!0,i.aborted?n():i.addEventListener(`abort`,n,{once:!0}),i))}),e}var be=(()=>{let e=()=>ee;return{isServer(){return e()},setIsServer(t){e=t}}})();function xe(){let e,t,n=new Promise((n,r)=>{e=n,t=r});n.status=`pending`,n.catch(()=>{});function r(e){Object.assign(n,e),delete n.resolve,delete n.reject}return n.resolve=t=>{r({status:`fulfilled`,value:t}),e(t)},n.reject=e=>{r({status:`rejected`,reason:e}),t(e)},n}var Se=x;function Ce(){let e=[],t=0,n=e=>{e()},r=e=>{e()},i=Se,a=r=>{t?e.push(r):i(()=>{n(r)})},o=()=>{let t=e;e=[],t.length&&i(()=>{r(()=>{t.forEach(e=>{n(e)})})})};return{batch:e=>{let n;t++;try{n=e()}finally{t--,t||o()}return n},batchCalls:e=>(...t)=>{a(()=>{e(...t)})},schedule:a,setNotifyFunction:e=>{n=e},setBatchNotifyFunction:e=>{r=e},setScheduler:e=>{i=e}}}var O=Ce(),we=new class extends _{#e=!0;#t;#n;constructor(){super(),this.#n=e=>{if(typeof window<`u`&&window.addEventListener){let t=()=>e(!0),n=()=>e(!1);return window.addEventListener(`online`,t,!1),window.addEventListener(`offline`,n,!1),()=>{window.removeEventListener(`online`,t),window.removeEventListener(`offline`,n)}}}}onSubscribe(){this.#t||this.setEventListener(this.#n)}onUnsubscribe(){this.hasListeners()||(this.#t?.(),this.#t=void 0)}setEventListener(e){this.#n=e,this.#t?.(),this.#t=e(this.setOnline.bind(this))}setOnline(e){this.#e!==e&&(this.#e=e,this.listeners.forEach(t=>{t(e)}))}isOnline(){return this.#e}};function Te(e){return Math.min(1e3*2**e,3e4)}function Ee(e){return(e??`online`)===`online`?we.isOnline():!0}var De=class extends Error{constructor(e){super(`CancelledError`),this.revert=e?.revert,this.silent=e?.silent}};function Oe(e){let t=!1,n=0,r,i=xe(),a=()=>i.status!==`pending`,o=t=>{if(!a()){let n=new De(t);f(n),e.onCancel?.(n)}},s=()=>{t=!0},c=()=>{t=!1},l=()=>v.isFocused()&&(e.networkMode===`always`||we.isOnline())&&e.canRun(),u=()=>Ee(e.networkMode)&&e.canRun(),d=e=>{a()||(r?.(),i.resolve(e))},f=e=>{a()||(r?.(),i.reject(e))},p=()=>new Promise(t=>{r=e=>{(a()||l())&&t(e)},e.onPause?.()}).then(()=>{r=void 0,a()||e.onContinue?.()}),m=()=>{if(a())return;let r,i=n===0?e.initialPromise:void 0;try{r=i??e.fn()}catch(e){r=Promise.reject(e)}Promise.resolve(r).then(d).catch(r=>{if(a())return;let i=e.retry??(be.isServer()?0:3),o=e.retryDelay??Te,s=typeof o==`function`?o(n,r):o,c=i===!0||typeof i==`number`&&nl()?void 0:p()).then(()=>{t?f(r):m()})})};return{promise:i,status:()=>i.status,cancel:o,continue:()=>(r?.(),i),cancelRetry:s,continueRetry:c,canStart:u,start:()=>(u()?m():p().then(m),i)}}var ke=class{#e;destroy(){this.clearGcTimeout()}scheduleGc(){this.clearGcTimeout(),te(this.gcTime)&&(this.#e=b.setTimeout(()=>{this.optionalRemove()},this.gcTime))}updateGcTime(e){this.gcTime=Math.max(this.gcTime||0,e??(be.isServer()?1/0:300*1e3))}clearGcTimeout(){this.#e!==void 0&&(b.clearTimeout(this.#e),this.#e=void 0)}};function Ae(e){return{onFetch:(t,n)=>{let r=t.options,i=t.fetchOptions?.meta?.fetchMore?.direction,a=t.state.data?.pages||[],o=t.state.data?.pageParams||[],s={pages:[],pageParams:[]},c=0,l=async()=>{let n=!1,l=e=>{ye(e,()=>t.signal,()=>n=!0)},u=_e(t.options,t.fetchOptions),d=async(e,r,i)=>{if(n)return Promise.reject(t.signal.reason);if(r==null&&e.pages.length)return Promise.resolve(e);let a=await u((()=>{let e={client:t.client,queryKey:t.queryKey,pageParam:r,direction:i?`backward`:`forward`,meta:t.options.meta};return l(e),e})()),{maxPages:o}=t.options,s=i?D:he;return{pages:s(e.pages,a,o),pageParams:s(e.pageParams,r,o)}};if(i&&a.length){let e=i===`backward`,t=e?Me:je,n={pages:a,pageParams:o};s=await d(n,t(r,n),e)}else{let t=e??a.length;do{let e=c===0?o[0]??r.initialPageParam:je(r,s);if(c>0&&e==null)break;s=await d(s,e),c++}while(ct.options.persister?.(l,{client:t.client,queryKey:t.queryKey,meta:t.options.meta,signal:t.signal},n):t.fetchFn=l}}}function je(e,{pages:t,pageParams:n}){let r=t.length-1;return t.length>0?e.getNextPageParam(t[r],t,n[r],n):void 0}function Me(e,{pages:t,pageParams:n}){return t.length>0?e.getPreviousPageParam?.(t[0],t,n[0],n):void 0}var Ne=class extends ke{#e;#t;#n;#r;#i;#a;#o;#s;constructor(e){super(),this.#s=!1,this.#o=e.defaultOptions,this.setOptions(e.options),this.observers=[],this.#i=e.client,this.#r=this.#i.getQueryCache(),this.queryKey=e.queryKey,this.queryHash=e.queryHash,this.#t=Ie(this.options),this.state=e.state??this.#t,this.scheduleGc()}get meta(){return this.options.meta}get queryType(){return this.#e}get promise(){return this.#a?.promise}setOptions(e){if(this.options={...this.#o,...e},e?._type&&(this.#e=e._type),this.updateGcTime(this.options.gcTime),this.state&&this.state.data===void 0){let e=Ie(this.options);e.data!==void 0&&(this.setState(Fe(e.data,e.dataUpdatedAt)),this.#t=e)}}optionalRemove(){!this.observers.length&&this.state.fetchStatus===`idle`&&this.#r.remove(this)}setData(e,t){let n=me(this.state.data,e,this.options);return this.#l({data:n,type:`success`,dataUpdatedAt:t?.updatedAt,manual:t?.manual}),n}setState(e){this.#l({type:`setState`,state:e})}cancel(e){let t=this.#a?.promise;return this.#a?.cancel(e),t?t.then(S).catch(S):Promise.resolve()}destroy(){super.destroy(),this.cancel({silent:!0})}get resetState(){return this.#t}reset(){this.destroy(),this.setState(this.resetState)}isActive(){return this.observers.some(e=>w(e.options.enabled,this)!==!1)}isDisabled(){return this.getObserversCount()>0?!this.isActive():this.options.queryFn===ge||!this.isFetched()}isFetched(){return this.state.dataUpdateCount+this.state.errorUpdateCount>0}isStatic(){return this.getObserversCount()>0?this.observers.some(e=>re(e.options.staleTime,this)===`static`):!1}isStale(){return this.getObserversCount()>0?this.observers.some(e=>e.getCurrentResult().isStale):this.state.data===void 0||this.state.isInvalidated}isStaleByTime(e=0){return this.state.data===void 0?!0:e===`static`?!1:this.state.isInvalidated?!0:!ne(this.state.dataUpdatedAt,e)}onFocus(){this.observers.find(e=>e.shouldFetchOnWindowFocus())?.refetch({cancelRefetch:!1}),this.#a?.continue()}onOnline(){this.observers.find(e=>e.shouldFetchOnReconnect())?.refetch({cancelRefetch:!1}),this.#a?.continue()}addObserver(e){this.observers.includes(e)||(this.observers.push(e),this.clearGcTimeout(),this.#r.notify({type:`observerAdded`,query:this,observer:e}))}removeObserver(e){this.observers.includes(e)&&(this.observers=this.observers.filter(t=>t!==e),this.observers.length||(this.#a&&(this.#s||this.#c()?this.#a.cancel({revert:!0}):this.#a.cancelRetry()),this.scheduleGc()),this.#r.notify({type:`observerRemoved`,query:this,observer:e}))}getObserversCount(){return this.observers.length}#c(){return this.state.fetchStatus===`paused`&&this.state.status===`pending`}invalidate(){this.state.isInvalidated||this.#l({type:`invalidate`})}async fetch(e,t){if(this.state.fetchStatus!==`idle`&&this.#a?.status()!==`rejected`){if(this.state.data!==void 0&&t?.cancelRefetch)this.cancel({silent:!0});else if(this.#a)return this.#a.continueRetry(),this.#a.promise}if(e&&this.setOptions(e),!this.options.queryFn){let e=this.observers.find(e=>e.options.queryFn);e&&this.setOptions(e.options)}let n=new AbortController,r=e=>{Object.defineProperty(e,"signal",{enumerable:!0,get:()=>(this.#s=!0,n.signal)})},i=()=>{let e=_e(this.options,t),n=(()=>{let e={client:this.#i,queryKey:this.queryKey,meta:this.meta};return r(e),e})();return this.#s=!1,this.options.persister?this.options.persister(e,n,this):e(n)},a=(()=>{let e={fetchOptions:t,options:this.options,queryKey:this.queryKey,client:this.#i,state:this.state,fetchFn:i};return r(e),e})();(this.#e===`infinite`?Ae(this.options.pages):this.options.behavior)?.onFetch(a,this),this.#n=this.state,(this.state.fetchStatus===`idle`||this.state.fetchMeta!==a.fetchOptions?.meta)&&this.#l({type:`fetch`,meta:a.fetchOptions?.meta}),this.#a=Oe({initialPromise:t?.initialPromise,fn:a.fetchFn,onCancel:e=>{e instanceof De&&e.revert&&this.setState({...this.#n,fetchStatus:`idle`}),n.abort()},onFail:(e,t)=>{this.#l({type:`failed`,failureCount:e,error:t})},onPause:()=>{this.#l({type:`pause`})},onContinue:()=>{this.#l({type:`continue`})},retry:a.options.retry,retryDelay:a.options.retryDelay,networkMode:a.options.networkMode,canRun:()=>!0});try{let e=await this.#a.start();if(e===void 0)throw Error(`${this.queryHash} data is undefined`);return this.setData(e),this.#r.config.onSuccess?.(e,this),this.#r.config.onSettled?.(e,this.state.error,this),e}catch(e){if(e instanceof De){if(e.silent)return this.#a.promise;if(e.revert){if(this.state.data===void 0)throw e;return this.state.data}}throw this.#l({type:`error`,error:e}),this.#r.config.onError?.(e,this),this.#r.config.onSettled?.(this.state.data,e,this),e}finally{this.scheduleGc()}}#l(e){let t=t=>{switch(e.type){case`failed`:return{...t,fetchFailureCount:e.failureCount,fetchFailureReason:e.error};case`pause`:return{...t,fetchStatus:`paused`};case`continue`:return{...t,fetchStatus:`fetching`};case`fetch`:return{...t,...Pe(t.data,this.options),fetchMeta:e.meta??null};case`success`:let n={...t,...Fe(e.data,e.dataUpdatedAt),dataUpdateCount:t.dataUpdateCount+1,...!e.manual&&{fetchStatus:`idle`,fetchFailureCount:0,fetchFailureReason:null}};return this.#n=e.manual?n:void 0,n;case`error`:let r=e.error;return{...t,error:r,errorUpdateCount:t.errorUpdateCount+1,errorUpdatedAt:Date.now(),fetchFailureCount:t.fetchFailureCount+1,fetchFailureReason:r,fetchStatus:`idle`,status:`error`,isInvalidated:!0};case`invalidate`:return{...t,isInvalidated:!0};case`setState`:return{...t,...e.state}}};this.state=t(this.state),O.batch(()=>{this.observers.forEach(e=>{e.onQueryUpdate()}),this.#r.notify({query:this,type:`updated`,action:e})})}};function Pe(e,t){return{fetchFailureCount:0,fetchFailureReason:null,fetchStatus:Ee(t.networkMode)?`fetching`:`paused`,...e===void 0&&{error:null,status:`pending`}}}function Fe(e,t){return{data:e,dataUpdatedAt:t??Date.now(),error:null,isInvalidated:!1,status:`success`}}function Ie(e){let t=typeof e.initialData==`function`?e.initialData():e.initialData,n=t!==void 0,r=n?typeof e.initialDataUpdatedAt==`function`?e.initialDataUpdatedAt():e.initialDataUpdatedAt:0;return{data:t,dataUpdateCount:0,dataUpdatedAt:n?r??Date.now():0,error:null,errorUpdateCount:0,errorUpdatedAt:0,fetchFailureCount:0,fetchFailureReason:null,fetchMeta:null,isInvalidated:!1,status:n?`success`:`pending`,fetchStatus:`idle`}}var Le=class extends _{constructor(e,t){super(),this.options=t,this.#e=e,this.#s=null,this.#o=xe(),this.bindMethods(),this.setOptions(t)}#e;#t=void 0;#n=void 0;#r=void 0;#i;#a;#o;#s;#c;#l;#u;#d;#f;#p;#m=new Set;bindMethods(){this.refetch=this.refetch.bind(this)}onSubscribe(){this.listeners.size===1&&(this.#t.addObserver(this),ze(this.#t,this.options)?this.#h():this.updateResult(),this.#y())}onUnsubscribe(){this.hasListeners()||this.destroy()}shouldFetchOnReconnect(){return Be(this.#t,this.options,this.options.refetchOnReconnect)}shouldFetchOnWindowFocus(){return Be(this.#t,this.options,this.options.refetchOnWindowFocus)}destroy(){this.listeners=new Set,this.#b(),this.#x(),this.#t.removeObserver(this)}setOptions(e){let t=this.options,n=this.#t;if(this.options=this.#e.defaultQueryOptions(e),this.options.enabled!==void 0&&typeof this.options.enabled!=`boolean`&&typeof this.options.enabled!=`function`&&typeof w(this.options.enabled,this.#t)!=`boolean`)throw Error(`Expected enabled to be a boolean or a callback that returns a boolean`);this.#S(),this.#t.setOptions(this.options),t._defaulted&&!T(this.options,t)&&this.#e.getQueryCache().notify({type:`observerOptionsUpdated`,query:this.#t,observer:this});let r=this.hasListeners();r&&Ve(this.#t,n,this.options,t)&&this.#h(),this.updateResult(),r&&(this.#t!==n||w(this.options.enabled,this.#t)!==w(t.enabled,this.#t)||re(this.options.staleTime,this.#t)!==re(t.staleTime,this.#t))&&this.#g();let i=this.#_();r&&(this.#t!==n||w(this.options.enabled,this.#t)!==w(t.enabled,this.#t)||i!==this.#p)&&this.#v(i)}getOptimisticResult(e){let t=this.#e.getQueryCache().build(this.#e,e),n=this.createResult(t,e);return Ue(this,n)&&(this.#r=n,this.#a=this.options,this.#i=this.#t.state),n}getCurrentResult(){return this.#r}trackResult(e,t){return new Proxy(e,{get:(e,n)=>(this.trackProp(n),t?.(n),n===`promise`&&(this.trackProp(`data`),!this.options.experimental_prefetchInRender&&this.#o.status===`pending`&&this.#o.reject(Error(`experimental_prefetchInRender feature flag is not enabled`))),Reflect.get(e,n))})}trackProp(e){this.#m.add(e)}getCurrentQuery(){return this.#t}refetch({...e}={}){return this.fetch({...e})}fetchOptimistic(e){let t=this.#e.defaultQueryOptions(e),n=this.#e.getQueryCache().build(this.#e,t);return n.fetch().then(()=>this.createResult(n,t))}fetch(e){return this.#h({...e,cancelRefetch:e.cancelRefetch??!0}).then(()=>(this.updateResult(),this.#r))}#h(e){this.#S();let t=this.#t.fetch(this.options,e);return e?.throwOnError||(t=t.catch(S)),t}#g(){this.#b();let e=re(this.options.staleTime,this.#t);if(be.isServer()||this.#r.isStale||!te(e))return;let t=ne(this.#r.dataUpdatedAt,e)+1;this.#d=b.setTimeout(()=>{this.#r.isStale||this.updateResult()},t)}#_(){return(typeof this.options.refetchInterval==`function`?this.options.refetchInterval(this.#t):this.options.refetchInterval)??!1}#v(e){this.#x(),this.#p=e,!(be.isServer()||w(this.options.enabled,this.#t)===!1||!te(this.#p)||this.#p===0)&&(this.#f=b.setInterval(()=>{(this.options.refetchIntervalInBackground||v.isFocused())&&this.#h()},this.#p))}#y(){this.#g(),this.#v(this.#_())}#b(){this.#d!==void 0&&(b.clearTimeout(this.#d),this.#d=void 0)}#x(){this.#f!==void 0&&(b.clearInterval(this.#f),this.#f=void 0)}createResult(e,t){let n=this.#t,r=this.options,i=this.#r,a=this.#i,o=this.#a,s=e===n?this.#n:e.state,{state:c}=e,l={...c},u=!1,d;if(t._optimisticResults){let i=this.hasListeners(),a=!i&&ze(e,t),o=i&&Ve(e,n,t,r);(a||o)&&(l={...l,...Pe(c.data,e.options)}),t._optimisticResults===`isRestoring`&&(l.fetchStatus=`idle`)}let{error:f,errorUpdatedAt:p,status:m}=l;d=l.data;let h=!1;if(t.placeholderData!==void 0&&d===void 0&&m===`pending`){let e;i?.isPlaceholderData&&t.placeholderData===o?.placeholderData?(e=i.data,h=!0):e=typeof t.placeholderData==`function`?t.placeholderData(this.#u?.state.data,this.#u):t.placeholderData,e!==void 0&&(m=`success`,d=me(i?.data,e,t),u=!0)}if(t.select&&d!==void 0&&!h)if(i&&d===a?.data&&t.select===this.#c)d=this.#l;else try{this.#c=t.select,d=t.select(d),d=me(i?.data,d,t),this.#l=d,this.#s=null}catch(e){this.#s=e}this.#s&&(f=this.#s,d=this.#l,p=Date.now(),m=`error`);let g=l.fetchStatus===`fetching`,_=m===`pending`,v=m===`error`,y=_&&g,b=d!==void 0,x={status:m,fetchStatus:l.fetchStatus,isPending:_,isSuccess:m===`success`,isError:v,isInitialLoading:y,isLoading:y,data:d,dataUpdatedAt:l.dataUpdatedAt,error:f,errorUpdatedAt:p,failureCount:l.fetchFailureCount,failureReason:l.fetchFailureReason,errorUpdateCount:l.errorUpdateCount,isFetched:e.isFetched(),isFetchedAfterMount:l.dataUpdateCount>s.dataUpdateCount||l.errorUpdateCount>s.errorUpdateCount,isFetching:g,isRefetching:g&&!_,isLoadingError:v&&!b,isPaused:l.fetchStatus===`paused`,isPlaceholderData:u,isRefetchError:v&&b,isStale:He(e,t),refetch:this.refetch,promise:this.#o,isEnabled:w(t.enabled,e)!==!1};if(this.options.experimental_prefetchInRender){let t=x.data!==void 0,r=x.status===`error`&&!t,i=e=>{r?e.reject(x.error):t&&e.resolve(x.data)},a=()=>{i(this.#o=x.promise=xe())},o=this.#o;switch(o.status){case`pending`:e.queryHash===n.queryHash&&i(o);break;case`fulfilled`:(r||x.data!==o.value)&&a();break;case`rejected`:(!r||x.error!==o.reason)&&a();break}}return x}updateResult(){let e=this.#r,t=this.createResult(this.#t,this.options);this.#i=this.#t.state,this.#a=this.options,this.#i.data!==void 0&&(this.#u=this.#t),!T(t,e)&&(this.#r=t,this.#C({listeners:(()=>{if(!e)return!0;let{notifyOnChangeProps:t}=this.options,n=typeof t==`function`?t():t;if(n===`all`||!n&&!this.#m.size)return!0;let r=new Set(n??this.#m);return this.options.throwOnError&&r.add(`error`),Object.keys(this.#r).some(t=>{let n=t;return this.#r[n]!==e[n]&&r.has(n)})})()}))}#S(){let e=this.#e.getQueryCache().build(this.#e,this.options);if(e===this.#t)return;let t=this.#t;this.#t=e,this.#n=e.state,this.hasListeners()&&(t?.removeObserver(this),e.addObserver(this))}onQueryUpdate(){this.updateResult(),this.hasListeners()&&this.#y()}#C(e){O.batch(()=>{e.listeners&&this.listeners.forEach(e=>{e(this.#r)}),this.#e.getQueryCache().notify({query:this.#t,type:`observerResultsUpdated`})})}};function Re(e,t){return w(t.enabled,e)!==!1&&e.state.data===void 0&&!(e.state.status===`error`&&w(t.retryOnMount,e)===!1)}function ze(e,t){return Re(e,t)||e.state.data!==void 0&&Be(e,t,t.refetchOnMount)}function Be(e,t,n){if(w(t.enabled,e)!==!1&&re(t.staleTime,e)!==`static`){let r=typeof n==`function`?n(e):n;return r===`always`||r!==!1&&He(e,t)}return!1}function Ve(e,t,n,r){return(e!==t||w(r.enabled,e)===!1)&&(!n.suspense||e.state.status!==`error`)&&He(e,n)}function He(e,t){return w(t.enabled,e)!==!1&&e.isStaleByTime(re(t.staleTime,e))}function Ue(e,t){return!T(e.getCurrentResult(),t)}var We=class extends ke{#e;#t;#n;#r;constructor(e){super(),this.#e=e.client,this.mutationId=e.mutationId,this.#n=e.mutationCache,this.#t=[],this.state=e.state||Ge(),this.setOptions(e.options),this.scheduleGc()}setOptions(e){this.options=e,this.updateGcTime(this.options.gcTime)}get meta(){return this.options.meta}addObserver(e){this.#t.includes(e)||(this.#t.push(e),this.clearGcTimeout(),this.#n.notify({type:`observerAdded`,mutation:this,observer:e}))}removeObserver(e){this.#t=this.#t.filter(t=>t!==e),this.scheduleGc(),this.#n.notify({type:`observerRemoved`,mutation:this,observer:e})}optionalRemove(){this.#t.length||(this.state.status===`pending`?this.scheduleGc():this.#n.remove(this))}continue(){return this.#r?.continue()??this.execute(this.state.variables)}async execute(e){let t=()=>{this.#i({type:`continue`})},n={client:this.#e,meta:this.options.meta,mutationKey:this.options.mutationKey};this.#r=Oe({fn:()=>this.options.mutationFn?this.options.mutationFn(e,n):Promise.reject(Error(`No mutationFn found`)),onFail:(e,t)=>{this.#i({type:`failed`,failureCount:e,error:t})},onPause:()=>{this.#i({type:`pause`})},onContinue:t,retry:this.options.retry??0,retryDelay:this.options.retryDelay,networkMode:this.options.networkMode,canRun:()=>this.#n.canRun(this)});let r=this.state.status===`pending`,i=!this.#r.canStart();try{if(r)t();else{this.#i({type:`pending`,variables:e,isPaused:i}),this.#n.config.onMutate&&await this.#n.config.onMutate(e,this,n);let t=await this.options.onMutate?.(e,n);t!==this.state.context&&this.#i({type:`pending`,context:t,variables:e,isPaused:i})}let a=await this.#r.start();return await this.#n.config.onSuccess?.(a,e,this.state.context,this,n),await this.options.onSuccess?.(a,e,this.state.context,n),await this.#n.config.onSettled?.(a,null,this.state.variables,this.state.context,this,n),await this.options.onSettled?.(a,null,e,this.state.context,n),this.#i({type:`success`,data:a}),a}catch(t){try{await this.#n.config.onError?.(t,e,this.state.context,this,n)}catch(e){Promise.reject(e)}try{await this.options.onError?.(t,e,this.state.context,n)}catch(e){Promise.reject(e)}try{await this.#n.config.onSettled?.(void 0,t,this.state.variables,this.state.context,this,n)}catch(e){Promise.reject(e)}try{await this.options.onSettled?.(void 0,t,e,this.state.context,n)}catch(e){Promise.reject(e)}throw this.#i({type:`error`,error:t}),t}finally{this.#n.runNext(this)}}#i(e){let t=t=>{switch(e.type){case`failed`:return{...t,failureCount:e.failureCount,failureReason:e.error};case`pause`:return{...t,isPaused:!0};case`continue`:return{...t,isPaused:!1};case`pending`:return{...t,context:e.context,data:void 0,failureCount:0,failureReason:null,error:null,isPaused:e.isPaused,status:`pending`,variables:e.variables,submittedAt:Date.now()};case`success`:return{...t,data:e.data,failureCount:0,failureReason:null,error:null,status:`success`,isPaused:!1};case`error`:return{...t,data:void 0,error:e.error,failureCount:t.failureCount+1,failureReason:e.error,isPaused:!1,status:`error`}}};this.state=t(this.state),O.batch(()=>{this.#t.forEach(t=>{t.onMutationUpdate(e)}),this.#n.notify({mutation:this,type:`updated`,action:e})})}};function Ge(){return{context:void 0,data:void 0,error:null,failureCount:0,failureReason:null,isPaused:!1,status:`idle`,variables:void 0,submittedAt:0}}var Ke=class extends _{constructor(e={}){super(),this.config=e,this.#e=new Set,this.#t=new Map,this.#n=0}#e;#t;#n;build(e,t,n){let r=new We({client:e,mutationCache:this,mutationId:++this.#n,options:e.defaultMutationOptions(t),state:n});return this.add(r),r}add(e){this.#e.add(e);let t=qe(e);if(typeof t==`string`){let n=this.#t.get(t);n?n.push(e):this.#t.set(t,[e])}this.notify({type:`added`,mutation:e})}remove(e){if(this.#e.delete(e)){let t=qe(e);if(typeof t==`string`){let n=this.#t.get(t);if(n)if(n.length>1){let t=n.indexOf(e);t!==-1&&n.splice(t,1)}else n[0]===e&&this.#t.delete(t)}}this.notify({type:`removed`,mutation:e})}canRun(e){let t=qe(e);if(typeof t==`string`){let n=this.#t.get(t)?.find(e=>e.state.status===`pending`);return!n||n===e}else return!0}runNext(e){let t=qe(e);return typeof t==`string`?(this.#t.get(t)?.find(t=>t!==e&&t.state.isPaused))?.continue()??Promise.resolve():Promise.resolve()}clear(){O.batch(()=>{this.#e.forEach(e=>{this.notify({type:`removed`,mutation:e})}),this.#e.clear(),this.#t.clear()})}getAll(){return Array.from(this.#e)}find(e){let t={exact:!0,...e};return this.getAll().find(e=>ae(t,e))}findAll(e={}){return this.getAll().filter(t=>ae(e,t))}notify(e){O.batch(()=>{this.listeners.forEach(t=>{t(e)})})}resumePausedMutations(){let e=this.getAll().filter(e=>e.state.isPaused);return O.batch(()=>Promise.all(e.map(e=>e.continue().catch(S))))}};function qe(e){return e.options.scope?.id}var Je=class extends _{#e;#t=void 0;#n;#r;constructor(e,t){super(),this.#e=e,this.setOptions(t),this.bindMethods(),this.#i()}bindMethods(){this.mutate=this.mutate.bind(this),this.reset=this.reset.bind(this)}setOptions(e){let t=this.options;this.options=this.#e.defaultMutationOptions(e),T(this.options,t)||this.#e.getMutationCache().notify({type:`observerOptionsUpdated`,mutation:this.#n,observer:this}),t?.mutationKey&&this.options.mutationKey&&se(t.mutationKey)!==se(this.options.mutationKey)?this.reset():this.#n?.state.status===`pending`&&this.#n.setOptions(this.options)}onUnsubscribe(){this.hasListeners()||this.#n?.removeObserver(this)}onMutationUpdate(e){this.#i(),this.#a(e)}getCurrentResult(){return this.#t}reset(){this.#n?.removeObserver(this),this.#n=void 0,this.#i(),this.#a()}mutate(e,t){return this.#r=t,this.#n?.removeObserver(this),this.#n=this.#e.getMutationCache().build(this.#e,this.options),this.#n.addObserver(this),this.#n.execute(e)}#i(){let e=this.#n?.state??Ge();this.#t={...e,isPending:e.status===`pending`,isSuccess:e.status===`success`,isError:e.status===`error`,isIdle:e.status===`idle`,mutate:this.mutate,reset:this.reset}}#a(e){O.batch(()=>{if(this.#r&&this.hasListeners()){let t=this.#t.variables,n=this.#t.context,r={client:this.#e,meta:this.options.meta,mutationKey:this.options.mutationKey};if(e?.type===`success`){try{this.#r.onSuccess?.(e.data,t,n,r)}catch(e){Promise.reject(e)}try{this.#r.onSettled?.(e.data,null,t,n,r)}catch(e){Promise.reject(e)}}else if(e?.type===`error`){try{this.#r.onError?.(e.error,t,n,r)}catch(e){Promise.reject(e)}try{this.#r.onSettled?.(void 0,e.error,t,n,r)}catch(e){Promise.reject(e)}}}this.listeners.forEach(e=>{e(this.#t)})})}};function Ye(e,t){let n=new Set(t);return e.filter(e=>!n.has(e))}function Xe(e,t,n){let r=e.slice(0);return r[t]=n,r}var Ze=class extends _{#e;#t;#n;#r;#i;#a;#o;#s;#c;#l=[];constructor(e,t,n){super(),this.#e=e,this.#r=n,this.#n=[],this.#i=[],this.#t=[],this.setQueries(t)}onSubscribe(){this.listeners.size===1&&this.#i.forEach(e=>{e.subscribe(t=>{this.#m(e,t)})})}onUnsubscribe(){this.listeners.size||this.destroy()}destroy(){this.listeners=new Set,this.#i.forEach(e=>{e.destroy()})}setQueries(e,t){this.#n=e,this.#r=t,O.batch(()=>{let e=this.#i,t=this.#p(this.#n);t.forEach(e=>e.observer.setOptions(e.defaultedQueryOptions));let n=t.map(e=>e.observer),r=n.map(e=>e.getCurrentResult()),i=e.length!==n.length,a=n.some((t,n)=>t!==e[n]),o=i||a,s=o?!0:r.some((e,t)=>{let n=this.#t[t];return!n||!T(e,n)});!o&&!s||(o&&(this.#l=t,this.#i=n),this.#t=r,this.hasListeners()&&(o&&(Ye(e,n).forEach(e=>{e.destroy()}),Ye(n,e).forEach(e=>{e.subscribe(t=>{this.#m(e,t)})})),this.#h()))})}getCurrentResult(){return this.#t}getQueries(){return this.#i.map(e=>e.getCurrentQuery())}getObservers(){return this.#i}getOptimisticResult(e,t){let n=this.#p(e),r=n.map(e=>e.observer.getOptimisticResult(e.defaultedQueryOptions)),i=n.map(e=>e.defaultedQueryOptions.queryHash);return[r,e=>this.#d(e??r,t,i),()=>this.#u(r,n)]}#u(e,t){return t.map((n,r)=>{let i=e[r];return n.defaultedQueryOptions.notifyOnChangeProps?i:n.observer.trackResult(i,e=>{t.forEach(t=>{t.observer.trackProp(e)})})})}#d(e,t,n){if(t){let r=this.#c,i=n!==void 0&&r!==void 0&&(r.length!==n.length||n.some((e,t)=>e!==r[t]));return(!this.#a||this.#t!==this.#s||i||t!==this.#o)&&(this.#o=t,this.#s=this.#t,n!==void 0&&(this.#c=n),this.#a=ue(this.#a,t(e))),this.#a}return e}#f(){return this.#r?.combine!==void 0&&this.#i.some((e,t)=>e.options.suspense&&this.#t[t]?.data===void 0)}#p(e){let t=new Map;this.#i.forEach(e=>{let n=e.options.queryHash;if(!n)return;let r=t.get(n);r?r.push(e):t.set(n,[e])});let n=[];return e.forEach(e=>{let r=this.#e.defaultQueryOptions(e),i=t.get(r.queryHash)?.shift()??new Le(this.#e,r);n.push({defaultedQueryOptions:r,observer:i})}),n}#m(e,t){let n=this.#i.indexOf(e);n!==-1&&(this.#t=Xe(this.#t,n,t),this.#h())}#h(){if(this.hasListeners()){let e=this.#u(this.#t,this.#l),t=this.#f(),n=this.#a,r=t?n:this.#d(e,this.#r?.combine);(t||n!==r)&&O.batch(()=>{this.listeners.forEach(e=>{e(this.#t)})})}}},Qe=class extends _{constructor(e={}){super(),this.config=e,this.#e=new Map}#e;build(e,t,n){let r=t.queryKey,i=t.queryHash??oe(r,t),a=this.get(i);return a||(a=new Ne({client:e,queryKey:r,queryHash:i,options:e.defaultQueryOptions(t),state:n,defaultOptions:e.getQueryDefaults(r)}),this.add(a)),a}add(e){this.#e.has(e.queryHash)||(this.#e.set(e.queryHash,e),this.notify({type:`added`,query:e}))}remove(e){let t=this.#e.get(e.queryHash);t&&(e.destroy(),t===e&&this.#e.delete(e.queryHash),this.notify({type:`removed`,query:e}))}clear(){O.batch(()=>{this.getAll().forEach(e=>{this.remove(e)})})}get(e){return this.#e.get(e)}getAll(){return[...this.#e.values()]}find(e){let t={exact:!0,...e};return this.getAll().find(e=>ie(t,e))}findAll(e={}){let t=this.getAll();return Object.keys(e).length>0?t.filter(t=>ie(e,t)):t}notify(e){O.batch(()=>{this.listeners.forEach(t=>{t(e)})})}onFocus(){O.batch(()=>{this.getAll().forEach(e=>{e.onFocus()})})}onOnline(){O.batch(()=>{this.getAll().forEach(e=>{e.onOnline()})})}},$e=class{#e;#t;#n;#r;#i;#a;#o;#s;constructor(e={}){this.#e=e.queryCache||new Qe,this.#t=e.mutationCache||new Ke,this.#n=e.defaultOptions||{},this.#r=new Map,this.#i=new Map,this.#a=0}mount(){this.#a++,this.#a===1&&(this.#o=v.subscribe(async e=>{e&&(await this.resumePausedMutations(),this.#e.onFocus())}),this.#s=we.subscribe(async e=>{e&&(await this.resumePausedMutations(),this.#e.onOnline())}))}unmount(){this.#a--,this.#a===0&&(this.#o?.(),this.#o=void 0,this.#s?.(),this.#s=void 0)}isFetching(e){return this.#e.findAll({...e,fetchStatus:`fetching`}).length}isMutating(e){return this.#t.findAll({...e,status:`pending`}).length}getQueryData(e){let t=this.defaultQueryOptions({queryKey:e});return this.#e.get(t.queryHash)?.state.data}ensureQueryData(e){let t=this.defaultQueryOptions(e),n=this.#e.build(this,t),r=n.state.data;return r===void 0?this.fetchQuery(e):(e.revalidateIfStale&&n.isStaleByTime(re(t.staleTime,n))&&this.prefetchQuery(t),Promise.resolve(r))}getQueriesData(e){return this.#e.findAll(e).map(({queryKey:e,state:t})=>[e,t.data])}setQueryData(e,t,n){let r=this.defaultQueryOptions({queryKey:e}),i=this.#e.get(r.queryHash)?.state.data,a=C(t,i);if(a!==void 0)return this.#e.build(this,r).setData(a,{...n,manual:!0})}setQueriesData(e,t,n){return O.batch(()=>this.#e.findAll(e).map(({queryKey:e})=>[e,this.setQueryData(e,t,n)]))}getQueryState(e){let t=this.defaultQueryOptions({queryKey:e});return this.#e.get(t.queryHash)?.state}removeQueries(e){let t=this.#e;O.batch(()=>{t.findAll(e).forEach(e=>{t.remove(e)})})}resetQueries(e,t){let n=this.#e;return O.batch(()=>(n.findAll(e).forEach(e=>{e.reset()}),this.refetchQueries({type:`active`,...e},t)))}cancelQueries(e,t={}){let n={revert:!0,...t},r=O.batch(()=>this.#e.findAll(e).map(e=>e.cancel(n)));return Promise.all(r).then(S).catch(S)}invalidateQueries(e,t={}){return O.batch(()=>(this.#e.findAll(e).forEach(e=>{e.invalidate()}),e?.refetchType===`none`?Promise.resolve():this.refetchQueries({...e,type:e?.refetchType??e?.type??`active`},t)))}refetchQueries(e,t={}){let n={...t,cancelRefetch:t.cancelRefetch??!0},r=O.batch(()=>this.#e.findAll(e).filter(e=>!e.isDisabled()&&!e.isStatic()).map(e=>{let t=e.fetch(void 0,n);return n.throwOnError||(t=t.catch(S)),e.state.fetchStatus===`paused`?Promise.resolve():t}));return Promise.all(r).then(S)}fetchQuery(e){let t=this.defaultQueryOptions(e);t.retry===void 0&&(t.retry=!1);let n=this.#e.build(this,t);return n.isStaleByTime(re(t.staleTime,n))?n.fetch(t):Promise.resolve(n.state.data)}prefetchQuery(e){return this.fetchQuery(e).then(S).catch(S)}fetchInfiniteQuery(e){return e._type=`infinite`,this.fetchQuery(e)}prefetchInfiniteQuery(e){return this.fetchInfiniteQuery(e).then(S).catch(S)}ensureInfiniteQueryData(e){return e._type=`infinite`,this.ensureQueryData(e)}resumePausedMutations(){return we.isOnline()?this.#t.resumePausedMutations():Promise.resolve()}getQueryCache(){return this.#e}getMutationCache(){return this.#t}getDefaultOptions(){return this.#n}setDefaultOptions(e){this.#n=e}setQueryDefaults(e,t){this.#r.set(se(e),{queryKey:e,defaultOptions:t})}getQueryDefaults(e){let t=[...this.#r.values()],n={};return t.forEach(t=>{ce(e,t.queryKey)&&Object.assign(n,t.defaultOptions)}),n}setMutationDefaults(e,t){this.#i.set(se(e),{mutationKey:e,defaultOptions:t})}getMutationDefaults(e){let t=[...this.#i.values()],n={};return t.forEach(t=>{ce(e,t.mutationKey)&&Object.assign(n,t.defaultOptions)}),n}defaultQueryOptions(e){if(e._defaulted)return e;let t={...this.#n.queries,...this.getQueryDefaults(e.queryKey),...e,_defaulted:!0};return t.queryHash||=oe(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===ge&&(t.enabled=!1),t}defaultMutationOptions(e){return e?._defaulted?e:{...this.#n.mutations,...e?.mutationKey&&this.getMutationDefaults(e.mutationKey),...e,_defaulted:!0}}clear(){this.#e.clear(),this.#t.clear()}},et=o((e=>{var t=Symbol.for(`react.transitional.element`),n=Symbol.for(`react.fragment`);function r(e,n,r){var i=null;if(r!==void 0&&(i=``+r),n.key!==void 0&&(i=``+n.key),`key`in n)for(var a in r={},n)a!==`key`&&(r[a]=n[a]);else r=n;return n=r.ref,{$$typeof:t,type:e,key:i,ref:n===void 0?null:n,props:r}}e.Fragment=n,e.jsx=r,e.jsxs=r})),tt=o(((e,t)=>{t.exports=et()})),k=c(u(),1),A=tt(),nt=k.createContext(void 0),rt=e=>{let t=k.useContext(nt);if(e)return e;if(!t)throw Error(`No QueryClient set, use QueryClientProvider to set one`);return t},it=({client:e,children:t})=>(k.useEffect(()=>(e.mount(),()=>{e.unmount()}),[e]),(0,A.jsx)(nt.Provider,{value:e,children:t})),at=k.createContext(!1),ot=()=>k.useContext(at);at.Provider;function st(){let e=!1;return{clearReset:()=>{e=!1},reset:()=>{e=!0},isReset:()=>e}}var ct=k.createContext(st()),lt=()=>k.useContext(ct),ut=(e,t,n)=>{let r=n?.state.error&&typeof e.throwOnError==`function`?ve(e.throwOnError,[n.state.error,n]):e.throwOnError;(e.suspense||e.experimental_prefetchInRender||r)&&(t.isReset()||(e.retryOnMount=!1))},dt=e=>{k.useEffect(()=>{e.clearReset()},[e])},ft=({result:e,errorResetBoundary:t,throwOnError:n,query:r,suspense:i})=>e.isError&&!t.isReset()&&!e.isFetching&&r&&(i&&e.data===void 0||ve(n,[e.error,r])),pt=e=>{if(e.suspense){let t=1e3,n=e=>e===`static`?e:Math.max(e??t,t),r=e.staleTime;e.staleTime=typeof r==`function`?(...e)=>n(r(...e)):n(r),typeof e.gcTime==`number`&&(e.gcTime=Math.max(e.gcTime,t))}},mt=(e,t)=>e.isLoading&&e.isFetching&&!t,ht=(e,t)=>e?.suspense&&t.isPending,gt=(e,t,n)=>t.fetchOptimistic(e).catch(()=>{n.clearReset()});function _t({queries:e,...t},n){let r=rt(n),i=ot(),a=lt(),o=k.useMemo(()=>e.map(e=>{let t=r.defaultQueryOptions(e);return t._optimisticResults=i?`isRestoring`:`optimistic`,t}),[e,r,i]);o.forEach(e=>{pt(e),ut(e,a,r.getQueryCache().get(e.queryHash))}),dt(a);let[s]=k.useState(()=>new Ze(r,o,t)),[c,l,u]=s.getOptimisticResult(o,t.combine),d=!i&&t.subscribed!==!1;k.useSyncExternalStore(k.useCallback(e=>d?s.subscribe(O.batchCalls(e)):S,[s,d]),()=>s.getCurrentResult(),()=>s.getCurrentResult()),k.useEffect(()=>{s.setQueries(o,t)},[o,t,s]);let f=c.some((e,t)=>ht(o[t],e))?c.flatMap((e,t)=>{let n=o[t];return n&&ht(n,e)?gt(n,new Le(r,n),a):[]}):[];if(f.length>0)throw Promise.all(f);let p=c.find((e,t)=>{let n=o[t];return n&&ft({result:e,errorResetBoundary:a,throwOnError:n.throwOnError,query:r.getQueryCache().get(n.queryHash),suspense:n.suspense})});if(p?.error)throw p.error;return l(u())}function vt(e,t,n){let r=ot(),i=lt(),a=rt(n),o=a.defaultQueryOptions(e);a.getDefaultOptions().queries?._experimental_beforeQuery?.(o);let s=a.getQueryCache().get(o.queryHash),c=e.subscribed!==!1;o._optimisticResults=r?`isRestoring`:c?`optimistic`:void 0,pt(o),ut(o,i,s),dt(i);let l=!a.getQueryCache().get(o.queryHash),[u]=k.useState(()=>new t(a,o)),d=u.getOptimisticResult(o),f=!r&&c;if(k.useSyncExternalStore(k.useCallback(e=>{let t=f?u.subscribe(O.batchCalls(e)):S;return u.updateResult(),t},[u,f]),()=>u.getCurrentResult(),()=>u.getCurrentResult()),k.useEffect(()=>{u.setOptions(o)},[o,u]),ht(o,d))throw gt(o,u,i);if(ft({result:d,errorResetBoundary:i,throwOnError:o.throwOnError,query:s,suspense:o.suspense}))throw d.error;return a.getDefaultOptions().queries?._experimental_afterQuery?.(o,d),o.experimental_prefetchInRender&&!be.isServer()&&mt(d,r)&&(l?gt(o,u,i):s?.promise)?.catch(S).finally(()=>{u.updateResult()}),o.notifyOnChangeProps?d:u.trackResult(d)}function j(e,t){return vt(e,Le,t)}function yt(e,t){let n=rt(t),[r]=k.useState(()=>new Je(n,e));k.useEffect(()=>{r.setOptions(e)},[r,e]);let i=k.useSyncExternalStore(k.useCallback(e=>r.subscribe(O.batchCalls(e)),[r]),()=>r.getCurrentResult(),()=>r.getCurrentResult()),a=k.useCallback((e,t)=>{r.mutate(e,t).catch(S)},[r]);if(i.error&&ve(r.options.throwOnError,[i.error]))throw i.error;return{...i,mutate:a,mutateAsync:i.mutate}}var bt=c(g(),1),xt=`berth.adminToken`;function St(){return localStorage.getItem(xt)}function Ct(e){localStorage.setItem(xt,e)}function wt(){localStorage.removeItem(xt)}var M={deployments:[`deps`],models:[`models`],keys:[`keys`],gpus:[`gpus`],backends:[`backends`],adapters:[`adapters`],profiles:[`profiles`],routes:[`routes`],nodes:[`nodes`],requests:[`requests`],predictorCandidates:[`predictor-candidates`],predictorStats:[`predictor-stats`],metricsSnapshot:[`metrics-snapshot`],clusterInfo:[`cluster-info`],config:[`config`],requestsSeed:[`requests-seed`],node:e=>[`node`,e],keyUsage:(e,t)=>[`key-usage`,e,t],usageSeries:(e,t,n)=>[`usage-series`,e,t,n],metricsHistory:(e,t)=>[`metrics-history`,e,t],metricsSummary:(e,t)=>[`metrics-summary`,e,t]};async function Tt(e){if(!St())return e;let t=await P.createStreamToken(new URL(e,window.location.origin).pathname);return`${e}${e.includes(`?`)?`&`:`?`}stream_token=${encodeURIComponent(t.token)}`}async function N(e,t,n){let r={"Content-Type":`application/json`},i=St();i&&(r.Authorization=`Bearer ${i}`);let a=await fetch(t,{method:e,headers:r,body:n===void 0?void 0:JSON.stringify(n)});if(!a.ok){let e=await a.text();throw Error(`${a.status}: ${e}`)}if(a.status!==204)return a.json()}var P={listDeployments:()=>N(`GET`,`/admin/deployments`),stopDeployment:e=>N(`DELETE`,`/admin/deployments/${e}`),pinDeployment:e=>N(`POST`,`/admin/deployments/${e}/pin`),unpinDeployment:e=>N(`POST`,`/admin/deployments/${e}/unpin`),listModels:()=>N(`GET`,`/admin/models`),createModel:e=>N(`POST`,`/admin/models`,e),deleteModel:e=>N(`DELETE`,`/admin/models/${e}`),listKeys:()=>N(`GET`,`/admin/keys`),createKey:e=>N(`POST`,`/admin/keys`,e),revokeKey:e=>N(`DELETE`,`/admin/keys/${e}`),listGpus:()=>N(`GET`,`/admin/gpus`),listBackends:()=>N(`GET`,`/admin/backends`),loadModel:e=>N(`POST`,`/admin/deployments`,e),createStreamToken:e=>N(`POST`,`/admin/stream-token`,{path:e}),listAdapters:()=>N(`GET`,`/admin/adapters`),createAdapter:e=>N(`POST`,`/admin/adapters`,e),downloadAdapter:e=>N(`POST`,`/admin/adapters/${e}/download`),addLocalAdapter:e=>N(`POST`,`/admin/adapters/local`,e),deleteAdapter:(e,t=!1)=>N(`DELETE`,`/admin/adapters/${e}${t?`?force=true`:``}`),hotLoadAdapter:(e,t)=>N(`POST`,`/admin/deployments/${e}/adapters/${t}`),hotUnloadAdapter:(e,t)=>N(`DELETE`,`/admin/deployments/${e}/adapters/${t}`),predictorCandidates:()=>N(`GET`,`/admin/predictor/candidates`),predictorStats:()=>N(`GET`,`/admin/predictor/stats`),listProfiles:()=>N(`GET`,`/admin/service-profiles`),createProfile:e=>N(`POST`,`/admin/service-profiles`,e),deployProfile:e=>N(`POST`,`/admin/service-profiles/${encodeURIComponent(e)}/deploy`),deleteProfile:e=>N(`DELETE`,`/admin/service-profiles/${encodeURIComponent(e)}`),listRoutes:()=>N(`GET`,`/admin/routes`),createRoute:e=>N(`POST`,`/admin/routes`,e),deleteRoute:e=>N(`DELETE`,`/admin/routes/${encodeURIComponent(e)}`),dryRunRoute:e=>N(`GET`,`/admin/routes/match/dry-run?model=${encodeURIComponent(e)}`),keyUsage:(e,t=86400,n=3600)=>N(`GET`,`/admin/keys/${e}/usage?window_s=${t}&bucket_s=${n}`),listRequests:()=>N(`GET`,`/admin/requests`),listNodes:()=>N(`GET`,`/admin/nodes`),getNode:e=>N(`GET`,`/admin/nodes/${e}`),enrollNode:e=>N(`POST`,`/admin/nodes/enroll`,{label:e}),removeNode:e=>N(`DELETE`,`/admin/nodes/${e}`),getClusterInfo:()=>N(`GET`,`/admin/cluster`),getConfig:()=>N(`GET`,`/admin/config`),getMetricsSnapshot:()=>N(`GET`,`/admin/metrics/snapshot`),getUsageSeries:(e=86400,t=3600)=>N(`GET`,`/admin/usage/series?window_s=${e}&bucket_s=${t}`),getUsageByModel:(e=86400,t=3600)=>N(`GET`,`/admin/usage/series?window_s=${e}&bucket_s=${t}&group_by=model`),getMetricsHistory:(e=86400,t=3600)=>N(`GET`,`/admin/metrics/history?window_s=${e}&bucket_s=${t}`),getMetricsSummary:(e=86400)=>N(`GET`,`/admin/metrics/history?window_s=${e}&summary=true`),getMetricsByModel:(e=86400)=>N(`GET`,`/admin/metrics/history?window_s=${e}&summary=true&group_by=model`)};function Et(e){return`berth://enroll?${new URLSearchParams({leader:e.leader_url,token:e.token,ca_fp:e.ca_fingerprint}).toString()}`}function Dt({children:e}){let[t,n]=(0,k.useState)(St()),[r,i]=(0,k.useState)(``);return t?(0,A.jsx)(A.Fragment,{children:e}):(0,A.jsx)(`div`,{className:`min-h-screen flex items-center justify-center px-6`,children:(0,A.jsxs)(`div`,{className:`w-full max-w-md enter`,children:[(0,A.jsxs)(`div`,{className:`flex items-center gap-2 mb-12`,children:[(0,A.jsx)(`div`,{className:`text-base`,children:`berth`}),(0,A.jsx)(`span`,{className:`caret`})]}),(0,A.jsxs)(`div`,{className:`space-y-8`,children:[(0,A.jsxs)(`div`,{className:`space-y-2`,children:[(0,A.jsx)(`div`,{className:`label`,children:`authenticate`}),(0,A.jsx)(`p`,{className:`text-dim text-[12px] leading-relaxed`,children:`Paste an admin-tier API key. If you don't have one, run this on the host:`}),(0,A.jsxs)(`pre`,{className:`text-[12px] bg-elev border border-rule px-3 py-2 text-ink overflow-x-auto`,children:[(0,A.jsx)(`span`,{className:`text-mute select-none`,children:`$ `}),`berth key create web --tier admin`]})]}),(0,A.jsxs)(`div`,{className:`space-y-3`,children:[(0,A.jsx)(`div`,{className:`label`,children:`api key`}),(0,A.jsx)(`input`,{className:`field w-full font-mono`,placeholder:`sk-...`,value:r,onChange:e=>i(e.target.value),onKeyDown:e=>{e.key===`Enter`&&r.trim()&&(Ct(r.trim()),n(r.trim()))},autoFocus:!0}),(0,A.jsx)(`button`,{className:`btn-primary w-full`,disabled:!r.trim(),onClick:()=>{Ct(r.trim()),n(r.trim())},children:`Continue`})]})]})]})})}function Ot({label:e,usedMb:t,totalMb:n,utilPct:r,powerW:i,right:a,loaded:o}){let s=n>0?t/n*100:0;return(0,A.jsxs)(`div`,{className:`space-y-4`,children:[(0,A.jsxs)(`div`,{className:`flex items-baseline justify-between`,children:[(0,A.jsx)(`div`,{className:`label`,children:e}),(0,A.jsxs)(`div`,{className:`text-mute text-[11px] tnum`,children:[s.toFixed(0),`%`]})]}),(0,A.jsxs)(`div`,{className:`flex items-baseline gap-2 tnum`,children:[(0,A.jsx)(`div`,{className:`text-3xl font-light tracking-tightish`,children:(t/1024).toFixed(1)}),(0,A.jsxs)(`div`,{className:`text-mute text-[12px]`,children:[`/ `,(n/1024).toFixed(0),` GB`]})]}),(0,A.jsx)(`div`,{className:`h-px bg-rule relative overflow-hidden`,children:(0,A.jsx)(`div`,{className:`absolute inset-y-0 left-0 bg-accent transition-[width] duration-500`,style:{width:`${s}%`}})}),(0,A.jsxs)(`div`,{className:`flex items-center gap-6 text-mute text-[11px] tnum`,children:[(0,A.jsxs)(`span`,{children:[`util `,r,`%`]}),i!=null&&(0,A.jsxs)(`span`,{children:[i,` w`]}),a&&(0,A.jsx)(`span`,{className:`ml-auto`,children:a})]}),o]})}function kt(e){return e?e>=1024?`${(e/1024).toFixed(1)} GB`:`${e} MB`:`-`}function At(e){return!e||e.length===0?`-`:e.length===1?`gpu ${e[0]}`:`gpu ${e.join(`,`)}`}function jt(e){return e<=1?`grid-cols-1`:e===2?`grid-cols-1 md:grid-cols-2`:e===3?`grid-cols-1 md:grid-cols-3`:`grid-cols-1 md:grid-cols-2 lg:grid-cols-4`}function Mt(e){if(e.pinned||!e.idle_timeout_s||!e.last_request_at)return null;let t=String(e.last_request_at).replace(` `,`T`)+`Z`,n=Date.parse(t);if(Number.isNaN(n))return null;let r=e.idle_timeout_s-(Date.now()-n)/1e3;return r<=0?`evicting`:r<60?`${Math.round(r)}s`:`${Math.round(r/60)}m`}function Nt({d:e,modelName:t}){let n=Mt(e),r=e.vram_used_mb&&e.vram_used_mb>0?e.vram_used_mb:e.vram_reserved_mb;return(0,A.jsxs)(`div`,{className:`flex items-center gap-3 text-[12px] py-1.5`,title:e.last_error||`deployment #${e.id} on ${e.backend}`,children:[(0,A.jsx)(`span`,{className:`dot dot-${e.status}`}),(0,A.jsx)(`span`,{className:`text-ink truncate flex-1 min-w-0`,children:t}),(0,A.jsx)(`span`,{className:`text-mute text-[10px] tracking-wider hidden lg:inline`,children:e.backend}),(0,A.jsx)(`span`,{className:`text-dim tnum`,children:kt(r)}),e.pinned?(0,A.jsx)(`span`,{className:`text-accent text-[10px] tracking-wider`,children:`pin`}):n?(0,A.jsx)(`span`,{className:`text-mute text-[10px] tracking-wider`,title:`idle countdown`,children:n}):(0,A.jsx)(`span`,{className:`text-mute text-[10px]`,children:`—`})]})}function Pt({g:e,deployments:t,models:n}){let r=t.filter(t=>(t.gpu_ids??[]).includes(e.index)&&(t.status===`ready`||t.status===`loading`));return(0,A.jsx)(Ot,{label:`gpu ${e.index}`,usedMb:e.memory_used_mb,totalMb:e.memory_total_mb,utilPct:e.gpu_util_pct,powerW:e.power_w,right:r.length===0?(0,A.jsx)(`span`,{className:`text-mute`,children:`idle`}):(0,A.jsxs)(`span`,{className:`text-dim`,children:[r.length,` loaded`]}),loaded:r.length>0&&(0,A.jsx)(`div`,{className:`pt-2 border-t border-rule-soft space-y-0.5`,children:r.map(e=>(0,A.jsx)(Nt,{d:e,modelName:n.find(t=>t.id===e.model_id)?.name??`#${e.id}`},e.id))})})}function Ft(){let e=j({queryKey:M.metricsSnapshot,queryFn:P.getMetricsSnapshot,refetchInterval:2e3}),t=j({queryKey:M.deployments,queryFn:P.listDeployments,refetchInterval:2e3}),n=j({queryKey:M.models,queryFn:P.listModels,refetchInterval:5e3}),r=j({queryKey:M.gpus,queryFn:P.listGpus,refetchInterval:2e3}),i=e.data?.nodes??[],a=t.data??[],o=n.data??[],s=i.reduce((e,t)=>e+t.gpus.length,0),c=i.filter(e=>e.gpus.length>0).length>1,l=(e,t)=>i.length<=1||e.node_id===t.node_id||t.label===`local`&&e.node_id==null;if(s===0){let e=r.data??[];return(0,A.jsxs)(`section`,{className:`space-y-6`,children:[(0,A.jsx)(`div`,{className:`label`,children:`gpus`}),e.length===0?(0,A.jsx)(`div`,{className:`text-mute text-[12px]`,children:`no gpus reported`}):(0,A.jsx)(`div`,{className:`grid gap-12 `+jt(e.length),children:e.map(e=>(0,A.jsx)(Pt,{g:e,deployments:a,models:o},e.index))})]})}return(0,A.jsxs)(`section`,{className:`space-y-8`,children:[(0,A.jsx)(`div`,{className:`label`,children:`gpus`}),i.filter(e=>e.gpus.length>0).map(e=>(0,A.jsxs)(`div`,{className:`space-y-4`,children:[c&&(0,A.jsxs)(`div`,{className:`flex items-baseline gap-3`,children:[(0,A.jsx)(`span`,{className:e.label===`local`?`text-dim text-[12px] tracking-wider`:`text-accent text-[12px] tracking-wider`,children:e.label}),(0,A.jsxs)(`span`,{className:`text-mute text-[11px]`,children:[e.gpus.length,` gpu`]})]}),(0,A.jsx)(`div`,{className:`grid gap-12 `+jt(e.gpus.length),children:e.gpus.map(t=>{let n=a.filter(n=>(n.gpu_ids??[]).includes(t.index)&&(n.status===`ready`||n.status===`loading`)&&l(n,e));return(0,A.jsx)(Ot,{label:`gpu ${t.index}`,usedMb:t.mem_used_mb,totalMb:t.mem_total_mb,utilPct:t.util_pct,right:n.length===0?(0,A.jsx)(`span`,{className:`text-mute`,children:`idle`}):(0,A.jsxs)(`span`,{className:`text-dim`,children:[n.length,` loaded`]}),loaded:n.length>0&&(0,A.jsx)(`div`,{className:`pt-2 border-t border-rule-soft space-y-0.5`,children:n.map(e=>(0,A.jsx)(Nt,{d:e,modelName:o.find(t=>t.id===e.model_id)?.name??`#${e.id}`},e.id))})},t.index)})})]},e.node_id))]})}function It({values:e,width:t=80,height:n=20}){if(e.length===0)return(0,A.jsx)(`span`,{style:{color:`#888`},children:`—`});let r=Math.max(1,...e),i=t/Math.max(1,e.length-1);return(0,A.jsx)(`svg`,{width:t,height:n,"aria-label":`sparkline`,children:(0,A.jsx)(`polyline`,{fill:`none`,stroke:`currentColor`,strokeWidth:`1`,points:e.map((e,t)=>`${(t*i).toFixed(1)},${(n-e/r*n).toFixed(1)}`).join(` `)})})}function Lt({title:e,value:t,sub:n,spark:r,badge:i,onClick:a}){return(0,A.jsxs)(`div`,{className:`space-y-3 border-l border-rule pl-5 `+(a?`cursor-pointer hover:border-accent transition-colors`:``),onClick:a,children:[(0,A.jsx)(`div`,{className:`label`,children:e}),(0,A.jsx)(`div`,{className:`text-2xl font-light tracking-tightish tnum`,children:t}),r&&r.length>0&&(0,A.jsx)(`div`,{className:`text-accent`,children:(0,A.jsx)(It,{values:r,width:120,height:22})}),n&&(0,A.jsx)(`div`,{className:`text-mute text-[11px] tracking-wider`,children:n}),i&&(0,A.jsx)(`div`,{className:`text-mute text-[10px] tracking-wider uppercase`,children:i})]})}function Rt({buckets:e,height:t=56}){if(e.length===0)return(0,A.jsx)(`div`,{className:`text-mute text-[12px]`,children:`no traffic in window`});let n=Math.max(1,...e.map(e=>e.count)),r=100/e.length;return(0,A.jsx)(`svg`,{width:`100%`,height:t,viewBox:`0 0 100 ${t}`,preserveAspectRatio:`none`,"aria-label":`requests over time`,children:e.map((e,i)=>{let a=e.count/n*t;return(0,A.jsx)(`rect`,{x:i*r+1/2,y:t-a,width:Math.max(r-1,.4),height:a,className:`text-accent`,fill:`currentColor`,opacity:e.count===0?.15:.85,children:(0,A.jsxs)(`title`,{children:[e.count,` req`]})},i)})})}function zt({buckets:e,height:t=56}){if(e.filter(e=>e.count>0).length===0)return(0,A.jsx)(`div`,{className:`text-mute text-[12px]`,children:`no requests in window`});let n=Math.max(1,...e.map(e=>e.latency_p95_ms??0)),r=100/e.length;return(0,A.jsxs)(`div`,{className:`space-y-1`,children:[(0,A.jsx)(`svg`,{width:`100%`,height:t,viewBox:`0 0 100 ${t}`,preserveAspectRatio:`none`,"aria-label":`p95 latency over time`,children:e.map((e,i)=>{let a=(e.latency_p95_ms??0)/n*t;return(0,A.jsx)(`rect`,{x:i*r+1/2,y:t-a,width:Math.max(r-1,.4),height:a,className:`text-accent`,fill:`currentColor`,opacity:e.count===0?.12:.85,children:(0,A.jsxs)(`title`,{children:[`p95 `,e.latency_p95_ms??0,`ms · `,e.count,` req`]})},i)})}),(0,A.jsx)(`svg`,{width:`100%`,height:8,viewBox:`0 0 100 8`,preserveAspectRatio:`none`,"aria-label":`error rate over time`,children:e.map((e,t)=>(0,A.jsx)(`rect`,{x:t*r+1/2,y:0,width:Math.max(r-1,.4),height:8,className:`text-err`,fill:`currentColor`,opacity:e.count===0?.06:Math.max(.08,e.error_rate),children:(0,A.jsxs)(`title`,{children:[(e.error_rate*100).toFixed(1),`% errors · `,e.error_count,`/`,e.count]})},t))}),(0,A.jsxs)(`div`,{className:`flex justify-between text-mute text-[10px] tracking-wider`,children:[(0,A.jsx)(`span`,{children:`p95 latency`}),(0,A.jsxs)(`span`,{children:[`peak `,n.toLocaleString(),` ms · error rate strip`]})]})]})}function Bt({groups:e,limit:t=5}){let n=e.slice(0,t);if(n.length===0)return(0,A.jsx)(`div`,{className:`text-mute text-[12px]`,children:`no requests in window`});let r=Math.max(1,...n.map(e=>e.total));return(0,A.jsx)(`div`,{className:`space-y-2`,children:n.map(e=>(0,A.jsxs)(`div`,{className:`flex items-center gap-3 text-[12px]`,children:[(0,A.jsx)(`span`,{className:`font-mono text-ink truncate w-[14ch]`,title:e.label,children:e.label}),(0,A.jsx)(`span`,{className:`text-dim tnum w-[8ch] text-right`,children:e.total.toLocaleString()}),(0,A.jsx)(`div`,{className:`flex-1 h-1 bg-rule-soft relative overflow-hidden`,children:(0,A.jsx)(`div`,{className:`absolute inset-y-0 left-0 bg-accent`,style:{width:`${e.total/r*100}%`}})})]},e.key))})}function Vt({groups:e,limit:t=6}){let n=e.slice(0,t);return n.length===0?(0,A.jsx)(`div`,{className:`text-mute text-[12px]`,children:`no requests in window`}):(0,A.jsxs)(`table`,{className:`ditable`,children:[(0,A.jsx)(`thead`,{children:(0,A.jsxs)(`tr`,{children:[(0,A.jsx)(`th`,{children:`model`}),(0,A.jsx)(`th`,{className:`text-right`,children:`p95`}),(0,A.jsx)(`th`,{className:`text-right`,children:`errors`}),(0,A.jsx)(`th`,{className:`text-right`,children:`req`})]})}),(0,A.jsx)(`tbody`,{children:n.map(e=>{let t=e.summary.error_rate*100;return(0,A.jsxs)(`tr`,{children:[(0,A.jsx)(`td`,{className:`font-mono truncate max-w-[16ch]`,title:e.label,children:e.label}),(0,A.jsx)(`td`,{className:`text-right tnum text-dim`,children:e.summary.latency_p95_ms===null?`—`:`${e.summary.latency_p95_ms} ms`}),(0,A.jsx)(`td`,{className:`text-right tnum`,children:(0,A.jsxs)(`span`,{className:t>0?`text-err`:`text-mute`,children:[t.toFixed(+(t>0&&t<1)),`%`]})}),(0,A.jsx)(`td`,{className:`text-right tnum text-mute`,children:e.summary.count.toLocaleString()})]},e.key)})})]})}function Ht(){let e=j({queryKey:M.deployments,queryFn:P.listDeployments,refetchInterval:2e3}),t=j({queryKey:M.models,queryFn:P.listModels,refetchInterval:5e3}),n=j({queryKey:M.nodes,queryFn:P.listNodes,refetchInterval:5e3}),r=(e.data??[]).filter(e=>e.status===`ready`||e.status===`loading`);return(0,A.jsxs)(`div`,{className:`space-y-4`,children:[(0,A.jsxs)(`div`,{className:`flex items-baseline justify-between`,children:[(0,A.jsx)(`div`,{className:`label`,children:`active deployments`}),(0,A.jsx)(`button`,{className:`text-mute text-[11px] tracking-wider hover:text-dim transition-colors`,onClick:()=>{location.hash=`#/serving/deployments`},children:`manage in serving →`})]}),r.length===0?(0,A.jsx)(`div`,{className:`text-mute text-[12px]`,children:`nothing loaded`}):(0,A.jsx)(`div`,{className:`space-y-1`,children:r.map(e=>{let r=(t.data??[]).find(t=>t.id===e.model_id),i=(n.data?.nodes??[]).find(t=>t.id===e.node_id)?.label??(e.node_id?`#${e.node_id}`:`local`);return(0,A.jsxs)(`div`,{className:`flex items-center gap-3 text-[12px] py-1`,children:[(0,A.jsx)(`span`,{className:`dot dot-${e.status}`}),(0,A.jsx)(`span`,{className:`text-ink truncate flex-1 min-w-0`,children:r?.name??`#${e.id}`}),(0,A.jsx)(`span`,{className:`text-mute text-[10px] tracking-wider`,children:e.backend}),(0,A.jsx)(`span`,{className:`text-dim tnum w-[7ch] text-right`,children:(e.gpu_ids??[]).length?`gpu ${(e.gpu_ids??[]).join(`,`)}`:`-`}),i!==`local`&&(0,A.jsx)(`span`,{className:`text-accent text-[10px]`,children:i})]},e.id)})})]})}function Ut(e){let t=(e?.nodes??[]).flatMap(e=>e.deployments),n=0,r=0,i=0,a=0,o=0,s=0;for(let e of t){n+=e.in_flight,r+=e.requests_last_window,i+=e.errors_last_window;let t=e.requests_last_window||0;a+=e.latency_p50_ms*t,o+=e.latency_p95_ms*t,s+=t}let c=t.length?t.reduce((e,t)=>e+t.latency_p50_ms,0)/t.length:0,l=t.length?t.reduce((e,t)=>e+t.latency_p95_ms,0)/t.length:0;return{inFlight:n,requestsWindow:r,errorsWindow:i,errorRate:i/Math.max(r,1),latencyP50:s?a/s:c,latencyP95:s?o/s:l}}function Wt(e,t){if(e.length===0||t<=0)return{reqPerMin:0,tokPerSec:0,totalOut:0};let n=e.slice(-3),r=n.length*t,i=n.reduce((e,t)=>e+t.count,0),a=n.reduce((e,t)=>e+t.tokens_out,0),o=e.reduce((e,t)=>e+t.tokens_out,0);return{reqPerMin:r?i/r*60:0,tokPerSec:r?a/r:0,totalOut:o}}function Gt(e,t){return(0,A.jsxs)(A.Fragment,{children:[e,(0,A.jsxs)(`span`,{className:`text-mute text-[13px]`,children:[` `,t]})]})}function Kt(){let e=j({queryKey:M.deployments,queryFn:P.listDeployments,refetchInterval:2e3}),t=j({queryKey:M.gpus,queryFn:P.listGpus,refetchInterval:2e3}),n=j({queryKey:M.nodes,queryFn:P.listNodes,refetchInterval:5e3}),r=j({queryKey:M.metricsSnapshot,queryFn:P.getMetricsSnapshot,refetchInterval:2e3}),i=j({queryKey:M.usageSeries(3600,60,`none`),queryFn:()=>P.getUsageSeries(3600,60),refetchInterval:5e3}),a=j({queryKey:M.usageSeries(86400,3600,`none`),queryFn:()=>P.getUsageSeries(86400,3600),refetchInterval:3e4}),o=j({queryKey:M.usageSeries(86400,3600,`model`),queryFn:()=>P.getUsageByModel(86400,3600),refetchInterval:3e4}),s=j({queryKey:M.metricsSummary(86400,`none`),queryFn:()=>P.getMetricsSummary(86400),refetchInterval:15e3}),c=j({queryKey:M.metricsHistory(86400,3600),queryFn:()=>P.getMetricsHistory(86400,3600),refetchInterval:3e4}),l=j({queryKey:M.metricsSummary(86400,`model`),queryFn:()=>P.getMetricsByModel(86400),refetchInterval:3e4}),u=(e.data??[]).filter(e=>e.status===`ready`||e.status===`loading`),d=Ut(r.data),f=i.data?.buckets??[],p=Wt(f,60),m=f.slice(-30).map(e=>e.count),h=f.slice(-30).map(e=>e.tokens_out),g=s.data?.summary,_=(r.data?.nodes??[]).reduce((e,t)=>e+t.gpus.length,0)||(t.data??[]).length;return(0,A.jsxs)(`div`,{className:`space-y-14`,children:[(0,A.jsxs)(`header`,{className:`flex items-baseline justify-between`,children:[(0,A.jsx)(`h2`,{className:`text-2xl font-light tracking-tightish caret`,children:`overview`}),(0,A.jsxs)(`div`,{className:`flex items-baseline gap-6`,children:[(()=>{let e=n.data?.nodes??[],t=e.filter(e=>e.status===`ready`).length,r=e.filter(e=>e.label!==`local`).length;return e.length===0?null:(0,A.jsx)(`div`,{className:`label`,title:`cluster nodes`,children:r===0?(0,A.jsx)(A.Fragment,{children:`single-node`}):(0,A.jsxs)(A.Fragment,{children:[`cluster `,(0,A.jsxs)(`span`,{className:`text-dim`,children:[t,`/`,e.length]})]})})})(),(0,A.jsxs)(`div`,{className:`label`,children:[_,` gpu / `,u.length,` active`]})]})]}),(0,A.jsx)(Ft,{}),(0,A.jsxs)(`section`,{className:`space-y-6`,children:[(0,A.jsx)(`div`,{className:`label`,children:`request stats`}),(0,A.jsxs)(`div`,{className:`grid grid-cols-2 lg:grid-cols-4 gap-y-8 gap-x-6`,children:[(0,A.jsx)(Lt,{title:`volume`,value:Gt(p.reqPerMin.toFixed(+(p.reqPerMin<10)),`req/min`),sub:`${d.inFlight} in flight`,spark:m,badge:`live`}),(0,A.jsx)(Lt,{title:`latency`,value:Gt(g?.latency_p50_ms==null?`—`:String(g.latency_p50_ms),`ms p50`),sub:`p95 ${g?.latency_p95_ms??`—`} ms`,badge:`24h`}),(0,A.jsx)(Lt,{title:`errors`,value:Gt(g?(g.error_rate*100).toFixed(1):`—`,`%`),sub:(0,A.jsxs)(`span`,{className:`text-accent`,children:[g?.error_count??0,` in 24h → see traffic`]}),badge:`24h`,onClick:()=>{location.hash=`#/observe/requests`}}),(0,A.jsx)(Lt,{title:`throughput`,value:Gt(p.tokPerSec.toFixed(0),`tok/s`),sub:`${p.totalOut.toLocaleString()} out tok · 1h`,spark:h,badge:`live`})]})]}),(0,A.jsxs)(`section`,{className:`space-y-4`,children:[(0,A.jsxs)(`div`,{className:`flex items-baseline justify-between`,children:[(0,A.jsx)(`div`,{className:`label`,children:`traffic over time`}),(0,A.jsx)(`div`,{className:`text-mute text-[10px] tracking-wider uppercase`,children:`last 24h · bounded by retention`})]}),(0,A.jsx)(Rt,{buckets:a.data?.buckets??[]})]}),(0,A.jsxs)(`section`,{className:`space-y-4`,children:[(0,A.jsxs)(`div`,{className:`flex items-baseline justify-between`,children:[(0,A.jsx)(`div`,{className:`label`,children:`latency & errors over time`}),(0,A.jsx)(`div`,{className:`text-mute text-[10px] tracking-wider uppercase`,children:`last 24h`})]}),(0,A.jsx)(zt,{buckets:c.data?.buckets??[]})]}),(0,A.jsxs)(`div`,{className:`grid grid-cols-1 lg:grid-cols-2 gap-x-12 gap-y-10`,children:[(0,A.jsxs)(`section`,{className:`space-y-4`,children:[(0,A.jsx)(`div`,{className:`label`,children:`top models · 24h`}),(0,A.jsx)(Bt,{groups:o.data?.groups??[]})]}),(0,A.jsxs)(`section`,{className:`space-y-4`,children:[(0,A.jsx)(`div`,{className:`label`,children:`latency & errors by model · 24h`}),(0,A.jsx)(Vt,{groups:l.data?.groups??[]})]})]}),(0,A.jsx)(`section`,{children:(0,A.jsx)(Ht,{})})]})}function qt({used:e,reserved:t,status:n}){return n===`stopped`||n===`failed`?(0,A.jsx)(`span`,{children:`-`}):e&&e>0?(0,A.jsxs)(`div`,{className:`flex flex-col items-end leading-tight`,children:[(0,A.jsx)(`span`,{children:kt(e)}),(0,A.jsxs)(`span`,{className:`text-mute text-[10px]`,children:[`est `,kt(t)]})]}):(0,A.jsxs)(`div`,{className:`flex flex-col items-end leading-tight`,children:[(0,A.jsx)(`span`,{className:`text-dim`,children:kt(t)}),(0,A.jsx)(`span`,{className:`text-mute text-[10px]`,children:`est`})]})}function Jt(){let e=rt(),t=j({queryKey:M.deployments,queryFn:P.listDeployments,refetchInterval:2e3}),n=j({queryKey:M.models,queryFn:P.listModels,refetchInterval:5e3}),r=j({queryKey:M.nodes,queryFn:P.listNodes,refetchInterval:5e3}),[i,a]=(0,k.useState)(!1),[o,s]=(0,k.useState)(null),[c,l]=(0,k.useState)(``),u=yt({mutationFn:e=>P.stopDeployment(e),onMutate:e=>{s(e),l(``)},onError:e=>l(e.message),onSettled:()=>{s(null),e.invalidateQueries({queryKey:M.deployments})}}),d=yt({mutationFn:({id:e,pinned:t})=>t?P.unpinDeployment(e):P.pinDeployment(e),onMutate:({id:e})=>{s(e),l(``)},onError:e=>l(e.message),onSettled:()=>{s(null),e.invalidateQueries({queryKey:M.deployments})}}),f=t.data??[],p=f.filter(e=>e.status===`ready`||e.status===`loading`),m=i?f:p,h=f.length-m.length;return(0,A.jsxs)(`div`,{className:`space-y-10`,children:[(0,A.jsxs)(`header`,{className:`flex items-baseline justify-between`,children:[(0,A.jsx)(`h2`,{className:`text-2xl font-light tracking-tightish caret`,children:`deployments`}),(0,A.jsxs)(`div`,{className:`label`,children:[p.length,` active / `,f.length,` total`]})]}),(0,A.jsxs)(`section`,{className:`space-y-4`,children:[(0,A.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,A.jsx)(`div`,{className:`label`,children:`deployments`}),(0,A.jsxs)(`label`,{className:`text-mute text-[11px] tracking-wider select-none cursor-pointer hover:text-dim transition-colors`,children:[(0,A.jsx)(`input`,{type:`checkbox`,className:`mr-2 accent-accent align-middle`,checked:i,onChange:e=>a(e.target.checked)}),`show stopped `,h>0&&!i&&(0,A.jsxs)(`span`,{className:`text-accent`,children:[`(`,h,`)`]})]})]}),c&&(0,A.jsx)(`div`,{className:`text-err text-[11px] tracking-wider`,children:c}),(0,A.jsxs)(`table`,{className:`ditable`,children:[(0,A.jsx)(`thead`,{children:(0,A.jsxs)(`tr`,{children:[(0,A.jsx)(`th`,{children:`#`}),(0,A.jsx)(`th`,{children:`model`}),(0,A.jsx)(`th`,{children:`backend`}),(0,A.jsx)(`th`,{children:`node`}),(0,A.jsx)(`th`,{children:`status`}),(0,A.jsx)(`th`,{className:`text-right`,children:`vram`}),(0,A.jsx)(`th`,{className:`text-right`,children:`gpu`}),(0,A.jsx)(`th`,{className:`text-right`,children:`actions`})]})}),(0,A.jsxs)(`tbody`,{children:[m.length===0&&(0,A.jsx)(`tr`,{children:(0,A.jsxs)(`td`,{colSpan:8,className:`!py-12 text-center text-mute`,children:[`no active deployments. load one from `,(0,A.jsx)(`span`,{className:`text-dim`,children:`models`})]})}),m.map(e=>{let t=(n.data??[]).find(t=>t.id===e.model_id),i=(r.data?.nodes??[]).find(t=>t.id===e.node_id)?.label??(e.node_id?`#${e.node_id}`:`local`),a=e.status===`ready`||e.status===`loading`,s=o===e.id;return(0,A.jsxs)(`tr`,{title:e.last_error||void 0,children:[(0,A.jsx)(`td`,{className:`text-mute tnum`,children:e.id}),(0,A.jsx)(`td`,{children:t?.name??`-`}),(0,A.jsx)(`td`,{className:`text-dim`,children:e.backend}),(0,A.jsx)(`td`,{children:(0,A.jsx)(`span`,{className:i===`local`?`text-mute`:`text-accent`,children:i})}),(0,A.jsxs)(`td`,{children:[(0,A.jsx)(`span`,{className:`dot dot-${e.status}`}),(0,A.jsx)(`span`,{className:`text-dim`,children:e.status})]}),(0,A.jsx)(`td`,{className:`text-right tnum`,children:(0,A.jsx)(qt,{used:e.vram_used_mb??null,reserved:e.vram_reserved_mb,status:e.status})}),(0,A.jsx)(`td`,{className:`text-right text-dim tnum`,children:At(e.gpu_ids)}),(0,A.jsxs)(`td`,{className:`text-right space-x-5 whitespace-nowrap`,children:[(0,A.jsx)(`button`,{className:`transition-opacity hover:opacity-70 disabled:opacity-40 `+(e.pinned?`text-accent`:`text-dim`),disabled:s,onClick:()=>d.mutate({id:e.id,pinned:!!e.pinned}),title:e.pinned?`pinned: idle reaper will not stop this deployment`:`pin to keep alive through idle timeout`,children:e.pinned?`unpin`:`pin`}),a?(0,A.jsx)(`button`,{className:`btn-link-danger disabled:opacity-40`,disabled:s,onClick:()=>{confirm(`stop deployment #${e.id}?`)&&u.mutate(e.id)},children:s?`stopping...`:`stop`}):(0,A.jsx)(`span`,{className:`text-mute`,children:`—`})]})]},e.id)})]})]})]})]})}function Yt(e){let t=e.split(`,`).map(e=>e.trim()).filter(Boolean).map(Number).filter(e=>Number.isInteger(e)&&e>=0);if(t.length===0)throw Error(`gpu_ids: at least one integer required`);return t}function Xt(e){let t=Number(e);if(!Number.isInteger(t)||t<128)throw Error(`max_model_len: integer >= 128`);return t}function Zt(e){return e&&e!==`local`?e:null}var Qt={backend:``,maxModelLen:`4096`,gpuIds:`0`,pinned:!1,nodeLabel:``},$t=e=>new Promise(t=>setTimeout(t,e));function en(e){return e instanceof TypeError&&/failed to fetch|network/i.test(e.message)}async function tn(e,t){for(let n=0;n<15;n+=1){let n=(await P.listDeployments()).filter(n=>n.id>t&&n.model_id===e).sort((e,t)=>t.id-e.id)[0];if(n){if(n.status===`failed`)throw Error(n.last_error||`deployment failed after it started`);return n}await $t(1e3)}throw Error(`deployment request disconnected before a new deployment appeared`)}function nn(){let e=rt(),t=j({queryKey:M.models,queryFn:P.listModels}),n=j({queryKey:M.backends,queryFn:P.listBackends}),r=j({queryKey:M.gpus,queryFn:P.listGpus}),i=j({queryKey:M.nodes,queryFn:P.listNodes}),a=j({queryKey:M.config,queryFn:P.getConfig}),[o,s]=(0,k.useState)(``),[c,l]=(0,k.useState)(``),[u,d]=(0,k.useState)(null),[f,p]=(0,k.useState)(Qt),[m,h]=(0,k.useState)(``),g=a.data?.values.leader_only===!0,_=(i.data?.nodes??[]).filter(e=>e.label!==`local`),v=_.filter(e=>e.status===`ready`),y=f.nodeLabel||(g?v[0]?.label??``:``),b=g&&!y,x=yt({mutationFn:()=>P.createModel({name:c||o.split(`/`).pop().toLowerCase(),hf_repo:o}),onSuccess:()=>{s(``),l(``),e.invalidateQueries({queryKey:M.models})}}),ee=yt({mutationFn:e=>P.deleteModel(e),onSuccess:()=>e.invalidateQueries({queryKey:M.models})}),S=yt({mutationFn:async e=>{let t=Yt(f.gpuIds),n=Xt(f.maxModelLen),r={model_name:e.name,hf_repo:e.hf_repo,gpu_ids:t,max_model_len:n,pinned:f.pinned};f.backend&&(r.backend=f.backend),r.node_label=Zt(y);let i=(await P.listDeployments()).reduce((e,t)=>Math.max(e,t.id),0);try{return await P.loadModel(r)}catch(t){if(!en(t))throw t;return tn(e.id,i)}},onMutate:()=>h(``),onSuccess:()=>{d(null),p(Qt),e.invalidateQueries({queryKey:M.deployments})},onError:e=>h(e.message)});return(0,A.jsxs)(`div`,{className:`space-y-14`,children:[(0,A.jsxs)(`header`,{className:`flex items-baseline justify-between`,children:[(0,A.jsx)(`h2`,{className:`text-2xl font-light tracking-tightish caret`,children:`models`}),(0,A.jsxs)(`div`,{className:`label`,children:[(t.data??[]).length,` registered`]})]}),(0,A.jsxs)(`section`,{className:`space-y-5`,children:[(0,A.jsx)(`div`,{className:`label`,children:`register`}),(0,A.jsxs)(`div`,{className:`grid grid-cols-[1fr_220px_auto] gap-3 max-w-3xl`,children:[(0,A.jsx)(`input`,{className:`field font-mono`,placeholder:`huggingface repo (e.g. Qwen/Qwen3.6-35B-A3B-FP8)`,value:o,onChange:e=>s(e.target.value)}),(0,A.jsx)(`input`,{className:`field font-mono`,placeholder:`local alias (optional)`,value:c,onChange:e=>l(e.target.value)}),(0,A.jsx)(`button`,{className:`btn-primary`,disabled:!o.trim()||x.isPending,onClick:()=>x.mutate(),children:x.isPending?`registering...`:`register`})]}),x.error&&(0,A.jsx)(`div`,{className:`text-err text-[12px]`,children:x.error.message})]}),(0,A.jsxs)(`section`,{className:`space-y-4`,children:[(0,A.jsx)(`div`,{className:`label`,children:`registry`}),(0,A.jsxs)(`table`,{className:`ditable`,children:[(0,A.jsx)(`thead`,{children:(0,A.jsxs)(`tr`,{children:[(0,A.jsx)(`th`,{children:`name`}),(0,A.jsx)(`th`,{children:`huggingface`}),(0,A.jsx)(`th`,{children:`revision`}),(0,A.jsx)(`th`,{className:`text-right`})]})}),(0,A.jsxs)(`tbody`,{children:[(t.data??[]).length===0&&(0,A.jsx)(`tr`,{children:(0,A.jsx)(`td`,{colSpan:4,className:`!py-12 text-center text-mute`,children:`no models registered yet`})}),(t.data??[]).map(e=>{let t=u===e.name,i=S.isPending&&u===e.name;return(0,A.jsxs)(k.Fragment,{children:[(0,A.jsxs)(`tr`,{children:[(0,A.jsx)(`td`,{children:e.name}),(0,A.jsx)(`td`,{className:`text-dim`,children:e.hf_repo}),(0,A.jsx)(`td`,{className:`text-mute`,children:e.revision}),(0,A.jsxs)(`td`,{className:`text-right space-x-6`,children:[(0,A.jsx)(`button`,{className:`text-accent hover:opacity-70 transition-opacity`,onClick:()=>{t?d(null):(d(e.name),p(Qt),h(``))},children:t?`cancel`:`load`}),(0,A.jsx)(`button`,{className:`btn-link-danger`,onClick:()=>ee.mutate(e.name),children:`delete`})]})]}),t&&(0,A.jsx)(`tr`,{children:(0,A.jsx)(`td`,{colSpan:4,className:`!pt-2 !pb-6`,children:(0,A.jsxs)(`div`,{className:`bg-elev/40 border border-rule p-5 space-y-4`,children:[(0,A.jsxs)(`div`,{className:`grid grid-cols-2 md:grid-cols-5 gap-4`,children:[(0,A.jsxs)(`div`,{className:`space-y-1`,children:[(0,A.jsx)(`div`,{className:`label`,children:`backend`}),(0,A.jsxs)(`select`,{className:`field font-mono w-full text-[12px]`,value:f.backend,onChange:e=>p(t=>({...t,backend:e.target.value})),children:[(0,A.jsx)(`option`,{value:``,children:`auto (server picks)`}),(n.data??[]).map(e=>(0,A.jsx)(`option`,{value:e.name,children:e.name},e.name))]})]}),(0,A.jsxs)(`div`,{className:`space-y-1`,children:[(0,A.jsx)(`div`,{className:`label`,children:`node`}),(0,A.jsxs)(`select`,{className:`field font-mono w-full text-[12px]`,value:y,onChange:e=>p(t=>({...t,nodeLabel:e.target.value})),children:[!g&&(0,A.jsx)(`option`,{value:``,children:`leader (local)`}),v.map(e=>(0,A.jsxs)(`option`,{value:e.label,children:[e.label,` · `,e.gpu_count,` gpu`]},e.id)),g&&v.length===0&&(0,A.jsx)(`option`,{value:``,disabled:!0,children:`no ready agents`})]}),_.length===0&&(0,A.jsx)(`div`,{className:`text-mute text-[10px] tracking-wider`,children:`no agents enrolled`}),_.length>0&&v.length===0&&(0,A.jsx)(`div`,{className:`text-mute text-[10px] tracking-wider`,children:`no ready agents online`})]}),(0,A.jsxs)(`div`,{className:`space-y-1`,children:[(0,A.jsx)(`div`,{className:`label`,children:`max model len`}),(0,A.jsx)(`input`,{className:`field font-mono w-full text-[12px]`,value:f.maxModelLen,onChange:e=>p(t=>({...t,maxModelLen:e.target.value})),placeholder:`4096`})]}),(0,A.jsxs)(`div`,{className:`space-y-1`,children:[(0,A.jsx)(`div`,{className:`label`,children:`gpu ids`}),(0,A.jsx)(`input`,{className:`field font-mono w-full text-[12px]`,value:f.gpuIds,onChange:e=>p(t=>({...t,gpuIds:e.target.value})),placeholder:`0 or 0,1`}),f.nodeLabel&&f.nodeLabel!==`local`?(0,A.jsxs)(`div`,{className:`text-mute text-[10px] tracking-wider`,children:[`on agent `,f.nodeLabel]}):(r.data??[]).length>0&&(0,A.jsxs)(`div`,{className:`text-mute text-[10px] tracking-wider`,children:[`available: `,(r.data??[]).map(e=>e.index).join(`, `)]})]}),(0,A.jsxs)(`div`,{className:`space-y-1`,children:[(0,A.jsx)(`div`,{className:`label`,children:`options`}),(0,A.jsxs)(`label`,{className:`text-[12px] text-dim flex items-center gap-2 select-none cursor-pointer pt-1`,children:[(0,A.jsx)(`input`,{type:`checkbox`,className:`accent-accent`,checked:f.pinned,onChange:e=>p(t=>({...t,pinned:e.target.checked}))}),`pin (idle reaper skips it)`]})]})]}),m&&(0,A.jsx)(`div`,{className:`text-err text-[11px] tracking-wider`,children:m}),(0,A.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,A.jsx)(`button`,{className:`btn-primary`,disabled:i||b,onClick:()=>S.mutate(e),children:i?`launching...`:`deploy`}),(0,A.jsx)(`button`,{className:`btn`,disabled:i,onClick:()=>d(null),children:`cancel`})]})]})})})]},e.id)})]})]})]})]})}function rn(){let e=rt(),t=j({queryKey:M.adapters,queryFn:P.listAdapters,refetchInterval:5e3}),n=j({queryKey:M.models,queryFn:P.listModels}),[r,i]=(0,k.useState)(`hf`),[a,o]=(0,k.useState)(``),[s,c]=(0,k.useState)(``),[l,u]=(0,k.useState)(``),[d,f]=(0,k.useState)(``),p=n.data??[],m=yt({mutationFn:async()=>{let e=d||a.split(`/`).pop().toLowerCase();return await P.createAdapter({name:e,base_model_name:l,hf_repo:a}),P.downloadAdapter(e)},onSuccess:()=>{o(``),f(``),e.invalidateQueries({queryKey:M.adapters})}}),h=yt({mutationFn:()=>{let e=d||s.split(`/`).filter(Boolean).pop().toLowerCase();return P.addLocalAdapter({name:e,base_model_name:l,local_path:s})},onSuccess:()=>{c(``),f(``),e.invalidateQueries({queryKey:M.adapters})}}),g=yt({mutationFn:e=>P.deleteAdapter(e,!0),onSuccess:()=>e.invalidateQueries({queryKey:M.adapters})}),_=t.data??[];return(0,A.jsxs)(`div`,{className:`space-y-14`,children:[(0,A.jsxs)(`header`,{className:`flex items-baseline justify-between`,children:[(0,A.jsx)(`h2`,{className:`text-2xl font-light tracking-tightish caret`,children:`adapters`}),(0,A.jsxs)(`div`,{className:`label`,children:[_.length,` registered`]})]}),(0,A.jsxs)(`section`,{className:`space-y-5`,children:[(0,A.jsxs)(`div`,{className:`flex items-center gap-6`,children:[(0,A.jsx)(`div`,{className:`label`,children:`register`}),(0,A.jsxs)(`div`,{className:`flex items-center gap-3 text-[11px]`,children:[(0,A.jsx)(`button`,{onClick:()=>i(`hf`),className:r===`hf`?`text-ink`:`text-mute hover:text-dim`,children:`huggingface`}),(0,A.jsx)(`span`,{className:`text-mute`,children:`/`}),(0,A.jsx)(`button`,{onClick:()=>i(`local`),className:r===`local`?`text-ink`:`text-mute hover:text-dim`,children:`local path`})]})]}),(0,A.jsxs)(`div`,{className:`grid grid-cols-[1fr_200px_160px_auto] gap-3 max-w-4xl`,children:[r===`hf`?(0,A.jsx)(`input`,{className:`field font-mono`,placeholder:`hf repo (e.g. user/qwen3-lora)`,value:a,onChange:e=>o(e.target.value)}):(0,A.jsx)(`input`,{className:`field font-mono`,placeholder:`/abs/path/to/adapter-dir`,value:s,onChange:e=>c(e.target.value)}),(0,A.jsxs)(`select`,{className:`field font-mono`,value:l,onChange:e=>u(e.target.value),children:[(0,A.jsx)(`option`,{value:``,children:`base model`}),p.map(e=>(0,A.jsx)(`option`,{value:e.name,children:e.name},e.id))]}),(0,A.jsx)(`input`,{className:`field font-mono`,placeholder:`local name (opt)`,value:d,onChange:e=>f(e.target.value)}),r===`hf`?(0,A.jsx)(`button`,{className:`btn-primary`,disabled:!a.trim()||!l||m.isPending,onClick:()=>m.mutate(),children:m.isPending?`pulling...`:`pull`}):(0,A.jsx)(`button`,{className:`btn-primary`,disabled:!s.trim()||!l||h.isPending,onClick:()=>h.mutate(),children:h.isPending?`adding...`:`add`})]}),m.error&&(0,A.jsx)(`div`,{className:`text-err text-[12px]`,children:m.error.message}),h.error&&(0,A.jsx)(`div`,{className:`text-err text-[12px]`,children:h.error.message})]}),(0,A.jsxs)(`section`,{className:`space-y-4`,children:[(0,A.jsx)(`div`,{className:`label`,children:`registry`}),(0,A.jsxs)(`table`,{className:`ditable`,children:[(0,A.jsx)(`thead`,{children:(0,A.jsxs)(`tr`,{children:[(0,A.jsx)(`th`,{children:`name`}),(0,A.jsx)(`th`,{children:`base`}),(0,A.jsx)(`th`,{children:`source`}),(0,A.jsx)(`th`,{className:`text-right`,children:`rank`}),(0,A.jsx)(`th`,{className:`text-right`,children:`size`}),(0,A.jsx)(`th`,{children:`loaded into`}),(0,A.jsx)(`th`,{className:`text-right`})]})}),(0,A.jsxs)(`tbody`,{children:[_.length===0&&(0,A.jsx)(`tr`,{children:(0,A.jsx)(`td`,{colSpan:7,className:`!py-12 text-center text-mute`,children:`no adapters registered yet`})}),_.map(e=>(0,A.jsxs)(`tr`,{children:[(0,A.jsx)(`td`,{children:e.name}),(0,A.jsx)(`td`,{className:`text-dim`,children:e.base}),(0,A.jsx)(`td`,{className:`text-mute font-mono text-[11px]`,children:e.hf_repo.startsWith(`local:`)?`local`:e.hf_repo}),(0,A.jsx)(`td`,{className:`text-right tnum`,children:e.lora_rank??`-`}),(0,A.jsx)(`td`,{className:`text-right tnum`,children:e.size_mb==null?e.downloaded?`-`:`not pulled`:`${e.size_mb} MB`}),(0,A.jsx)(`td`,{className:`text-mute tnum`,children:(e.loaded_into??[]).length>0?(e.loaded_into??[]).join(`,`):`-`}),(0,A.jsx)(`td`,{className:`text-right`,children:(0,A.jsx)(`button`,{className:`btn-link-danger`,onClick:()=>g.mutate(e.name),children:`remove`})})]},e.id))]})]})]})]})}function an({profiles:e,models:t,backends:n,nodes:r,form:i,setForm:a,formError:o,actionError:s,createProfile:c,deployProfile:l,deleteProfile:u}){return(0,A.jsxs)(`section`,{className:`space-y-4`,children:[(0,A.jsxs)(`div`,{className:`flex items-baseline justify-between`,children:[(0,A.jsx)(`div`,{className:`label`,children:`profiles`}),(0,A.jsx)(`div`,{className:`text-mute text-[11px] tracking-wider`,children:`reusable launch definition`})]}),s&&(0,A.jsx)(`div`,{className:`text-err text-[11px] tracking-wider`,children:s}),(0,A.jsxs)(`div`,{className:`bg-elev/40 border border-rule p-5 space-y-4`,children:[(0,A.jsxs)(`div`,{className:`grid grid-cols-12 gap-3`,children:[(0,A.jsxs)(`div`,{className:`space-y-1 col-span-12 md:col-span-3`,children:[(0,A.jsx)(`div`,{className:`label`,children:`profile name`}),(0,A.jsx)(`input`,{className:`field font-mono w-full text-[12px]`,placeholder:`qwen-vllm`,value:i.name,onChange:e=>a(t=>({...t,name:e.target.value}))})]}),(0,A.jsxs)(`div`,{className:`space-y-1 col-span-12 md:col-span-3`,children:[(0,A.jsx)(`div`,{className:`label`,children:`model name`}),(0,A.jsx)(`input`,{className:`field font-mono w-full text-[12px]`,list:`profile-model-list`,placeholder:`qwen`,value:i.model_name,onChange:e=>{let n=e.target.value,r=t.find(e=>e.name===n);a(e=>({...e,model_name:n,hf_repo:r?r.hf_repo:e.hf_repo}))}}),(0,A.jsx)(`datalist`,{id:`profile-model-list`,children:t.map(e=>(0,A.jsx)(`option`,{value:e.name},e.id))})]}),(0,A.jsxs)(`div`,{className:`space-y-1 col-span-12 md:col-span-6`,children:[(0,A.jsx)(`div`,{className:`label`,children:`hf repo`}),(0,A.jsx)(`input`,{className:`field font-mono w-full text-[12px]`,placeholder:`Qwen/Qwen2.5-0.5B-Instruct`,value:i.hf_repo,onChange:e=>a(t=>({...t,hf_repo:e.target.value}))})]}),(0,A.jsxs)(`div`,{className:`space-y-1 col-span-6 md:col-span-2`,children:[(0,A.jsx)(`div`,{className:`label`,children:`backend`}),(0,A.jsxs)(`select`,{className:`field font-mono w-full text-[12px]`,value:i.backend,onChange:e=>a(t=>({...t,backend:e.target.value})),children:[(0,A.jsx)(`option`,{value:``,children:`auto`}),n.map(e=>(0,A.jsx)(`option`,{value:e.name,children:e.name},e.name))]})]}),(0,A.jsxs)(`div`,{className:`space-y-1 col-span-6 md:col-span-2`,children:[(0,A.jsx)(`div`,{className:`label`,children:`node`}),(0,A.jsxs)(`select`,{className:`field font-mono w-full text-[12px]`,value:i.node_label,onChange:e=>a(t=>({...t,node_label:e.target.value})),children:[(0,A.jsx)(`option`,{value:``,children:`leader (local)`}),r.filter(e=>e.label!==`local`&&e.status===`ready`).map(e=>(0,A.jsxs)(`option`,{value:e.label,children:[e.label,` · `,e.gpu_count,` gpu`]},e.id))]})]}),(0,A.jsxs)(`div`,{className:`space-y-1 col-span-6 md:col-span-2`,children:[(0,A.jsx)(`div`,{className:`label`,children:`gpu ids`}),(0,A.jsx)(`input`,{className:`field font-mono w-full text-[12px] tnum`,placeholder:`0 or 0,1`,value:i.gpu_ids,onChange:e=>a(t=>({...t,gpu_ids:e.target.value}))})]}),(0,A.jsxs)(`div`,{className:`space-y-1 col-span-6 md:col-span-3`,children:[(0,A.jsx)(`div`,{className:`label`,children:`max model len`}),(0,A.jsx)(`input`,{className:`field font-mono w-full text-[12px] tnum`,value:i.max_model_len,onChange:e=>a(t=>({...t,max_model_len:e.target.value}))})]}),(0,A.jsxs)(`div`,{className:`space-y-1 col-span-6 md:col-span-3 flex flex-col`,children:[(0,A.jsx)(`div`,{className:`label`,children:`options`}),(0,A.jsxs)(`label`,{className:`text-[12px] text-dim flex items-center gap-2 select-none cursor-pointer pt-2`,children:[(0,A.jsx)(`input`,{type:`checkbox`,className:`accent-accent`,checked:i.pinned,onChange:e=>a(t=>({...t,pinned:e.target.checked}))}),`pinned (skip idle reaper)`]})]})]}),o&&(0,A.jsx)(`div`,{className:`text-err text-[11px] tracking-wider`,children:o}),(0,A.jsx)(`div`,{className:`flex items-center gap-3`,children:(0,A.jsx)(`button`,{className:`btn-primary`,disabled:!i.name.trim()||!i.model_name.trim()||!i.hf_repo.trim()||c.isPending,onClick:()=>c.mutate(),children:c.isPending?`creating…`:`create profile`})})]}),(0,A.jsxs)(`table`,{className:`ditable`,children:[(0,A.jsx)(`thead`,{children:(0,A.jsxs)(`tr`,{children:[(0,A.jsx)(`th`,{children:`name`}),(0,A.jsx)(`th`,{children:`model`}),(0,A.jsx)(`th`,{children:`backend`}),(0,A.jsx)(`th`,{className:`text-right`,children:`gpus`}),(0,A.jsx)(`th`,{className:`text-right`,children:`ctx`}),(0,A.jsx)(`th`,{children:`pinned`}),(0,A.jsx)(`th`,{className:`text-right`,children:`actions`})]})}),(0,A.jsxs)(`tbody`,{children:[e.length===0&&(0,A.jsx)(`tr`,{children:(0,A.jsx)(`td`,{colSpan:7,className:`!py-12 text-center text-mute`,children:`no profiles yet. create one above to define how a model is launched.`})}),e.map(e=>{let t=l.isPending&&l.variables===e.name,n=u.isPending&&u.variables===e.name;return(0,A.jsxs)(`tr`,{children:[(0,A.jsx)(`td`,{children:e.name}),(0,A.jsx)(`td`,{className:`text-dim`,children:e.model_name}),(0,A.jsx)(`td`,{className:`text-dim`,children:e.backend}),(0,A.jsx)(`td`,{className:`text-right text-dim tnum`,children:e.gpu_ids.join(`,`)||`—`}),(0,A.jsx)(`td`,{className:`text-right tnum`,children:e.max_model_len}),(0,A.jsx)(`td`,{children:e.pinned?(0,A.jsx)(`span`,{className:`text-accent`,children:`yes`}):(0,A.jsx)(`span`,{className:`text-mute`,children:`no`})}),(0,A.jsxs)(`td`,{className:`text-right space-x-5 whitespace-nowrap`,children:[(0,A.jsx)(`button`,{className:`text-accent hover:opacity-70 transition-opacity disabled:opacity-40`,disabled:t,onClick:()=>l.mutate(e.name),children:t?`deploying…`:`deploy`}),(0,A.jsx)(`button`,{className:`btn-link-danger disabled:opacity-40`,disabled:n,onClick:()=>{confirm(`delete profile ${e.name}?`)&&u.mutate(e.name)},children:n?`deleting…`:`delete`})]})]},e.id)})]})]})]})}function on(e){return e===null?(0,A.jsx)(`span`,{className:`text-mute`,children:`—`}):e?(0,A.jsxs)(`span`,{children:[(0,A.jsx)(`span`,{className:`dot dot-ready`}),(0,A.jsx)(`span`,{className:`text-ok`,children:`ready`})]}):(0,A.jsxs)(`span`,{children:[(0,A.jsx)(`span`,{className:`dot dot-failed`}),(0,A.jsx)(`span`,{className:`text-err`,children:`not ready`})]})}function sn({result:e}){if(!e.matched)return(0,A.jsxs)(`div`,{className:`text-[12px] space-y-2`,children:[(0,A.jsxs)(`div`,{className:`text-err`,children:[`no enabled route matches `,(0,A.jsx)(`span`,{className:`font-mono`,children:e.requested})]}),e.candidates.length>0&&(0,A.jsxs)(`div`,{className:`text-mute text-[11px] tracking-wider`,children:[e.candidates.length,` disabled candidate`,e.candidates.length===1?``:`s`,` share this match_model:`,` `,e.candidates.map(e=>e.name).join(`, `)]}),(0,A.jsxs)(`div`,{className:`text-mute text-[11px] tracking-wider`,children:[`the proxy will fall back to treating `,(0,A.jsx)(`span`,{className:`font-mono`,children:e.requested}),` as a direct model name.`]})]});let t=e.matched;return(0,A.jsxs)(`div`,{className:`text-[12px] grid grid-cols-1 md:grid-cols-2 gap-x-8 gap-y-2`,children:[(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`span`,{className:`text-mute`,children:`matched route `}),(0,A.jsx)(`span`,{className:`text-ink`,children:t.name}),(0,A.jsxs)(`span`,{className:`text-mute`,children:[` (priority `,t.priority,`)`]})]}),(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`span`,{className:`text-mute`,children:`primary profile `}),(0,A.jsx)(`span`,{className:`text-dim`,children:t.profile_name}),(0,A.jsx)(`span`,{className:`text-mute`,children:` → `}),(0,A.jsx)(`span`,{className:`font-mono`,children:t.target_model_name}),(0,A.jsx)(`span`,{className:`ml-3`,children:on(e.primary_ready)})]}),(0,A.jsxs)(`div`,{className:`md:col-start-2`,children:[(0,A.jsx)(`span`,{className:`text-mute`,children:`fallback `}),t.fallback_profile_name?(0,A.jsxs)(A.Fragment,{children:[(0,A.jsx)(`span`,{className:`text-dim`,children:t.fallback_profile_name}),(0,A.jsx)(`span`,{className:`text-mute`,children:` → `}),(0,A.jsx)(`span`,{className:`font-mono`,children:t.fallback_model_name}),(0,A.jsx)(`span`,{className:`ml-3`,children:on(e.fallback_ready)})]}):(0,A.jsx)(`span`,{className:`text-mute`,children:`—`})]}),e.candidates.length>1&&(0,A.jsxs)(`div`,{className:`md:col-span-2 text-mute text-[11px] tracking-wider pt-1`,children:[e.candidates.length-1,` other route`,e.candidates.length-1==1?``:`s`,` share this match_model (lower priority or disabled):`,` `,e.candidates.filter(e=>e.id!==t.id).map(e=>e.name).join(`, `)]}),e.primary_ready===!1&&e.fallback_ready!==!0&&(0,A.jsx)(`div`,{className:`md:col-span-2 text-err text-[11px] tracking-wider pt-1`,children:`neither primary nor fallback has a ready deployment — a request would 503.`})]})}function cn({profiles:e,routes:t,hasProfiles:n,form:r,setForm:i,routeError:a,createRoute:o,deleteRoute:s,dryRunModel:c,setDryRunModel:l,dryRunResult:u,setDryRunResult:d,dryRun:f}){return(0,A.jsxs)(`section`,{className:`space-y-4`,children:[(0,A.jsxs)(`div`,{className:`flex items-baseline justify-between`,children:[(0,A.jsx)(`div`,{className:`label`,children:`routes`}),(0,A.jsx)(`div`,{className:`text-mute text-[11px] tracking-wider`,children:`public model name → profile · lower priority wins`})]}),n?(0,A.jsxs)(`div`,{className:`bg-elev/40 border border-rule p-5 space-y-4`,children:[(0,A.jsxs)(`div`,{className:`grid grid-cols-12 gap-3`,children:[(0,A.jsxs)(`div`,{className:`space-y-1 col-span-6 md:col-span-2`,children:[(0,A.jsx)(`div`,{className:`label`,children:`name`}),(0,A.jsx)(`input`,{className:`field font-mono w-full text-[12px]`,placeholder:`chat-default`,value:r.name,onChange:e=>i(t=>({...t,name:e.target.value}))})]}),(0,A.jsxs)(`div`,{className:`space-y-1 col-span-6 md:col-span-3`,children:[(0,A.jsx)(`div`,{className:`label`,children:`profile`}),(0,A.jsxs)(`select`,{className:`field font-mono w-full text-[12px]`,value:r.profile_name,onChange:e=>i(t=>({...t,profile_name:e.target.value})),children:[(0,A.jsx)(`option`,{value:``,children:`choose…`}),e.map(e=>(0,A.jsx)(`option`,{value:e.name,children:e.name},e.id))]})]}),(0,A.jsxs)(`div`,{className:`space-y-1 col-span-6 md:col-span-3`,children:[(0,A.jsx)(`div`,{className:`label`,children:`fallback (optional)`}),(0,A.jsxs)(`select`,{className:`field font-mono w-full text-[12px]`,value:r.fallback_profile_name,onChange:e=>i(t=>({...t,fallback_profile_name:e.target.value})),children:[(0,A.jsx)(`option`,{value:``,children:`none`}),e.filter(e=>e.name!==r.profile_name).map(e=>(0,A.jsx)(`option`,{value:e.name,children:e.name},e.id))]})]}),(0,A.jsxs)(`div`,{className:`space-y-1 col-span-6 md:col-span-3`,children:[(0,A.jsx)(`div`,{className:`label`,children:`match model (exact)`}),(0,A.jsx)(`input`,{className:`field font-mono w-full text-[12px]`,placeholder:`chat`,value:r.match_model,onChange:e=>i(t=>({...t,match_model:e.target.value}))})]}),(0,A.jsxs)(`div`,{className:`space-y-1 col-span-12 md:col-span-1`,children:[(0,A.jsx)(`div`,{className:`label`,children:`pri`}),(0,A.jsx)(`input`,{className:`field font-mono w-full text-[12px] tnum text-right`,value:r.priority,onChange:e=>i(t=>({...t,priority:e.target.value}))})]})]}),a&&(0,A.jsx)(`div`,{className:`text-err text-[11px] tracking-wider`,children:a}),(0,A.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,A.jsx)(`button`,{className:`btn-primary`,disabled:!r.name.trim()||!r.match_model.trim()||!r.profile_name||o.isPending,onClick:()=>o.mutate(),children:o.isPending?`creating…`:`create route`}),(0,A.jsxs)(`span`,{className:`label`,children:[`callable as `,(0,A.jsxs)(`span`,{className:`text-dim`,children:[`model: `,r.match_model||``]})]})]})]}):(0,A.jsx)(`div`,{className:`border border-rule bg-elev/40 px-5 py-12 text-center text-mute text-[12px]`,children:`create a profile above first — routes point at profiles.`}),n&&t.length>0&&(0,A.jsxs)(`div`,{className:`bg-elev/40 border border-rule px-5 py-4 space-y-3`,children:[(0,A.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,A.jsx)(`div`,{className:`label whitespace-nowrap`,children:`dry-run`}),(0,A.jsx)(`input`,{className:`field font-mono w-full text-[12px]`,placeholder:`model name to test (e.g. chat)`,value:c,onChange:e=>l(e.target.value),onKeyDown:e=>{e.key===`Enter`&&c.trim()&&f.mutate(c.trim())}}),(0,A.jsx)(`button`,{className:`btn`,disabled:!c.trim()||f.isPending,onClick:()=>f.mutate(c.trim()),children:f.isPending?`testing…`:`test`}),u&&(0,A.jsx)(`button`,{className:`text-mute text-[11px] tracking-wider hover:text-dim transition-colors whitespace-nowrap`,onClick:()=>{d(null),l(``)},children:`clear`})]}),u&&(0,A.jsx)(sn,{result:u})]}),(0,A.jsxs)(`table`,{className:`ditable`,children:[(0,A.jsx)(`thead`,{children:(0,A.jsxs)(`tr`,{children:[(0,A.jsx)(`th`,{className:`w-12`,children:`pri`}),(0,A.jsx)(`th`,{children:`name`}),(0,A.jsx)(`th`,{children:`match model`}),(0,A.jsx)(`th`,{children:`profile`}),(0,A.jsx)(`th`,{children:`fallback`}),(0,A.jsx)(`th`,{children:`enabled`}),(0,A.jsx)(`th`,{className:`text-right`,children:`actions`})]})}),(0,A.jsxs)(`tbody`,{children:[t.length===0&&(0,A.jsx)(`tr`,{children:(0,A.jsx)(`td`,{colSpan:7,className:`!py-12 text-center text-mute`,children:n?`no routes. create one above to expose a public model name.`:`no routes — and no profiles to route at yet.`})}),t.slice().sort((e,t)=>e.priority-t.priority).map(e=>(0,A.jsxs)(`tr`,{children:[(0,A.jsx)(`td`,{className:`text-mute tnum`,children:e.priority}),(0,A.jsx)(`td`,{children:e.name}),(0,A.jsx)(`td`,{className:`font-mono text-[12px]`,children:e.match_model}),(0,A.jsx)(`td`,{className:`text-dim`,children:e.profile_name}),(0,A.jsx)(`td`,{className:`text-mute`,children:e.fallback_profile_name??`—`}),(0,A.jsxs)(`td`,{children:[(0,A.jsx)(`span`,{className:`dot ${e.enabled?`dot-ready`:`dot-stopped`}`}),(0,A.jsx)(`span`,{className:`text-dim`,children:e.enabled?`on`:`off`})]}),(0,A.jsx)(`td`,{className:`text-right`,children:(0,A.jsx)(`button`,{className:`btn-link-danger disabled:opacity-40`,disabled:s.isPending,onClick:()=>{confirm(`delete route ${e.name}?`)&&s.mutate(e.name)},children:`delete`})})]},e.id))]})]})]})}var ln={name:``,model_name:``,hf_repo:``,backend:``,gpu_ids:`0`,max_model_len:`8192`,pinned:!1,node_label:``},un={name:``,match_model:``,profile_name:``,fallback_profile_name:``,priority:`100`};function dn({mode:e=`both`}){let t=rt(),n=j({queryKey:M.profiles,queryFn:P.listProfiles}),r=j({queryKey:M.routes,queryFn:P.listRoutes}),i=j({queryKey:M.models,queryFn:P.listModels}),a=j({queryKey:M.backends,queryFn:P.listBackends}),o=j({queryKey:M.nodes,queryFn:P.listNodes}),s=n.data??[],c=r.data??[],l=s.length>0,[u,d]=(0,k.useState)(ln),[f,p]=(0,k.useState)(``),[m,h]=(0,k.useState)(``),g=yt({mutationFn:()=>{let e=Yt(u.gpu_ids),t=Xt(u.max_model_len);return P.createProfile({name:u.name.trim(),model_name:u.model_name.trim(),hf_repo:u.hf_repo.trim(),backend:u.backend||void 0,gpu_ids:e,max_model_len:t,pinned:u.pinned,node_label:Zt(u.node_label)})},onMutate:()=>p(``),onError:e=>p(e.message),onSuccess:()=>{d(ln),t.invalidateQueries({queryKey:M.profiles})}}),_=yt({mutationFn:e=>P.deployProfile(e),onMutate:()=>h(``),onError:e=>h(e.message),onSuccess:()=>t.invalidateQueries({queryKey:M.deployments})}),v=yt({mutationFn:e=>P.deleteProfile(e),onMutate:()=>h(``),onError:e=>h(e.message),onSuccess:()=>{t.invalidateQueries({queryKey:M.profiles}),t.invalidateQueries({queryKey:M.routes})}}),[y,b]=(0,k.useState)(un),[x,ee]=(0,k.useState)(``),S=yt({mutationFn:()=>{let e=Number(y.priority);if(!Number.isInteger(e))throw Error(`priority must be an integer`);return P.createRoute({name:y.name.trim(),match_model:y.match_model.trim(),profile_name:y.profile_name,fallback_profile_name:y.fallback_profile_name||null,priority:e})},onMutate:()=>ee(``),onError:e=>ee(e.message),onSuccess:()=>{b(un),t.invalidateQueries({queryKey:M.routes})}}),C=yt({mutationFn:e=>P.deleteRoute(e),onSuccess:()=>t.invalidateQueries({queryKey:M.routes})}),[te,ne]=(0,k.useState)(``),[re,w]=(0,k.useState)(null),ie=yt({mutationFn:e=>P.dryRunRoute(e),onSuccess:e=>w(e),onError:()=>w(null)}),ae=e===`both`||e===`profiles`,oe=e===`both`||e===`routes`,se=e===`routes`?`routes`:e===`profiles`?`profiles`:`services`,ce=e===`routes`?`${c.length} routes`:e===`profiles`?`${s.length} profiles`:`${s.length} profiles / ${c.length} routes`;return(0,A.jsxs)(`div`,{className:`space-y-14`,children:[(0,A.jsxs)(`header`,{className:`flex items-baseline justify-between`,children:[(0,A.jsx)(`h2`,{className:`text-2xl font-light tracking-tightish caret`,children:se}),(0,A.jsx)(`div`,{className:`label`,children:ce})]}),ae&&(0,A.jsx)(an,{profiles:s,models:i.data??[],backends:a.data??[],nodes:o.data?.nodes??[],form:u,setForm:d,formError:f,actionError:m,createProfile:g,deployProfile:_,deleteProfile:v}),oe&&(0,A.jsx)(cn,{profiles:s,routes:c,hasProfiles:l,form:y,setForm:b,routeError:x,createRoute:S,deleteRoute:C,dryRunModel:te,setDryRunModel:ne,dryRunResult:re,setDryRunResult:w,dryRun:ie})]})}function fn(){return(0,A.jsx)(dn,{mode:`routes`})}function pn(){return(0,A.jsx)(dn,{mode:`profiles`})}var mn={enabled:!1,preloads_attempted:0,preloads_succeeded:0,preloads_skipped_already_warm:0,preloads_skipped_no_deployment:0,base_prewarms_attempted:0,base_prewarms_succeeded:0,base_prewarms_skipped_no_plan:0};function hn({label:e,value:t,dim:n=!1}){return(0,A.jsxs)(`div`,{className:`space-y-1`,children:[(0,A.jsx)(`div`,{className:`text-mute text-[11px]`,children:e}),(0,A.jsx)(`div`,{className:`tnum text-lg font-light ${n?`text-dim`:``}`,children:t??0})]})}function gn(){let e=j({queryKey:M.predictorCandidates,queryFn:P.predictorCandidates,refetchInterval:5e3}),t=j({queryKey:M.predictorStats,queryFn:P.predictorStats,refetchInterval:5e3}).data??mn,n=e.data??[],r=t.enabled!==!1,i=t.preloads_attempted>0?Math.round(100*(t.preloads_succeeded/t.preloads_attempted)):null,a=t.base_prewarms_attempted>0?Math.round(100*(t.base_prewarms_succeeded/t.base_prewarms_attempted)):null;return(0,A.jsxs)(`div`,{className:`space-y-14`,children:[(0,A.jsxs)(`header`,{className:`flex items-baseline justify-between`,children:[(0,A.jsx)(`h2`,{className:`text-2xl font-light tracking-tightish caret`,children:`predictor`}),(0,A.jsx)(`div`,{className:`label`,children:r?(0,A.jsxs)(A.Fragment,{children:[`tick `,t.tick_interval_s,`s / adapter `,t.max_prewarm_per_tick,`/tick / base `,t.max_base_prewarm_per_tick??0,`/tick`]}):`disabled`})]}),(0,A.jsxs)(`section`,{className:`space-y-5`,children:[(0,A.jsx)(`div`,{className:`label`,children:`adapter pre-warming`}),(0,A.jsxs)(`div`,{className:`grid grid-cols-5 gap-8 max-w-4xl`,children:[(0,A.jsx)(hn,{label:`attempted`,value:t.preloads_attempted}),(0,A.jsx)(hn,{label:`succeeded`,value:t.preloads_succeeded}),(0,A.jsx)(hn,{label:`success rate`,value:i==null?`-`:`${i}%`,dim:!0}),(0,A.jsx)(hn,{label:`skipped (warm)`,value:t.preloads_skipped_already_warm,dim:!0}),(0,A.jsx)(hn,{label:`skipped (no dep)`,value:t.preloads_skipped_no_deployment,dim:!0})]})]}),(0,A.jsxs)(`section`,{className:`space-y-5`,children:[(0,A.jsx)(`div`,{className:`label`,children:`base pre-warming`}),(0,A.jsxs)(`div`,{className:`grid grid-cols-5 gap-8 max-w-4xl`,children:[(0,A.jsx)(hn,{label:`attempted`,value:t.base_prewarms_attempted}),(0,A.jsx)(hn,{label:`succeeded`,value:t.base_prewarms_succeeded}),(0,A.jsx)(hn,{label:`success rate`,value:a==null?`-`:`${a}%`,dim:!0}),(0,A.jsx)(hn,{label:`skipped (no plan)`,value:t.base_prewarms_skipped_no_plan,dim:!0}),(0,A.jsx)(hn,{label:`-`,value:`-`,dim:!0})]})]}),(0,A.jsxs)(`section`,{className:`space-y-4`,children:[(0,A.jsx)(`div`,{className:`label`,children:`current candidates`}),(0,A.jsxs)(`table`,{className:`ditable`,children:[(0,A.jsx)(`thead`,{children:(0,A.jsxs)(`tr`,{children:[(0,A.jsx)(`th`,{children:`model`}),(0,A.jsx)(`th`,{className:`text-right`,children:`score`}),(0,A.jsx)(`th`,{children:`reason`})]})}),(0,A.jsxs)(`tbody`,{children:[n.length===0&&(0,A.jsx)(`tr`,{children:(0,A.jsx)(`td`,{colSpan:3,className:`!py-12 text-center text-mute`,children:`no candidates. rules have nothing to suggest right now`})}),n.map((e,t)=>(0,A.jsxs)(`tr`,{children:[(0,A.jsx)(`td`,{className:`font-mono`,children:e.adapter_name?`${e.base_name}:${e.adapter_name}`:e.base_name}),(0,A.jsx)(`td`,{className:`text-right tnum`,children:e.score.toFixed(3)}),(0,A.jsx)(`td`,{className:`text-mute text-[11px]`,children:e.reason})]},`${e.base_name}:${e.adapter_name}:${t}`))]})]})]})]})}var _n={reasoning:``,answer:``,error:``,stats:{ttftMs:null,totalMs:null,tokens:0,tps:null},pending:!1};async function vn(e,t,n,r,i){let a=performance.now(),o=null,s=0;try{let c={"Content-Type":`application/json`},l=St();l&&(c.Authorization=`Bearer ${l}`);let u=await fetch(`/v1/chat/completions`,{method:`POST`,headers:c,signal:r,body:JSON.stringify({model:e,messages:[{role:`user`,content:t}],stream:!0,max_tokens:n})});if(!u.ok){let e=await u.text();i(t=>({...t,error:`${u.status}: ${e.slice(0,500)}`}));return}if(!u.body)return;let d=u.body.getReader(),f=new TextDecoder,p=``;for(;;){let{done:e,value:t}=await d.read();if(e)break;p+=f.decode(t,{stream:!0});let n=p.split(` +`).replace(Ad,``)}function Md(e,t){return t=jd(t),jd(e)===t}function $(e,t,n,r,a,o){switch(n){case`children`:typeof r==`string`?t===`body`||t===`textarea`&&r===``||Yt(e,r):(typeof r==`number`||typeof r==`bigint`)&&t!==`body`&&Yt(e,``+r);break;case`className`:Nt(e,`class`,r);break;case`tabIndex`:Nt(e,`tabindex`,r);break;case`dir`:case`role`:case`viewBox`:case`width`:case`height`:Nt(e,n,r);break;case`style`:Qt(e,r,o);break;case`data`:if(t!==`object`){Nt(e,`data`,r);break}case`src`:case`href`:if(r===``&&(t!==`a`||n!==`href`)){e.removeAttribute(n);break}if(r==null||typeof r==`function`||typeof r==`symbol`||typeof r==`boolean`){e.removeAttribute(n);break}r=nn(``+r),e.setAttribute(n,r);break;case`action`:case`formAction`:if(typeof r==`function`){e.setAttribute(n,`javascript:throw new Error('A React form was unexpectedly submitted. If you called form.submit() manually, consider using form.requestSubmit() instead. If you\\'re trying to use event.stopPropagation() in a submit event handler, consider also calling event.preventDefault().')`);break}else typeof o==`function`&&(n===`formAction`?(t!==`input`&&$(e,t,`name`,a.name,a,null),$(e,t,`formEncType`,a.formEncType,a,null),$(e,t,`formMethod`,a.formMethod,a,null),$(e,t,`formTarget`,a.formTarget,a,null)):($(e,t,`encType`,a.encType,a,null),$(e,t,`method`,a.method,a,null),$(e,t,`target`,a.target,a,null)));if(r==null||typeof r==`symbol`||typeof r==`boolean`){e.removeAttribute(n);break}r=nn(``+r),e.setAttribute(n,r);break;case`onClick`:r!=null&&(e.onclick=rn);break;case`onScroll`:r!=null&&Q(`scroll`,e);break;case`onScrollEnd`:r!=null&&Q(`scrollend`,e);break;case`dangerouslySetInnerHTML`:if(r!=null){if(typeof r!=`object`||!(`__html`in r))throw Error(i(61));if(n=r.__html,n!=null){if(a.children!=null)throw Error(i(60));e.innerHTML=n}}break;case`multiple`:e.multiple=r&&typeof r!=`function`&&typeof r!=`symbol`;break;case`muted`:e.muted=r&&typeof r!=`function`&&typeof r!=`symbol`;break;case`suppressContentEditableWarning`:case`suppressHydrationWarning`:case`defaultValue`:case`defaultChecked`:case`innerHTML`:case`ref`:break;case`autoFocus`:break;case`xlinkHref`:if(r==null||typeof r==`function`||typeof r==`boolean`||typeof r==`symbol`){e.removeAttribute(`xlink:href`);break}n=nn(``+r),e.setAttributeNS(`http://www.w3.org/1999/xlink`,`xlink:href`,n);break;case`contentEditable`:case`spellCheck`:case`draggable`:case`value`:case`autoReverse`:case`externalResourcesRequired`:case`focusable`:case`preserveAlpha`:r!=null&&typeof r!=`function`&&typeof r!=`symbol`?e.setAttribute(n,``+r):e.removeAttribute(n);break;case`inert`:case`allowFullScreen`:case`async`:case`autoPlay`:case`controls`:case`default`:case`defer`:case`disabled`:case`disablePictureInPicture`:case`disableRemotePlayback`:case`formNoValidate`:case`hidden`:case`loop`:case`noModule`:case`noValidate`:case`open`:case`playsInline`:case`readOnly`:case`required`:case`reversed`:case`scoped`:case`seamless`:case`itemScope`:r&&typeof r!=`function`&&typeof r!=`symbol`?e.setAttribute(n,``):e.removeAttribute(n);break;case`capture`:case`download`:!0===r?e.setAttribute(n,``):!1!==r&&r!=null&&typeof r!=`function`&&typeof r!=`symbol`?e.setAttribute(n,r):e.removeAttribute(n);break;case`cols`:case`rows`:case`size`:case`span`:r!=null&&typeof r!=`function`&&typeof r!=`symbol`&&!isNaN(r)&&1<=r?e.setAttribute(n,r):e.removeAttribute(n);break;case`rowSpan`:case`start`:r==null||typeof r==`function`||typeof r==`symbol`||isNaN(r)?e.removeAttribute(n):e.setAttribute(n,r);break;case`popover`:Q(`beforetoggle`,e),Q(`toggle`,e),Mt(e,`popover`,r);break;case`xlinkActuate`:Pt(e,`http://www.w3.org/1999/xlink`,`xlink:actuate`,r);break;case`xlinkArcrole`:Pt(e,`http://www.w3.org/1999/xlink`,`xlink:arcrole`,r);break;case`xlinkRole`:Pt(e,`http://www.w3.org/1999/xlink`,`xlink:role`,r);break;case`xlinkShow`:Pt(e,`http://www.w3.org/1999/xlink`,`xlink:show`,r);break;case`xlinkTitle`:Pt(e,`http://www.w3.org/1999/xlink`,`xlink:title`,r);break;case`xlinkType`:Pt(e,`http://www.w3.org/1999/xlink`,`xlink:type`,r);break;case`xmlBase`:Pt(e,`http://www.w3.org/XML/1998/namespace`,`xml:base`,r);break;case`xmlLang`:Pt(e,`http://www.w3.org/XML/1998/namespace`,`xml:lang`,r);break;case`xmlSpace`:Pt(e,`http://www.w3.org/XML/1998/namespace`,`xml:space`,r);break;case`is`:Mt(e,`is`,r);break;case`innerText`:case`textContent`:break;default:(!(2s)break;var u=c.transferSize,d=c.initiatorType;u&&Id(d)&&(c=c.responseEnd,o+=u*(c`u`?null:document;function xf(e,t,n){var r=bf;if(r&&typeof t==`string`&&t){var i=Ht(t);i=`link[rel="`+e+`"][href="`+i+`"]`,typeof n==`string`&&(i+=`[crossorigin="`+n+`"]`),hf.has(i)||(hf.add(i),e={rel:e,crossOrigin:n,href:t},r.querySelector(i)===null&&(t=r.createElement(`link`),Pd(t,`link`,e),Tt(t),r.head.appendChild(t)))}}function Sf(e){_f.D(e),xf(`dns-prefetch`,e,null)}function Cf(e,t){_f.C(e,t),xf(`preconnect`,e,t)}function wf(e,t,n){_f.L(e,t,n);var r=bf;if(r&&e&&t){var i=`link[rel="preload"][as="`+Ht(t)+`"]`;t===`image`&&n&&n.imageSrcSet?(i+=`[imagesrcset="`+Ht(n.imageSrcSet)+`"]`,typeof n.imageSizes==`string`&&(i+=`[imagesizes="`+Ht(n.imageSizes)+`"]`)):i+=`[href="`+Ht(e)+`"]`;var a=i;switch(t){case`style`:a=Af(e);break;case`script`:a=Pf(e)}mf.has(a)||(e=h({rel:`preload`,href:t===`image`&&n&&n.imageSrcSet?void 0:e,as:t},n),mf.set(a,e),r.querySelector(i)!==null||t===`style`&&r.querySelector(jf(a))||t===`script`&&r.querySelector(Ff(a))||(t=r.createElement(`link`),Pd(t,`link`,e),Tt(t),r.head.appendChild(t)))}}function Tf(e,t){_f.m(e,t);var n=bf;if(n&&e){var r=t&&typeof t.as==`string`?t.as:`script`,i=`link[rel="modulepreload"][as="`+Ht(r)+`"][href="`+Ht(e)+`"]`,a=i;switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:a=Pf(e)}if(!mf.has(a)&&(e=h({rel:`modulepreload`,href:e},t),mf.set(a,e),n.querySelector(i)===null)){switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:if(n.querySelector(Ff(a)))return}r=n.createElement(`link`),Pd(r,`link`,e),Tt(r),n.head.appendChild(r)}}}function Ef(e,t,n){_f.S(e,t,n);var r=bf;if(r&&e){var i=M(r).hoistableStyles,a=Af(e);t||=`default`;var o=i.get(a);if(!o){var s={loading:0,preload:null};if(o=r.querySelector(jf(a)))s.loading=5;else{e=h({rel:`stylesheet`,href:e,"data-precedence":t},n),(n=mf.get(a))&&Rf(e,n);var c=o=r.createElement(`link`);Tt(c),Pd(c,`link`,e),c._p=new Promise(function(e,t){c.onload=e,c.onerror=t}),c.addEventListener(`load`,function(){s.loading|=1}),c.addEventListener(`error`,function(){s.loading|=2}),s.loading|=4,Lf(o,t,r)}o={type:`stylesheet`,instance:o,count:1,state:s},i.set(a,o)}}}function Df(e,t){_f.X(e,t);var n=bf;if(n&&e){var r=M(n).hoistableScripts,i=Pf(e),a=r.get(i);a||(a=n.querySelector(Ff(i)),a||(e=h({src:e,async:!0},t),(t=mf.get(i))&&zf(e,t),a=n.createElement(`script`),Tt(a),Pd(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function Of(e,t){_f.M(e,t);var n=bf;if(n&&e){var r=M(n).hoistableScripts,i=Pf(e),a=r.get(i);a||(a=n.querySelector(Ff(i)),a||(e=h({src:e,async:!0,type:`module`},t),(t=mf.get(i))&&zf(e,t),a=n.createElement(`script`),Tt(a),Pd(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function kf(e,t,n,r){var a=(a=ve.current)?gf(a):null;if(!a)throw Error(i(446));switch(e){case`meta`:case`title`:return null;case`style`:return typeof n.precedence==`string`&&typeof n.href==`string`?(t=Af(n.href),n=M(a).hoistableStyles,r=n.get(t),r||(r={type:`style`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};case`link`:if(n.rel===`stylesheet`&&typeof n.href==`string`&&typeof n.precedence==`string`){e=Af(n.href);var o=M(a).hoistableStyles,s=o.get(e);if(s||(a=a.ownerDocument||a,s={type:`stylesheet`,instance:null,count:0,state:{loading:0,preload:null}},o.set(e,s),(o=a.querySelector(jf(e)))&&!o._p&&(s.instance=o,s.state.loading=5),mf.has(e)||(n={rel:`preload`,as:`style`,href:n.href,crossOrigin:n.crossOrigin,integrity:n.integrity,media:n.media,hrefLang:n.hrefLang,referrerPolicy:n.referrerPolicy},mf.set(e,n),o||Nf(a,e,n,s.state))),t&&r===null)throw Error(i(528,``));return s}if(t&&r!==null)throw Error(i(529,``));return null;case`script`:return t=n.async,n=n.src,typeof n==`string`&&t&&typeof t!=`function`&&typeof t!=`symbol`?(t=Pf(n),n=M(a).hoistableScripts,r=n.get(t),r||(r={type:`script`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};default:throw Error(i(444,e))}}function Af(e){return`href="`+Ht(e)+`"`}function jf(e){return`link[rel="stylesheet"][`+e+`]`}function Mf(e){return h({},e,{"data-precedence":e.precedence,precedence:null})}function Nf(e,t,n,r){e.querySelector(`link[rel="preload"][as="style"][`+t+`]`)?r.loading=1:(t=e.createElement(`link`),r.preload=t,t.addEventListener(`load`,function(){return r.loading|=1}),t.addEventListener(`error`,function(){return r.loading|=2}),Pd(t,`link`,n),Tt(t),e.head.appendChild(t))}function Pf(e){return`[src="`+Ht(e)+`"]`}function Ff(e){return`script[async]`+e}function If(e,t,n){if(t.count++,t.instance===null)switch(t.type){case`style`:var r=e.querySelector(`style[data-href~="`+Ht(n.href)+`"]`);if(r)return t.instance=r,Tt(r),r;var a=h({},n,{"data-href":n.href,"data-precedence":n.precedence,href:null,precedence:null});return r=(e.ownerDocument||e).createElement(`style`),Tt(r),Pd(r,`style`,a),Lf(r,n.precedence,e),t.instance=r;case`stylesheet`:a=Af(n.href);var o=e.querySelector(jf(a));if(o)return t.state.loading|=4,t.instance=o,Tt(o),o;r=Mf(n),(a=mf.get(a))&&Rf(r,a),o=(e.ownerDocument||e).createElement(`link`),Tt(o);var s=o;return s._p=new Promise(function(e,t){s.onload=e,s.onerror=t}),Pd(o,`link`,r),t.state.loading|=4,Lf(o,n.precedence,e),t.instance=o;case`script`:return o=Pf(n.src),(a=e.querySelector(Ff(o)))?(t.instance=a,Tt(a),a):(r=n,(a=mf.get(o))&&(r=h({},n),zf(r,a)),e=e.ownerDocument||e,a=e.createElement(`script`),Tt(a),Pd(a,`link`,r),e.head.appendChild(a),t.instance=a);case`void`:return null;default:throw Error(i(443,t.type))}else t.type===`stylesheet`&&!(t.state.loading&4)&&(r=t.instance,t.state.loading|=4,Lf(r,n.precedence,e));return t.instance}function Lf(e,t,n){for(var r=n.querySelectorAll(`link[rel="stylesheet"][data-precedence],style[data-precedence]`),i=r.length?r[r.length-1]:null,a=i,o=0;o title`):null)}function Uf(e,t,n){if(n===1||t.itemProp!=null)return!1;switch(e){case`meta`:case`title`:return!0;case`style`:if(typeof t.precedence!=`string`||typeof t.href!=`string`||t.href===``)break;return!0;case`link`:if(typeof t.rel!=`string`||typeof t.href!=`string`||t.href===``||t.onLoad||t.onError)break;switch(t.rel){case`stylesheet`:return e=t.disabled,typeof t.precedence==`string`&&e==null;default:return!0}case`script`:if(t.async&&typeof t.async!=`function`&&typeof t.async!=`symbol`&&!t.onLoad&&!t.onError&&t.src&&typeof t.src==`string`)return!0}return!1}function Wf(e){return!(e.type===`stylesheet`&&!(e.state.loading&3))}function Gf(e,t,n,r){if(n.type===`stylesheet`&&(typeof r.media!=`string`||!1!==matchMedia(r.media).matches)&&!(n.state.loading&4)){if(n.instance===null){var i=Af(r.href),a=t.querySelector(jf(i));if(a){t=a._p,typeof t==`object`&&t&&typeof t.then==`function`&&(e.count++,e=Jf.bind(e),t.then(e,e)),n.state.loading|=4,n.instance=a,Tt(a);return}a=t.ownerDocument||t,r=Mf(r),(i=mf.get(i))&&Rf(r,i),a=a.createElement(`link`),Tt(a);var o=a;o._p=new Promise(function(e,t){o.onload=e,o.onerror=t}),Pd(a,`link`,r),n.instance=a}e.stylesheets===null&&(e.stylesheets=new Map),e.stylesheets.set(n,t),(t=n.state.preload)&&!(n.state.loading&3)&&(e.count++,n=Jf.bind(e),t.addEventListener(`load`,n),t.addEventListener(`error`,n))}}var Kf=0;function qf(e,t){return e.stylesheets&&e.count===0&&Xf(e,e.stylesheets),0Kf?50:800)+t);return e.unsuspend=n,function(){e.unsuspend=null,clearTimeout(r),clearTimeout(i)}}:null}function Jf(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)Xf(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var Yf=null;function Xf(e,t){e.stylesheets=null,e.unsuspend!==null&&(e.count++,Yf=new Map,t.forEach(Zf,e),Yf=null,Jf.call(e))}function Zf(e,t){if(!(t.state.loading&4)){var n=Yf.get(e);if(n)var r=n.get(null);else{n=new Map,Yf.set(e,n);for(var i=e.querySelectorAll(`link[data-precedence],style[data-precedence]`),a=0;a{function n(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>`u`||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=`function`))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}n(),t.exports=h()})),_=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(){}},v=new class extends _{#e;#t;#n;constructor(){super(),this.#n=e=>{if(typeof window<`u`&&window.addEventListener){let t=()=>e();return window.addEventListener(`visibilitychange`,t,!1),()=>{window.removeEventListener(`visibilitychange`,t)}}}}onSubscribe(){this.#t||this.setEventListener(this.#n)}onUnsubscribe(){this.hasListeners()||(this.#t?.(),this.#t=void 0)}setEventListener(e){this.#n=e,this.#t?.(),this.#t=e(e=>{typeof e==`boolean`?this.setFocused(e):this.onFocus()})}setFocused(e){this.#e!==e&&(this.#e=e,this.onFocus())}onFocus(){let e=this.isFocused();this.listeners.forEach(t=>{t(e)})}isFocused(){return typeof this.#e==`boolean`?this.#e:globalThis.document?.visibilityState!==`hidden`}},y={setTimeout:(e,t)=>setTimeout(e,t),clearTimeout:e=>clearTimeout(e),setInterval:(e,t)=>setInterval(e,t),clearInterval:e=>clearInterval(e)},b=new class{#e=y;setTimeoutProvider(e){this.#e=e}setTimeout(e,t){return this.#e.setTimeout(e,t)}clearTimeout(e){this.#e.clearTimeout(e)}setInterval(e,t){return this.#e.setInterval(e,t)}clearInterval(e){this.#e.clearInterval(e)}};function x(e){setTimeout(e,0)}var ee=typeof window>`u`||`Deno`in globalThis;function S(){}function C(e,t){return typeof e==`function`?e(t):e}function te(e){return typeof e==`number`&&e>=0&&e!==1/0}function ne(e,t){return Math.max(e+(t||0)-Date.now(),0)}function re(e,t){return typeof e==`function`?e(t):e}function w(e,t){return typeof e==`function`?e(t):e}function ie(e,t){let{type:n=`all`,exact:r,fetchStatus:i,predicate:a,queryKey:o,stale:s}=e;if(o){if(r){if(t.queryHash!==oe(o,t.options))return!1}else if(!ce(t.queryKey,o))return!1}if(n!==`all`){let e=t.isActive();if(n===`active`&&!e||n===`inactive`&&e)return!1}return!(typeof s==`boolean`&&t.isStale()!==s||i&&i!==t.state.fetchStatus||a&&!a(t))}function ae(e,t){let{exact:n,status:r,predicate:i,mutationKey:a}=e;if(a){if(!t.options.mutationKey)return!1;if(n){if(se(t.options.mutationKey)!==se(a))return!1}else if(!ce(t.options.mutationKey,a))return!1}return!(r&&t.state.status!==r||i&&!i(t))}function oe(e,t){return(t?.queryKeyHashFn||se)(e)}function se(e){return JSON.stringify(e,(e,t)=>de(t)?Object.keys(t).sort().reduce((e,n)=>(e[n]=t[n],e),{}):t)}function ce(e,t){return e===t?!0:typeof e==typeof t&&e&&t&&typeof e==`object`&&typeof t==`object`?Object.keys(t).every(n=>ce(e[n],t[n])):!1}var le=Object.prototype.hasOwnProperty;function ue(e,t,n=0){if(e===t)return e;if(n>500)return t;let r=E(e)&&E(t);if(!r&&!(de(e)&&de(t)))return t;let i=(r?e:Object.keys(e)).length,a=r?t:Object.keys(t),o=a.length,s=r?Array(o):{},c=0;for(let l=0;l{b.setTimeout(t,e)})}function me(e,t,n){return typeof n.structuralSharing==`function`?n.structuralSharing(e,t):n.structuralSharing===!1?t:ue(e,t)}function he(e,t,n=0){let r=[...e,t];return n&&r.length>n?r.slice(1):r}function D(e,t,n=0){let r=[t,...e];return n&&r.length>n?r.slice(0,-1):r}var ge=Symbol();function _e(e,t){return!e.queryFn&&t?.initialPromise?()=>t.initialPromise:!e.queryFn||e.queryFn===ge?()=>Promise.reject(Error(`Missing queryFn: '${e.queryHash}'`)):e.queryFn}function ve(e,t){return typeof e==`function`?e(...t):!!e}function ye(e,t,n){let r=!1,i;return Object.defineProperty(e,"signal",{enumerable:!0,get:()=>(i??=t(),r?i:(r=!0,i.aborted?n():i.addEventListener(`abort`,n,{once:!0}),i))}),e}var be=(()=>{let e=()=>ee;return{isServer(){return e()},setIsServer(t){e=t}}})();function xe(){let e,t,n=new Promise((n,r)=>{e=n,t=r});n.status=`pending`,n.catch(()=>{});function r(e){Object.assign(n,e),delete n.resolve,delete n.reject}return n.resolve=t=>{r({status:`fulfilled`,value:t}),e(t)},n.reject=e=>{r({status:`rejected`,reason:e}),t(e)},n}var Se=x;function Ce(){let e=[],t=0,n=e=>{e()},r=e=>{e()},i=Se,a=r=>{t?e.push(r):i(()=>{n(r)})},o=()=>{let t=e;e=[],t.length&&i(()=>{r(()=>{t.forEach(e=>{n(e)})})})};return{batch:e=>{let n;t++;try{n=e()}finally{t--,t||o()}return n},batchCalls:e=>(...t)=>{a(()=>{e(...t)})},schedule:a,setNotifyFunction:e=>{n=e},setBatchNotifyFunction:e=>{r=e},setScheduler:e=>{i=e}}}var O=Ce(),we=new class extends _{#e=!0;#t;#n;constructor(){super(),this.#n=e=>{if(typeof window<`u`&&window.addEventListener){let t=()=>e(!0),n=()=>e(!1);return window.addEventListener(`online`,t,!1),window.addEventListener(`offline`,n,!1),()=>{window.removeEventListener(`online`,t),window.removeEventListener(`offline`,n)}}}}onSubscribe(){this.#t||this.setEventListener(this.#n)}onUnsubscribe(){this.hasListeners()||(this.#t?.(),this.#t=void 0)}setEventListener(e){this.#n=e,this.#t?.(),this.#t=e(this.setOnline.bind(this))}setOnline(e){this.#e!==e&&(this.#e=e,this.listeners.forEach(t=>{t(e)}))}isOnline(){return this.#e}};function Te(e){return Math.min(1e3*2**e,3e4)}function Ee(e){return(e??`online`)===`online`?we.isOnline():!0}var De=class extends Error{constructor(e){super(`CancelledError`),this.revert=e?.revert,this.silent=e?.silent}};function Oe(e){let t=!1,n=0,r,i=xe(),a=()=>i.status!==`pending`,o=t=>{if(!a()){let n=new De(t);f(n),e.onCancel?.(n)}},s=()=>{t=!0},c=()=>{t=!1},l=()=>v.isFocused()&&(e.networkMode===`always`||we.isOnline())&&e.canRun(),u=()=>Ee(e.networkMode)&&e.canRun(),d=e=>{a()||(r?.(),i.resolve(e))},f=e=>{a()||(r?.(),i.reject(e))},p=()=>new Promise(t=>{r=e=>{(a()||l())&&t(e)},e.onPause?.()}).then(()=>{r=void 0,a()||e.onContinue?.()}),m=()=>{if(a())return;let r,i=n===0?e.initialPromise:void 0;try{r=i??e.fn()}catch(e){r=Promise.reject(e)}Promise.resolve(r).then(d).catch(r=>{if(a())return;let i=e.retry??(be.isServer()?0:3),o=e.retryDelay??Te,s=typeof o==`function`?o(n,r):o,c=i===!0||typeof i==`number`&&nl()?void 0:p()).then(()=>{t?f(r):m()})})};return{promise:i,status:()=>i.status,cancel:o,continue:()=>(r?.(),i),cancelRetry:s,continueRetry:c,canStart:u,start:()=>(u()?m():p().then(m),i)}}var ke=class{#e;destroy(){this.clearGcTimeout()}scheduleGc(){this.clearGcTimeout(),te(this.gcTime)&&(this.#e=b.setTimeout(()=>{this.optionalRemove()},this.gcTime))}updateGcTime(e){this.gcTime=Math.max(this.gcTime||0,e??(be.isServer()?1/0:300*1e3))}clearGcTimeout(){this.#e!==void 0&&(b.clearTimeout(this.#e),this.#e=void 0)}};function Ae(e){return{onFetch:(t,n)=>{let r=t.options,i=t.fetchOptions?.meta?.fetchMore?.direction,a=t.state.data?.pages||[],o=t.state.data?.pageParams||[],s={pages:[],pageParams:[]},c=0,l=async()=>{let n=!1,l=e=>{ye(e,()=>t.signal,()=>n=!0)},u=_e(t.options,t.fetchOptions),d=async(e,r,i)=>{if(n)return Promise.reject(t.signal.reason);if(r==null&&e.pages.length)return Promise.resolve(e);let a=await u((()=>{let e={client:t.client,queryKey:t.queryKey,pageParam:r,direction:i?`backward`:`forward`,meta:t.options.meta};return l(e),e})()),{maxPages:o}=t.options,s=i?D:he;return{pages:s(e.pages,a,o),pageParams:s(e.pageParams,r,o)}};if(i&&a.length){let e=i===`backward`,t=e?Me:je,n={pages:a,pageParams:o};s=await d(n,t(r,n),e)}else{let t=e??a.length;do{let e=c===0?o[0]??r.initialPageParam:je(r,s);if(c>0&&e==null)break;s=await d(s,e),c++}while(ct.options.persister?.(l,{client:t.client,queryKey:t.queryKey,meta:t.options.meta,signal:t.signal},n):t.fetchFn=l}}}function je(e,{pages:t,pageParams:n}){let r=t.length-1;return t.length>0?e.getNextPageParam(t[r],t,n[r],n):void 0}function Me(e,{pages:t,pageParams:n}){return t.length>0?e.getPreviousPageParam?.(t[0],t,n[0],n):void 0}var Ne=class extends ke{#e;#t;#n;#r;#i;#a;#o;#s;constructor(e){super(),this.#s=!1,this.#o=e.defaultOptions,this.setOptions(e.options),this.observers=[],this.#i=e.client,this.#r=this.#i.getQueryCache(),this.queryKey=e.queryKey,this.queryHash=e.queryHash,this.#t=Ie(this.options),this.state=e.state??this.#t,this.scheduleGc()}get meta(){return this.options.meta}get queryType(){return this.#e}get promise(){return this.#a?.promise}setOptions(e){if(this.options={...this.#o,...e},e?._type&&(this.#e=e._type),this.updateGcTime(this.options.gcTime),this.state&&this.state.data===void 0){let e=Ie(this.options);e.data!==void 0&&(this.setState(Fe(e.data,e.dataUpdatedAt)),this.#t=e)}}optionalRemove(){!this.observers.length&&this.state.fetchStatus===`idle`&&this.#r.remove(this)}setData(e,t){let n=me(this.state.data,e,this.options);return this.#l({data:n,type:`success`,dataUpdatedAt:t?.updatedAt,manual:t?.manual}),n}setState(e){this.#l({type:`setState`,state:e})}cancel(e){let t=this.#a?.promise;return this.#a?.cancel(e),t?t.then(S).catch(S):Promise.resolve()}destroy(){super.destroy(),this.cancel({silent:!0})}get resetState(){return this.#t}reset(){this.destroy(),this.setState(this.resetState)}isActive(){return this.observers.some(e=>w(e.options.enabled,this)!==!1)}isDisabled(){return this.getObserversCount()>0?!this.isActive():this.options.queryFn===ge||!this.isFetched()}isFetched(){return this.state.dataUpdateCount+this.state.errorUpdateCount>0}isStatic(){return this.getObserversCount()>0?this.observers.some(e=>re(e.options.staleTime,this)===`static`):!1}isStale(){return this.getObserversCount()>0?this.observers.some(e=>e.getCurrentResult().isStale):this.state.data===void 0||this.state.isInvalidated}isStaleByTime(e=0){return this.state.data===void 0?!0:e===`static`?!1:this.state.isInvalidated?!0:!ne(this.state.dataUpdatedAt,e)}onFocus(){this.observers.find(e=>e.shouldFetchOnWindowFocus())?.refetch({cancelRefetch:!1}),this.#a?.continue()}onOnline(){this.observers.find(e=>e.shouldFetchOnReconnect())?.refetch({cancelRefetch:!1}),this.#a?.continue()}addObserver(e){this.observers.includes(e)||(this.observers.push(e),this.clearGcTimeout(),this.#r.notify({type:`observerAdded`,query:this,observer:e}))}removeObserver(e){this.observers.includes(e)&&(this.observers=this.observers.filter(t=>t!==e),this.observers.length||(this.#a&&(this.#s||this.#c()?this.#a.cancel({revert:!0}):this.#a.cancelRetry()),this.scheduleGc()),this.#r.notify({type:`observerRemoved`,query:this,observer:e}))}getObserversCount(){return this.observers.length}#c(){return this.state.fetchStatus===`paused`&&this.state.status===`pending`}invalidate(){this.state.isInvalidated||this.#l({type:`invalidate`})}async fetch(e,t){if(this.state.fetchStatus!==`idle`&&this.#a?.status()!==`rejected`){if(this.state.data!==void 0&&t?.cancelRefetch)this.cancel({silent:!0});else if(this.#a)return this.#a.continueRetry(),this.#a.promise}if(e&&this.setOptions(e),!this.options.queryFn){let e=this.observers.find(e=>e.options.queryFn);e&&this.setOptions(e.options)}let n=new AbortController,r=e=>{Object.defineProperty(e,"signal",{enumerable:!0,get:()=>(this.#s=!0,n.signal)})},i=()=>{let e=_e(this.options,t),n=(()=>{let e={client:this.#i,queryKey:this.queryKey,meta:this.meta};return r(e),e})();return this.#s=!1,this.options.persister?this.options.persister(e,n,this):e(n)},a=(()=>{let e={fetchOptions:t,options:this.options,queryKey:this.queryKey,client:this.#i,state:this.state,fetchFn:i};return r(e),e})();(this.#e===`infinite`?Ae(this.options.pages):this.options.behavior)?.onFetch(a,this),this.#n=this.state,(this.state.fetchStatus===`idle`||this.state.fetchMeta!==a.fetchOptions?.meta)&&this.#l({type:`fetch`,meta:a.fetchOptions?.meta}),this.#a=Oe({initialPromise:t?.initialPromise,fn:a.fetchFn,onCancel:e=>{e instanceof De&&e.revert&&this.setState({...this.#n,fetchStatus:`idle`}),n.abort()},onFail:(e,t)=>{this.#l({type:`failed`,failureCount:e,error:t})},onPause:()=>{this.#l({type:`pause`})},onContinue:()=>{this.#l({type:`continue`})},retry:a.options.retry,retryDelay:a.options.retryDelay,networkMode:a.options.networkMode,canRun:()=>!0});try{let e=await this.#a.start();if(e===void 0)throw Error(`${this.queryHash} data is undefined`);return this.setData(e),this.#r.config.onSuccess?.(e,this),this.#r.config.onSettled?.(e,this.state.error,this),e}catch(e){if(e instanceof De){if(e.silent)return this.#a.promise;if(e.revert){if(this.state.data===void 0)throw e;return this.state.data}}throw this.#l({type:`error`,error:e}),this.#r.config.onError?.(e,this),this.#r.config.onSettled?.(this.state.data,e,this),e}finally{this.scheduleGc()}}#l(e){let t=t=>{switch(e.type){case`failed`:return{...t,fetchFailureCount:e.failureCount,fetchFailureReason:e.error};case`pause`:return{...t,fetchStatus:`paused`};case`continue`:return{...t,fetchStatus:`fetching`};case`fetch`:return{...t,...Pe(t.data,this.options),fetchMeta:e.meta??null};case`success`:let n={...t,...Fe(e.data,e.dataUpdatedAt),dataUpdateCount:t.dataUpdateCount+1,...!e.manual&&{fetchStatus:`idle`,fetchFailureCount:0,fetchFailureReason:null}};return this.#n=e.manual?n:void 0,n;case`error`:let r=e.error;return{...t,error:r,errorUpdateCount:t.errorUpdateCount+1,errorUpdatedAt:Date.now(),fetchFailureCount:t.fetchFailureCount+1,fetchFailureReason:r,fetchStatus:`idle`,status:`error`,isInvalidated:!0};case`invalidate`:return{...t,isInvalidated:!0};case`setState`:return{...t,...e.state}}};this.state=t(this.state),O.batch(()=>{this.observers.forEach(e=>{e.onQueryUpdate()}),this.#r.notify({query:this,type:`updated`,action:e})})}};function Pe(e,t){return{fetchFailureCount:0,fetchFailureReason:null,fetchStatus:Ee(t.networkMode)?`fetching`:`paused`,...e===void 0&&{error:null,status:`pending`}}}function Fe(e,t){return{data:e,dataUpdatedAt:t??Date.now(),error:null,isInvalidated:!1,status:`success`}}function Ie(e){let t=typeof e.initialData==`function`?e.initialData():e.initialData,n=t!==void 0,r=n?typeof e.initialDataUpdatedAt==`function`?e.initialDataUpdatedAt():e.initialDataUpdatedAt:0;return{data:t,dataUpdateCount:0,dataUpdatedAt:n?r??Date.now():0,error:null,errorUpdateCount:0,errorUpdatedAt:0,fetchFailureCount:0,fetchFailureReason:null,fetchMeta:null,isInvalidated:!1,status:n?`success`:`pending`,fetchStatus:`idle`}}var Le=class extends _{constructor(e,t){super(),this.options=t,this.#e=e,this.#s=null,this.#o=xe(),this.bindMethods(),this.setOptions(t)}#e;#t=void 0;#n=void 0;#r=void 0;#i;#a;#o;#s;#c;#l;#u;#d;#f;#p;#m=new Set;bindMethods(){this.refetch=this.refetch.bind(this)}onSubscribe(){this.listeners.size===1&&(this.#t.addObserver(this),ze(this.#t,this.options)?this.#h():this.updateResult(),this.#y())}onUnsubscribe(){this.hasListeners()||this.destroy()}shouldFetchOnReconnect(){return Be(this.#t,this.options,this.options.refetchOnReconnect)}shouldFetchOnWindowFocus(){return Be(this.#t,this.options,this.options.refetchOnWindowFocus)}destroy(){this.listeners=new Set,this.#b(),this.#x(),this.#t.removeObserver(this)}setOptions(e){let t=this.options,n=this.#t;if(this.options=this.#e.defaultQueryOptions(e),this.options.enabled!==void 0&&typeof this.options.enabled!=`boolean`&&typeof this.options.enabled!=`function`&&typeof w(this.options.enabled,this.#t)!=`boolean`)throw Error(`Expected enabled to be a boolean or a callback that returns a boolean`);this.#S(),this.#t.setOptions(this.options),t._defaulted&&!T(this.options,t)&&this.#e.getQueryCache().notify({type:`observerOptionsUpdated`,query:this.#t,observer:this});let r=this.hasListeners();r&&Ve(this.#t,n,this.options,t)&&this.#h(),this.updateResult(),r&&(this.#t!==n||w(this.options.enabled,this.#t)!==w(t.enabled,this.#t)||re(this.options.staleTime,this.#t)!==re(t.staleTime,this.#t))&&this.#g();let i=this.#_();r&&(this.#t!==n||w(this.options.enabled,this.#t)!==w(t.enabled,this.#t)||i!==this.#p)&&this.#v(i)}getOptimisticResult(e){let t=this.#e.getQueryCache().build(this.#e,e),n=this.createResult(t,e);return Ue(this,n)&&(this.#r=n,this.#a=this.options,this.#i=this.#t.state),n}getCurrentResult(){return this.#r}trackResult(e,t){return new Proxy(e,{get:(e,n)=>(this.trackProp(n),t?.(n),n===`promise`&&(this.trackProp(`data`),!this.options.experimental_prefetchInRender&&this.#o.status===`pending`&&this.#o.reject(Error(`experimental_prefetchInRender feature flag is not enabled`))),Reflect.get(e,n))})}trackProp(e){this.#m.add(e)}getCurrentQuery(){return this.#t}refetch({...e}={}){return this.fetch({...e})}fetchOptimistic(e){let t=this.#e.defaultQueryOptions(e),n=this.#e.getQueryCache().build(this.#e,t);return n.fetch().then(()=>this.createResult(n,t))}fetch(e){return this.#h({...e,cancelRefetch:e.cancelRefetch??!0}).then(()=>(this.updateResult(),this.#r))}#h(e){this.#S();let t=this.#t.fetch(this.options,e);return e?.throwOnError||(t=t.catch(S)),t}#g(){this.#b();let e=re(this.options.staleTime,this.#t);if(be.isServer()||this.#r.isStale||!te(e))return;let t=ne(this.#r.dataUpdatedAt,e)+1;this.#d=b.setTimeout(()=>{this.#r.isStale||this.updateResult()},t)}#_(){return(typeof this.options.refetchInterval==`function`?this.options.refetchInterval(this.#t):this.options.refetchInterval)??!1}#v(e){this.#x(),this.#p=e,!(be.isServer()||w(this.options.enabled,this.#t)===!1||!te(this.#p)||this.#p===0)&&(this.#f=b.setInterval(()=>{(this.options.refetchIntervalInBackground||v.isFocused())&&this.#h()},this.#p))}#y(){this.#g(),this.#v(this.#_())}#b(){this.#d!==void 0&&(b.clearTimeout(this.#d),this.#d=void 0)}#x(){this.#f!==void 0&&(b.clearInterval(this.#f),this.#f=void 0)}createResult(e,t){let n=this.#t,r=this.options,i=this.#r,a=this.#i,o=this.#a,s=e===n?this.#n:e.state,{state:c}=e,l={...c},u=!1,d;if(t._optimisticResults){let i=this.hasListeners(),a=!i&&ze(e,t),o=i&&Ve(e,n,t,r);(a||o)&&(l={...l,...Pe(c.data,e.options)}),t._optimisticResults===`isRestoring`&&(l.fetchStatus=`idle`)}let{error:f,errorUpdatedAt:p,status:m}=l;d=l.data;let h=!1;if(t.placeholderData!==void 0&&d===void 0&&m===`pending`){let e;i?.isPlaceholderData&&t.placeholderData===o?.placeholderData?(e=i.data,h=!0):e=typeof t.placeholderData==`function`?t.placeholderData(this.#u?.state.data,this.#u):t.placeholderData,e!==void 0&&(m=`success`,d=me(i?.data,e,t),u=!0)}if(t.select&&d!==void 0&&!h)if(i&&d===a?.data&&t.select===this.#c)d=this.#l;else try{this.#c=t.select,d=t.select(d),d=me(i?.data,d,t),this.#l=d,this.#s=null}catch(e){this.#s=e}this.#s&&(f=this.#s,d=this.#l,p=Date.now(),m=`error`);let g=l.fetchStatus===`fetching`,_=m===`pending`,v=m===`error`,y=_&&g,b=d!==void 0,x={status:m,fetchStatus:l.fetchStatus,isPending:_,isSuccess:m===`success`,isError:v,isInitialLoading:y,isLoading:y,data:d,dataUpdatedAt:l.dataUpdatedAt,error:f,errorUpdatedAt:p,failureCount:l.fetchFailureCount,failureReason:l.fetchFailureReason,errorUpdateCount:l.errorUpdateCount,isFetched:e.isFetched(),isFetchedAfterMount:l.dataUpdateCount>s.dataUpdateCount||l.errorUpdateCount>s.errorUpdateCount,isFetching:g,isRefetching:g&&!_,isLoadingError:v&&!b,isPaused:l.fetchStatus===`paused`,isPlaceholderData:u,isRefetchError:v&&b,isStale:He(e,t),refetch:this.refetch,promise:this.#o,isEnabled:w(t.enabled,e)!==!1};if(this.options.experimental_prefetchInRender){let t=x.data!==void 0,r=x.status===`error`&&!t,i=e=>{r?e.reject(x.error):t&&e.resolve(x.data)},a=()=>{i(this.#o=x.promise=xe())},o=this.#o;switch(o.status){case`pending`:e.queryHash===n.queryHash&&i(o);break;case`fulfilled`:(r||x.data!==o.value)&&a();break;case`rejected`:(!r||x.error!==o.reason)&&a();break}}return x}updateResult(){let e=this.#r,t=this.createResult(this.#t,this.options);this.#i=this.#t.state,this.#a=this.options,this.#i.data!==void 0&&(this.#u=this.#t),!T(t,e)&&(this.#r=t,this.#C({listeners:(()=>{if(!e)return!0;let{notifyOnChangeProps:t}=this.options,n=typeof t==`function`?t():t;if(n===`all`||!n&&!this.#m.size)return!0;let r=new Set(n??this.#m);return this.options.throwOnError&&r.add(`error`),Object.keys(this.#r).some(t=>{let n=t;return this.#r[n]!==e[n]&&r.has(n)})})()}))}#S(){let e=this.#e.getQueryCache().build(this.#e,this.options);if(e===this.#t)return;let t=this.#t;this.#t=e,this.#n=e.state,this.hasListeners()&&(t?.removeObserver(this),e.addObserver(this))}onQueryUpdate(){this.updateResult(),this.hasListeners()&&this.#y()}#C(e){O.batch(()=>{e.listeners&&this.listeners.forEach(e=>{e(this.#r)}),this.#e.getQueryCache().notify({query:this.#t,type:`observerResultsUpdated`})})}};function Re(e,t){return w(t.enabled,e)!==!1&&e.state.data===void 0&&!(e.state.status===`error`&&w(t.retryOnMount,e)===!1)}function ze(e,t){return Re(e,t)||e.state.data!==void 0&&Be(e,t,t.refetchOnMount)}function Be(e,t,n){if(w(t.enabled,e)!==!1&&re(t.staleTime,e)!==`static`){let r=typeof n==`function`?n(e):n;return r===`always`||r!==!1&&He(e,t)}return!1}function Ve(e,t,n,r){return(e!==t||w(r.enabled,e)===!1)&&(!n.suspense||e.state.status!==`error`)&&He(e,n)}function He(e,t){return w(t.enabled,e)!==!1&&e.isStaleByTime(re(t.staleTime,e))}function Ue(e,t){return!T(e.getCurrentResult(),t)}var We=class extends ke{#e;#t;#n;#r;constructor(e){super(),this.#e=e.client,this.mutationId=e.mutationId,this.#n=e.mutationCache,this.#t=[],this.state=e.state||Ge(),this.setOptions(e.options),this.scheduleGc()}setOptions(e){this.options=e,this.updateGcTime(this.options.gcTime)}get meta(){return this.options.meta}addObserver(e){this.#t.includes(e)||(this.#t.push(e),this.clearGcTimeout(),this.#n.notify({type:`observerAdded`,mutation:this,observer:e}))}removeObserver(e){this.#t=this.#t.filter(t=>t!==e),this.scheduleGc(),this.#n.notify({type:`observerRemoved`,mutation:this,observer:e})}optionalRemove(){this.#t.length||(this.state.status===`pending`?this.scheduleGc():this.#n.remove(this))}continue(){return this.#r?.continue()??this.execute(this.state.variables)}async execute(e){let t=()=>{this.#i({type:`continue`})},n={client:this.#e,meta:this.options.meta,mutationKey:this.options.mutationKey};this.#r=Oe({fn:()=>this.options.mutationFn?this.options.mutationFn(e,n):Promise.reject(Error(`No mutationFn found`)),onFail:(e,t)=>{this.#i({type:`failed`,failureCount:e,error:t})},onPause:()=>{this.#i({type:`pause`})},onContinue:t,retry:this.options.retry??0,retryDelay:this.options.retryDelay,networkMode:this.options.networkMode,canRun:()=>this.#n.canRun(this)});let r=this.state.status===`pending`,i=!this.#r.canStart();try{if(r)t();else{this.#i({type:`pending`,variables:e,isPaused:i}),this.#n.config.onMutate&&await this.#n.config.onMutate(e,this,n);let t=await this.options.onMutate?.(e,n);t!==this.state.context&&this.#i({type:`pending`,context:t,variables:e,isPaused:i})}let a=await this.#r.start();return await this.#n.config.onSuccess?.(a,e,this.state.context,this,n),await this.options.onSuccess?.(a,e,this.state.context,n),await this.#n.config.onSettled?.(a,null,this.state.variables,this.state.context,this,n),await this.options.onSettled?.(a,null,e,this.state.context,n),this.#i({type:`success`,data:a}),a}catch(t){try{await this.#n.config.onError?.(t,e,this.state.context,this,n)}catch(e){Promise.reject(e)}try{await this.options.onError?.(t,e,this.state.context,n)}catch(e){Promise.reject(e)}try{await this.#n.config.onSettled?.(void 0,t,this.state.variables,this.state.context,this,n)}catch(e){Promise.reject(e)}try{await this.options.onSettled?.(void 0,t,e,this.state.context,n)}catch(e){Promise.reject(e)}throw this.#i({type:`error`,error:t}),t}finally{this.#n.runNext(this)}}#i(e){let t=t=>{switch(e.type){case`failed`:return{...t,failureCount:e.failureCount,failureReason:e.error};case`pause`:return{...t,isPaused:!0};case`continue`:return{...t,isPaused:!1};case`pending`:return{...t,context:e.context,data:void 0,failureCount:0,failureReason:null,error:null,isPaused:e.isPaused,status:`pending`,variables:e.variables,submittedAt:Date.now()};case`success`:return{...t,data:e.data,failureCount:0,failureReason:null,error:null,status:`success`,isPaused:!1};case`error`:return{...t,data:void 0,error:e.error,failureCount:t.failureCount+1,failureReason:e.error,isPaused:!1,status:`error`}}};this.state=t(this.state),O.batch(()=>{this.#t.forEach(t=>{t.onMutationUpdate(e)}),this.#n.notify({mutation:this,type:`updated`,action:e})})}};function Ge(){return{context:void 0,data:void 0,error:null,failureCount:0,failureReason:null,isPaused:!1,status:`idle`,variables:void 0,submittedAt:0}}var Ke=class extends _{constructor(e={}){super(),this.config=e,this.#e=new Set,this.#t=new Map,this.#n=0}#e;#t;#n;build(e,t,n){let r=new We({client:e,mutationCache:this,mutationId:++this.#n,options:e.defaultMutationOptions(t),state:n});return this.add(r),r}add(e){this.#e.add(e);let t=qe(e);if(typeof t==`string`){let n=this.#t.get(t);n?n.push(e):this.#t.set(t,[e])}this.notify({type:`added`,mutation:e})}remove(e){if(this.#e.delete(e)){let t=qe(e);if(typeof t==`string`){let n=this.#t.get(t);if(n)if(n.length>1){let t=n.indexOf(e);t!==-1&&n.splice(t,1)}else n[0]===e&&this.#t.delete(t)}}this.notify({type:`removed`,mutation:e})}canRun(e){let t=qe(e);if(typeof t==`string`){let n=this.#t.get(t)?.find(e=>e.state.status===`pending`);return!n||n===e}else return!0}runNext(e){let t=qe(e);return typeof t==`string`?(this.#t.get(t)?.find(t=>t!==e&&t.state.isPaused))?.continue()??Promise.resolve():Promise.resolve()}clear(){O.batch(()=>{this.#e.forEach(e=>{this.notify({type:`removed`,mutation:e})}),this.#e.clear(),this.#t.clear()})}getAll(){return Array.from(this.#e)}find(e){let t={exact:!0,...e};return this.getAll().find(e=>ae(t,e))}findAll(e={}){return this.getAll().filter(t=>ae(e,t))}notify(e){O.batch(()=>{this.listeners.forEach(t=>{t(e)})})}resumePausedMutations(){let e=this.getAll().filter(e=>e.state.isPaused);return O.batch(()=>Promise.all(e.map(e=>e.continue().catch(S))))}};function qe(e){return e.options.scope?.id}var Je=class extends _{#e;#t=void 0;#n;#r;constructor(e,t){super(),this.#e=e,this.setOptions(t),this.bindMethods(),this.#i()}bindMethods(){this.mutate=this.mutate.bind(this),this.reset=this.reset.bind(this)}setOptions(e){let t=this.options;this.options=this.#e.defaultMutationOptions(e),T(this.options,t)||this.#e.getMutationCache().notify({type:`observerOptionsUpdated`,mutation:this.#n,observer:this}),t?.mutationKey&&this.options.mutationKey&&se(t.mutationKey)!==se(this.options.mutationKey)?this.reset():this.#n?.state.status===`pending`&&this.#n.setOptions(this.options)}onUnsubscribe(){this.hasListeners()||this.#n?.removeObserver(this)}onMutationUpdate(e){this.#i(),this.#a(e)}getCurrentResult(){return this.#t}reset(){this.#n?.removeObserver(this),this.#n=void 0,this.#i(),this.#a()}mutate(e,t){return this.#r=t,this.#n?.removeObserver(this),this.#n=this.#e.getMutationCache().build(this.#e,this.options),this.#n.addObserver(this),this.#n.execute(e)}#i(){let e=this.#n?.state??Ge();this.#t={...e,isPending:e.status===`pending`,isSuccess:e.status===`success`,isError:e.status===`error`,isIdle:e.status===`idle`,mutate:this.mutate,reset:this.reset}}#a(e){O.batch(()=>{if(this.#r&&this.hasListeners()){let t=this.#t.variables,n=this.#t.context,r={client:this.#e,meta:this.options.meta,mutationKey:this.options.mutationKey};if(e?.type===`success`){try{this.#r.onSuccess?.(e.data,t,n,r)}catch(e){Promise.reject(e)}try{this.#r.onSettled?.(e.data,null,t,n,r)}catch(e){Promise.reject(e)}}else if(e?.type===`error`){try{this.#r.onError?.(e.error,t,n,r)}catch(e){Promise.reject(e)}try{this.#r.onSettled?.(void 0,e.error,t,n,r)}catch(e){Promise.reject(e)}}}this.listeners.forEach(e=>{e(this.#t)})})}};function Ye(e,t){let n=new Set(t);return e.filter(e=>!n.has(e))}function Xe(e,t,n){let r=e.slice(0);return r[t]=n,r}var Ze=class extends _{#e;#t;#n;#r;#i;#a;#o;#s;#c;#l=[];constructor(e,t,n){super(),this.#e=e,this.#r=n,this.#n=[],this.#i=[],this.#t=[],this.setQueries(t)}onSubscribe(){this.listeners.size===1&&this.#i.forEach(e=>{e.subscribe(t=>{this.#m(e,t)})})}onUnsubscribe(){this.listeners.size||this.destroy()}destroy(){this.listeners=new Set,this.#i.forEach(e=>{e.destroy()})}setQueries(e,t){this.#n=e,this.#r=t,O.batch(()=>{let e=this.#i,t=this.#p(this.#n);t.forEach(e=>e.observer.setOptions(e.defaultedQueryOptions));let n=t.map(e=>e.observer),r=n.map(e=>e.getCurrentResult()),i=e.length!==n.length,a=n.some((t,n)=>t!==e[n]),o=i||a,s=o?!0:r.some((e,t)=>{let n=this.#t[t];return!n||!T(e,n)});!o&&!s||(o&&(this.#l=t,this.#i=n),this.#t=r,this.hasListeners()&&(o&&(Ye(e,n).forEach(e=>{e.destroy()}),Ye(n,e).forEach(e=>{e.subscribe(t=>{this.#m(e,t)})})),this.#h()))})}getCurrentResult(){return this.#t}getQueries(){return this.#i.map(e=>e.getCurrentQuery())}getObservers(){return this.#i}getOptimisticResult(e,t){let n=this.#p(e),r=n.map(e=>e.observer.getOptimisticResult(e.defaultedQueryOptions)),i=n.map(e=>e.defaultedQueryOptions.queryHash);return[r,e=>this.#d(e??r,t,i),()=>this.#u(r,n)]}#u(e,t){return t.map((n,r)=>{let i=e[r];return n.defaultedQueryOptions.notifyOnChangeProps?i:n.observer.trackResult(i,e=>{t.forEach(t=>{t.observer.trackProp(e)})})})}#d(e,t,n){if(t){let r=this.#c,i=n!==void 0&&r!==void 0&&(r.length!==n.length||n.some((e,t)=>e!==r[t]));return(!this.#a||this.#t!==this.#s||i||t!==this.#o)&&(this.#o=t,this.#s=this.#t,n!==void 0&&(this.#c=n),this.#a=ue(this.#a,t(e))),this.#a}return e}#f(){return this.#r?.combine!==void 0&&this.#i.some((e,t)=>e.options.suspense&&this.#t[t]?.data===void 0)}#p(e){let t=new Map;this.#i.forEach(e=>{let n=e.options.queryHash;if(!n)return;let r=t.get(n);r?r.push(e):t.set(n,[e])});let n=[];return e.forEach(e=>{let r=this.#e.defaultQueryOptions(e),i=t.get(r.queryHash)?.shift()??new Le(this.#e,r);n.push({defaultedQueryOptions:r,observer:i})}),n}#m(e,t){let n=this.#i.indexOf(e);n!==-1&&(this.#t=Xe(this.#t,n,t),this.#h())}#h(){if(this.hasListeners()){let e=this.#u(this.#t,this.#l),t=this.#f(),n=this.#a,r=t?n:this.#d(e,this.#r?.combine);(t||n!==r)&&O.batch(()=>{this.listeners.forEach(e=>{e(this.#t)})})}}},Qe=class extends _{constructor(e={}){super(),this.config=e,this.#e=new Map}#e;build(e,t,n){let r=t.queryKey,i=t.queryHash??oe(r,t),a=this.get(i);return a||(a=new Ne({client:e,queryKey:r,queryHash:i,options:e.defaultQueryOptions(t),state:n,defaultOptions:e.getQueryDefaults(r)}),this.add(a)),a}add(e){this.#e.has(e.queryHash)||(this.#e.set(e.queryHash,e),this.notify({type:`added`,query:e}))}remove(e){let t=this.#e.get(e.queryHash);t&&(e.destroy(),t===e&&this.#e.delete(e.queryHash),this.notify({type:`removed`,query:e}))}clear(){O.batch(()=>{this.getAll().forEach(e=>{this.remove(e)})})}get(e){return this.#e.get(e)}getAll(){return[...this.#e.values()]}find(e){let t={exact:!0,...e};return this.getAll().find(e=>ie(t,e))}findAll(e={}){let t=this.getAll();return Object.keys(e).length>0?t.filter(t=>ie(e,t)):t}notify(e){O.batch(()=>{this.listeners.forEach(t=>{t(e)})})}onFocus(){O.batch(()=>{this.getAll().forEach(e=>{e.onFocus()})})}onOnline(){O.batch(()=>{this.getAll().forEach(e=>{e.onOnline()})})}},$e=class{#e;#t;#n;#r;#i;#a;#o;#s;constructor(e={}){this.#e=e.queryCache||new Qe,this.#t=e.mutationCache||new Ke,this.#n=e.defaultOptions||{},this.#r=new Map,this.#i=new Map,this.#a=0}mount(){this.#a++,this.#a===1&&(this.#o=v.subscribe(async e=>{e&&(await this.resumePausedMutations(),this.#e.onFocus())}),this.#s=we.subscribe(async e=>{e&&(await this.resumePausedMutations(),this.#e.onOnline())}))}unmount(){this.#a--,this.#a===0&&(this.#o?.(),this.#o=void 0,this.#s?.(),this.#s=void 0)}isFetching(e){return this.#e.findAll({...e,fetchStatus:`fetching`}).length}isMutating(e){return this.#t.findAll({...e,status:`pending`}).length}getQueryData(e){let t=this.defaultQueryOptions({queryKey:e});return this.#e.get(t.queryHash)?.state.data}ensureQueryData(e){let t=this.defaultQueryOptions(e),n=this.#e.build(this,t),r=n.state.data;return r===void 0?this.fetchQuery(e):(e.revalidateIfStale&&n.isStaleByTime(re(t.staleTime,n))&&this.prefetchQuery(t),Promise.resolve(r))}getQueriesData(e){return this.#e.findAll(e).map(({queryKey:e,state:t})=>[e,t.data])}setQueryData(e,t,n){let r=this.defaultQueryOptions({queryKey:e}),i=this.#e.get(r.queryHash)?.state.data,a=C(t,i);if(a!==void 0)return this.#e.build(this,r).setData(a,{...n,manual:!0})}setQueriesData(e,t,n){return O.batch(()=>this.#e.findAll(e).map(({queryKey:e})=>[e,this.setQueryData(e,t,n)]))}getQueryState(e){let t=this.defaultQueryOptions({queryKey:e});return this.#e.get(t.queryHash)?.state}removeQueries(e){let t=this.#e;O.batch(()=>{t.findAll(e).forEach(e=>{t.remove(e)})})}resetQueries(e,t){let n=this.#e;return O.batch(()=>(n.findAll(e).forEach(e=>{e.reset()}),this.refetchQueries({type:`active`,...e},t)))}cancelQueries(e,t={}){let n={revert:!0,...t},r=O.batch(()=>this.#e.findAll(e).map(e=>e.cancel(n)));return Promise.all(r).then(S).catch(S)}invalidateQueries(e,t={}){return O.batch(()=>(this.#e.findAll(e).forEach(e=>{e.invalidate()}),e?.refetchType===`none`?Promise.resolve():this.refetchQueries({...e,type:e?.refetchType??e?.type??`active`},t)))}refetchQueries(e,t={}){let n={...t,cancelRefetch:t.cancelRefetch??!0},r=O.batch(()=>this.#e.findAll(e).filter(e=>!e.isDisabled()&&!e.isStatic()).map(e=>{let t=e.fetch(void 0,n);return n.throwOnError||(t=t.catch(S)),e.state.fetchStatus===`paused`?Promise.resolve():t}));return Promise.all(r).then(S)}fetchQuery(e){let t=this.defaultQueryOptions(e);t.retry===void 0&&(t.retry=!1);let n=this.#e.build(this,t);return n.isStaleByTime(re(t.staleTime,n))?n.fetch(t):Promise.resolve(n.state.data)}prefetchQuery(e){return this.fetchQuery(e).then(S).catch(S)}fetchInfiniteQuery(e){return e._type=`infinite`,this.fetchQuery(e)}prefetchInfiniteQuery(e){return this.fetchInfiniteQuery(e).then(S).catch(S)}ensureInfiniteQueryData(e){return e._type=`infinite`,this.ensureQueryData(e)}resumePausedMutations(){return we.isOnline()?this.#t.resumePausedMutations():Promise.resolve()}getQueryCache(){return this.#e}getMutationCache(){return this.#t}getDefaultOptions(){return this.#n}setDefaultOptions(e){this.#n=e}setQueryDefaults(e,t){this.#r.set(se(e),{queryKey:e,defaultOptions:t})}getQueryDefaults(e){let t=[...this.#r.values()],n={};return t.forEach(t=>{ce(e,t.queryKey)&&Object.assign(n,t.defaultOptions)}),n}setMutationDefaults(e,t){this.#i.set(se(e),{mutationKey:e,defaultOptions:t})}getMutationDefaults(e){let t=[...this.#i.values()],n={};return t.forEach(t=>{ce(e,t.mutationKey)&&Object.assign(n,t.defaultOptions)}),n}defaultQueryOptions(e){if(e._defaulted)return e;let t={...this.#n.queries,...this.getQueryDefaults(e.queryKey),...e,_defaulted:!0};return t.queryHash||=oe(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===ge&&(t.enabled=!1),t}defaultMutationOptions(e){return e?._defaulted?e:{...this.#n.mutations,...e?.mutationKey&&this.getMutationDefaults(e.mutationKey),...e,_defaulted:!0}}clear(){this.#e.clear(),this.#t.clear()}},et=o((e=>{var t=Symbol.for(`react.transitional.element`),n=Symbol.for(`react.fragment`);function r(e,n,r){var i=null;if(r!==void 0&&(i=``+r),n.key!==void 0&&(i=``+n.key),`key`in n)for(var a in r={},n)a!==`key`&&(r[a]=n[a]);else r=n;return n=r.ref,{$$typeof:t,type:e,key:i,ref:n===void 0?null:n,props:r}}e.Fragment=n,e.jsx=r,e.jsxs=r})),tt=o(((e,t)=>{t.exports=et()})),k=c(u(),1),A=tt(),nt=k.createContext(void 0),rt=e=>{let t=k.useContext(nt);if(e)return e;if(!t)throw Error(`No QueryClient set, use QueryClientProvider to set one`);return t},it=({client:e,children:t})=>(k.useEffect(()=>(e.mount(),()=>{e.unmount()}),[e]),(0,A.jsx)(nt.Provider,{value:e,children:t})),at=k.createContext(!1),ot=()=>k.useContext(at);at.Provider;function st(){let e=!1;return{clearReset:()=>{e=!1},reset:()=>{e=!0},isReset:()=>e}}var ct=k.createContext(st()),lt=()=>k.useContext(ct),ut=(e,t,n)=>{let r=n?.state.error&&typeof e.throwOnError==`function`?ve(e.throwOnError,[n.state.error,n]):e.throwOnError;(e.suspense||e.experimental_prefetchInRender||r)&&(t.isReset()||(e.retryOnMount=!1))},dt=e=>{k.useEffect(()=>{e.clearReset()},[e])},ft=({result:e,errorResetBoundary:t,throwOnError:n,query:r,suspense:i})=>e.isError&&!t.isReset()&&!e.isFetching&&r&&(i&&e.data===void 0||ve(n,[e.error,r])),pt=e=>{if(e.suspense){let t=1e3,n=e=>e===`static`?e:Math.max(e??t,t),r=e.staleTime;e.staleTime=typeof r==`function`?(...e)=>n(r(...e)):n(r),typeof e.gcTime==`number`&&(e.gcTime=Math.max(e.gcTime,t))}},mt=(e,t)=>e.isLoading&&e.isFetching&&!t,ht=(e,t)=>e?.suspense&&t.isPending,gt=(e,t,n)=>t.fetchOptimistic(e).catch(()=>{n.clearReset()});function _t({queries:e,...t},n){let r=rt(n),i=ot(),a=lt(),o=k.useMemo(()=>e.map(e=>{let t=r.defaultQueryOptions(e);return t._optimisticResults=i?`isRestoring`:`optimistic`,t}),[e,r,i]);o.forEach(e=>{pt(e),ut(e,a,r.getQueryCache().get(e.queryHash))}),dt(a);let[s]=k.useState(()=>new Ze(r,o,t)),[c,l,u]=s.getOptimisticResult(o,t.combine),d=!i&&t.subscribed!==!1;k.useSyncExternalStore(k.useCallback(e=>d?s.subscribe(O.batchCalls(e)):S,[s,d]),()=>s.getCurrentResult(),()=>s.getCurrentResult()),k.useEffect(()=>{s.setQueries(o,t)},[o,t,s]);let f=c.some((e,t)=>ht(o[t],e))?c.flatMap((e,t)=>{let n=o[t];return n&&ht(n,e)?gt(n,new Le(r,n),a):[]}):[];if(f.length>0)throw Promise.all(f);let p=c.find((e,t)=>{let n=o[t];return n&&ft({result:e,errorResetBoundary:a,throwOnError:n.throwOnError,query:r.getQueryCache().get(n.queryHash),suspense:n.suspense})});if(p?.error)throw p.error;return l(u())}function vt(e,t,n){let r=ot(),i=lt(),a=rt(n),o=a.defaultQueryOptions(e);a.getDefaultOptions().queries?._experimental_beforeQuery?.(o);let s=a.getQueryCache().get(o.queryHash),c=e.subscribed!==!1;o._optimisticResults=r?`isRestoring`:c?`optimistic`:void 0,pt(o),ut(o,i,s),dt(i);let l=!a.getQueryCache().get(o.queryHash),[u]=k.useState(()=>new t(a,o)),d=u.getOptimisticResult(o),f=!r&&c;if(k.useSyncExternalStore(k.useCallback(e=>{let t=f?u.subscribe(O.batchCalls(e)):S;return u.updateResult(),t},[u,f]),()=>u.getCurrentResult(),()=>u.getCurrentResult()),k.useEffect(()=>{u.setOptions(o)},[o,u]),ht(o,d))throw gt(o,u,i);if(ft({result:d,errorResetBoundary:i,throwOnError:o.throwOnError,query:s,suspense:o.suspense}))throw d.error;return a.getDefaultOptions().queries?._experimental_afterQuery?.(o,d),o.experimental_prefetchInRender&&!be.isServer()&&mt(d,r)&&(l?gt(o,u,i):s?.promise)?.catch(S).finally(()=>{u.updateResult()}),o.notifyOnChangeProps?d:u.trackResult(d)}function j(e,t){return vt(e,Le,t)}function yt(e,t){let n=rt(t),[r]=k.useState(()=>new Je(n,e));k.useEffect(()=>{r.setOptions(e)},[r,e]);let i=k.useSyncExternalStore(k.useCallback(e=>r.subscribe(O.batchCalls(e)),[r]),()=>r.getCurrentResult(),()=>r.getCurrentResult()),a=k.useCallback((e,t)=>{r.mutate(e,t).catch(S)},[r]);if(i.error&&ve(r.options.throwOnError,[i.error]))throw i.error;return{...i,mutate:a,mutateAsync:i.mutate}}var bt=c(g(),1),xt=`berth.adminToken`;function St(){return sessionStorage.getItem(xt)}function Ct(e){sessionStorage.setItem(xt,e)}function wt(){sessionStorage.removeItem(xt)}var M={deployments:[`deps`],models:[`models`],keys:[`keys`],gpus:[`gpus`],backends:[`backends`],adapters:[`adapters`],profiles:[`profiles`],routes:[`routes`],nodes:[`nodes`],requests:[`requests`],predictorCandidates:[`predictor-candidates`],predictorStats:[`predictor-stats`],metricsSnapshot:[`metrics-snapshot`],clusterInfo:[`cluster-info`],config:[`config`],requestsSeed:[`requests-seed`],node:e=>[`node`,e],keyUsage:(e,t)=>[`key-usage`,e,t],usageSeries:(e,t,n)=>[`usage-series`,e,t,n],metricsHistory:(e,t)=>[`metrics-history`,e,t],metricsSummary:(e,t)=>[`metrics-summary`,e,t]};async function Tt(e){if(!St())return e;let t=await P.createStreamToken(new URL(e,window.location.origin).pathname);return`${e}${e.includes(`?`)?`&`:`?`}stream_token=${encodeURIComponent(t.token)}`}async function N(e,t,n){let r={"Content-Type":`application/json`},i=St();i&&(r.Authorization=`Bearer ${i}`);let a=await fetch(t,{method:e,headers:r,body:n===void 0?void 0:JSON.stringify(n)});if(!a.ok){let e=await a.text();throw Error(`${a.status}: ${e}`)}if(a.status!==204)return a.json()}var P={listDeployments:()=>N(`GET`,`/admin/deployments`),stopDeployment:e=>N(`DELETE`,`/admin/deployments/${e}`),pinDeployment:e=>N(`POST`,`/admin/deployments/${e}/pin`),unpinDeployment:e=>N(`POST`,`/admin/deployments/${e}/unpin`),listModels:()=>N(`GET`,`/admin/models`),createModel:e=>N(`POST`,`/admin/models`,e),deleteModel:e=>N(`DELETE`,`/admin/models/${e}`),listKeys:()=>N(`GET`,`/admin/keys`),createKey:e=>N(`POST`,`/admin/keys`,e),revokeKey:e=>N(`DELETE`,`/admin/keys/${e}`),listGpus:()=>N(`GET`,`/admin/gpus`),listBackends:()=>N(`GET`,`/admin/backends`),loadModel:e=>N(`POST`,`/admin/deployments`,e),createStreamToken:e=>N(`POST`,`/admin/stream-token`,{path:e}),listAdapters:()=>N(`GET`,`/admin/adapters`),createAdapter:e=>N(`POST`,`/admin/adapters`,e),downloadAdapter:e=>N(`POST`,`/admin/adapters/${e}/download`),addLocalAdapter:e=>N(`POST`,`/admin/adapters/local`,e),deleteAdapter:(e,t=!1)=>N(`DELETE`,`/admin/adapters/${e}${t?`?force=true`:``}`),hotLoadAdapter:(e,t)=>N(`POST`,`/admin/deployments/${e}/adapters/${t}`),hotUnloadAdapter:(e,t)=>N(`DELETE`,`/admin/deployments/${e}/adapters/${t}`),predictorCandidates:()=>N(`GET`,`/admin/predictor/candidates`),predictorStats:()=>N(`GET`,`/admin/predictor/stats`),listProfiles:()=>N(`GET`,`/admin/service-profiles`),createProfile:e=>N(`POST`,`/admin/service-profiles`,e),deployProfile:e=>N(`POST`,`/admin/service-profiles/${encodeURIComponent(e)}/deploy`),deleteProfile:e=>N(`DELETE`,`/admin/service-profiles/${encodeURIComponent(e)}`),listRoutes:()=>N(`GET`,`/admin/routes`),createRoute:e=>N(`POST`,`/admin/routes`,e),deleteRoute:e=>N(`DELETE`,`/admin/routes/${encodeURIComponent(e)}`),dryRunRoute:e=>N(`GET`,`/admin/routes/match/dry-run?model=${encodeURIComponent(e)}`),keyUsage:(e,t=86400,n=3600)=>N(`GET`,`/admin/keys/${e}/usage?window_s=${t}&bucket_s=${n}`),listRequests:()=>N(`GET`,`/admin/requests`),listNodes:()=>N(`GET`,`/admin/nodes`),getNode:e=>N(`GET`,`/admin/nodes/${e}`),enrollNode:e=>N(`POST`,`/admin/nodes/enroll`,{label:e}),removeNode:e=>N(`DELETE`,`/admin/nodes/${e}`),getClusterInfo:()=>N(`GET`,`/admin/cluster`),getConfig:()=>N(`GET`,`/admin/config`),getMetricsSnapshot:()=>N(`GET`,`/admin/metrics/snapshot`),getUsageSeries:(e=86400,t=3600)=>N(`GET`,`/admin/usage/series?window_s=${e}&bucket_s=${t}`),getUsageByModel:(e=86400,t=3600)=>N(`GET`,`/admin/usage/series?window_s=${e}&bucket_s=${t}&group_by=model`),getMetricsHistory:(e=86400,t=3600)=>N(`GET`,`/admin/metrics/history?window_s=${e}&bucket_s=${t}`),getMetricsSummary:(e=86400)=>N(`GET`,`/admin/metrics/history?window_s=${e}&summary=true`),getMetricsByModel:(e=86400)=>N(`GET`,`/admin/metrics/history?window_s=${e}&summary=true&group_by=model`)};function Et(e){return`berth://enroll?${new URLSearchParams({leader:e.leader_url,token:e.token,ca_fp:e.ca_fingerprint}).toString()}`}function Dt({children:e}){let[t,n]=(0,k.useState)(St()),[r,i]=(0,k.useState)(``);return t?(0,A.jsx)(A.Fragment,{children:e}):(0,A.jsx)(`div`,{className:`min-h-screen flex items-center justify-center px-6`,children:(0,A.jsxs)(`div`,{className:`w-full max-w-md enter`,children:[(0,A.jsxs)(`div`,{className:`flex items-center gap-2 mb-12`,children:[(0,A.jsx)(`div`,{className:`text-base`,children:`berth`}),(0,A.jsx)(`span`,{className:`caret`})]}),(0,A.jsxs)(`div`,{className:`space-y-8`,children:[(0,A.jsxs)(`div`,{className:`space-y-2`,children:[(0,A.jsx)(`div`,{className:`label`,children:`authenticate`}),(0,A.jsx)(`p`,{className:`text-dim text-[12px] leading-relaxed`,children:`Paste an admin-tier API key. If you don't have one, run this on the host:`}),(0,A.jsxs)(`pre`,{className:`text-[12px] bg-elev border border-rule px-3 py-2 text-ink overflow-x-auto`,children:[(0,A.jsx)(`span`,{className:`text-mute select-none`,children:`$ `}),`berth key create web --tier admin`]})]}),(0,A.jsxs)(`div`,{className:`space-y-3`,children:[(0,A.jsx)(`div`,{className:`label`,children:`api key`}),(0,A.jsx)(`input`,{className:`field w-full font-mono`,placeholder:`sk-...`,value:r,onChange:e=>i(e.target.value),onKeyDown:e=>{e.key===`Enter`&&r.trim()&&(Ct(r.trim()),n(r.trim()))},autoFocus:!0}),(0,A.jsx)(`button`,{className:`btn-primary w-full`,disabled:!r.trim(),onClick:()=>{Ct(r.trim()),n(r.trim())},children:`Continue`})]})]})]})})}function Ot({label:e,usedMb:t,totalMb:n,utilPct:r,powerW:i,right:a,loaded:o}){let s=n>0?t/n*100:0;return(0,A.jsxs)(`div`,{className:`space-y-4`,children:[(0,A.jsxs)(`div`,{className:`flex items-baseline justify-between`,children:[(0,A.jsx)(`div`,{className:`label`,children:e}),(0,A.jsxs)(`div`,{className:`text-mute text-[11px] tnum`,children:[s.toFixed(0),`%`]})]}),(0,A.jsxs)(`div`,{className:`flex items-baseline gap-2 tnum`,children:[(0,A.jsx)(`div`,{className:`text-3xl font-light tracking-tightish`,children:(t/1024).toFixed(1)}),(0,A.jsxs)(`div`,{className:`text-mute text-[12px]`,children:[`/ `,(n/1024).toFixed(0),` GB`]})]}),(0,A.jsx)(`div`,{className:`h-px bg-rule relative overflow-hidden`,children:(0,A.jsx)(`div`,{className:`absolute inset-y-0 left-0 bg-accent transition-[width] duration-500`,style:{width:`${s}%`}})}),(0,A.jsxs)(`div`,{className:`flex items-center gap-6 text-mute text-[11px] tnum`,children:[(0,A.jsxs)(`span`,{children:[`util `,r,`%`]}),i!=null&&(0,A.jsxs)(`span`,{children:[i,` w`]}),a&&(0,A.jsx)(`span`,{className:`ml-auto`,children:a})]}),o]})}function kt(e){return e?e>=1024?`${(e/1024).toFixed(1)} GB`:`${e} MB`:`-`}function At(e){return!e||e.length===0?`-`:e.length===1?`gpu ${e[0]}`:`gpu ${e.join(`,`)}`}function jt(e){return e<=1?`grid-cols-1`:e===2?`grid-cols-1 md:grid-cols-2`:e===3?`grid-cols-1 md:grid-cols-3`:`grid-cols-1 md:grid-cols-2 lg:grid-cols-4`}function Mt(e){if(e.pinned||!e.idle_timeout_s||!e.last_request_at)return null;let t=String(e.last_request_at).replace(` `,`T`)+`Z`,n=Date.parse(t);if(Number.isNaN(n))return null;let r=e.idle_timeout_s-(Date.now()-n)/1e3;return r<=0?`evicting`:r<60?`${Math.round(r)}s`:`${Math.round(r/60)}m`}function Nt({d:e,modelName:t}){let n=Mt(e),r=e.vram_used_mb&&e.vram_used_mb>0?e.vram_used_mb:e.vram_reserved_mb;return(0,A.jsxs)(`div`,{className:`flex items-center gap-3 text-[12px] py-1.5`,title:e.last_error||`deployment #${e.id} on ${e.backend}`,children:[(0,A.jsx)(`span`,{className:`dot dot-${e.status}`}),(0,A.jsx)(`span`,{className:`text-ink truncate flex-1 min-w-0`,children:t}),(0,A.jsx)(`span`,{className:`text-mute text-[10px] tracking-wider hidden lg:inline`,children:e.backend}),(0,A.jsx)(`span`,{className:`text-dim tnum`,children:kt(r)}),e.pinned?(0,A.jsx)(`span`,{className:`text-accent text-[10px] tracking-wider`,children:`pin`}):n?(0,A.jsx)(`span`,{className:`text-mute text-[10px] tracking-wider`,title:`idle countdown`,children:n}):(0,A.jsx)(`span`,{className:`text-mute text-[10px]`,children:`—`})]})}function Pt({g:e,deployments:t,models:n}){let r=t.filter(t=>(t.gpu_ids??[]).includes(e.index)&&(t.status===`ready`||t.status===`loading`));return(0,A.jsx)(Ot,{label:`gpu ${e.index}`,usedMb:e.memory_used_mb,totalMb:e.memory_total_mb,utilPct:e.gpu_util_pct,powerW:e.power_w,right:r.length===0?(0,A.jsx)(`span`,{className:`text-mute`,children:`idle`}):(0,A.jsxs)(`span`,{className:`text-dim`,children:[r.length,` loaded`]}),loaded:r.length>0&&(0,A.jsx)(`div`,{className:`pt-2 border-t border-rule-soft space-y-0.5`,children:r.map(e=>(0,A.jsx)(Nt,{d:e,modelName:n.find(t=>t.id===e.model_id)?.name??`#${e.id}`},e.id))})})}function Ft(){let e=j({queryKey:M.metricsSnapshot,queryFn:P.getMetricsSnapshot,refetchInterval:2e3}),t=j({queryKey:M.deployments,queryFn:P.listDeployments,refetchInterval:2e3}),n=j({queryKey:M.models,queryFn:P.listModels,refetchInterval:5e3}),r=j({queryKey:M.gpus,queryFn:P.listGpus,refetchInterval:2e3}),i=e.data?.nodes??[],a=t.data??[],o=n.data??[],s=i.reduce((e,t)=>e+t.gpus.length,0),c=i.filter(e=>e.gpus.length>0).length>1,l=(e,t)=>i.length<=1||e.node_id===t.node_id||t.label===`local`&&e.node_id==null;if(s===0){let e=r.data??[];return(0,A.jsxs)(`section`,{className:`space-y-6`,children:[(0,A.jsx)(`div`,{className:`label`,children:`gpus`}),e.length===0?(0,A.jsx)(`div`,{className:`text-mute text-[12px]`,children:`no gpus reported`}):(0,A.jsx)(`div`,{className:`grid gap-12 `+jt(e.length),children:e.map(e=>(0,A.jsx)(Pt,{g:e,deployments:a,models:o},e.index))})]})}return(0,A.jsxs)(`section`,{className:`space-y-8`,children:[(0,A.jsx)(`div`,{className:`label`,children:`gpus`}),i.filter(e=>e.gpus.length>0).map(e=>(0,A.jsxs)(`div`,{className:`space-y-4`,children:[c&&(0,A.jsxs)(`div`,{className:`flex items-baseline gap-3`,children:[(0,A.jsx)(`span`,{className:e.label===`local`?`text-dim text-[12px] tracking-wider`:`text-accent text-[12px] tracking-wider`,children:e.label}),(0,A.jsxs)(`span`,{className:`text-mute text-[11px]`,children:[e.gpus.length,` gpu`]})]}),(0,A.jsx)(`div`,{className:`grid gap-12 `+jt(e.gpus.length),children:e.gpus.map(t=>{let n=a.filter(n=>(n.gpu_ids??[]).includes(t.index)&&(n.status===`ready`||n.status===`loading`)&&l(n,e));return(0,A.jsx)(Ot,{label:`gpu ${t.index}`,usedMb:t.mem_used_mb,totalMb:t.mem_total_mb,utilPct:t.util_pct,right:n.length===0?(0,A.jsx)(`span`,{className:`text-mute`,children:`idle`}):(0,A.jsxs)(`span`,{className:`text-dim`,children:[n.length,` loaded`]}),loaded:n.length>0&&(0,A.jsx)(`div`,{className:`pt-2 border-t border-rule-soft space-y-0.5`,children:n.map(e=>(0,A.jsx)(Nt,{d:e,modelName:o.find(t=>t.id===e.model_id)?.name??`#${e.id}`},e.id))})},t.index)})})]},e.node_id))]})}function It({values:e,width:t=80,height:n=20}){if(e.length===0)return(0,A.jsx)(`span`,{style:{color:`#888`},children:`—`});let r=Math.max(1,...e),i=t/Math.max(1,e.length-1);return(0,A.jsx)(`svg`,{width:t,height:n,"aria-label":`sparkline`,children:(0,A.jsx)(`polyline`,{fill:`none`,stroke:`currentColor`,strokeWidth:`1`,points:e.map((e,t)=>`${(t*i).toFixed(1)},${(n-e/r*n).toFixed(1)}`).join(` `)})})}function Lt({title:e,value:t,sub:n,spark:r,badge:i,onClick:a}){return(0,A.jsxs)(`div`,{className:`space-y-3 border-l border-rule pl-5 `+(a?`cursor-pointer hover:border-accent transition-colors`:``),onClick:a,children:[(0,A.jsx)(`div`,{className:`label`,children:e}),(0,A.jsx)(`div`,{className:`text-2xl font-light tracking-tightish tnum`,children:t}),r&&r.length>0&&(0,A.jsx)(`div`,{className:`text-accent`,children:(0,A.jsx)(It,{values:r,width:120,height:22})}),n&&(0,A.jsx)(`div`,{className:`text-mute text-[11px] tracking-wider`,children:n}),i&&(0,A.jsx)(`div`,{className:`text-mute text-[10px] tracking-wider uppercase`,children:i})]})}function Rt({buckets:e,height:t=56}){if(e.length===0)return(0,A.jsx)(`div`,{className:`text-mute text-[12px]`,children:`no traffic in window`});let n=Math.max(1,...e.map(e=>e.count)),r=100/e.length;return(0,A.jsx)(`svg`,{width:`100%`,height:t,viewBox:`0 0 100 ${t}`,preserveAspectRatio:`none`,"aria-label":`requests over time`,children:e.map((e,i)=>{let a=e.count/n*t;return(0,A.jsx)(`rect`,{x:i*r+1/2,y:t-a,width:Math.max(r-1,.4),height:a,className:`text-accent`,fill:`currentColor`,opacity:e.count===0?.15:.85,children:(0,A.jsxs)(`title`,{children:[e.count,` req`]})},i)})})}function zt({buckets:e,height:t=56}){if(e.filter(e=>e.count>0).length===0)return(0,A.jsx)(`div`,{className:`text-mute text-[12px]`,children:`no requests in window`});let n=Math.max(1,...e.map(e=>e.latency_p95_ms??0)),r=100/e.length;return(0,A.jsxs)(`div`,{className:`space-y-1`,children:[(0,A.jsx)(`svg`,{width:`100%`,height:t,viewBox:`0 0 100 ${t}`,preserveAspectRatio:`none`,"aria-label":`p95 latency over time`,children:e.map((e,i)=>{let a=(e.latency_p95_ms??0)/n*t;return(0,A.jsx)(`rect`,{x:i*r+1/2,y:t-a,width:Math.max(r-1,.4),height:a,className:`text-accent`,fill:`currentColor`,opacity:e.count===0?.12:.85,children:(0,A.jsxs)(`title`,{children:[`p95 `,e.latency_p95_ms??0,`ms · `,e.count,` req`]})},i)})}),(0,A.jsx)(`svg`,{width:`100%`,height:8,viewBox:`0 0 100 8`,preserveAspectRatio:`none`,"aria-label":`error rate over time`,children:e.map((e,t)=>(0,A.jsx)(`rect`,{x:t*r+1/2,y:0,width:Math.max(r-1,.4),height:8,className:`text-err`,fill:`currentColor`,opacity:e.count===0?.06:Math.max(.08,e.error_rate),children:(0,A.jsxs)(`title`,{children:[(e.error_rate*100).toFixed(1),`% errors · `,e.error_count,`/`,e.count]})},t))}),(0,A.jsxs)(`div`,{className:`flex justify-between text-mute text-[10px] tracking-wider`,children:[(0,A.jsx)(`span`,{children:`p95 latency`}),(0,A.jsxs)(`span`,{children:[`peak `,n.toLocaleString(),` ms · error rate strip`]})]})]})}function Bt({groups:e,limit:t=5}){let n=e.slice(0,t);if(n.length===0)return(0,A.jsx)(`div`,{className:`text-mute text-[12px]`,children:`no requests in window`});let r=Math.max(1,...n.map(e=>e.total));return(0,A.jsx)(`div`,{className:`space-y-2`,children:n.map(e=>(0,A.jsxs)(`div`,{className:`flex items-center gap-3 text-[12px]`,children:[(0,A.jsx)(`span`,{className:`font-mono text-ink truncate w-[14ch]`,title:e.label,children:e.label}),(0,A.jsx)(`span`,{className:`text-dim tnum w-[8ch] text-right`,children:e.total.toLocaleString()}),(0,A.jsx)(`div`,{className:`flex-1 h-1 bg-rule-soft relative overflow-hidden`,children:(0,A.jsx)(`div`,{className:`absolute inset-y-0 left-0 bg-accent`,style:{width:`${e.total/r*100}%`}})})]},e.key))})}function Vt({groups:e,limit:t=6}){let n=e.slice(0,t);return n.length===0?(0,A.jsx)(`div`,{className:`text-mute text-[12px]`,children:`no requests in window`}):(0,A.jsxs)(`table`,{className:`ditable`,children:[(0,A.jsx)(`thead`,{children:(0,A.jsxs)(`tr`,{children:[(0,A.jsx)(`th`,{children:`model`}),(0,A.jsx)(`th`,{className:`text-right`,children:`p95`}),(0,A.jsx)(`th`,{className:`text-right`,children:`errors`}),(0,A.jsx)(`th`,{className:`text-right`,children:`req`})]})}),(0,A.jsx)(`tbody`,{children:n.map(e=>{let t=e.summary.error_rate*100;return(0,A.jsxs)(`tr`,{children:[(0,A.jsx)(`td`,{className:`font-mono truncate max-w-[16ch]`,title:e.label,children:e.label}),(0,A.jsx)(`td`,{className:`text-right tnum text-dim`,children:e.summary.latency_p95_ms===null?`—`:`${e.summary.latency_p95_ms} ms`}),(0,A.jsx)(`td`,{className:`text-right tnum`,children:(0,A.jsxs)(`span`,{className:t>0?`text-err`:`text-mute`,children:[t.toFixed(+(t>0&&t<1)),`%`]})}),(0,A.jsx)(`td`,{className:`text-right tnum text-mute`,children:e.summary.count.toLocaleString()})]},e.key)})})]})}function Ht(){let e=j({queryKey:M.deployments,queryFn:P.listDeployments,refetchInterval:2e3}),t=j({queryKey:M.models,queryFn:P.listModels,refetchInterval:5e3}),n=j({queryKey:M.nodes,queryFn:P.listNodes,refetchInterval:5e3}),r=(e.data??[]).filter(e=>e.status===`ready`||e.status===`loading`);return(0,A.jsxs)(`div`,{className:`space-y-4`,children:[(0,A.jsxs)(`div`,{className:`flex items-baseline justify-between`,children:[(0,A.jsx)(`div`,{className:`label`,children:`active deployments`}),(0,A.jsx)(`button`,{className:`text-mute text-[11px] tracking-wider hover:text-dim transition-colors`,onClick:()=>{location.hash=`#/serving/deployments`},children:`manage in serving →`})]}),r.length===0?(0,A.jsx)(`div`,{className:`text-mute text-[12px]`,children:`nothing loaded`}):(0,A.jsx)(`div`,{className:`space-y-1`,children:r.map(e=>{let r=(t.data??[]).find(t=>t.id===e.model_id),i=(n.data?.nodes??[]).find(t=>t.id===e.node_id)?.label??(e.node_id?`#${e.node_id}`:`local`);return(0,A.jsxs)(`div`,{className:`flex items-center gap-3 text-[12px] py-1`,children:[(0,A.jsx)(`span`,{className:`dot dot-${e.status}`}),(0,A.jsx)(`span`,{className:`text-ink truncate flex-1 min-w-0`,children:r?.name??`#${e.id}`}),(0,A.jsx)(`span`,{className:`text-mute text-[10px] tracking-wider`,children:e.backend}),(0,A.jsx)(`span`,{className:`text-dim tnum w-[7ch] text-right`,children:(e.gpu_ids??[]).length?`gpu ${(e.gpu_ids??[]).join(`,`)}`:`-`}),i!==`local`&&(0,A.jsx)(`span`,{className:`text-accent text-[10px]`,children:i})]},e.id)})})]})}function Ut(e){let t=(e?.nodes??[]).flatMap(e=>e.deployments),n=0,r=0,i=0,a=0,o=0,s=0;for(let e of t){n+=e.in_flight,r+=e.requests_last_window,i+=e.errors_last_window;let t=e.requests_last_window||0;a+=e.latency_p50_ms*t,o+=e.latency_p95_ms*t,s+=t}let c=t.length?t.reduce((e,t)=>e+t.latency_p50_ms,0)/t.length:0,l=t.length?t.reduce((e,t)=>e+t.latency_p95_ms,0)/t.length:0;return{inFlight:n,requestsWindow:r,errorsWindow:i,errorRate:i/Math.max(r,1),latencyP50:s?a/s:c,latencyP95:s?o/s:l}}function Wt(e,t){if(e.length===0||t<=0)return{reqPerMin:0,tokPerSec:0,totalOut:0};let n=e.slice(-3),r=n.length*t,i=n.reduce((e,t)=>e+t.count,0),a=n.reduce((e,t)=>e+t.tokens_out,0),o=e.reduce((e,t)=>e+t.tokens_out,0);return{reqPerMin:r?i/r*60:0,tokPerSec:r?a/r:0,totalOut:o}}function Gt(e,t){return(0,A.jsxs)(A.Fragment,{children:[e,(0,A.jsxs)(`span`,{className:`text-mute text-[13px]`,children:[` `,t]})]})}function Kt(){let e=j({queryKey:M.deployments,queryFn:P.listDeployments,refetchInterval:2e3}),t=j({queryKey:M.gpus,queryFn:P.listGpus,refetchInterval:2e3}),n=j({queryKey:M.nodes,queryFn:P.listNodes,refetchInterval:5e3}),r=j({queryKey:M.metricsSnapshot,queryFn:P.getMetricsSnapshot,refetchInterval:2e3}),i=j({queryKey:M.usageSeries(3600,60,`none`),queryFn:()=>P.getUsageSeries(3600,60),refetchInterval:5e3}),a=j({queryKey:M.usageSeries(86400,3600,`none`),queryFn:()=>P.getUsageSeries(86400,3600),refetchInterval:3e4}),o=j({queryKey:M.usageSeries(86400,3600,`model`),queryFn:()=>P.getUsageByModel(86400,3600),refetchInterval:3e4}),s=j({queryKey:M.metricsSummary(86400,`none`),queryFn:()=>P.getMetricsSummary(86400),refetchInterval:15e3}),c=j({queryKey:M.metricsHistory(86400,3600),queryFn:()=>P.getMetricsHistory(86400,3600),refetchInterval:3e4}),l=j({queryKey:M.metricsSummary(86400,`model`),queryFn:()=>P.getMetricsByModel(86400),refetchInterval:3e4}),u=(e.data??[]).filter(e=>e.status===`ready`||e.status===`loading`),d=Ut(r.data),f=i.data?.buckets??[],p=Wt(f,60),m=f.slice(-30).map(e=>e.count),h=f.slice(-30).map(e=>e.tokens_out),g=s.data?.summary,_=(r.data?.nodes??[]).reduce((e,t)=>e+t.gpus.length,0)||(t.data??[]).length;return(0,A.jsxs)(`div`,{className:`space-y-14`,children:[(0,A.jsxs)(`header`,{className:`flex items-baseline justify-between`,children:[(0,A.jsx)(`h2`,{className:`text-2xl font-light tracking-tightish caret`,children:`overview`}),(0,A.jsxs)(`div`,{className:`flex items-baseline gap-6`,children:[(()=>{let e=n.data?.nodes??[],t=e.filter(e=>e.status===`ready`).length,r=e.filter(e=>e.label!==`local`).length;return e.length===0?null:(0,A.jsx)(`div`,{className:`label`,title:`cluster nodes`,children:r===0?(0,A.jsx)(A.Fragment,{children:`single-node`}):(0,A.jsxs)(A.Fragment,{children:[`cluster `,(0,A.jsxs)(`span`,{className:`text-dim`,children:[t,`/`,e.length]})]})})})(),(0,A.jsxs)(`div`,{className:`label`,children:[_,` gpu / `,u.length,` active`]})]})]}),(0,A.jsx)(Ft,{}),(0,A.jsxs)(`section`,{className:`space-y-6`,children:[(0,A.jsx)(`div`,{className:`label`,children:`request stats`}),(0,A.jsxs)(`div`,{className:`grid grid-cols-2 lg:grid-cols-4 gap-y-8 gap-x-6`,children:[(0,A.jsx)(Lt,{title:`volume`,value:Gt(p.reqPerMin.toFixed(+(p.reqPerMin<10)),`req/min`),sub:`${d.inFlight} in flight`,spark:m,badge:`live`}),(0,A.jsx)(Lt,{title:`latency`,value:Gt(g?.latency_p50_ms==null?`—`:String(g.latency_p50_ms),`ms p50`),sub:`p95 ${g?.latency_p95_ms??`—`} ms`,badge:`24h`}),(0,A.jsx)(Lt,{title:`errors`,value:Gt(g?(g.error_rate*100).toFixed(1):`—`,`%`),sub:(0,A.jsxs)(`span`,{className:`text-accent`,children:[g?.error_count??0,` in 24h → see traffic`]}),badge:`24h`,onClick:()=>{location.hash=`#/observe/requests`}}),(0,A.jsx)(Lt,{title:`throughput`,value:Gt(p.tokPerSec.toFixed(0),`tok/s`),sub:`${p.totalOut.toLocaleString()} out tok · 1h`,spark:h,badge:`live`})]})]}),(0,A.jsxs)(`section`,{className:`space-y-4`,children:[(0,A.jsxs)(`div`,{className:`flex items-baseline justify-between`,children:[(0,A.jsx)(`div`,{className:`label`,children:`traffic over time`}),(0,A.jsx)(`div`,{className:`text-mute text-[10px] tracking-wider uppercase`,children:`last 24h · bounded by retention`})]}),(0,A.jsx)(Rt,{buckets:a.data?.buckets??[]})]}),(0,A.jsxs)(`section`,{className:`space-y-4`,children:[(0,A.jsxs)(`div`,{className:`flex items-baseline justify-between`,children:[(0,A.jsx)(`div`,{className:`label`,children:`latency & errors over time`}),(0,A.jsx)(`div`,{className:`text-mute text-[10px] tracking-wider uppercase`,children:`last 24h`})]}),(0,A.jsx)(zt,{buckets:c.data?.buckets??[]})]}),(0,A.jsxs)(`div`,{className:`grid grid-cols-1 lg:grid-cols-2 gap-x-12 gap-y-10`,children:[(0,A.jsxs)(`section`,{className:`space-y-4`,children:[(0,A.jsx)(`div`,{className:`label`,children:`top models · 24h`}),(0,A.jsx)(Bt,{groups:o.data?.groups??[]})]}),(0,A.jsxs)(`section`,{className:`space-y-4`,children:[(0,A.jsx)(`div`,{className:`label`,children:`latency & errors by model · 24h`}),(0,A.jsx)(Vt,{groups:l.data?.groups??[]})]})]}),(0,A.jsx)(`section`,{children:(0,A.jsx)(Ht,{})})]})}function qt({used:e,reserved:t,status:n}){return n===`stopped`||n===`failed`?(0,A.jsx)(`span`,{children:`-`}):e&&e>0?(0,A.jsxs)(`div`,{className:`flex flex-col items-end leading-tight`,children:[(0,A.jsx)(`span`,{children:kt(e)}),(0,A.jsxs)(`span`,{className:`text-mute text-[10px]`,children:[`est `,kt(t)]})]}):(0,A.jsxs)(`div`,{className:`flex flex-col items-end leading-tight`,children:[(0,A.jsx)(`span`,{className:`text-dim`,children:kt(t)}),(0,A.jsx)(`span`,{className:`text-mute text-[10px]`,children:`est`})]})}function Jt(){let e=rt(),t=j({queryKey:M.deployments,queryFn:P.listDeployments,refetchInterval:2e3}),n=j({queryKey:M.models,queryFn:P.listModels,refetchInterval:5e3}),r=j({queryKey:M.nodes,queryFn:P.listNodes,refetchInterval:5e3}),[i,a]=(0,k.useState)(!1),[o,s]=(0,k.useState)(null),[c,l]=(0,k.useState)(``),u=yt({mutationFn:e=>P.stopDeployment(e),onMutate:e=>{s(e),l(``)},onError:e=>l(e.message),onSettled:()=>{s(null),e.invalidateQueries({queryKey:M.deployments})}}),d=yt({mutationFn:({id:e,pinned:t})=>t?P.unpinDeployment(e):P.pinDeployment(e),onMutate:({id:e})=>{s(e),l(``)},onError:e=>l(e.message),onSettled:()=>{s(null),e.invalidateQueries({queryKey:M.deployments})}}),f=t.data??[],p=f.filter(e=>e.status===`ready`||e.status===`loading`),m=i?f:p,h=f.length-m.length;return(0,A.jsxs)(`div`,{className:`space-y-10`,children:[(0,A.jsxs)(`header`,{className:`flex items-baseline justify-between`,children:[(0,A.jsx)(`h2`,{className:`text-2xl font-light tracking-tightish caret`,children:`deployments`}),(0,A.jsxs)(`div`,{className:`label`,children:[p.length,` active / `,f.length,` total`]})]}),(0,A.jsxs)(`section`,{className:`space-y-4`,children:[(0,A.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,A.jsx)(`div`,{className:`label`,children:`deployments`}),(0,A.jsxs)(`label`,{className:`text-mute text-[11px] tracking-wider select-none cursor-pointer hover:text-dim transition-colors`,children:[(0,A.jsx)(`input`,{type:`checkbox`,className:`mr-2 accent-accent align-middle`,checked:i,onChange:e=>a(e.target.checked)}),`show stopped `,h>0&&!i&&(0,A.jsxs)(`span`,{className:`text-accent`,children:[`(`,h,`)`]})]})]}),c&&(0,A.jsx)(`div`,{className:`text-err text-[11px] tracking-wider`,children:c}),(0,A.jsxs)(`table`,{className:`ditable`,children:[(0,A.jsx)(`thead`,{children:(0,A.jsxs)(`tr`,{children:[(0,A.jsx)(`th`,{children:`#`}),(0,A.jsx)(`th`,{children:`model`}),(0,A.jsx)(`th`,{children:`backend`}),(0,A.jsx)(`th`,{children:`node`}),(0,A.jsx)(`th`,{children:`status`}),(0,A.jsx)(`th`,{className:`text-right`,children:`vram`}),(0,A.jsx)(`th`,{className:`text-right`,children:`gpu`}),(0,A.jsx)(`th`,{className:`text-right`,children:`actions`})]})}),(0,A.jsxs)(`tbody`,{children:[m.length===0&&(0,A.jsx)(`tr`,{children:(0,A.jsxs)(`td`,{colSpan:8,className:`!py-12 text-center text-mute`,children:[`no active deployments. load one from `,(0,A.jsx)(`span`,{className:`text-dim`,children:`models`})]})}),m.map(e=>{let t=(n.data??[]).find(t=>t.id===e.model_id),i=(r.data?.nodes??[]).find(t=>t.id===e.node_id)?.label??(e.node_id?`#${e.node_id}`:`local`),a=e.status===`ready`||e.status===`loading`,s=o===e.id;return(0,A.jsxs)(`tr`,{title:e.last_error||void 0,children:[(0,A.jsx)(`td`,{className:`text-mute tnum`,children:e.id}),(0,A.jsx)(`td`,{children:t?.name??`-`}),(0,A.jsx)(`td`,{className:`text-dim`,children:e.backend}),(0,A.jsx)(`td`,{children:(0,A.jsx)(`span`,{className:i===`local`?`text-mute`:`text-accent`,children:i})}),(0,A.jsxs)(`td`,{children:[(0,A.jsx)(`span`,{className:`dot dot-${e.status}`}),(0,A.jsx)(`span`,{className:`text-dim`,children:e.status})]}),(0,A.jsx)(`td`,{className:`text-right tnum`,children:(0,A.jsx)(qt,{used:e.vram_used_mb??null,reserved:e.vram_reserved_mb,status:e.status})}),(0,A.jsx)(`td`,{className:`text-right text-dim tnum`,children:At(e.gpu_ids)}),(0,A.jsxs)(`td`,{className:`text-right space-x-5 whitespace-nowrap`,children:[(0,A.jsx)(`button`,{className:`transition-opacity hover:opacity-70 disabled:opacity-40 `+(e.pinned?`text-accent`:`text-dim`),disabled:s,onClick:()=>d.mutate({id:e.id,pinned:!!e.pinned}),title:e.pinned?`pinned: idle reaper will not stop this deployment`:`pin to keep alive through idle timeout`,children:e.pinned?`unpin`:`pin`}),a?(0,A.jsx)(`button`,{className:`btn-link-danger disabled:opacity-40`,disabled:s,onClick:()=>{confirm(`stop deployment #${e.id}?`)&&u.mutate(e.id)},children:s?`stopping...`:`stop`}):(0,A.jsx)(`span`,{className:`text-mute`,children:`—`})]})]},e.id)})]})]})]})]})}function Yt(e){let t=e.split(`,`).map(e=>e.trim()).filter(Boolean).map(Number).filter(e=>Number.isInteger(e)&&e>=0);if(t.length===0)throw Error(`gpu_ids: at least one integer required`);return t}function Xt(e){let t=Number(e);if(!Number.isInteger(t)||t<128)throw Error(`max_model_len: integer >= 128`);return t}function Zt(e){return e&&e!==`local`?e:null}var Qt={backend:``,maxModelLen:`4096`,gpuIds:`0`,pinned:!1,nodeLabel:``},$t=e=>new Promise(t=>setTimeout(t,e));function en(e){return e instanceof TypeError&&/failed to fetch|network/i.test(e.message)}async function tn(e,t){for(let n=0;n<15;n+=1){let n=(await P.listDeployments()).filter(n=>n.id>t&&n.model_id===e).sort((e,t)=>t.id-e.id)[0];if(n){if(n.status===`failed`)throw Error(n.last_error||`deployment failed after it started`);return n}await $t(1e3)}throw Error(`deployment request disconnected before a new deployment appeared`)}function nn(){let e=rt(),t=j({queryKey:M.models,queryFn:P.listModels}),n=j({queryKey:M.backends,queryFn:P.listBackends}),r=j({queryKey:M.gpus,queryFn:P.listGpus}),i=j({queryKey:M.nodes,queryFn:P.listNodes}),a=j({queryKey:M.config,queryFn:P.getConfig}),[o,s]=(0,k.useState)(``),[c,l]=(0,k.useState)(``),[u,d]=(0,k.useState)(null),[f,p]=(0,k.useState)(Qt),[m,h]=(0,k.useState)(``),g=a.data?.values.leader_only===!0,_=(i.data?.nodes??[]).filter(e=>e.label!==`local`),v=_.filter(e=>e.status===`ready`),y=f.nodeLabel||(g?v[0]?.label??``:``),b=g&&!y,x=yt({mutationFn:()=>P.createModel({name:c||o.split(`/`).pop().toLowerCase(),hf_repo:o}),onSuccess:()=>{s(``),l(``),e.invalidateQueries({queryKey:M.models})}}),ee=yt({mutationFn:e=>P.deleteModel(e),onSuccess:()=>e.invalidateQueries({queryKey:M.models})}),S=yt({mutationFn:async e=>{let t=Yt(f.gpuIds),n=Xt(f.maxModelLen),r={model_name:e.name,hf_repo:e.hf_repo,gpu_ids:t,max_model_len:n,pinned:f.pinned};f.backend&&(r.backend=f.backend),r.node_label=Zt(y);let i=(await P.listDeployments()).reduce((e,t)=>Math.max(e,t.id),0);try{return await P.loadModel(r)}catch(t){if(!en(t))throw t;return tn(e.id,i)}},onMutate:()=>h(``),onSuccess:()=>{d(null),p(Qt),e.invalidateQueries({queryKey:M.deployments})},onError:e=>h(e.message)});return(0,A.jsxs)(`div`,{className:`space-y-14`,children:[(0,A.jsxs)(`header`,{className:`flex items-baseline justify-between`,children:[(0,A.jsx)(`h2`,{className:`text-2xl font-light tracking-tightish caret`,children:`models`}),(0,A.jsxs)(`div`,{className:`label`,children:[(t.data??[]).length,` registered`]})]}),(0,A.jsxs)(`section`,{className:`space-y-5`,children:[(0,A.jsx)(`div`,{className:`label`,children:`register`}),(0,A.jsxs)(`div`,{className:`grid grid-cols-[1fr_220px_auto] gap-3 max-w-3xl`,children:[(0,A.jsx)(`input`,{className:`field font-mono`,placeholder:`huggingface repo (e.g. Qwen/Qwen3.6-35B-A3B-FP8)`,value:o,onChange:e=>s(e.target.value)}),(0,A.jsx)(`input`,{className:`field font-mono`,placeholder:`local alias (optional)`,value:c,onChange:e=>l(e.target.value)}),(0,A.jsx)(`button`,{className:`btn-primary`,disabled:!o.trim()||x.isPending,onClick:()=>x.mutate(),children:x.isPending?`registering...`:`register`})]}),x.error&&(0,A.jsx)(`div`,{className:`text-err text-[12px]`,children:x.error.message})]}),(0,A.jsxs)(`section`,{className:`space-y-4`,children:[(0,A.jsx)(`div`,{className:`label`,children:`registry`}),(0,A.jsxs)(`table`,{className:`ditable`,children:[(0,A.jsx)(`thead`,{children:(0,A.jsxs)(`tr`,{children:[(0,A.jsx)(`th`,{children:`name`}),(0,A.jsx)(`th`,{children:`huggingface`}),(0,A.jsx)(`th`,{children:`revision`}),(0,A.jsx)(`th`,{className:`text-right`})]})}),(0,A.jsxs)(`tbody`,{children:[(t.data??[]).length===0&&(0,A.jsx)(`tr`,{children:(0,A.jsx)(`td`,{colSpan:4,className:`!py-12 text-center text-mute`,children:`no models registered yet`})}),(t.data??[]).map(e=>{let t=u===e.name,i=S.isPending&&u===e.name;return(0,A.jsxs)(k.Fragment,{children:[(0,A.jsxs)(`tr`,{children:[(0,A.jsx)(`td`,{children:e.name}),(0,A.jsx)(`td`,{className:`text-dim`,children:e.hf_repo}),(0,A.jsx)(`td`,{className:`text-mute`,children:e.revision}),(0,A.jsxs)(`td`,{className:`text-right space-x-6`,children:[(0,A.jsx)(`button`,{className:`text-accent hover:opacity-70 transition-opacity`,onClick:()=>{t?d(null):(d(e.name),p(Qt),h(``))},children:t?`cancel`:`load`}),(0,A.jsx)(`button`,{className:`btn-link-danger`,onClick:()=>ee.mutate(e.name),children:`delete`})]})]}),t&&(0,A.jsx)(`tr`,{children:(0,A.jsx)(`td`,{colSpan:4,className:`!pt-2 !pb-6`,children:(0,A.jsxs)(`div`,{className:`bg-elev/40 border border-rule p-5 space-y-4`,children:[(0,A.jsxs)(`div`,{className:`grid grid-cols-2 md:grid-cols-5 gap-4`,children:[(0,A.jsxs)(`div`,{className:`space-y-1`,children:[(0,A.jsx)(`div`,{className:`label`,children:`backend`}),(0,A.jsxs)(`select`,{className:`field font-mono w-full text-[12px]`,value:f.backend,onChange:e=>p(t=>({...t,backend:e.target.value})),children:[(0,A.jsx)(`option`,{value:``,children:`auto (server picks)`}),(n.data??[]).map(e=>(0,A.jsx)(`option`,{value:e.name,children:e.name},e.name))]})]}),(0,A.jsxs)(`div`,{className:`space-y-1`,children:[(0,A.jsx)(`div`,{className:`label`,children:`node`}),(0,A.jsxs)(`select`,{className:`field font-mono w-full text-[12px]`,value:y,onChange:e=>p(t=>({...t,nodeLabel:e.target.value})),children:[!g&&(0,A.jsx)(`option`,{value:``,children:`leader (local)`}),v.map(e=>(0,A.jsxs)(`option`,{value:e.label,children:[e.label,` · `,e.gpu_count,` gpu`]},e.id)),g&&v.length===0&&(0,A.jsx)(`option`,{value:``,disabled:!0,children:`no ready agents`})]}),_.length===0&&(0,A.jsx)(`div`,{className:`text-mute text-[10px] tracking-wider`,children:`no agents enrolled`}),_.length>0&&v.length===0&&(0,A.jsx)(`div`,{className:`text-mute text-[10px] tracking-wider`,children:`no ready agents online`})]}),(0,A.jsxs)(`div`,{className:`space-y-1`,children:[(0,A.jsx)(`div`,{className:`label`,children:`max model len`}),(0,A.jsx)(`input`,{className:`field font-mono w-full text-[12px]`,value:f.maxModelLen,onChange:e=>p(t=>({...t,maxModelLen:e.target.value})),placeholder:`4096`})]}),(0,A.jsxs)(`div`,{className:`space-y-1`,children:[(0,A.jsx)(`div`,{className:`label`,children:`gpu ids`}),(0,A.jsx)(`input`,{className:`field font-mono w-full text-[12px]`,value:f.gpuIds,onChange:e=>p(t=>({...t,gpuIds:e.target.value})),placeholder:`0 or 0,1`}),f.nodeLabel&&f.nodeLabel!==`local`?(0,A.jsxs)(`div`,{className:`text-mute text-[10px] tracking-wider`,children:[`on agent `,f.nodeLabel]}):(r.data??[]).length>0&&(0,A.jsxs)(`div`,{className:`text-mute text-[10px] tracking-wider`,children:[`available: `,(r.data??[]).map(e=>e.index).join(`, `)]})]}),(0,A.jsxs)(`div`,{className:`space-y-1`,children:[(0,A.jsx)(`div`,{className:`label`,children:`options`}),(0,A.jsxs)(`label`,{className:`text-[12px] text-dim flex items-center gap-2 select-none cursor-pointer pt-1`,children:[(0,A.jsx)(`input`,{type:`checkbox`,className:`accent-accent`,checked:f.pinned,onChange:e=>p(t=>({...t,pinned:e.target.checked}))}),`pin (idle reaper skips it)`]})]})]}),m&&(0,A.jsx)(`div`,{className:`text-err text-[11px] tracking-wider`,children:m}),(0,A.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,A.jsx)(`button`,{className:`btn-primary`,disabled:i||b,onClick:()=>S.mutate(e),children:i?`launching...`:`deploy`}),(0,A.jsx)(`button`,{className:`btn`,disabled:i,onClick:()=>d(null),children:`cancel`})]})]})})})]},e.id)})]})]})]})]})}function rn(){let e=rt(),t=j({queryKey:M.adapters,queryFn:P.listAdapters,refetchInterval:5e3}),n=j({queryKey:M.models,queryFn:P.listModels}),[r,i]=(0,k.useState)(`hf`),[a,o]=(0,k.useState)(``),[s,c]=(0,k.useState)(``),[l,u]=(0,k.useState)(``),[d,f]=(0,k.useState)(``),p=n.data??[],m=yt({mutationFn:async()=>{let e=d||a.split(`/`).pop().toLowerCase();return await P.createAdapter({name:e,base_model_name:l,hf_repo:a}),P.downloadAdapter(e)},onSuccess:()=>{o(``),f(``),e.invalidateQueries({queryKey:M.adapters})}}),h=yt({mutationFn:()=>{let e=d||s.split(`/`).filter(Boolean).pop().toLowerCase();return P.addLocalAdapter({name:e,base_model_name:l,local_path:s})},onSuccess:()=>{c(``),f(``),e.invalidateQueries({queryKey:M.adapters})}}),g=yt({mutationFn:e=>P.deleteAdapter(e,!0),onSuccess:()=>e.invalidateQueries({queryKey:M.adapters})}),_=t.data??[];return(0,A.jsxs)(`div`,{className:`space-y-14`,children:[(0,A.jsxs)(`header`,{className:`flex items-baseline justify-between`,children:[(0,A.jsx)(`h2`,{className:`text-2xl font-light tracking-tightish caret`,children:`adapters`}),(0,A.jsxs)(`div`,{className:`label`,children:[_.length,` registered`]})]}),(0,A.jsxs)(`section`,{className:`space-y-5`,children:[(0,A.jsxs)(`div`,{className:`flex items-center gap-6`,children:[(0,A.jsx)(`div`,{className:`label`,children:`register`}),(0,A.jsxs)(`div`,{className:`flex items-center gap-3 text-[11px]`,children:[(0,A.jsx)(`button`,{onClick:()=>i(`hf`),className:r===`hf`?`text-ink`:`text-mute hover:text-dim`,children:`huggingface`}),(0,A.jsx)(`span`,{className:`text-mute`,children:`/`}),(0,A.jsx)(`button`,{onClick:()=>i(`local`),className:r===`local`?`text-ink`:`text-mute hover:text-dim`,children:`local path`})]})]}),(0,A.jsxs)(`div`,{className:`grid grid-cols-[1fr_200px_160px_auto] gap-3 max-w-4xl`,children:[r===`hf`?(0,A.jsx)(`input`,{className:`field font-mono`,placeholder:`hf repo (e.g. user/qwen3-lora)`,value:a,onChange:e=>o(e.target.value)}):(0,A.jsx)(`input`,{className:`field font-mono`,placeholder:`/abs/path/to/adapter-dir`,value:s,onChange:e=>c(e.target.value)}),(0,A.jsxs)(`select`,{className:`field font-mono`,value:l,onChange:e=>u(e.target.value),children:[(0,A.jsx)(`option`,{value:``,children:`base model`}),p.map(e=>(0,A.jsx)(`option`,{value:e.name,children:e.name},e.id))]}),(0,A.jsx)(`input`,{className:`field font-mono`,placeholder:`local name (opt)`,value:d,onChange:e=>f(e.target.value)}),r===`hf`?(0,A.jsx)(`button`,{className:`btn-primary`,disabled:!a.trim()||!l||m.isPending,onClick:()=>m.mutate(),children:m.isPending?`pulling...`:`pull`}):(0,A.jsx)(`button`,{className:`btn-primary`,disabled:!s.trim()||!l||h.isPending,onClick:()=>h.mutate(),children:h.isPending?`adding...`:`add`})]}),m.error&&(0,A.jsx)(`div`,{className:`text-err text-[12px]`,children:m.error.message}),h.error&&(0,A.jsx)(`div`,{className:`text-err text-[12px]`,children:h.error.message})]}),(0,A.jsxs)(`section`,{className:`space-y-4`,children:[(0,A.jsx)(`div`,{className:`label`,children:`registry`}),(0,A.jsxs)(`table`,{className:`ditable`,children:[(0,A.jsx)(`thead`,{children:(0,A.jsxs)(`tr`,{children:[(0,A.jsx)(`th`,{children:`name`}),(0,A.jsx)(`th`,{children:`base`}),(0,A.jsx)(`th`,{children:`source`}),(0,A.jsx)(`th`,{className:`text-right`,children:`rank`}),(0,A.jsx)(`th`,{className:`text-right`,children:`size`}),(0,A.jsx)(`th`,{children:`loaded into`}),(0,A.jsx)(`th`,{className:`text-right`})]})}),(0,A.jsxs)(`tbody`,{children:[_.length===0&&(0,A.jsx)(`tr`,{children:(0,A.jsx)(`td`,{colSpan:7,className:`!py-12 text-center text-mute`,children:`no adapters registered yet`})}),_.map(e=>(0,A.jsxs)(`tr`,{children:[(0,A.jsx)(`td`,{children:e.name}),(0,A.jsx)(`td`,{className:`text-dim`,children:e.base}),(0,A.jsx)(`td`,{className:`text-mute font-mono text-[11px]`,children:e.hf_repo.startsWith(`local:`)?`local`:e.hf_repo}),(0,A.jsx)(`td`,{className:`text-right tnum`,children:e.lora_rank??`-`}),(0,A.jsx)(`td`,{className:`text-right tnum`,children:e.size_mb==null?e.downloaded?`-`:`not pulled`:`${e.size_mb} MB`}),(0,A.jsx)(`td`,{className:`text-mute tnum`,children:(e.loaded_into??[]).length>0?(e.loaded_into??[]).join(`,`):`-`}),(0,A.jsx)(`td`,{className:`text-right`,children:(0,A.jsx)(`button`,{className:`btn-link-danger`,onClick:()=>g.mutate(e.name),children:`remove`})})]},e.id))]})]})]})]})}function an({profiles:e,models:t,backends:n,nodes:r,form:i,setForm:a,formError:o,actionError:s,createProfile:c,deployProfile:l,deleteProfile:u}){return(0,A.jsxs)(`section`,{className:`space-y-4`,children:[(0,A.jsxs)(`div`,{className:`flex items-baseline justify-between`,children:[(0,A.jsx)(`div`,{className:`label`,children:`profiles`}),(0,A.jsx)(`div`,{className:`text-mute text-[11px] tracking-wider`,children:`reusable launch definition`})]}),s&&(0,A.jsx)(`div`,{className:`text-err text-[11px] tracking-wider`,children:s}),(0,A.jsxs)(`div`,{className:`bg-elev/40 border border-rule p-5 space-y-4`,children:[(0,A.jsxs)(`div`,{className:`grid grid-cols-12 gap-3`,children:[(0,A.jsxs)(`div`,{className:`space-y-1 col-span-12 md:col-span-3`,children:[(0,A.jsx)(`div`,{className:`label`,children:`profile name`}),(0,A.jsx)(`input`,{className:`field font-mono w-full text-[12px]`,placeholder:`qwen-vllm`,value:i.name,onChange:e=>a(t=>({...t,name:e.target.value}))})]}),(0,A.jsxs)(`div`,{className:`space-y-1 col-span-12 md:col-span-3`,children:[(0,A.jsx)(`div`,{className:`label`,children:`model name`}),(0,A.jsx)(`input`,{className:`field font-mono w-full text-[12px]`,list:`profile-model-list`,placeholder:`qwen`,value:i.model_name,onChange:e=>{let n=e.target.value,r=t.find(e=>e.name===n);a(e=>({...e,model_name:n,hf_repo:r?r.hf_repo:e.hf_repo}))}}),(0,A.jsx)(`datalist`,{id:`profile-model-list`,children:t.map(e=>(0,A.jsx)(`option`,{value:e.name},e.id))})]}),(0,A.jsxs)(`div`,{className:`space-y-1 col-span-12 md:col-span-6`,children:[(0,A.jsx)(`div`,{className:`label`,children:`hf repo`}),(0,A.jsx)(`input`,{className:`field font-mono w-full text-[12px]`,placeholder:`Qwen/Qwen2.5-0.5B-Instruct`,value:i.hf_repo,onChange:e=>a(t=>({...t,hf_repo:e.target.value}))})]}),(0,A.jsxs)(`div`,{className:`space-y-1 col-span-6 md:col-span-2`,children:[(0,A.jsx)(`div`,{className:`label`,children:`backend`}),(0,A.jsxs)(`select`,{className:`field font-mono w-full text-[12px]`,value:i.backend,onChange:e=>a(t=>({...t,backend:e.target.value})),children:[(0,A.jsx)(`option`,{value:``,children:`auto`}),n.map(e=>(0,A.jsx)(`option`,{value:e.name,children:e.name},e.name))]})]}),(0,A.jsxs)(`div`,{className:`space-y-1 col-span-6 md:col-span-2`,children:[(0,A.jsx)(`div`,{className:`label`,children:`node`}),(0,A.jsxs)(`select`,{className:`field font-mono w-full text-[12px]`,value:i.node_label,onChange:e=>a(t=>({...t,node_label:e.target.value})),children:[(0,A.jsx)(`option`,{value:``,children:`leader (local)`}),r.filter(e=>e.label!==`local`&&e.status===`ready`).map(e=>(0,A.jsxs)(`option`,{value:e.label,children:[e.label,` · `,e.gpu_count,` gpu`]},e.id))]})]}),(0,A.jsxs)(`div`,{className:`space-y-1 col-span-6 md:col-span-2`,children:[(0,A.jsx)(`div`,{className:`label`,children:`gpu ids`}),(0,A.jsx)(`input`,{className:`field font-mono w-full text-[12px] tnum`,placeholder:`0 or 0,1`,value:i.gpu_ids,onChange:e=>a(t=>({...t,gpu_ids:e.target.value}))})]}),(0,A.jsxs)(`div`,{className:`space-y-1 col-span-6 md:col-span-3`,children:[(0,A.jsx)(`div`,{className:`label`,children:`max model len`}),(0,A.jsx)(`input`,{className:`field font-mono w-full text-[12px] tnum`,value:i.max_model_len,onChange:e=>a(t=>({...t,max_model_len:e.target.value}))})]}),(0,A.jsxs)(`div`,{className:`space-y-1 col-span-6 md:col-span-3 flex flex-col`,children:[(0,A.jsx)(`div`,{className:`label`,children:`options`}),(0,A.jsxs)(`label`,{className:`text-[12px] text-dim flex items-center gap-2 select-none cursor-pointer pt-2`,children:[(0,A.jsx)(`input`,{type:`checkbox`,className:`accent-accent`,checked:i.pinned,onChange:e=>a(t=>({...t,pinned:e.target.checked}))}),`pinned (skip idle reaper)`]})]})]}),o&&(0,A.jsx)(`div`,{className:`text-err text-[11px] tracking-wider`,children:o}),(0,A.jsx)(`div`,{className:`flex items-center gap-3`,children:(0,A.jsx)(`button`,{className:`btn-primary`,disabled:!i.name.trim()||!i.model_name.trim()||!i.hf_repo.trim()||c.isPending,onClick:()=>c.mutate(),children:c.isPending?`creating…`:`create profile`})})]}),(0,A.jsxs)(`table`,{className:`ditable`,children:[(0,A.jsx)(`thead`,{children:(0,A.jsxs)(`tr`,{children:[(0,A.jsx)(`th`,{children:`name`}),(0,A.jsx)(`th`,{children:`model`}),(0,A.jsx)(`th`,{children:`backend`}),(0,A.jsx)(`th`,{className:`text-right`,children:`gpus`}),(0,A.jsx)(`th`,{className:`text-right`,children:`ctx`}),(0,A.jsx)(`th`,{children:`pinned`}),(0,A.jsx)(`th`,{className:`text-right`,children:`actions`})]})}),(0,A.jsxs)(`tbody`,{children:[e.length===0&&(0,A.jsx)(`tr`,{children:(0,A.jsx)(`td`,{colSpan:7,className:`!py-12 text-center text-mute`,children:`no profiles yet. create one above to define how a model is launched.`})}),e.map(e=>{let t=l.isPending&&l.variables===e.name,n=u.isPending&&u.variables===e.name;return(0,A.jsxs)(`tr`,{children:[(0,A.jsx)(`td`,{children:e.name}),(0,A.jsx)(`td`,{className:`text-dim`,children:e.model_name}),(0,A.jsx)(`td`,{className:`text-dim`,children:e.backend}),(0,A.jsx)(`td`,{className:`text-right text-dim tnum`,children:e.gpu_ids.join(`,`)||`—`}),(0,A.jsx)(`td`,{className:`text-right tnum`,children:e.max_model_len}),(0,A.jsx)(`td`,{children:e.pinned?(0,A.jsx)(`span`,{className:`text-accent`,children:`yes`}):(0,A.jsx)(`span`,{className:`text-mute`,children:`no`})}),(0,A.jsxs)(`td`,{className:`text-right space-x-5 whitespace-nowrap`,children:[(0,A.jsx)(`button`,{className:`text-accent hover:opacity-70 transition-opacity disabled:opacity-40`,disabled:t,onClick:()=>l.mutate(e.name),children:t?`deploying…`:`deploy`}),(0,A.jsx)(`button`,{className:`btn-link-danger disabled:opacity-40`,disabled:n,onClick:()=>{confirm(`delete profile ${e.name}?`)&&u.mutate(e.name)},children:n?`deleting…`:`delete`})]})]},e.id)})]})]})]})}function on(e){return e===null?(0,A.jsx)(`span`,{className:`text-mute`,children:`—`}):e?(0,A.jsxs)(`span`,{children:[(0,A.jsx)(`span`,{className:`dot dot-ready`}),(0,A.jsx)(`span`,{className:`text-ok`,children:`ready`})]}):(0,A.jsxs)(`span`,{children:[(0,A.jsx)(`span`,{className:`dot dot-failed`}),(0,A.jsx)(`span`,{className:`text-err`,children:`not ready`})]})}function sn({result:e}){if(!e.matched)return(0,A.jsxs)(`div`,{className:`text-[12px] space-y-2`,children:[(0,A.jsxs)(`div`,{className:`text-err`,children:[`no enabled route matches `,(0,A.jsx)(`span`,{className:`font-mono`,children:e.requested})]}),e.candidates.length>0&&(0,A.jsxs)(`div`,{className:`text-mute text-[11px] tracking-wider`,children:[e.candidates.length,` disabled candidate`,e.candidates.length===1?``:`s`,` share this match_model:`,` `,e.candidates.map(e=>e.name).join(`, `)]}),(0,A.jsxs)(`div`,{className:`text-mute text-[11px] tracking-wider`,children:[`the proxy will fall back to treating `,(0,A.jsx)(`span`,{className:`font-mono`,children:e.requested}),` as a direct model name.`]})]});let t=e.matched;return(0,A.jsxs)(`div`,{className:`text-[12px] grid grid-cols-1 md:grid-cols-2 gap-x-8 gap-y-2`,children:[(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`span`,{className:`text-mute`,children:`matched route `}),(0,A.jsx)(`span`,{className:`text-ink`,children:t.name}),(0,A.jsxs)(`span`,{className:`text-mute`,children:[` (priority `,t.priority,`)`]})]}),(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`span`,{className:`text-mute`,children:`primary profile `}),(0,A.jsx)(`span`,{className:`text-dim`,children:t.profile_name}),(0,A.jsx)(`span`,{className:`text-mute`,children:` → `}),(0,A.jsx)(`span`,{className:`font-mono`,children:t.target_model_name}),(0,A.jsx)(`span`,{className:`ml-3`,children:on(e.primary_ready)})]}),(0,A.jsxs)(`div`,{className:`md:col-start-2`,children:[(0,A.jsx)(`span`,{className:`text-mute`,children:`fallback `}),t.fallback_profile_name?(0,A.jsxs)(A.Fragment,{children:[(0,A.jsx)(`span`,{className:`text-dim`,children:t.fallback_profile_name}),(0,A.jsx)(`span`,{className:`text-mute`,children:` → `}),(0,A.jsx)(`span`,{className:`font-mono`,children:t.fallback_model_name}),(0,A.jsx)(`span`,{className:`ml-3`,children:on(e.fallback_ready)})]}):(0,A.jsx)(`span`,{className:`text-mute`,children:`—`})]}),e.candidates.length>1&&(0,A.jsxs)(`div`,{className:`md:col-span-2 text-mute text-[11px] tracking-wider pt-1`,children:[e.candidates.length-1,` other route`,e.candidates.length-1==1?``:`s`,` share this match_model (lower priority or disabled):`,` `,e.candidates.filter(e=>e.id!==t.id).map(e=>e.name).join(`, `)]}),e.primary_ready===!1&&e.fallback_ready!==!0&&(0,A.jsx)(`div`,{className:`md:col-span-2 text-err text-[11px] tracking-wider pt-1`,children:`neither primary nor fallback has a ready deployment — a request would 503.`})]})}function cn({profiles:e,routes:t,hasProfiles:n,form:r,setForm:i,routeError:a,createRoute:o,deleteRoute:s,dryRunModel:c,setDryRunModel:l,dryRunResult:u,setDryRunResult:d,dryRun:f}){return(0,A.jsxs)(`section`,{className:`space-y-4`,children:[(0,A.jsxs)(`div`,{className:`flex items-baseline justify-between`,children:[(0,A.jsx)(`div`,{className:`label`,children:`routes`}),(0,A.jsx)(`div`,{className:`text-mute text-[11px] tracking-wider`,children:`public model name → profile · lower priority wins`})]}),n?(0,A.jsxs)(`div`,{className:`bg-elev/40 border border-rule p-5 space-y-4`,children:[(0,A.jsxs)(`div`,{className:`grid grid-cols-12 gap-3`,children:[(0,A.jsxs)(`div`,{className:`space-y-1 col-span-6 md:col-span-2`,children:[(0,A.jsx)(`div`,{className:`label`,children:`name`}),(0,A.jsx)(`input`,{className:`field font-mono w-full text-[12px]`,placeholder:`chat-default`,value:r.name,onChange:e=>i(t=>({...t,name:e.target.value}))})]}),(0,A.jsxs)(`div`,{className:`space-y-1 col-span-6 md:col-span-3`,children:[(0,A.jsx)(`div`,{className:`label`,children:`profile`}),(0,A.jsxs)(`select`,{className:`field font-mono w-full text-[12px]`,value:r.profile_name,onChange:e=>i(t=>({...t,profile_name:e.target.value})),children:[(0,A.jsx)(`option`,{value:``,children:`choose…`}),e.map(e=>(0,A.jsx)(`option`,{value:e.name,children:e.name},e.id))]})]}),(0,A.jsxs)(`div`,{className:`space-y-1 col-span-6 md:col-span-3`,children:[(0,A.jsx)(`div`,{className:`label`,children:`fallback (optional)`}),(0,A.jsxs)(`select`,{className:`field font-mono w-full text-[12px]`,value:r.fallback_profile_name,onChange:e=>i(t=>({...t,fallback_profile_name:e.target.value})),children:[(0,A.jsx)(`option`,{value:``,children:`none`}),e.filter(e=>e.name!==r.profile_name).map(e=>(0,A.jsx)(`option`,{value:e.name,children:e.name},e.id))]})]}),(0,A.jsxs)(`div`,{className:`space-y-1 col-span-6 md:col-span-3`,children:[(0,A.jsx)(`div`,{className:`label`,children:`match model (exact)`}),(0,A.jsx)(`input`,{className:`field font-mono w-full text-[12px]`,placeholder:`chat`,value:r.match_model,onChange:e=>i(t=>({...t,match_model:e.target.value}))})]}),(0,A.jsxs)(`div`,{className:`space-y-1 col-span-12 md:col-span-1`,children:[(0,A.jsx)(`div`,{className:`label`,children:`pri`}),(0,A.jsx)(`input`,{className:`field font-mono w-full text-[12px] tnum text-right`,value:r.priority,onChange:e=>i(t=>({...t,priority:e.target.value}))})]})]}),a&&(0,A.jsx)(`div`,{className:`text-err text-[11px] tracking-wider`,children:a}),(0,A.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,A.jsx)(`button`,{className:`btn-primary`,disabled:!r.name.trim()||!r.match_model.trim()||!r.profile_name||o.isPending,onClick:()=>o.mutate(),children:o.isPending?`creating…`:`create route`}),(0,A.jsxs)(`span`,{className:`label`,children:[`callable as `,(0,A.jsxs)(`span`,{className:`text-dim`,children:[`model: `,r.match_model||``]})]})]})]}):(0,A.jsx)(`div`,{className:`border border-rule bg-elev/40 px-5 py-12 text-center text-mute text-[12px]`,children:`create a profile above first — routes point at profiles.`}),n&&t.length>0&&(0,A.jsxs)(`div`,{className:`bg-elev/40 border border-rule px-5 py-4 space-y-3`,children:[(0,A.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,A.jsx)(`div`,{className:`label whitespace-nowrap`,children:`dry-run`}),(0,A.jsx)(`input`,{className:`field font-mono w-full text-[12px]`,placeholder:`model name to test (e.g. chat)`,value:c,onChange:e=>l(e.target.value),onKeyDown:e=>{e.key===`Enter`&&c.trim()&&f.mutate(c.trim())}}),(0,A.jsx)(`button`,{className:`btn`,disabled:!c.trim()||f.isPending,onClick:()=>f.mutate(c.trim()),children:f.isPending?`testing…`:`test`}),u&&(0,A.jsx)(`button`,{className:`text-mute text-[11px] tracking-wider hover:text-dim transition-colors whitespace-nowrap`,onClick:()=>{d(null),l(``)},children:`clear`})]}),u&&(0,A.jsx)(sn,{result:u})]}),(0,A.jsxs)(`table`,{className:`ditable`,children:[(0,A.jsx)(`thead`,{children:(0,A.jsxs)(`tr`,{children:[(0,A.jsx)(`th`,{className:`w-12`,children:`pri`}),(0,A.jsx)(`th`,{children:`name`}),(0,A.jsx)(`th`,{children:`match model`}),(0,A.jsx)(`th`,{children:`profile`}),(0,A.jsx)(`th`,{children:`fallback`}),(0,A.jsx)(`th`,{children:`enabled`}),(0,A.jsx)(`th`,{className:`text-right`,children:`actions`})]})}),(0,A.jsxs)(`tbody`,{children:[t.length===0&&(0,A.jsx)(`tr`,{children:(0,A.jsx)(`td`,{colSpan:7,className:`!py-12 text-center text-mute`,children:n?`no routes. create one above to expose a public model name.`:`no routes — and no profiles to route at yet.`})}),t.slice().sort((e,t)=>e.priority-t.priority).map(e=>(0,A.jsxs)(`tr`,{children:[(0,A.jsx)(`td`,{className:`text-mute tnum`,children:e.priority}),(0,A.jsx)(`td`,{children:e.name}),(0,A.jsx)(`td`,{className:`font-mono text-[12px]`,children:e.match_model}),(0,A.jsx)(`td`,{className:`text-dim`,children:e.profile_name}),(0,A.jsx)(`td`,{className:`text-mute`,children:e.fallback_profile_name??`—`}),(0,A.jsxs)(`td`,{children:[(0,A.jsx)(`span`,{className:`dot ${e.enabled?`dot-ready`:`dot-stopped`}`}),(0,A.jsx)(`span`,{className:`text-dim`,children:e.enabled?`on`:`off`})]}),(0,A.jsx)(`td`,{className:`text-right`,children:(0,A.jsx)(`button`,{className:`btn-link-danger disabled:opacity-40`,disabled:s.isPending,onClick:()=>{confirm(`delete route ${e.name}?`)&&s.mutate(e.name)},children:`delete`})})]},e.id))]})]})]})}var ln={name:``,model_name:``,hf_repo:``,backend:``,gpu_ids:`0`,max_model_len:`8192`,pinned:!1,node_label:``},un={name:``,match_model:``,profile_name:``,fallback_profile_name:``,priority:`100`};function dn({mode:e=`both`}){let t=rt(),n=j({queryKey:M.profiles,queryFn:P.listProfiles}),r=j({queryKey:M.routes,queryFn:P.listRoutes}),i=j({queryKey:M.models,queryFn:P.listModels}),a=j({queryKey:M.backends,queryFn:P.listBackends}),o=j({queryKey:M.nodes,queryFn:P.listNodes}),s=n.data??[],c=r.data??[],l=s.length>0,[u,d]=(0,k.useState)(ln),[f,p]=(0,k.useState)(``),[m,h]=(0,k.useState)(``),g=yt({mutationFn:()=>{let e=Yt(u.gpu_ids),t=Xt(u.max_model_len);return P.createProfile({name:u.name.trim(),model_name:u.model_name.trim(),hf_repo:u.hf_repo.trim(),backend:u.backend||void 0,gpu_ids:e,max_model_len:t,pinned:u.pinned,node_label:Zt(u.node_label)})},onMutate:()=>p(``),onError:e=>p(e.message),onSuccess:()=>{d(ln),t.invalidateQueries({queryKey:M.profiles})}}),_=yt({mutationFn:e=>P.deployProfile(e),onMutate:()=>h(``),onError:e=>h(e.message),onSuccess:()=>t.invalidateQueries({queryKey:M.deployments})}),v=yt({mutationFn:e=>P.deleteProfile(e),onMutate:()=>h(``),onError:e=>h(e.message),onSuccess:()=>{t.invalidateQueries({queryKey:M.profiles}),t.invalidateQueries({queryKey:M.routes})}}),[y,b]=(0,k.useState)(un),[x,ee]=(0,k.useState)(``),S=yt({mutationFn:()=>{let e=Number(y.priority);if(!Number.isInteger(e))throw Error(`priority must be an integer`);return P.createRoute({name:y.name.trim(),match_model:y.match_model.trim(),profile_name:y.profile_name,fallback_profile_name:y.fallback_profile_name||null,priority:e})},onMutate:()=>ee(``),onError:e=>ee(e.message),onSuccess:()=>{b(un),t.invalidateQueries({queryKey:M.routes})}}),C=yt({mutationFn:e=>P.deleteRoute(e),onSuccess:()=>t.invalidateQueries({queryKey:M.routes})}),[te,ne]=(0,k.useState)(``),[re,w]=(0,k.useState)(null),ie=yt({mutationFn:e=>P.dryRunRoute(e),onSuccess:e=>w(e),onError:()=>w(null)}),ae=e===`both`||e===`profiles`,oe=e===`both`||e===`routes`,se=e===`routes`?`routes`:e===`profiles`?`profiles`:`services`,ce=e===`routes`?`${c.length} routes`:e===`profiles`?`${s.length} profiles`:`${s.length} profiles / ${c.length} routes`;return(0,A.jsxs)(`div`,{className:`space-y-14`,children:[(0,A.jsxs)(`header`,{className:`flex items-baseline justify-between`,children:[(0,A.jsx)(`h2`,{className:`text-2xl font-light tracking-tightish caret`,children:se}),(0,A.jsx)(`div`,{className:`label`,children:ce})]}),ae&&(0,A.jsx)(an,{profiles:s,models:i.data??[],backends:a.data??[],nodes:o.data?.nodes??[],form:u,setForm:d,formError:f,actionError:m,createProfile:g,deployProfile:_,deleteProfile:v}),oe&&(0,A.jsx)(cn,{profiles:s,routes:c,hasProfiles:l,form:y,setForm:b,routeError:x,createRoute:S,deleteRoute:C,dryRunModel:te,setDryRunModel:ne,dryRunResult:re,setDryRunResult:w,dryRun:ie})]})}function fn(){return(0,A.jsx)(dn,{mode:`routes`})}function pn(){return(0,A.jsx)(dn,{mode:`profiles`})}var mn={enabled:!1,preloads_attempted:0,preloads_succeeded:0,preloads_skipped_already_warm:0,preloads_skipped_no_deployment:0,base_prewarms_attempted:0,base_prewarms_succeeded:0,base_prewarms_skipped_no_plan:0};function hn({label:e,value:t,dim:n=!1}){return(0,A.jsxs)(`div`,{className:`space-y-1`,children:[(0,A.jsx)(`div`,{className:`text-mute text-[11px]`,children:e}),(0,A.jsx)(`div`,{className:`tnum text-lg font-light ${n?`text-dim`:``}`,children:t??0})]})}function gn(){let e=j({queryKey:M.predictorCandidates,queryFn:P.predictorCandidates,refetchInterval:5e3}),t=j({queryKey:M.predictorStats,queryFn:P.predictorStats,refetchInterval:5e3}).data??mn,n=e.data??[],r=t.enabled!==!1,i=t.preloads_attempted>0?Math.round(100*(t.preloads_succeeded/t.preloads_attempted)):null,a=t.base_prewarms_attempted>0?Math.round(100*(t.base_prewarms_succeeded/t.base_prewarms_attempted)):null;return(0,A.jsxs)(`div`,{className:`space-y-14`,children:[(0,A.jsxs)(`header`,{className:`flex items-baseline justify-between`,children:[(0,A.jsx)(`h2`,{className:`text-2xl font-light tracking-tightish caret`,children:`predictor`}),(0,A.jsx)(`div`,{className:`label`,children:r?(0,A.jsxs)(A.Fragment,{children:[`tick `,t.tick_interval_s,`s / adapter `,t.max_prewarm_per_tick,`/tick / base `,t.max_base_prewarm_per_tick??0,`/tick`]}):`disabled`})]}),(0,A.jsxs)(`section`,{className:`space-y-5`,children:[(0,A.jsx)(`div`,{className:`label`,children:`adapter pre-warming`}),(0,A.jsxs)(`div`,{className:`grid grid-cols-5 gap-8 max-w-4xl`,children:[(0,A.jsx)(hn,{label:`attempted`,value:t.preloads_attempted}),(0,A.jsx)(hn,{label:`succeeded`,value:t.preloads_succeeded}),(0,A.jsx)(hn,{label:`success rate`,value:i==null?`-`:`${i}%`,dim:!0}),(0,A.jsx)(hn,{label:`skipped (warm)`,value:t.preloads_skipped_already_warm,dim:!0}),(0,A.jsx)(hn,{label:`skipped (no dep)`,value:t.preloads_skipped_no_deployment,dim:!0})]})]}),(0,A.jsxs)(`section`,{className:`space-y-5`,children:[(0,A.jsx)(`div`,{className:`label`,children:`base pre-warming`}),(0,A.jsxs)(`div`,{className:`grid grid-cols-5 gap-8 max-w-4xl`,children:[(0,A.jsx)(hn,{label:`attempted`,value:t.base_prewarms_attempted}),(0,A.jsx)(hn,{label:`succeeded`,value:t.base_prewarms_succeeded}),(0,A.jsx)(hn,{label:`success rate`,value:a==null?`-`:`${a}%`,dim:!0}),(0,A.jsx)(hn,{label:`skipped (no plan)`,value:t.base_prewarms_skipped_no_plan,dim:!0}),(0,A.jsx)(hn,{label:`-`,value:`-`,dim:!0})]})]}),(0,A.jsxs)(`section`,{className:`space-y-4`,children:[(0,A.jsx)(`div`,{className:`label`,children:`current candidates`}),(0,A.jsxs)(`table`,{className:`ditable`,children:[(0,A.jsx)(`thead`,{children:(0,A.jsxs)(`tr`,{children:[(0,A.jsx)(`th`,{children:`model`}),(0,A.jsx)(`th`,{className:`text-right`,children:`score`}),(0,A.jsx)(`th`,{children:`reason`})]})}),(0,A.jsxs)(`tbody`,{children:[n.length===0&&(0,A.jsx)(`tr`,{children:(0,A.jsx)(`td`,{colSpan:3,className:`!py-12 text-center text-mute`,children:`no candidates. rules have nothing to suggest right now`})}),n.map((e,t)=>(0,A.jsxs)(`tr`,{children:[(0,A.jsx)(`td`,{className:`font-mono`,children:e.adapter_name?`${e.base_name}:${e.adapter_name}`:e.base_name}),(0,A.jsx)(`td`,{className:`text-right tnum`,children:e.score.toFixed(3)}),(0,A.jsx)(`td`,{className:`text-mute text-[11px]`,children:e.reason})]},`${e.base_name}:${e.adapter_name}:${t}`))]})]})]})]})}var _n={reasoning:``,answer:``,error:``,stats:{ttftMs:null,totalMs:null,tokens:0,tps:null},pending:!1};async function vn(e,t,n,r,i){let a=performance.now(),o=null,s=0;try{let c={"Content-Type":`application/json`},l=St();l&&(c.Authorization=`Bearer ${l}`);let u=await fetch(`/v1/chat/completions`,{method:`POST`,headers:c,signal:r,body:JSON.stringify({model:e,messages:[{role:`user`,content:t}],stream:!0,max_tokens:n})});if(!u.ok){let e=await u.text();i(t=>({...t,error:`${u.status}: ${e.slice(0,500)}`}));return}if(!u.body)return;let d=u.body.getReader(),f=new TextDecoder,p=``;for(;;){let{done:e,value:t}=await d.read();if(e)break;p+=f.decode(t,{stream:!0});let n=p.split(` `);p=n.pop();for(let e of n){if(!e.startsWith(`data:`))continue;let t=e.slice(5).trim();if(t!==`[DONE]`)try{let e=JSON.parse(t).choices?.[0]?.delta??{},n=e.reasoning??e.reasoning_content??``,r=e.content??``;if((n||r)&&o===null){o=performance.now();let e=Math.round(o-a);i(t=>({...t,stats:{...t.stats,ttftMs:e}}))}n&&(s+=1,i(e=>({...e,reasoning:e.reasoning+n}))),r&&(s+=1,i(e=>({...e,answer:e.answer+r})))}catch{}}}}catch(e){if(!(e instanceof DOMException&&e.name===`AbortError`)){let t=e instanceof Error?e.message:String(e);i(e=>({...e,error:`error: ${t}`}))}}finally{let e=performance.now();i(t=>({...t,stats:{...t.stats,totalMs:Math.round(e-a),tokens:s,tps:s&&e>a?Math.round(s/(e-a)*1e4)/10:null}}))}}function yn({value:e,onChange:t,models:n,routes:r}){return(0,A.jsxs)(`select`,{className:`field w-full font-mono`,value:e,onChange:e=>t(e.target.value),children:[(0,A.jsx)(`option`,{value:``,children:`choose model or route`}),r.length>0&&(0,A.jsx)(`optgroup`,{label:`routes`,children:r.map(e=>(0,A.jsxs)(`option`,{value:e.match_model,children:[e.match_model,` → `,e.profile_name]},`r-${e.id}`))}),n.length>0&&(0,A.jsx)(`optgroup`,{label:`models`,children:n.map(e=>(0,A.jsx)(`option`,{value:e.name,children:e.name},`m-${e.id}`))})]})}function bn({stats:e}){return e.ttftMs===null&&e.totalMs===null?null:(0,A.jsxs)(`div`,{className:`flex gap-5 text-mute text-[11px] tnum`,children:[e.ttftMs!==null&&(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`span`,{className:`text-dim`,children:`ttft`}),` `,e.ttftMs,`ms`]}),e.totalMs!==null&&(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`span`,{className:`text-dim`,children:`total`}),` `,e.totalMs,`ms`]}),e.tps!==null&&(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`span`,{className:`text-dim`,children:`tok/s`}),` `,e.tps]}),e.tokens>0&&(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`span`,{className:`text-dim`,children:`tokens`}),` `,e.tokens]})]})}function xn({pane:e,showThinking:t,onToggleThinking:n}){return e.error?(0,A.jsx)(`pre`,{className:`text-err text-[12px] whitespace-pre-wrap font-mono border border-err/30 px-3 py-2`,children:e.error}):(0,A.jsxs)(`div`,{className:`space-y-3`,children:[e.reasoning&&(0,A.jsxs)(`details`,{open:t,onToggle:e=>n(e.target.open),className:`border border-rule`,children:[(0,A.jsxs)(`summary`,{className:`cursor-pointer px-4 py-3 text-dim text-[11px] tracking-wider hover:text-ink transition-colors select-none flex items-center gap-2`,children:[(0,A.jsx)(`span`,{className:`dot dot-loading`,style:{width:5,height:5}}),`thinking`,(0,A.jsxs)(`span`,{className:`text-mute tnum`,children:[e.reasoning.length.toLocaleString(),`c`]})]}),(0,A.jsx)(`pre`,{className:`px-4 pb-4 text-[12px] text-dim whitespace-pre-wrap font-mono leading-relaxed`,children:e.reasoning})]}),(e.answer||e.pending&&!e.reasoning)&&(0,A.jsx)(`pre`,{className:`text-[13px] whitespace-pre-wrap font-mono leading-relaxed border-l border-accent pl-4 min-h-[2.5rem]`,children:e.answer||(e.pending?(0,A.jsx)(`span`,{className:`text-mute`,children:`waiting for tokens…`}):``)}),!e.answer&&!e.reasoning&&!e.pending&&(0,A.jsx)(`div`,{className:`text-mute text-[11px] tracking-wider`,children:`no output yet`})]})}function Sn(){let e=j({queryKey:M.models,queryFn:P.listModels}),t=j({queryKey:M.routes,queryFn:P.listRoutes}),[n,r]=(0,k.useState)(!1),[i,a]=(0,k.useState)({model:``,..._n}),[o,s]=(0,k.useState)({model:``,..._n}),[c,l]=(0,k.useState)(``),[u,d]=(0,k.useState)(4096),[f,p]=(0,k.useState)(!0),[m,h]=(0,k.useState)(!0),g=(0,k.useRef)(null),_=(0,k.useMemo)(()=>e.data??[],[e.data]),v=(0,k.useMemo)(()=>(t.data??[]).filter(e=>e.enabled),[t.data]),y=!!i.model&&!!c.trim(),b=i.pending||o.pending;async function x(){if(!y||n&&!o.model)return;g.current?.abort();let e=new AbortController;g.current=e,a(e=>({...e,..._n,model:e.model,pending:!0})),n&&s(e=>({...e,..._n,model:e.model,pending:!0}));let t=[vn(i.model,c,u,e.signal,a).finally(()=>a(e=>({...e,pending:!1})))];n&&t.push(vn(o.model,c,u,e.signal,s).finally(()=>s(e=>({...e,pending:!1})))),await Promise.allSettled(t)}function ee(){g.current?.abort()}return(0,A.jsxs)(`div`,{className:`space-y-10`,children:[(0,A.jsxs)(`header`,{className:`flex items-baseline justify-between`,children:[(0,A.jsx)(`h2`,{className:`text-2xl font-light tracking-tightish caret`,children:`playground`}),(0,A.jsxs)(`div`,{className:`flex items-center gap-6`,children:[(0,A.jsxs)(`div`,{className:`flex items-center gap-2 text-[11px] tracking-wider`,children:[(0,A.jsx)(`button`,{className:`transition-colors `+(n?`text-mute hover:text-dim`:`text-ink`),onClick:()=>r(!1),children:`single`}),(0,A.jsx)(`span`,{className:`text-mute`,children:`/`}),(0,A.jsx)(`button`,{className:`transition-colors `+(n?`text-ink`:`text-mute hover:text-dim`),onClick:()=>r(!0),children:`compare`})]}),(0,A.jsx)(`div`,{className:`label`,children:`openai-compatible`})]})]}),(0,A.jsxs)(`section`,{className:`space-y-6`,children:[(0,A.jsxs)(`div`,{className:`grid gap-6 `+(n?`grid-cols-1 md:grid-cols-2`:`grid-cols-1`),children:[(0,A.jsxs)(`div`,{className:`space-y-2`,children:[(0,A.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,A.jsx)(`div`,{className:`label`,children:n?`a`:`model`}),(0,A.jsx)(bn,{stats:i.stats})]}),(0,A.jsx)(yn,{value:i.model,onChange:e=>a(t=>({...t,model:e})),models:_,routes:v})]}),n&&(0,A.jsxs)(`div`,{className:`space-y-2`,children:[(0,A.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,A.jsx)(`div`,{className:`label`,children:`b`}),(0,A.jsx)(bn,{stats:o.stats})]}),(0,A.jsx)(yn,{value:o.model,onChange:e=>s(t=>({...t,model:e})),models:_,routes:v})]})]}),(0,A.jsxs)(`div`,{className:`grid grid-cols-[1fr_180px] gap-4`,children:[(0,A.jsxs)(`div`,{className:`space-y-2`,children:[(0,A.jsx)(`div`,{className:`label`,children:`prompt`}),(0,A.jsx)(`textarea`,{className:`field w-full font-mono text-[13px]`,style:{minHeight:`8rem`},placeholder:`ask something`,value:c,onChange:e=>l(e.target.value),onKeyDown:e=>{e.key===`Enter`&&(e.metaKey||e.ctrlKey)&&!b&&x()}})]}),(0,A.jsxs)(`div`,{className:`space-y-2`,children:[(0,A.jsx)(`div`,{className:`label`,children:`max tokens`}),(0,A.jsx)(`input`,{type:`number`,className:`field w-full font-mono tnum`,value:u,min:32,max:32768,step:256,onChange:e=>d(Number(e.target.value)||4096)})]})]}),(0,A.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,A.jsx)(`button`,{className:`btn-primary`,disabled:!y||n&&!o.model||b,onClick:x,children:b?`streaming…`:n?`send both`:`send`}),b&&(0,A.jsx)(`button`,{className:`btn`,onClick:ee,children:`stop`}),(0,A.jsx)(`span`,{className:`label`,children:`Ctrl+Enter`})]}),(0,A.jsxs)(`div`,{className:`grid gap-8 `+(n?`grid-cols-1 md:grid-cols-2`:`grid-cols-1`),children:[(0,A.jsxs)(`div`,{className:`space-y-3`,children:[n&&(0,A.jsxs)(`div`,{className:`label flex items-center justify-between`,children:[(0,A.jsxs)(`span`,{children:[`a — `,i.model||`—`]}),i.pending&&(0,A.jsx)(`span`,{className:`text-accent tracking-wider`,children:`streaming`})]}),(0,A.jsx)(xn,{pane:i,showThinking:f,onToggleThinking:p})]}),n&&(0,A.jsxs)(`div`,{className:`space-y-3`,children:[(0,A.jsxs)(`div`,{className:`label flex items-center justify-between`,children:[(0,A.jsxs)(`span`,{children:[`b — `,o.model||`—`]}),o.pending&&(0,A.jsx)(`span`,{className:`text-accent tracking-wider`,children:`streaming`})]}),(0,A.jsx)(xn,{pane:o,showThinking:m,onToggleThinking:h})]})]})]})]})}function Cn(e){return e<1e3?String(e):e<1e6?`${(e/1e3).toFixed(1)}k`:`${(e/1e6).toFixed(1)}m`}function wn({values:e,width:t=80,height:n=18,color:r=`currentColor`}){if(e.length===0||e.every(e=>e===0))return(0,A.jsx)(`span`,{className:`text-mute text-[10px] tracking-wider`,children:`no traffic`});let i=Math.max(...e,1),a=t/e.length;return(0,A.jsx)(`svg`,{width:t,height:n,className:`overflow-visible align-middle`,children:e.map((e,t)=>{let o=i?e/i*n:0;return(0,A.jsx)(`rect`,{x:t*a,y:n-o,width:Math.max(a-1,1),height:Math.max(o,1),fill:r,opacity:e===0?.15:1},t)})})}function Tn({values:e,height:t=56,accent:n=!1}){if(e.length===0)return null;let r=Math.max(...e,1),i=100/e.length;return(0,A.jsx)(`svg`,{viewBox:`0 0 100 ${t}`,preserveAspectRatio:`none`,width:`100%`,height:t,className:n?`text-accent`:`text-dim`,children:e.map((e,n)=>{let a=r?e/r*t:0;return(0,A.jsx)(`rect`,{x:n*i,y:t-a,width:Math.max(i-.3,.3),height:Math.max(a,.5),fill:`currentColor`,opacity:e===0?.15:1},n)})})}function En({keyId:e}){let t=j({queryKey:M.keyUsage(e,`detail`),queryFn:()=>P.keyUsage(e,86400,3600),staleTime:3e4});if(t.isLoading)return(0,A.jsx)(`div`,{className:`text-mute text-[11px] tracking-wider`,children:`loading…`});if(t.error||!t.data)return(0,A.jsx)(`div`,{className:`text-err text-[11px] tracking-wider`,children:t.error?.message??`no data`});let n=t.data.buckets,r=n.map(e=>e.requests),i=n.map(e=>e.tokens_in+e.tokens_out),a=r.reduce((e,t)=>e+t,0),o=i.reduce((e,t)=>e+t,0);return(0,A.jsxs)(`div`,{className:`grid grid-cols-1 md:grid-cols-2 gap-6`,children:[(0,A.jsxs)(`div`,{className:`space-y-2`,children:[(0,A.jsxs)(`div`,{className:`flex items-baseline justify-between`,children:[(0,A.jsx)(`div`,{className:`label`,children:`requests · 24h`}),(0,A.jsxs)(`div`,{className:`text-mute text-[11px] tnum`,children:[a.toLocaleString(),` total`]})]}),(0,A.jsx)(Tn,{values:r,accent:!0}),(0,A.jsxs)(`div`,{className:`flex justify-between text-mute text-[10px] tracking-wider`,children:[(0,A.jsx)(`span`,{children:`24h ago`}),(0,A.jsx)(`span`,{children:`now`})]})]}),(0,A.jsxs)(`div`,{className:`space-y-2`,children:[(0,A.jsxs)(`div`,{className:`flex items-baseline justify-between`,children:[(0,A.jsx)(`div`,{className:`label`,children:`tokens (in+out) · 24h`}),(0,A.jsxs)(`div`,{className:`text-mute text-[11px] tnum`,children:[Cn(o),` total`]})]}),(0,A.jsx)(Tn,{values:i}),(0,A.jsxs)(`div`,{className:`flex justify-between text-mute text-[10px] tracking-wider`,children:[(0,A.jsx)(`span`,{children:`24h ago`}),(0,A.jsx)(`span`,{children:`now`})]})]})]})}function Dn(){let e=rt(),t=j({queryKey:M.keys,queryFn:P.listKeys}),[n,r]=(0,k.useState)(``),[i,a]=(0,k.useState)(`standard`),[o,s]=(0,k.useState)(null),[c,l]=(0,k.useState)(!1),[u,d]=(0,k.useState)(!1),[f,p]=(0,k.useState)(null),m=yt({mutationFn:()=>P.createKey({name:n,tier:i}),onSuccess:t=>{s(t.secret),l(!1),r(``),e.invalidateQueries({queryKey:M.keys})}}),h=yt({mutationFn:e=>P.revokeKey(e),onSuccess:()=>e.invalidateQueries({queryKey:M.keys})});async function g(){if(o)try{await navigator.clipboard.writeText(o),l(!0),setTimeout(()=>l(!1),1600)}catch{}}let _=t.data??[],v=_.filter(e=>!e.revoked).length,y=_.length-v,b=u?_:_.filter(e=>!e.revoked),x=_t({queries:b.filter(e=>!e.revoked).map(e=>({queryKey:M.keyUsage(e.id,`spark`),queryFn:()=>P.keyUsage(e.id,86400,3600),staleTime:6e4,refetchInterval:6e4}))}),ee=new Map;return b.filter(e=>!e.revoked).forEach((e,t)=>{let n=x[t]?.data;n&&ee.set(e.id,n)}),(0,A.jsxs)(`div`,{className:`space-y-14`,children:[(0,A.jsxs)(`header`,{className:`flex items-baseline justify-between`,children:[(0,A.jsx)(`h2`,{className:`text-2xl font-light tracking-tightish caret`,children:`api keys`}),(0,A.jsxs)(`div`,{className:`label`,children:[v,` active`]})]}),(0,A.jsxs)(`section`,{className:`space-y-5`,children:[(0,A.jsx)(`div`,{className:`label`,children:`issue a key`}),(0,A.jsxs)(`div`,{className:`grid grid-cols-[1fr_180px_auto] gap-3 max-w-3xl`,children:[(0,A.jsx)(`input`,{className:`field font-mono`,placeholder:`label (e.g. alice / web / cron)`,value:n,onChange:e=>r(e.target.value)}),(0,A.jsxs)(`select`,{className:`field font-mono`,value:i,onChange:e=>a(e.target.value),children:[(0,A.jsx)(`option`,{value:`admin`,children:`admin`}),(0,A.jsx)(`option`,{value:`standard`,children:`standard`}),(0,A.jsx)(`option`,{value:`trial`,children:`trial`})]}),(0,A.jsx)(`button`,{className:`btn-primary`,disabled:!n.trim()||m.isPending,onClick:()=>m.mutate(),children:m.isPending?`issuing...`:`issue`})]}),o&&(0,A.jsxs)(`div`,{className:`border border-accent/40 bg-[var(--accent-soft)] px-4 py-3 max-w-3xl`,children:[(0,A.jsxs)(`div`,{className:`flex items-center justify-between mb-2`,children:[(0,A.jsx)(`div`,{className:`label text-accent`,children:`save this; it won't be shown again`}),(0,A.jsxs)(`div`,{className:`flex items-center gap-4`,children:[(0,A.jsx)(`button`,{onClick:g,className:`text-accent text-[11px] tracking-wider hover:opacity-70 transition-opacity`,children:c?`copied ✓`:`copy`}),(0,A.jsx)(`button`,{onClick:()=>s(null),className:`text-mute text-[11px] tracking-wider hover:text-dim transition-colors`,"aria-label":`dismiss`,children:`dismiss`})]})]}),(0,A.jsx)(`code`,{className:`font-mono text-[13px] break-all select-all`,children:o})]})]}),(0,A.jsxs)(`section`,{className:`space-y-4`,children:[(0,A.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,A.jsx)(`div`,{className:`label`,children:`issued keys`}),y>0&&(0,A.jsxs)(`label`,{className:`text-mute text-[11px] tracking-wider select-none cursor-pointer hover:text-dim transition-colors`,children:[(0,A.jsx)(`input`,{type:`checkbox`,className:`mr-2 accent-accent align-middle`,checked:u,onChange:e=>d(e.target.checked)}),`show revoked `,!u&&(0,A.jsxs)(`span`,{className:`text-accent`,children:[`(`,y,`)`]})]})]}),(0,A.jsxs)(`table`,{className:`ditable`,children:[(0,A.jsx)(`thead`,{children:(0,A.jsxs)(`tr`,{children:[(0,A.jsx)(`th`,{children:`#`}),(0,A.jsx)(`th`,{children:`label`}),(0,A.jsx)(`th`,{children:`tier`}),(0,A.jsx)(`th`,{children:`prefix`}),(0,A.jsx)(`th`,{children:`status`}),(0,A.jsx)(`th`,{children:`24h activity`}),(0,A.jsx)(`th`,{className:`text-right`})]})}),(0,A.jsxs)(`tbody`,{children:[b.length===0&&(0,A.jsx)(`tr`,{children:(0,A.jsx)(`td`,{colSpan:7,className:`!py-12 text-center text-mute`,children:_.length===0?`no keys yet`:`no active keys`})}),b.map(e=>{let t=ee.get(e.id)?.buckets.map(e=>e.requests)??[],n=t.reduce((e,t)=>e+t,0),r=f===e.id;return(0,A.jsxs)(k.Fragment,{children:[(0,A.jsxs)(`tr`,{className:e.revoked?``:`cursor-pointer`,onClick:()=>!e.revoked&&p(r?null:e.id),children:[(0,A.jsx)(`td`,{className:`text-mute tnum`,children:e.id}),(0,A.jsx)(`td`,{children:e.name}),(0,A.jsx)(`td`,{className:`text-dim`,children:e.tier}),(0,A.jsx)(`td`,{className:`text-mute`,children:e.prefix}),(0,A.jsxs)(`td`,{children:[(0,A.jsx)(`span`,{className:`dot ${e.revoked?`dot-failed`:`dot-ready`}`}),(0,A.jsx)(`span`,{className:e.revoked?`text-err`:`text-dim`,children:e.revoked?`revoked`:`active`})]}),(0,A.jsx)(`td`,{children:e.revoked?(0,A.jsx)(`span`,{className:`text-mute text-[10px]`,children:`—`}):(0,A.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,A.jsx)(`span`,{className:`text-accent`,children:(0,A.jsx)(wn,{values:t})}),n>0&&(0,A.jsxs)(`span`,{className:`text-mute text-[10px] tnum`,children:[n.toLocaleString(),` req`]})]})}),(0,A.jsx)(`td`,{className:`text-right`,children:!e.revoked&&(0,A.jsx)(`button`,{className:`btn-link-danger disabled:opacity-40`,disabled:h.isPending&&h.variables===e.id,onClick:t=>{t.stopPropagation(),confirm(`revoke key "${e.name}" (#${e.id})? this cannot be undone.`)&&h.mutate(e.id)},children:h.isPending&&h.variables===e.id?`revoking…`:`revoke`})})]}),r&&(0,A.jsx)(`tr`,{children:(0,A.jsx)(`td`,{colSpan:7,className:`!pt-2 !pb-6`,children:(0,A.jsx)(`div`,{className:`bg-elev/40 border border-rule p-5`,children:(0,A.jsx)(En,{keyId:e.id})})})})]},e.id)})]})]})]})]})}function On(e,t){let n=!1,r=null;return Tt(e).then(e=>{if(!n){r=new EventSource(e),t.onMessage&&(r.onmessage=t.onMessage),t.onError&&(r.onerror=e=>t.onError?.(e,r));for(let[e,n]of Object.entries(t.listeners??{}))r.addEventListener(e,n)}}).catch(e=>{n||t.onOpenError?.(e instanceof Error?e:Error(String(e)))}),()=>{n=!0,r?.close()}}function kn(){let e=j({queryKey:M.deployments,queryFn:P.listDeployments,refetchInterval:5e3}),t=j({queryKey:M.models,queryFn:P.listModels}),[n,r]=(0,k.useState)(null),[i,a]=(0,k.useState)([]),[o,s]=(0,k.useState)(!1),[c,l]=(0,k.useState)(``),[u,d]=(0,k.useState)([]),f=(0,k.useRef)(null),p=(0,k.useRef)(!0);(0,k.useEffect)(()=>{if(n!==null)return;let t=e.data??[],i=t.find(e=>e.status===`ready`||e.status===`loading`);if(i){r(i.id);return}let a=[...t].sort((e,t)=>t.id-e.id);a.length>0&&r(a[0].id)},[e.data,n]),(0,k.useEffect)(()=>{if(n===null)return;a([]),l(``),s(!0);let e=On(`/admin/deployments/${n}/logs/stream`,{onMessage:e=>{a(t=>{let n=[...t,e.data];return n.length>2e3?n.slice(-2e3):n})},onError:(e,t)=>{s(!1),l(`stream closed (container stopped or auth failed)`),t.close()},onOpenError:e=>{s(!1),l(e.message)}});return()=>{s(!1),e()}},[n]),(0,k.useEffect)(()=>On(`/admin/events`,{onMessage:e=>{try{let t=JSON.parse(e.data);d(e=>[t,...e].slice(0,50))}catch{}},onError:(e,t)=>t.close()}),[]),(0,k.useEffect)(()=>{!f.current||!p.current||(f.current.scrollTop=f.current.scrollHeight)},[i]);function m(e){let t=e.currentTarget;p.current=t.scrollHeight-t.scrollTop-t.clientHeight<60}let h=(e.data??[]).filter(e=>e.container_id!==null&&e.container_id!==void 0).sort((e,t)=>{let n=e.status===`ready`||e.status===`loading`?0:1,r=t.status===`ready`||t.status===`loading`?0:1;return n===r?t.id-e.id:n-r}),g=h.find(e=>e.id===n);return(0,A.jsxs)(`div`,{className:`space-y-10`,children:[(0,A.jsxs)(`header`,{className:`flex items-baseline justify-between`,children:[(0,A.jsx)(`h2`,{className:`text-2xl font-light tracking-tightish caret`,children:`logs`}),(0,A.jsxs)(`div`,{className:`flex items-center gap-3`,children:[o&&(0,A.jsxs)(`span`,{className:`flex items-center text-[11px] tracking-wider text-accent`,children:[(0,A.jsx)(`span`,{className:`dot dot-loading`}),`live`]}),c&&(0,A.jsx)(`span`,{className:`text-err text-[11px] tracking-wider`,children:c})]})]}),(0,A.jsxs)(`section`,{className:`space-y-3`,children:[(0,A.jsx)(`div`,{className:`label`,children:`container`}),(0,A.jsxs)(`select`,{className:`field font-mono text-[13px] min-w-[420px]`,value:n??``,onChange:e=>{r(e.target.value?Number(e.target.value):null)},children:[(0,A.jsx)(`option`,{value:``,children:`select deployment`}),h.map(e=>{let n=(t.data??[]).find(t=>t.id===e.model_id),r=e.status===`ready`||e.status===`loading`?`●`:`·`;return(0,A.jsxs)(`option`,{value:e.id,children:[r,` #`,e.id,` · `,n?.name??`model ${e.model_id}`,` · `,e.status]},e.id)})]})]}),(0,A.jsxs)(`section`,{className:`space-y-3`,children:[(0,A.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,A.jsx)(`div`,{className:`label`,children:`stdout`}),(0,A.jsxs)(`div`,{className:`text-mute text-[10px] tracking-wider tnum`,children:[i.length,` lines`]})]}),(0,A.jsxs)(`div`,{ref:f,onScroll:m,className:`border border-rule font-mono text-[11.5px] leading-relaxed text-ink/80 overflow-y-auto h-[32rem] p-4 bg-[#08080a]`,children:[n===null&&(0,A.jsx)(`div`,{className:`text-mute`,children:`select a deployment above to tail its container logs`}),n!==null&&i.length===0&&o&&(0,A.jsxs)(`div`,{className:`text-mute`,children:[`waiting for output`,(0,A.jsx)(`span`,{className:`caret`})]}),n!==null&&i.length===0&&!o&&(0,A.jsxs)(`div`,{className:`text-mute`,children:[`no log output. the container for #`,n,g?` (${g.status})`:``,` may have been removed.`]}),i.map((e,t)=>(0,A.jsx)(`div`,{className:`whitespace-pre-wrap break-all `+(e.startsWith(`[berth]`)?`text-accent/70`:``),children:e},t))]})]}),(0,A.jsxs)(`details`,{className:`border border-rule`,children:[(0,A.jsxs)(`summary`,{className:`cursor-pointer px-4 py-3 text-dim text-[11px] tracking-wider hover:text-ink transition-colors select-none flex items-center justify-between`,children:[(0,A.jsx)(`span`,{children:`lifecycle events`}),(0,A.jsx)(`span`,{className:`text-mute tnum`,children:u.length})]}),(0,A.jsxs)(`div`,{className:`px-4 pb-4 text-[11px] font-mono space-y-1 max-h-64 overflow-y-auto`,children:[u.length===0&&(0,A.jsx)(`div`,{className:`text-mute`,children:`no events yet`}),u.map((e,t)=>(0,A.jsxs)(`div`,{className:`flex gap-3`,children:[(0,A.jsx)(`span`,{className:`text-mute tnum w-16 shrink-0`,children:e.ts.slice(11,19)}),(0,A.jsx)(`span`,{className:`text-accent shrink-0`,children:e.kind}),(0,A.jsx)(`span`,{className:`text-dim break-all`,children:JSON.stringify(e.payload)})]},t))]})]})]})}function An(e){let t=e*1e3;return t<1?`0ms`:t<10?`${t.toFixed(1)}ms`:t<1e3?`${Math.round(t)}ms`:`${(t/1e3).toFixed(2)}s`}function jn(e){return e.completed_at===null?0:e.completed_at-e.arrived_at}function Mn(e){return e.completed_at===null?`inflight`:e.error||e.status_code!==null&&e.status_code>=400?`err`:`ok`}function Nn(e){switch(Mn(e)){case`inflight`:return`dot-loading`;case`err`:return`dot-failed`;default:return`dot-ready`}}function Pn({t:e}){let t=e.arrived_at,n=e.completed_at??Math.max(e.first_byte_at??0,e.dispatched_at??0,e.route_resolved_at??0,e.arrived_at),r=Math.max(n-t,1e-6),i=[];return e.route_resolved_at!==null&&i.push({label:`route`,from:t,to:e.route_resolved_at,color:`var(--ink-mute)`}),e.route_resolved_at!==null&&e.dispatched_at!==null&&i.push({label:`placement`,from:e.route_resolved_at,to:e.dispatched_at,color:`var(--ink-dim)`}),e.dispatched_at!==null&&e.first_byte_at!==null&&i.push({label:`ttft`,from:e.dispatched_at,to:e.first_byte_at,color:`var(--accent-dim)`}),e.first_byte_at!==null&&e.completed_at!==null&&i.push({label:`stream`,from:e.first_byte_at,to:e.completed_at,color:`var(--accent)`}),(0,A.jsxs)(`div`,{className:`space-y-2`,children:[(0,A.jsx)(`div`,{className:`relative h-3 bg-rule-soft`,children:i.map((e,n)=>{let i=(e.from-t)/r*100,a=Math.max((e.to-e.from)/r*100,.5);return(0,A.jsx)(`div`,{className:`absolute inset-y-0`,style:{left:`${i}%`,width:`${a}%`,background:e.color},title:`${e.label}: ${An(e.to-e.from)}`},n)})}),(0,A.jsxs)(`div`,{className:`flex flex-wrap gap-x-6 gap-y-1 text-[11px] text-mute tracking-wider`,children:[i.map((e,t)=>(0,A.jsxs)(`span`,{children:[(0,A.jsx)(`span`,{className:`text-dim`,children:e.label}),` `,(0,A.jsx)(`span`,{className:`tnum`,children:An(e.to-e.from)})]},t)),(0,A.jsxs)(`span`,{className:`ml-auto`,children:[(0,A.jsx)(`span`,{className:`text-dim`,children:`total`}),` `,(0,A.jsx)(`span`,{className:`tnum`,children:An(r)})]})]})]})}function Fn({t:e,isOpen:t,onToggle:n}){return(0,A.jsxs)(A.Fragment,{children:[(0,A.jsxs)(`tr`,{className:`cursor-pointer`,onClick:n,children:[(0,A.jsxs)(`td`,{children:[(0,A.jsx)(`span`,{className:`dot ${Nn(e)}`}),(0,A.jsx)(`span`,{className:`text-dim font-mono text-[11px]`,children:e.request_id})]}),(0,A.jsx)(`td`,{className:`text-dim text-[11px]`,children:e.method}),(0,A.jsx)(`td`,{className:`font-mono text-[12px] truncate max-w-[16ch]`,children:e.model_requested??`—`}),(0,A.jsx)(`td`,{className:`text-dim text-[12px]`,children:e.route_name?(0,A.jsxs)(`span`,{children:[e.route_name,(0,A.jsx)(`span`,{className:`text-mute`,children:` → `}),(0,A.jsx)(`span`,{className:`font-mono`,children:e.target_model})]}):e.target_model??(0,A.jsx)(`span`,{className:`text-mute`,children:`direct`})}),(0,A.jsx)(`td`,{className:`text-mute text-[12px]`,children:e.backend??`—`}),(0,A.jsx)(`td`,{className:`text-right tnum text-[12px]`,children:e.completed_at===null?(0,A.jsx)(`span`,{className:`text-accent`,children:`streaming…`}):An(jn(e))}),(0,A.jsx)(`td`,{className:`text-right tnum text-[12px] text-dim`,children:e.tokens_out>0?`${e.tokens_out}`:`—`}),(0,A.jsx)(`td`,{className:`text-right text-[12px]`,children:e.error?(0,A.jsx)(`span`,{className:`text-err`,children:e.status_code??`err`}):e.status_code===null?(0,A.jsx)(`span`,{className:`text-mute`,children:`—`}):(0,A.jsx)(`span`,{className:e.status_code>=400?`text-err`:`text-ok`,children:e.status_code})})]}),t&&(0,A.jsx)(`tr`,{children:(0,A.jsx)(`td`,{colSpan:8,className:`!pt-2 !pb-6`,children:(0,A.jsxs)(`div`,{className:`bg-elev/40 border border-rule p-5 space-y-5`,children:[(0,A.jsxs)(`div`,{className:`grid grid-cols-1 md:grid-cols-3 gap-x-8 gap-y-2 text-[12px]`,children:[(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`div`,{className:`label`,children:`request`}),(0,A.jsxs)(`div`,{className:`font-mono`,children:[e.method,` `,e.path]})]}),(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`div`,{className:`label`,children:`api key`}),(0,A.jsx)(`div`,{children:e.api_key_name??(0,A.jsx)(`span`,{className:`text-mute`,children:`none`})})]}),(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`div`,{className:`label`,children:`deployment`}),(0,A.jsx)(`div`,{children:e.deployment_id===null?(0,A.jsx)(`span`,{className:`text-mute`,children:`—`}):(0,A.jsxs)(A.Fragment,{children:[`#`,e.deployment_id,` `,(0,A.jsxs)(`span`,{className:`text-mute`,children:[`(`,e.backend,`)`]})]})})]}),(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`div`,{className:`label`,children:`route`}),(0,A.jsx)(`div`,{children:e.route_name??(0,A.jsx)(`span`,{className:`text-mute`,children:`direct`})})]}),(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`div`,{className:`label`,children:`profile`}),(0,A.jsx)(`div`,{children:e.profile_name??(0,A.jsx)(`span`,{className:`text-mute`,children:`—`})})]}),(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`div`,{className:`label`,children:`cold load`}),(0,A.jsx)(`div`,{children:e.cold_loaded?(0,A.jsx)(`span`,{className:`text-accent`,children:`yes`}):(0,A.jsx)(`span`,{className:`text-mute`,children:`no`})})]})]}),(0,A.jsx)(Pn,{t:e}),e.error&&(0,A.jsx)(`div`,{className:`text-err text-[12px] font-mono whitespace-pre-wrap border-l border-err/40 pl-3`,children:e.error})]})})})]})}function In(){let e=j({queryKey:M.requestsSeed,queryFn:P.listRequests}),[t,n]=(0,k.useState)(new Map),[r,i]=(0,k.useState)(null),[a,o]=(0,k.useState)(!1),s=(0,k.useRef)(!1);(0,k.useEffect)(()=>{!e.data||s.current||(s.current=!0,n(t=>{let n=new Map(t);for(let t of e.data)n.set(t.request_id,t);return n}))},[e.data]),(0,k.useEffect)(()=>{if(a)return;let e=e=>{try{let t=JSON.parse(e.data);Array.isArray(t)?n(()=>{let e=new Map;for(let n of t)e.set(n.request_id,n);return e}):t&&typeof t==`object`&&`request_id`in t&&n(e=>{let n=t,r=new Map(e);if(r.set(n.request_id,n),r.size>256){let e=Array.from(r.keys()).slice(0,r.size-256);for(let t of e)r.delete(t)}return r})}catch{}};return On(`/admin/requests/stream`,{listeners:{snapshot:e,started:e,updated:e,completed:e},onOpenError:e=>console.error(`requests stream open failed`,e)})},[a]);let c=Array.from(t.values()).sort((e,t)=>t.arrived_at-e.arrived_at),l=c.filter(e=>e.completed_at===null).length,u=c.filter(e=>Mn(e)===`err`).length;return(0,A.jsxs)(`div`,{className:`space-y-10`,children:[(0,A.jsxs)(`header`,{className:`flex items-baseline justify-between`,children:[(0,A.jsx)(`h2`,{className:`text-2xl font-light tracking-tightish caret`,children:`requests`}),(0,A.jsxs)(`div`,{className:`flex items-center gap-6`,children:[(0,A.jsx)(`button`,{className:`text-[11px] tracking-wider hover:text-dim transition-colors`,onClick:()=>o(e=>!e),children:(0,A.jsx)(`span`,{className:a?`text-accent`:`text-mute`,children:a?`▶ resume`:`❚❚ pause`})}),(0,A.jsx)(`button`,{className:`text-mute text-[11px] tracking-wider hover:text-dim transition-colors`,onClick:()=>{n(new Map),i(null)},children:`clear`}),(0,A.jsxs)(`div`,{className:`label`,children:[c.length,` traced · `,l,` in flight`,u>0?` · ${u} errored`:``]})]})]}),(0,A.jsx)(`section`,{className:`space-y-4`,children:(0,A.jsxs)(`table`,{className:`ditable`,children:[(0,A.jsx)(`thead`,{children:(0,A.jsxs)(`tr`,{children:[(0,A.jsx)(`th`,{children:`id`}),(0,A.jsx)(`th`,{children:`method`}),(0,A.jsx)(`th`,{children:`model`}),(0,A.jsx)(`th`,{children:`route → target`}),(0,A.jsx)(`th`,{children:`backend`}),(0,A.jsx)(`th`,{className:`text-right`,children:`total`}),(0,A.jsx)(`th`,{className:`text-right`,children:`out tok`}),(0,A.jsx)(`th`,{className:`text-right`,children:`status`})]})}),(0,A.jsxs)(`tbody`,{children:[c.length===0&&(0,A.jsx)(`tr`,{children:(0,A.jsx)(`td`,{colSpan:8,className:`!py-12 text-center text-mute`,children:`no traffic yet. send a request to /v1/chat/completions to see it appear.`})}),c.map(e=>(0,A.jsx)(Fn,{t:e,isOpen:r===e.request_id,onToggle:()=>i(r===e.request_id?null:e.request_id)},e.request_id))]})]})})]})}function Ln({label:e,value:t,hint:n}){return(0,A.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,A.jsx)(`div`,{className:`label`,children:e}),(0,A.jsx)(`div`,{className:`text-2xl font-light tnum tracking-tightish text-ink`,children:t}),n&&(0,A.jsx)(`div`,{className:`text-mute text-[10px] tracking-wider`,children:n})]})}function Rn({onMinted:e}){let t=rt(),[n,r]=(0,k.useState)(``),[i,a]=(0,k.useState)(``),[o,s]=(0,k.useState)(null),[c,l]=(0,k.useState)(null),[u,d]=(0,k.useState)(null),[f,p]=(0,k.useState)(Date.now());(0,k.useEffect)(()=>{if(!u)return;let e=window.setInterval(()=>p(Date.now()),1e3);return()=>window.clearInterval(e)},[u]);let m=yt({mutationFn:e=>P.enrollNode(e),onMutate:()=>{a(``),s(null)},onError:e=>a(e.message),onSuccess:n=>{s(n),d(Date.now()+600*1e3),t.invalidateQueries({queryKey:M.nodes}),e()}}),h=o?Et(o):``,g=o?`berth agent register --uri '${h}'`:``,_=u?Math.max(0,u-f):0,v=_>0?`${Math.floor(_/6e4)}m ${Math.floor(_%6e4/1e3).toString().padStart(2,`0`)}s`:`expired`;function y(e,t){navigator.clipboard.writeText(e),l(t),setTimeout(()=>l(null),1500)}return(0,A.jsxs)(`div`,{className:`border border-rule p-6 space-y-6`,children:[(0,A.jsxs)(`div`,{className:`flex items-baseline justify-between`,children:[(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`div`,{className:`label`,children:`enroll new node`}),(0,A.jsx)(`p`,{className:`text-mute text-[11px] tracking-wider mt-1`,children:`mint a single-use uri that pins the cluster ca to its fingerprint`})]}),o&&(0,A.jsxs)(`span`,{className:`text-[10px] tracking-wider `+(_>6e4?`text-mute`:`text-warn`),children:[`expires in `,v]})]}),(0,A.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,A.jsx)(`input`,{className:`field flex-1 font-mono`,placeholder:`label (e.g. gpu-rig-2)`,value:n,onChange:e=>r(e.target.value.toLowerCase().replace(/\s+/g,`-`)),onKeyDown:e=>{e.key===`Enter`&&n.trim()&&m.mutate(n.trim())}}),(0,A.jsx)(`button`,{className:`btn-primary`,disabled:!n.trim()||m.isPending,onClick:()=>m.mutate(n.trim()),children:m.isPending?`minting…`:`mint uri`})]}),i&&(0,A.jsx)(`div`,{className:`text-err text-[11px] tracking-wider`,children:i}),o&&(0,A.jsxs)(`div`,{className:`space-y-5 pt-2 border-t border-rule-soft`,children:[(0,A.jsxs)(`div`,{className:`space-y-2`,children:[(0,A.jsxs)(`div`,{className:`flex items-baseline justify-between`,children:[(0,A.jsx)(`div`,{className:`label`,children:`enrollment uri`}),(0,A.jsx)(`button`,{onClick:()=>y(h,`uri`),className:`text-mute hover:text-accent text-[10px] tracking-wider transition-colors`,children:c===`uri`?`copied`:`copy`})]}),(0,A.jsx)(`pre`,{className:`text-[11px] bg-bg border border-rule px-3 py-3 text-dim overflow-x-auto break-all whitespace-pre-wrap leading-relaxed`,children:h})]}),(0,A.jsxs)(`div`,{className:`space-y-2`,children:[(0,A.jsxs)(`div`,{className:`flex items-baseline justify-between`,children:[(0,A.jsx)(`div`,{className:`label`,children:`on the agent host`}),(0,A.jsx)(`button`,{onClick:()=>y(g,`cmd`),className:`text-mute hover:text-accent text-[10px] tracking-wider transition-colors`,children:c===`cmd`?`copied`:`copy`})]}),(0,A.jsxs)(`pre`,{className:`text-[12px] bg-bg border border-rule px-3 py-3 text-ink overflow-x-auto break-all whitespace-pre-wrap`,children:[(0,A.jsx)(`span`,{className:`text-mute select-none`,children:`$ `}),g]}),(0,A.jsxs)(`p`,{className:`text-mute text-[11px] tracking-wider leading-relaxed`,children:[`the agent fetches the ca, verifies its sha256 against the pin in the uri, then registers. re-run `,(0,A.jsx)(`code`,{className:`text-dim`,children:`berth agent start`}),` after.`]})]})]})]})}function zn(e){return!e||e<=0?`-`:e>=1024?`${(e/1024).toFixed(1)} GB`:`${e} MB`}function Bn(e){if(!e)return`—`;let t=Math.max(0,Date.now()/1e3-e);return t<5?`just now`:t<60?`${Math.round(t)}s ago`:t<3600?`${Math.round(t/60)}m ago`:t<86400?`${Math.round(t/3600)}h ago`:`${Math.round(t/86400)}d ago`}function Vn(e){return e===`ready`?`text-ok`:e===`unreachable`?`text-warn`:e===`gone`||e===`failed`?`text-err`:`text-mute`}function Hn(e){return e===`ready`?`dot-ready`:e===`unreachable`?`dot-stopping`:e===`gone`||e===`failed`?`dot-failed`:`dot-stopped`}function Un({node:e,selected:t,onSelect:n,liveMetrics:r}){let i=e.label===`local`;return(0,A.jsxs)(`button`,{onClick:n,className:`group text-left p-5 border transition-all duration-200 `+(t?`border-accent bg-elev`:`border-rule hover:border-ink-mute hover:bg-elev/40`),children:[(0,A.jsxs)(`div`,{className:`flex items-baseline justify-between mb-4`,children:[(0,A.jsxs)(`div`,{className:`flex items-baseline gap-2`,children:[(0,A.jsx)(`span`,{className:`dot ${Hn(e.status)}`}),(0,A.jsx)(`span`,{className:`text-ink text-[13px]`,children:e.label}),i&&(0,A.jsx)(`span`,{className:`text-mute text-[10px] tracking-wider ml-1`,children:`— this host`})]}),(0,A.jsx)(`span`,{className:`text-[10px] tracking-wider ${Vn(e.status)}`,children:e.status})]}),(0,A.jsxs)(`div`,{className:`grid grid-cols-2 gap-x-4 gap-y-2 text-[11px]`,children:[(0,A.jsx)(`div`,{className:`text-mute tracking-wider`,children:`gpus`}),(0,A.jsxs)(`div`,{className:`text-right tnum text-ink`,children:[e.gpu_count,` `,(0,A.jsxs)(`span`,{className:`text-mute`,children:[`/ `,zn(e.total_vram_mb)]})]}),(0,A.jsx)(`div`,{className:`text-mute tracking-wider`,children:`cpus`}),(0,A.jsxs)(`div`,{className:`text-right tnum text-dim`,children:[e.cpu_count||`-`,` `,(0,A.jsxs)(`span`,{className:`text-mute`,children:[`/ `,zn(e.total_ram_mb)]})]}),(0,A.jsx)(`div`,{className:`text-mute tracking-wider`,children:`agent`}),(0,A.jsx)(`div`,{className:`text-right text-dim`,children:e.agent_version??`—`}),(0,A.jsx)(`div`,{className:`text-mute tracking-wider`,children:`heartbeat`}),(0,A.jsx)(`div`,{className:`text-right text-dim`,children:Bn(e.last_seen)})]}),r&&(0,A.jsxs)(`div`,{className:`mt-4 pt-3 border-t border-rule/40 space-y-1.5 text-[10px]`,children:[Object.entries(r.series.gpu_util_pct).map(([e,t])=>(0,A.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,A.jsxs)(`span`,{className:`text-mute tracking-wider`,children:[e,` util`]}),(0,A.jsx)(It,{values:t})]},e)),(0,A.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,A.jsx)(`span`,{className:`text-mute tracking-wider`,children:`req/s`}),(0,A.jsx)(It,{values:r.series.request_rate})]})]})]})}function Wn({fp:e,copyable:t=!0}){let[n,r]=(0,k.useState)(!1),i=e.replace(/^sha256:/,``),a=[];for(let e=0;e{navigator.clipboard.writeText(e),r(!0),setTimeout(()=>r(!1),1200)},children:n?`copied`:`copy`})]})}function Gn({gpu:e,totalInNode:t}){let n=t>0?e.total_vram_mb/t*100:0;return(0,A.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,A.jsxs)(`div`,{className:`flex items-baseline justify-between`,children:[(0,A.jsxs)(`div`,{className:`text-[11px] text-dim`,children:[(0,A.jsxs)(`span`,{className:`text-mute mr-2`,children:[`[`,e.gpu_index,`]`]}),e.name]}),(0,A.jsx)(`div`,{className:`tnum text-[11px] text-dim`,children:zn(e.total_vram_mb)})]}),(0,A.jsx)(`div`,{className:`h-px bg-rule relative overflow-hidden`,children:(0,A.jsx)(`div`,{className:`absolute inset-y-0 left-0 bg-accent/70`,style:{width:`${n}%`}})}),e.driver_version&&(0,A.jsxs)(`div`,{className:`text-mute text-[10px] tracking-wider`,children:[`driver `,e.driver_version]})]})}function Kn({node:e,deployments:t,models:n,onRemove:r}){let i=j({queryKey:M.node(e.id),queryFn:()=>P.getNode(e.id),refetchInterval:5e3}),a=i.data?.gpus??[],o=a.reduce((e,t)=>e+t.total_vram_mb,0),s=e.label===`local`,c=t.filter(t=>(t.node_id===e.id||s&&(!t.node_id||t.node_id===0))&&t.status!==`stopped`);return(0,A.jsxs)(`aside`,{className:`border border-rule bg-elev/30`,children:[(0,A.jsxs)(`header`,{className:`flex items-baseline justify-between px-6 py-4 border-b border-rule`,children:[(0,A.jsxs)(`div`,{className:`flex items-baseline gap-3`,children:[(0,A.jsx)(`span`,{className:`dot ${Hn(e.status)}`}),(0,A.jsx)(`h3`,{className:`text-lg font-light tracking-tightish`,children:e.label}),(0,A.jsx)(`span`,{className:`text-[10px] tracking-wider ${Vn(e.status)}`,children:e.status}),s&&(0,A.jsx)(`span`,{className:`text-mute text-[10px] tracking-wider ml-1`,children:`— this host`})]}),!s&&r&&(0,A.jsx)(`button`,{onClick:r,className:`btn-link-danger text-[11px] tracking-wider`,children:`remove node`})]}),(0,A.jsxs)(`div`,{className:`grid grid-cols-1 lg:grid-cols-2 divide-y lg:divide-y-0 lg:divide-x divide-rule-soft`,children:[(0,A.jsxs)(`div`,{className:`p-6 space-y-6`,children:[(0,A.jsxs)(`section`,{className:`grid grid-cols-2 gap-6 text-[12px]`,children:[(0,A.jsxs)(`div`,{className:`space-y-1`,children:[(0,A.jsx)(`div`,{className:`label`,children:`cpu / ram`}),(0,A.jsxs)(`div`,{className:`tnum text-dim`,children:[e.cpu_count||`-`,` cpu / `,zn(e.total_ram_mb)]})]}),(0,A.jsxs)(`div`,{className:`space-y-1`,children:[(0,A.jsx)(`div`,{className:`label`,children:`gpu total`}),(0,A.jsxs)(`div`,{className:`tnum text-dim`,children:[e.gpu_count,` gpu / `,zn(e.total_vram_mb)]})]}),(0,A.jsxs)(`div`,{className:`space-y-1`,children:[(0,A.jsx)(`div`,{className:`label`,children:`agent version`}),(0,A.jsx)(`div`,{className:`text-dim`,children:e.agent_version??`—`})]}),(0,A.jsxs)(`div`,{className:`space-y-1`,children:[(0,A.jsx)(`div`,{className:`label`,children:`last heartbeat`}),(0,A.jsx)(`div`,{className:`text-dim`,children:Bn(e.last_seen)})]})]}),(0,A.jsxs)(`section`,{className:`space-y-3 pt-2`,children:[(0,A.jsx)(`div`,{className:`label`,children:`cert fingerprint`}),s?(0,A.jsx)(`div`,{className:`text-mute text-[11px] tracking-wider`,children:`local node — no agent certificate (control runs in-process)`}):(0,A.jsx)(Wn,{fp:e.fingerprint})]})]}),(0,A.jsxs)(`div`,{className:`p-6 space-y-6`,children:[(0,A.jsxs)(`section`,{className:`space-y-3`,children:[(0,A.jsx)(`div`,{className:`label`,children:`gpu inventory`}),a.length===0?(0,A.jsx)(`div`,{className:`text-mute text-[11px] tracking-wider`,children:i.isLoading?`loading…`:`no gpus reported`}):(0,A.jsx)(`div`,{className:`space-y-4`,children:a.map(e=>(0,A.jsx)(Gn,{gpu:e,totalInNode:o},e.gpu_index))})]}),(0,A.jsxs)(`section`,{className:`space-y-3 pt-2 border-t border-rule-soft`,children:[(0,A.jsxs)(`div`,{className:`label`,children:[`deployments on this node · `,c.length]}),c.length===0?(0,A.jsx)(`div`,{className:`text-mute text-[11px] tracking-wider`,children:`no active deployments`}):(0,A.jsx)(`div`,{className:`space-y-2`,children:c.map(e=>{let t=n.find(t=>t.id===e.model_id);return(0,A.jsxs)(`div`,{className:`flex items-center gap-3 text-[12px]`,title:e.last_error||void 0,children:[(0,A.jsx)(`span`,{className:`dot dot-${e.status}`}),(0,A.jsx)(`span`,{className:`text-ink truncate`,children:t?.name??`#${e.id}`}),(0,A.jsx)(`span`,{className:`text-mute text-[10px] tracking-wider`,children:e.backend}),(0,A.jsxs)(`span`,{className:`text-dim tnum ml-auto`,children:[`gpu `,(e.gpu_ids??[]).join(`,`)||`-`]})]},e.id)})})]})]})]})]})}function qn({nodes:e}){let t=e.find(e=>e.label===`local`),n=e.filter(e=>e.label!==`local`),r=Math.max(n.length,1),i=Math.min(220,120+n.length*24);return(0,A.jsxs)(`svg`,{viewBox:`0 0 720 280`,preserveAspectRatio:`xMidYMid meet`,className:`w-full h-[280px] select-none`,"aria-hidden":!0,children:[[.35,.65,1].map((e,t)=>(0,A.jsx)(`circle`,{cx:360,cy:140,r:i*e,fill:`none`,stroke:`var(--rule-soft)`,strokeWidth:1,strokeDasharray:t===2?`2 6`:void 0},t)),Array.from({length:6},(e,t)=>{let n=t/6*2*Math.PI;return(0,A.jsx)(`line`,{x1:360,y1:140,x2:360+Math.cos(n)*i,y2:140+Math.sin(n)*i,stroke:`var(--rule-soft)`,strokeWidth:.5},t)}),n.map((e,t)=>{let n=t/r*2*Math.PI-Math.PI/2,a=360+Math.cos(n)*i,o=140+Math.sin(n)*i,s=e.status===`ready`,c=e.status===`unreachable`,l=s?`var(--accent)`:c?`var(--warn)`:`var(--ink-mute)`;return(0,A.jsxs)(`g`,{children:[(0,A.jsx)(`line`,{x1:360,y1:140,x2:a,y2:o,stroke:l,strokeWidth:s?1.25:1,strokeDasharray:s?void 0:`4 4`,opacity:s?.7:.4}),s&&(0,A.jsx)(`circle`,{r:2.5,fill:l,children:(0,A.jsx)(`animateMotion`,{dur:`2.8s`,repeatCount:`indefinite`,path:`M 360 140 L ${a} ${o}`})}),(0,A.jsxs)(`g`,{transform:`translate(${a}, ${o})`,children:[(0,A.jsx)(`circle`,{r:14,fill:`var(--bg-page)`,stroke:l,strokeWidth:1.25}),(0,A.jsx)(`circle`,{r:5,fill:l,opacity:s?1:.5}),(0,A.jsx)(`text`,{x:0,y:28,textAnchor:`middle`,fontSize:10,fill:`var(--ink-dim)`,style:{fontFamily:`JetBrains Mono, monospace`,letterSpacing:`0.04em`},children:e.label}),(0,A.jsxs)(`text`,{x:0,y:42,textAnchor:`middle`,fontSize:9,fill:`var(--ink-mute)`,style:{fontFamily:`JetBrains Mono, monospace`,letterSpacing:`0.06em`},children:[e.gpu_count,` gpu / `,zn(e.total_vram_mb)]})]})]},e.id)}),(0,A.jsxs)(`g`,{children:[(0,A.jsx)(`circle`,{cx:360,cy:140,r:28,fill:`var(--bg-elev)`,stroke:`var(--accent)`,strokeWidth:1.5}),(0,A.jsx)(`circle`,{cx:360,cy:140,r:10,fill:`var(--accent)`}),(0,A.jsx)(`text`,{x:360,y:190,textAnchor:`middle`,fontSize:10,fill:`var(--ink)`,style:{fontFamily:`JetBrains Mono, monospace`,letterSpacing:`0.14em`,textTransform:`uppercase`},children:`leader`}),t&&(0,A.jsxs)(`text`,{x:360,y:204,textAnchor:`middle`,fontSize:9,fill:`var(--ink-mute)`,style:{fontFamily:`JetBrains Mono, monospace`,letterSpacing:`0.04em`},children:[t.gpu_count,` gpu / `,zn(t.total_vram_mb)]})]})]})}function Jn({info:e}){let t=e.leader_server_cert;return(0,A.jsxs)(`section`,{className:`border border-rule`,children:[(0,A.jsxs)(`div`,{className:`px-6 py-4 border-b border-rule flex items-baseline justify-between`,children:[(0,A.jsx)(`div`,{className:`label`,children:`cluster transport`}),(0,A.jsx)(`div`,{className:`text-mute text-[10px] tracking-wider`,children:e.public_tls_configured?`public_tls configured`:`⚠ cluster-ca cert on public listener`})]}),(0,A.jsxs)(`div`,{className:`grid grid-cols-1 md:grid-cols-2 divide-x divide-rule-soft`,children:[(0,A.jsxs)(`div`,{className:`p-6 space-y-4`,children:[(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`div`,{className:`label`,children:`public listener`}),(0,A.jsx)(`code`,{className:`block text-[12px] text-ink mt-1.5`,children:e.public_url}),(0,A.jsxs)(`div`,{className:`text-mute text-[10px] tracking-wider mt-1`,children:[`bind `,e.public_bind,` · `,e.public_tls_configured?`operator cert`:`cluster-ca fallback`]})]}),(0,A.jsx)(`div`,{className:`text-[11px] text-mute leading-relaxed`,children:`/v1/* · /admin/* · bearer auth · external sdk clients`})]}),(0,A.jsxs)(`div`,{className:`p-6 space-y-4`,children:[(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`div`,{className:`label`,children:`cluster listener`}),(0,A.jsx)(`code`,{className:`block text-[12px] text-ink mt-1.5`,children:e.cluster_url}),(0,A.jsxs)(`div`,{className:`text-mute text-[10px] tracking-wider mt-1`,children:[`bind `,e.cluster_bind,` · cluster-ca signed`]})]}),(0,A.jsx)(`div`,{className:`text-[11px] text-mute leading-relaxed`,children:`/cluster/agent · mtls websocket · /admin/nodes/register`})]})]}),(0,A.jsxs)(`div`,{className:`px-6 py-5 border-t border-rule space-y-3`,children:[(0,A.jsx)(`div`,{className:`label`,children:`ca fingerprint`}),(0,A.jsx)(Wn,{fp:e.ca_fingerprint}),t.present&&`san`in t&&(0,A.jsxs)(`div`,{className:`flex flex-wrap gap-x-6 gap-y-2 pt-3 text-[11px]`,children:[(0,A.jsx)(`div`,{className:`text-mute tracking-wider`,children:`leader server cert`}),(0,A.jsxs)(`div`,{className:`text-dim`,children:[`san\xA0`,(0,A.jsx)(`span`,{className:`text-mute`,children:`[`}),t.san.map((e,n)=>(0,A.jsxs)(`span`,{children:[(0,A.jsx)(`code`,{className:`text-ink`,children:e}),n{let e=e=>e===`ready`?0:e===`unreachable`?1:2;return[...c].sort((t,n)=>t.label===`local`?-1:n.label===`local`?1:e(t.status)-e(n.status))},[c]);(0,k.useEffect)(()=>{o===null&&c.length!==0&&s((c.find(e=>e.label!==`local`)??c[0]).id)},[c,o]);let u=c.find(e=>e.id===o)??null,d=yt({mutationFn:e=>P.removeNode(e),onSuccess:()=>{e.invalidateQueries({queryKey:M.nodes}),s(null)}}),f=c.filter(e=>e.status===`ready`).length,p=c.filter(e=>e.label!==`local`).length,m=c.reduce((e,t)=>e+t.gpu_count,0),h=c.reduce((e,t)=>e+t.total_vram_mb,0);return(0,A.jsxs)(`div`,{className:`space-y-14`,children:[(0,A.jsxs)(`header`,{className:`flex items-baseline justify-between`,children:[(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`h2`,{className:`text-2xl font-light tracking-tightish caret`,children:`cluster`}),(0,A.jsx)(`p`,{className:`text-mute text-[11px] tracking-wider mt-2`,children:p===0?`single-node leader. enroll an agent to scale out.`:`${p} agent${p===1?``:`s`} attached · leader at the hub`})]}),(0,A.jsxs)(`div`,{className:`label`,children:[f,`/`,c.length,` ready`]})]}),(0,A.jsxs)(`section`,{className:`grid grid-cols-2 md:grid-cols-4 gap-12`,children:[(0,A.jsx)(Ln,{label:`nodes`,value:String(c.length),hint:`${f} ready`}),(0,A.jsx)(Ln,{label:`agents`,value:String(p),hint:p>0?`${p} remote`:`no remote agents`}),(0,A.jsx)(Ln,{label:`gpus`,value:String(m),hint:`across the fleet`}),(0,A.jsx)(Ln,{label:`vram`,value:zn(h),hint:`aggregated`})]}),(0,A.jsx)(`section`,{className:`border border-rule p-4`,children:c.length===0?(0,A.jsx)(`div`,{className:`h-[280px] flex items-center justify-center text-mute text-[11px] tracking-wider`,children:`no nodes yet`}):(0,A.jsx)(qn,{nodes:l})}),r.data&&(0,A.jsx)(Jn,{info:r.data}),(0,A.jsxs)(`section`,{className:`space-y-6`,children:[(0,A.jsxs)(`div`,{className:`flex items-baseline justify-between`,children:[(0,A.jsxs)(`div`,{className:`label`,children:[`fleet · `,c.length,` node`,c.length===1?``:`s`]}),d.isError&&(0,A.jsx)(`div`,{className:`text-err text-[11px] tracking-wider`,children:d.error.message})]}),(0,A.jsx)(`div`,{className:`grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4`,children:l.map(e=>(0,A.jsx)(Un,{node:e,selected:o===e.id,onSelect:()=>s(e.id),liveMetrics:n.data?.nodes.find(t=>t.node_id===e.id)},e.id))}),l.length>0&&(0,A.jsx)(`p`,{className:`text-mute text-[11px] tracking-wider`,children:`click any node to view its certificate and gpu inventory below`})]}),u&&(0,A.jsxs)(`section`,{className:`space-y-4`,children:[(0,A.jsxs)(`div`,{className:`flex items-baseline gap-3`,children:[(0,A.jsxs)(`div`,{className:`label`,children:[`selected · `,u.label]}),(0,A.jsx)(`div`,{className:`h-px bg-rule flex-1`})]}),(0,A.jsx)(Kn,{node:u,deployments:i.data??[],models:a.data??[],onRemove:u.label===`local`?void 0:()=>{confirm(`remove node "${u.label}"?\nany live connection is dropped and its cert fingerprint stops authenticating.`)&&d.mutate(u.id)}})]}),(0,A.jsxs)(`section`,{className:`space-y-4`,children:[(0,A.jsx)(`div`,{className:`label`,children:`enrollment`}),(0,A.jsx)(Rn,{onMinted:()=>e.invalidateQueries({queryKey:M.nodes})})]})]})}function Xn(e){return e===`flag`?`text-accent`:e.startsWith(`env`)?`text-warn`:e===`file`?`text-ok`:e===`autodetect`||e.startsWith(`inherit`)?`text-dim`:`text-mute`}function Zn(e){return e.startsWith(`inherit:`)?`inherit ${e.slice(8)}`:e.startsWith(`env:`)?e.slice(4):e}var Qn=[{key:`public_host`,label:`host`,group:`public`},{key:`public_port`,label:`port`,group:`public`},{key:`public_bind`,label:`bind`,group:`public`},{key:`cluster_host`,label:`host`,group:`cluster`},{key:`cluster_port`,label:`port`,group:`cluster`},{key:`cluster_bind`,label:`bind`,group:`cluster`},{key:`public_cert_path`,label:`cert`,group:`tls`},{key:`public_key_path`,label:`key`,group:`tls`}];function $n({title:e,rows:t,values:n,sources:r}){return(0,A.jsxs)(`div`,{className:`space-y-3`,children:[(0,A.jsx)(`div`,{className:`label`,children:e}),(0,A.jsx)(`div`,{className:`border border-rule-soft`,children:t.map((e,i)=>{let a=n[e.key],o=r[e.key]??`default`;return(0,A.jsxs)(`div`,{className:`grid grid-cols-12 items-center px-4 py-3 text-[12px] `+(i{let a=i.filter(([e])=>t[e]===`file`);if(a.length!==0){n.push(`[${r}]`);for(let[t,r]of a){let i=e[t];if(i==null)continue;let a=typeof i==`string`?`"${i}"`:String(i);n.push(`${r} = ${a}`)}n.push(``)}};return r(`public`,[[`public_host`,`host`],[`public_port`,`port`],[`public_bind`,`bind`]]),r(`public_tls`,[[`public_cert_path`,`cert`],[`public_key_path`,`key`]]),r(`cluster`,[[`cluster_host`,`host`],[`cluster_port`,`port`],[`cluster_bind`,`bind`]]),n.join(` `).trim()||`# config.toml is empty — all values from autodetect/env/default`}function tr(){let e=j({queryKey:M.config,queryFn:P.getConfig}),t=j({queryKey:M.clusterInfo,queryFn:P.getClusterInfo});if(e.isLoading)return(0,A.jsx)(`div`,{className:`text-mute text-[11px] tracking-wider`,children:`loading…`});if(!e.data)return(0,A.jsx)(`div`,{className:`text-err text-[11px] tracking-wider`,children:`no config`});let{values:n,sources:r,config_file:i,config_file_exists:a}=e.data,o=Qn.filter(e=>e.group===`public`),s=Qn.filter(e=>e.group===`cluster`),c=Qn.filter(e=>e.group===`tls`);return(0,A.jsxs)(`div`,{className:`space-y-14`,children:[(0,A.jsxs)(`header`,{className:`flex items-baseline justify-between`,children:[(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`h2`,{className:`text-2xl font-light tracking-tightish caret`,children:`settings`}),(0,A.jsx)(`p`,{className:`text-mute text-[11px] tracking-wider mt-2`,children:`resolved daemon configuration · flag > env > file > autodetect > default`})]}),t.data&&(0,A.jsxs)(`div`,{className:`text-right`,children:[(0,A.jsx)(`div`,{className:`label`,children:`advertised`}),(0,A.jsx)(`code`,{className:`text-[11px] text-dim mt-1 block`,children:t.data.cluster_url})]})]}),(0,A.jsxs)(`section`,{className:`grid grid-cols-1 lg:grid-cols-2 gap-x-10 gap-y-10`,children:[(0,A.jsx)($n,{title:`public listener`,rows:o,values:n,sources:r}),(0,A.jsx)($n,{title:`cluster listener`,rows:s,values:n,sources:r}),(0,A.jsx)($n,{title:`public tls (operator cert)`,rows:c,values:n,sources:r}),(0,A.jsxs)(`div`,{className:`space-y-3`,children:[(0,A.jsx)(`div`,{className:`label`,children:`overrides`}),(0,A.jsx)(`div`,{className:`border border-rule-soft`,children:(0,A.jsxs)(`div`,{className:`grid grid-cols-12 items-center px-4 py-3 text-[12px]`,children:[(0,A.jsx)(`div`,{className:`col-span-3 text-mute tracking-wider`,children:`leader url`}),(0,A.jsx)(`div`,{className:`col-span-6 text-ink`,children:n.leader_url_override?(0,A.jsx)(`code`,{children:n.leader_url_override}):(0,A.jsx)(`span`,{className:`text-mute`,children:`—`})}),(0,A.jsx)(`div`,{className:`col-span-3 text-right text-[10px] tracking-wider `+Xn(r.leader_url??`default`),children:Zn(r.leader_url??`default`)})]})})]})]}),(0,A.jsxs)(`section`,{className:`space-y-4`,children:[(0,A.jsxs)(`div`,{className:`flex items-baseline justify-between`,children:[(0,A.jsx)(`div`,{className:`label`,children:`~/.berth/config.toml`}),(0,A.jsx)(`div`,{className:`text-mute text-[10px] tracking-wider`,children:a?i:`${i} · not present`})]}),(0,A.jsx)(`pre`,{className:`bg-bg border border-rule px-4 py-4 text-[12px] text-dim leading-relaxed overflow-x-auto`,children:er(n,r)}),(0,A.jsxs)(`p`,{className:`text-mute text-[11px] tracking-wider leading-relaxed`,children:[`edit via cli: `,(0,A.jsx)(`code`,{className:`text-dim`,children:`berth config set-public host=... port=...`}),` ·`,` `,(0,A.jsx)(`code`,{className:`text-dim`,children:`berth config set-cluster bind=...`}),` ·`,` `,(0,A.jsx)(`code`,{className:`text-dim`,children:`berth config set-public-tls cert=... key=...`}),`.`,` `,`restart the daemon to pick up changes.`]})]}),(0,A.jsxs)(`section`,{className:`space-y-4`,children:[(0,A.jsx)(`div`,{className:`label`,children:`legend`}),(0,A.jsxs)(`div`,{className:`grid grid-cols-2 md:grid-cols-5 gap-x-6 gap-y-2 text-[11px] tracking-wider`,children:[(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`span`,{className:`text-accent`,children:`flag`}),` `,(0,A.jsx)(`span`,{className:`text-mute`,children:`cli`})]}),(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`span`,{className:`text-warn`,children:`env`}),` `,(0,A.jsx)(`span`,{className:`text-mute`,children:`environment`})]}),(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`span`,{className:`text-ok`,children:`file`}),` `,(0,A.jsx)(`span`,{className:`text-mute`,children:`config.toml`})]}),(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`span`,{className:`text-dim`,children:`autodetect`}),` `,(0,A.jsx)(`span`,{className:`text-mute`,children:`probed`})]}),(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`span`,{className:`text-mute`,children:`default`}),` `,(0,A.jsx)(`span`,{className:`text-mute`,children:`fallback`})]})]})]})]})}var nr=[{id:`overview`,label:`overview`,tabs:[{id:`overview`,label:`overview`,component:Kt}]},{id:`serving`,label:`serving`,tabs:[{id:`deployments`,label:`deployments`,component:Jt},{id:`models`,label:`models`,component:nn},{id:`adapters`,label:`adapters`,component:rn},{id:`routes`,label:`routes`,component:fn},{id:`profiles`,label:`profiles`,component:pn}]},{id:`observe`,label:`observe`,tabs:[{id:`requests`,label:`requests`,component:In},{id:`logs`,label:`logs`,component:kn},{id:`cluster`,label:`cluster`,component:Yn},{id:`predictor`,label:`predictor`,component:gn}]},{id:`admin`,label:`admin`,tabs:[{id:`keys`,label:`keys`,component:Dn},{id:`settings`,label:`settings`,component:tr}]},{id:`playground`,label:`playground`,tabs:[{id:`playground`,label:`playground`,component:Sn}]}];function rr(e){return nr.find(t=>t.id===e)??nr[0]}function ir(e,t){return e.tabs.find(e=>e.id===t)??e.tabs[0]}function ar({active:e,onSelect:t,onSignOut:n}){return(0,A.jsx)(`header`,{className:`sticky top-0 z-10 backdrop-blur-sm bg-bg/80 border-b border-rule`,children:(0,A.jsxs)(`div`,{className:`max-w-[1280px] mx-auto px-8 h-14 flex items-center justify-between gap-8`,children:[(0,A.jsxs)(`div`,{className:`flex items-center gap-10`,children:[(0,A.jsx)(`div`,{className:`text-[13px] tracking-tightish select-none`,children:`berth`}),(0,A.jsx)(`nav`,{className:`flex items-center gap-6`,children:nr.map(n=>{let r=e===n.id;return(0,A.jsxs)(`button`,{onClick:()=>t(n.id),className:`relative text-[12px] tracking-wider transition-colors py-4 `+(r?`text-ink`:`text-mute hover:text-dim`),children:[n.label,r&&(0,A.jsx)(`span`,{className:`absolute left-0 right-0 bottom-0 h-px bg-accent`})]},n.id)})})]}),(0,A.jsx)(`button`,{onClick:n,className:`label hover:text-dim transition-colors`,children:`sign out`})]})})}function or({section:e,activeTab:t,onSelect:n}){return e.tabs.length<=1?null:(0,A.jsx)(`div`,{className:`border-b border-rule-soft`,children:(0,A.jsx)(`div`,{className:`max-w-[1280px] mx-auto px-8 flex items-center gap-6`,children:e.tabs.map(e=>{let r=t===e.id;return(0,A.jsxs)(`button`,{onClick:()=>n(e.id),className:`relative text-[11px] tracking-wider transition-colors py-3 `+(r?`text-ink`:`text-mute hover:text-dim`),children:[e.label,r&&(0,A.jsx)(`span`,{className:`absolute left-0 right-0 bottom-0 h-px bg-accent`})]},e.id)})})})}function sr(e){let t=e.replace(/^#\/?/,``);if(!t)return{section:`overview`,tab:null};let[n,r]=t.split(`/`);return{section:n,tab:r||null}}function cr(e,t){return t?`#/${e}/${t}`:`#/${e}`}function lr(){let[e,t]=(0,k.useState)(()=>sr(location.hash));return(0,k.useEffect)(()=>{let e=()=>t(sr(location.hash));return window.addEventListener(`hashchange`,e),()=>window.removeEventListener(`hashchange`,e)},[]),[e,(e,t)=>{location.hash=cr(e,t)}]}function ur(){let[e,t]=lr(),n=rr(e.section),r=ir(n,e.tab??n.tabs[0].id),i=r.component;return(0,A.jsx)(Dt,{children:(0,A.jsxs)(`div`,{className:`min-h-screen flex flex-col`,children:[(0,A.jsx)(ar,{active:n.id,onSelect:e=>{let n=rr(e);t(n.id,n.tabs[0].id)},onSignOut:()=>{wt(),location.reload()}}),(0,A.jsx)(or,{section:n,activeTab:r.id,onSelect:e=>t(n.id,e)}),(0,A.jsx)(`main`,{className:`flex-1 overflow-y-auto`,children:(0,A.jsx)(`div`,{className:`max-w-[1280px] mx-auto px-8 py-12 enter`,children:(0,A.jsx)(i,{})},`${n.id}/${r.id}`)})]})})}var dr=new $e({defaultOptions:{queries:{staleTime:1e3}}});bt.createRoot(document.getElementById(`root`)).render((0,A.jsx)(k.StrictMode,{children:(0,A.jsx)(it,{client:dr,children:(0,A.jsx)(ur,{})})})); \ No newline at end of file diff --git a/src/berth/ui/index.html b/src/berth/ui/index.html index 2c3b1c3..9c5649b 100644 --- a/src/berth/ui/index.html +++ b/src/berth/ui/index.html @@ -15,7 +15,7 @@ href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;500;600;700&display=swap" rel="stylesheet" /> - + diff --git a/tests/unit/test_backup_cmd.py b/tests/unit/test_backup_cmd.py index 239b7a4..bf28bf3 100644 --- a/tests/unit/test_backup_cmd.py +++ b/tests/unit/test_backup_cmd.py @@ -2,12 +2,14 @@ from __future__ import annotations import os +import sqlite3 import stat import tarfile from typer.testing import CliRunner from berth import cli, config +from berth.cli import backup_cmd from berth.store import db @@ -60,3 +62,39 @@ def test_backup_archive_is_owner_only(tmp_path, monkeypatch): assert res.exit_code == 0, res.output assert stat.S_IMODE(dest.stat().st_mode) == 0o600 + + +def test_backup_snapshot_is_owner_only(tmp_path, monkeypatch): + # The intermediate sqlite snapshot holds a full copy of the DB and must be + # private (0600), even under a loose umask, before sqlite opens it. + monkeypatch.setattr(config, "BERTH_DIR", tmp_path) + monkeypatch.setattr(config, "DB_PATH", tmp_path / "db.sqlite") + monkeypatch.setattr(config, "CONFIG_FILE", tmp_path / "config.toml") + + (tmp_path / "key_pepper").write_bytes(b"\x00" * 32) + conn = db.connect(tmp_path / "db.sqlite") + db.init_schema(conn) + + captured: dict = {} + real_connect = sqlite3.connect + + def _spy_connect(target, *args, **kwargs): + # Record the snapshot's mode at the moment sqlite opens it. + if ".db-backup-" in str(target): + captured["mode"] = stat.S_IMODE(os.stat(target).st_mode) + captured["path"] = target + return real_connect(target, *args, **kwargs) + + monkeypatch.setattr(backup_cmd.sqlite3, "connect", _spy_connect) + + dest = tmp_path / "snap.tar.gz" + old_umask = os.umask(0o022) + try: + res = CliRunner().invoke(cli.app, ["backup", "create", str(dest)]) + finally: + os.umask(old_umask) + + assert res.exit_code == 0, res.output + assert captured["mode"] == 0o600 + # Snapshot is removed in the finally block. + assert not os.path.exists(captured["path"]) diff --git a/tests/unit/test_cli_agent_register.py b/tests/unit/test_cli_agent_register.py index 17a503c..932c659 100644 --- a/tests/unit/test_cli_agent_register.py +++ b/tests/unit/test_cli_agent_register.py @@ -78,6 +78,75 @@ def _post(url, json, verify=None, timeout=None): assert mode == 0o600 +def _mock_register_http(monkeypatch, ca_pem): + class _MockResp: + status_code = 200 + def raise_for_status(self): pass + def json(self): + return { + "node_id": 9, + "agent_cert": "-----BEGIN CERTIFICATE-----\nA\n-----END CERTIFICATE-----\n", + "agent_key": ( + "-----BEGIN PRIVATE KEY-----\nB\n-----END PRIVATE KEY-----\n" + ), + } + + def _get(url, verify=None, timeout=None): + class _CAResp: + text = ca_pem + def raise_for_status(self): pass + return _CAResp() + + def _post(url, json, verify=None, timeout=None): + return _MockResp() + + monkeypatch.setattr(httpx, "get", _get) + monkeypatch.setattr(httpx, "post", _post) + + +def test_register_reads_uri_from_env_without_argv(tmp_path, monkeypatch): + # Supplying the URI via env keeps the embedded token out of argv/history. + home = tmp_path / "home" + home.mkdir() + home.chmod(0o755) + monkeypatch.setenv("BERTH_HOME", str(home)) + ca_pem = "-----BEGIN CERTIFICATE-----\nC\n-----END CERTIFICATE-----\n" + ca_fp = "sha256:" + hashlib.sha256(ca_pem.encode("utf-8")).hexdigest() + _mock_register_http(monkeypatch, ca_pem) + + monkeypatch.setenv( + "BERTH_ENROLL_URI", + "berth://enroll?leader=https%3A%2F%2Fleader.example%3A11500" + f"&token=tok-env&ca_fp={ca_fp}", + ) + # No --uri on the command line at all. + r = CliRunner().invoke(app, ["agent", "register"]) + assert r.exit_code == 0, r.output + cfg = yaml.safe_load((home / "agent.yaml").read_text()) + assert cfg["node_id"] == 9 + + +def test_register_prompts_for_uri_when_omitted(tmp_path, monkeypatch): + home = tmp_path / "home" + home.mkdir() + home.chmod(0o755) + monkeypatch.setenv("BERTH_HOME", str(home)) + monkeypatch.delenv("BERTH_ENROLL_URI", raising=False) + ca_pem = "-----BEGIN CERTIFICATE-----\nC\n-----END CERTIFICATE-----\n" + ca_fp = "sha256:" + hashlib.sha256(ca_pem.encode("utf-8")).hexdigest() + _mock_register_http(monkeypatch, ca_pem) + + uri = ( + "berth://enroll?leader=https%3A%2F%2Fleader.example%3A11500" + f"&token=tok-prompt&ca_fp={ca_fp}" + ) + # No --uri flag: the URI is read from the (hidden) prompt via stdin. + r = CliRunner().invoke(app, ["agent", "register"], input=uri + "\n") + assert r.exit_code == 0, r.output + cfg = yaml.safe_load((home / "agent.yaml").read_text()) + assert cfg["node_id"] == 9 + + def test_register_rejects_removed_leader_token_flags(tmp_path, monkeypatch): monkeypatch.setenv("BERTH_HOME", str(tmp_path)) r = CliRunner().invoke(app, [ diff --git a/tests/unit/test_image_digest_pin.py b/tests/unit/test_image_digest_pin.py new file mode 100644 index 0000000..9171be5 --- /dev/null +++ b/tests/unit/test_image_digest_pin.py @@ -0,0 +1,86 @@ +"""Tests for the engine-image security fixes: + +FINDING 5 - engine containers must not default to host IPC namespace. +FINDING 4 - optional digest-pin verification of the launched image. +""" +from unittest.mock import MagicMock + +import pytest + +from berth.backends.vllm import VLLMBackend +from berth.lifecycle.docker_client import DockerClient, ImageDigestMismatch +from berth.lifecycle.plan import DeploymentPlan + + +def _plan(**overrides): + base = dict( + model_name="llama-1b", + hf_repo="meta-llama/Llama-3.2-1B-Instruct", + revision="main", + backend="vllm", + image_tag="vllm/vllm-openai:v0.7.3", + gpu_ids=[0], + max_model_len=8192, + target_concurrency=8, + ) + base.update(overrides) + return DeploymentPlan(**base) + + +# --- FINDING 5: no host IPC by default --------------------------------------- + +def test_default_container_kwargs_not_host_ipc(): + kw = VLLMBackend().container_kwargs(_plan()) + assert kw.get("ipc_mode") != "host" + # The private shm_size still covers the single-container case. + assert kw["shm_size"] == "2g" + + +# --- FINDING 4: digest-pin verification -------------------------------------- + +def _client_with_image(image_id, repo_digests=None): + client = MagicMock() + container = MagicMock() + container.id = "abc123" + image = MagicMock() + image.id = image_id + image.attrs = {"RepoDigests": repo_digests or []} + container.image = image + client.containers.get.return_value = container + return client + + +def test_verify_image_digest_passes_on_match(): + digest = "sha256:" + "a" * 64 + dc = DockerClient(client=_client_with_image(digest), network_name="berth-engines") + # Must not raise when the running image id matches the pinned digest. + dc.verify_image_digest("abc123", digest) + + +def test_verify_image_digest_raises_on_mismatch(): + running = "sha256:" + "a" * 64 + pinned = "sha256:" + "b" * 64 + dc = DockerClient(client=_client_with_image(running), network_name="berth-engines") + with pytest.raises(ImageDigestMismatch, match="digest mismatch"): + dc.verify_image_digest("abc123", pinned) + + +def test_verify_image_digest_accepts_repo_digest(): + pinned = "sha256:" + "c" * 64 + repo = f"vllm/vllm-openai@{pinned}" + dc = DockerClient( + client=_client_with_image("sha256:" + "9" * 64, repo_digests=[repo]), + network_name="berth-engines", + ) + # Operator pinned the registry repo-digest rather than the local image id. + dc.verify_image_digest("abc123", pinned) + + +def test_verify_image_digest_raises_when_container_gone(): + from docker.errors import NotFound + + client = MagicMock() + client.containers.get.side_effect = NotFound("gone") + dc = DockerClient(client=client, network_name="berth-engines") + with pytest.raises(ImageDigestMismatch): + dc.verify_image_digest("abc123", "sha256:" + "d" * 64) diff --git a/tests/unit/test_metrics_auth.py b/tests/unit/test_metrics_auth.py index c205d1d..7b0e3be 100644 --- a/tests/unit/test_metrics_auth.py +++ b/tests/unit/test_metrics_auth.py @@ -47,9 +47,9 @@ async def test_metrics_requires_auth_when_keys_exist(tmp_path): @pytest.mark.asyncio -async def test_metrics_with_valid_key_returns_200(tmp_path): +async def test_metrics_with_admin_key_returns_200(tmp_path): app, conn = _public_app(tmp_path) - secret, _ = ak_store.create(conn, name="scraper", tier="standard") + secret, _ = ak_store.create(conn, name="scraper", tier="admin") transport = httpx.ASGITransport(app=app) async with httpx.AsyncClient( transport=transport, base_url="http://1.2.3.4", @@ -60,3 +60,19 @@ async def test_metrics_with_valid_key_returns_200(tmp_path): ) assert r.status_code == 200 assert b"berth_" in r.content + + +@pytest.mark.asyncio +async def test_metrics_rejects_non_admin_key(tmp_path): + """A low-tier tenant key must not be able to scrape cluster inventory.""" + app, conn = _public_app(tmp_path) + secret, _ = ak_store.create(conn, name="tenant", tier="standard") + transport = httpx.ASGITransport(app=app) + async with httpx.AsyncClient( + transport=transport, base_url="http://1.2.3.4", + ) as c: + r = await c.get( + "/metrics", + headers={"Authorization": f"Bearer {secret}"}, + ) + assert r.status_code == 403 diff --git a/tests/unit/test_net_guard.py b/tests/unit/test_net_guard.py new file mode 100644 index 0000000..a3def7a --- /dev/null +++ b/tests/unit/test_net_guard.py @@ -0,0 +1,57 @@ +from __future__ import annotations + +from dataclasses import dataclass + +import pytest + +from berth.net_guard import assert_dialable_engine, is_blocked_adopted_address + + +@dataclass +class _Dep: + source: str + container_address: str | None + + +@pytest.mark.parametrize( + "addr", + [ + "169.254.169.254", # cloud metadata endpoint + "169.254.0.1", # link-local + "224.0.0.1", # multicast + "0.0.0.0", # unspecified + ], +) +def test_blocked_addresses(addr): + assert is_blocked_adopted_address(addr) is True + + +@pytest.mark.parametrize( + "addr", + [ + "127.0.0.1", # loopback — adopt-localhost is legitimate + "10.1.2.3", # private — adopt-LAN + "172.17.0.2", # docker bridge + "engine-abc", # container name / hostname + "tunnel", # remote sentinel + None, + "", + ], +) +def test_allowed_addresses(addr): + assert is_blocked_adopted_address(addr) is False + + +def test_assert_dialable_managed_is_noop(): + # Managed deployments carry a berth-derived address: never blocked, even + # if it somehow parses as a sensitive range. + assert_dialable_engine(_Dep(source="managed", container_address="169.254.169.254")) + + +def test_assert_dialable_adopted_unsafe_raises(): + with pytest.raises(ValueError): + assert_dialable_engine(_Dep(source="adopted", container_address="169.254.169.254")) + + +def test_assert_dialable_adopted_safe_ok(): + assert_dialable_engine(_Dep(source="adopted", container_address="10.0.0.5")) diff --git a/tests/unit/test_sglang_backend.py b/tests/unit/test_sglang_backend.py index 9d19821..bcf4133 100644 --- a/tests/unit/test_sglang_backend.py +++ b/tests/unit/test_sglang_backend.py @@ -55,7 +55,9 @@ def test_build_argv_tp_4(): def test_container_kwargs_gpu_request(): kw = SGLangBackend().container_kwargs(_plan(gpu_ids=[2, 3], tensor_parallel=2)) assert kw["device_requests"][0]["device_ids"] == ["2", "3"] - assert kw["ipc_mode"] == "host" + # Host IPC is no longer the default (weakens container/host isolation); + # the private shm_size covers the single-container case. + assert kw.get("ipc_mode") != "host" assert kw["shm_size"] == "2g" diff --git a/tests/unit/test_trtllm_backend.py b/tests/unit/test_trtllm_backend.py index fccee1d..bbd7ea9 100644 --- a/tests/unit/test_trtllm_backend.py +++ b/tests/unit/test_trtllm_backend.py @@ -55,7 +55,9 @@ def test_build_argv_tp_4(): def test_container_kwargs_gpu_request(): kw = TRTLLMBackend().container_kwargs(_plan(gpu_ids=[2, 3], tensor_parallel=2)) assert kw["device_requests"][0]["device_ids"] == ["2", "3"] - assert kw["ipc_mode"] == "host" + # Host IPC is no longer the default (weakens container/host isolation); + # the private shm_size covers the single-container case. + assert kw.get("ipc_mode") != "host" assert kw["shm_size"] == "2g" assert kw["ulimits"][0].name == "memlock" diff --git a/tests/unit/test_vllm_backend.py b/tests/unit/test_vllm_backend.py index 5d46234..1f120be 100644 --- a/tests/unit/test_vllm_backend.py +++ b/tests/unit/test_vllm_backend.py @@ -51,7 +51,9 @@ def test_build_argv_tp_4(): def test_container_kwargs_gpu_request(): kw = VLLMBackend().container_kwargs(_plan(gpu_ids=[2, 3], tensor_parallel=2)) assert kw["device_requests"][0]["device_ids"] == ["2", "3"] - assert kw["ipc_mode"] == "host" + # Host IPC is no longer the default (weakens container/host isolation); + # the private shm_size covers the single-container case. + assert kw.get("ipc_mode") != "host" assert kw["shm_size"] == "2g" assert kw["ulimits"][0].name == "memlock" diff --git a/tests/unit/test_wipe_cmd.py b/tests/unit/test_wipe_cmd.py index 10f0fca..2e18323 100644 --- a/tests/unit/test_wipe_cmd.py +++ b/tests/unit/test_wipe_cmd.py @@ -13,6 +13,46 @@ def test_wipe_refuses_broad_paths(): assert "refusing to wipe broad path" in result.output +def test_wipe_refuses_plain_home_without_marker(monkeypatch, tmp_path): + # A real user home: deep enough to clear the denylist, but with no berth + # marker. It must be refused so `--home /home/alice` can't rm -rf a home. + home = tmp_path / "alice" + (home / "Documents").mkdir(parents=True) + (home / "Documents" / "thesis.txt").write_text("important") + (home / ".bashrc").write_text("export PATH=...") + + # Ensure the configured BERTH_DIR doesn't happen to match this path. + monkeypatch.setattr(wipe_cmd.config, "BERTH_DIR", tmp_path / "real-berth") + + # Wide terminal so Rich doesn't wrap/truncate the error panel mid-phrase. + result = CliRunner().invoke( + cli.app, ["wipe", "--home", str(home), "--yes"], + env={"COLUMNS": "200"}, + ) + + assert result.exit_code != 0 + assert "does not look like a berth home" in result.output + # Nothing was deleted. + assert (home / "Documents" / "thesis.txt").exists() + assert (home / ".bashrc").exists() + + +def test_wipe_allows_dotberth_named_dir(monkeypatch, tmp_path): + # A directory named .berth is accepted even without a marker file. + home = tmp_path / ".berth" + home.mkdir() + (home / "logs").mkdir() + + monkeypatch.setattr(wipe_cmd, "_stop_systemd_service", lambda: None) + monkeypatch.setattr(wipe_cmd, "_stop_pid_daemon", lambda home: None) + monkeypatch.setattr(wipe_cmd, "_remove_berth_docker", lambda: []) + monkeypatch.setattr(wipe_cmd.config, "BERTH_DIR", tmp_path / "real-berth") + + result = CliRunner().invoke(cli.app, ["wipe", "--home", str(home), "--yes"]) + + assert result.exit_code == 0, result.output + + def test_wipe_clears_home_with_yes(monkeypatch, tmp_path): home = tmp_path / "berth-home" (home / "models").mkdir(parents=True) diff --git a/ui/src/api.ts b/ui/src/api.ts index 241aab7..dcc6d22 100644 --- a/ui/src/api.ts +++ b/ui/src/api.ts @@ -1,15 +1,21 @@ const TOKEN_KEY = 'berth.adminToken' +// The admin token is a long-lived, high-privilege credential. We store it in +// sessionStorage (not localStorage) so it is scoped to the tab/session and is +// cleared when the tab or browser closes. This shrinks the durable-theft window +// from an XSS or a malicious extension: a stolen token can no longer be +// exfiltrated from a persistent store across browser restarts. Callers must go +// through these helpers and never touch the backing store directly. export function getToken(): string | null { - return localStorage.getItem(TOKEN_KEY) + return sessionStorage.getItem(TOKEN_KEY) } export function setToken(t: string) { - localStorage.setItem(TOKEN_KEY, t) + sessionStorage.setItem(TOKEN_KEY, t) } export function clearToken() { - localStorage.removeItem(TOKEN_KEY) + sessionStorage.removeItem(TOKEN_KEY) } export const queryKeys = { @@ -45,6 +51,19 @@ export async function eventSourceUrl(path: string): Promise { const ticket = await api.createStreamToken( new URL(path, window.location.origin).pathname, ) + // The stream ticket is passed in the query string because the browser + // EventSource API cannot set request headers (no Authorization header). + // This is acceptable because the ticket issued by /admin/stream-token is + // single-use, short-TTL (~60s), and path-bound server-side, so even if it + // leaks it is of very limited value. NOTE for operators: reverse proxies / + // gateways in front of berth should NOT log query strings, to avoid the + // ticket landing in access logs. + // + // A fetch()-based SSE reader (see streamChat in views/Playground.tsx, which + // manually parses the response body and sends a real Authorization header) + // would remove the URL credential entirely. Migrating these EventSource + // calls to that pattern is the proper long-term fix, but is intentionally + // left out of scope here to keep behavior unchanged. const sep = path.includes('?') ? '&' : '?' return `${path}${sep}stream_token=${encodeURIComponent(ticket.token)}` }