aigetwey 1.3.6 → 1.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/dashboard/.next/BUILD_ID +1 -1
  3. package/dashboard/.next/build-manifest.json +3 -3
  4. package/dashboard/.next/diagnostics/route-bundle-stats.json +10 -10
  5. package/dashboard/.next/fallback-build-manifest.json +3 -3
  6. package/dashboard/.next/server/app/(console)/combos/page_client-reference-manifest.js +1 -1
  7. package/dashboard/.next/server/app/(console)/config/page_client-reference-manifest.js +1 -1
  8. package/dashboard/.next/server/app/(console)/console/page_client-reference-manifest.js +1 -1
  9. package/dashboard/.next/server/app/(console)/endpoint/page_client-reference-manifest.js +1 -1
  10. package/dashboard/.next/server/app/(console)/page_client-reference-manifest.js +1 -1
  11. package/dashboard/.next/server/app/(console)/providers/[id]/page_client-reference-manifest.js +1 -1
  12. package/dashboard/.next/server/app/(console)/providers/page_client-reference-manifest.js +1 -1
  13. package/dashboard/.next/server/app/(console)/quota/page_client-reference-manifest.js +1 -1
  14. package/dashboard/.next/server/app/(console)/tools/[id]/page_client-reference-manifest.js +1 -1
  15. package/dashboard/.next/server/app/(console)/tools/page_client-reference-manifest.js +1 -1
  16. package/dashboard/.next/server/app/(console)/usage/page_client-reference-manifest.js +1 -1
  17. package/dashboard/.next/server/app/_global-error.html +1 -1
  18. package/dashboard/.next/server/app/_global-error.rsc +1 -1
  19. package/dashboard/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  20. package/dashboard/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  21. package/dashboard/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  22. package/dashboard/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  23. package/dashboard/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  24. package/dashboard/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  25. package/dashboard/.next/server/app/_not-found.html +1 -1
  26. package/dashboard/.next/server/app/_not-found.rsc +2 -2
  27. package/dashboard/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  28. package/dashboard/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  29. package/dashboard/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  30. package/dashboard/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  31. package/dashboard/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  32. package/dashboard/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  33. package/dashboard/.next/server/app/combos.html +1 -1
  34. package/dashboard/.next/server/app/combos.rsc +2 -2
  35. package/dashboard/.next/server/app/combos.segments/!KGNvbnNvbGUp/combos/__PAGE__.segment.rsc +1 -1
  36. package/dashboard/.next/server/app/combos.segments/!KGNvbnNvbGUp/combos.segment.rsc +1 -1
  37. package/dashboard/.next/server/app/combos.segments/!KGNvbnNvbGUp.segment.rsc +1 -1
  38. package/dashboard/.next/server/app/combos.segments/_full.segment.rsc +2 -2
  39. package/dashboard/.next/server/app/combos.segments/_head.segment.rsc +1 -1
  40. package/dashboard/.next/server/app/combos.segments/_index.segment.rsc +2 -2
  41. package/dashboard/.next/server/app/combos.segments/_tree.segment.rsc +2 -2
  42. package/dashboard/.next/server/app/config.html +1 -1
  43. package/dashboard/.next/server/app/config.rsc +2 -2
  44. package/dashboard/.next/server/app/config.segments/!KGNvbnNvbGUp/config/__PAGE__.segment.rsc +1 -1
  45. package/dashboard/.next/server/app/config.segments/!KGNvbnNvbGUp/config.segment.rsc +1 -1
  46. package/dashboard/.next/server/app/config.segments/!KGNvbnNvbGUp.segment.rsc +1 -1
  47. package/dashboard/.next/server/app/config.segments/_full.segment.rsc +2 -2
  48. package/dashboard/.next/server/app/config.segments/_head.segment.rsc +1 -1
  49. package/dashboard/.next/server/app/config.segments/_index.segment.rsc +2 -2
  50. package/dashboard/.next/server/app/config.segments/_tree.segment.rsc +2 -2
  51. package/dashboard/.next/server/app/console.html +1 -1
  52. package/dashboard/.next/server/app/console.rsc +2 -2
  53. package/dashboard/.next/server/app/console.segments/!KGNvbnNvbGUp/console/__PAGE__.segment.rsc +1 -1
  54. package/dashboard/.next/server/app/console.segments/!KGNvbnNvbGUp/console.segment.rsc +1 -1
  55. package/dashboard/.next/server/app/console.segments/!KGNvbnNvbGUp.segment.rsc +1 -1
  56. package/dashboard/.next/server/app/console.segments/_full.segment.rsc +2 -2
  57. package/dashboard/.next/server/app/console.segments/_head.segment.rsc +1 -1
  58. package/dashboard/.next/server/app/console.segments/_index.segment.rsc +2 -2
  59. package/dashboard/.next/server/app/console.segments/_tree.segment.rsc +2 -2
  60. package/dashboard/.next/server/app/endpoint.html +1 -1
  61. package/dashboard/.next/server/app/endpoint.rsc +3 -3
  62. package/dashboard/.next/server/app/endpoint.segments/!KGNvbnNvbGUp/endpoint/__PAGE__.segment.rsc +2 -2
  63. package/dashboard/.next/server/app/endpoint.segments/!KGNvbnNvbGUp/endpoint.segment.rsc +1 -1
  64. package/dashboard/.next/server/app/endpoint.segments/!KGNvbnNvbGUp.segment.rsc +1 -1
  65. package/dashboard/.next/server/app/endpoint.segments/_full.segment.rsc +3 -3
  66. package/dashboard/.next/server/app/endpoint.segments/_head.segment.rsc +1 -1
  67. package/dashboard/.next/server/app/endpoint.segments/_index.segment.rsc +2 -2
  68. package/dashboard/.next/server/app/endpoint.segments/_tree.segment.rsc +2 -2
  69. package/dashboard/.next/server/app/index.html +1 -1
  70. package/dashboard/.next/server/app/index.rsc +3 -3
  71. package/dashboard/.next/server/app/index.segments/!KGNvbnNvbGUp/__PAGE__.segment.rsc +2 -2
  72. package/dashboard/.next/server/app/index.segments/!KGNvbnNvbGUp.segment.rsc +1 -1
  73. package/dashboard/.next/server/app/index.segments/_full.segment.rsc +3 -3
  74. package/dashboard/.next/server/app/index.segments/_head.segment.rsc +1 -1
  75. package/dashboard/.next/server/app/index.segments/_index.segment.rsc +2 -2
  76. package/dashboard/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  77. package/dashboard/.next/server/app/login/page_client-reference-manifest.js +1 -1
  78. package/dashboard/.next/server/app/login.html +1 -1
  79. package/dashboard/.next/server/app/login.rsc +2 -2
  80. package/dashboard/.next/server/app/login.segments/_full.segment.rsc +2 -2
  81. package/dashboard/.next/server/app/login.segments/_head.segment.rsc +1 -1
  82. package/dashboard/.next/server/app/login.segments/_index.segment.rsc +2 -2
  83. package/dashboard/.next/server/app/login.segments/_tree.segment.rsc +2 -2
  84. package/dashboard/.next/server/app/login.segments/login/__PAGE__.segment.rsc +1 -1
  85. package/dashboard/.next/server/app/login.segments/login.segment.rsc +1 -1
  86. package/dashboard/.next/server/app/providers.html +1 -1
  87. package/dashboard/.next/server/app/providers.rsc +3 -3
  88. package/dashboard/.next/server/app/providers.segments/!KGNvbnNvbGUp/providers/__PAGE__.segment.rsc +2 -2
  89. package/dashboard/.next/server/app/providers.segments/!KGNvbnNvbGUp/providers.segment.rsc +1 -1
  90. package/dashboard/.next/server/app/providers.segments/!KGNvbnNvbGUp.segment.rsc +1 -1
  91. package/dashboard/.next/server/app/providers.segments/_full.segment.rsc +3 -3
  92. package/dashboard/.next/server/app/providers.segments/_head.segment.rsc +1 -1
  93. package/dashboard/.next/server/app/providers.segments/_index.segment.rsc +2 -2
  94. package/dashboard/.next/server/app/providers.segments/_tree.segment.rsc +2 -2
  95. package/dashboard/.next/server/app/quota.html +1 -1
  96. package/dashboard/.next/server/app/quota.rsc +2 -2
  97. package/dashboard/.next/server/app/quota.segments/!KGNvbnNvbGUp/quota/__PAGE__.segment.rsc +1 -1
  98. package/dashboard/.next/server/app/quota.segments/!KGNvbnNvbGUp/quota.segment.rsc +1 -1
  99. package/dashboard/.next/server/app/quota.segments/!KGNvbnNvbGUp.segment.rsc +1 -1
  100. package/dashboard/.next/server/app/quota.segments/_full.segment.rsc +2 -2
  101. package/dashboard/.next/server/app/quota.segments/_head.segment.rsc +1 -1
  102. package/dashboard/.next/server/app/quota.segments/_index.segment.rsc +2 -2
  103. package/dashboard/.next/server/app/quota.segments/_tree.segment.rsc +2 -2
  104. package/dashboard/.next/server/app/tools.html +1 -1
  105. package/dashboard/.next/server/app/tools.rsc +2 -2
  106. package/dashboard/.next/server/app/tools.segments/!KGNvbnNvbGUp/tools/__PAGE__.segment.rsc +1 -1
  107. package/dashboard/.next/server/app/tools.segments/!KGNvbnNvbGUp/tools.segment.rsc +1 -1
  108. package/dashboard/.next/server/app/tools.segments/!KGNvbnNvbGUp.segment.rsc +1 -1
  109. package/dashboard/.next/server/app/tools.segments/_full.segment.rsc +2 -2
  110. package/dashboard/.next/server/app/tools.segments/_head.segment.rsc +1 -1
  111. package/dashboard/.next/server/app/tools.segments/_index.segment.rsc +2 -2
  112. package/dashboard/.next/server/app/tools.segments/_tree.segment.rsc +2 -2
  113. package/dashboard/.next/server/chunks/[root-of-the-server]__043un18._.js +1 -1
  114. package/dashboard/.next/server/chunks/[root-of-the-server]__043un18._.js.map +1 -1
  115. package/dashboard/.next/server/chunks/_0digmky._.js +1 -1
  116. package/dashboard/.next/server/chunks/_0digmky._.js.map +1 -1
  117. package/dashboard/.next/server/chunks/ssr/_1mumvwn._.js +1 -1
  118. package/dashboard/.next/server/chunks/ssr/_1mumvwn._.js.map +1 -1
  119. package/dashboard/.next/server/chunks/ssr/src_components_0nuo5yx._.js +1 -1
  120. package/dashboard/.next/server/chunks/ssr/src_components_0nuo5yx._.js.map +1 -1
  121. package/dashboard/.next/server/chunks/ssr/src_components_EndpointView_tsx_0awdzb5._.js +1 -1
  122. package/dashboard/.next/server/chunks/ssr/src_components_EndpointView_tsx_0awdzb5._.js.map +1 -1
  123. package/dashboard/.next/server/chunks/ssr/src_components_ProviderDetail_tsx_06sxu0r._.js +1 -1
  124. package/dashboard/.next/server/chunks/ssr/src_components_ProviderDetail_tsx_06sxu0r._.js.map +1 -1
  125. package/dashboard/.next/server/chunks/ssr/src_components_ToolDetail_tsx_0qperd-._.js +1 -1
  126. package/dashboard/.next/server/chunks/ssr/src_components_ToolDetail_tsx_0qperd-._.js.map +1 -1
  127. package/dashboard/.next/server/middleware-build-manifest.js +3 -3
  128. package/dashboard/.next/server/pages/404.html +1 -1
  129. package/dashboard/.next/server/pages/500.html +1 -1
  130. package/dashboard/.next/static/chunks/03o9w8fy3awov.css +3 -0
  131. package/dashboard/.next/static/chunks/{0_fo_1xhw25rd.js → 063d_vdu_m-g_.js} +1 -1
  132. package/dashboard/.next/static/chunks/{3i6nr2y3h_7s2.js → 0tq5u12liycmg.js} +1 -1
  133. package/dashboard/.next/static/chunks/{00415cmd3ji2s.js → 16vbdc0g5xea0.js} +1 -1
  134. package/dashboard/.next/static/chunks/{05i93ivai9obr.js → 3mhsmb2ks1vev.js} +1 -1
  135. package/dashboard/.next/trace +1 -1
  136. package/dashboard/.next/trace-build +1 -1
  137. package/dashboard/src/components/EndpointView.tsx +13 -7
  138. package/dashboard/src/components/ProviderDetail.tsx +1 -1
  139. package/dashboard/src/components/ProviderManager.tsx +1 -1
  140. package/dashboard/src/components/ToolDetail.tsx +160 -20
  141. package/dashboard/src/lib/session.ts +6 -1
  142. package/dist/cli.js +1 -1
  143. package/dist/cli.js.map +1 -1
  144. package/package.json +1 -1
  145. package/src/cli.ts +1 -1
  146. package/dashboard/.next/static/chunks/2284qz1hy9776.css +0 -3
  147. /package/dashboard/.next/static/{kpgVHg6Rdnh2YUO8-xGjX → BHVoneq9_CCAAPwET7GfO}/_buildManifest.js +0 -0
  148. /package/dashboard/.next/static/{kpgVHg6Rdnh2YUO8-xGjX → BHVoneq9_CCAAPwET7GfO}/_clientMiddlewareManifest.js +0 -0
  149. /package/dashboard/.next/static/{kpgVHg6Rdnh2YUO8-xGjX → BHVoneq9_CCAAPwET7GfO}/_ssgManifest.js +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/components/EndpointView.tsx","../../../../src/components/KeyReveal.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState, useCallback } from \"react\";\nimport { adminApi } from \"@/lib/client\";\nimport { Badge } from \"@/components/Badge\";\nimport { RichCard, CardTitle } from \"@/components/RichCard\";\nimport { Button, Input } from \"@/components/Button\";\nimport { Icon } from \"@/components/Icon\";\nimport { KeyReveal } from \"@/components/KeyReveal\";\nimport { Empty, fmt } from \"@/components/ui\";\nimport { ModelPicker, type ModelGroup } from \"@/components/ModelPicker\";\nimport { ConfirmModal } from \"@/components/ConfirmModal\";\nimport type { EndpointPayload, HeadroomStatusReply, InjectLevel, MaskedConfig } from \"@/lib/gateway\";\n\nconst LEVELS: InjectLevel[] = [\"off\", \"lite\", \"full\", \"ultra\"];\n\n/** Segment-pill style — matches the Budgets page pills. */\nconst pill = (active: boolean): string =>\n `rounded-brand px-3 py-1.5 text-[13px] font-medium transition-colors ${\n active ? \"bg-accent/12 text-accent\" : \"bg-surface-2 text-text-muted hover:text-text\"\n }`;\n\nconst DAY_MS = 86_400_000;\nconst EXPIRY_MS: Record<\"24h\" | \"7day\" | \"30day\", number> = {\n \"24h\": DAY_MS,\n \"7day\": 7 * DAY_MS,\n \"30day\": 30 * DAY_MS,\n};\n\n/** Generate a random gateway key client-side (aigetwey's one-click create). */\nfunction generateKey(): string {\n const bytes = new Uint8Array(24);\n crypto.getRandomValues(bytes);\n const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n return `aig-${hex}`;\n}\n\nexport function EndpointView() {\n const [ep, setEp] = useState<EndpointPayload | null>(null);\n const [error, setError] = useState(\"\");\n const [busy, setBusy] = useState(\"\");\n const [keyName, setKeyName] = useState(\"\");\n const [created, setCreated] = useState<{ key: string; name: string } | null>(null);\n const [pendingDelKey, setPendingDelKey] = useState<{ i: number; label: string } | null>(null);\n const [hr, setHr] = useState<HeadroomStatusReply | null>(null);\n const [editKey, setEditKey] = useState<number | null>(null);\n const [editKeyName, setEditKeyName] = useState(\"\");\n const [groups, setGroups] = useState<ModelGroup[]>([]);\n const [scopeKey, setScopeKey] = useState<number | null>(null);\n const [scopeModels, setScopeModels] = useState<string[]>([]);\n const [scopeRpm, setScopeRpm] = useState(\"\");\n const [scopeExpiry, setScopeExpiry] = useState<\"keep\" | \"never\" | \"24h\" | \"7day\" | \"30day\" | \"custom\">(\"never\");\n const [scopeCustomDays, setScopeCustomDays] = useState(\"\");\n const [scopeLimit, setScopeLimit] = useState(\"\"); // USD limit, \"\" = no cap\n const [scopeWindow, setScopeWindow] = useState<\"5h\" | \"24h\" | \"7day\" | \"30day\">(\"30day\");\n const [keyBudgets, setKeyBudgets] = useState<Record<string, { limit: number; window: string }>>({});\n const [pickerOpen, setPickerOpen] = useState(false);\n\n const reload = useCallback(async () => {\n const r = await adminApi.endpoint();\n if (!r.ok) {\n setError(r.error ?? \"could not reach the gateway\");\n return;\n }\n setError(\"\");\n setEp(r.data);\n }, []);\n\n // Headroom status is a live probe (installed/running/python), separate from the\n // endpoint config — reload it on mount and after any headroom action.\n const reloadHr = useCallback(async () => {\n const r = await adminApi.headroomStatus();\n if (r.ok) setHr(r.data);\n }, []);\n\n useEffect(() => {\n void reload();\n void reloadHr();\n // load the model catalog for the per-key scope picker (combos + provider/model refs).\n void (async () => {\n try {\n const res = await fetch(\"/api/gw/admin/config\");\n if (!res.ok) return;\n const cfg = (await res.json()) as MaskedConfig;\n const grps: ModelGroup[] = [];\n if (cfg.models.length) grps.push({ label: \"Combos\", items: cfg.models.map((m) => ({ value: m.alias, label: m.alias })) });\n for (const p of cfg.providers) {\n if (p.models.length) grps.push({ label: p.id, items: p.models.map((m) => ({ value: `${p.id}/${m.id}`, label: `${p.id}/${m.id}` })) });\n }\n setGroups(grps);\n } catch { /* non-critical — picker will just be empty */ }\n })();\n // index existing key-scoped budgets by fingerprint so the modal can prefill.\n void adminApi.budgets().then((r) => {\n if (!r.ok || !r.data) return;\n const map: Record<string, { limit: number; window: string }> = {};\n for (const b of r.data.budgets) {\n if (b.scope.type === \"key\") map[b.scope.id] = { limit: b.limit, window: b.window };\n }\n setKeyBudgets(map);\n });\n }, [reload, reloadHr]);\n\n if (error) return <Empty>{error}</Empty>;\n if (!ep) return <Empty>Loading…</Empty>;\n\n const baseUrl = `http://127.0.0.1:${ep.port}`;\n\n async function run(label: string, fn: () => Promise<{ ok: boolean; error?: string }>) {\n setBusy(label);\n const r = await fn();\n setBusy(\"\");\n if (!r.ok) setError(r.error ?? \"action failed\");\n else {\n setError(\"\");\n await reload();\n }\n }\n\n // Create a key (generated or pasted) with its label, then surface it once in a\n // modal — aigetwey, where the full key is shown at creation time.\n async function addKey(label: string, rawKey: string) {\n const name = (label || \"Gateway key\").trim();\n setBusy(\"genkey\");\n const r = await adminApi.addServerKey(rawKey, name);\n setBusy(\"\");\n if (!r.ok) {\n setError(r.error ?? \"could not add key\");\n return;\n }\n setError(\"\");\n setKeyName(\"\");\n setCreated({ key: rawKey, name });\n await reload();\n }\n\n return (\n <div>\n <div className=\"mb-6\">\n <h1 className=\"text-[22px] font-semibold tracking-tight text-text\">Endpoint &amp; Key</h1>\n <p className=\"mt-1 text-[13px] text-text-muted\">Gateway address, client keys, and the token-saver toggles.</p>\n </div>\n\n <div className=\"grid gap-4 lg:grid-cols-2\">\n <RichCard header={<CardTitle title=\"Gateway URL\" sub=\"one endpoint for every client\" />}>\n <div className=\"text-[13px]\">\n <CopyRow label=\"Gateway URL\" value={baseUrl} />\n </div>\n <p className=\"mt-3 text-[12px] text-text-subtle\">\n One gateway, both formats. Anthropic clients (Claude Code) use it as-is; OpenAI clients (opencode,\n Cursor, Codex) append <span className=\"tnum\">/v1</span>. The <span className=\"text-text-muted\">CLI Tools</span>{\" \"}\n page has copy-ready env per tool.\n </p>\n </RichCard>\n\n <RichCard header={<CardTitle title=\"Gateway keys\" sub={`${ep.keys.length} configured`} />}>\n {ep.keys.length === 0 ? (\n <Empty>No keys — auth is DISABLED (localhost only). Generate one below.</Empty>\n ) : (\n <div className=\"space-y-1.5\">\n {ep.keys.map((k, i) =>\n editKey === i ? (\n <div key={i} className=\"space-y-2 rounded-brand border border-accent bg-accent-soft/40 px-3 py-2.5\">\n <Input value={editKeyName} onChange={(e) => setEditKeyName(e.target.value)} placeholder=\"key name (e.g. Claude Code)\" />\n <div className=\"flex justify-end gap-2\">\n <Button variant=\"ghost\" onClick={() => setEditKey(null)}>Cancel</Button>\n <Button\n disabled={busy === `editkey${i}`}\n onClick={() =>\n run(`editkey${i}`, async () => {\n const r = await adminApi.editServerKey(i, editKeyName.trim());\n if (r.ok) setEditKey(null);\n return r;\n })\n }\n >\n Save\n </Button>\n </div>\n </div>\n ) : (\n <div key={i} className=\"space-y-0 rounded-brand border border-border-subtle\">\n <div className=\"flex items-center justify-between gap-2 px-3 py-2\">\n <div className=\"flex min-w-0 flex-col gap-0.5\">\n {k.name && <span className=\"text-[12px] font-semibold text-text-muted\">{k.name}</span>}\n <KeyReveal\n masked={k.key}\n reveal={async () => {\n const r = await adminApi.revealServerKey(i);\n return r.ok ? r.data?.key ?? null : null;\n }}\n />\n <div className=\"mt-0.5 flex flex-wrap items-center gap-1.5 text-[11px] text-text-subtle\">\n <span>{k.models?.length ? `${k.models.length} model${k.models.length > 1 ? \"s\" : \"\"}` : \"all models\"}</span>\n <span>·</span>\n <span>{k.rpm ? `${k.rpm}/min` : \"no rate limit\"}</span>\n <span>·</span>\n <span>\n {k.expires\n ? (Date.now() > k.expires ? <span className=\"text-danger\">expired</span> : `expires ${fmt.date(k.expires)}`)\n : \"no expiry\"}\n </span>\n </div>\n </div>\n <div className=\"flex flex-none items-center gap-1\">\n <button\n onClick={() => {\n setScopeKey(i);\n setScopeModels(k.models ?? []);\n setScopeRpm(k.rpm ? String(k.rpm) : \"\");\n setScopeExpiry(k.expires ? \"keep\" : \"never\");\n setScopeCustomDays(\"\");\n const kb = keyBudgets[k.fingerprint];\n setScopeLimit(kb ? String(kb.limit) : \"\");\n setScopeWindow((kb?.window as \"5h\" | \"24h\" | \"7day\" | \"30day\") ?? \"30day\");\n }}\n className=\"text-text-subtle hover:text-text\"\n aria-label=\"Edit key scope\"\n title=\"Model allowlist + rate limit + budget + expiry\"\n >\n <Icon name=\"tune\" size={15} />\n </button>\n <button\n onClick={() => { setEditKey(i); setEditKeyName(k.name ?? \"\"); }}\n className=\"text-text-subtle hover:text-text\"\n aria-label=\"Rename key\"\n title=\"Rename key\"\n >\n <Icon name=\"edit\" size={15} />\n </button>\n <button onClick={() => setPendingDelKey({ i, label: k.name || k.key })} className=\"text-text-subtle hover:text-danger\" aria-label=\"Remove key\">\n <Icon name=\"delete\" size={16} />\n </button>\n </div>\n </div>\n {scopeKey === i && (\n <div className=\"space-y-2 border-t border-border-subtle bg-accent-soft/40 px-3 py-2.5\">\n <div>\n <div className=\"mb-1 text-[11px] font-medium uppercase tracking-wider text-text-subtle\">Allowed models</div>\n <div className=\"flex flex-wrap items-center gap-1.5\">\n {scopeModels.length === 0 ? (\n <span className=\"text-[12px] text-text-subtle\">All models (unrestricted)</span>\n ) : (\n scopeModels.map((m) => (\n <span key={m} className=\"inline-flex items-center gap-1 rounded border border-accent bg-accent-soft px-2 py-0.5 text-[12px] text-accent\">\n <span className=\"tnum\">{m}</span>\n <button onClick={() => setScopeModels((s) => s.filter((x) => x !== m))} className=\"hover:text-danger\" aria-label={`Remove ${m}`}>\n <Icon name=\"close\" size={12} />\n </button>\n </span>\n ))\n )}\n </div>\n <Button type=\"button\" variant=\"ghost\" className=\"mt-1.5\" onClick={() => setPickerOpen(true)}>\n <Icon name=\"add\" size={15} /> Pick models\n </Button>\n </div>\n <div>\n <div className=\"mb-1 text-[11px] font-medium uppercase tracking-wider text-text-subtle\">Rate limit</div>\n <Input\n inputMode=\"numeric\"\n value={scopeRpm}\n onChange={(e) => setScopeRpm(e.target.value.replace(/[^\\d]/g, \"\"))}\n placeholder=\"req/min (blank = unlimited)\"\n />\n </div>\n <div>\n <div className=\"mb-1 text-[11px] font-medium uppercase tracking-wider text-text-subtle\">Access expiry</div>\n {k.expires && (\n <div className=\"mb-1.5 text-[11px] text-text-subtle\">\n currently {Date.now() > k.expires ? <span className=\"text-danger\">expired</span> : `expires ${fmt.date(k.expires)}`}\n </div>\n )}\n <div className=\"flex flex-wrap gap-1\">\n {(k.expires\n ? ([\"keep\", \"never\", \"24h\", \"7day\", \"30day\", \"custom\"] as const)\n : ([\"never\", \"24h\", \"7day\", \"30day\", \"custom\"] as const)\n ).map((opt) => (\n <button\n key={opt}\n type=\"button\"\n onClick={() => setScopeExpiry(opt)}\n className={pill(scopeExpiry === opt)}\n >\n {opt === \"never\" ? \"no expiry\" : opt}\n </button>\n ))}\n </div>\n {scopeExpiry === \"custom\" && (\n <div className=\"mt-1.5 flex items-center gap-1.5\">\n <Input\n inputMode=\"numeric\"\n value={scopeCustomDays}\n onChange={(e) => setScopeCustomDays(e.target.value.replace(/[^\\d]/g, \"\"))}\n placeholder=\"days\"\n className=\"w-24\"\n />\n <span className=\"text-[11px] text-text-subtle\">days from now</span>\n </div>\n )}\n </div>\n <div>\n <div className=\"mb-1 text-[11px] font-medium uppercase tracking-wider text-text-subtle\">Spend cap (USD)</div>\n <Input\n inputMode=\"decimal\"\n value={scopeLimit}\n onChange={(e) => setScopeLimit(e.target.value.replace(/[^\\d.]/g, \"\"))}\n placeholder=\"USD (blank = no cap)\"\n />\n {scopeLimit && (\n <div className=\"mt-1.5 flex items-center gap-1.5\">\n <span className=\"text-[11px] text-text-subtle\">resets every</span>\n {([\"5h\", \"24h\", \"7day\", \"30day\"] as const).map((w) => (\n <button\n key={w}\n type=\"button\"\n onClick={() => setScopeWindow(w)}\n className={pill(scopeWindow === w)}\n >\n {w}\n </button>\n ))}\n </div>\n )}\n </div>\n <div className=\"flex justify-end gap-2\">\n <Button variant=\"ghost\" onClick={() => setScopeKey(null)}>Cancel</Button>\n <Button\n disabled={busy === `scope${i}`}\n onClick={() =>\n run(`scope${i}`, async () => {\n // \"keep\" leaves expiry untouched (omit); \"never\" clears; a duration sets now+N.\n const expires =\n scopeExpiry === \"keep\" ? undefined\n : scopeExpiry === \"never\" ? null\n : scopeExpiry === \"custom\" ? (scopeCustomDays ? Date.now() + Number(scopeCustomDays) * DAY_MS : null)\n : Date.now() + EXPIRY_MS[scopeExpiry];\n const r = await adminApi.setServerKeyScope(i, {\n models: scopeModels,\n rpm: scopeRpm ? Number(scopeRpm) : null,\n expires,\n });\n if (!r.ok) return r;\n const limit = scopeLimit ? Number(scopeLimit) : 0;\n if (limit > 0) {\n await adminApi.setBudget({ scope: { type: \"key\", id: k.fingerprint }, unit: \"usd\", limit, window: scopeWindow });\n } else if (keyBudgets[k.fingerprint]) {\n await adminApi.clearBudget(`key:${k.fingerprint}`);\n }\n setScopeKey(null);\n return r;\n })\n }\n >\n Save\n </Button>\n </div>\n </div>\n )}\n </div>\n ),\n )}\n </div>\n )}\n <div className=\"mt-3 space-y-2\">\n <div className=\"flex gap-2\">\n <Input value={keyName} onChange={(e) => setKeyName(e.target.value)} placeholder=\"key name (e.g. Claude Code)\" className=\"flex-1\" />\n <Button disabled={busy === \"genkey\"} onClick={() => addKey(keyName, generateKey())}>\n <Icon name=\"add\" size={16} /> {busy === \"genkey\" ? \"Adding…\" : \"Add key\"}\n </Button>\n </div>\n <p className=\"text-[11px] text-text-subtle\">Name it, then click Add key — a key is generated and shown once. Configure its limits after.</p>\n </div>\n </RichCard>\n\n <RichCard className=\"lg:col-span-2\" header={<CardTitle title=\"Token savers\" sub=\"applied to every request before routing\" />}>\n <div className=\"space-y-4\">\n <Toggle\n label=\"RTK\"\n desc=\"Compress bulky tool_result blocks (diffs, grep, listings) in the request.\"\n on={ep.rtk}\n busy={busy === \"rtk\"}\n onChange={(v) => run(\"rtk\", () => adminApi.setRtk(v))}\n />\n <LevelRow\n label=\"Caveman\"\n desc=\"Terser model output — drops filler, keeps substance.\"\n value={ep.caveman}\n busy={busy === \"caveman\"}\n onChange={(lvl) => run(\"caveman\", () => adminApi.setCaveman(lvl))}\n />\n <LevelRow\n label=\"Ponytail\"\n desc=\"Minimal, YAGNI code style — deletion over addition.\"\n value={ep.ponytail}\n busy={busy === \"ponytail\"}\n onChange={(lvl) => run(\"ponytail\", () => adminApi.setPonytail(lvl))}\n />\n </div>\n </RichCard>\n\n <HeadroomCard\n ep={ep}\n hr={hr}\n refresh={async () => {\n await reload();\n await reloadHr();\n }}\n />\n </div>\n\n {created && <KeyCreatedModal name={created.name} value={created.key} onClose={() => setCreated(null)} />}\n {pendingDelKey && (\n <ConfirmModal\n title=\"Remove gateway key\"\n message={`Delete \"${pendingDelKey.label}\"? Any client using this key stops working immediately.`}\n confirmLabel=\"Remove\"\n busy={busy === `rmkey${pendingDelKey.i}`}\n onCancel={() => setPendingDelKey(null)}\n onConfirm={() => {\n const i = pendingDelKey.i;\n void run(`rmkey${i}`, () => adminApi.removeServerKey(i)).then(() => setPendingDelKey(null));\n }}\n />\n )}\n {pickerOpen && (\n <ModelPicker\n title=\"Allowed models\"\n note=\"Pick the models this key may call. None = all.\"\n groups={groups}\n selected={scopeModels}\n onToggle={(v) => setScopeModels((s) => s.includes(v) ? s.filter((x) => x !== v) : [...s, v])}\n onClose={() => setPickerOpen(false)}\n showThinkingHint={false}\n />\n )}\n </div>\n );\n}\n\n/**\n * Headroom = external context-compression proxy. Status is a live probe; the\n * enable/url/compress fields persist to endpoint config; Start/Stop manage a\n * gateway-spawned proxy when the CLI is installed and the URL is loopback.\n */\nfunction HeadroomCard({\n ep,\n hr,\n refresh,\n}: {\n ep: EndpointPayload;\n hr: HeadroomStatusReply | null;\n refresh: () => Promise<void>;\n}) {\n const h = ep.headroom;\n const [url, setUrl] = useState(h.url);\n const [localBusy, setLocalBusy] = useState(\"\");\n const [msg, setMsg] = useState(\"\");\n const [check, setCheck] = useState<{ ok: boolean; text: string } | null>(null);\n useEffect(() => setUrl(h.url), [h.url]);\n\n async function act(label: string, fn: () => Promise<{ ok: boolean; error?: string }>) {\n setLocalBusy(label);\n setMsg(\"\");\n setCheck(null);\n const r = await fn();\n setLocalBusy(\"\");\n if (!r.ok) setMsg(r.error ?? \"action failed\");\n await refresh();\n }\n\n // Live re-probe: ask the gateway whether the proxy at the configured URL\n // actually answers right now, and surface the result inline.\n async function checkProxy() {\n setLocalBusy(\"check\");\n setMsg(\"\");\n setCheck(null);\n const r = await adminApi.headroomStatus();\n setLocalBusy(\"\");\n await refresh();\n if (!r.ok || !r.data) {\n setCheck({ ok: false, text: r.error ?? \"could not reach the gateway\" });\n return;\n }\n setCheck(\n r.data.running\n ? { ok: true, text: `proxy is up at ${r.data.url}` }\n : { ok: false, text: `no proxy responding at ${r.data.url}` },\n );\n }\n\n return (\n <RichCard className=\"lg:col-span-2\" header={<CardTitle title=\"Headroom\" sub=\"external context-compression proxy\" />}>\n <div className=\"space-y-4\">\n <div className=\"flex flex-wrap items-center gap-2 text-[12px]\">\n <Badge tone={hr?.installed ? \"live\" : \"neutral\"}>{hr?.installed ? \"installed\" : \"not installed\"}</Badge>\n <Badge tone={hr?.running ? \"live\" : \"warn\"}>{hr?.running ? \"proxy running\" : \"proxy down\"}</Badge>\n <Badge tone={hr?.python ? \"info\" : \"neutral\"}>{hr?.python ? `python ${hr.python}` : \"no python ≥3.10\"}</Badge>\n {hr?.managedPid ? <span className=\"tnum text-text-subtle\">pid {hr.managedPid}</span> : null}\n </div>\n\n <Toggle\n label=\"Enable headroom\"\n desc=\"Compress the full context through the proxy before each request (fail-open if it's down).\"\n on={h.enabled}\n busy={localBusy === \"enable\"}\n onChange={(v) => act(\"enable\", () => adminApi.setHeadroom({ enabled: v }))}\n />\n <Toggle\n label=\"Compress user messages\"\n desc=\"Also squeeze user turns, not just tool/assistant context.\"\n on={h.compress_user_messages}\n busy={localBusy === \"cum\"}\n onChange={(v) => act(\"cum\", () => adminApi.setHeadroom({ compress_user_messages: v }))}\n />\n\n <div className=\"flex items-end gap-2\">\n <div className=\"flex-1\">\n <div className=\"mb-1 text-[11px] font-medium uppercase tracking-wider text-text-subtle\">Proxy URL</div>\n <Input value={url} onChange={(e) => setUrl(e.target.value)} placeholder=\"http://localhost:8787\" className=\"font-mono text-[12.5px]\" />\n </div>\n <Button\n variant=\"ghost\"\n disabled={url.trim() === h.url || localBusy === \"url\"}\n onClick={() => act(\"url\", () => adminApi.setHeadroom({ url: url.trim() }))}\n >\n Save URL\n </Button>\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <Button\n disabled={!hr?.canStart || hr?.running || localBusy === \"start\"}\n onClick={() => act(\"start\", () => adminApi.headroomStart())}\n >\n <Icon name=\"play_arrow\" size={16} /> {localBusy === \"start\" ? \"Starting…\" : \"Start proxy\"}\n </Button>\n <Button\n variant=\"danger\"\n disabled={!hr?.managedPid || localBusy === \"stop\"}\n onClick={() => act(\"stop\", () => adminApi.headroomStop())}\n >\n <Icon name=\"stop\" size={16} /> Stop\n </Button>\n <Button variant=\"ghost\" disabled={localBusy === \"check\"} onClick={checkProxy}>\n <Icon name=\"sync\" size={16} /> {localBusy === \"check\" ? \"Checking…\" : \"Check\"}\n </Button>\n {hr && !hr.installed && (\n <span className=\"text-[11px] text-text-subtle\">\n Headroom isn’t installed. Get it from{\" \"}\n <a href=\"https://github.com/chopratejas/headroom\" target=\"_blank\" rel=\"noreferrer\" className=\"text-accent hover:underline\">\n chopratejas/headroom\n </a>{\" \"}\n (needs Python ≥ 3.10):{\" \"}\n <code className=\"rounded bg-surface-2 px-1\">pipx install git+https://github.com/chopratejas/headroom</code>{\" \"}\n — then re-open this page.\n </span>\n )}\n {hr?.installed && !hr.localUrl && (\n <span className=\"text-[11px] text-text-subtle\">URL isn’t loopback — start that proxy yourself.</span>\n )}\n </div>\n\n {msg && <p className=\"text-[12px] text-danger\">{msg}</p>}\n {check && (\n <p className={`flex items-center gap-1 text-[12px] ${check.ok ? \"text-success\" : \"text-danger\"}`}>\n <Icon name={check.ok ? \"check_circle\" : \"error\"} size={14} /> {check.text}\n </p>\n )}\n </div>\n </RichCard>\n );\n}\n\n/** Shows a freshly created key once (it's masked everywhere after), with copy. */\nfunction KeyCreatedModal({ name, value, onClose }: { name: string; value: string; onClose: () => void }) {\n const [copied, setCopied] = useState(false);\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-6\" onClick={onClose}>\n <div\n className=\"w-full max-w-md rounded-brand-lg border border-border bg-surface p-5 shadow-elevated\"\n onClick={(e) => e.stopPropagation()}\n >\n <div className=\"mb-1 flex items-center gap-2\">\n <span className=\"flex h-7 w-7 items-center justify-center rounded-full bg-accent-soft text-accent\">\n <Icon name=\"key\" size={16} />\n </span>\n <h2 className=\"text-[15px] font-semibold text-text\">Key created</h2>\n </div>\n <p className=\"mb-3 text-[12px] text-text-muted\">\n Copy <span className=\"text-text\">{name}</span> now. You can reveal it again later from this page.\n </p>\n <button\n onClick={() => {\n void navigator.clipboard.writeText(value);\n setCopied(true);\n setTimeout(() => setCopied(false), 1500);\n }}\n className=\"flex w-full items-center justify-between gap-2 rounded-brand border border-border-subtle bg-bg px-3 py-2.5 text-left hover:border-text-subtle\"\n >\n <span className=\"tnum truncate text-[12.5px] text-text\">{value}</span>\n <Icon name={copied ? \"check\" : \"content_copy\"} size={15} />\n </button>\n <div className=\"mt-4 flex justify-end\">\n <Button onClick={onClose}>Done</Button>\n </div>\n </div>\n </div>\n );\n}\n\nfunction CopyRow({ label, value }: { label: string; value: string }) {\n const [copied, setCopied] = useState(false);\n return (\n <div className=\"flex items-center justify-between gap-3\">\n <span className=\"text-text-subtle\">{label}</span>\n <button\n onClick={() => {\n void navigator.clipboard.writeText(value);\n setCopied(true);\n setTimeout(() => setCopied(false), 1200);\n }}\n className=\"flex items-center gap-1.5 rounded-brand border border-border-subtle px-2.5 py-1 tnum text-[12.5px] text-text hover:border-text-subtle\"\n >\n {value}\n <Icon name={copied ? \"check\" : \"content_copy\"} size={13} />\n </button>\n </div>\n );\n}\n\nfunction Toggle({ label, desc, on, busy, onChange }: { label: string; desc: string; on: boolean; busy: boolean; onChange: (v: boolean) => void }) {\n return (\n <div className=\"flex items-center justify-between gap-4\">\n <div>\n <div className=\"text-[13px] font-semibold text-text\">{label}</div>\n <div className=\"text-[12px] text-text-muted\">{desc}</div>\n </div>\n <button\n disabled={busy}\n onClick={() => onChange(!on)}\n className={`relative h-6 w-11 flex-none rounded-full transition-colors ${on ? \"bg-accent\" : \"bg-surface-3\"}`}\n aria-pressed={on}\n >\n <span className={`absolute left-0.5 top-0.5 h-5 w-5 rounded-full bg-bg transition-transform ${on ? \"translate-x-5\" : \"translate-x-0\"}`} />\n </button>\n </div>\n );\n}\n\nfunction LevelRow({ label, desc, value, busy, onChange }: { label: string; desc: string; value: InjectLevel; busy: boolean; onChange: (l: InjectLevel) => void }) {\n return (\n <div className=\"flex items-center justify-between gap-4\">\n <div>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-[13px] font-semibold text-text\">{label}</span>\n {value !== \"off\" && <Badge tone=\"info\">{value}</Badge>}\n </div>\n <div className=\"text-[12px] text-text-muted\">{desc}</div>\n </div>\n <div className=\"flex flex-none items-center gap-1 rounded-full border border-border bg-surface p-1\">\n {LEVELS.map((lvl) => (\n <button\n key={lvl}\n disabled={busy}\n onClick={() => onChange(lvl)}\n className={`rounded-full px-2.5 py-1 text-[11.5px] font-medium transition-colors ${\n value === lvl ? \"bg-surface-2 text-text\" : \"text-text-muted hover:text-text\"\n }`}\n >\n {lvl}\n </button>\n ))}\n </div>\n </div>\n );\n}\n","\"use client\";\n\nimport { useState } from \"react\";\nimport { Icon } from \"./Icon\";\n\n/**\n * A masked key with an eye toggle that fetches the raw value on demand — for the\n * local operator who forgot what they pasted. `masked` is the already-masked\n * string the dashboard renders everywhere; `reveal` lazily fetches the real key\n * (admin-gated) the first time it's shown, then we cache it for copy/hide.\n */\n/**\n * `align`: \"inline\" keeps the eye + copy right next to the key text (use in a\n * label/column context like Endpoint). \"right\" lets the text grow so the eye +\n * copy push to the right edge (use in a single-line row like Provider keys).\n */\nexport function KeyReveal({\n masked,\n reveal,\n className,\n align = \"inline\",\n}: {\n masked: string;\n reveal: () => Promise<string | null>;\n className?: string;\n align?: \"inline\" | \"right\";\n}) {\n const [real, setReal] = useState<string | null>(null);\n const [shown, setShown] = useState(false);\n const [loading, setLoading] = useState(false);\n const [copied, setCopied] = useState(false);\n\n async function toggle() {\n if (shown) {\n setShown(false);\n return;\n }\n if (real === null) {\n setLoading(true);\n const k = await reveal();\n setLoading(false);\n if (k === null) return; // reveal failed — stay masked\n setReal(k);\n }\n setShown(true);\n }\n\n const display = shown && real !== null ? real : masked;\n\n return (\n <span className={`flex min-w-0 items-center gap-1.5${className ? ` ${className}` : \"\"}`}>\n <span className={`tnum truncate text-[12.5px] text-text${align === \"right\" ? \" flex-1\" : \"\"}`}>{display}</span>\n {shown && real !== null && (\n <button\n type=\"button\"\n onClick={() => {\n void navigator.clipboard.writeText(real);\n setCopied(true);\n setTimeout(() => setCopied(false), 1200);\n }}\n className=\"flex-none text-text-subtle transition-colors hover:text-text\"\n aria-label=\"Copy key\"\n >\n <Icon name={copied ? \"check\" : \"content_copy\"} size={14} />\n </button>\n )}\n <button\n type=\"button\"\n onClick={toggle}\n disabled={loading}\n className=\"flex-none text-text-subtle transition-colors hover:text-text disabled:opacity-40\"\n aria-label={shown ? \"Hide key\" : \"Show key\"}\n >\n <Icon name={loading ? \"hourglass_empty\" : shown ? \"visibility_off\" : \"visibility\"} size={15} />\n </button>\n </span>\n );\n}\n"],"names":["KeyReveal","masked","reveal","className","align","real","setReal","shown","setShown","loading","setLoading","copied","setCopied","toggle","k","display","type","onClick","navigator","clipboard","writeText","setTimeout","name","size","disabled"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../src/components/EndpointView.tsx","../../../../src/components/KeyReveal.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState, useCallback } from \"react\";\nimport { adminApi } from \"@/lib/client\";\nimport { Badge } from \"@/components/Badge\";\nimport { RichCard, CardTitle } from \"@/components/RichCard\";\nimport { Button, Input } from \"@/components/Button\";\nimport { Icon } from \"@/components/Icon\";\nimport { KeyReveal } from \"@/components/KeyReveal\";\nimport { Empty, fmt } from \"@/components/ui\";\nimport { ModelPicker, type ModelGroup } from \"@/components/ModelPicker\";\nimport { ConfirmModal } from \"@/components/ConfirmModal\";\nimport type { EndpointPayload, HeadroomStatusReply, InjectLevel, MaskedConfig } from \"@/lib/gateway\";\n\nconst LEVELS: InjectLevel[] = [\"off\", \"lite\", \"full\", \"ultra\"];\n\n/** Segment-pill style — matches the Budgets page pills. */\nconst pill = (active: boolean): string =>\n `rounded-brand px-3 py-1.5 text-[13px] font-medium transition-colors ${\n active ? \"bg-accent/12 text-accent\" : \"bg-surface-2 text-text-muted hover:text-text\"\n }`;\n\nconst DAY_MS = 86_400_000;\nconst EXPIRY_MS: Record<\"24h\" | \"7day\" | \"30day\", number> = {\n \"24h\": DAY_MS,\n \"7day\": 7 * DAY_MS,\n \"30day\": 30 * DAY_MS,\n};\n\n/** Generate a random gateway key client-side (aigetwey's one-click create). */\nfunction generateKey(): string {\n const bytes = new Uint8Array(24);\n crypto.getRandomValues(bytes);\n const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n return `aig-${hex}`;\n}\n\nexport function EndpointView() {\n const [ep, setEp] = useState<EndpointPayload | null>(null);\n const [error, setError] = useState(\"\");\n const [busy, setBusy] = useState(\"\");\n const [keyName, setKeyName] = useState(\"\");\n const [created, setCreated] = useState<{ key: string; name: string } | null>(null);\n const [pendingDelKey, setPendingDelKey] = useState<{ i: number; label: string } | null>(null);\n const [hr, setHr] = useState<HeadroomStatusReply | null>(null);\n const [editKey, setEditKey] = useState<number | null>(null);\n const [editKeyName, setEditKeyName] = useState(\"\");\n const [groups, setGroups] = useState<ModelGroup[]>([]);\n const [scopeKey, setScopeKey] = useState<number | null>(null);\n const [scopeModels, setScopeModels] = useState<string[]>([]);\n const [scopeRpm, setScopeRpm] = useState(\"\");\n const [scopeExpiry, setScopeExpiry] = useState<\"keep\" | \"never\" | \"24h\" | \"7day\" | \"30day\" | \"custom\">(\"never\");\n const [scopeCustomDays, setScopeCustomDays] = useState(\"\");\n const [scopeLimit, setScopeLimit] = useState(\"\"); // USD limit, \"\" = no cap\n const [scopeWindow, setScopeWindow] = useState<\"5h\" | \"24h\" | \"7day\" | \"30day\">(\"30day\");\n const [keyBudgets, setKeyBudgets] = useState<Record<string, { limit: number; window: string }>>({});\n const [pickerOpen, setPickerOpen] = useState(false);\n\n const reload = useCallback(async () => {\n const r = await adminApi.endpoint();\n if (!r.ok) {\n setError(r.error ?? \"could not reach the gateway\");\n return;\n }\n setError(\"\");\n setEp(r.data);\n }, []);\n\n // Headroom status is a live probe (installed/running/python), separate from the\n // endpoint config — reload it on mount and after any headroom action.\n const reloadHr = useCallback(async () => {\n const r = await adminApi.headroomStatus();\n if (r.ok) setHr(r.data);\n }, []);\n\n useEffect(() => {\n void reload();\n void reloadHr();\n // load the model catalog for the per-key scope picker (combos + provider/model refs).\n void (async () => {\n try {\n const res = await fetch(\"/api/gw/admin/config\");\n if (!res.ok) return;\n const cfg = (await res.json()) as MaskedConfig;\n const grps: ModelGroup[] = [];\n if (cfg.models.length) grps.push({ label: \"Combos\", items: cfg.models.map((m) => ({ value: m.alias, label: m.alias })) });\n for (const p of cfg.providers) {\n if (p.models.length) grps.push({ label: p.id, items: p.models.map((m) => ({ value: `${p.id}/${m.id}`, label: `${p.id}/${m.id}` })) });\n }\n setGroups(grps);\n } catch { /* non-critical — picker will just be empty */ }\n })();\n // index existing key-scoped budgets by fingerprint so the modal can prefill.\n void adminApi.budgets().then((r) => {\n if (!r.ok || !r.data) return;\n const map: Record<string, { limit: number; window: string }> = {};\n for (const b of r.data.budgets) {\n if (b.scope.type === \"key\") map[b.scope.id] = { limit: b.limit, window: b.window };\n }\n setKeyBudgets(map);\n });\n }, [reload, reloadHr]);\n\n if (error) return <Empty>{error}</Empty>;\n if (!ep) return <Empty>Loading…</Empty>;\n\n const baseUrl = `http://127.0.0.1:${ep.port}`;\n\n async function run(label: string, fn: () => Promise<{ ok: boolean; error?: string }>) {\n setBusy(label);\n const r = await fn();\n setBusy(\"\");\n if (!r.ok) setError(r.error ?? \"action failed\");\n else {\n setError(\"\");\n await reload();\n }\n }\n\n // Create a key (generated or pasted) with its label, then surface it once in a\n // modal — aigetwey, where the full key is shown at creation time.\n async function addKey(label: string, rawKey: string) {\n const name = (label || \"Gateway key\").trim();\n setBusy(\"genkey\");\n const r = await adminApi.addServerKey(rawKey, name);\n setBusy(\"\");\n if (!r.ok) {\n setError(r.error ?? \"could not add key\");\n return;\n }\n setError(\"\");\n setKeyName(\"\");\n setCreated({ key: rawKey, name });\n await reload();\n }\n\n return (\n <div>\n <div className=\"mb-6\">\n <h1 className=\"text-[22px] font-semibold tracking-tight text-text\">Endpoint &amp; Key</h1>\n <p className=\"mt-1 text-[13px] text-text-muted\">Gateway address, client keys, and the token-saver toggles.</p>\n </div>\n\n <div className=\"grid gap-4 lg:grid-cols-2\">\n <RichCard header={<CardTitle title=\"Gateway URL\" sub=\"one endpoint for every client\" />}>\n <div className=\"text-[13px]\">\n <CopyRow label=\"Gateway URL\" value={baseUrl} />\n </div>\n <p className=\"mt-3 text-[12px] text-text-subtle\">\n One gateway, both formats. Anthropic clients (Claude Code) use it as-is; OpenAI clients (opencode,\n Cursor, Codex) append <span className=\"tnum\">/v1</span>. The <span className=\"text-text-muted\">CLI Tools</span>{\" \"}\n page has copy-ready env per tool.\n </p>\n </RichCard>\n\n <RichCard header={<CardTitle title=\"Gateway keys\" sub={`${ep.keys.length} configured`} />}>\n {ep.keys.length === 0 ? (\n <Empty>No keys — auth is DISABLED (localhost only). Generate one below.</Empty>\n ) : (\n <div className=\"space-y-1.5\">\n {ep.keys.map((k, i) =>\n editKey === i ? (\n <div key={i} className=\"space-y-2 rounded-brand border border-accent bg-accent-soft/40 px-3 py-2.5\">\n <Input value={editKeyName} onChange={(e) => setEditKeyName(e.target.value)} placeholder=\"key name (e.g. Claude Code)\" />\n <div className=\"flex justify-end gap-2\">\n <Button variant=\"ghost\" onClick={() => setEditKey(null)}>Cancel</Button>\n <Button\n disabled={busy === `editkey${i}`}\n onClick={() =>\n run(`editkey${i}`, async () => {\n const r = await adminApi.editServerKey(i, editKeyName.trim());\n if (r.ok) setEditKey(null);\n return r;\n })\n }\n >\n Save\n </Button>\n </div>\n </div>\n ) : (\n <div key={i} className=\"space-y-0 rounded-brand border border-border-subtle\">\n <div className=\"flex items-center justify-between gap-2 px-3 py-2\">\n <div className=\"flex min-w-0 flex-col gap-0.5\">\n {k.name && <span className=\"text-[12px] font-semibold text-text-muted\">{k.name}</span>}\n <KeyReveal\n masked={k.key}\n reveal={async () => {\n const r = await adminApi.revealServerKey(i);\n return r.ok ? r.data?.key ?? null : null;\n }}\n />\n <div className=\"mt-0.5 flex flex-wrap items-center gap-1.5 text-[11px] text-text-subtle\">\n <span>{k.models?.length ? `${k.models.length} model${k.models.length > 1 ? \"s\" : \"\"}` : \"all models\"}</span>\n <span>·</span>\n <span>{k.rpm ? `${k.rpm}/min` : \"no rate limit\"}</span>\n <span>·</span>\n <span>\n {k.expires\n ? (Date.now() > k.expires ? <span className=\"text-danger\">expired</span> : `expires ${fmt.date(k.expires)}`)\n : \"no expiry\"}\n </span>\n </div>\n </div>\n <div className=\"flex flex-none items-center gap-1\">\n <button\n onClick={() => {\n setScopeKey(i);\n setScopeModels(k.models ?? []);\n setScopeRpm(k.rpm ? String(k.rpm) : \"\");\n setScopeExpiry(k.expires ? \"keep\" : \"never\");\n setScopeCustomDays(\"\");\n const kb = keyBudgets[k.fingerprint];\n setScopeLimit(kb ? String(kb.limit) : \"\");\n setScopeWindow((kb?.window as \"5h\" | \"24h\" | \"7day\" | \"30day\") ?? \"30day\");\n }}\n className=\"text-text-subtle hover:text-text\"\n aria-label=\"Edit key scope\"\n title=\"Model allowlist + rate limit + budget + expiry\"\n >\n <Icon name=\"tune\" size={15} />\n </button>\n <button\n onClick={() => { setEditKey(i); setEditKeyName(k.name ?? \"\"); }}\n className=\"text-text-subtle hover:text-text\"\n aria-label=\"Rename key\"\n title=\"Rename key\"\n >\n <Icon name=\"edit\" size={15} />\n </button>\n <button onClick={() => setPendingDelKey({ i, label: k.name || k.key })} className=\"text-text-subtle hover:text-danger\" aria-label=\"Remove key\">\n <Icon name=\"delete\" size={16} />\n </button>\n </div>\n </div>\n {scopeKey === i && (\n <div className=\"space-y-2 border-t border-border-subtle bg-accent-soft/40 px-3 py-2.5\">\n <div>\n <div className=\"mb-1 text-[11px] font-medium uppercase tracking-wider text-text-subtle\">Allowed models</div>\n <div className=\"flex flex-wrap items-center gap-1.5\">\n {scopeModels.length === 0 ? (\n <span className=\"text-[12px] text-text-subtle\">All models (unrestricted)</span>\n ) : (\n scopeModels.map((m) => (\n <span key={m} className=\"inline-flex items-center gap-1 rounded border border-accent bg-accent-soft px-2 py-0.5 text-[12px] text-accent\">\n <span className=\"tnum\">{m}</span>\n <button onClick={() => setScopeModels((s) => s.filter((x) => x !== m))} className=\"hover:text-danger\" aria-label={`Remove ${m}`}>\n <Icon name=\"close\" size={12} />\n </button>\n </span>\n ))\n )}\n </div>\n <Button type=\"button\" variant=\"ghost\" className=\"mt-1.5\" onClick={() => setPickerOpen(true)}>\n <Icon name=\"add\" size={15} /> Pick models\n </Button>\n </div>\n <div>\n <div className=\"mb-1 text-[11px] font-medium uppercase tracking-wider text-text-subtle\">Rate limit</div>\n <Input\n inputMode=\"numeric\"\n value={scopeRpm}\n onChange={(e) => setScopeRpm(e.target.value.replace(/[^\\d]/g, \"\"))}\n placeholder=\"req/min (blank = unlimited)\"\n />\n </div>\n <div>\n <div className=\"mb-1 text-[11px] font-medium uppercase tracking-wider text-text-subtle\">Access expiry</div>\n {k.expires && (\n <div className=\"mb-1.5 text-[11px] text-text-subtle\">\n currently {Date.now() > k.expires ? <span className=\"text-danger\">expired</span> : `expires ${fmt.date(k.expires)}`}\n </div>\n )}\n <div className=\"flex flex-wrap gap-1\">\n {(k.expires\n ? ([\"keep\", \"never\", \"24h\", \"7day\", \"30day\", \"custom\"] as const)\n : ([\"never\", \"24h\", \"7day\", \"30day\", \"custom\"] as const)\n ).map((opt) => (\n <button\n key={opt}\n type=\"button\"\n onClick={() => setScopeExpiry(opt)}\n className={pill(scopeExpiry === opt)}\n >\n {opt === \"never\" ? \"no expiry\" : opt}\n </button>\n ))}\n </div>\n {scopeExpiry === \"custom\" && (\n <div className=\"mt-1.5 flex items-center gap-1.5\">\n <Input\n inputMode=\"numeric\"\n value={scopeCustomDays}\n onChange={(e) => setScopeCustomDays(e.target.value.replace(/[^\\d]/g, \"\"))}\n placeholder=\"days\"\n className=\"w-24\"\n />\n <span className=\"text-[11px] text-text-subtle\">days from now</span>\n </div>\n )}\n </div>\n <div>\n <div className=\"mb-1 text-[11px] font-medium uppercase tracking-wider text-text-subtle\">Spend cap (USD)</div>\n <Input\n inputMode=\"decimal\"\n value={scopeLimit}\n onChange={(e) => setScopeLimit(e.target.value.replace(/[^\\d.]/g, \"\"))}\n placeholder=\"USD (blank = no cap)\"\n />\n {scopeLimit && (\n <div className=\"mt-1.5 flex items-center gap-1.5\">\n <span className=\"text-[11px] text-text-subtle\">resets every</span>\n {([\"5h\", \"24h\", \"7day\", \"30day\"] as const).map((w) => (\n <button\n key={w}\n type=\"button\"\n onClick={() => setScopeWindow(w)}\n className={pill(scopeWindow === w)}\n >\n {w}\n </button>\n ))}\n </div>\n )}\n </div>\n <div className=\"flex justify-end gap-2\">\n <Button variant=\"ghost\" onClick={() => setScopeKey(null)}>Cancel</Button>\n <Button\n disabled={busy === `scope${i}`}\n onClick={() =>\n run(`scope${i}`, async () => {\n // \"keep\" leaves expiry untouched (omit); \"never\" clears; a duration sets now+N.\n const expires =\n scopeExpiry === \"keep\" ? undefined\n : scopeExpiry === \"never\" ? null\n : scopeExpiry === \"custom\" ? (scopeCustomDays ? Date.now() + Number(scopeCustomDays) * DAY_MS : null)\n : Date.now() + EXPIRY_MS[scopeExpiry];\n const r = await adminApi.setServerKeyScope(i, {\n models: scopeModels,\n rpm: scopeRpm ? Number(scopeRpm) : null,\n expires,\n });\n if (!r.ok) return r;\n const limit = scopeLimit ? Number(scopeLimit) : 0;\n if (limit > 0) {\n await adminApi.setBudget({ scope: { type: \"key\", id: k.fingerprint }, unit: \"usd\", limit, window: scopeWindow });\n } else if (keyBudgets[k.fingerprint]) {\n await adminApi.clearBudget(`key:${k.fingerprint}`);\n }\n setScopeKey(null);\n return r;\n })\n }\n >\n Save\n </Button>\n </div>\n </div>\n )}\n </div>\n ),\n )}\n </div>\n )}\n <div className=\"mt-3 space-y-2\">\n <div className=\"flex gap-2\">\n <Input value={keyName} onChange={(e) => setKeyName(e.target.value)} placeholder=\"key name (e.g. Claude Code)\" className=\"flex-1\" />\n <Button disabled={busy === \"genkey\"} onClick={() => addKey(keyName, generateKey())}>\n <Icon name=\"add\" size={16} /> {busy === \"genkey\" ? \"Adding…\" : \"Add key\"}\n </Button>\n </div>\n <p className=\"text-[11px] text-text-subtle\">Name it, then click Add key — a key is generated and shown once. Configure its limits after.</p>\n </div>\n </RichCard>\n\n <RichCard className=\"lg:col-span-2\" header={<CardTitle title=\"Token savers\" sub=\"applied to every request before routing\" />}>\n <div className=\"space-y-4\">\n <Toggle\n label=\"RTK\"\n desc=\"Compress bulky tool_result blocks (diffs, grep, listings) in the request.\"\n on={ep.rtk}\n busy={busy === \"rtk\"}\n onChange={(v) => run(\"rtk\", () => adminApi.setRtk(v))}\n />\n <LevelRow\n label=\"Caveman\"\n desc=\"Terser model output — drops filler, keeps substance.\"\n value={ep.caveman}\n busy={busy === \"caveman\"}\n onChange={(lvl) => run(\"caveman\", () => adminApi.setCaveman(lvl))}\n />\n <LevelRow\n label=\"Ponytail\"\n desc=\"Minimal, YAGNI code style — deletion over addition.\"\n value={ep.ponytail}\n busy={busy === \"ponytail\"}\n onChange={(lvl) => run(\"ponytail\", () => adminApi.setPonytail(lvl))}\n />\n </div>\n </RichCard>\n\n <HeadroomCard\n ep={ep}\n hr={hr}\n refresh={async () => {\n await reload();\n await reloadHr();\n }}\n />\n </div>\n\n {created && <KeyCreatedModal name={created.name} value={created.key} onClose={() => setCreated(null)} />}\n {pendingDelKey && (\n <ConfirmModal\n title=\"Remove gateway key\"\n message={`Delete \"${pendingDelKey.label}\"? Any client using this key stops working immediately.`}\n confirmLabel=\"Remove\"\n busy={busy === `rmkey${pendingDelKey.i}`}\n onCancel={() => setPendingDelKey(null)}\n onConfirm={() => {\n const i = pendingDelKey.i;\n void run(`rmkey${i}`, () => adminApi.removeServerKey(i)).then(() => setPendingDelKey(null));\n }}\n />\n )}\n {pickerOpen && (\n <ModelPicker\n title=\"Allowed models\"\n note=\"Pick the models this key may call. None = all.\"\n groups={groups}\n selected={scopeModels}\n onToggle={(v) => setScopeModels((s) => s.includes(v) ? s.filter((x) => x !== v) : [...s, v])}\n onClose={() => setPickerOpen(false)}\n showThinkingHint={false}\n />\n )}\n </div>\n );\n}\n\n/**\n * Headroom = external context-compression proxy. Status is a live probe; the\n * enable/url/compress fields persist to endpoint config; Start/Stop manage a\n * gateway-spawned proxy when the CLI is installed and the URL is loopback.\n */\nfunction HeadroomCard({\n ep,\n hr,\n refresh,\n}: {\n ep: EndpointPayload;\n hr: HeadroomStatusReply | null;\n refresh: () => Promise<void>;\n}) {\n const h = ep.headroom;\n const [url, setUrl] = useState(h.url);\n const [localBusy, setLocalBusy] = useState(\"\");\n const [msg, setMsg] = useState(\"\");\n const [check, setCheck] = useState<{ ok: boolean; text: string } | null>(null);\n useEffect(() => setUrl(h.url), [h.url]);\n\n async function act(label: string, fn: () => Promise<{ ok: boolean; error?: string }>) {\n setLocalBusy(label);\n setMsg(\"\");\n setCheck(null);\n const r = await fn();\n setLocalBusy(\"\");\n if (!r.ok) setMsg(r.error ?? \"action failed\");\n await refresh();\n }\n\n // Live re-probe: ask the gateway whether the proxy at the configured URL\n // actually answers right now, and surface the result inline.\n async function checkProxy() {\n setLocalBusy(\"check\");\n setMsg(\"\");\n setCheck(null);\n const r = await adminApi.headroomStatus();\n setLocalBusy(\"\");\n await refresh();\n if (!r.ok || !r.data) {\n setCheck({ ok: false, text: r.error ?? \"could not reach the gateway\" });\n return;\n }\n setCheck(\n r.data.running\n ? { ok: true, text: `proxy is up at ${r.data.url}` }\n : { ok: false, text: `no proxy responding at ${r.data.url}` },\n );\n }\n\n return (\n <RichCard className=\"lg:col-span-2\" header={<CardTitle title=\"Headroom\" sub=\"external context-compression proxy\" />}>\n <div className=\"space-y-4\">\n <div className=\"flex flex-wrap items-center gap-2 text-[12px]\">\n <Badge tone={hr?.installed ? \"live\" : \"neutral\"}>{hr?.installed ? \"installed\" : \"not installed\"}</Badge>\n <Badge tone={hr?.running ? \"live\" : \"warn\"}>{hr?.running ? \"proxy running\" : \"proxy down\"}</Badge>\n <Badge tone={hr?.python ? \"info\" : \"neutral\"}>{hr?.python ? `python ${hr.python}` : \"no python ≥3.10\"}</Badge>\n {hr?.managedPid ? <span className=\"tnum text-text-subtle\">pid {hr.managedPid}</span> : null}\n </div>\n\n <Toggle\n label=\"Enable headroom\"\n desc=\"Compress the full context through the proxy before each request.\"\n on={h.enabled}\n busy={localBusy === \"enable\"}\n disabled={!hr?.running && !h.enabled}\n onChange={(v) => act(\"enable\", () => adminApi.setHeadroom({ enabled: v }))}\n />\n <Toggle\n label=\"Compress user messages\"\n desc=\"Also squeeze user turns, not just tool/assistant context.\"\n on={h.compress_user_messages}\n busy={localBusy === \"cum\"}\n onChange={(v) => act(\"cum\", () => adminApi.setHeadroom({ compress_user_messages: v }))}\n />\n\n <div className=\"flex items-end gap-2\">\n <div className=\"flex-1\">\n <div className=\"mb-1 text-[11px] font-medium uppercase tracking-wider text-text-subtle\">Proxy URL</div>\n <Input value={url} onChange={(e) => setUrl(e.target.value)} placeholder=\"http://localhost:8787\" className=\"font-mono text-[12.5px]\" />\n </div>\n <Button\n variant=\"ghost\"\n disabled={url.trim() === h.url || localBusy === \"url\"}\n onClick={() => act(\"url\", () => adminApi.setHeadroom({ url: url.trim() }))}\n >\n Save URL\n </Button>\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <Button\n disabled={!hr?.canStart || hr?.running || !!localBusy}\n onClick={async () => {\n await act(\"start\", () => adminApi.headroomStart());\n await checkProxy();\n }}\n >\n <Icon name={localBusy === \"start\" ? \"sync\" : \"play_arrow\"} size={16} className={localBusy === \"start\" ? \"animate-spin\" : \"\"} />\n {localBusy === \"start\" ? \"Starting…\" : \"Start proxy\"}\n </Button>\n <Button\n variant=\"danger\"\n disabled={!hr?.managedPid || localBusy === \"stop\"}\n onClick={() => act(\"stop\", () => adminApi.headroomStop())}\n >\n <Icon name=\"stop\" size={16} /> Stop\n </Button>\n <Button variant=\"ghost\" disabled={localBusy === \"check\"} onClick={checkProxy}>\n <Icon name=\"sync\" size={16} /> {localBusy === \"check\" ? \"Checking…\" : \"Check\"}\n </Button>\n {hr && !hr.installed && (\n <span className=\"text-[11px] text-text-subtle\">\n Headroom isn’t installed. Get it from{\" \"}\n <a href=\"https://github.com/chopratejas/headroom\" target=\"_blank\" rel=\"noreferrer\" className=\"text-accent hover:underline\">\n chopratejas/headroom\n </a>{\" \"}\n (needs Python ≥ 3.10):{\" \"}\n <code className=\"rounded bg-surface-2 px-1\">pipx install git+https://github.com/chopratejas/headroom</code>{\" \"}\n — then re-open this page.\n </span>\n )}\n {hr?.installed && !hr.localUrl && (\n <span className=\"text-[11px] text-text-subtle\">URL isn’t loopback — start that proxy yourself.</span>\n )}\n </div>\n\n {msg && <p className=\"text-[12px] text-danger\">{msg}</p>}\n {check && (\n <p className={`flex items-center gap-1 text-[12px] ${check.ok ? \"text-success\" : \"text-danger\"}`}>\n <Icon name={check.ok ? \"check_circle\" : \"error\"} size={14} /> {check.text}\n </p>\n )}\n </div>\n </RichCard>\n );\n}\n\n/** Shows a freshly created key once (it's masked everywhere after), with copy. */\nfunction KeyCreatedModal({ name, value, onClose }: { name: string; value: string; onClose: () => void }) {\n const [copied, setCopied] = useState(false);\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-6\" onClick={onClose}>\n <div\n className=\"w-full max-w-md rounded-brand-lg border border-border bg-surface p-5 shadow-elevated\"\n onClick={(e) => e.stopPropagation()}\n >\n <div className=\"mb-1 flex items-center gap-2\">\n <span className=\"flex h-7 w-7 items-center justify-center rounded-full bg-accent-soft text-accent\">\n <Icon name=\"key\" size={16} />\n </span>\n <h2 className=\"text-[15px] font-semibold text-text\">Key created</h2>\n </div>\n <p className=\"mb-3 text-[12px] text-text-muted\">\n Copy <span className=\"text-text\">{name}</span> now. You can reveal it again later from this page.\n </p>\n <button\n onClick={() => {\n void navigator.clipboard.writeText(value);\n setCopied(true);\n setTimeout(() => setCopied(false), 1500);\n }}\n className=\"flex w-full items-center justify-between gap-2 rounded-brand border border-border-subtle bg-bg px-3 py-2.5 text-left hover:border-text-subtle\"\n >\n <span className=\"tnum truncate text-[12.5px] text-text\">{value}</span>\n <Icon name={copied ? \"check\" : \"content_copy\"} size={15} />\n </button>\n <div className=\"mt-4 flex justify-end\">\n <Button onClick={onClose}>Done</Button>\n </div>\n </div>\n </div>\n );\n}\n\nfunction CopyRow({ label, value }: { label: string; value: string }) {\n const [copied, setCopied] = useState(false);\n return (\n <div className=\"flex items-center justify-between gap-3\">\n <span className=\"text-text-subtle\">{label}</span>\n <button\n onClick={() => {\n void navigator.clipboard.writeText(value);\n setCopied(true);\n setTimeout(() => setCopied(false), 1200);\n }}\n className=\"flex items-center gap-1.5 rounded-brand border border-border-subtle px-2.5 py-1 tnum text-[12.5px] text-text hover:border-text-subtle\"\n >\n {value}\n <Icon name={copied ? \"check\" : \"content_copy\"} size={13} />\n </button>\n </div>\n );\n}\n\nfunction Toggle({ label, desc, on, busy, disabled, onChange }: { label: string; desc: string; on: boolean; busy: boolean; disabled?: boolean; onChange: (v: boolean) => void }) {\n const off = busy || disabled;\n return (\n <div className={`flex items-center justify-between gap-4 ${off ? \"opacity-40\" : \"\"}`}>\n <div>\n <div className=\"text-[13px] font-semibold text-text\">{label}</div>\n <div className=\"text-[12px] text-text-muted\">{desc}</div>\n </div>\n <button\n disabled={off}\n onClick={() => onChange(!on)}\n className={`relative h-6 w-11 flex-none rounded-full transition-colors ${on ? \"bg-accent\" : \"bg-surface-3\"}`}\n aria-pressed={on}\n >\n <span className={`absolute left-0.5 top-0.5 h-5 w-5 rounded-full bg-bg transition-transform ${on ? \"translate-x-5\" : \"translate-x-0\"}`} />\n </button>\n </div>\n );\n}\n\nfunction LevelRow({ label, desc, value, busy, onChange }: { label: string; desc: string; value: InjectLevel; busy: boolean; onChange: (l: InjectLevel) => void }) {\n return (\n <div className=\"flex items-center justify-between gap-4\">\n <div>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-[13px] font-semibold text-text\">{label}</span>\n {value !== \"off\" && <Badge tone=\"info\">{value}</Badge>}\n </div>\n <div className=\"text-[12px] text-text-muted\">{desc}</div>\n </div>\n <div className=\"flex flex-none items-center gap-1 rounded-full border border-border bg-surface p-1\">\n {LEVELS.map((lvl) => (\n <button\n key={lvl}\n disabled={busy}\n onClick={() => onChange(lvl)}\n className={`rounded-full px-2.5 py-1 text-[11.5px] font-medium transition-colors ${\n value === lvl ? \"bg-surface-2 text-text\" : \"text-text-muted hover:text-text\"\n }`}\n >\n {lvl}\n </button>\n ))}\n </div>\n </div>\n );\n}\n","\"use client\";\n\nimport { useState } from \"react\";\nimport { Icon } from \"./Icon\";\n\n/**\n * A masked key with an eye toggle that fetches the raw value on demand — for the\n * local operator who forgot what they pasted. `masked` is the already-masked\n * string the dashboard renders everywhere; `reveal` lazily fetches the real key\n * (admin-gated) the first time it's shown, then we cache it for copy/hide.\n */\n/**\n * `align`: \"inline\" keeps the eye + copy right next to the key text (use in a\n * label/column context like Endpoint). \"right\" lets the text grow so the eye +\n * copy push to the right edge (use in a single-line row like Provider keys).\n */\nexport function KeyReveal({\n masked,\n reveal,\n className,\n align = \"inline\",\n}: {\n masked: string;\n reveal: () => Promise<string | null>;\n className?: string;\n align?: \"inline\" | \"right\";\n}) {\n const [real, setReal] = useState<string | null>(null);\n const [shown, setShown] = useState(false);\n const [loading, setLoading] = useState(false);\n const [copied, setCopied] = useState(false);\n\n async function toggle() {\n if (shown) {\n setShown(false);\n return;\n }\n if (real === null) {\n setLoading(true);\n const k = await reveal();\n setLoading(false);\n if (k === null) return; // reveal failed — stay masked\n setReal(k);\n }\n setShown(true);\n }\n\n const display = shown && real !== null ? real : masked;\n\n return (\n <span className={`flex min-w-0 items-center gap-1.5${className ? ` ${className}` : \"\"}`}>\n <span className={`tnum truncate text-[12.5px] text-text${align === \"right\" ? \" flex-1\" : \"\"}`}>{display}</span>\n {shown && real !== null && (\n <button\n type=\"button\"\n onClick={() => {\n void navigator.clipboard.writeText(real);\n setCopied(true);\n setTimeout(() => setCopied(false), 1200);\n }}\n className=\"flex-none text-text-subtle transition-colors hover:text-text\"\n aria-label=\"Copy key\"\n >\n <Icon name={copied ? \"check\" : \"content_copy\"} size={14} />\n </button>\n )}\n <button\n type=\"button\"\n onClick={toggle}\n disabled={loading}\n className=\"flex-none text-text-subtle transition-colors hover:text-text disabled:opacity-40\"\n aria-label={shown ? \"Hide key\" : \"Show key\"}\n >\n <Icon name={loading ? \"hourglass_empty\" : shown ? \"visibility_off\" : \"visibility\"} size={15} />\n </button>\n </span>\n );\n}\n"],"names":["KeyReveal","masked","reveal","className","align","real","setReal","shown","setShown","loading","setLoading","copied","setCopied","toggle","k","display","type","onClick","navigator","clipboard","writeText","setTimeout","name","size","disabled"],"mappings":"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"}
@@ -1,3 +1,3 @@
1
- module.exports=[33410,a=>{"use strict";var b=a.i(87924),c=a.i(72131),d=a.i(50944),e=a.i(56173),f=a.i(47153),g=a.i(2693),h=a.i(2799),i=a.i(85732),j=a.i(7078),k=a.i(93026),l=a.i(58918);function m({checked:a,indeterminate:c,onChange:d,className:e,ariaLabel:f}){let g=a||c;return(0,b.jsx)("button",{type:"button",role:"checkbox","aria-checked":c?"mixed":a,"aria-label":f,onClick:a=>{a.stopPropagation(),d()},className:`flex h-[18px] w-[18px] flex-none items-center justify-center rounded-[5px] border transition-colors ${g?"border-accent bg-accent text-accent-ink":"border-border bg-bg text-transparent hover:border-text-subtle"}${e?` ${e}`:""}`,children:(0,b.jsx)(k.Icon,{name:c?"remove":"check",size:13})})}function n({models:a,busy:d,onAdd:e,onClose:f}){let[g,h]=(0,c.useState)(""),[i,l]=(0,c.useState)(()=>new Set(a.filter(a=>!a.added).map(a=>a.id))),o=(0,c.useMemo)(()=>{let b=g.trim().toLowerCase();return b?a.filter(a=>a.id.toLowerCase().includes(b)):a},[a,g]);function p(a){l(b=>{let c=new Set(b);return c.has(a)?c.delete(a):c.add(a),c})}let q=o.filter(a=>i.has(a.id)).length,r=o.length>0&&q===o.length;function s(){l(a=>{let b=new Set(a);return r?o.forEach(a=>b.delete(a.id)):o.forEach(a=>b.add(a.id)),b})}return(0,b.jsx)("div",{className:"fixed inset-0 z-50 grid place-items-center bg-black/50 p-6",onClick:f,children:(0,b.jsxs)("div",{className:"flex max-h-[80vh] w-full max-w-[480px] flex-col overflow-hidden rounded-brand-lg border border-border bg-surface shadow-elevated",onClick:a=>a.stopPropagation(),children:[(0,b.jsxs)("header",{className:"flex items-center justify-between border-b border-border-subtle px-4 py-3",children:[(0,b.jsxs)("span",{className:"text-[14px] font-semibold text-text",children:[a.length," models found"]}),(0,b.jsx)("button",{onClick:f,className:"text-text-subtle hover:text-text","aria-label":"Close",children:(0,b.jsx)(k.Icon,{name:"close",size:18})})]}),(0,b.jsx)("div",{className:"border-b border-border-subtle px-4 py-2.5",children:(0,b.jsx)(j.Input,{value:g,onChange:a=>h(a.target.value),placeholder:"filter…",autoFocus:!0})}),o.length>0&&(0,b.jsxs)("button",{onClick:s,className:"flex items-center gap-2.5 border-b border-border-subtle px-4 py-2 text-left hover:bg-surface-2",children:[(0,b.jsx)(m,{checked:r,indeterminate:q>0&&!r,onChange:s,ariaLabel:"Select all"}),(0,b.jsxs)("span",{className:"text-[12.5px] font-medium text-text",children:["Select all",g?" (filtered)":""]}),(0,b.jsxs)("span",{className:"ml-auto tnum text-[11px] text-text-subtle",children:[q,"/",o.length]})]}),(0,b.jsx)("div",{className:"flex-1 overflow-y-auto px-2 py-2",children:0===o.length?(0,b.jsx)("div",{className:"px-2 py-6 text-center text-[13px] text-text-muted",children:"No matches."}):o.map(a=>{let c=i.has(a.id);return(0,b.jsxs)("button",{onClick:()=>p(a.id),className:`flex w-full items-center gap-2.5 rounded-brand border px-2.5 py-2 text-left transition-colors ${c?"border-accent/40 bg-accent-soft":"border-transparent hover:bg-surface-2"}`,children:[(0,b.jsx)(m,{checked:c,onChange:()=>p(a.id),ariaLabel:a.id}),(0,b.jsx)("span",{className:"flex-1 truncate text-[12.5px] text-text",children:a.id}),a.added&&(0,b.jsx)("span",{className:"text-[11px] text-text-subtle",children:"in catalog"})]},a.id)})}),(0,b.jsxs)("footer",{className:"flex items-center justify-between gap-3 border-t border-border-subtle bg-bg-alt px-4 py-2.5",children:[(0,b.jsxs)("span",{className:"tnum text-[12px] text-text-muted",children:[i.size," selected"]}),(0,b.jsxs)("div",{className:"flex gap-2",children:[(0,b.jsx)(j.Button,{variant:"ghost",onClick:f,children:"Cancel"}),(0,b.jsx)(j.Button,{disabled:0===i.size||d,onClick:()=>e([...i]),children:d?"Adding…":`Add ${i.size}`})]})]})]})})}var o=a.i(52065),p=a.i(73858);function q({k:a,v:c}){return(0,b.jsxs)("div",{className:"flex items-center justify-between gap-3",children:[(0,b.jsx)("span",{className:"text-text-subtle",children:a}),(0,b.jsx)("span",{className:"truncate text-text",children:c})]})}a.s(["ProviderDetail",0,function({id:a}){let m=(0,d.useRouter)(),[r,s]=(0,c.useState)(null),[t,u]=(0,c.useState)(null),[v,w]=(0,c.useState)(""),[x,y]=(0,c.useState)(null),[z,A]=(0,c.useState)(""),[B,C]=(0,c.useState)(""),[D,E]=(0,c.useState)(""),[F,G]=(0,c.useState)(null),[H,I]=(0,c.useState)(""),[J,K]=(0,c.useState)(""),[L,M]=(0,c.useState)(""),[N,O]=(0,c.useState)(""),[P,Q]=(0,c.useState)(null),[R,S]=(0,c.useState)({}),[T,U]=(0,c.useState)({}),[V,W]=(0,c.useState)(!1),[X,Y]=(0,c.useState)(null),Z=(0,c.useRef)(!1),[$,_]=(0,c.useState)(!1),[aa,ab]=(0,c.useState)(""),[ac,ad]=(0,c.useState)(""),[ae,af]=(0,c.useState)({}),[ag,ah]=(0,c.useState)(!1);async function ai(b){S(a=>({...a,[b]:"testing"}));let c=await e.adminApi.testModel(a,b);S(a=>({...a,[b]:c.ok&&c.data?.ok?"ok":"fail"}))}async function aj(b){U(a=>({...a,[b]:"testing"}));let c=await e.adminApi.testKey(a,b);U(a=>({...a,[b]:c.data??{ok:!1,reachable:!1,status:0,error:c.error}}))}async function ak(b){Z.current=!1,W(!0),Y(null),U({});let c=0,d=0;for(let f=0;f<b&&!Z.current;f++){U(a=>({...a,[f]:"testing"}));let g=await e.adminApi.testKey(a,f),h=g.data??{ok:!1,reachable:!1,status:0,error:g.error};U(a=>({...a,[f]:h})),h.ok?c++:d++,f<b-1&&!Z.current&&await new Promise(a=>setTimeout(a,500))}W(!1),Y({total:b,passed:c,failed:d})}let al=(0,c.useCallback)(async()=>{let[b,c]=await Promise.all([fetch("/api/gw/admin/config"),e.adminApi.providers()]);if(!b.ok)return void w("could not reach the gateway");let d=(await b.json()).providers.find(b=>b.id===a)??null;d?(w(""),s(d),u(c.data?.providers.find(b=>b.id===a)??null)):w(`provider "${a}" not found`)},[a]);if((0,c.useEffect)(()=>{al()},[al]),v)return(0,b.jsx)(l.Empty,{children:v});if(!r)return(0,b.jsx)(l.Empty,{children:"Loading…"});let am=r.api_keys??(r.api_key?[r.api_key]:[]),an=N.trim().toLowerCase(),ao=an?r.models.filter(a=>a.id.toLowerCase().includes(an)):r.models;async function ap(a,b){A(a);let c=await b();A(""),c.ok?(w(""),await al()):w(c.error??"action failed")}return(0,b.jsxs)("div",{children:[(0,b.jsxs)("button",{onClick:()=>m.push("/providers"),className:"mb-4 inline-flex items-center gap-1 text-[12px] text-text-muted hover:text-text",children:[(0,b.jsx)(k.Icon,{name:"arrow_back",size:15})," Providers"]}),(0,b.jsxs)("div",{className:"mb-6 flex items-center gap-3",children:[(0,b.jsx)(f.Lamp,{state:r.disabled?"idle":t?.keys.some(a=>a.healthy)??!0?"live":"down"}),(0,b.jsxs)("div",{children:[(0,b.jsx)("h1",{className:"text-[22px] font-semibold tracking-tight text-text",children:r.name||r.id}),r.name&&(0,b.jsxs)("span",{className:"text-[12px] text-text-subtle",children:[r.id,"/"]})]}),(0,b.jsx)(g.FormatBadge,{format:r.format}),r.free&&(0,b.jsx)(g.Badge,{tone:"info",children:"free"}),r.service_account&&(0,b.jsx)(g.Badge,{tone:"info",children:"service-account"}),r.disabled&&(0,b.jsx)(g.Badge,{tone:"down",children:"disabled"})]}),(0,b.jsxs)("div",{className:`grid gap-4 lg:grid-cols-2 transition-opacity ${r.disabled?"opacity-50":""}`,children:[(0,b.jsx)(i.RichCard,{header:(0,b.jsx)(i.CardTitle,{title:"Connection"}),children:$?(0,b.jsxs)("div",{className:"space-y-3",children:[(0,b.jsx)(j.Field,{label:"Name",hint:"the id — also the call prefix (name/model) & combos",children:(0,b.jsx)(j.Input,{value:ac,onChange:a=>ad(a.target.value),placeholder:"e.g. huki",className:"font-mono text-[12.5px]"})}),ac.trim()&&ac.trim()!==a&&(0,b.jsxs)("p",{className:"flex items-start gap-1.5 rounded-brand border border-warning/40 bg-warning/8 px-2.5 py-2 text-[11.5px] text-warning",children:[(0,b.jsx)(k.Icon,{name:"warning",size:14,className:"mt-0.5 flex-none"}),(0,b.jsxs)("span",{children:["Renaming rewrites the call string. CLI tools pointing at"," ",(0,b.jsxs)("code",{className:"tnum",children:[a,"/…"]})," will break until repointed; combos that target it are updated automatically."]})]}),(0,b.jsx)(j.Field,{label:"Base URL",children:(0,b.jsx)(j.Input,{value:aa,onChange:a=>ab(a.target.value),placeholder:"https://...",className:"font-mono text-[12.5px]"})}),(0,b.jsxs)("div",{className:"flex justify-end gap-2",children:[(0,b.jsx)(j.Button,{variant:"ghost",onClick:()=>_(!1),children:"Cancel"}),(0,b.jsx)(j.Button,{disabled:"editconn"===z,onClick:()=>ap("editconn",async()=>{let b=ac.trim(),c=a;if(b&&b!==a){let d=await e.adminApi.renameProvider(a,b);if(!d.ok)return d;c=b}let d=await e.adminApi.editProvider(c,{base_url:aa.trim()||void 0});return d.ok&&(_(!1),c!==a&&m.push(`/providers/${encodeURIComponent(c)}`)),d}),children:"Save"})]})]}):(0,b.jsxs)(b.Fragment,{children:[(0,b.jsxs)("div",{className:"space-y-2 text-[13px]",children:[(0,b.jsx)(q,{k:"Base URL",v:r.base_url}),(0,b.jsx)(q,{k:"Format",v:r.format}),(0,b.jsx)(q,{k:"Cooldown base",v:`${r.cooldown_base_ms}ms`}),(0,b.jsx)(q,{k:"Max retries",v:String(r.max_retries)})]}),(0,b.jsxs)("div",{className:"mt-4 flex items-center gap-2",children:[(0,b.jsxs)(j.Button,{variant:"ghost",onClick:()=>{_(!0),ab(r.base_url),ad(r.id)},children:[(0,b.jsx)(k.Icon,{name:"edit",size:15})," Edit"]}),(0,b.jsxs)(j.Button,{variant:"ghost",disabled:"test"===z,onClick:()=>ap("test",async()=>{let b=await e.adminApi.testProvider(a);return b.ok&&y(b.data),b}),children:[(0,b.jsx)(k.Icon,{name:"wifi_tethering",size:16})," ","test"===z?"Testing…":"Test connection"]}),(0,b.jsxs)(j.Button,{variant:"ghost",disabled:"discover"===z,onClick:()=>ap("discover",async()=>{let b=await e.adminApi.discoverModels(a);return b.ok&&Q(b.data?.models??[]),b}),children:[(0,b.jsx)(k.Icon,{name:"sync",size:16})," ","discover"===z?"Fetching…":"Fetch models"]})]}),x&&(0,b.jsxs)("div",{className:"mt-3 text-[12px]",children:[(0,b.jsx)(g.Badge,{tone:x.ok?"live":x.reachable?"warn":"down",children:x.ok?`ok (${x.status})`:x.reachable?`reachable (${x.status})`:"unreachable"}),x.error&&(0,b.jsx)("span",{className:"ml-2 text-text-subtle",children:x.error})]})]})}),(0,b.jsxs)(i.RichCard,{header:(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(i.CardTitle,{title:"Keys",sub:`${am.length} configured`}),(0,b.jsxs)("div",{className:"flex flex-wrap items-center gap-3",children:[am.length>1&&(0,b.jsxs)(j.Button,{variant:"ghost",disabled:V,onClick:()=>ak(am.length),children:[(0,b.jsx)(k.Icon,{name:V?"progress_activity":"sync",size:15}),V?"Testing…":"Test All"]}),V&&(0,b.jsxs)(j.Button,{variant:"ghost",onClick:()=>{Z.current=!0},children:[(0,b.jsx)(k.Icon,{name:"stop",size:15})," Stop"]}),(0,b.jsx)("span",{className:"text-[11px] text-text-subtle",children:"Round Robin"}),(0,b.jsx)("button",{onClick:()=>{let b="round-robin"===r.strategy?null:"round-robin";e.adminApi.setProviderStrategy(a,b,r.sticky??1).then(()=>al())},className:`relative h-5 w-9 rounded-full transition-colors ${"round-robin"===r.strategy?"bg-accent":"bg-border-subtle"}`,"aria-label":"Toggle round-robin",children:(0,b.jsx)("span",{className:`absolute left-0.5 top-0.5 h-4 w-4 rounded-full bg-white transition-transform ${"round-robin"===r.strategy?"translate-x-[18px]":"translate-x-0"}`})}),"round-robin"===r.strategy&&(0,b.jsxs)("div",{className:"flex items-center gap-1.5",children:[(0,b.jsx)("span",{className:"text-[11px] text-text-subtle",children:"Sticky:"}),(0,b.jsxs)("div",{className:"flex items-center rounded-brand border border-border-subtle",children:[(0,b.jsx)("button",{type:"button",disabled:(r.sticky??1)<=1,onClick:()=>void e.adminApi.setProviderStrategy(a,"round-robin",Math.max(1,(r.sticky??1)-1)).then(()=>al()),className:"px-1.5 py-0.5 text-text-subtle transition-colors hover:text-text disabled:opacity-30","aria-label":"Decrease sticky",children:(0,b.jsx)(k.Icon,{name:"remove",size:13})}),(0,b.jsx)("span",{className:"tnum w-6 text-center text-[11px] text-text",children:r.sticky??1}),(0,b.jsx)("button",{type:"button",onClick:()=>void e.adminApi.setProviderStrategy(a,"round-robin",(r.sticky??1)+1).then(()=>al()),className:"px-1.5 py-0.5 text-text-subtle transition-colors hover:text-text","aria-label":"Increase sticky",children:(0,b.jsx)(k.Icon,{name:"add",size:13})})]})]})]})]}),children:[X&&(0,b.jsx)("div",{className:"mb-3 flex items-center gap-2 text-[11.5px]",children:(0,b.jsxs)(g.Badge,{tone:0===X.failed?"live":"warn",children:[X.total," tested: ",X.passed," valid, ",X.failed," failed"]})}),0===am.length?(0,b.jsx)(l.Empty,{children:"No keys (free / service-account provider)."}):(0,b.jsx)("div",{className:"space-y-1.5",children:am.map((c,d)=>{let i=t?.keys[d],l=T[d],m=l&&"testing"!==l?l:null,n=m?m.ok?"live":m.reachable?"idle":"down":i?i.healthy?"live":"down":"idle",o=r.key_names?.[c],p=r.disabled_keys?.includes(d)??!1;return F===d?(0,b.jsxs)("div",{className:"space-y-2 rounded-brand border border-accent bg-accent-soft/40 px-3 py-2.5",children:[(0,b.jsx)(j.Input,{value:H,onChange:a=>I(a.target.value),placeholder:"key name (optional)"}),(0,b.jsx)(j.Input,{value:J,onChange:a=>K(a.target.value),placeholder:"new key value (leave blank to keep)",className:"font-mono text-[12.5px]"}),(0,b.jsxs)("div",{className:"flex justify-end gap-2",children:[(0,b.jsx)(j.Button,{variant:"ghost",onClick:()=>G(null),children:"Cancel"}),(0,b.jsx)(j.Button,{disabled:z===`editkey${d}`,onClick:()=>ap(`editkey${d}`,async()=>{let b=await e.adminApi.editKey(a,d,{name:H,key:J.trim()||void 0});return b.ok&&G(null),b}),children:"Save"})]})]},d):(0,b.jsxs)("div",{className:`rounded-brand border border-border-subtle px-3 py-2${p?" opacity-60":""}`,children:[(0,b.jsxs)("div",{className:"flex items-center gap-2",children:[(0,b.jsxs)("div",{className:"flex flex-col",children:[(0,b.jsx)("button",{onClick:()=>ap(`reorder${d}up`,()=>e.adminApi.reorderKey(a,d,d-1)),disabled:0===d,className:"p-0.5 text-text-subtle hover:text-text disabled:opacity-30","aria-label":"Move up",children:(0,b.jsx)(k.Icon,{name:"keyboard_arrow_up",size:14})}),(0,b.jsx)("button",{onClick:()=>ap(`reorder${d}dn`,()=>e.adminApi.reorderKey(a,d,d+1)),disabled:d===am.length-1,className:"p-0.5 text-text-subtle hover:text-text disabled:opacity-30","aria-label":"Move down",children:(0,b.jsx)(k.Icon,{name:"keyboard_arrow_down",size:14})})]}),(0,b.jsx)(f.Lamp,{state:n}),(0,b.jsxs)("div",{className:"min-w-0 flex-1",children:[o&&(0,b.jsx)("div",{className:"text-[12px] font-semibold text-text-muted",children:o}),(0,b.jsx)("span",{className:"block truncate font-mono text-[12.5px] text-text",children:ae[d]??c})]}),ae[d]&&(0,b.jsx)("button",{onClick:()=>{navigator.clipboard.writeText(ae[d])},className:"flex-none rounded p-1 text-text-subtle transition-colors hover:text-text","aria-label":"Copy key",title:"Copy to clipboard",children:(0,b.jsx)(k.Icon,{name:"content_copy",size:14})}),i&&i.cooldown_ms>0&&(0,b.jsx)(h.CooldownTimer,{ms:i.cooldown_ms}),(0,b.jsx)("button",{onClick:async()=>{if(ae[d])return void af(a=>{let b={...a};return delete b[d],b});let b=await e.adminApi.revealKey(a,d);b.ok&&b.data?.key&&af(a=>({...a,[d]:b.data.key}))},className:"flex-none rounded p-1 text-text-subtle transition-colors hover:text-text","aria-label":ae[d]?"Hide key":"Show key",title:ae[d]?"Hide key":"Show key",children:(0,b.jsx)(k.Icon,{name:ae[d]?"visibility_off":"visibility",size:15})}),(0,b.jsx)("button",{onClick:()=>ap(`toggle${d}`,()=>e.adminApi.toggleKey(a,d,p)),className:"flex-none rounded p-1 text-text-subtle transition-colors hover:text-text","aria-label":p?"Enable key":"Disable key",title:p?"Enable this key":"Disable this key",children:(0,b.jsx)(k.Icon,{name:p?"toggle_off":"toggle_on",size:20,className:p?"text-text-subtle":"text-success"})}),(0,b.jsx)("button",{onClick:()=>aj(d),disabled:"testing"===l,className:"flex-none rounded p-1 text-text-subtle transition-colors hover:text-text disabled:opacity-60","aria-label":`Check key ${d+1}`,title:"Check this key against the base URL",children:(0,b.jsx)(k.Icon,{name:"testing"===l?"progress_activity":"wifi_tethering",size:15})}),(0,b.jsx)("button",{onClick:()=>{G(d),I(o??""),K("")},className:"flex-none rounded p-1 text-text-subtle transition-colors hover:text-text","aria-label":`Edit key ${d+1}`,title:"Rename or replace this key",children:(0,b.jsx)(k.Icon,{name:"edit",size:15})}),(0,b.jsx)("button",{onClick:()=>ap(`rmkey${d}`,()=>e.adminApi.removeKey(a,d)),className:"flex-none rounded p-1 text-text-subtle transition-colors hover:text-danger","aria-label":"Remove key",children:(0,b.jsx)(k.Icon,{name:"delete",size:15})})]}),m&&(0,b.jsxs)("div",{className:"mt-1.5 flex items-center gap-2 pl-8 text-[11.5px]",children:[(0,b.jsx)(g.Badge,{tone:m.ok?"live":m.reachable?"warn":"down",children:m.ok?"valid":m.reachable?`reachable (${m.status})`:"invalid"}),m.error&&(0,b.jsx)("span",{className:"truncate text-danger",children:m.error})]}),!m&&i?.last_error&&(0,b.jsxs)("div",{className:"mt-1.5 flex items-center gap-2 pl-8 text-[11.5px]",children:[(0,b.jsxs)("span",{className:"text-danger",children:[i.last_error.status?`${i.last_error.status}: `:"",i.last_error.message]}),(0,b.jsx)("span",{className:"text-text-subtle",children:new Date(i.last_error.at).toLocaleTimeString()})]})]},d)})}),(0,b.jsxs)("div",{className:"mt-3 space-y-2",children:[(0,b.jsx)(j.Input,{value:D,onChange:a=>E(a.target.value),placeholder:"key name (optional, e.g. primary)"}),(0,b.jsxs)("div",{className:"flex gap-2",children:[(0,b.jsx)(j.Input,{value:B,onChange:a=>C(a.target.value),placeholder:"add a key…",className:"font-mono text-[12.5px]"}),(0,b.jsx)(j.Button,{disabled:!B||"addkey"===z,onClick:()=>ap("addkey",async()=>{let b=await e.adminApi.addKey(a,B,D.trim()||void 0);return b.ok&&(C(""),E("")),b}),children:"Add"})]})]})]}),(0,b.jsxs)(i.RichCard,{className:"lg:col-span-2",header:(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(i.CardTitle,{title:"Models served",sub:`${r.models.length} in catalog`}),r.models.length>0&&(0,b.jsx)("button",{onClick:()=>ap("clear",()=>e.adminApi.clearModels(a)),disabled:"clear"===z,className:"text-[12px] text-text-subtle hover:text-danger",children:"Clear all"})]}),children:[0===r.models.length?(0,b.jsx)(l.Empty,{children:"No models. Add one below, or fetch them for a free/auto provider."}):(0,b.jsxs)(b.Fragment,{children:[(0,b.jsxs)("p",{className:"mb-2.5 text-[12px] text-text-subtle",children:["Call any of these as ",(0,b.jsxs)("span",{className:"tnum text-text-muted",children:[r.id,"/<model>"]}),", as a combo alias, or by the bare id."]}),r.models.length>8&&(0,b.jsxs)("div",{className:"mb-2.5 flex items-center gap-2",children:[(0,b.jsxs)("div",{className:"relative flex-1",children:[(0,b.jsx)(k.Icon,{name:"search",size:15,className:"pointer-events-none absolute left-2.5 top-1/2 -translate-y-1/2 text-text-subtle"}),(0,b.jsx)(j.Input,{value:N,onChange:a=>O(a.target.value),placeholder:"filter models…",className:"pl-8"})]}),(0,b.jsx)("span",{className:"tnum whitespace-nowrap text-[12px] text-text-subtle",children:an?`${ao.length} of ${r.models.length}`:`${r.models.length}`})]}),0===ao.length?(0,b.jsxs)(l.Empty,{children:["No model matches “",N,"”."]}):(0,b.jsx)("div",{className:"max-h-[360px] divide-y divide-border-subtle overflow-y-auto rounded-brand border border-border-subtle",children:ao.map(c=>{let d=R[c.id];return(0,b.jsxs)("div",{className:"group flex items-center justify-between gap-3 px-3 py-2 hover:bg-bg",children:[(0,b.jsxs)("div",{className:"flex min-w-0 items-center gap-2",children:[(0,b.jsx)(k.Icon,{name:"ok"===d?"check_circle":"fail"===d?"cancel":"smart_toy",size:15,className:`flex-none ${"ok"===d?"text-success":"fail"===d?"text-danger":"text-text-subtle"}`}),(0,b.jsxs)("span",{className:"tnum truncate text-[12.5px]",children:[(0,b.jsxs)("span",{className:"text-text-subtle",children:[r.id,"/"]}),(0,b.jsx)("span",{className:"text-text",children:c.id})]}),(0,b.jsx)(o.CapacityBadges,{model:c.id,provider:r.id}),(void 0!==c.price_in||void 0!==c.price_out)&&(0,b.jsxs)("span",{className:"tnum whitespace-nowrap text-[11px] text-text-subtle",children:[l.fmt.cost(c.price_in??0),"/",l.fmt.cost(c.price_out??0)," per 1M"]})]}),(0,b.jsxs)("div",{className:"flex flex-none items-center gap-0.5",children:[(0,b.jsx)("button",{onClick:()=>ai(c.id),disabled:"testing"===d,className:"rounded p-1 text-text-subtle transition-colors hover:bg-surface hover:text-accent disabled:opacity-60","aria-label":`Test ${c.id}`,title:"fail"===d?"Test failed — click to retry":"Test this model",children:(0,b.jsx)(k.Icon,{name:"testing"===d?"progress_activity":"science",size:15})}),(0,b.jsx)("button",{onClick:()=>ap(`rmmodel${c.id}`,()=>e.adminApi.removeModel(a,c.id)),disabled:z===`rmmodel${c.id}`,className:"rounded p-1 text-text-subtle transition-colors hover:bg-surface hover:text-danger disabled:opacity-40","aria-label":`Remove ${c.id}`,children:(0,b.jsx)(k.Icon,{name:"delete",size:16})})]})]},c.id)})})]}),(0,b.jsxs)("div",{className:"mt-3 flex gap-2",children:[(0,b.jsx)(j.Input,{value:L,onChange:a=>M(a.target.value),placeholder:"add a model id…"}),(0,b.jsx)(j.Button,{disabled:!L||"addmodel"===z,onClick:()=>ap("addmodel",async()=>{let b=await e.adminApi.addModel(a,L);return b.ok&&M(""),b}),children:"Add"})]})]})]}),P&&(0,b.jsx)(n,{models:P,busy:"addmodels"===z,onClose:()=>Q(null),onAdd:b=>ap("addmodels",async()=>{let c=await e.adminApi.addModels(a,b);return c.ok&&Q(null),c})}),(0,b.jsx)("div",{className:"mt-6",children:(0,b.jsxs)(j.Button,{variant:"danger",onClick:()=>ah(!0),children:[(0,b.jsx)(k.Icon,{name:"delete",size:16})," Remove provider"]})}),ag&&(0,b.jsx)(p.ConfirmModal,{title:"Remove provider",message:`Delete "${r.name??a}"? All keys and model associations will be lost.`,confirmLabel:"Remove",busy:"rmprov"===z,onCancel:()=>ah(!1),onConfirm:()=>ap("rmprov",async()=>{let b=await e.adminApi.removeProvider(a);return b.ok?m.push("/providers"):ah(!1),b})})]})}],33410)}];
1
+ module.exports=[33410,a=>{"use strict";var b=a.i(87924),c=a.i(72131),d=a.i(50944),e=a.i(56173),f=a.i(47153),g=a.i(2693),h=a.i(2799),i=a.i(85732),j=a.i(7078),k=a.i(93026),l=a.i(58918);function m({checked:a,indeterminate:c,onChange:d,className:e,ariaLabel:f}){let g=a||c;return(0,b.jsx)("button",{type:"button",role:"checkbox","aria-checked":c?"mixed":a,"aria-label":f,onClick:a=>{a.stopPropagation(),d()},className:`flex h-[18px] w-[18px] flex-none items-center justify-center rounded-[5px] border transition-colors ${g?"border-accent bg-accent text-accent-ink":"border-border bg-bg text-transparent hover:border-text-subtle"}${e?` ${e}`:""}`,children:(0,b.jsx)(k.Icon,{name:c?"remove":"check",size:13})})}function n({models:a,busy:d,onAdd:e,onClose:f}){let[g,h]=(0,c.useState)(""),[i,l]=(0,c.useState)(()=>new Set(a.filter(a=>!a.added).map(a=>a.id))),o=(0,c.useMemo)(()=>{let b=g.trim().toLowerCase();return b?a.filter(a=>a.id.toLowerCase().includes(b)):a},[a,g]);function p(a){l(b=>{let c=new Set(b);return c.has(a)?c.delete(a):c.add(a),c})}let q=o.filter(a=>i.has(a.id)).length,r=o.length>0&&q===o.length;function s(){l(a=>{let b=new Set(a);return r?o.forEach(a=>b.delete(a.id)):o.forEach(a=>b.add(a.id)),b})}return(0,b.jsx)("div",{className:"fixed inset-0 z-50 grid place-items-center bg-black/50 p-6",onClick:f,children:(0,b.jsxs)("div",{className:"flex max-h-[80vh] w-full max-w-[480px] flex-col overflow-hidden rounded-brand-lg border border-border bg-surface shadow-elevated",onClick:a=>a.stopPropagation(),children:[(0,b.jsxs)("header",{className:"flex items-center justify-between border-b border-border-subtle px-4 py-3",children:[(0,b.jsxs)("span",{className:"text-[14px] font-semibold text-text",children:[a.length," models found"]}),(0,b.jsx)("button",{onClick:f,className:"text-text-subtle hover:text-text","aria-label":"Close",children:(0,b.jsx)(k.Icon,{name:"close",size:18})})]}),(0,b.jsx)("div",{className:"border-b border-border-subtle px-4 py-2.5",children:(0,b.jsx)(j.Input,{value:g,onChange:a=>h(a.target.value),placeholder:"filter…",autoFocus:!0})}),o.length>0&&(0,b.jsxs)("button",{onClick:s,className:"flex items-center gap-2.5 border-b border-border-subtle px-4 py-2 text-left hover:bg-surface-2",children:[(0,b.jsx)(m,{checked:r,indeterminate:q>0&&!r,onChange:s,ariaLabel:"Select all"}),(0,b.jsxs)("span",{className:"text-[12.5px] font-medium text-text",children:["Select all",g?" (filtered)":""]}),(0,b.jsxs)("span",{className:"ml-auto tnum text-[11px] text-text-subtle",children:[q,"/",o.length]})]}),(0,b.jsx)("div",{className:"flex-1 overflow-y-auto px-2 py-2",children:0===o.length?(0,b.jsx)("div",{className:"px-2 py-6 text-center text-[13px] text-text-muted",children:"No matches."}):o.map(a=>{let c=i.has(a.id);return(0,b.jsxs)("button",{onClick:()=>p(a.id),className:`flex w-full items-center gap-2.5 rounded-brand border px-2.5 py-2 text-left transition-colors ${c?"border-accent/40 bg-accent-soft":"border-transparent hover:bg-surface-2"}`,children:[(0,b.jsx)(m,{checked:c,onChange:()=>p(a.id),ariaLabel:a.id}),(0,b.jsx)("span",{className:"flex-1 truncate text-[12.5px] text-text",children:a.id}),a.added&&(0,b.jsx)("span",{className:"text-[11px] text-text-subtle",children:"in catalog"})]},a.id)})}),(0,b.jsxs)("footer",{className:"flex items-center justify-between gap-3 border-t border-border-subtle bg-bg-alt px-4 py-2.5",children:[(0,b.jsxs)("span",{className:"tnum text-[12px] text-text-muted",children:[i.size," selected"]}),(0,b.jsxs)("div",{className:"flex gap-2",children:[(0,b.jsx)(j.Button,{variant:"ghost",onClick:f,children:"Cancel"}),(0,b.jsx)(j.Button,{disabled:0===i.size||d,onClick:()=>e([...i]),children:d?"Adding…":`Add ${i.size}`})]})]})]})})}var o=a.i(52065),p=a.i(73858);function q({k:a,v:c}){return(0,b.jsxs)("div",{className:"flex items-center justify-between gap-3",children:[(0,b.jsx)("span",{className:"text-text-subtle",children:a}),(0,b.jsx)("span",{className:"truncate text-text",children:c})]})}a.s(["ProviderDetail",0,function({id:a}){let m=(0,d.useRouter)(),[r,s]=(0,c.useState)(null),[t,u]=(0,c.useState)(null),[v,w]=(0,c.useState)(""),[x,y]=(0,c.useState)(null),[z,A]=(0,c.useState)(""),[B,C]=(0,c.useState)(""),[D,E]=(0,c.useState)(""),[F,G]=(0,c.useState)(null),[H,I]=(0,c.useState)(""),[J,K]=(0,c.useState)(""),[L,M]=(0,c.useState)(""),[N,O]=(0,c.useState)(""),[P,Q]=(0,c.useState)(null),[R,S]=(0,c.useState)({}),[T,U]=(0,c.useState)({}),[V,W]=(0,c.useState)(!1),[X,Y]=(0,c.useState)(null),Z=(0,c.useRef)(!1),[$,_]=(0,c.useState)(!1),[aa,ab]=(0,c.useState)(""),[ac,ad]=(0,c.useState)(""),[ae,af]=(0,c.useState)({}),[ag,ah]=(0,c.useState)(!1);async function ai(b){S(a=>({...a,[b]:"testing"}));let c=await e.adminApi.testModel(a,b);S(a=>({...a,[b]:c.ok&&c.data?.ok?"ok":"fail"}))}async function aj(b){U(a=>({...a,[b]:"testing"}));let c=await e.adminApi.testKey(a,b);U(a=>({...a,[b]:c.data??{ok:!1,reachable:!1,status:0,error:c.error}}))}async function ak(b){Z.current=!1,W(!0),Y(null),U({});let c=0,d=0;for(let f=0;f<b&&!Z.current;f++){U(a=>({...a,[f]:"testing"}));let g=await e.adminApi.testKey(a,f),h=g.data??{ok:!1,reachable:!1,status:0,error:g.error};U(a=>({...a,[f]:h})),h.ok?c++:d++,f<b-1&&!Z.current&&await new Promise(a=>setTimeout(a,500))}W(!1),Y({total:b,passed:c,failed:d})}let al=(0,c.useCallback)(async()=>{let[b,c]=await Promise.all([fetch("/api/gw/admin/config"),e.adminApi.providers()]);if(!b.ok)return void w("could not reach the gateway");let d=(await b.json()).providers.find(b=>b.id===a)??null;d?(w(""),s(d),u(c.data?.providers.find(b=>b.id===a)??null)):w(`provider "${a}" not found`)},[a]);if((0,c.useEffect)(()=>{al()},[al]),v)return(0,b.jsx)(l.Empty,{children:v});if(!r)return(0,b.jsx)(l.Empty,{children:"Loading…"});let am=r.api_keys??(r.api_key?[r.api_key]:[]),an=N.trim().toLowerCase(),ao=an?r.models.filter(a=>a.id.toLowerCase().includes(an)):r.models;async function ap(a,b){A(a);let c=await b();A(""),c.ok?(w(""),await al()):w(c.error??"action failed")}return(0,b.jsxs)("div",{children:[(0,b.jsxs)("button",{onClick:()=>m.push("/providers"),className:"mb-4 inline-flex items-center gap-1 text-[12px] text-text-muted hover:text-text",children:[(0,b.jsx)(k.Icon,{name:"arrow_back",size:15})," Providers"]}),(0,b.jsxs)("div",{className:"mb-6 flex items-center gap-3",children:[(0,b.jsx)(f.Lamp,{state:r.disabled?"idle":t?.keys.some(a=>a.healthy)??!0?"live":"down"}),(0,b.jsxs)("div",{children:[(0,b.jsx)("h1",{className:"text-[22px] font-semibold tracking-tight text-text",children:r.name||r.id}),r.name&&(0,b.jsxs)("span",{className:"text-[12px] text-text-subtle",children:[r.id,"/"]})]}),(0,b.jsx)(g.FormatBadge,{format:r.format}),r.free&&(0,b.jsx)(g.Badge,{tone:"info",children:"free"}),r.service_account&&(0,b.jsx)(g.Badge,{tone:"info",children:"service-account"}),r.disabled&&(0,b.jsx)(g.Badge,{tone:"down",children:"disabled"})]}),(0,b.jsxs)("div",{className:`grid gap-4 lg:grid-cols-2 transition-opacity ${r.disabled?"opacity-50":""}`,children:[(0,b.jsx)(i.RichCard,{header:(0,b.jsx)(i.CardTitle,{title:"Connection"}),children:$?(0,b.jsxs)("div",{className:"space-y-3",children:[(0,b.jsx)(j.Field,{label:"Name",hint:"the id — also the call prefix (name/model) & combos",children:(0,b.jsx)(j.Input,{value:ac,onChange:a=>ad(a.target.value),placeholder:"e.g. openai",className:"font-mono text-[12.5px]"})}),ac.trim()&&ac.trim()!==a&&(0,b.jsxs)("p",{className:"flex items-start gap-1.5 rounded-brand border border-warning/40 bg-warning/8 px-2.5 py-2 text-[11.5px] text-warning",children:[(0,b.jsx)(k.Icon,{name:"warning",size:14,className:"mt-0.5 flex-none"}),(0,b.jsxs)("span",{children:["Renaming rewrites the call string. CLI tools pointing at"," ",(0,b.jsxs)("code",{className:"tnum",children:[a,"/…"]})," will break until repointed; combos that target it are updated automatically."]})]}),(0,b.jsx)(j.Field,{label:"Base URL",children:(0,b.jsx)(j.Input,{value:aa,onChange:a=>ab(a.target.value),placeholder:"https://...",className:"font-mono text-[12.5px]"})}),(0,b.jsxs)("div",{className:"flex justify-end gap-2",children:[(0,b.jsx)(j.Button,{variant:"ghost",onClick:()=>_(!1),children:"Cancel"}),(0,b.jsx)(j.Button,{disabled:"editconn"===z,onClick:()=>ap("editconn",async()=>{let b=ac.trim(),c=a;if(b&&b!==a){let d=await e.adminApi.renameProvider(a,b);if(!d.ok)return d;c=b}let d=await e.adminApi.editProvider(c,{base_url:aa.trim()||void 0});return d.ok&&(_(!1),c!==a&&m.push(`/providers/${encodeURIComponent(c)}`)),d}),children:"Save"})]})]}):(0,b.jsxs)(b.Fragment,{children:[(0,b.jsxs)("div",{className:"space-y-2 text-[13px]",children:[(0,b.jsx)(q,{k:"Base URL",v:r.base_url}),(0,b.jsx)(q,{k:"Format",v:r.format}),(0,b.jsx)(q,{k:"Cooldown base",v:`${r.cooldown_base_ms}ms`}),(0,b.jsx)(q,{k:"Max retries",v:String(r.max_retries)})]}),(0,b.jsxs)("div",{className:"mt-4 flex items-center gap-2",children:[(0,b.jsxs)(j.Button,{variant:"ghost",onClick:()=>{_(!0),ab(r.base_url),ad(r.id)},children:[(0,b.jsx)(k.Icon,{name:"edit",size:15})," Edit"]}),(0,b.jsxs)(j.Button,{variant:"ghost",disabled:"test"===z,onClick:()=>ap("test",async()=>{let b=await e.adminApi.testProvider(a);return b.ok&&y(b.data),b}),children:[(0,b.jsx)(k.Icon,{name:"wifi_tethering",size:16})," ","test"===z?"Testing…":"Test connection"]}),(0,b.jsxs)(j.Button,{variant:"ghost",disabled:"discover"===z,onClick:()=>ap("discover",async()=>{let b=await e.adminApi.discoverModels(a);return b.ok&&Q(b.data?.models??[]),b}),children:[(0,b.jsx)(k.Icon,{name:"sync",size:16})," ","discover"===z?"Fetching…":"Fetch models"]})]}),x&&(0,b.jsxs)("div",{className:"mt-3 text-[12px]",children:[(0,b.jsx)(g.Badge,{tone:x.ok?"live":x.reachable?"warn":"down",children:x.ok?`ok (${x.status})`:x.reachable?`reachable (${x.status})`:"unreachable"}),x.error&&(0,b.jsx)("span",{className:"ml-2 text-text-subtle",children:x.error})]})]})}),(0,b.jsxs)(i.RichCard,{header:(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(i.CardTitle,{title:"Keys",sub:`${am.length} configured`}),(0,b.jsxs)("div",{className:"flex flex-wrap items-center gap-3",children:[am.length>1&&(0,b.jsxs)(j.Button,{variant:"ghost",disabled:V,onClick:()=>ak(am.length),children:[(0,b.jsx)(k.Icon,{name:V?"progress_activity":"sync",size:15}),V?"Testing…":"Test All"]}),V&&(0,b.jsxs)(j.Button,{variant:"ghost",onClick:()=>{Z.current=!0},children:[(0,b.jsx)(k.Icon,{name:"stop",size:15})," Stop"]}),(0,b.jsx)("span",{className:"text-[11px] text-text-subtle",children:"Round Robin"}),(0,b.jsx)("button",{onClick:()=>{let b="round-robin"===r.strategy?null:"round-robin";e.adminApi.setProviderStrategy(a,b,r.sticky??1).then(()=>al())},className:`relative h-5 w-9 rounded-full transition-colors ${"round-robin"===r.strategy?"bg-accent":"bg-border-subtle"}`,"aria-label":"Toggle round-robin",children:(0,b.jsx)("span",{className:`absolute left-0.5 top-0.5 h-4 w-4 rounded-full bg-white transition-transform ${"round-robin"===r.strategy?"translate-x-[18px]":"translate-x-0"}`})}),"round-robin"===r.strategy&&(0,b.jsxs)("div",{className:"flex items-center gap-1.5",children:[(0,b.jsx)("span",{className:"text-[11px] text-text-subtle",children:"Sticky:"}),(0,b.jsxs)("div",{className:"flex items-center rounded-brand border border-border-subtle",children:[(0,b.jsx)("button",{type:"button",disabled:(r.sticky??1)<=1,onClick:()=>void e.adminApi.setProviderStrategy(a,"round-robin",Math.max(1,(r.sticky??1)-1)).then(()=>al()),className:"px-1.5 py-0.5 text-text-subtle transition-colors hover:text-text disabled:opacity-30","aria-label":"Decrease sticky",children:(0,b.jsx)(k.Icon,{name:"remove",size:13})}),(0,b.jsx)("span",{className:"tnum w-6 text-center text-[11px] text-text",children:r.sticky??1}),(0,b.jsx)("button",{type:"button",onClick:()=>void e.adminApi.setProviderStrategy(a,"round-robin",(r.sticky??1)+1).then(()=>al()),className:"px-1.5 py-0.5 text-text-subtle transition-colors hover:text-text","aria-label":"Increase sticky",children:(0,b.jsx)(k.Icon,{name:"add",size:13})})]})]})]})]}),children:[X&&(0,b.jsx)("div",{className:"mb-3 flex items-center gap-2 text-[11.5px]",children:(0,b.jsxs)(g.Badge,{tone:0===X.failed?"live":"warn",children:[X.total," tested: ",X.passed," valid, ",X.failed," failed"]})}),0===am.length?(0,b.jsx)(l.Empty,{children:"No keys (free / service-account provider)."}):(0,b.jsx)("div",{className:"space-y-1.5",children:am.map((c,d)=>{let i=t?.keys[d],l=T[d],m=l&&"testing"!==l?l:null,n=m?m.ok?"live":m.reachable?"idle":"down":i?i.healthy?"live":"down":"idle",o=r.key_names?.[c],p=r.disabled_keys?.includes(d)??!1;return F===d?(0,b.jsxs)("div",{className:"space-y-2 rounded-brand border border-accent bg-accent-soft/40 px-3 py-2.5",children:[(0,b.jsx)(j.Input,{value:H,onChange:a=>I(a.target.value),placeholder:"key name (optional)"}),(0,b.jsx)(j.Input,{value:J,onChange:a=>K(a.target.value),placeholder:"new key value (leave blank to keep)",className:"font-mono text-[12.5px]"}),(0,b.jsxs)("div",{className:"flex justify-end gap-2",children:[(0,b.jsx)(j.Button,{variant:"ghost",onClick:()=>G(null),children:"Cancel"}),(0,b.jsx)(j.Button,{disabled:z===`editkey${d}`,onClick:()=>ap(`editkey${d}`,async()=>{let b=await e.adminApi.editKey(a,d,{name:H,key:J.trim()||void 0});return b.ok&&G(null),b}),children:"Save"})]})]},d):(0,b.jsxs)("div",{className:`rounded-brand border border-border-subtle px-3 py-2${p?" opacity-60":""}`,children:[(0,b.jsxs)("div",{className:"flex items-center gap-2",children:[(0,b.jsxs)("div",{className:"flex flex-col",children:[(0,b.jsx)("button",{onClick:()=>ap(`reorder${d}up`,()=>e.adminApi.reorderKey(a,d,d-1)),disabled:0===d,className:"p-0.5 text-text-subtle hover:text-text disabled:opacity-30","aria-label":"Move up",children:(0,b.jsx)(k.Icon,{name:"keyboard_arrow_up",size:14})}),(0,b.jsx)("button",{onClick:()=>ap(`reorder${d}dn`,()=>e.adminApi.reorderKey(a,d,d+1)),disabled:d===am.length-1,className:"p-0.5 text-text-subtle hover:text-text disabled:opacity-30","aria-label":"Move down",children:(0,b.jsx)(k.Icon,{name:"keyboard_arrow_down",size:14})})]}),(0,b.jsx)(f.Lamp,{state:n}),(0,b.jsxs)("div",{className:"min-w-0 flex-1",children:[o&&(0,b.jsx)("div",{className:"text-[12px] font-semibold text-text-muted",children:o}),(0,b.jsx)("span",{className:"block truncate font-mono text-[12.5px] text-text",children:ae[d]??c})]}),ae[d]&&(0,b.jsx)("button",{onClick:()=>{navigator.clipboard.writeText(ae[d])},className:"flex-none rounded p-1 text-text-subtle transition-colors hover:text-text","aria-label":"Copy key",title:"Copy to clipboard",children:(0,b.jsx)(k.Icon,{name:"content_copy",size:14})}),i&&i.cooldown_ms>0&&(0,b.jsx)(h.CooldownTimer,{ms:i.cooldown_ms}),(0,b.jsx)("button",{onClick:async()=>{if(ae[d])return void af(a=>{let b={...a};return delete b[d],b});let b=await e.adminApi.revealKey(a,d);b.ok&&b.data?.key&&af(a=>({...a,[d]:b.data.key}))},className:"flex-none rounded p-1 text-text-subtle transition-colors hover:text-text","aria-label":ae[d]?"Hide key":"Show key",title:ae[d]?"Hide key":"Show key",children:(0,b.jsx)(k.Icon,{name:ae[d]?"visibility_off":"visibility",size:15})}),(0,b.jsx)("button",{onClick:()=>ap(`toggle${d}`,()=>e.adminApi.toggleKey(a,d,p)),className:"flex-none rounded p-1 text-text-subtle transition-colors hover:text-text","aria-label":p?"Enable key":"Disable key",title:p?"Enable this key":"Disable this key",children:(0,b.jsx)(k.Icon,{name:p?"toggle_off":"toggle_on",size:20,className:p?"text-text-subtle":"text-success"})}),(0,b.jsx)("button",{onClick:()=>aj(d),disabled:"testing"===l,className:"flex-none rounded p-1 text-text-subtle transition-colors hover:text-text disabled:opacity-60","aria-label":`Check key ${d+1}`,title:"Check this key against the base URL",children:(0,b.jsx)(k.Icon,{name:"testing"===l?"progress_activity":"wifi_tethering",size:15})}),(0,b.jsx)("button",{onClick:()=>{G(d),I(o??""),K("")},className:"flex-none rounded p-1 text-text-subtle transition-colors hover:text-text","aria-label":`Edit key ${d+1}`,title:"Rename or replace this key",children:(0,b.jsx)(k.Icon,{name:"edit",size:15})}),(0,b.jsx)("button",{onClick:()=>ap(`rmkey${d}`,()=>e.adminApi.removeKey(a,d)),className:"flex-none rounded p-1 text-text-subtle transition-colors hover:text-danger","aria-label":"Remove key",children:(0,b.jsx)(k.Icon,{name:"delete",size:15})})]}),m&&(0,b.jsxs)("div",{className:"mt-1.5 flex items-center gap-2 pl-8 text-[11.5px]",children:[(0,b.jsx)(g.Badge,{tone:m.ok?"live":m.reachable?"warn":"down",children:m.ok?"valid":m.reachable?`reachable (${m.status})`:"invalid"}),m.error&&(0,b.jsx)("span",{className:"truncate text-danger",children:m.error})]}),!m&&i?.last_error&&(0,b.jsxs)("div",{className:"mt-1.5 flex items-center gap-2 pl-8 text-[11.5px]",children:[(0,b.jsxs)("span",{className:"text-danger",children:[i.last_error.status?`${i.last_error.status}: `:"",i.last_error.message]}),(0,b.jsx)("span",{className:"text-text-subtle",children:new Date(i.last_error.at).toLocaleTimeString()})]})]},d)})}),(0,b.jsxs)("div",{className:"mt-3 space-y-2",children:[(0,b.jsx)(j.Input,{value:D,onChange:a=>E(a.target.value),placeholder:"key name (optional, e.g. primary)"}),(0,b.jsxs)("div",{className:"flex gap-2",children:[(0,b.jsx)(j.Input,{value:B,onChange:a=>C(a.target.value),placeholder:"add a key…",className:"font-mono text-[12.5px]"}),(0,b.jsx)(j.Button,{disabled:!B||"addkey"===z,onClick:()=>ap("addkey",async()=>{let b=await e.adminApi.addKey(a,B,D.trim()||void 0);return b.ok&&(C(""),E("")),b}),children:"Add"})]})]})]}),(0,b.jsxs)(i.RichCard,{className:"lg:col-span-2",header:(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(i.CardTitle,{title:"Models served",sub:`${r.models.length} in catalog`}),r.models.length>0&&(0,b.jsx)("button",{onClick:()=>ap("clear",()=>e.adminApi.clearModels(a)),disabled:"clear"===z,className:"text-[12px] text-text-subtle hover:text-danger",children:"Clear all"})]}),children:[0===r.models.length?(0,b.jsx)(l.Empty,{children:"No models. Add one below, or fetch them for a free/auto provider."}):(0,b.jsxs)(b.Fragment,{children:[(0,b.jsxs)("p",{className:"mb-2.5 text-[12px] text-text-subtle",children:["Call any of these as ",(0,b.jsxs)("span",{className:"tnum text-text-muted",children:[r.id,"/<model>"]}),", as a combo alias, or by the bare id."]}),r.models.length>8&&(0,b.jsxs)("div",{className:"mb-2.5 flex items-center gap-2",children:[(0,b.jsxs)("div",{className:"relative flex-1",children:[(0,b.jsx)(k.Icon,{name:"search",size:15,className:"pointer-events-none absolute left-2.5 top-1/2 -translate-y-1/2 text-text-subtle"}),(0,b.jsx)(j.Input,{value:N,onChange:a=>O(a.target.value),placeholder:"filter models…",className:"pl-8"})]}),(0,b.jsx)("span",{className:"tnum whitespace-nowrap text-[12px] text-text-subtle",children:an?`${ao.length} of ${r.models.length}`:`${r.models.length}`})]}),0===ao.length?(0,b.jsxs)(l.Empty,{children:["No model matches “",N,"”."]}):(0,b.jsx)("div",{className:"max-h-[360px] divide-y divide-border-subtle overflow-y-auto rounded-brand border border-border-subtle",children:ao.map(c=>{let d=R[c.id];return(0,b.jsxs)("div",{className:"group flex items-center justify-between gap-3 px-3 py-2 hover:bg-bg",children:[(0,b.jsxs)("div",{className:"flex min-w-0 items-center gap-2",children:[(0,b.jsx)(k.Icon,{name:"ok"===d?"check_circle":"fail"===d?"cancel":"smart_toy",size:15,className:`flex-none ${"ok"===d?"text-success":"fail"===d?"text-danger":"text-text-subtle"}`}),(0,b.jsxs)("span",{className:"tnum truncate text-[12.5px]",children:[(0,b.jsxs)("span",{className:"text-text-subtle",children:[r.id,"/"]}),(0,b.jsx)("span",{className:"text-text",children:c.id})]}),(0,b.jsx)(o.CapacityBadges,{model:c.id,provider:r.id}),(void 0!==c.price_in||void 0!==c.price_out)&&(0,b.jsxs)("span",{className:"tnum whitespace-nowrap text-[11px] text-text-subtle",children:[l.fmt.cost(c.price_in??0),"/",l.fmt.cost(c.price_out??0)," per 1M"]})]}),(0,b.jsxs)("div",{className:"flex flex-none items-center gap-0.5",children:[(0,b.jsx)("button",{onClick:()=>ai(c.id),disabled:"testing"===d,className:"rounded p-1 text-text-subtle transition-colors hover:bg-surface hover:text-accent disabled:opacity-60","aria-label":`Test ${c.id}`,title:"fail"===d?"Test failed — click to retry":"Test this model",children:(0,b.jsx)(k.Icon,{name:"testing"===d?"progress_activity":"science",size:15})}),(0,b.jsx)("button",{onClick:()=>ap(`rmmodel${c.id}`,()=>e.adminApi.removeModel(a,c.id)),disabled:z===`rmmodel${c.id}`,className:"rounded p-1 text-text-subtle transition-colors hover:bg-surface hover:text-danger disabled:opacity-40","aria-label":`Remove ${c.id}`,children:(0,b.jsx)(k.Icon,{name:"delete",size:16})})]})]},c.id)})})]}),(0,b.jsxs)("div",{className:"mt-3 flex gap-2",children:[(0,b.jsx)(j.Input,{value:L,onChange:a=>M(a.target.value),placeholder:"add a model id…"}),(0,b.jsx)(j.Button,{disabled:!L||"addmodel"===z,onClick:()=>ap("addmodel",async()=>{let b=await e.adminApi.addModel(a,L);return b.ok&&M(""),b}),children:"Add"})]})]})]}),P&&(0,b.jsx)(n,{models:P,busy:"addmodels"===z,onClose:()=>Q(null),onAdd:b=>ap("addmodels",async()=>{let c=await e.adminApi.addModels(a,b);return c.ok&&Q(null),c})}),(0,b.jsx)("div",{className:"mt-6",children:(0,b.jsxs)(j.Button,{variant:"danger",onClick:()=>ah(!0),children:[(0,b.jsx)(k.Icon,{name:"delete",size:16})," Remove provider"]})}),ag&&(0,b.jsx)(p.ConfirmModal,{title:"Remove provider",message:`Delete "${r.name??a}"? All keys and model associations will be lost.`,confirmLabel:"Remove",busy:"rmprov"===z,onCancel:()=>ah(!1),onConfirm:()=>ap("rmprov",async()=>{let b=await e.adminApi.removeProvider(a);return b.ok?m.push("/providers"):ah(!1),b})})]})}],33410)}];
2
2
 
3
3
  //# sourceMappingURL=src_components_ProviderDetail_tsx_06sxu0r._.js.map