ldrouter 1.10.0 → 1.10.1
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.
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,19 @@ All notable changes to this project are documented here. The format follows
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/) and the project adheres to
|
|
5
5
|
[Semantic Versioning](https://semver.org/).
|
|
6
6
|
|
|
7
|
+
## [1.10.1] - 2026-09-01
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **Restore now reloads the database hot — no gateway restart needed**: `POST /api/admin/backup/restore` closes the in-process SQLite connection, swaps the file, reopens it in the same process, validates schema, and re-seeds the admin session — the admin stays logged in and sees the restored data immediately. Previously the admin had to restart the gateway after every restore.
|
|
12
|
+
- **Restore no longer loses data on restart**: the restore previously renamed over `data.sqlite` while the app's stale `-wal`/`-shm` sidecars were left behind; on restart SQLite could replay the old WAL over the restored snapshot, making the gateway appear empty (setup screen). The restore now fully closes the old connection before swapping, so the stale sidecars never survive.
|
|
13
|
+
- **Automatic rollback**: if the reopened restored database fails validation (e.g. schema mismatch), the gateway automatically rolls back to the pre-restore snapshot instead of staying broken.
|
|
14
|
+
- **Restore snapshot leak closed**: the pre-restore snapshot connection is now always closed.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- Settings → Backup & restore now auto-reloads the admin UI after a successful restore (restore toast: "Restored. Reloading…").
|
|
19
|
+
|
|
7
20
|
## [1.10.0] - 2026-09-01
|
|
8
21
|
|
|
9
22
|
### Added
|
|
@@ -3,14 +3,54 @@ import fs from 'node:fs';
|
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import zlib from 'node:zlib';
|
|
5
5
|
import crypto from 'node:crypto';
|
|
6
|
-
import { getDb } from '../../db/index.js';
|
|
6
|
+
import { getDb, closeDb, openDb, schema } from '../../db/index.js';
|
|
7
7
|
import { requireAdminAuth } from '../../auth/middleware.js';
|
|
8
|
+
import { sha256Hex } from '../../auth/ids.js';
|
|
8
9
|
import { recordAudit } from '../../db/repositories/audit.js';
|
|
9
10
|
import { loadConfig } from '../../config/index.js';
|
|
10
11
|
import { getSettings } from '../../db/repositories/settings.js';
|
|
11
12
|
import { GatewayError } from '../../errors.js';
|
|
12
13
|
import { getAppVersion } from '../../version.js';
|
|
14
|
+
import { eq, sql } from 'drizzle-orm';
|
|
13
15
|
const BACKUP_VERSION = 1;
|
|
16
|
+
/** Reopen the in-process SQLite connection on the (possibly just-replaced)
|
|
17
|
+
* database file. The old connection must already be closed: a hot restore
|
|
18
|
+
* swaps the file on disk, then the gateway keeps serving from the new data
|
|
19
|
+
* without a restart. Schema migrations and the app_settings bootstrap run
|
|
20
|
+
* automatically on open. */
|
|
21
|
+
function reopenDatabase(dbFile) {
|
|
22
|
+
const dir = path.dirname(dbFile);
|
|
23
|
+
const base = path.basename(dbFile);
|
|
24
|
+
// When the WAL is in non-persistent mode, SQLite keeps `data.sqlite-wal`
|
|
25
|
+
// and `data.sqlite-shm` next to the DB. After we replace the DB file the
|
|
26
|
+
// OLD wal/shm describe the PREVIOUS database — replaying them would
|
|
27
|
+
// resurrect the old data over the restored snapshot (the gateway looked
|
|
28
|
+
// like "nothing was restored"). They are safe to delete: the old
|
|
29
|
+
// connection is closed (wal fully checkpointed) and the restored backup is
|
|
30
|
+
// a consistent standalone snapshot.
|
|
31
|
+
for (const suffix of ['-wal', '-shm']) {
|
|
32
|
+
const stale = path.join(dir, `${base}${suffix}`);
|
|
33
|
+
try {
|
|
34
|
+
if (fs.existsSync(stale))
|
|
35
|
+
fs.unlinkSync(stale);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
/* ignore: unlink failure is not fatal, next restart would retry */
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
openDb(dbFile);
|
|
42
|
+
}
|
|
43
|
+
/** Verify the current database (as restored) is consistent: matches the
|
|
44
|
+
* schema version we expect and has the bootstrap app_settings row. */
|
|
45
|
+
function assertDatabaseUsable(expectedSchemaVersion) {
|
|
46
|
+
const db = getDb();
|
|
47
|
+
const row = db.select().from(schema.appSettings).where(eq(schema.appSettings.id, 1)).get();
|
|
48
|
+
if (!row)
|
|
49
|
+
throw new Error('restored database is missing the app_settings bootstrap row');
|
|
50
|
+
if (row.schemaVersion !== expectedSchemaVersion) {
|
|
51
|
+
throw new Error(`restored database schema version mismatch: expected ${expectedSchemaVersion}, got ${row.schemaVersion}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
14
54
|
export async function registerBackupRoutes(app) {
|
|
15
55
|
app.addHook('preHandler', requireAdminAuth);
|
|
16
56
|
app.post('/api/admin/backup/create', async (req, reply) => {
|
|
@@ -82,21 +122,27 @@ export async function registerBackupRoutes(app) {
|
|
|
82
122
|
recordAudit({ action: 'db.restore', success: false, ip: req.ip, metadata: { reason: 'not_sqlite' } });
|
|
83
123
|
throw new GatewayError('invalid_request_error', 'Backup does not contain a valid SQLite database', { status: 400 });
|
|
84
124
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
void db;
|
|
125
|
+
const liveDb = cfg.dbFile;
|
|
126
|
+
// Snapshot current DB before restore (kept for manual rollback).
|
|
88
127
|
const snapshot = path.join(cfg.dataDir, `pre-restore-${Date.now()}.sqlite`);
|
|
89
128
|
const Database = (await import('better-sqlite3')).default;
|
|
90
|
-
const live = new Database(
|
|
129
|
+
const live = new Database(liveDb);
|
|
91
130
|
try {
|
|
92
131
|
await live.backup(snapshot);
|
|
93
132
|
}
|
|
94
133
|
catch (e) {
|
|
134
|
+
live.close();
|
|
95
135
|
recordAudit({ action: 'db.restore', success: false, ip: req.ip, metadata: { reason: 'snapshot_failed', err: String(e) } });
|
|
96
136
|
throw new GatewayError('gateway_error', 'Could not snapshot current database', { status: 500 });
|
|
97
137
|
}
|
|
98
|
-
|
|
99
|
-
|
|
138
|
+
live.close();
|
|
139
|
+
// Close the in-process connection before swapping the file. The gateway
|
|
140
|
+
// keeps serving (no restart) but the file must be free: on Windows a
|
|
141
|
+
// rename fails while a handle is open. Reopening runs migrations + the
|
|
142
|
+
// app_settings bootstrap automatically.
|
|
143
|
+
getDb();
|
|
144
|
+
closeDb();
|
|
145
|
+
// Atomic replace.
|
|
100
146
|
const tempDb = `${liveDb}.restore-${Date.now()}`;
|
|
101
147
|
fs.writeFileSync(tempDb, buf);
|
|
102
148
|
try {
|
|
@@ -107,7 +153,65 @@ export async function registerBackupRoutes(app) {
|
|
|
107
153
|
recordAudit({ action: 'db.restore', success: false, ip: req.ip, metadata: { reason: 'rename_failed', err: String(e) } });
|
|
108
154
|
throw new GatewayError('gateway_error', 'Restore atomic replace failed', { status: 500 });
|
|
109
155
|
}
|
|
156
|
+
// Hot-reload the database in-process: reopen the replaced file, validate
|
|
157
|
+
// it, and keep serving. No gateway restart needed.
|
|
158
|
+
try {
|
|
159
|
+
reopenDatabase(liveDb);
|
|
160
|
+
assertDatabaseUsable(envelope.schemaVersion);
|
|
161
|
+
}
|
|
162
|
+
catch (e) {
|
|
163
|
+
// Roll back to the snapshot taken before the restore so the gateway
|
|
164
|
+
// never stays on a broken database.
|
|
165
|
+
try {
|
|
166
|
+
closeDb();
|
|
167
|
+
}
|
|
168
|
+
catch { /* ignore */ }
|
|
169
|
+
try {
|
|
170
|
+
for (const suffix of ['-wal', '-shm']) {
|
|
171
|
+
const stale = path.join(path.dirname(liveDb), `${path.basename(liveDb)}${suffix}`);
|
|
172
|
+
if (fs.existsSync(stale))
|
|
173
|
+
fs.unlinkSync(stale);
|
|
174
|
+
}
|
|
175
|
+
fs.copyFileSync(snapshot, liveDb);
|
|
176
|
+
openDb(liveDb);
|
|
177
|
+
}
|
|
178
|
+
catch (rollbackErr) {
|
|
179
|
+
const err = e.message;
|
|
180
|
+
const rerr = rollbackErr.message;
|
|
181
|
+
recordAudit({ action: 'db.restore', success: false, ip: req.ip, metadata: { reason: 'rollback_failed', err, rollbackErr: rerr } });
|
|
182
|
+
throw new GatewayError('gateway_error', `Restore failed (${err}) and automatic rollback also failed (${rerr}). Please restart the gateway.`, { status: 500 });
|
|
183
|
+
}
|
|
184
|
+
recordAudit({ action: 'db.restore', success: false, ip: req.ip, metadata: { reason: 'validation_failed', err: e.message } });
|
|
185
|
+
throw new GatewayError('gateway_error', `Restore failed: ${e.message}`, { status: 500 });
|
|
186
|
+
}
|
|
187
|
+
// The swap invalidates the previous admin session (its row lived in the
|
|
188
|
+
// old database). Re-create the current session in the restored database so
|
|
189
|
+
// the admin stays logged in across the hot restore.
|
|
190
|
+
const sessionToken = req.cookies['ld_session'];
|
|
191
|
+
const sessionId = req.adminSessionId;
|
|
192
|
+
if (sessionId && sessionToken) {
|
|
193
|
+
const db = getDb();
|
|
194
|
+
const expiresAt = new Date(Date.now() + 12 * 3600 * 1000).toISOString();
|
|
195
|
+
db.delete(schema.adminSessions).where(sql `id = ${sessionId}`).run();
|
|
196
|
+
db.insert(schema.adminSessions).values({
|
|
197
|
+
id: sessionId,
|
|
198
|
+
tokenDigest: sha256Hex(sessionToken),
|
|
199
|
+
expiresAt,
|
|
200
|
+
lastSeenAt: new Date().toISOString(),
|
|
201
|
+
ip: req.ip,
|
|
202
|
+
}).run();
|
|
203
|
+
// Re-seed the CSRF token that was bound to the old session.
|
|
204
|
+
const csrfRow = db.select().from(schema.csrfTokens).where(eq(schema.csrfTokens.sessionId, sessionId)).get();
|
|
205
|
+
if (!csrfRow) {
|
|
206
|
+
db.insert(schema.csrfTokens).values({
|
|
207
|
+
id: crypto.randomUUID(),
|
|
208
|
+
sessionId,
|
|
209
|
+
token: crypto.randomBytes(32).toString('base64url'),
|
|
210
|
+
expiresAt,
|
|
211
|
+
}).run();
|
|
212
|
+
}
|
|
213
|
+
}
|
|
110
214
|
recordAudit({ action: 'db.restore', success: true, ip: req.ip, metadata: { schemaVersion: envelope.schemaVersion } });
|
|
111
|
-
return reply.code(200).send({ ok: true, message: '
|
|
215
|
+
return reply.code(200).send({ ok: true, message: 'Database restored. The gateway continues running with the restored data — no restart needed.' });
|
|
112
216
|
});
|
|
113
217
|
}
|
|
@@ -321,4 +321,4 @@ Please change the parent <Route path="${T}"> to <Route path="${T==="/"?"*":`${T}
|
|
|
321
321
|
`);function ic(a){return a.label!==void 0}var CM=3,EM="32px",RM="16px",uy=4e3,NM=356,TM=14,MM=20,AM=200;function na(...a){return a.filter(Boolean).join(" ")}function _M(a){let[l,o]=a.split("-"),i=[];return l&&i.push(l),o&&i.push(o),i}var DM=a=>{var l,o,i,c,d,h,m,g,v,b,S;let{invert:x,toast:w,unstyled:E,interacting:j,setHeights:C,visibleToasts:T,heights:N,index:M,toasts:A,expanded:_,removeToast:z,defaultRichColors:q,closeButton:k,style:W,cancelButtonStyle:re,actionButtonStyle:K,className:V="",descriptionClassName:le="",duration:se,position:ce,gap:U,loadingIcon:$,expandByDefault:ne,classNames:H,icons:F,closeButtonAriaLabel:D="Close toast",pauseWhenPageIsHidden:P}=a,[Q,ae]=ue.useState(null),[de,Z]=ue.useState(null),[oe,ie]=ue.useState(!1),[me,Re]=ue.useState(!1),[Ae,Me]=ue.useState(!1),[He,mt]=ue.useState(!1),[pt,bt]=ue.useState(!1),[St,Lt]=ue.useState(0),[fn,Qn]=ue.useState(0),hn=ue.useRef(w.duration||se||uy),ja=ue.useRef(null),Ca=ue.useRef(null),$t=M===0,Zc=M+1<=T,Kt=w.type,Ea=w.dismissible!==!1,br=w.className||"",Jc=w.descriptionClassName||"",ql=ue.useMemo(()=>N.findIndex(Ee=>Ee.toastId===w.id)||0,[N,w.id]),Wc=ue.useMemo(()=>{var Ee;return(Ee=w.closeButton)!=null?Ee:k},[w.closeButton,k]),Po=ue.useMemo(()=>w.duration||se||uy,[w.duration,se]),Ra=ue.useRef(0),wt=ue.useRef(0),Zn=ue.useRef(0),jt=ue.useRef(null),[eu,tu]=ce.split("-"),qo=ue.useMemo(()=>N.reduce((Ee,Ke,st)=>st>=ql?Ee:Ee+Ke.height,0),[N,ql]),Vl=gM(),Sr=w.invert||x,rl=Kt==="loading";wt.current=ue.useMemo(()=>ql*U+qo,[ql,qo]),ue.useEffect(()=>{hn.current=Po},[Po]),ue.useEffect(()=>{ie(!0)},[]),ue.useEffect(()=>{let Ee=Ca.current;if(Ee){let Ke=Ee.getBoundingClientRect().height;return Qn(Ke),C(st=>[{toastId:w.id,height:Ke,position:w.position},...st]),()=>C(st=>st.filter(Xt=>Xt.toastId!==w.id))}},[C,w.id]),ue.useLayoutEffect(()=>{if(!oe)return;let Ee=Ca.current,Ke=Ee.style.height;Ee.style.height="auto";let st=Ee.getBoundingClientRect().height;Ee.style.height=Ke,Qn(st),C(Xt=>Xt.find(Ut=>Ut.toastId===w.id)?Xt.map(Ut=>Ut.toastId===w.id?{...Ut,height:st}:Ut):[{toastId:w.id,height:st,position:w.position},...Xt])},[oe,w.title,w.description,C,w.id]);let It=ue.useCallback(()=>{Re(!0),Lt(wt.current),C(Ee=>Ee.filter(Ke=>Ke.toastId!==w.id)),setTimeout(()=>{z(w)},AM)},[w,z,C,wt]);ue.useEffect(()=>{if(w.promise&&Kt==="loading"||w.duration===1/0||w.type==="loading")return;let Ee;return _||j||P&&Vl?(()=>{if(Zn.current<Ra.current){let Ke=new Date().getTime()-Ra.current;hn.current=hn.current-Ke}Zn.current=new Date().getTime()})():hn.current!==1/0&&(Ra.current=new Date().getTime(),Ee=setTimeout(()=>{var Ke;(Ke=w.onAutoClose)==null||Ke.call(w,w),It()},hn.current)),()=>clearTimeout(Ee)},[_,j,w,Kt,P,Vl,It]),ue.useEffect(()=>{w.delete&&It()},[It,w.delete]);function wr(){var Ee,Ke,st;return F!=null&&F.loading?ue.createElement("div",{className:na(H==null?void 0:H.loader,(Ee=w==null?void 0:w.classNames)==null?void 0:Ee.loader,"sonner-loader"),"data-visible":Kt==="loading"},F.loading):$?ue.createElement("div",{className:na(H==null?void 0:H.loader,(Ke=w==null?void 0:w.classNames)==null?void 0:Ke.loader,"sonner-loader"),"data-visible":Kt==="loading"},$):ue.createElement(uM,{className:na(H==null?void 0:H.loader,(st=w==null?void 0:w.classNames)==null?void 0:st.loader),visible:Kt==="loading"})}return ue.createElement("li",{tabIndex:0,ref:Ca,className:na(V,br,H==null?void 0:H.toast,(l=w==null?void 0:w.classNames)==null?void 0:l.toast,H==null?void 0:H.default,H==null?void 0:H[Kt],(o=w==null?void 0:w.classNames)==null?void 0:o[Kt]),"data-sonner-toast":"","data-rich-colors":(i=w.richColors)!=null?i:q,"data-styled":!(w.jsx||w.unstyled||E),"data-mounted":oe,"data-promise":!!w.promise,"data-swiped":pt,"data-removed":me,"data-visible":Zc,"data-y-position":eu,"data-x-position":tu,"data-index":M,"data-front":$t,"data-swiping":Ae,"data-dismissible":Ea,"data-type":Kt,"data-invert":Sr,"data-swipe-out":He,"data-swipe-direction":de,"data-expanded":!!(_||ne&&oe),style:{"--index":M,"--toasts-before":M,"--z-index":A.length-M,"--offset":`${me?St:wt.current}px`,"--initial-height":ne?"auto":`${fn}px`,...W,...w.style},onDragEnd:()=>{Me(!1),ae(null),jt.current=null},onPointerDown:Ee=>{rl||!Ea||(ja.current=new Date,Lt(wt.current),Ee.target.setPointerCapture(Ee.pointerId),Ee.target.tagName!=="BUTTON"&&(Me(!0),jt.current={x:Ee.clientX,y:Ee.clientY}))},onPointerUp:()=>{var Ee,Ke,st,Xt;if(He||!Ea)return;jt.current=null;let Ut=Number(((Ee=Ca.current)==null?void 0:Ee.style.getPropertyValue("--swipe-amount-x").replace("px",""))||0),oa=Number(((Ke=Ca.current)==null?void 0:Ke.style.getPropertyValue("--swipe-amount-y").replace("px",""))||0),ia=new Date().getTime()-((st=ja.current)==null?void 0:st.getTime()),Zt=Q==="x"?Ut:oa,Jn=Math.abs(Zt)/ia;if(Math.abs(Zt)>=MM||Jn>.11){Lt(wt.current),(Xt=w.onDismiss)==null||Xt.call(w,w),Z(Q==="x"?Ut>0?"right":"left":oa>0?"down":"up"),It(),mt(!0),bt(!1);return}Me(!1),ae(null)},onPointerMove:Ee=>{var Ke,st,Xt,Ut;if(!jt.current||!Ea||((Ke=window.getSelection())==null?void 0:Ke.toString().length)>0)return;let oa=Ee.clientY-jt.current.y,ia=Ee.clientX-jt.current.x,Zt=(st=a.swipeDirections)!=null?st:_M(ce);!Q&&(Math.abs(ia)>1||Math.abs(oa)>1)&&ae(Math.abs(ia)>Math.abs(oa)?"x":"y");let Jn={x:0,y:0};Q==="y"?(Zt.includes("top")||Zt.includes("bottom"))&&(Zt.includes("top")&&oa<0||Zt.includes("bottom")&&oa>0)&&(Jn.y=oa):Q==="x"&&(Zt.includes("left")||Zt.includes("right"))&&(Zt.includes("left")&&ia<0||Zt.includes("right")&&ia>0)&&(Jn.x=ia),(Math.abs(Jn.x)>0||Math.abs(Jn.y)>0)&&bt(!0),(Xt=Ca.current)==null||Xt.style.setProperty("--swipe-amount-x",`${Jn.x}px`),(Ut=Ca.current)==null||Ut.style.setProperty("--swipe-amount-y",`${Jn.y}px`)}},Wc&&!w.jsx?ue.createElement("button",{"aria-label":D,"data-disabled":rl,"data-close-button":!0,onClick:rl||!Ea?()=>{}:()=>{var Ee;It(),(Ee=w.onDismiss)==null||Ee.call(w,w)},className:na(H==null?void 0:H.closeButton,(c=w==null?void 0:w.classNames)==null?void 0:c.closeButton)},(d=F==null?void 0:F.close)!=null?d:pM):null,w.jsx||p.isValidElement(w.title)?w.jsx?w.jsx:typeof w.title=="function"?w.title():w.title:ue.createElement(ue.Fragment,null,Kt||w.icon||w.promise?ue.createElement("div",{"data-icon":"",className:na(H==null?void 0:H.icon,(h=w==null?void 0:w.classNames)==null?void 0:h.icon)},w.promise||w.type==="loading"&&!w.icon?w.icon||wr():null,w.type!=="loading"?w.icon||(F==null?void 0:F[Kt])||iM(Kt):null):null,ue.createElement("div",{"data-content":"",className:na(H==null?void 0:H.content,(m=w==null?void 0:w.classNames)==null?void 0:m.content)},ue.createElement("div",{"data-title":"",className:na(H==null?void 0:H.title,(g=w==null?void 0:w.classNames)==null?void 0:g.title)},typeof w.title=="function"?w.title():w.title),w.description?ue.createElement("div",{"data-description":"",className:na(le,Jc,H==null?void 0:H.description,(v=w==null?void 0:w.classNames)==null?void 0:v.description)},typeof w.description=="function"?w.description():w.description):null),p.isValidElement(w.cancel)?w.cancel:w.cancel&&ic(w.cancel)?ue.createElement("button",{"data-button":!0,"data-cancel":!0,style:w.cancelButtonStyle||re,onClick:Ee=>{var Ke,st;ic(w.cancel)&&Ea&&((st=(Ke=w.cancel).onClick)==null||st.call(Ke,Ee),It())},className:na(H==null?void 0:H.cancelButton,(b=w==null?void 0:w.classNames)==null?void 0:b.cancelButton)},w.cancel.label):null,p.isValidElement(w.action)?w.action:w.action&&ic(w.action)?ue.createElement("button",{"data-button":!0,"data-action":!0,style:w.actionButtonStyle||K,onClick:Ee=>{var Ke,st;ic(w.action)&&((st=(Ke=w.action).onClick)==null||st.call(Ke,Ee),!Ee.defaultPrevented&&It())},className:na(H==null?void 0:H.actionButton,(S=w==null?void 0:w.classNames)==null?void 0:S.actionButton)},w.action.label):null))};function dy(){if(typeof window>"u"||typeof document>"u")return"ltr";let a=document.documentElement.getAttribute("dir");return a==="auto"||!a?window.getComputedStyle(document.documentElement).direction:a}function OM(a,l){let o={};return[a,l].forEach((i,c)=>{let d=c===1,h=d?"--mobile-offset":"--offset",m=d?RM:EM;function g(v){["top","right","bottom","left"].forEach(b=>{o[`${h}-${b}`]=typeof v=="number"?`${v}px`:v})}typeof i=="number"||typeof i=="string"?g(i):typeof i=="object"?["top","right","bottom","left"].forEach(v=>{i[v]===void 0?o[`${h}-${v}`]=m:o[`${h}-${v}`]=typeof i[v]=="number"?`${i[v]}px`:i[v]}):g(m)}),o}var kM=p.forwardRef(function(a,l){let{invert:o,position:i="bottom-right",hotkey:c=["altKey","KeyT"],expand:d,closeButton:h,className:m,offset:g,mobileOffset:v,theme:b="light",richColors:S,duration:x,style:w,visibleToasts:E=CM,toastOptions:j,dir:C=dy(),gap:T=TM,loadingIcon:N,icons:M,containerAriaLabel:A="Notifications",pauseWhenPageIsHidden:_}=a,[z,q]=ue.useState([]),k=ue.useMemo(()=>Array.from(new Set([i].concat(z.filter(P=>P.position).map(P=>P.position)))),[z,i]),[W,re]=ue.useState([]),[K,V]=ue.useState(!1),[le,se]=ue.useState(!1),[ce,U]=ue.useState(b!=="system"?b:typeof window<"u"&&window.matchMedia&&window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"),$=ue.useRef(null),ne=c.join("+").replace(/Key/g,"").replace(/Digit/g,""),H=ue.useRef(null),F=ue.useRef(!1),D=ue.useCallback(P=>{q(Q=>{var ae;return(ae=Q.find(de=>de.id===P.id))!=null&&ae.delete||sn.dismiss(P.id),Q.filter(({id:de})=>de!==P.id)})},[]);return ue.useEffect(()=>sn.subscribe(P=>{if(P.dismiss){q(Q=>Q.map(ae=>ae.id===P.id?{...ae,delete:!0}:ae));return}setTimeout(()=>{IC.flushSync(()=>{q(Q=>{let ae=Q.findIndex(de=>de.id===P.id);return ae!==-1?[...Q.slice(0,ae),{...Q[ae],...P},...Q.slice(ae+1)]:[P,...Q]})})})}),[]),ue.useEffect(()=>{if(b!=="system"){U(b);return}if(b==="system"&&(window.matchMedia&&window.matchMedia("(prefers-color-scheme: dark)").matches?U("dark"):U("light")),typeof window>"u")return;let P=window.matchMedia("(prefers-color-scheme: dark)");try{P.addEventListener("change",({matches:Q})=>{U(Q?"dark":"light")})}catch{P.addListener(({matches:ae})=>{try{U(ae?"dark":"light")}catch(de){console.error(de)}})}},[b]),ue.useEffect(()=>{z.length<=1&&V(!1)},[z]),ue.useEffect(()=>{let P=Q=>{var ae,de;c.every(Z=>Q[Z]||Q.code===Z)&&(V(!0),(ae=$.current)==null||ae.focus()),Q.code==="Escape"&&(document.activeElement===$.current||(de=$.current)!=null&&de.contains(document.activeElement))&&V(!1)};return document.addEventListener("keydown",P),()=>document.removeEventListener("keydown",P)},[c]),ue.useEffect(()=>{if($.current)return()=>{H.current&&(H.current.focus({preventScroll:!0}),H.current=null,F.current=!1)}},[$.current]),ue.createElement("section",{ref:l,"aria-label":`${A} ${ne}`,tabIndex:-1,"aria-live":"polite","aria-relevant":"additions text","aria-atomic":"false",suppressHydrationWarning:!0},k.map((P,Q)=>{var ae;let[de,Z]=P.split("-");return z.length?ue.createElement("ol",{key:P,dir:C==="auto"?dy():C,tabIndex:-1,ref:$,className:m,"data-sonner-toaster":!0,"data-theme":ce,"data-y-position":de,"data-lifted":K&&z.length>1&&!d,"data-x-position":Z,style:{"--front-toast-height":`${((ae=W[0])==null?void 0:ae.height)||0}px`,"--width":`${NM}px`,"--gap":`${T}px`,...w,...OM(g,v)},onBlur:oe=>{F.current&&!oe.currentTarget.contains(oe.relatedTarget)&&(F.current=!1,H.current&&(H.current.focus({preventScroll:!0}),H.current=null))},onFocus:oe=>{oe.target instanceof HTMLElement&&oe.target.dataset.dismissible==="false"||F.current||(F.current=!0,H.current=oe.relatedTarget)},onMouseEnter:()=>V(!0),onMouseMove:()=>V(!0),onMouseLeave:()=>{le||V(!1)},onDragEnd:()=>V(!1),onPointerDown:oe=>{oe.target instanceof HTMLElement&&oe.target.dataset.dismissible==="false"||se(!0)},onPointerUp:()=>se(!1)},z.filter(oe=>!oe.position&&Q===0||oe.position===P).map((oe,ie)=>{var me,Re;return ue.createElement(DM,{key:oe.id,icons:M,index:ie,toast:oe,defaultRichColors:S,duration:(me=j==null?void 0:j.duration)!=null?me:x,className:j==null?void 0:j.className,descriptionClassName:j==null?void 0:j.descriptionClassName,invert:o,visibleToasts:E,closeButton:(Re=j==null?void 0:j.closeButton)!=null?Re:h,interacting:le,position:P,style:j==null?void 0:j.style,unstyled:j==null?void 0:j.unstyled,classNames:j==null?void 0:j.classNames,cancelButtonStyle:j==null?void 0:j.cancelButtonStyle,actionButtonStyle:j==null?void 0:j.actionButtonStyle,removeToast:D,toasts:z.filter(Ae=>Ae.position==oe.position),heights:W.filter(Ae=>Ae.position==oe.position),setHeights:re,expandByDefault:d,gap:T,loadingIcon:N,expanded:K,pauseWhenPageIsHidden:_,swipeDirections:a.swipeDirections})})):null}))});function zM(){const{login:a}=Rh(),[l,o]=p.useState("admin"),[i,c]=p.useState(""),[d,h]=p.useState(""),[m,g]=p.useState(""),[v,b]=p.useState(!1),[S,x]=p.useState(!1),w=_o(),E=un();return s.jsx("div",{className:"flex min-h-screen items-center justify-center bg-background p-4",children:s.jsxs(Ze,{className:"w-full max-w-sm",children:[s.jsxs(Je,{children:[s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsx("img",{src:"/logo.png",alt:"LateDev Router",className:"h-8 w-8 object-contain"}),s.jsx(We,{children:"Sign in"})]}),s.jsx(wn,{children:"Enter your admin credentials."})]}),s.jsxs(et,{className:"space-y-3",children:[s.jsxs("div",{className:"space-y-1",children:[s.jsx(ye,{children:"Username"}),s.jsx(Ne,{value:l,onChange:j=>o(j.target.value),autoFocus:!0})]}),s.jsxs("div",{className:"space-y-1",children:[s.jsx(ye,{children:"Password"}),s.jsx(Ne,{type:"password",value:i,onChange:j=>c(j.target.value)})]}),v&&s.jsxs(s.Fragment,{children:[s.jsxs("div",{className:"space-y-1",children:[s.jsx(ye,{children:"2FA code (or recovery code)"}),s.jsx(Ne,{value:d,onChange:j=>h(j.target.value),placeholder:"123456",maxLength:6})]}),s.jsxs("div",{className:"space-y-1",children:[s.jsx(ye,{children:"Recovery code (alternative)"}),s.jsx(Ne,{value:m,onChange:j=>g(j.target.value),placeholder:"ABCD12-EF3456"})]})]})]}),s.jsx("div",{className:"px-6 pb-6",children:s.jsx(he,{className:"w-full",disabled:S,onClick:async()=>{var j,C;x(!0);try{if((await a(l,i,d||void 0,m||void 0)).totpRequired){b(!0);return}const N=((C=(j=E.state)==null?void 0:j.from)==null?void 0:C.pathname)??"/";w(N,{replace:!0})}catch(T){xe.error(T.message)}finally{x(!1)}},children:"Sign in"})})]})})}function LM(){const[a,l]=p.useState("admin"),[o,i]=p.useState(""),[c,d]=p.useState(""),[h,m]=p.useState(!1),[g,v]=p.useState(!0);p.useEffect(()=>{Se.get("/api/admin/setup/status").then(x=>v(!x.masterKeyConfigured)).catch(()=>v(!0))},[]);const b=!g||c.trim().length>=32,S=!h&&o.length>=12&&b;return s.jsx("div",{className:"flex min-h-screen items-center justify-center bg-background p-4",children:s.jsxs(Ze,{className:"w-full max-w-md",children:[s.jsxs(Je,{children:[s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsx("img",{src:"/logo.png",alt:"LateDev Router",className:"h-8 w-8 object-contain rounded"}),s.jsx(We,{children:"Welcome to LateDev Router"})]}),s.jsx(wn,{children:"Set up the administrator account to get started."})]}),s.jsxs(et,{className:"space-y-3",children:[s.jsxs("div",{className:"space-y-1",children:[s.jsx(ye,{children:"Username"}),s.jsx(Ne,{value:a,onChange:x=>l(x.target.value)})]}),s.jsxs("div",{className:"space-y-1",children:[s.jsx(ye,{children:"Password (12+ chars)"}),s.jsx(Ne,{type:"password",value:o,onChange:x=>i(x.target.value)})]}),g&&s.jsxs("div",{className:"space-y-1",children:[s.jsx(ye,{children:"Master encryption key (required, 32+ chars)"}),s.jsx(Ne,{type:"password",value:c,onChange:x=>d(x.target.value),placeholder:"Paste or generate a 32+ character key"}),s.jsxs("p",{className:"text-xs text-muted-foreground",children:["Provider API keys are encrypted with this key (AES-256-GCM). Store it somewhere safe — if it is lost, stored provider credentials cannot be recovered. Generate one with:"," ",s.jsx("code",{className:"break-all",children:`node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"`})]})]})]}),s.jsx(I0,{children:s.jsx(he,{disabled:!S,onClick:async()=>{m(!0);try{await Se.post("/api/admin/setup",{username:a,password:o,setupMasterKey:g?c.trim():void 0}),xe.success("Admin account created"),window.location.assign("/login")}catch(x){xe.error(x.message)}finally{m(!1)}},children:"Create admin"})})]})})}function wa({title:a,description:l,actions:o,className:i}){return s.jsxs("div",{className:je("mb-6 flex items-start justify-between gap-4",i),children:[s.jsxs("div",{children:[s.jsx("h1",{className:"text-2xl font-semibold tracking-tight",children:a}),l&&s.jsx("p",{className:"mt-1 text-sm text-muted-foreground",children:l})]}),o&&s.jsx("div",{className:"flex items-center gap-2",children:o})]})}const UM=hb("inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none",{variants:{variant:{default:"border-transparent bg-primary text-primary-foreground",secondary:"border-transparent bg-secondary text-secondary-foreground",destructive:"border-transparent bg-destructive text-destructive-foreground",success:"border-transparent bg-emerald-600 text-white",warning:"border-transparent bg-amber-500 text-white",outline:"text-foreground"}},defaultVariants:{variant:"default"}});function Qe({className:a,variant:l,...o}){return s.jsx("div",{className:je(UM({variant:l}),a),...o})}function HM(){const[a,l]=p.useState(null);return p.useEffect(()=>{Se.get("/api/admin/dashboard").then(l).catch(()=>l(null))},[]),a?s.jsxs("div",{children:[s.jsx(wa,{title:"Dashboard",description:"Operational summary for today",actions:s.jsxs("div",{className:"flex gap-2",children:[s.jsx(he,{asChild:!0,variant:"outline",size:"sm",children:s.jsxs(ur,{to:"/providers",children:[s.jsx(Oo,{className:"mr-1 h-4 w-4"})," Provider"]})}),s.jsx(he,{asChild:!0,variant:"outline",size:"sm",children:s.jsxs(ur,{to:"/combos",children:[s.jsx(Qy,{className:"mr-1 h-4 w-4"})," Combo"]})}),s.jsx(he,{asChild:!0,variant:"outline",size:"sm",children:s.jsxs(ur,{to:"/api-keys",children:[s.jsx(Fy,{className:"mr-1 h-4 w-4"})," API Key"]})})]})}),s.jsxs("div",{className:"grid gap-4 md:grid-cols-2 lg:grid-cols-4",children:[s.jsxs(Ze,{children:[s.jsx(Je,{className:"pb-1",children:s.jsx(We,{className:"text-sm text-muted-foreground",children:"Requests today"})}),s.jsx(et,{className:"text-2xl font-semibold",children:At(a.today.total)})]}),s.jsxs(Ze,{children:[s.jsx(Je,{className:"pb-1",children:s.jsx(We,{className:"text-sm text-muted-foreground",children:"Success rate"})}),s.jsx(et,{className:"text-2xl font-semibold",children:a.today.total?Oc(a.today.success/a.today.total):"—"})]}),s.jsxs(Ze,{children:[s.jsx(Je,{className:"pb-1",children:s.jsx(We,{className:"text-sm text-muted-foreground",children:"Failed"})}),s.jsx(et,{className:"text-2xl font-semibold",children:At(a.today.failed)})]}),s.jsxs(Ze,{children:[s.jsx(Je,{className:"pb-1",children:s.jsx(We,{className:"text-sm text-muted-foreground",children:"Tokens today"})}),s.jsx(et,{className:"text-2xl font-semibold",children:At(a.today.totalTokens)})]})]}),s.jsxs("div",{className:"mt-6 grid gap-4 lg:grid-cols-2",children:[s.jsxs(Ze,{children:[s.jsxs(Je,{children:[s.jsx(We,{className:"text-base",children:"Provider health"}),s.jsxs(wn,{children:[a.providers.length," configured"]})]}),s.jsxs(et,{className:"space-y-2",children:[a.providers.length===0&&s.jsxs("p",{className:"text-sm text-muted-foreground",children:["No providers yet. ",s.jsx(ur,{to:"/providers",className:"text-primary",children:"Add one"}),"."]}),a.providers.map(o=>s.jsxs("div",{className:"flex items-center justify-between rounded border p-2 text-sm",children:[s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsx(Zy,{className:"h-4 w-4 text-muted-foreground"}),s.jsx("span",{className:"font-medium",children:o.name}),s.jsx("span",{className:"text-xs text-muted-foreground",children:o.slug}),s.jsx(Qe,{variant:"outline",className:"ml-2",children:o.type})]}),s.jsx(Qe,{variant:o.health==="healthy"?"success":o.health==="down"?"destructive":"secondary",children:o.health})]},o.id))]})]}),s.jsxs(Ze,{children:[s.jsxs(Je,{children:[s.jsx(We,{className:"text-base",children:"Recent failures"}),s.jsx(wn,{children:"Today"})]}),s.jsxs(et,{className:"space-y-1 text-sm",children:[a.recentFailures.length===0&&s.jsx("p",{className:"text-muted-foreground",children:"No failures today."}),a.recentFailures.map(o=>{var i;return s.jsxs("div",{className:"flex items-center justify-between border-b py-1 last:border-0",children:[s.jsxs("div",{children:[s.jsx("span",{className:"font-mono text-xs",children:o.requestedModel}),s.jsxs("div",{className:"text-xs text-muted-foreground",children:[o.errorType??`HTTP ${o.httpStatus}`," — ",(i=o.errorMessage)==null?void 0:i.slice(0,60)]})]}),s.jsx("span",{className:"text-xs text-muted-foreground",children:Th(o.createdAt)})]},o.id)})]})]})]})]}):s.jsx("div",{className:"text-muted-foreground",children:"Loading…"})}const Kn=p.forwardRef(({className:a,...l},o)=>s.jsx("div",{className:"relative w-full overflow-auto",children:s.jsx("table",{ref:o,className:je("w-full caption-bottom text-sm",a),...l})}));Kn.displayName="Table";const Xn=p.forwardRef(({className:a,...l},o)=>s.jsx("thead",{ref:o,className:je("[&_tr]:border-b",a),...l}));Xn.displayName="TableHeader";const Fn=p.forwardRef(({className:a,...l},o)=>s.jsx("tbody",{ref:o,className:je("[&_tr:last-child]:border-0",a),...l}));Fn.displayName="TableBody";const Ye=p.forwardRef(({className:a,...l},o)=>s.jsx("tr",{ref:o,className:je("border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",a),...l}));Ye.displayName="TableRow";const pe=p.forwardRef(({className:a,...l},o)=>s.jsx("th",{ref:o,className:je("h-10 px-2 text-left align-middle font-medium text-muted-foreground",a),...l}));pe.displayName="TableHead";const fe=p.forwardRef(({className:a,...l},o)=>s.jsx("td",{ref:o,className:je("p-2 align-middle",a),...l}));fe.displayName="TableCell";var BM=Object.defineProperty,Mn=(a,l)=>BM(a,"name",{value:l,configurable:!0}),Qh="Dialog",[G0,Y0]=dn(Qh),[PM,sa]=G0(Qh),$0=Mn(a=>{const{__scopeDialog:l,children:o,open:i,defaultOpen:c,onOpenChange:d,modal:h=!0}=a,m=p.useRef(null),g=p.useRef(null),[v,b]=Za({prop:i,defaultProp:c??!1,onChange:d,caller:Qh}),[S,x]=p.useState(0),[w,E]=p.useState(0);return s.jsx(PM,{scope:l,triggerRef:m,contentRef:g,contentId:ga(),titleId:ga(),descriptionId:ga(),titlePresent:S>0,descriptionPresent:w>0,setTitleCount:x,setDescriptionCount:E,open:v,onOpenChange:b,onOpenToggle:p.useCallback(()=>b(j=>!j),[b]),modal:h,children:o})},"Dialog"),qM="DialogTrigger",K0=p.forwardRef(Mn(function(l,o){const{__scopeDialog:i,...c}=l,d=sa(qM,i),h=Ve(o,d.triggerRef);return s.jsx(Ue.button,{type:"button","aria-haspopup":"dialog","aria-expanded":d.open,"aria-controls":d.open?d.contentId:void 0,"data-state":Xc(d.open),...c,ref:h,onClick:we(l.onClick,d.onOpenToggle)})},"DialogTrigger")),X0="DialogPortal",[VM,F0]=G0(X0,{forceMount:void 0}),Q0=Mn(a=>{const{__scopeDialog:l,forceMount:o,children:i,container:c}=a,d=sa(X0,l);return s.jsx(VM,{scope:l,forceMount:o,children:p.Children.map(i,h=>s.jsx(nl,{present:o||d.open,children:s.jsx(Ih,{asChild:!0,container:c,children:h})}))})},"DialogPortal"),ih="DialogOverlay",Zh=p.forwardRef(Mn(function(l,o){const i=F0(ih,l.__scopeDialog),{forceMount:c=i.forceMount,...d}=l,h=sa(ih,l.__scopeDialog);return h.modal?s.jsx(nl,{present:c||h.open,children:s.jsx(GM,{...d,ref:o})}):null},"DialogOverlay")),IM=va("DialogOverlay.RemoveScroll"),GM=p.forwardRef(Mn(function(l,o){const{__scopeDialog:i,...c}=l,d=sa(ih,i),h=Nb(),m=Ve(o,h);return s.jsx($c,{as:IM,allowPinchZoom:!0,shards:[d.contentRef],children:s.jsx(Ue.div,{"data-state":Xc(d.open),...c,ref:m,style:{pointerEvents:"auto",...c.style}})})},"DialogOverlayImpl")),No="DialogContent",Jh=p.forwardRef(Mn(function(l,o){const i=F0(No,l.__scopeDialog),{forceMount:c=i.forceMount,...d}=l,h=sa(No,l.__scopeDialog);return s.jsx(nl,{present:c||h.open,children:h.modal?s.jsx(YM,{...d,ref:o}):s.jsx($M,{...d,ref:o})})},"DialogContent")),YM=p.forwardRef(Mn(function(l,o){const i=sa(No,l.__scopeDialog),c=p.useRef(null),d=Ve(o,i.contentRef,c);return p.useEffect(()=>{const h=c.current;if(h)return $h(h)},[]),s.jsx(Z0,{...l,ref:d,trapFocus:i.open,disableOutsidePointerEvents:i.open,onCloseAutoFocus:we(l.onCloseAutoFocus,h=>{var m;h.preventDefault(),(m=i.triggerRef.current)==null||m.focus()}),onPointerDownOutside:we(l.onPointerDownOutside,h=>{const m=h.detail.originalEvent,g=m.button===0&&m.ctrlKey===!0;(m.button===2||g)&&h.preventDefault()}),onFocusOutside:we(l.onFocusOutside,h=>h.preventDefault())})},"DialogContentModal")),$M=p.forwardRef(Mn(function(l,o){const i=sa(No,l.__scopeDialog),c=p.useRef(!1),d=p.useRef(!1);return s.jsx(Z0,{...l,ref:o,trapFocus:!1,disableOutsidePointerEvents:!1,onCloseAutoFocus:h=>{var m,g;(m=l.onCloseAutoFocus)==null||m.call(l,h),h.defaultPrevented||(c.current||(g=i.triggerRef.current)==null||g.focus(),h.preventDefault()),c.current=!1,d.current=!1},onInteractOutside:h=>{var v,b;(v=l.onInteractOutside)==null||v.call(l,h),h.defaultPrevented||(c.current=!0,h.detail.originalEvent.type==="pointerdown"&&(d.current=!0));const m=h.target;((b=i.triggerRef.current)==null?void 0:b.contains(m))&&h.preventDefault(),h.detail.originalEvent.type==="focusin"&&d.current&&h.preventDefault()}})},"DialogContentNonModal")),Z0=p.forwardRef(Mn(function(l,o){const{__scopeDialog:i,trapFocus:c,onOpenAutoFocus:d,onCloseAutoFocus:h,...m}=l,g=sa(No,i);return Lo(),s.jsx(s.Fragment,{children:s.jsx(kh,{asChild:!0,loop:!0,trapped:c,onMountAutoFocus:d,onUnmountAutoFocus:h,children:s.jsx(zc,{role:"dialog",id:g.contentId,"aria-describedby":g.descriptionPresent?g.descriptionId:void 0,"aria-labelledby":g.titlePresent?g.titleId:void 0,"data-state":Xc(g.open),...m,ref:o,deferPointerDownOutside:!0,onDismiss:()=>g.onOpenChange(!1)})})})},"DialogContentImpl")),KM="DialogTitle",Wh=p.forwardRef(Mn(function(l,o){const{__scopeDialog:i,...c}=l,d=sa(KM,i),{setTitleCount:h}=d;return _t(()=>(h(m=>m+1),()=>h(m=>m-1)),[h]),s.jsx(Ue.h2,{id:d.titleId,...c,ref:o})},"DialogTitle")),XM="DialogDescription",em=p.forwardRef(Mn(function(l,o){const{__scopeDialog:i,...c}=l,d=sa(XM,i),{setDescriptionCount:h}=d;return _t(()=>(h(m=>m+1),()=>h(m=>m-1)),[h]),s.jsx(Ue.p,{id:d.descriptionId,...c,ref:o})},"DialogDescription")),FM="DialogClose",tm=p.forwardRef(Mn(function(l,o){const{__scopeDialog:i,...c}=l,d=sa(FM,i);return s.jsx(Ue.button,{type:"button",...c,ref:o,onClick:we(l.onClick,()=>d.onOpenChange(!1))})},"DialogClose"));function Xc(a){return a?"open":"closed"}Mn(Xc,"getState");const qn=$0,Ho=K0,QM=Q0,J0=p.forwardRef(({className:a,...l},o)=>s.jsx(Zh,{ref:o,className:je("fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",a),...l}));J0.displayName=Zh.displayName;const jn=p.forwardRef(({className:a,children:l,...o},i)=>s.jsxs(QM,{children:[s.jsx(J0,{}),s.jsxs(Jh,{ref:i,className:je("fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 sm:rounded-lg",a),...o,children:[l,s.jsxs(tm,{className:"absolute right-4 top-4 rounded-sm opacity-70 hover:opacity-100",children:[s.jsx(Dc,{className:"h-4 w-4"}),s.jsx("span",{className:"sr-only",children:"Close"})]})]})]}));jn.displayName=Jh.displayName;const Cn=({className:a,...l})=>s.jsx("div",{className:je("flex flex-col space-y-1.5 text-center sm:text-left",a),...l});Cn.displayName="DialogHeader";const Vn=({className:a,...l})=>s.jsx("div",{className:je("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",a),...l});Vn.displayName="DialogFooter";const En=p.forwardRef(({className:a,...l},o)=>s.jsx(Wh,{ref:o,className:je("text-lg font-semibold leading-none tracking-tight",a),...l}));En.displayName=Wh.displayName;const ch=p.forwardRef(({className:a,...l},o)=>s.jsx(em,{ref:o,className:je("text-sm text-muted-foreground",a),...l}));ch.displayName=em.displayName;var ZM=Object.defineProperty,al=(a,l)=>ZM(a,"name",{value:l,configurable:!0}),JM="AlertDialog",[WM,qD]=dn(JM,[Y0]),ll=Y0(),eA=al(a=>{const{__scopeAlertDialog:l,...o}=a,i=ll(l);return s.jsx($0,{...i,...o,modal:!0})},"AlertDialog"),tA=p.forwardRef(al(function(l,o){const{__scopeAlertDialog:i,...c}=l,d=ll(i);return s.jsx(K0,{...d,...c,ref:o})},"AlertDialogTrigger")),nA=al(a=>{const{__scopeAlertDialog:l,...o}=a,i=ll(l);return s.jsx(Q0,{...i,...o})},"AlertDialogPortal"),aA=p.forwardRef(al(function(l,o){const{__scopeAlertDialog:i,...c}=l,d=ll(i);return s.jsx(Zh,{...d,...c,ref:o})},"AlertDialogOverlay")),lA="AlertDialogContent",[rA,sA]=WM(lA),oA=p.forwardRef(al(function(l,o){const{__scopeAlertDialog:i,children:c,...d}=l,h=ll(i),m=p.useRef(null),g=Ve(o,m),v=p.useRef(null);return s.jsx(rA,{scope:i,cancelRef:v,children:s.jsx(Jh,{role:"alertdialog",...h,...d,ref:g,onOpenAutoFocus:we(d.onOpenAutoFocus,b=>{var S;b.preventDefault(),(S=v.current)==null||S.focus({preventScroll:!0})}),onPointerDownOutside:b=>b.preventDefault(),onInteractOutside:b=>b.preventDefault(),children:c})})},"AlertDialogContent")),iA=p.forwardRef(al(function(l,o){const{__scopeAlertDialog:i,...c}=l,d=ll(i);return s.jsx(Wh,{...d,...c,ref:o})},"AlertDialogTitle")),cA=p.forwardRef(al(function(l,o){const{__scopeAlertDialog:i,...c}=l,d=ll(i);return s.jsx(em,{...d,...c,ref:o})},"AlertDialogDescription")),uA=p.forwardRef(al(function(l,o){const{__scopeAlertDialog:i,...c}=l,d=ll(i);return s.jsx(tm,{...d,...c,ref:o})},"AlertDialogAction")),dA="AlertDialogCancel",fA=p.forwardRef(al(function(l,o){const{__scopeAlertDialog:i,...c}=l,{cancelRef:d}=sA(dA,i),h=ll(i),m=Ve(o,d);return s.jsx(tm,{...h,...c,ref:m})},"AlertDialogCancel")),hA=eA,mA=tA,pA=nA,W0=aA,e1=oA,t1=uA,n1=fA,a1=iA,l1=cA;const r1=hA,gA=mA,vA=pA,s1=p.forwardRef(({className:a,...l},o)=>s.jsx(W0,{ref:o,className:je("fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",a),...l}));s1.displayName=W0.displayName;const nm=p.forwardRef(({className:a,...l},o)=>s.jsxs(vA,{children:[s.jsx(s1,{}),s.jsx(e1,{ref:o,className:je("fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg sm:max-w-[425px]",a),...l})]}));nm.displayName=e1.displayName;const o1=({className:a,...l})=>s.jsx("div",{className:je("flex flex-col space-y-2 text-center sm:text-left",a),...l}),i1=({className:a,...l})=>s.jsx("div",{className:je("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",a),...l}),am=p.forwardRef(({className:a,...l},o)=>s.jsx(a1,{ref:o,className:je("text-lg font-semibold",a),...l}));am.displayName=a1.displayName;const lm=p.forwardRef(({className:a,...l},o)=>s.jsx(l1,{ref:o,className:je("text-sm text-muted-foreground",a),...l}));lm.displayName=l1.displayName;const rm=p.forwardRef(({className:a,...l},o)=>s.jsx(t1,{ref:o,className:je("inline-flex h-9 items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90",a),...l}));rm.displayName=t1.displayName;const sm=p.forwardRef(({className:a,...l},o)=>s.jsx(n1,{ref:o,className:je("inline-flex h-9 items-center justify-center rounded-md border border-input bg-background px-4 py-2 text-sm font-medium hover:bg-accent",a),...l}));sm.displayName=n1.displayName;var xA=Object.defineProperty,yA=(a,l)=>xA(a,"name",{value:l,configurable:!0});function uh(a,[l,o]){return Math.min(o,Math.max(l,a))}yA(uh,"clamp");var bA=Object.defineProperty,SA=(a,l)=>bA(a,"name",{value:l,configurable:!0});function c1(a){const l=p.useRef({value:a,previous:a});return p.useMemo(()=>(l.current.value!==a&&(l.current.previous=l.current.value,l.current.value=a),l.current.previous),[a])}SA(c1,"usePrevious");var wA=Object.defineProperty,jA=(a,l)=>wA(a,"name",{value:l,configurable:!0}),u1=Object.freeze({position:"absolute",border:0,width:1,height:1,padding:0,margin:-1,overflow:"hidden",clip:"rect(0, 0, 0, 0)",whiteSpace:"nowrap",wordWrap:"normal"}),CA=p.forwardRef(jA(function(l,o){return s.jsx(Ue.span,{...l,ref:o,style:{...u1,...l.style}})},"VisuallyHidden")),EA=CA,RA=Object.defineProperty,rt=(a,l)=>RA(a,"name",{value:l,configurable:!0}),NA=[" ","Enter","ArrowUp","ArrowDown"],TA=[" ","Enter"],ms="Select",[Fc,om,MA]=kc(ms),[yr,VD]=dn(ms,[MA,Cs]),im=Cs(),[AA,Pl]=yr(ms),[_A,DA]=yr(ms);function d1(a){const{__scopeSelect:l,children:o,open:i,defaultOpen:c,onOpenChange:d,value:h,defaultValue:m,onValueChange:g,dir:v,name:b,autoComplete:S,disabled:x,required:w,form:E,internal_do_not_use_render:j}=a,C=im(l),[T,N]=p.useState(null),[M,A]=p.useState(null),[_,z]=p.useState(!1),q=zo(v),[k,W]=Za({prop:i,defaultProp:c??!1,onChange:d,caller:ms}),[re,K]=Za({prop:h,defaultProp:m,onChange:g,caller:ms}),V=p.useRef(null),le=p.useRef(re);p.useEffect(()=>{const P=E?T==null?void 0:T.ownerDocument.getElementById(E):T==null?void 0:T.form;if(P instanceof HTMLFormElement){const Q=rt(()=>K(le.current),"reset");return P.addEventListener("reset",Q),()=>P.removeEventListener("reset",Q)}},[E,T,K]);const se=T?!!E||!!T.closest("form"):!0,[ce,U]=p.useState(new Set),$=ga(),ne=Array.from(ce).map(P=>P.props.value).join(";"),H=p.useCallback(P=>{U(Q=>new Set(Q).add(P))},[]),F=p.useCallback(P=>{U(Q=>{const ae=new Set(Q);return ae.delete(P),ae})},[]),D={required:w,trigger:T,onTriggerChange:N,valueNode:M,onValueNodeChange:A,valueNodeHasChildren:_,onValueNodeHasChildrenChange:z,contentId:$,value:re,onValueChange:K,open:k,onOpenChange:W,dir:q,triggerPointerDownPosRef:V,disabled:x,name:b,autoComplete:S,form:E,nativeOptions:ce,nativeSelectKey:ne,isFormControl:se};return s.jsx(Jb,{...C,children:s.jsx(AA,{scope:l,...D,children:s.jsx(Fc.Provider,{scope:l,children:s.jsx(_A,{scope:l,onNativeOptionAdd:H,onNativeOptionRemove:F,children:v1(j)?j(D):o})})})})}rt(d1,"SelectProvider");var OA=rt(a=>{const{__scopeSelect:l,children:o,...i}=a;return s.jsx(d1,{__scopeSelect:l,...i,internal_do_not_use_render:({isFormControl:c})=>s.jsxs(s.Fragment,{children:[o,c?s.jsx(t_,{__scopeSelect:l}):null]})})},"Select"),kA="SelectTrigger",f1=p.forwardRef(rt(function(l,o){const{__scopeSelect:i,disabled:c=!1,...d}=l,h=im(i),m=Pl(kA,i),g=m.disabled||c,v=Ve(o,m.onTriggerChange),b=om(i),S=p.useRef("touch"),[x,w,E]=cm(C=>{const T=b().filter(A=>!A.disabled),N=T.find(A=>A.value===m.value),M=um(T,C,N);M!==void 0&&m.onValueChange(M.value)}),j=rt(C=>{g||(m.onOpenChange(!0),E()),C&&(m.triggerPointerDownPosRef.current={x:Math.round(C.pageX),y:Math.round(C.pageY)})},"handleOpen");return s.jsx(Wb,{asChild:!0,...h,children:s.jsx(Ue.button,{type:"button",role:"combobox","aria-controls":m.open?m.contentId:void 0,"aria-expanded":m.open,"aria-required":m.required,"aria-autocomplete":"none",dir:m.dir,"data-state":m.open?"open":"closed",disabled:g,"data-disabled":g?"":void 0,"data-placeholder":Bo(m.value)?"":void 0,...d,ref:v,onClick:we(d.onClick,C=>{C.currentTarget.focus(),S.current!=="mouse"&&j(C)}),onPointerDown:we(d.onPointerDown,C=>{S.current=C.pointerType;const T=C.target;T.hasPointerCapture(C.pointerId)&&T.releasePointerCapture(C.pointerId),C.button===0&&C.ctrlKey===!1&&C.pointerType==="mouse"&&(j(C),C.preventDefault())}),onKeyDown:we(d.onKeyDown,C=>{const T=x.current!=="";!(C.ctrlKey||C.altKey||C.metaKey)&&C.key.length===1&&w(C.key),!(T&&C.key===" ")&&NA.includes(C.key)&&(j(),C.preventDefault())})})})},"SelectTrigger")),zA="SelectValue",LA=p.forwardRef(rt(function(l,o){const{__scopeSelect:i,className:c,style:d,children:h,placeholder:m="",...g}=l,v=Pl(zA,i),{onValueNodeHasChildrenChange:b}=v,S=h!==void 0,x=Ve(o,v.onValueNodeChange);_t(()=>{b(S)},[b,S]);const w=Bo(v.value);return s.jsx(Ue.span,{...g,asChild:w?!1:g.asChild,ref:x,style:{pointerEvents:"none"},children:s.jsx(p.Fragment,{children:w?m:h},w?"placeholder":"value")})},"SelectValue")),UA=p.forwardRef(rt(function(l,o){const{__scopeSelect:i,children:c,...d}=l;return s.jsx(Ue.span,{"aria-hidden":!0,...d,ref:o,children:c||"▼"})},"SelectIcon")),HA="SelectPortal",[BA,PA]=yr(HA,{forceMount:void 0}),qA=rt(a=>{const{__scopeSelect:l,forceMount:o,...i}=a;return s.jsx(BA,{scope:a.__scopeSelect,forceMount:o,children:s.jsx(Ih,{asChild:!0,...i})})},"SelectPortal"),mr="SelectContent",h1=p.forwardRef(rt(function(l,o){const i=PA(mr,l.__scopeSelect),{forceMount:c=i.forceMount,...d}=l,h=Pl(mr,l.__scopeSelect),[m,g]=p.useState();return _t(()=>{g(new DocumentFragment)},[]),s.jsx(nl,{present:c||h.open,children:({present:v})=>v?s.jsx(GA,{...d,ref:o}):s.jsx(VA,{...d,fragment:m})})},"SelectContent")),VA=p.forwardRef(rt(function(l,o){const{__scopeSelect:i,children:c,fragment:d}=l;return d?ys.createPortal(s.jsx(m1,{scope:i,children:s.jsx(Fc.Slot,{scope:i,children:s.jsx("div",{ref:o,children:c})})}),d):null},"SelectContentFragment")),aa=10,[m1,Qc]=yr(mr),IA=va("SelectContent.RemoveScroll"),GA=p.forwardRef(rt(function(l,o){const{__scopeSelect:i}=l,{position:c="item-aligned",onCloseAutoFocus:d,onEscapeKeyDown:h,onPointerDownOutside:m,side:g,sideOffset:v,align:b,alignOffset:S,arrowPadding:x,collisionBoundary:w,collisionPadding:E,sticky:j,hideWhenDetached:C,avoidCollisions:T,...N}=l,M=Pl(mr,i),[A,_]=p.useState(null),[z,q]=p.useState(null),k=Ve(o,_),[W,re]=p.useState(null),[K,V]=p.useState(null),le=om(i),[se,ce]=p.useState(!1),U=p.useRef(!1);p.useEffect(()=>{if(A)return $h(A)},[A]),Lo();const $=p.useCallback(ie=>{const[me,...Re]=le().map(He=>He.ref.current),[Ae]=Re.slice(-1),Me=document.activeElement;for(const He of ie)if(He===Me||(He==null||He.scrollIntoView({block:"nearest"}),He===me&&z&&(z.scrollTop=0),He===Ae&&z&&(z.scrollTop=z.scrollHeight),He==null||He.focus(),document.activeElement!==Me))return},[le,z]),ne=p.useCallback(()=>$([W,A]),[$,W,A]);p.useEffect(()=>{se&&ne()},[se,ne]);const{onOpenChange:H,triggerPointerDownPosRef:F}=M;p.useEffect(()=>{if(A){let ie={x:0,y:0};const me=rt(Ae=>{var Me,He;ie={x:Math.abs(Math.round(Ae.pageX)-(((Me=F.current)==null?void 0:Me.x)??0)),y:Math.abs(Math.round(Ae.pageY)-(((He=F.current)==null?void 0:He.y)??0))}},"handlePointerMove"),Re=rt(Ae=>{ie.x<=10&&ie.y<=10?Ae.preventDefault():Ae.composedPath().includes(A)||H(!1),document.removeEventListener("pointermove",me),F.current=null},"handlePointerUp");return F.current!==null&&(document.addEventListener("pointermove",me),document.addEventListener("pointerup",Re,{capture:!0,once:!0})),()=>{document.removeEventListener("pointermove",me),document.removeEventListener("pointerup",Re,{capture:!0})}}},[A,H,F]),p.useEffect(()=>{const ie=rt(()=>H(!1),"close");return window.addEventListener("blur",ie),window.addEventListener("resize",ie),()=>{window.removeEventListener("blur",ie),window.removeEventListener("resize",ie)}},[H]);const[D,P]=cm(ie=>{const me=le().filter(Me=>!Me.disabled),Re=me.find(Me=>Me.ref.current===document.activeElement),Ae=um(me,ie,Re);Ae&&setTimeout(()=>{var Me;return(Me=Ae.ref.current)==null?void 0:Me.focus()})}),Q=p.useCallback((ie,me,Re)=>{const Ae=!U.current&&!Re;(M.value!==void 0&&M.value===me||Ae)&&(re(ie),Ae&&(U.current=!0))},[M.value]),ae=p.useCallback(()=>A==null?void 0:A.focus(),[A]),de=p.useCallback((ie,me,Re)=>{const Ae=!U.current&&!Re;(M.value!==void 0&&M.value===me||Ae)&&V(ie)},[M.value]),Z=c==="popper"?fy:YA,oe=Z===fy?{side:g,sideOffset:v,align:b,alignOffset:S,arrowPadding:x,collisionBoundary:w,collisionPadding:E,sticky:j,hideWhenDetached:C,avoidCollisions:T}:{};return s.jsx(m1,{scope:i,content:A,viewport:z,onViewportChange:q,itemRefCallback:Q,selectedItem:W,onItemLeave:ae,itemTextRefCallback:de,focusSelectedItem:ne,selectedItemText:K,position:c,isPositioned:se,searchRef:D,children:s.jsx($c,{as:IA,allowPinchZoom:!0,children:s.jsx(kh,{asChild:!0,trapped:M.open,onMountAutoFocus:ie=>{ie.preventDefault()},onUnmountAutoFocus:we(d,ie=>{var me;(me=M.trigger)==null||me.focus({preventScroll:!0}),ie.preventDefault()}),children:s.jsx(zc,{asChild:!0,disableOutsidePointerEvents:!0,onEscapeKeyDown:h,onPointerDownOutside:m,onFocusOutside:ie=>ie.preventDefault(),onDismiss:()=>M.onOpenChange(!1),children:s.jsx(Z,{role:"listbox",id:M.contentId,"data-state":M.open?"open":"closed",dir:M.dir,onContextMenu:ie=>ie.preventDefault(),...N,...oe,onPlaced:()=>ce(!0),ref:k,style:{display:"flex",flexDirection:"column",outline:"none",...N.style},onKeyDown:we(N.onKeyDown,ie=>{const me=ie.ctrlKey||ie.altKey||ie.metaKey;if(ie.key==="Tab"&&ie.preventDefault(),!me&&ie.key.length===1&&P(ie.key),["ArrowUp","ArrowDown","Home","End"].includes(ie.key)){let Ae=le().filter(Me=>!Me.disabled).map(Me=>Me.ref.current);if(["ArrowUp","End"].includes(ie.key)&&(Ae=Ae.slice().reverse()),["ArrowUp","ArrowDown"].includes(ie.key)){const Me=ie.target,He=Ae.indexOf(Me);Ae=Ae.slice(He+1)}setTimeout(()=>$(Ae)),ie.preventDefault()}})})})})})})},"SelectContentImpl")),YA=p.forwardRef(rt(function(l,o){const{__scopeSelect:i,onPlaced:c,...d}=l,h=Pl(mr,i),m=Qc(mr,i),[g,v]=p.useState(null),[b,S]=p.useState(null),x=Ve(o,S),w=om(i),E=p.useRef(!1),j=p.useRef(!0),{viewport:C,selectedItem:T,selectedItemText:N,focusSelectedItem:M}=m,A=p.useCallback(()=>{if(h.trigger&&h.valueNode&&g&&b&&C&&T&&N){const k=h.trigger.getBoundingClientRect(),W=b.getBoundingClientRect(),re=h.valueNode.getBoundingClientRect(),K=N.getBoundingClientRect();if(h.dir!=="rtl"){const Me=K.left-W.left,He=re.left-Me,mt=k.left-He,pt=k.width+mt,bt=Math.max(pt,W.width),St=window.innerWidth-aa,Lt=uh(He,[aa,Math.max(aa,St-bt)]);g.style.minWidth=pt+"px",g.style.left=Lt+"px"}else{const Me=W.right-K.right,He=window.innerWidth-re.right-Me,mt=window.innerWidth-k.right-He,pt=k.width+mt,bt=Math.max(pt,W.width),St=window.innerWidth-aa,Lt=uh(He,[aa,Math.max(aa,St-bt)]);g.style.minWidth=pt+"px",g.style.right=Lt+"px"}const V=w(),le=window.innerHeight-aa*2,se=C.scrollHeight,ce=window.getComputedStyle(b),U=parseInt(ce.borderTopWidth,10),$=parseInt(ce.paddingTop,10),ne=parseInt(ce.borderBottomWidth,10),H=parseInt(ce.paddingBottom,10),F=U+$+se+H+ne,D=Math.min(T.offsetHeight*5,F),P=window.getComputedStyle(C),Q=parseInt(P.paddingTop,10),ae=parseInt(P.paddingBottom,10),de=k.top+k.height/2-aa,Z=le-de,oe=T.offsetHeight/2,ie=T.offsetTop+oe,me=U+$+ie,Re=F-me;if(me<=de){const Me=V.length>0&&T===V[V.length-1].ref.current;g.style.bottom="0px";const He=b.clientHeight-C.offsetTop-C.offsetHeight,mt=Math.max(Z,oe+(Me?ae:0)+He+ne),pt=me+mt;g.style.height=pt+"px"}else{const Me=V.length>0&&T===V[0].ref.current;g.style.top="0px";const mt=Math.max(de,U+C.offsetTop+(Me?Q:0)+oe)+Re;g.style.height=mt+"px",C.scrollTop=me-de+C.offsetTop}g.style.margin=`${aa}px 0`,g.style.minHeight=D+"px",g.style.maxHeight=le+"px",c==null||c(),requestAnimationFrame(()=>E.current=!0)}},[w,h.trigger,h.valueNode,g,b,C,T,N,h.dir,c]);_t(()=>A(),[A]);const[_,z]=p.useState();_t(()=>{b&&z(window.getComputedStyle(b).zIndex)},[b]);const q=p.useCallback(k=>{k&&j.current===!0&&(A(),M==null||M(),j.current=!1)},[A,M]);return s.jsx($A,{scope:i,contentWrapper:g,shouldExpandOnScrollRef:E,onScrollButtonChange:q,children:s.jsx("div",{ref:v,style:{display:"flex",flexDirection:"column",position:"fixed",zIndex:_},children:s.jsx(Ue.div,{...d,ref:x,style:{boxSizing:"border-box",maxHeight:"100%",...d.style}})})})},"SelectItemAlignedPosition")),fy=p.forwardRef(rt(function(l,o){const{__scopeSelect:i,align:c="start",collisionPadding:d=aa,...h}=l,m=im(i);return s.jsx(Vh,{...m,...h,ref:o,align:c,collisionPadding:d,style:{boxSizing:"border-box",...h.style,"--radix-select-content-transform-origin":"var(--radix-popper-transform-origin)","--radix-select-content-available-width":"var(--radix-popper-available-width)","--radix-select-content-available-height":"var(--radix-popper-available-height)","--radix-select-trigger-width":"var(--radix-popper-anchor-width)","--radix-select-trigger-height":"var(--radix-popper-anchor-height)"}})},"SelectPopperPosition")),[$A,KA]=yr(mr,{}),hy="SelectViewport",XA=p.forwardRef(rt(function(l,o){const{__scopeSelect:i,nonce:c,...d}=l,h=Qc(hy,i),m=KA(hy,i),g=Ve(o,h.onViewportChange),v=p.useRef(0);return s.jsxs(s.Fragment,{children:[s.jsx("style",{dangerouslySetInnerHTML:{__html:"[data-radix-select-viewport]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}[data-radix-select-viewport]::-webkit-scrollbar{display:none}"},nonce:c}),s.jsx(Fc.Slot,{scope:i,children:s.jsx(Ue.div,{"data-radix-select-viewport":"",role:"presentation",...d,ref:g,style:{position:"relative",flex:1,overflow:"hidden auto",...d.style},onScroll:we(d.onScroll,b=>{const S=b.currentTarget,{contentWrapper:x,shouldExpandOnScrollRef:w}=m;if(w!=null&&w.current&&x){const E=Math.abs(v.current-S.scrollTop);if(E>0){const j=window.innerHeight-aa*2,C=parseFloat(x.style.minHeight),T=parseFloat(x.style.height),N=Math.max(C,T);if(N<j){const M=N+E,A=Math.min(j,M),_=M-A;x.style.height=A+"px",x.style.bottom==="0px"&&(S.scrollTop=_>0?_:0,x.style.justifyContent="flex-end")}}}v.current=S.scrollTop})})})]})},"SelectViewport")),FA="SelectGroup",[ID,GD]=yr(FA),dh="SelectItem",[QA,p1]=yr(dh),g1=p.forwardRef(rt(function(l,o){const{__scopeSelect:i,value:c,disabled:d=!1,textValue:h,...m}=l,g=Pl(dh,i),v=Qc(dh,i),b=g.value===c,[S,x]=p.useState(h??""),[w,E]=p.useState(!1),j=$n(A=>{var _;return(_=v.itemRefCallback)==null?void 0:_.call(v,A,c,d)}),C=Ve(o,j),T=ga(),N=p.useRef("touch"),M=rt(()=>{d||(g.onValueChange(c),g.onOpenChange(!1))},"handleSelect");return s.jsx(QA,{scope:i,value:c,disabled:d,textId:T,isSelected:b,onItemTextChange:p.useCallback(A=>{x(_=>_||((A==null?void 0:A.textContent)??"").trim())},[]),children:s.jsx(Fc.ItemSlot,{scope:i,value:c,disabled:d,textValue:S,children:s.jsx(Ue.div,{role:"option","aria-labelledby":T,"data-highlighted":w?"":void 0,"aria-selected":b&&w,"data-state":b?"checked":"unchecked","aria-disabled":d||void 0,"data-disabled":d?"":void 0,tabIndex:d?void 0:-1,...m,ref:C,onFocus:we(m.onFocus,()=>E(!0)),onBlur:we(m.onBlur,()=>E(!1)),onClick:we(m.onClick,()=>{N.current!=="mouse"&&M()}),onPointerUp:we(m.onPointerUp,()=>{N.current==="mouse"&&M()}),onPointerDown:we(m.onPointerDown,A=>{N.current=A.pointerType}),onPointerMove:we(m.onPointerMove,A=>{var _;N.current=A.pointerType,d?(_=v.onItemLeave)==null||_.call(v):N.current==="mouse"&&A.currentTarget.focus({preventScroll:!0})}),onPointerLeave:we(m.onPointerLeave,A=>{var _;A.currentTarget===document.activeElement&&((_=v.onItemLeave)==null||_.call(v))}),onKeyDown:we(m.onKeyDown,A=>{var z;d||A.target!==A.currentTarget||((z=v.searchRef)==null?void 0:z.current)!==""&&A.key===" "||(TA.includes(A.key)&&M(),A.key===" "&&A.preventDefault())})})})})},"SelectItem")),cc="SelectItemText",ZA=p.forwardRef(rt(function(l,o){const{__scopeSelect:i,className:c,style:d,...h}=l,m=Pl(cc,i),g=Qc(cc,i),v=p1(cc,i),b=DA(cc,i),[S,x]=p.useState(null),w=$n(M=>{var A;return(A=g.itemTextRefCallback)==null?void 0:A.call(g,M,v.value,v.disabled)}),E=Ve(o,x,v.onItemTextChange,w),j=S==null?void 0:S.textContent,C=p.useMemo(()=>s.jsx("option",{value:v.value,disabled:v.disabled,children:j},v.value),[v.disabled,v.value,j]),{onNativeOptionAdd:T,onNativeOptionRemove:N}=b;return _t(()=>(T(C),()=>N(C)),[T,N,C]),s.jsxs(s.Fragment,{children:[s.jsx(Ue.span,{id:v.textId,...h,ref:E}),v.isSelected&&m.valueNode&&!m.valueNodeHasChildren&&!Bo(m.value)?ys.createPortal(h.children,m.valueNode):null]})},"SelectItemText")),JA="SelectItemIndicator",WA=p.forwardRef(rt(function(l,o){const{__scopeSelect:i,...c}=l;return p1(JA,i).isSelected?s.jsx(Ue.span,{"aria-hidden":!0,...c,ref:o}):null},"SelectItemIndicator")),e_="SelectBubbleInput",t_=p.forwardRef(rt(function({__scopeSelect:l,...o},i){const c=Pl(e_,l),{value:d,onValueChange:h,required:m,disabled:g,name:v,autoComplete:b,form:S}=c,{nativeOptions:x,nativeSelectKey:w}=c,E=p.useRef(null),j=Ve(i,E),C=d??"",T=c1(C),N=Array.from(x).some(M=>(M.props.value??"")==="");return p.useEffect(()=>{const M=E.current;if(!M)return;const A=window.HTMLSelectElement.prototype,z=Object.getOwnPropertyDescriptor(A,"value").set;if(T!==C&&z){const q=new Event("change",{bubbles:!0});z.call(M,C),M.dispatchEvent(q)}},[T,C]),s.jsxs(Ue.select,{"aria-hidden":!0,required:m,tabIndex:-1,name:v,autoComplete:b,disabled:g,form:S,onChange:M=>h(M.target.value),...o,style:{...u1,...o.style},ref:j,defaultValue:C,children:[Bo(d)&&!N?s.jsx("option",{value:""}):null,Array.from(x)]},w)},"SelectBubbleInput"));function v1(a){return typeof a=="function"}rt(v1,"isFunction");function Bo(a){return a===""||a===void 0}rt(Bo,"shouldShowPlaceholder");function cm(a){const l=$n(a),o=p.useRef(""),i=p.useRef(0),c=p.useCallback(h=>{const m=o.current+h;l(m),rt((function g(v){o.current=v,window.clearTimeout(i.current),v!==""&&(i.current=window.setTimeout(()=>g(""),1e3))}),"updateSearch")(m)},[l]),d=p.useCallback(()=>{o.current="",window.clearTimeout(i.current)},[]);return p.useEffect(()=>()=>window.clearTimeout(i.current),[]),[o,c,d]}rt(cm,"useTypeaheadSearch");function um(a,l,o){const c=l.length>1&&Array.from(l).every(v=>v===l[0])?l[0]:l,d=o?a.indexOf(o):-1;let h=x1(a,Math.max(d,0));c.length===1&&(h=h.filter(v=>v!==o));const g=h.find(v=>v.textValue.toLowerCase().startsWith(c.toLowerCase()));return g!==o?g:void 0}rt(um,"findNextItem");function x1(a,l){return a.map((o,i)=>a[(l+i)%a.length])}rt(x1,"wrapArray");const In=OA,Gn=LA,Rn=p.forwardRef(({className:a,children:l,...o},i)=>s.jsxs(f1,{ref:i,className:je("flex h-9 w-full items-center justify-between rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50",a),...o,children:[l,s.jsx(UA,{asChild:!0,children:s.jsx(WC,{className:"h-4 w-4 opacity-50"})})]}));Rn.displayName=f1.displayName;const Nn=p.forwardRef(({className:a,children:l,position:o="popper",...i},c)=>s.jsx(qA,{children:s.jsx(h1,{ref:c,className:je("relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md",a),position:o,...i,children:s.jsx(XA,{className:je("p-1",o==="popper"&&"w-full min-w-[var(--radix-select-trigger-width)]"),children:l})})}));Nn.displayName=h1.displayName;const lt=p.forwardRef(({className:a,children:l,...o},i)=>s.jsxs(g1,{ref:i,className:je("relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",a),...o,children:[s.jsx("span",{className:"absolute left-2 flex h-3.5 w-3.5 items-center justify-center",children:s.jsx(WA,{children:s.jsx($y,{className:"h-4 w-4"})})}),s.jsx(ZA,{children:l})]}));lt.displayName=g1.displayName;var n_=Object.defineProperty,Hl=(a,l)=>n_(a,"name",{value:l,configurable:!0}),dm="Switch",[a_,YD]=dn(dm),[l_,fm]=a_(dm);function y1(a){const{__scopeSwitch:l,checked:o,children:i,defaultChecked:c,disabled:d,form:h,name:m,onCheckedChange:g,required:v,value:b="on",internal_do_not_use_render:S}=a,[x,w]=Za({prop:o,defaultProp:c??!1,onChange:g,caller:dm}),[E,j]=p.useState(null),[C,T]=p.useState(null),N=p.useRef(!1),[M,A]=p.useReducer(q=>q+1,0),_=E?!!h||!!E.closest("form"):!0,z={checked:x,setChecked:w,disabled:d,control:E,setControl:j,name:m,form:h,value:b,hasConsumerStoppedPropagationRef:N,userInteractionCount:M,onUserInteraction:A,required:v,defaultChecked:c,isFormControl:_,bubbleInput:C,setBubbleInput:T};return s.jsx(l_,{scope:l,...z,children:S1(S)?S(z):i})}Hl(y1,"SwitchProvider");var r_="SwitchTrigger",s_=p.forwardRef(Hl(function({__scopeSwitch:l,onClick:o,...i},c){const{control:d,form:h,value:m,disabled:g,checked:v,required:b,setControl:S,setChecked:x,hasConsumerStoppedPropagationRef:w,onUserInteraction:E,isFormControl:j,bubbleInput:C}=fm(r_,l),T=Ve(c,S),N=p.useRef(v);return p.useEffect(()=>{const M=h?d==null?void 0:d.ownerDocument.getElementById(h):d==null?void 0:d.form;if(M instanceof HTMLFormElement){const A=Hl(()=>x(N.current),"reset");return M.addEventListener("reset",A),()=>M.removeEventListener("reset",A)}},[d,h,x]),s.jsx(Ue.button,{type:"button",role:"switch","aria-checked":v,"aria-required":b,"data-state":hm(v),"data-disabled":g?"":void 0,disabled:g,value:m,...i,ref:T,onClick:we(o,M=>{E(),x(A=>!A),C&&j&&(w.current=M.isPropagationStopped(),w.current||M.stopPropagation())})})},"SwitchTrigger")),b1=p.forwardRef(Hl(function(l,o){const{__scopeSwitch:i,name:c,checked:d,defaultChecked:h,required:m,disabled:g,value:v,onCheckedChange:b,form:S,...x}=l;return s.jsx(y1,{__scopeSwitch:i,checked:d,defaultChecked:h,disabled:g,required:m,onCheckedChange:b,name:c,form:S,value:v,internal_do_not_use_render:({isFormControl:w})=>s.jsxs(s.Fragment,{children:[s.jsx(s_,{...x,ref:o,__scopeSwitch:i}),w&&s.jsx(u_,{__scopeSwitch:i})]})})},"Switch")),o_="SwitchThumb",i_=p.forwardRef(Hl(function(l,o){const{__scopeSwitch:i,...c}=l,d=fm(o_,i);return s.jsx(Ue.span,{"data-state":hm(d.checked),"data-disabled":d.disabled?"":void 0,...c,ref:o})},"SwitchThumb")),c_="SwitchBubbleInput",u_=p.forwardRef(Hl(function({__scopeSwitch:l,onClick:o,...i},c){const{control:d,hasConsumerStoppedPropagationRef:h,userInteractionCount:m,checked:g,defaultChecked:v,required:b,disabled:S,name:x,value:w,form:E,bubbleInput:j,setBubbleInput:C}=fm(c_,l),T=Ve(c,C),N=qc(d),M=p.useRef(!1),A=p.useRef(g),_=p.useRef(m);p.useEffect(()=>{const q=j;if(!q)return;const k=window.HTMLInputElement.prototype,re=Object.getOwnPropertyDescriptor(k,"checked").set,K=m!==_.current;_.current=m;const V=A.current!==g;A.current=g;const le=!(K&&h.current);if(V&&re){M.current=!K;const se=new Event("click",{bubbles:le});re.call(q,g),q.dispatchEvent(se),M.current=!1}},[j,g,h,m]);const z=p.useRef(g);return s.jsx(Ue.input,{type:"checkbox","aria-hidden":!0,defaultChecked:v??z.current,required:b,disabled:S,name:x,value:w,form:E,...i,tabIndex:-1,ref:T,onClick:we(o,q=>{M.current&&q.stopPropagation()}),style:{...i.style,...N,position:"absolute",pointerEvents:"none",opacity:0,margin:0,transform:"translateX(-100%)"}})},"SwitchBubbleInput"));function S1(a){return typeof a=="function"}Hl(S1,"isFunction");function hm(a){return a?"checked":"unchecked"}Hl(hm,"getState");const ba=p.forwardRef(({className:a,...l},o)=>s.jsx(b1,{className:je("peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",a),...l,ref:o,children:s.jsx(i_,{className:je("pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0")})}));ba.displayName=b1.displayName;const or={name:"",slug:"",type:"openai",baseUrl:"https://api.openai.com",apiKey:"",customHeaders:"",enabled:!0};function d_(){const[a,l]=p.useState([]),[o,i]=p.useState(!1),[c,d]=p.useState(or),[h,m]=p.useState(!1),[g,v]=p.useState(null),[b,S]=p.useState(null),[x,w]=p.useState(or),[E,j]=p.useState(null),[C,T]=p.useState(!1),N=()=>Se.get("/api/admin/providers").then(k=>l(k.providers));p.useEffect(()=>{N()},[]);const M=async()=>{m(!0);try{let k;if(c.customHeaders.trim())try{k=JSON.parse(c.customHeaders)}catch{throw new Error("Custom headers must be valid JSON object")}await Se.post("/api/admin/providers",{name:c.name,slug:c.slug||void 0,type:c.type,baseUrl:c.baseUrl,apiKey:c.apiKey,customHeaders:k,enabled:c.enabled}),xe.success("Provider created"),i(!1),d(or),N()}catch(k){xe.error(k.message)}finally{m(!1)}},A=async k=>{v(k);try{const W=await Se.post(`/api/admin/providers/${k}/test`);xe.success(W.ok?`Connection OK: ${W.detail}`:`Failed: ${W.detail}`),N()}catch(W){xe.error(W.message)}finally{v(null)}},_=k=>{S(k.id),w({...or,name:k.name,slug:k.slug||"",type:k.type,baseUrl:k.baseUrl,apiKey:"",customHeaders:"",enabled:k.enabled})},z=async()=>{if(b){m(!0);try{let k;if(x.customHeaders.trim())try{k=JSON.parse(x.customHeaders)}catch{throw new Error("Custom headers must be valid JSON object")}await Se.patch("/api/admin/providers",{id:b,name:x.name,slug:x.slug||void 0,type:x.type,baseUrl:x.baseUrl,apiKey:x.apiKey||void 0,customHeaders:k,enabled:x.enabled}),xe.success("Provider updated"),S(null),w(or),N()}catch(k){xe.error(k.message)}finally{m(!1)}}},q=async k=>{T(!0);try{await Se.del(`/api/admin/providers/${k}`),xe.success("Provider removed"),N()}catch(W){xe.error(W.message)}finally{T(!1),j(null)}};return s.jsxs("div",{children:[s.jsx(wa,{title:"Providers",description:"Upstream LLM providers and their credentials",actions:s.jsxs(qn,{open:o,onOpenChange:i,children:[s.jsx(Ho,{asChild:!0,children:s.jsxs(he,{children:[s.jsx(Oo,{className:"mr-1 h-4 w-4"})," Add provider"]})}),s.jsxs(jn,{children:[s.jsx(Cn,{children:s.jsx(En,{children:"New provider"})}),s.jsxs("div",{className:"space-y-3",children:[s.jsxs("div",{children:[s.jsx(ye,{children:"Name"}),s.jsx(Ne,{value:c.name,onChange:k=>d({...c,name:k.target.value})})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"Slug (optional)"}),s.jsx(Ne,{value:c.slug,onChange:k=>d({...c,slug:k.target.value})})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"Type"}),s.jsxs(In,{value:c.type,onValueChange:k=>d({...c,type:k}),children:[s.jsx(Rn,{children:s.jsx(Gn,{})}),s.jsxs(Nn,{children:[s.jsx(lt,{value:"openai",children:"OpenAI-compatible"}),s.jsx(lt,{value:"anthropic",children:"Anthropic-compatible"})]})]})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"Base URL"}),s.jsx(Ne,{value:c.baseUrl,onChange:k=>d({...c,baseUrl:k.target.value})})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"API key"}),s.jsx(Ne,{type:"password",value:c.apiKey,onChange:k=>d({...c,apiKey:k.target.value})})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"Custom headers (JSON)"}),s.jsx(Ne,{value:c.customHeaders,onChange:k=>d({...c,customHeaders:k.target.value}),placeholder:'{"X-Org":"acme"}'})]}),s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsx(ba,{checked:c.enabled,onCheckedChange:k=>d({...c,enabled:k})}),s.jsx(ye,{children:"Enabled"})]})]}),s.jsxs(Vn,{children:[s.jsx(he,{variant:"outline",onClick:()=>i(!1),children:"Cancel"}),s.jsx(he,{disabled:h||!c.name||!c.apiKey,onClick:M,children:"Create"})]})]})]})}),s.jsxs(Ze,{children:[s.jsxs(Je,{children:[s.jsx(We,{className:"text-base",children:"All providers"}),s.jsxs(wn,{children:[a.length," total"]})]}),s.jsx(et,{children:s.jsxs(Kn,{children:[s.jsx(Xn,{children:s.jsxs(Ye,{children:[s.jsx(pe,{children:"Name"}),s.jsx(pe,{children:"Type"}),s.jsx(pe,{children:"Base URL"}),s.jsx(pe,{children:"Models"}),s.jsx(pe,{children:"Health"}),s.jsx(pe,{children:"Enabled"}),s.jsx(pe,{className:"text-right",children:"Actions"})]})}),s.jsxs(Fn,{children:[a.length===0&&s.jsx(Ye,{children:s.jsx(fe,{colSpan:7,className:"text-center text-muted-foreground",children:"No providers yet."})}),a.map(k=>s.jsxs(Ye,{children:[s.jsxs(fe,{className:"font-medium",children:[k.name," ",s.jsx("span",{className:"text-xs text-muted-foreground",children:k.slug})]}),s.jsx(fe,{children:s.jsx(Qe,{variant:"outline",children:k.type})}),s.jsx(fe,{className:"text-xs text-muted-foreground",children:k.baseUrl}),s.jsx(fe,{children:k.modelCount}),s.jsx(fe,{children:s.jsx(Qe,{variant:k.health==="healthy"?"success":k.health==="down"?"destructive":"secondary",children:k.health})}),s.jsx(fe,{children:k.enabled?"Yes":"No"}),s.jsx(fe,{className:"text-right",children:s.jsxs("div",{className:"flex justify-end gap-1",children:[s.jsx(he,{size:"sm",variant:"outline",disabled:g===k.id,onClick:()=>A(k.id),children:s.jsx(h2,{className:"h-3 w-3"})}),s.jsx(he,{size:"sm",variant:"outline",onClick:()=>_(k),children:"✎"}),s.jsx(he,{size:"sm",variant:"outline",onClick:()=>j(k.id),children:s.jsx(_c,{className:"h-3 w-3"})})]})})]},k.id))]})]})})]}),s.jsx(qn,{open:!!b,onOpenChange:k=>{k||(S(null),w(or))},children:s.jsxs(jn,{children:[s.jsx(Cn,{children:s.jsx(En,{children:"Edit provider"})}),s.jsxs("div",{className:"space-y-3",children:[s.jsxs("div",{children:[s.jsx(ye,{children:"Name"}),s.jsx(Ne,{value:x.name,onChange:k=>w({...x,name:k.target.value})})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"Slug (optional)"}),s.jsx(Ne,{value:x.slug,onChange:k=>w({...x,slug:k.target.value})})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"Type"}),s.jsxs(In,{value:x.type,onValueChange:k=>w({...x,type:k}),children:[s.jsx(Rn,{children:s.jsx(Gn,{})}),s.jsxs(Nn,{children:[s.jsx(lt,{value:"openai",children:"OpenAI-compatible"}),s.jsx(lt,{value:"anthropic",children:"Anthropic-compatible"})]})]})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"Base URL"}),s.jsx(Ne,{value:x.baseUrl,onChange:k=>w({...x,baseUrl:k.target.value})})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"API key (leave empty to keep current)"}),s.jsx(Ne,{type:"password",value:x.apiKey,onChange:k=>w({...x,apiKey:k.target.value})})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"Custom headers (JSON)"}),s.jsx(Ne,{value:x.customHeaders,onChange:k=>w({...x,customHeaders:k.target.value}),placeholder:'{"X-Org":"acme"}'})]}),s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsx(ba,{checked:x.enabled,onCheckedChange:k=>w({...x,enabled:k})}),s.jsx(ye,{children:"Enabled"})]})]}),s.jsxs(Vn,{children:[s.jsx(he,{variant:"outline",onClick:()=>{S(null),w(or)},children:"Cancel"}),s.jsx(he,{disabled:h||!x.name,onClick:z,children:"Save changes"})]})]})}),s.jsx(r1,{open:!!E,onOpenChange:k=>{k||j(null)},children:s.jsxs(nm,{children:[s.jsxs(o1,{children:[s.jsx(am,{children:"Delete provider?"}),s.jsx(lm,{children:"This will soft-disable the provider if models depend on it."})]}),s.jsxs(i1,{children:[s.jsx(sm,{children:"Cancel"}),s.jsx(rm,{disabled:C,onClick:k=>{E&&(k.preventDefault(),q(E))},children:C?"Deleting…":"Delete"})]})]})})]})}var f_=Object.defineProperty,el=(a,l)=>f_(a,"name",{value:l,configurable:!0}),mm="Checkbox",[h_,$D]=dn(mm),[m_,pm]=h_(mm);function w1(a){const{__scopeCheckbox:l,checked:o,children:i,defaultChecked:c,disabled:d,form:h,name:m,onCheckedChange:g,required:v,value:b="on",internal_do_not_use_render:S}=a,[x,w]=Za({prop:o,defaultProp:c??!1,onChange:g,caller:mm}),[E,j]=p.useState(null),[C,T]=p.useState(null),N=p.useRef(!1),[M,A]=p.useReducer(q=>q+1,0),_=E?!!h||!!E.closest("form"):!0,z={checked:x,disabled:d,setChecked:w,control:E,setControl:j,name:m,form:h,value:b,hasConsumerStoppedPropagationRef:N,userInteractionCount:M,onUserInteraction:A,required:v,defaultChecked:Fa(c)?!1:c,isFormControl:_,bubbleInput:C,setBubbleInput:T};return s.jsx(m_,{scope:l,...z,children:C1(S)?S(z):i})}el(w1,"CheckboxProvider");var p_="CheckboxTrigger",g_=p.forwardRef(el(function({__scopeCheckbox:l,onKeyDown:o,onClick:i,...c},d){const{control:h,value:m,disabled:g,checked:v,required:b,setControl:S,setChecked:x,hasConsumerStoppedPropagationRef:w,onUserInteraction:E,isFormControl:j,bubbleInput:C}=pm(p_,l),T=Ve(d,S),N=p.useRef(v);return p.useEffect(()=>{const M=h==null?void 0:h.form;if(M){const A=el(()=>x(N.current),"reset");return M.addEventListener("reset",A),()=>M.removeEventListener("reset",A)}},[h,x]),s.jsx(Ue.button,{type:"button",role:"checkbox","aria-checked":Fa(v)?"mixed":v,"aria-required":b,"data-state":gm(v),"data-disabled":g?"":void 0,disabled:g,value:m,...c,ref:T,onKeyDown:we(o,M=>{M.key==="Enter"&&M.preventDefault()}),onClick:we(i,M=>{E(),x(A=>Fa(A)?!0:!A),C&&j&&(w.current=M.isPropagationStopped(),w.current||M.stopPropagation())})})},"CheckboxTrigger")),j1=p.forwardRef(el(function(l,o){const{__scopeCheckbox:i,name:c,checked:d,defaultChecked:h,required:m,disabled:g,value:v,onCheckedChange:b,form:S,...x}=l;return s.jsx(w1,{__scopeCheckbox:i,checked:d,defaultChecked:h,disabled:g,required:m,onCheckedChange:b,name:c,form:S,value:v,internal_do_not_use_render:({isFormControl:w})=>s.jsxs(s.Fragment,{children:[s.jsx(g_,{...x,ref:o,__scopeCheckbox:i}),w&&s.jsx(b_,{__scopeCheckbox:i})]})})},"Checkbox")),v_="CheckboxIndicator",x_=p.forwardRef(el(function(l,o){const{__scopeCheckbox:i,forceMount:c,...d}=l,h=pm(v_,i);return s.jsx(nl,{present:c||Fa(h.checked)||h.checked===!0,children:s.jsx(Ue.span,{"data-state":gm(h.checked),"data-disabled":h.disabled?"":void 0,...d,ref:o,style:{pointerEvents:"none",...l.style}})})},"CheckboxIndicator")),y_="CheckboxBubbleInput",b_=p.forwardRef(el(function({__scopeCheckbox:l,onClick:o,...i},c){const{control:d,hasConsumerStoppedPropagationRef:h,userInteractionCount:m,checked:g,defaultChecked:v,required:b,disabled:S,name:x,value:w,form:E,bubbleInput:j,setBubbleInput:C}=pm(y_,l),T=Ve(c,C),N=qc(d),M=p.useRef(!1),A=p.useRef(g),_=p.useRef(m);p.useEffect(()=>{const q=j;if(!q)return;const k=window.HTMLInputElement.prototype,re=Object.getOwnPropertyDescriptor(k,"checked").set,K=m!==_.current;_.current=m;const V=A.current!==g;A.current=g;const le=!(K&&h.current);if(V&&re){M.current=!K;const se=new Event("click",{bubbles:le});q.indeterminate=Fa(g),re.call(q,Fa(g)?!1:g),q.dispatchEvent(se),M.current=!1}},[j,g,h,m]);const z=p.useRef(Fa(g)?!1:g);return s.jsx(Ue.input,{type:"checkbox","aria-hidden":!0,defaultChecked:v??z.current,required:b,disabled:S,name:x,value:w,form:E,...i,tabIndex:-1,ref:T,onClick:we(o,q=>{M.current&&q.stopPropagation()}),style:{...i.style,...N,position:"absolute",pointerEvents:"none",opacity:0,margin:0,transform:"translateX(-100%)"}})},"CheckboxBubbleInput"));function C1(a){return typeof a=="function"}el(C1,"isFunction");function Fa(a){return a==="indeterminate"}el(Fa,"isIndeterminate");function gm(a){return Fa(a)?"indeterminate":a?"checked":"unchecked"}el(gm,"getState");const vm=p.forwardRef(({className:a,...l},o)=>s.jsx(j1,{ref:o,className:je("peer h-4 w-4 shrink-0 rounded-sm border border-primary shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",a),...l,children:s.jsx(x_,{className:je("flex items-center justify-center text-current"),children:s.jsx($y,{className:"h-3.5 w-3.5"})})}));vm.displayName=j1.displayName;function S_(){const[a,l]=p.useState([]),[o,i]=p.useState([]),[c,d]=p.useState("all"),[h,m]=p.useState(!1),[g,v]=p.useState(""),[b,S]=p.useState([]),[x,w]=p.useState(new Set),[E,j]=p.useState(!1),[C,T]=p.useState(""),[N,M]=p.useState(""),[A,_]=p.useState(null),[z,q]=p.useState(!1),[k,W]=p.useState(null),[re,K]=p.useState(null),V=async()=>{const[H,F]=await Promise.all([Se.get("/api/admin/models"),Se.get("/api/admin/providers")]);l(H.models),i(F.providers)};p.useEffect(()=>{V()},[]);const le=a.filter(H=>!(c!=="all"&&H.providerId!==c||C&&!H.publicModelId.toLowerCase().includes(C.toLowerCase()))),se=b.filter(H=>{if(!N)return!0;const F=N.toLowerCase();return H.upstreamId.toLowerCase().includes(F)||H.displayName.toLowerCase().includes(F)}),ce=async()=>{if(g){j(!0);try{const H=await Se.post(`/api/admin/providers/${g}/discover`);S(H.models),w(new Set)}catch(H){xe.error(H.message)}finally{j(!1)}}},U=async()=>{if(x.size!==0)try{const H=await Se.post("/api/admin/models/import",{providerId:g,modelIds:Array.from(x)});xe.success(`Imported ${H.imported} of ${H.requested}`),m(!1),S([]),w(new Set),V()}catch(H){xe.error(H.message)}},$=async()=>{if(re)try{await Se.del(`/api/admin/models/${re.id}`),xe.success("Model deleted"),K(null),V()}catch(H){xe.error(H.message)}},ne=async H=>{var D,P,Q;_(H),q(!0);const F=Date.now();W({phase:"streaming",startedAt:F,text:"",progress:{}});try{const ae=await globalThis.fetch(`/api/admin/models/${H}/test-stream`,{method:"POST",headers:{"content-type":"application/json"},credentials:"include"});if(!ae.ok){const Re=await ae.text().catch(()=>"");W({phase:"error",model:H,error:`HTTP ${ae.status}: ${Re}`});return}const de=(D=ae.body)==null?void 0:D.getReader();if(!de){W({phase:"error",model:H,error:"No response body"});return}const Z=new TextDecoder;let oe="",ie="",me=!1;for(;!me;){const{value:Re,done:Ae}=await de.read();me=Ae,Re&&(oe+=Z.decode(Re,{stream:!0}));let Me;for(;(Me=oe.indexOf(`
|
|
322
322
|
|
|
323
323
|
`))>=0;){const He=oe.slice(0,Me);oe=oe.slice(Me+2);const mt=He.split(`
|
|
324
|
-
`);let pt="",bt="";for(const St of mt)St.startsWith("event: ")?pt=St.slice(7):St.startsWith("data: ")&&(bt=St.slice(6));if(bt){if(pt===""||pt==="message")try{const Lt=(P=JSON.parse(bt).choices)==null?void 0:P[0];(Q=Lt==null?void 0:Lt.delta)!=null&&Q.content&&(ie+=Lt.delta.content),W(fn=>{if(!fn||fn.phase!=="streaming")return fn;const Qn=Date.now()-F,hn=fn.progress.ttftMs??Qn;return{...fn,text:ie,progress:{ttftMs:hn,elapsedMs:Qn}}})}catch{}if(pt==="test_meta")try{const St=JSON.parse(bt);W({phase:"done",model:H,result:St,text:ie})}catch{}if(pt==="test_error")try{const St=JSON.parse(bt);W({phase:"error",model:H,error:St.message})}catch{}}}}W(Re=>!Re||Re.phase==="streaming"?{phase:"error",model:H,error:"Stream ended unexpectedly"}:Re)}catch(ae){W({phase:"error",model:H,error:ae.message})}finally{_(null)}};return s.jsxs("div",{children:[s.jsx(wa,{title:"Models",description:"Physical models imported from providers",actions:s.jsxs(qn,{open:h,onOpenChange:m,children:[s.jsx(Ho,{asChild:!0,children:s.jsxs(he,{variant:"outline",children:[s.jsx(Ky,{className:"mr-1 h-4 w-4"})," Fetch models"]})}),s.jsxs(jn,{className:"max-w-2xl",children:[s.jsx(Cn,{children:s.jsx(En,{children:"Discover models"})}),s.jsxs("div",{className:"space-y-3",children:[s.jsxs("div",{className:"flex items-end gap-2",children:[s.jsx("div",{className:"flex-1",children:s.jsxs(In,{value:g,onValueChange:v,children:[s.jsx(Rn,{children:s.jsx(Gn,{placeholder:"Choose provider"})}),s.jsx(Nn,{children:o.map(H=>s.jsx(lt,{value:H.id,children:H.name},H.id))})]})}),s.jsx(he,{onClick:ce,disabled:!g||E,children:E?"Fetching…":"Fetch"})]}),b.length>0&&s.jsxs("div",{className:"space-y-2",children:[s.jsxs("div",{className:"flex items-center justify-between gap-2",children:[s.jsx("div",{className:"flex items-center gap-2 flex-1",children:s.jsxs("div",{className:"relative flex-1",children:[s.jsx(Jy,{className:"absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground"}),s.jsx(Ne,{className:"pl-8",placeholder:"Search models…",value:N,onChange:H=>M(H.target.value)}),N&&s.jsx("button",{className:"absolute right-2 top-2.5 text-muted-foreground hover:text-foreground",onClick:()=>M(""),children:s.jsx(Dc,{className:"h-4 w-4"})})]})}),s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsxs("span",{className:"text-sm text-muted-foreground",children:[se.length," / ",b.length," · ",x.size," selected"]}),s.jsx(he,{variant:"outline",size:"sm",onClick:()=>w(new Set(se.filter(H=>!H.alreadyImported).map(H=>H.upstreamId))),children:"Select All (new)"}),s.jsx(he,{variant:"outline",size:"sm",onClick:()=>w(new Set),children:"Clear"})]})]}),s.jsx("div",{className:"max-h-80 space-y-1 overflow-auto rounded border p-2",children:se.length===0&&b.length>0?s.jsx("div",{className:"text-center text-sm text-muted-foreground py-4",children:"No models match your search."}):se.map(H=>s.jsxs("label",{className:"flex items-center gap-2 rounded p-1 text-sm hover:bg-accent",children:[s.jsx(vm,{checked:x.has(H.upstreamId),onCheckedChange:F=>{const D=new Set(x);F?D.add(H.upstreamId):D.delete(H.upstreamId),w(D)}}),s.jsx("span",{className:"font-mono text-xs",children:H.upstreamId}),H.alreadyImported&&s.jsx(Qe,{variant:"secondary",children:"imported"})]},H.upstreamId))})]})]}),s.jsxs(Vn,{children:[s.jsx(he,{variant:"outline",onClick:()=>m(!1),children:"Cancel"}),s.jsxs(he,{disabled:x.size===0,onClick:U,children:["Import ",x.size||""]})]})]})]})}),s.jsxs(Ze,{children:[s.jsxs(Je,{children:[s.jsx(We,{className:"text-base",children:"All models"}),s.jsxs(wn,{children:[a.length," total"]})]}),s.jsxs(et,{children:[s.jsxs("div",{className:"mb-3 flex items-center gap-2",children:[s.jsxs(In,{value:c,onValueChange:d,children:[s.jsx(Rn,{className:"w-56",children:s.jsx(Gn,{})}),s.jsxs(Nn,{children:[s.jsx(lt,{value:"all",children:"All providers"}),o.map(H=>s.jsx(lt,{value:H.id,children:H.name},H.id))]})]}),s.jsx(Ne,{className:"max-w-xs",placeholder:"Search public ID",value:C,onChange:H=>T(H.target.value)})]}),s.jsxs(Kn,{children:[s.jsx(Xn,{children:s.jsxs(Ye,{children:[s.jsx(pe,{children:"Public ID"}),s.jsx(pe,{children:"Provider"}),s.jsx(pe,{children:"Upstream ID"}),s.jsx(pe,{children:"Capabilities"}),s.jsx(pe,{children:"Available"}),s.jsx(pe,{children:"Enabled"}),s.jsx(pe,{})]})}),s.jsxs(Fn,{children:[le.length===0&&s.jsx(Ye,{children:s.jsx(fe,{colSpan:7,className:"text-center text-muted-foreground",children:"No models"})}),le.map(H=>s.jsxs(Ye,{children:[s.jsx(fe,{className:"font-mono text-xs",children:H.publicModelId}),s.jsx(fe,{children:H.providerSlug}),s.jsx(fe,{className:"text-xs text-muted-foreground",children:H.upstreamModelId}),s.jsx(fe,{className:"space-x-1",children:Object.entries(H.capabilities).filter(([,F])=>F===!0).slice(0,4).map(([F])=>s.jsx(Qe,{variant:"outline",className:"mr-1",children:F},F))}),s.jsx(fe,{children:H.upstreamAvailable?s.jsx(Qe,{variant:"success",children:"up"}):s.jsx(Qe,{variant:"destructive",children:"down"})}),s.jsx(fe,{children:H.enabled?"Yes":"No"}),s.jsx(fe,{className:"text-right",children:s.jsxs("div",{className:"flex items-center justify-end gap-1",children:[s.jsxs(he,{size:"sm",variant:"outline",onClick:()=>void ne(H.id),disabled:A!==null,children:[A===H.id?s.jsx(jo,{className:"h-3.5 w-3.5 animate-spin"}):s.jsx(c2,{className:"h-3.5 w-3.5"})," Test"]}),s.jsxs(he,{size:"sm",variant:"destructive",onClick:()=>K(H),disabled:A!==null,children:[s.jsx(_c,{className:"h-3.5 w-3.5"})," Xoá"]})]})})]},H.id))]})]})]})]}),s.jsx(qn,{open:!!re,onOpenChange:H=>{H||K(null)},children:s.jsxs(jn,{className:"max-w-md",children:[s.jsx(Cn,{children:s.jsx(En,{children:"Xoá model"})}),s.jsxs("div",{className:"space-y-2 text-sm",children:[s.jsxs("p",{children:["Bạn có chắc muốn xoá model ",s.jsx("span",{className:"font-mono",children:re==null?void 0:re.publicModelId}),"?"]}),s.jsx("p",{className:"text-muted-foreground",children:"Model đang được dùng trong combo sẽ bị soft-disable (vô hiệu hoá) thay vì xoá hẳn, để giữ lịch sử và tham chiếu combo."})]}),s.jsxs(Vn,{children:[s.jsx(he,{variant:"outline",onClick:()=>K(null),children:"Huỷ"}),s.jsx(he,{variant:"destructive",onClick:$,children:"Xoá"})]})]})}),s.jsx(qn,{open:z,onOpenChange:q,children:s.jsxs(jn,{className:"max-w-2xl",children:[s.jsx(Cn,{children:s.jsx(En,{children:"Kết quả test model"})}),k&&k.phase==="streaming"&&s.jsxs("div",{className:"space-y-3 text-sm",children:[s.jsxs("div",{className:"flex items-center gap-2 text-muted-foreground",children:[s.jsx(jo,{className:"h-4 w-4 animate-spin"})," Đang stream…",s.jsxs("span",{className:"font-mono text-xs text-muted-foreground/60",children:["TTFT ",k.progress.ttftMs!=null?`${k.progress.ttftMs} ms`:"…"]}),s.jsxs("span",{className:"font-mono text-xs text-muted-foreground/60",children:["· ",k.progress.elapsedMs!=null?`${k.progress.elapsedMs} ms`:"…"]})]}),s.jsxs("div",{children:[s.jsx("div",{className:"text-xs text-muted-foreground mb-1",children:"Phản hồi (streaming)"}),s.jsxs("div",{className:"max-h-60 overflow-auto whitespace-pre-wrap rounded border bg-muted p-3 font-mono text-xs",children:[k.text||s.jsx("span",{className:"text-muted-foreground/60 animate-pulse",children:"waiting for first token…"}),k.phase==="streaming"&&s.jsx("span",{className:"ml-0.5 inline-block h-3.5 w-1.5 animate-pulse bg-primary/70"})]})]})]}),k&&k.phase==="done"&&s.jsxs("div",{className:"space-y-3 text-sm",children:[s.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[s.jsx(Qe,{variant:k.result.success?"success":"destructive",children:k.result.success?"Thành công":"Thất bại"}),s.jsxs("div",{children:[s.jsx("div",{className:"text-xs text-muted-foreground",children:"Thời gian phản hồi"}),s.jsxs("div",{className:"font-mono",children:[k.result.latencyMs," ms"]})]}),s.jsxs("div",{children:[s.jsx("div",{className:"text-xs text-muted-foreground",children:"TTFT"}),s.jsx("div",{className:"font-mono",children:k.result.ttftMs!=null?`${k.result.ttftMs} ms`:"—"})]}),s.jsxs("div",{children:[s.jsx("div",{className:"text-xs text-muted-foreground",children:"Tokens (in / out)"}),s.jsxs("div",{className:"font-mono",children:[k.result.usage.input," / ",k.result.usage.output]})]})]}),s.jsxs("div",{children:[s.jsx("div",{className:"text-xs text-muted-foreground mb-1",children:"Phản hồi của model"}),s.jsx("div",{className:"max-h-60 overflow-auto whitespace-pre-wrap rounded border bg-muted p-3 font-mono text-xs",children:k.text||k.result.text||"(trống)"})]}),k.result.attempts.length>0&&s.jsxs("div",{children:[s.jsx("div",{className:"text-xs text-muted-foreground mb-1",children:"Attempts"}),s.jsx("div",{className:"space-y-1",children:k.result.attempts.map((H,F)=>s.jsxs("div",{className:"flex items-center gap-2 rounded border p-2 text-xs",children:[s.jsx(Qe,{variant:H.success?"success":"destructive",children:H.success?"OK":"FAIL"}),s.jsxs("span",{className:"font-mono",children:[H.providerName," / ",H.modelId]}),s.jsxs("span",{className:"text-muted-foreground",children:[H.latencyMs," ms"]}),H.failureReason&&s.jsx("span",{className:"text-destructive",children:H.failureReason})]},F))})]})]}),k&&k.phase==="error"&&s.jsxs("div",{className:"space-y-2 text-sm",children:[s.jsx(Qe,{variant:"destructive",children:"Thất bại"}),s.jsx("p",{className:"text-destructive",children:k.error})]}),s.jsx(Vn,{children:s.jsx(he,{variant:"outline",onClick:()=>q(!1),children:"Đóng"})})]})})]})}function w_(){const[a,l]=p.useState([]),[o,i]=p.useState([]),[c,d]=p.useState(!1),[h,m]=p.useState(!1),[g,v]=p.useState(null),[b,S]=p.useState(!1),[x,w]=p.useState(!1),[E,j]=p.useState({name:"",slug:"",mode:"fallback",enabled:!0,members:[]}),[C,T]=p.useState({name:"",slug:"",mode:"fallback",enabled:!0,members:[]}),N=async()=>{const[K,V]=await Promise.all([Se.get("/api/admin/combos"),Se.get("/api/admin/models")]);l(K.combos),i(V.models)};p.useEffect(()=>{N()},[]);const M=K=>{j(V=>({...V,members:[...V.members,{modelId:K,weight:1,position:V.members.length,enabled:!0}]}))},A=K=>{j(V=>({...V,members:V.members.filter((le,se)=>se!==K).map((le,se)=>({...le,position:se}))}))},_=async()=>{if(E.members.length===0){xe.error("Add at least one member");return}S(!0);try{await Se.post("/api/admin/combos",{name:E.name,slug:E.slug||void 0,mode:E.mode,enabled:E.enabled,members:E.members}),xe.success("Combo created"),d(!1),j({name:"",slug:"",mode:"fallback",enabled:!0,members:[]}),N()}catch(K){xe.error(K.message)}finally{S(!1)}},z=async K=>{try{const le=(await Se.get(`/api/admin/combos/${K.id}`)).combo;v(le.id),T({name:le.name,slug:le.slug??"",mode:le.mode,enabled:le.enabled,members:le.members.map(se=>({modelId:se.modelId,weight:se.weight,position:se.position,enabled:se.enabled}))}),m(!0)}catch(V){xe.error(V.message)}},q=async()=>{if(g){if(C.members.length===0){xe.error("Add at least one member");return}w(!0);try{await Se.patch("/api/admin/combos",{id:g,name:C.name,slug:C.slug||void 0,mode:C.mode,enabled:C.enabled,members:C.members}),xe.success("Combo updated"),m(!1),v(null),N()}catch(K){xe.error(K.message)}finally{w(!1)}}},k=K=>{T(V=>({...V,members:[...V.members,{modelId:K,weight:1,position:V.members.length,enabled:!0}]}))},W=K=>{T(V=>({...V,members:V.members.filter((le,se)=>se!==K).map((le,se)=>({...le,position:se}))}))},re=async K=>{if(confirm("Delete this combo?"))try{await Se.del(`/api/admin/combos/${K}`),xe.success("Combo removed"),N()}catch(V){xe.error(V.message)}};return s.jsxs("div",{children:[s.jsx(wa,{title:"Combos",description:"Virtual models combining physical models",actions:s.jsxs(qn,{open:c,onOpenChange:d,children:[s.jsx(Ho,{asChild:!0,children:s.jsxs(he,{children:[s.jsx(Oo,{className:"mr-1 h-4 w-4"})," New combo"]})}),s.jsxs(jn,{className:"max-w-2xl",children:[s.jsx(Cn,{children:s.jsx(En,{children:"New combo"})}),s.jsxs("div",{className:"space-y-3",children:[s.jsxs("div",{children:[s.jsx(ye,{children:"Name"}),s.jsx(Ne,{value:E.name,onChange:K=>j({...E,name:K.target.value})})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"Slug (optional — leave empty to use the name as the model ID)"}),s.jsx(Ne,{value:E.slug,onChange:K=>j({...E,slug:K.target.value}),placeholder:"empty → gpt-5.5 · set → combo/gpt-5.5"})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"Mode"}),s.jsxs(In,{value:E.mode,onValueChange:K=>j({...E,mode:K}),children:[s.jsx(Rn,{children:s.jsx(Gn,{})}),s.jsxs(Nn,{children:[s.jsx(lt,{value:"fallback",children:"Fallback (ordered)"}),s.jsx(lt,{value:"weighted_round_robin",children:"Weighted round-robin"})]})]})]}),s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsx(ba,{checked:E.enabled,onCheckedChange:K=>j({...E,enabled:K})}),s.jsx(ye,{children:"Enabled"})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"Members"}),s.jsx(my,{models:o,addedIds:E.members.map(K=>K.modelId),onAdd:M}),s.jsx("div",{className:"mt-2 space-y-1",children:E.members.map((K,V)=>{var le;return s.jsxs("div",{className:"flex items-center gap-2 rounded border p-2 text-sm",children:[s.jsx("span",{className:"font-mono text-xs",children:(le=o.find(se=>se.id===K.modelId))==null?void 0:le.publicModelId}),s.jsx(Ne,{type:"number",min:1,value:K.weight,onChange:se=>{const ce=Number(se.target.value);j(U=>({...U,members:U.members.map(($,ne)=>ne===V?{...$,weight:ce}:$)}))},className:"w-20"}),s.jsx(he,{size:"sm",variant:"outline",onClick:()=>A(V),children:"Remove"})]},V)})})]})]}),s.jsxs(Vn,{children:[s.jsx(he,{variant:"outline",onClick:()=>d(!1),children:"Cancel"}),s.jsx(he,{disabled:!E.name||b,onClick:_,children:b?"Creating…":"Create"})]})]})]})}),s.jsxs(Ze,{children:[s.jsxs(Je,{children:[s.jsx(We,{className:"text-base",children:"All combos"}),s.jsxs(wn,{children:[a.length," total"]})]}),s.jsx(et,{children:s.jsxs(Kn,{children:[s.jsx(Xn,{children:s.jsxs(Ye,{children:[s.jsx(pe,{children:"Public ID"}),s.jsx(pe,{children:"Mode"}),s.jsx(pe,{children:"Members"}),s.jsx(pe,{children:"Healthy"}),s.jsx(pe,{children:"Enabled"}),s.jsx(pe,{})]})}),s.jsxs(Fn,{children:[a.length===0&&s.jsx(Ye,{children:s.jsx(fe,{colSpan:6,className:"text-center text-muted-foreground",children:"No combos yet."})}),a.map(K=>s.jsxs(Ye,{children:[s.jsx(fe,{className:"font-mono text-xs",children:K.publicModelId}),s.jsx(fe,{children:s.jsx(Qe,{variant:"outline",children:K.mode})}),s.jsx(fe,{children:K.memberCount}),s.jsx(fe,{children:K.healthyMemberCount}),s.jsx(fe,{children:K.enabled?"Yes":"No"}),s.jsx(fe,{className:"text-right",children:s.jsxs("div",{className:"flex items-center justify-end gap-1",children:[s.jsxs(he,{size:"sm",variant:"outline",onClick:()=>void z(K),children:[s.jsx(v2,{className:"h-3.5 w-3.5"})," Sửa"]}),s.jsxs(he,{size:"sm",variant:"destructive",onClick:()=>re(K.id),children:[s.jsx(_c,{className:"h-3.5 w-3.5"})," Xoá"]})]})})]},K.id))]})]})})]}),s.jsx(qn,{open:h,onOpenChange:m,children:s.jsxs(jn,{className:"max-w-2xl",children:[s.jsx(Cn,{children:s.jsx(En,{children:"Edit combo"})}),s.jsxs("div",{className:"space-y-3",children:[s.jsxs("div",{children:[s.jsx(ye,{children:"Name"}),s.jsx(Ne,{value:C.name,onChange:K=>T({...C,name:K.target.value})})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"Slug (optional — leave empty to use the name as the model ID)"}),s.jsx(Ne,{value:C.slug,onChange:K=>T({...C,slug:K.target.value}),placeholder:"empty → gpt-5.5 · set → combo/gpt-5.5"})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"Mode"}),s.jsxs(In,{value:C.mode,onValueChange:K=>T({...C,mode:K}),children:[s.jsx(Rn,{children:s.jsx(Gn,{})}),s.jsxs(Nn,{children:[s.jsx(lt,{value:"fallback",children:"Fallback (ordered)"}),s.jsx(lt,{value:"weighted_round_robin",children:"Weighted round-robin"})]})]})]}),s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsx(ba,{checked:C.enabled,onCheckedChange:K=>T({...C,enabled:K})}),s.jsx(ye,{children:"Enabled"})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"Members"}),s.jsx(my,{models:o,addedIds:C.members.map(K=>K.modelId),onAdd:k}),s.jsx("div",{className:"mt-2 space-y-1",children:C.members.map((K,V)=>{var le;return s.jsxs("div",{className:"flex items-center gap-2 rounded border p-2 text-sm",children:[s.jsx("span",{className:"font-mono text-xs",children:(le=o.find(se=>se.id===K.modelId))==null?void 0:le.publicModelId}),s.jsx(Ne,{type:"number",min:1,value:K.weight,onChange:se=>{const ce=Number(se.target.value);T(U=>({...U,members:U.members.map(($,ne)=>ne===V?{...$,weight:ce}:$)}))},className:"w-20"}),s.jsx(he,{size:"sm",variant:"outline",onClick:()=>W(V),children:"Remove"})]},V)})})]})]}),s.jsxs(Vn,{children:[s.jsx(he,{variant:"outline",onClick:()=>m(!1),children:"Cancel"}),s.jsx(he,{disabled:!C.name||x,onClick:q,children:x?"Saving…":"Save"})]})]})})]})}function my({models:a,addedIds:l,onAdd:o}){const[i,c]=p.useState(""),h=(i?a.filter(m=>{const g=i.toLowerCase();return m.publicModelId.toLowerCase().includes(g)||m.displayName.toLowerCase().includes(g)}):a).filter(m=>!l.includes(m.id));return s.jsxs("div",{className:"space-y-1",children:[s.jsxs("div",{className:"relative",children:[s.jsx(Jy,{className:"absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground"}),s.jsx(Ne,{className:"pl-8",placeholder:"Search models…",value:i,onChange:m=>c(m.target.value)}),i&&s.jsx("button",{className:"absolute right-2 top-2.5 text-muted-foreground hover:text-foreground",onClick:()=>c(""),children:s.jsx(Dc,{className:"h-4 w-4"})})]}),h.length===0?s.jsx("p",{className:"text-xs text-muted-foreground",children:"No models match."}):s.jsx("div",{className:"max-h-40 space-y-1 overflow-auto rounded border p-1",children:h.map(m=>s.jsxs("div",{className:"flex items-center justify-between rounded p-1 text-sm hover:bg-accent",children:[s.jsx("span",{className:"font-mono text-xs",children:m.publicModelId}),s.jsx(he,{size:"sm",variant:"ghost",onClick:()=>o(m.id),children:"+ Add"})]},m.id))})]})}function j_(){const[a,l]=p.useState([]),[o,i]=p.useState([]),[c,d]=p.useState([]),[h,m]=p.useState(!1),[g,v]=p.useState({alias:"",targetKind:"model",targetId:"",enabled:!0}),b=async()=>{const[x,w,E]=await Promise.all([Se.get("/api/admin/aliases"),Se.get("/api/admin/models"),Se.get("/api/admin/combos")]);l(x.aliases),i(w.models),d(E.combos)};p.useEffect(()=>{b()},[]);const S=async()=>{try{await Se.post("/api/admin/aliases",g),xe.success("Alias created"),m(!1),v({alias:"",targetKind:"model",targetId:"",enabled:!0}),b()}catch(x){xe.error(x.message)}};return s.jsxs("div",{children:[s.jsx(wa,{title:"Aliases",description:"Stable client-visible names for models or combos",actions:s.jsxs(qn,{open:h,onOpenChange:m,children:[s.jsx(Ho,{asChild:!0,children:s.jsxs(he,{children:[s.jsx(Oo,{className:"mr-1 h-4 w-4"})," New alias"]})}),s.jsxs(jn,{children:[s.jsx(Cn,{children:s.jsx(En,{children:"New alias"})}),s.jsxs("div",{className:"space-y-3",children:[s.jsxs("div",{children:[s.jsx(ye,{children:"Alias"}),s.jsx(Ne,{value:g.alias,onChange:x=>v({...g,alias:x.target.value}),placeholder:"coding"})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"Target type"}),s.jsxs(In,{value:g.targetKind,onValueChange:x=>v({...g,targetKind:x}),children:[s.jsx(Rn,{children:s.jsx(Gn,{})}),s.jsxs(Nn,{children:[s.jsx(lt,{value:"model",children:"Model"}),s.jsx(lt,{value:"combo",children:"Combo"})]})]})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"Target"}),s.jsxs(In,{value:g.targetId,onValueChange:x=>v({...g,targetId:x}),children:[s.jsx(Rn,{children:s.jsx(Gn,{placeholder:"Choose target"})}),s.jsx(Nn,{children:(g.targetKind==="model"?o:c).map(x=>s.jsx(lt,{value:x.id,children:x.publicModelId},x.id))})]})]}),s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsx(ba,{checked:g.enabled,onCheckedChange:x=>v({...g,enabled:x})}),s.jsx(ye,{children:"Enabled"})]})]}),s.jsxs(Vn,{children:[s.jsx(he,{variant:"outline",onClick:()=>m(!1),children:"Cancel"}),s.jsx(he,{disabled:!g.alias||!g.targetId,onClick:S,children:"Create"})]})]})]})}),s.jsxs(Ze,{children:[s.jsxs(Je,{children:[s.jsx(We,{className:"text-base",children:"All aliases"}),s.jsxs(wn,{children:[a.length," total"]})]}),s.jsx(et,{children:s.jsxs(Kn,{children:[s.jsx(Xn,{children:s.jsxs(Ye,{children:[s.jsx(pe,{children:"Alias"}),s.jsx(pe,{children:"Target"}),s.jsx(pe,{children:"Type"}),s.jsx(pe,{children:"Enabled"}),s.jsx(pe,{})]})}),s.jsxs(Fn,{children:[a.length===0&&s.jsx(Ye,{children:s.jsx(fe,{colSpan:5,className:"text-center text-muted-foreground",children:"No aliases yet."})}),a.map(x=>s.jsxs(Ye,{children:[s.jsx(fe,{className:"font-mono text-xs",children:x.alias}),s.jsx(fe,{className:"font-mono text-xs",children:x.targetName??x.targetId}),s.jsx(fe,{children:s.jsx(Qe,{variant:"outline",children:x.targetKind})}),s.jsx(fe,{children:x.enabled?"Yes":"No"}),s.jsx(fe,{className:"text-right",children:s.jsx(he,{size:"sm",variant:"outline",onClick:async()=>{await Se.del(`/api/admin/aliases/${x.id}`),xe.success("Removed"),b()},children:"Delete"})})]},x.id))]})]})})]})]})}function C_(){const[a,l]=p.useState([]),[o,i]=p.useState([]),[c,d]=p.useState([]),[h,m]=p.useState(!1),[g,v]=p.useState(null),[b,S]=p.useState(null),[x,w]=p.useState({name:"",expiresAt:"",allowAll:!0,permissions:[],rpmLimit:"",tpmLimit:"",concurrency:"",customSecret:""}),E=async()=>{const[N,M,A]=await Promise.all([Se.get("/api/admin/api-keys"),Se.get("/api/admin/models"),Se.get("/api/admin/combos")]);l(N.apiKeys),i(M.models),d(A.combos)};p.useEffect(()=>{E()},[]);const j=async()=>{try{const N=await Se.post("/api/admin/api-keys",{name:x.name,expiresAt:x.expiresAt||null,allowAllModels:x.allowAll,permissions:x.allowAll?void 0:x.permissions,rpmLimit:x.rpmLimit?Number(x.rpmLimit):null,tpmLimit:x.tpmLimit?Number(x.tpmLimit):null,maxConcurrent:x.concurrency?Number(x.concurrency):null,...x.customSecret.trim()?{secret:x.customSecret.trim()}:{}});m(!1),v({secret:N.secret,name:N.name}),w({name:"",expiresAt:"",allowAll:!0,permissions:[],rpmLimit:"",tpmLimit:"",concurrency:"",customSecret:""}),E()}catch(N){xe.error(N.message)}},C=async(N,M)=>{try{await Se.patch("/api/admin/api-keys",{id:N,enabled:!M}),xe.success(M?"Key disabled":"Key enabled"),E()}catch(A){xe.error(A.message)}},T=async N=>{if(window.confirm("Delete this API key? This cannot be undone."))try{await Se.del(`/api/admin/api-keys/${N}`),xe.success("Key deleted"),E()}catch(M){xe.error(M.message)}};return s.jsxs("div",{children:[s.jsx(wa,{title:"API Keys",description:"Gateway bearer keys for client applications",actions:s.jsxs(qn,{open:h,onOpenChange:m,children:[s.jsx(Ho,{asChild:!0,children:s.jsxs(he,{children:[s.jsx(Oo,{className:"mr-1 h-4 w-4"})," New key"]})}),s.jsxs(jn,{className:"max-w-2xl",children:[s.jsx(Cn,{children:s.jsx(En,{children:"New API key"})}),s.jsxs("div",{className:"space-y-3",children:[s.jsxs("div",{children:[s.jsx(ye,{children:"Name"}),s.jsx(Ne,{value:x.name,onChange:N=>w({...x,name:N.target.value})})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"Expires (optional)"}),s.jsx(Ne,{type:"datetime-local",value:x.expiresAt,onChange:N=>w({...x,expiresAt:N.target.value})})]}),s.jsxs("div",{className:"grid grid-cols-3 gap-2",children:[s.jsxs("div",{children:[s.jsx(ye,{children:"RPM limit"}),s.jsx(Ne,{value:x.rpmLimit,onChange:N=>w({...x,rpmLimit:N.target.value}),type:"number"})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"TPM limit"}),s.jsx(Ne,{value:x.tpmLimit,onChange:N=>w({...x,tpmLimit:N.target.value}),type:"number"})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"Concurrency"}),s.jsx(Ne,{value:x.concurrency,onChange:N=>w({...x,concurrency:N.target.value}),type:"number"})]})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"Key value (optional)"}),s.jsx(Ne,{value:x.customSecret,onChange:N=>w({...x,customSecret:N.target.value}),placeholder:"Leave empty to auto-generate ld-…"}),s.jsx("p",{className:"text-xs text-muted-foreground",children:"If provided, this exact value is stored as the key. Otherwise a random ld-… key is generated."})]}),s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsx(ba,{checked:x.allowAll,onCheckedChange:N=>w({...x,allowAll:N})}),s.jsx(ye,{children:"Allow all current and future models"})]}),!x.allowAll&&s.jsxs("div",{children:[s.jsx(ye,{children:"Scope"}),s.jsx("div",{className:"max-h-48 space-y-1 overflow-auto rounded border p-2",children:[...o.map(N=>({targetKind:"model",targetId:N.id,label:N.publicModelId})),...c.map(N=>({targetKind:"combo",targetId:N.id,label:N.publicModelId}))].map(N=>{const M=x.permissions.some(A=>A.targetKind===N.targetKind&&A.targetId===N.targetId);return s.jsxs("label",{className:"flex items-center gap-2 rounded p-1 text-sm hover:bg-accent",children:[s.jsx(vm,{checked:M,onCheckedChange:A=>{w(_=>({..._,permissions:A?[..._.permissions,{targetKind:N.targetKind,targetId:N.targetId}]:_.permissions.filter(z=>!(z.targetKind===N.targetKind&&z.targetId===N.targetId))}))}}),s.jsx("span",{className:"font-mono text-xs",children:N.label}),s.jsx(Qe,{variant:"outline",className:"ml-1",children:N.targetKind})]},`${N.targetKind}:${N.targetId}`)})})]})]}),s.jsxs(Vn,{children:[s.jsx(he,{variant:"outline",onClick:()=>m(!1),children:"Cancel"}),s.jsx(he,{disabled:!x.name,onClick:j,children:"Create"})]})]})]})}),s.jsxs(Ze,{children:[s.jsxs(Je,{children:[s.jsx(We,{className:"text-base",children:"All keys"}),s.jsxs(wn,{children:[a.length," total"]})]}),s.jsx(et,{children:s.jsxs(Kn,{children:[s.jsx(Xn,{children:s.jsxs(Ye,{children:[s.jsx(pe,{children:"Name"}),s.jsx(pe,{children:"Prefix"}),s.jsx(pe,{children:"Status"}),s.jsx(pe,{children:"Scope"}),s.jsx(pe,{children:"RPM/TPM/Conc"}),s.jsx(pe,{})]})}),s.jsxs(Fn,{children:[a.length===0&&s.jsx(Ye,{children:s.jsx(fe,{colSpan:6,className:"text-center text-muted-foreground",children:"No API keys yet."})}),a.map(N=>s.jsxs(Ye,{children:[s.jsx(fe,{className:"font-medium",children:N.name}),s.jsxs(fe,{className:"font-mono text-xs",children:[N.keyPrefix,"…"]}),s.jsx(fe,{children:N.enabled?s.jsx(Qe,{variant:"success",children:"enabled"}):s.jsx(Qe,{variant:"destructive",children:"disabled"})}),s.jsx(fe,{children:N.allowAllModels?"all":`${N.modelScopeCount} scoped`}),s.jsx(fe,{className:"text-xs",children:[N.rpmLimit,N.tpmLimit,N.concurrencyLimit].map((M,A)=>M?["","RPM","TPM","Conc"][A+1]:null).filter(Boolean).join(" / ")||"—"}),s.jsx(fe,{className:"text-right",children:s.jsxs("div",{className:"flex items-center justify-end gap-1",children:[N.secret&&s.jsxs(s.Fragment,{children:[s.jsx(he,{size:"sm",variant:"ghost",title:"Copy secret",onClick:()=>{navigator.clipboard.writeText(N.secret),xe.success("Copied")},children:s.jsx(Cf,{className:"h-3.5 w-3.5"})}),s.jsx(he,{size:"sm",variant:"ghost",title:"Show secret",onClick:()=>S({secret:N.secret,name:N.name}),children:s.jsx(o2,{className:"h-3.5 w-3.5"})})]}),s.jsxs(he,{size:"sm",variant:"outline",onClick:()=>C(N.id,N.enabled),children:[N.enabled?s.jsx(QC,{className:"mr-1 h-3.5 w-3.5"}):s.jsx(Ac,{className:"mr-1 h-3.5 w-3.5"}),N.enabled?"Disable":"Enable"]}),s.jsx(he,{size:"sm",variant:"destructive",onClick:()=>T(N.id),children:s.jsx(_c,{className:"h-3.5 w-3.5"})})]})})]},N.id))]})]})})]}),s.jsx(qn,{open:!!g,onOpenChange:N=>{N||v(null)},children:s.jsxs(jn,{children:[s.jsxs(Cn,{children:[s.jsx(En,{children:"API key created"}),s.jsx(ch,{children:"Copy now — this secret will not be shown again."})]}),s.jsx("div",{className:"rounded border bg-muted p-3 font-mono text-xs break-all",children:g==null?void 0:g.secret}),s.jsxs(Vn,{children:[s.jsxs(he,{onClick:()=>{g&&(navigator.clipboard.writeText(g.secret),xe.success("Copied"))},children:[s.jsx(Cf,{className:"mr-1 h-4 w-4"})," Copy"]}),s.jsx(he,{variant:"outline",onClick:()=>v(null),children:"I have saved it"})]})]})}),s.jsx(qn,{open:!!b,onOpenChange:N=>{N||S(null)},children:s.jsxs(jn,{children:[s.jsxs(Cn,{children:[s.jsxs(En,{children:["API key: ",b==null?void 0:b.name]}),s.jsx(ch,{children:"Full secret for this key, readable any time."})]}),s.jsx("div",{className:"rounded border bg-muted p-3 font-mono text-xs break-all",children:b==null?void 0:b.secret}),s.jsxs(Vn,{children:[s.jsxs(he,{onClick:()=>{b&&(navigator.clipboard.writeText(b.secret),xe.success("Copied"))},children:[s.jsx(Cf,{className:"mr-1 h-4 w-4"})," Copy"]}),s.jsx(he,{variant:"outline",onClick:()=>S(null),children:"Close"})]})]})})]})}const E_=3e3;function R_(a,l){return!(l.success!=="all"&&a.success!==(l.success==="true")||l.protocol!=="all"&&a.protocol!==l.protocol||l.streaming!=="all"&&a.streaming!==(l.streaming==="true")||l.model&&!a.requestedModel.toLowerCase().includes(l.model.toLowerCase()))}function N_(){const[a,l]=p.useState([]),[o,i]=p.useState(0),[c,d]=p.useState(0),[h,m]=p.useState({success:"all",protocol:"all",streaming:"all",model:""}),[g,v]=p.useState(null),[b,S]=p.useState(null),[x,w]=p.useState(0),E=50,j=p.useRef(Date.now()),C=p.useRef(new Set),T=p.useRef(h);T.current=h;const N=p.useRef(c);N.current=c;const M=p.useCallback(async()=>{const _=new URLSearchParams;_.set("limit",String(E)),_.set("offset",String(c)),h.success!=="all"&&_.set("success",h.success),h.protocol!=="all"&&_.set("protocol",h.protocol),h.streaming!=="all"&&_.set("streaming",h.streaming),h.model&&_.set("requestedModel",h.model);const z=await Se.get(`/api/admin/requests?${_.toString()}`);l(z.requests),i(z.total);for(const q of z.requests)C.current.add(q.id)},[c,h]);p.useEffect(()=>{M()},[M]),p.useEffect(()=>{w(0)},[c,h]),p.useEffect(()=>{let _=!1,z=null;const q=new Set,k=()=>{_||(z=new EventSource(`/api/admin/requests/stream?since=${j.current}`),z.addEventListener("request",W=>{if(!_)try{const re=JSON.parse(W.data),K=new Date(re.createdAt).getTime();if(Number.isFinite(K)&&(j.current=Math.max(j.current,K)),C.current.has(re.id))return;C.current.add(re.id),w(V=>V+1),N.current===0&&R_(re,T.current)&&(l(V=>V.some(le=>le.id===re.id)?V:[re,...V].slice(0,E)),i(V=>V+1))}catch{}}),z.onerror=()=>{z==null||z.close(),z=null,_||q.add(setTimeout(k,E_))})};return k(),()=>{_=!0,z==null||z.close();for(const W of q)clearTimeout(W);q.clear()}},[]);const A=async _=>{v(_);const z=await Se.get(`/api/admin/requests/${_}`);S(z)};return s.jsxs("div",{children:[s.jsx(wa,{title:"Requests",description:`${o} matching · live updates`}),s.jsxs(Ze,{children:[s.jsxs(Je,{children:[s.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[s.jsxs(In,{value:h.success,onValueChange:_=>{d(0),m({...h,success:_})},children:[s.jsx(Rn,{className:"w-36",children:s.jsx(Gn,{})}),s.jsxs(Nn,{children:[s.jsx(lt,{value:"all",children:"All"}),s.jsx(lt,{value:"true",children:"Success"}),s.jsx(lt,{value:"false",children:"Failed"})]})]}),s.jsxs(In,{value:h.protocol,onValueChange:_=>{d(0),m({...h,protocol:_})},children:[s.jsx(Rn,{className:"w-32",children:s.jsx(Gn,{})}),s.jsxs(Nn,{children:[s.jsx(lt,{value:"all",children:"Any protocol"}),s.jsx(lt,{value:"openai",children:"OpenAI"}),s.jsx(lt,{value:"anthropic",children:"Anthropic"})]})]}),s.jsxs(In,{value:h.streaming,onValueChange:_=>{d(0),m({...h,streaming:_})},children:[s.jsx(Rn,{className:"w-32",children:s.jsx(Gn,{})}),s.jsxs(Nn,{children:[s.jsx(lt,{value:"all",children:"Any"}),s.jsx(lt,{value:"true",children:"Streaming"}),s.jsx(lt,{value:"false",children:"Non-stream"})]})]}),s.jsx(Ne,{className:"max-w-xs",placeholder:"Model contains…",value:h.model,onChange:_=>{d(0),m({...h,model:_.target.value})}}),x>0&&s.jsxs(he,{size:"sm",variant:"secondary",onClick:()=>{w(0),M()},children:[x," new request",x>1?"s":""," — refresh"]})]}),s.jsx(We,{className:"mt-3 text-base",children:"Results"})]}),s.jsxs(et,{children:[s.jsxs(Kn,{children:[s.jsx(Xn,{children:s.jsxs(Ye,{children:[s.jsx(pe,{children:"Time"}),s.jsx(pe,{children:"Status"}),s.jsx(pe,{children:"Requested"}),s.jsx(pe,{children:"Final"}),s.jsx(pe,{children:"Tokens"}),s.jsx(pe,{children:"Latency"}),s.jsx(pe,{children:"Attempts"}),s.jsx(pe,{children:"Key"}),s.jsx(pe,{children:"IP"}),s.jsx(pe,{})]})}),s.jsxs(Fn,{children:[a.length===0&&s.jsx(Ye,{children:s.jsx(fe,{colSpan:10,className:"text-center text-muted-foreground",children:"No requests yet."})}),a.map(_=>s.jsxs(Ye,{className:"cursor-pointer",onClick:()=>A(_.id),children:[s.jsx(fe,{className:"text-xs",children:Th(_.createdAt)}),s.jsx(fe,{children:_.success?s.jsx(Qe,{variant:"success",children:_.httpStatus}):s.jsx(Qe,{variant:"destructive",children:_.httpStatus})}),s.jsx(fe,{className:"font-mono text-xs",children:_.requestedModel}),s.jsx(fe,{className:"font-mono text-xs text-muted-foreground",children:_.finalModelPublicId??"—"}),s.jsxs(fe,{className:"text-xs",children:[At(_.inputTokens+_.outputTokens)," ",_.cacheReadTokens?s.jsxs("span",{className:"text-amber-600",children:["(+",_.cacheReadTokens," cache)"]}):null]}),s.jsxs(fe,{className:"text-xs",children:[dr(_.totalLatencyMs),_.ttftMs?s.jsxs("span",{className:"text-muted-foreground",children:[" · ttft ",_.ttftMs,"ms"]}):null]}),s.jsxs(fe,{className:"text-xs",children:[_.attemptsCount,_.gatewayCacheHit?s.jsx(Qe,{variant:"secondary",className:"ml-1",children:"cache"}):null]}),s.jsx(fe,{className:"text-xs",children:_.apiKeyName??"—"}),s.jsx(fe,{className:"text-xs",children:_.clientIp}),s.jsx(fe,{className:"text-right",children:s.jsx(he,{size:"sm",variant:"ghost",children:"View"})})]},_.id))]})]}),s.jsxs("div",{className:"mt-3 flex items-center justify-between",children:[s.jsxs("span",{className:"text-xs text-muted-foreground",children:["Showing ",c+1,"–",Math.min(c+E,o)," of ",o]}),s.jsxs("div",{className:"flex gap-2",children:[s.jsx(he,{size:"sm",variant:"outline",disabled:c===0,onClick:()=>d(Math.max(0,c-E)),children:"Prev"}),s.jsx(he,{size:"sm",variant:"outline",disabled:c+E>=o,onClick:()=>d(c+E),children:"Next"})]})]})]})]}),s.jsx(qn,{open:!!g,onOpenChange:_=>{_||(v(null),S(null))},children:s.jsxs(jn,{className:"max-w-3xl",children:[s.jsx(Cn,{children:s.jsxs(En,{children:["Request ",eE(g,16)]})}),b?s.jsxs("div",{className:"space-y-3 text-sm",children:[s.jsxs("div",{className:"grid grid-cols-2 gap-2",children:[s.jsxs("div",{children:[s.jsx("div",{className:"text-muted-foreground text-xs",children:"Status"}),b.request.success?s.jsx(Qe,{variant:"success",children:b.request.httpStatus}):s.jsx(Qe,{variant:"destructive",children:b.request.httpStatus})]}),s.jsxs("div",{children:[s.jsx("div",{className:"text-muted-foreground text-xs",children:"Latency"}),dr(b.request.totalLatencyMs)]}),s.jsxs("div",{children:[s.jsx("div",{className:"text-muted-foreground text-xs",children:"Tokens"}),"in ",At(b.request.inputTokens)," · out ",At(b.request.outputTokens)," · cache ",At(b.request.cacheReadTokens)]}),s.jsxs("div",{children:[s.jsx("div",{className:"text-muted-foreground text-xs",children:"Attempts"}),b.request.attemptsCount]})]}),b.request.errorType&&s.jsxs("div",{className:"rounded border border-destructive/40 bg-destructive/10 p-2",children:[s.jsx("div",{className:"text-xs text-muted-foreground",children:"Error"}),s.jsxs("div",{className:"font-mono text-xs",children:[b.request.errorType,": ",b.request.errorMessage]})]}),b.request.requestPayload&&s.jsxs("div",{children:[s.jsx("div",{className:"text-xs text-muted-foreground",children:"Request content"}),s.jsx("pre",{className:"max-h-60 overflow-auto rounded bg-muted p-2 font-mono text-xs whitespace-pre-wrap",children:b.request.requestPayload})]}),b.request.responsePayload&&s.jsxs("div",{children:[s.jsx("div",{className:"text-xs text-muted-foreground",children:"Response content"}),s.jsx("pre",{className:"max-h-60 overflow-auto rounded bg-muted p-2 font-mono text-xs whitespace-pre-wrap",children:b.request.responsePayload})]}),b.attempts.length>0&&s.jsxs("div",{children:[s.jsx("div",{className:"text-xs text-muted-foreground",children:"Attempts"}),s.jsxs(Kn,{children:[s.jsx(Xn,{children:s.jsxs(Ye,{children:[s.jsx(pe,{children:"#"}),s.jsx(pe,{children:"Provider"}),s.jsx(pe,{children:"Model"}),s.jsx(pe,{children:"Status"}),s.jsx(pe,{children:"Latency"}),s.jsx(pe,{children:"Reason"})]})}),s.jsx(Fn,{children:b.attempts.map(_=>s.jsxs(Ye,{children:[s.jsx(fe,{children:_.attemptNumber}),s.jsx(fe,{children:_.providerName}),s.jsx(fe,{className:"font-mono text-xs",children:_.modelPublicId}),s.jsx(fe,{children:_.success?s.jsx(Qe,{variant:"success",children:String(_.statusCode??"OK")}):s.jsx(Qe,{variant:"destructive",children:String(_.statusCode??"err")})}),s.jsx(fe,{className:"text-xs",children:dr(_.latencyMs)}),s.jsx(fe,{className:"text-xs",children:_.failureReason??_.selectionReason})]},_.id))})]})]})]}):s.jsx("div",{className:"text-muted-foreground",children:"Loading…"})]})})]})}var T_=Object.defineProperty,Es=(a,l)=>T_(a,"name",{value:l,configurable:!0}),xm="Tabs",[M_,KD]=dn(xm,[Gc]),E1=Gc(),[A_,ym]=M_(xm),__=p.forwardRef(Es(function(l,o){const{__scopeTabs:i,value:c,onValueChange:d,defaultValue:h,orientation:m="horizontal",dir:g,activationMode:v="automatic",...b}=l,S=zo(g),[x,w]=Za({prop:c,onChange:d,defaultProp:h??"",caller:xm});return s.jsx(A_,{scope:i,baseId:ga(),value:x,onValueChange:w,orientation:m,dir:S,activationMode:v,children:s.jsx(Ue.div,{dir:S,"data-orientation":m,...b,ref:o})})},"Tabs")),D_="TabsList",O_=p.forwardRef(Es(function(l,o){const{__scopeTabs:i,loop:c=!0,...d}=l,h=ym(D_,i),m=E1(i);return s.jsx(f0,{asChild:!0,...m,orientation:h.orientation,dir:h.dir,loop:c,children:s.jsx(Ue.div,{role:"tablist","aria-orientation":h.orientation,...d,ref:o})})},"TabsList")),k_="TabsTrigger",z_=p.forwardRef(Es(function(l,o){const{__scopeTabs:i,value:c,disabled:d=!1,...h}=l,m=ym(k_,i),g=E1(i),v=bm(m.baseId,c),b=Sm(m.baseId,c),S=c===m.value;return s.jsx(h0,{asChild:!0,...g,focusable:!d,active:S,children:s.jsx(Ue.button,{type:"button",role:"tab","aria-selected":S,"aria-controls":b,"data-state":S?"active":"inactive","data-disabled":d?"":void 0,disabled:d,id:v,...h,ref:o,onMouseDown:we(l.onMouseDown,x=>{!d&&x.button===0&&x.ctrlKey===!1?m.onValueChange(c):x.preventDefault()}),onKeyDown:we(l.onKeyDown,x=>{d||x.target!==x.currentTarget||[" ","Enter"].includes(x.key)&&m.onValueChange(c)}),onFocus:we(l.onFocus,()=>{const x=m.activationMode!=="manual";!S&&!d&&x&&m.onValueChange(c)})})})},"TabsTrigger")),L_="TabsContent",U_=p.forwardRef(Es(function(l,o){const{__scopeTabs:i,value:c,forceMount:d,children:h,...m}=l,g=ym(L_,i),v=bm(g.baseId,c),b=Sm(g.baseId,c),S=c===g.value,x=p.useRef(S);return p.useEffect(()=>{const w=requestAnimationFrame(()=>x.current=!1);return()=>cancelAnimationFrame(w)},[]),s.jsx(nl,{present:d||S,children:({present:w})=>s.jsx(Ue.div,{"data-state":S?"active":"inactive","data-orientation":g.orientation,role:"tabpanel","aria-labelledby":v,hidden:!w,id:b,tabIndex:0,...m,ref:o,style:{...l.style,animationDuration:x.current?"0s":void 0},children:w&&h})})},"TabsContent"));function bm(a,l){return`${a}-trigger-${l}`}Es(bm,"makeTriggerId");function Sm(a,l){return`${a}-content-${l}`}Es(Sm,"makeContentId");var H_=__,R1=O_,N1=z_,T1=U_;const M1=H_,wm=p.forwardRef(({className:a,...l},o)=>s.jsx(R1,{ref:o,className:je("inline-flex h-9 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground",a),...l}));wm.displayName=R1.displayName;const Ol=p.forwardRef(({className:a,...l},o)=>s.jsx(N1,{ref:o,className:je("inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow",a),...l}));Ol.displayName=N1.displayName;const wo=p.forwardRef(({className:a,...l},o)=>s.jsx(T1,{ref:o,className:je("mt-2 ring-offset-background focus-visible:outline-none",a),...l}));wo.displayName=T1.displayName;const B_=3e3,P_=1600,q_=10,V_=3;function I_(a,l){return{...a,totalRequests:a.totalRequests+1,successfulRequests:a.successfulRequests+(l.success?1:0),failedRequests:a.failedRequests+(l.success?0:1),successRate:a.totalRequests+1?(a.successfulRequests+(l.success?1:0))/(a.totalRequests+1):0,inputTokens:a.inputTokens+l.inputTokens,outputTokens:a.outputTokens+l.outputTokens,totalTokens:a.totalTokens+l.inputTokens+l.outputTokens,cacheReadTokens:a.cacheReadTokens+l.cacheReadTokens,averageLatencyMs:(a.averageLatencyMs*a.totalRequests+l.totalLatencyMs)/(a.totalRequests+1)}}function G_(a){const[l,o]=p.useState(null),[i,c]=p.useState(null),[d,h]=p.useState([]),[m,g]=p.useState([]),[v,b]=p.useState([]),[S,x]=p.useState(!0),[w,E]=p.useState(null),j=p.useRef([]),C=p.useRef(null),T=p.useRef(new Set),N=p.useRef(Date.now()),M=p.useRef(0),A=p.useRef([]);return p.useEffect(()=>{let _=!1;return x(!0),E(null),T.current=new Set,N.current=Date.now(),Se.get(`/api/admin/stats?preset=${a}`).then(z=>{if(!_){o(z),c(z.summary),C.current=z.summary,h(z.recent),g(z.providers),j.current=z.providers;for(const q of z.recent)T.current.add(q.id);x(!1)}}).catch(z=>{_||(E(z.message),x(!1))}),()=>{_=!0}},[a]),p.useEffect(()=>{let _=!1,z=null;const q=new Set,k=()=>{_||(z=new EventSource(`/api/admin/requests/stream?since=${N.current}`),z.addEventListener("request",W=>{if(!_)try{const re=JSON.parse(W.data),K=new Date(re.createdAt).getTime();if(Number.isFinite(K)&&(N.current=Math.max(N.current,K)),T.current.has(re.id))return;if(T.current.add(re.id),C.current&&c(I_(C.current,re)),h(V=>V.some(le=>le.id===re.id)?V:[re,...V].slice(0,q_)),re.providerId){j.current=j.current.map(ce=>ce.id===re.providerId?{...ce,requests:ce.requests+1,errorRate:ce.requests+1?(ce.errorRate*ce.requests+(re.success?0:1))/(ce.requests+1):0}:ce),g(j.current);const V=`p${++M.current}`,le={id:V,providerId:re.providerId,success:re.success};A.current=[...A.current.slice(-(V_*4)),le],b(A.current);const se=setTimeout(()=>{A.current=A.current.filter(ce=>ce.id!==V),b(A.current)},P_);q.add(se)}}catch{}}),z.onerror=()=>{z==null||z.close(),z=null,_||q.add(setTimeout(k,B_))})};return k(),()=>{_=!0,z==null||z.close();for(const W of q)clearTimeout(W);q.clear()}},[]),p.useEffect(()=>{const _=setInterval(()=>{Se.get("/api/admin/providers").then(z=>{const q=new Map(z.providers.map(k=>[k.id,k]));j.current=j.current.map(k=>{const W=q.get(k.id);return W?{...k,health:W.health,enabled:W.enabled}:k}),g(j.current)}).catch(()=>{})},3e4);return()=>clearInterval(_)},[]),{snapshot:l,live:i??(l==null?void 0:l.summary)??Y_,recent:d,providers:m,pulses:v,loading:S,error:w}}const Y_={totalRequests:0,successfulRequests:0,failedRequests:0,successRate:0,inputTokens:0,outputTokens:0,totalTokens:0,cacheReadTokens:0,cacheWriteTokens:0,reasoningTokens:0,averageLatencyMs:0,p95LatencyMs:0,averageTtftMs:null,p95TtftMs:null,cacheHitRate:0,gatewayCacheHitRate:0,fallbackRate:0};function A1({data:a,className:l,strokeClass:o="stroke-primary",fillClass:i}){if(a.length===0)return s.jsx("svg",{className:je("h-6 w-20",l),viewBox:"0 0 80 24"});const h=Math.max(...a),m=Math.min(...a),g=h-m||1,b=a.map((S,x)=>{const w=x/(a.length-1)*78+1,E=22-(S-m)/g*20;return`${w.toFixed(1)},${E.toFixed(1)}`}).join(" ");return s.jsxs("svg",{className:je("h-6 w-20",l),viewBox:"0 0 80 24",preserveAspectRatio:"none",children:[i&&s.jsx("polygon",{points:`1,23 ${b} 79,23`,className:i}),s.jsx("polyline",{points:b,fill:"none",strokeWidth:1.5,strokeLinecap:"round",strokeLinejoin:"round",className:o})]})}function $_(a,l,o){const i=performance.now();let c=0;const d=h=>{const m=Math.min((h-i)/l,1),g=Math.round(a*m);g!==c&&(c=g,o(g)),m<1&&requestAnimationFrame(d)};requestAnimationFrame(d)}function K_({delta:a,inverse:l}){if(Math.abs(a)<.005)return null;const o=a>0,i=l?!o:o,c=`${(Math.abs(a)*100).toFixed(1)}%`;return s.jsxs("span",{className:je("ml-1.5 inline-flex items-center rounded-full px-1.5 py-0.5 text-[10px] font-semibold leading-none",i?"bg-emerald-100 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300":"bg-red-100 text-red-700 dark:bg-red-900/40 dark:text-red-300"),children:[s.jsx("span",{className:"mr-0.5",children:o?"▲":"▼"}),c]})}function Dl({icon:a,label:l,value:o,format:i="number",delta:c,deltaInverse:d,sparkData:h,sparkStroke:m}){const[g,v]=p.useState(0),b=p.useRef(0);p.useEffect(()=>{const x=b.current,w=o;b.current=o,x!==w&&$_(Math.abs(w-x),600,E=>v(x+(w>x?E:-E)))},[o]);const S=i==="percent"?Oc(g):i==="latency"?dr(g):At(Math.round(g));return s.jsxs(Ze,{children:[s.jsxs(Je,{className:"flex flex-row items-center justify-between pb-1",children:[s.jsxs(We,{className:"flex items-center gap-2 text-sm font-medium text-muted-foreground",children:[s.jsx(a,{className:"h-4 w-4"}),l]}),c!==void 0&&s.jsx(K_,{delta:c,inverse:d})]}),s.jsxs(et,{className:"flex items-end justify-between",children:[s.jsx("span",{className:"text-2xl font-semibold tabular-nums",children:S}),h&&h.length>1&&s.jsx(A1,{data:h,strokeClass:m??"stroke-primary",fillClass:"fill-primary/10"})]})]})}const _1=1e3,py=380,uc=60,ir=_1/2,cr=720,Hf=62,X_=260;function F_(a){return a==="healthy"?"fill-emerald-400":a==="degraded"?"fill-amber-400":"fill-red-400"}function Bf(a,l,o,i){const c=a+(o-a)*.45,d=a+(o-a)*.55;return`M${a},${l} C${c},${l} ${d},${i} ${o},${i}`}function Q_({liveRequests:a,successRate:l,providers:o,pulses:i}){const c=py/2,d=c,h=Math.max(1,o.reduce((m,g)=>m+g.requests,0));return s.jsxs(Ze,{children:[s.jsx(Je,{className:"pb-2",children:s.jsxs("div",{className:"flex items-center justify-between",children:[s.jsx(We,{className:"text-base",children:"Real-time Request Routing"}),s.jsxs("div",{className:"flex items-center gap-3 text-xs text-muted-foreground",children:[s.jsxs("span",{className:"flex items-center gap-1",children:[s.jsx("span",{className:"inline-block h-2 w-2 rounded-full bg-emerald-400"})," healthy"]}),s.jsxs("span",{className:"flex items-center gap-1",children:[s.jsx("span",{className:"inline-block h-2 w-2 rounded-full bg-amber-400"})," degraded"]}),s.jsxs("span",{className:"flex items-center gap-1",children:[s.jsx("span",{className:"inline-block h-2 w-2 rounded-full bg-red-400"})," down"]})]})]})}),s.jsx(et,{className:"pt-0",children:s.jsx("div",{className:"relative w-full",children:s.jsxs("svg",{viewBox:`0 0 ${_1} ${py}`,className:"w-full h-auto",preserveAspectRatio:"xMidYMid meet",children:[s.jsx("defs",{children:s.jsxs("filter",{id:"glow",x:"-50%",y:"-50%",width:"200%",height:"200%",children:[s.jsx("feGaussianBlur",{stdDeviation:"3",result:"blur"}),s.jsxs("feMerge",{children:[s.jsx("feMergeNode",{in:"blur"}),s.jsx("feMergeNode",{in:"SourceGraphic"})]})]})}),o.map(m=>{const v=60+o.indexOf(m)*Hf,b=m.requests/h,S=Math.max(1.5,Math.min(6,2+b*8));return s.jsx("path",{d:Bf(ir,c,cr-20,v),fill:"none",stroke:"hsl(var(--border))",strokeWidth:S,strokeLinecap:"round",opacity:.6},m.id)}),s.jsx("path",{d:Bf(uc+30,d,ir-30,c),fill:"none",stroke:"hsl(var(--border))",strokeWidth:3,strokeLinecap:"round",strokeDasharray:"6 3",opacity:.5}),i.map(m=>{const g=o.findIndex(x=>x.id===m.providerId);if(g===-1)return null;const v=60+g*Hf,b=Bf(ir,c,cr-20,v),S=m.success?"var(--primary)":"#f87171";return s.jsxs("g",{filter:"url(#glow)",children:[s.jsx("circle",{r:5,fill:S,opacity:.9,children:s.jsx("animateMotion",{dur:"1.4s",fill:"freeze",path:b})}),s.jsx("circle",{r:9,fill:S,opacity:.25,children:s.jsx("animateMotion",{dur:"1.4s",fill:"freeze",path:b})})]},m.id)}),s.jsx("circle",{cx:uc,cy:d,r:28,fill:"hsl(var(--card))",stroke:"hsl(var(--border))",strokeWidth:1.5}),s.jsx("text",{x:uc,y:d-4,textAnchor:"middle",className:"fill-foreground",fontSize:12,fontWeight:600,children:gy(a)}),s.jsx("text",{x:uc,y:d+10,textAnchor:"middle",className:"fill-muted-foreground",fontSize:9,children:"requests"}),s.jsx("circle",{cx:ir,cy:c,r:36,fill:"hsl(var(--card))",stroke:"var(--primary)",strokeWidth:2}),s.jsx("image",{x:ir-12,y:c-16,width:24,height:24,href:"/logo.png"}),s.jsx("text",{x:ir,y:c+28,textAnchor:"middle",className:"fill-muted-foreground",fontSize:9,children:"AI Gateway"}),s.jsxs("text",{x:ir,y:c+38,textAnchor:"middle",className:"fill-emerald-500",fontSize:10,fontWeight:600,children:[(l*100).toFixed(1),"%"]}),o.map((m,g)=>{const v=60+g*Hf,b=m.requests/h,S=!m.enabled||m.requests===0;return s.jsxs("g",{opacity:S?.4:1,children:[s.jsx("rect",{x:cr-20,y:v-14,width:X_,height:50,rx:8,fill:"hsl(var(--card))",stroke:"hsl(var(--border))",strokeWidth:1}),s.jsx("circle",{cx:cr-6,cy:v+10,r:4,className:F_(m.health)}),s.jsx("text",{x:cr+6,y:v-2,className:"fill-foreground",fontSize:12,fontWeight:500,children:m.name}),s.jsxs("text",{x:cr+6,y:v+12,className:"fill-muted-foreground",fontSize:10,children:[m.modelCount," model",m.modelCount!==1?"s":""," · ",gy(m.requests)," req"]}),s.jsxs("text",{x:cr+6,y:v+25,className:"fill-muted-foreground",fontSize:10,children:[(b*100).toFixed(1),"% traffic · ",m.avgLatencyMs<1e3?`${Math.round(m.avgLatencyMs)}ms`:`${(m.avgLatencyMs/1e3).toFixed(1)}s`," avg",m.errorRate>0&&s.jsxs("tspan",{className:"fill-red-500",children:[" · ",(m.errorRate*100).toFixed(0),"% err"]})]})]},m.id)})]})})})]})}function gy(a){return a>=1e6?`${(a/1e6).toFixed(1)}M`:a>=1e3?`${(a/1e3).toFixed(1)}K`:String(a)}function Z_({rows:a}){return s.jsxs(Ze,{children:[s.jsx(Je,{className:"pb-2",children:s.jsx(We,{className:"text-base",children:"Recent Requests"})}),s.jsx(et,{children:a.length===0?s.jsx("div",{className:"py-6 text-center text-sm text-muted-foreground",children:"No requests yet — traffic will appear here live."}):s.jsxs(Kn,{children:[s.jsx(Xn,{children:s.jsxs(Ye,{children:[s.jsx(pe,{children:"Model"}),s.jsx(pe,{children:"Provider"}),s.jsx(pe,{children:"Tokens"}),s.jsx(pe,{children:"Status"}),s.jsx(pe,{children:"Time"})]})}),s.jsx(Fn,{children:a.map(l=>s.jsxs(Ye,{children:[s.jsx(fe,{className:"font-mono text-xs",children:l.requestedModel}),s.jsx(fe,{className:"text-xs text-muted-foreground",children:l.providerName??"—"}),s.jsxs(fe,{className:"text-xs",children:[s.jsxs("span",{className:"font-mono",children:["in ",At(l.inputTokens)," · out ",At(l.outputTokens)]}),l.cacheReadTokens>0&&s.jsxs("span",{className:"ml-1 text-amber-600",children:["(+",At(l.cacheReadTokens)," cache)"]})]}),s.jsx(fe,{children:s.jsxs("span",{className:"inline-flex items-center gap-1.5",children:[s.jsx("span",{className:l.success?"h-2 w-2 rounded-full bg-emerald-400":"h-2 w-2 rounded-full bg-red-400"}),s.jsx("span",{className:"text-xs",children:l.success?l.httpStatus:`${l.httpStatus} err`})]})}),s.jsx(fe,{className:"text-xs text-muted-foreground",children:tE(l.createdAt)})]},l.id))})]})})]})}const fh=34,vy=2*Math.PI*fh;function J_(a){return a>=.95?{stroke:"#4ade80",text:"text-emerald-500"}:a>=.8?{stroke:"#fbbf24",text:"text-amber-500"}:{stroke:"#f87171",text:"text-red-500"}}function W_({successRate:a,averageLatencyMs:l,latencySpark:o}){const{stroke:i,text:c}=J_(a),d=Math.min(1,Math.max(0,a)),h=vy*(1-d);return s.jsxs("div",{className:"grid gap-4 md:grid-cols-2",children:[s.jsxs(Ze,{children:[s.jsx(Je,{className:"pb-2",children:s.jsx(We,{className:"text-base",children:"Success Rate"})}),s.jsxs(et,{className:"flex items-center gap-4",children:[s.jsxs("div",{className:"relative h-20 w-20",children:[s.jsxs("svg",{viewBox:"0 0 80 80",className:"h-20 w-20 -rotate-90",children:[s.jsx("circle",{cx:"40",cy:"40",r:fh,fill:"none",stroke:"hsl(var(--border))",strokeWidth:7}),s.jsx("circle",{cx:"40",cy:"40",r:fh,fill:"none",stroke:i,strokeWidth:7,strokeLinecap:"round",strokeDasharray:vy,strokeDashoffset:h,style:{transition:"stroke-dashoffset 0.6s ease, stroke 0.4s ease"}})]}),s.jsx("span",{className:`absolute inset-0 flex items-center justify-center text-sm font-semibold tabular-nums ${c}`,children:Oc(a)})]}),s.jsx("p",{className:"text-sm text-muted-foreground",children:"Share of requests that completed successfully over the selected window. Updated in real time."})]})]}),s.jsxs(Ze,{children:[s.jsx(Je,{className:"pb-2",children:s.jsx(We,{className:"text-base",children:"Average Latency"})}),s.jsxs(et,{className:"flex items-end justify-between",children:[s.jsxs("div",{children:[s.jsx("div",{className:"text-2xl font-semibold tabular-nums",children:dr(l)}),s.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"Live average across the selected window"})]}),s.jsx(A1,{data:o,strokeClass:"stroke-amber-500",fillClass:"fill-amber-500/10",className:"h-10 w-28"})]})]})]})}function eD(){const[a,l]=p.useState("7d"),{snapshot:o,live:i,recent:c,providers:d,pulses:h,loading:m,error:g}=G_(a);if(m)return s.jsx("div",{className:"text-muted-foreground",children:"Loading…"});if(g||!o)return s.jsxs("div",{className:"text-destructive",children:["Failed to load statistics: ",g??"unknown error"]});const v=i,b=o.previous,S=o.series;function x(j,C){return C>0?(j-C)/C:void 0}const w=S.map(j=>j.requests),E=S.map(j=>j.avgLatency);return s.jsxs("div",{children:[s.jsx(wa,{title:"Statistics",description:"Real-time monitoring dashboard",actions:s.jsx(M1,{value:a,onValueChange:j=>void l(j),children:s.jsxs(wm,{children:[s.jsx(Ol,{value:"today",children:"Today"}),s.jsx(Ol,{value:"7d",children:"7 days"}),s.jsx(Ol,{value:"30d",children:"30 days"})]})})}),s.jsxs("div",{className:"grid gap-4 md:grid-cols-2 lg:grid-cols-4",children:[s.jsx(Dl,{icon:Yy,label:"Requests",value:v.totalRequests,delta:x(v.totalRequests,b.totalRequests),sparkData:w}),s.jsx(Dl,{icon:Ac,label:"Success rate",format:"percent",value:v.successRate,delta:x(v.successRate,b.successRate),sparkData:w,sparkStroke:"stroke-emerald-500"}),s.jsx(Dl,{icon:r2,label:"Total tokens",value:v.totalTokens,delta:x(v.totalTokens,b.totalTokens),sparkData:S.map(j=>j.inputTokens+j.outputTokens)}),s.jsx(Dl,{icon:s2,label:"Cache hit rate",format:"percent",value:v.cacheHitRate,delta:x(v.cacheHitRate,b.cacheHitRate),sparkData:S.map(j=>j.cacheRead)}),s.jsx(Dl,{icon:n2,label:"Avg latency",format:"latency",value:v.averageLatencyMs,delta:x(v.averageLatencyMs,b.averageLatencyMs),deltaInverse:!0,sparkData:E,sparkStroke:"stroke-amber-500"}),s.jsx(Dl,{icon:Xy,label:"p95 latency",format:"latency",value:v.p95LatencyMs}),s.jsx(Dl,{icon:y2,label:"Avg TTFT",format:"latency",value:v.averageTtftMs??0}),s.jsx(Dl,{icon:m2,label:"Fallback rate",format:"percent",value:v.fallbackRate,delta:x(v.fallbackRate,b.fallbackRate),deltaInverse:!0})]}),s.jsx("div",{className:"mt-6",children:s.jsx(Q_,{liveRequests:v.totalRequests,successRate:v.successRate,providers:d,pulses:h})}),s.jsxs("div",{className:"mt-6 grid gap-4 lg:grid-cols-3",children:[s.jsx("div",{className:"lg:col-span-2",children:s.jsx(Z_,{rows:c})}),s.jsxs("div",{className:"space-y-4",children:[s.jsxs(Ze,{children:[s.jsx(Je,{className:"pb-2",children:s.jsx(We,{className:"text-base",children:"Top Models"})}),s.jsx(et,{children:s.jsxs(Kn,{children:[s.jsx(Xn,{children:s.jsxs(Ye,{children:[s.jsx(pe,{children:"Model"}),s.jsx(pe,{children:"Req"}),s.jsx(pe,{children:"Errors"}),s.jsx(pe,{children:"Tokens"})]})}),s.jsxs(Fn,{children:[o.topModels.length===0&&s.jsx(Ye,{children:s.jsx(fe,{colSpan:4,className:"text-muted-foreground text-center",children:"No data"})}),o.topModels.map(j=>s.jsxs(Ye,{children:[s.jsx(fe,{className:"font-mono text-xs",children:j.publicId}),s.jsx(fe,{className:"text-xs",children:At(j.requests)}),s.jsx(fe,{className:"text-xs",children:s.jsx("span",{className:j.errorRate>.1?"text-destructive":"text-muted-foreground",children:Oc(j.errorRate)})}),s.jsx(fe,{className:"text-xs",children:At(j.totalTokens)})]},j.publicId))]})]})})]}),s.jsxs(Ze,{children:[s.jsx(Je,{className:"pb-2",children:s.jsx(We,{className:"text-base",children:"Top API Keys"})}),s.jsx(et,{children:s.jsxs(Kn,{children:[s.jsx(Xn,{children:s.jsxs(Ye,{children:[s.jsx(pe,{children:"Key"}),s.jsx(pe,{children:"Requests"}),s.jsx(pe,{children:"Tokens"})]})}),s.jsxs(Fn,{children:[o.topApiKeys.length===0&&s.jsx(Ye,{children:s.jsx(fe,{colSpan:3,className:"text-muted-foreground text-center",children:"No data"})}),o.topApiKeys.map((j,C)=>s.jsxs(Ye,{children:[s.jsx(fe,{className:"text-xs",children:j.name}),s.jsx(fe,{className:"text-xs",children:At(j.requests)}),s.jsx(fe,{className:"text-xs",children:At(j.totalTokens)})]},C))]})]})})]})]})]}),s.jsx("div",{className:"mt-6",children:s.jsx(W_,{successRate:v.successRate,averageLatencyMs:v.averageLatencyMs,latencySpark:E})})]})}function tD(){const[a,l]=p.useState([]),[o,i]=p.useState(0);return p.useEffect(()=>{Se.get("/api/admin/audit?limit=200").then(c=>{l(c.rows),i(c.total)})},[]),s.jsxs("div",{children:[s.jsx(wa,{title:"Audit Logs",description:`${o} entries · immutable`}),s.jsxs(Ze,{children:[s.jsx(Je,{children:s.jsx(We,{className:"text-base",children:"All entries"})}),s.jsx(et,{children:s.jsxs(Kn,{children:[s.jsx(Xn,{children:s.jsxs(Ye,{children:[s.jsx(pe,{children:"Time"}),s.jsx(pe,{children:"Action"}),s.jsx(pe,{children:"Status"}),s.jsx(pe,{children:"Target"}),s.jsx(pe,{children:"IP"}),s.jsx(pe,{children:"Actor"})]})}),s.jsxs(Fn,{children:[a.length===0&&s.jsx(Ye,{children:s.jsx(fe,{colSpan:6,className:"text-center text-muted-foreground",children:"No audit events yet."})}),a.map(c=>s.jsxs(Ye,{children:[s.jsx(fe,{className:"text-xs",children:Th(c.createdAt)}),s.jsx(fe,{className:"font-mono text-xs",children:c.action}),s.jsx(fe,{children:c.success?s.jsx(Qe,{variant:"success",children:"ok"}):s.jsx(Qe,{variant:"destructive",children:"fail"})}),s.jsx(fe,{className:"text-xs",children:c.targetName??c.targetId??"—"}),s.jsx(fe,{className:"text-xs",children:c.ip}),s.jsx(fe,{className:"text-xs",children:c.actor})]},c.id))]})]})})]})]})}const hh={enabled:!0,sound:!0};let To=hh,mh=!1,dc=null;const ph=new Set;function D1(){for(const a of ph)a()}function O1(a=!1){return mh&&!a?Promise.resolve():(!a&&dc||(dc=(async()=>{try{const l=await Se.get("/api/admin/settings");To={enabled:l.settings.notificationsEnabled??hh.enabled,sound:l.settings.notificationSoundEnabled??hh.sound},mh=!0,D1()}catch{}})()),dc)}async function xy(a){const l={};a.enabled!==void 0&&(l.notificationsEnabled=a.enabled),a.sound!==void 0&&(l.notificationSoundEnabled=a.sound),await Se.patch("/api/admin/settings",l),To={...To,...a},mh=!0,D1()}function nD(a){return ph.add(a),()=>ph.delete(a)}function k1(){return p.useSyncExternalStore(nD,()=>To,()=>To)}function aD(){const[a]=UC(),[l,o]=p.useState(null),[i,c]=p.useState(null),[d,h]=p.useState({current:"",next:""}),[m,g]=p.useState(null),[v,b]=p.useState(!1),[S,x]=p.useState("idle"),[w,E]=p.useState(null),j=async(Z=!1)=>{x("checking"),E(null);try{const oe=await Se.get(`/api/admin/update/check${Z?"?force=1":""}`);g(oe),x("idle")}catch(oe){E(oe.message),x("error")}},C=async()=>{b(!0),x("installing"),E(null);try{const Z=await Se.post("/api/admin/update/run");x("restarting"),xe.success(Z.message||"Update started — the gateway will restart shortly.");const oe=setInterval(()=>{fetch("/health").then(ie=>{ie.ok&&(clearInterval(oe),window.location.reload())}).catch(()=>{})},3e3);setTimeout(()=>clearInterval(oe),12e4)}catch(Z){xe.error(Z.message),E(Z.message),x("error")}finally{b(!1)}},[T,N]=p.useState("disabled"),[M,A]=p.useState(""),[_,z]=p.useState(""),[q,k]=p.useState(""),[W,re]=p.useState([]),[K,V]=p.useState(""),[le,se]=p.useState(""),[ce,U]=p.useState(!1),[$,ne]=p.useState(null),H=async()=>{const Z=await Se.get("/api/admin/settings");o(Z.settings);const oe=await Se.get("/api/admin/settings/system");c(oe);try{const ie=await Se.get("/api/admin/me");N(ie.totpEnabled?"enabled":"disabled")}catch{}};if(p.useEffect(()=>{O1(!0)},[]),p.useEffect(()=>{H(),j()},[]),!l)return s.jsx("div",{className:"text-muted-foreground",children:"Loading…"});const F=async Z=>{try{await Se.patch("/api/admin/settings",Z),xe.success("Saved"),H()}catch(oe){xe.error(oe.message)}},D=async()=>{try{const Z=await Se.post("/api/admin/account/totp/begin");A(Z.secret),z(Z.qr),N("setup"),xe.info("Scan the QR code with your authenticator app")}catch(Z){xe.error(Z.message)}},P=async()=>{if(!q||q.length!==6){xe.error("Enter a 6-digit code");return}try{const Z=await Se.post("/api/admin/account/totp/verify",{code:q});re(Z.recoveryCodes),N("showingRecovery"),xe.success("TOTP enabled successfully")}catch(Z){xe.error(Z.message)}},Q=async()=>{if(!K){xe.error("Enter your password");return}if(!le){xe.error("Enter a TOTP code or recovery code");return}try{await Se.post("/api/admin/account/totp/disable",{password:K,totp:le}),N("disabled"),V(""),se(""),xe.success("TOTP disabled"),H()}catch(Z){xe.error(Z.message)}},ae=async()=>{U(!0);try{const Z=await Se.post("/api/admin/account/totp/recovery/regenerate",{password:K,totp:le});re(Z.recoveryCodes),N("showingRecovery"),xe.success("Recovery codes regenerated")}catch(Z){xe.error(Z.message)}U(!1)},de=a.get("tab")||"logging";return s.jsxs("div",{children:[s.jsx(wa,{title:"Settings",description:"Logging, security, backup, and system info"}),s.jsxs(M1,{defaultValue:de,children:[s.jsxs(wm,{children:[s.jsx(Ol,{value:"logging",children:"Logging"}),s.jsx(Ol,{value:"security",children:"Security"}),s.jsx(Ol,{value:"backup",children:"Backup"}),s.jsx(Ol,{value:"system",children:"System"})]}),s.jsx(wo,{value:"logging",children:s.jsxs(Ze,{children:[s.jsx(Je,{children:s.jsx(We,{className:"text-base",children:"Logging policy"})}),s.jsxs(et,{className:"space-y-3",children:[s.jsxs("div",{className:"space-y-1",children:[s.jsx(ye,{children:"Request-content logging"}),s.jsxs(In,{value:l.contentLogMode,onValueChange:Z=>F({contentLogMode:Z}),children:[s.jsx(Rn,{children:s.jsx(Gn,{})}),s.jsxs(Nn,{children:[s.jsx(lt,{value:"off",children:"Off"}),s.jsx(lt,{value:"metadata",children:"Metadata only (default)"}),s.jsx(lt,{value:"prompt",children:"Prompt (sanitized)"}),s.jsx(lt,{value:"prompt_and_response",children:"Prompt + response (sanitized)"})]})]})]}),s.jsxs("div",{className:"space-y-1",children:[s.jsx(ye,{children:"Retention (days)"}),s.jsx(Ne,{type:"number",min:1,max:3650,value:l.retentionDays,onChange:Z=>F({retentionDays:Number(Z.target.value)})})]}),s.jsxs("div",{className:"space-y-1",children:[s.jsx(ye,{children:"Database size limit (MB)"}),s.jsx(Ne,{type:"number",min:64,value:l.dbSizeLimitMb,onChange:Z=>F({dbSizeLimitMb:Number(Z.target.value)})})]}),s.jsx("div",{className:"flex items-center gap-2 pt-2",children:s.jsx(he,{onClick:async()=>{const Z=await Se.post("/api/admin/settings/cleanup");xe.success(`Deleted ${Z.deletedRequests} old requests`)},children:"Run cleanup now"})})]})]})}),s.jsx(wo,{value:"security",children:s.jsxs(Ze,{children:[s.jsxs(Je,{children:[s.jsx(We,{className:"text-base",children:"Security"}),s.jsx(wn,{children:"Change password, 2FA, and trusted proxy configuration"})]}),s.jsxs(et,{className:"space-y-4",children:[s.jsxs("div",{className:"space-y-2",children:[s.jsx(ye,{children:"Trusted proxy hops"}),s.jsx(Ne,{type:"number",min:0,max:8,value:l.trustProxyHops,onChange:Z=>F({trustProxyHops:Number(Z.target.value)})}),s.jsx("p",{className:"text-xs text-muted-foreground",children:"0 = never trust X-Forwarded-For (direct exposure). 1+ only when behind a single trusted reverse proxy."})]}),s.jsxs("div",{className:"space-y-2 border-t pt-4",children:[s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsx(ye,{className:"text-base",children:"TOTP 2FA"}),T==="enabled"?s.jsx("span",{className:"rounded bg-green-100 px-2 py-0.5 text-xs font-medium text-green-800 dark:bg-green-900 dark:text-green-200",children:"Enabled"}):null,T==="disabled"?s.jsx("span",{className:"rounded bg-muted px-2 py-0.5 text-xs font-medium text-muted-foreground",children:"Disabled"}):null]}),T==="disabled"&&s.jsx(he,{variant:"outline",onClick:D,children:"Enable TOTP"}),T==="setup"&&s.jsxs("div",{className:"space-y-3 rounded border p-3",children:[s.jsx("p",{className:"text-sm text-muted-foreground",children:"Scan this QR code with your authenticator app, or enter the secret manually."}),_&&s.jsx("img",{src:_,alt:"TOTP QR code",className:"h-40 w-40"}),s.jsxs("div",{className:"text-xs font-mono text-muted-foreground",children:["Secret: ",M]}),s.jsxs("div",{className:"flex items-end gap-2",children:[s.jsxs("div",{className:"flex-1",children:[s.jsx(ye,{children:"Verify code"}),s.jsx(Ne,{value:q,onChange:Z=>k(Z.target.value),placeholder:"123456",maxLength:6})]}),s.jsx(he,{disabled:q.length<6,onClick:P,children:"Verify & enable"})]})]}),T==="showingRecovery"&&s.jsxs("div",{className:"space-y-3 rounded border border-amber-500/40 bg-amber-50 p-3 dark:bg-amber-950/20",children:[s.jsx("p",{className:"text-sm font-medium",children:"Recovery codes — save these now!"}),s.jsx("p",{className:"text-xs text-muted-foreground",children:"Each code can be used once to log in without your TOTP device. They will not be shown again."}),s.jsx("div",{className:"space-y-1",children:W.map((Z,oe)=>s.jsx("div",{className:"font-mono text-xs",children:Z},oe))}),s.jsx(he,{onClick:()=>{N("enabled"),xe.success("Recovery codes saved")},children:"I have saved them"})]}),T==="enabled"&&s.jsxs("div",{className:"space-y-3 rounded border p-3",children:[s.jsxs("div",{className:"grid gap-2 sm:grid-cols-2",children:[s.jsxs("div",{children:[s.jsx(ye,{children:"Password"}),s.jsx(Ne,{type:"password",value:K,onChange:Z=>V(Z.target.value),placeholder:"Current password"})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"TOTP code"}),s.jsx(Ne,{value:le,onChange:Z=>se(Z.target.value),placeholder:"123456",maxLength:6})]})]}),s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsx(he,{variant:"outline",size:"sm",disabled:ce||!K||le.length<6,onClick:ae,children:"Regenerate recovery codes"}),s.jsx(he,{variant:"destructive",size:"sm",disabled:!K||le.length<6,onClick:Q,children:"Disable TOTP"})]})]})]}),s.jsxs("div",{className:"space-y-2 border-t pt-4",children:[s.jsx(ye,{children:"Change password"}),s.jsx(Ne,{type:"password",placeholder:"Current password",value:d.current,onChange:Z=>h({...d,current:Z.target.value})}),s.jsx(Ne,{type:"password",placeholder:"New password (12+ chars)",value:d.next,onChange:Z=>h({...d,next:Z.target.value})}),s.jsx(he,{disabled:!d.current||d.next.length<12,onClick:async()=>{try{await Se.post("/api/admin/account/password",{currentPassword:d.current,newPassword:d.next}),xe.success("Password changed"),h({current:"",next:""})}catch(Z){xe.error(Z.message)}},children:"Change password"})]})]})]})}),s.jsx(wo,{value:"backup",children:s.jsxs(Ze,{children:[s.jsxs(Je,{children:[s.jsx(We,{className:"text-base",children:"Backup & restore"}),s.jsx(wn,{children:"Download a snapshot or restore from a previous backup"})]}),s.jsxs(et,{className:"space-y-3",children:[s.jsx(he,{onClick:async()=>{try{const Z=await fetch("/api/admin/backup/create",{method:"POST",credentials:"include"});if(!Z.ok)throw new Error("Backup failed");const oe=await Z.blob(),ie=URL.createObjectURL(oe),me=document.createElement("a");me.href=ie,me.download="latedev-backup.json",me.click(),URL.revokeObjectURL(ie),xe.success("Backup downloaded")}catch(Z){xe.error(Z.message)}},children:"Download backup"}),s.jsxs(r1,{open:$!==null,onOpenChange:Z=>{Z||ne(null)},children:[s.jsx(gA,{asChild:!0,children:s.jsxs("div",{children:[s.jsx(ye,{children:"Restore from backup file"}),s.jsx(Ne,{type:"file",accept:".json,application/json","data-testid":"restore-file",onChange:Z=>{var ie;const oe=(ie=Z.target.files)==null?void 0:ie[0];ne(oe??null)}})]})}),s.jsxs(nm,{children:[s.jsxs(o1,{children:[s.jsx(am,{children:"Restore backup?"}),s.jsxs(lm,{children:["Restoring will replace the entire current database with the selected backup (",($==null?void 0:$.name)??"file","). This cannot be undone. A snapshot of the current database is kept for rollback only if validation fails."]})]}),s.jsxs(i1,{children:[s.jsx(sm,{children:"Cancel"}),s.jsx(rm,{onClick:async()=>{var oe,ie;const Z=$;if(Z)try{const me=await fetch("/api/admin/backup/restore",{method:"POST",body:Z,credentials:"include",headers:{"content-type":"application/json"}});if(!me.ok)throw new Error(((ie=(oe=await me.json())==null?void 0:oe.error)==null?void 0:ie.message)??"Restore failed");xe.success("Restored. Please restart the gateway."),ne(null)}catch(me){xe.error(me.message)}},children:"Restore"})]})]})]})]})]})}),s.jsxs(wo,{value:"system",children:[s.jsxs(Ze,{children:[s.jsx(Je,{children:s.jsx(We,{className:"text-base",children:"System"})}),s.jsxs(et,{className:"space-y-2 text-sm",children:[s.jsxs("div",{children:[s.jsx("span",{className:"text-muted-foreground",children:"App version:"})," ",i==null?void 0:i.appVersion]}),s.jsxs("div",{children:[s.jsx("span",{className:"text-muted-foreground",children:"Data directory:"})," ",s.jsx("span",{className:"font-mono",children:i==null?void 0:i.dataDir})]}),s.jsxs("div",{children:[s.jsx("span",{className:"text-muted-foreground",children:"Encryption:"})," ",i!=null&&i.masterKeyConfigured?"Configured":"Not configured"," (v",i==null?void 0:i.masterKeyVersion,")"]}),s.jsxs("div",{children:[s.jsx("span",{className:"text-muted-foreground",children:"Environment:"})," ",i==null?void 0:i.environment]}),s.jsxs("div",{className:"flex items-center gap-2 pt-2",children:[s.jsx(ba,{checked:l.gatewayCacheEnabled,onCheckedChange:Z=>F({gatewayCacheEnabled:Z})}),s.jsx(ye,{children:"Gateway response cache (disabled by default)"})]}),s.jsxs("div",{className:"grid grid-cols-2 gap-2",children:[s.jsxs("div",{children:[s.jsx(ye,{children:"Cache TTL (s)"}),s.jsx(Ne,{type:"number",min:1,value:l.gatewayCacheDefaultTtlSeconds,onChange:Z=>F({gatewayCacheDefaultTtlSeconds:Number(Z.target.value)})})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"Cache max size (MB)"}),s.jsx(Ne,{type:"number",min:1,value:l.gatewayCacheMaxSizeMb,onChange:Z=>F({gatewayCacheMaxSizeMb:Number(Z.target.value)})})]})]}),s.jsx(he,{variant:"outline",onClick:async()=>{const Z=await Se.post("/api/admin/settings/cache/clear");xe.success(`Cleared ${Z.deleted} entries`)},children:"Clear gateway cache"})]})]}),s.jsx(lD,{}),s.jsxs(Ze,{className:"mt-4",children:[s.jsxs(Je,{children:[s.jsx(We,{className:"text-base",children:"Updates"}),s.jsx(wn,{children:"Automatic updates from the npm registry"})]}),s.jsxs(et,{className:"space-y-3 text-sm",children:[S==="checking"&&!m&&s.jsxs("div",{className:"flex items-center gap-2 text-muted-foreground",children:[s.jsx(jo,{className:"h-4 w-4 animate-spin"})," Checking for updates…"]}),m&&s.jsxs(s.Fragment,{children:[s.jsxs("div",{className:"flex flex-wrap items-center gap-4",children:[s.jsxs("div",{children:[s.jsx("div",{className:"text-xs text-muted-foreground",children:"Current version"}),s.jsxs("div",{className:"font-mono",children:["v",m.currentVersion]})]}),s.jsx("span",{className:"text-muted-foreground",children:"→"}),s.jsxs("div",{children:[s.jsx("div",{className:"text-xs text-muted-foreground",children:"Latest version"}),s.jsx("div",{className:"font-mono",children:m.latestVersion?`v${m.latestVersion}`:"—"})]}),m.status.docker?s.jsx(Qe,{variant:"secondary",children:m.status.watchtower?"Docker + Watchtower":"Docker"}):m.latestVersion===null?s.jsx(Qe,{variant:"secondary",children:"Registry unreachable"}):m.hasUpdate?s.jsx(Qe,{variant:"success",children:"Update available"}):s.jsxs(Qe,{variant:"outline",children:[s.jsx(Ac,{className:"mr-1 h-3 w-3"})," Up to date"]})]}),m.status.docker&&m.status.watchtower&&m.watchtowerReachable&&s.jsx("p",{className:"text-muted-foreground",children:"Watchtower pulls new images automatically every hour — or use Update now for an instant update."}),m.status.docker&&m.status.watchtower&&m.watchtowerReachable===!1&&s.jsxs("p",{className:"text-muted-foreground",children:["The Watchtower sidecar is configured but not running — start it with ",s.jsx("code",{className:"rounded bg-muted px-1 text-xs",children:"docker compose --profile updater up -d"}),"."]}),m.status.docker&&!m.status.watchtower&&s.jsx("p",{className:"text-muted-foreground",children:m.status.reason??"This instance runs in Docker — update by pulling the new image tag."}),!m.status.docker&&m.latestVersion===null&&s.jsxs("p",{className:"text-muted-foreground",children:["Could not reach the npm registry (offline or blocked). ",w&&s.jsx("span",{className:"text-destructive",children:w})]}),S==="installing"&&s.jsxs("div",{className:"flex items-center gap-2 text-muted-foreground",children:[s.jsx(jo,{className:"h-4 w-4 animate-spin"})," Applying the update… this can take a minute."]}),S==="restarting"&&s.jsxs("div",{className:"flex items-center gap-2 text-muted-foreground",children:[s.jsx(jo,{className:"h-4 w-4 animate-spin"})," Update applied — the gateway is restarting on the new version. This page reloads automatically."]}),s.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[m.hasUpdate&&S==="idle"&&(!m.status.docker||m.status.watchtower&&m.watchtowerReachable!==!1)&&s.jsxs(he,{disabled:v||m.status.docker&&m.watchtowerReachable===!1,onClick:C,children:[s.jsx(Ky,{className:"mr-1 h-4 w-4"})," Update now"]}),m.hasUpdate&&m.changelogUrl&&s.jsx(he,{variant:"outline",asChild:!0,children:s.jsx("a",{href:m.changelogUrl,target:"_blank",rel:"noreferrer",children:"View changes"})}),S==="idle"&&s.jsx(he,{variant:"ghost",disabled:v,onClick:()=>j(!0),children:"Check again"})]})]})]})]})]})]})]})}function lD(){const a=k1();return s.jsxs(Ze,{className:"mt-4",children:[s.jsx(Je,{children:s.jsxs(We,{className:"text-base flex items-center gap-2",children:[s.jsx(ZC,{className:"h-4 w-4"})," Notifications"]})}),s.jsxs(et,{className:"space-y-3 text-sm",children:[s.jsxs("div",{className:"flex items-center justify-between",children:[s.jsx("span",{children:"Show request notifications"}),s.jsx(ba,{checked:a.enabled,onCheckedChange:l=>void xy({enabled:l})})]}),s.jsxs("div",{className:"flex items-center justify-between",children:[s.jsxs("span",{className:"flex items-center gap-1",children:[s.jsx(b2,{className:"h-3 w-3"})," Play notification sound"]}),s.jsx(ba,{checked:a.sound,onCheckedChange:l=>void xy({sound:l})})]}),s.jsx("p",{className:"text-xs text-muted-foreground mt-2",children:"Notifications are disabled while muted. Changes apply immediately."})]})]})}function rD({items:a,onDismiss:l}){return a.length?s.jsx("div",{className:"fixed top-16 right-4 z-50 flex max-h-[calc(100vh-8rem)] w-80 flex-col gap-2 overflow-y-auto",children:a.map(o=>{const i=!o.success,c=o.success&&o.totalLatencyMs>15e3,d=je("rounded-md border shadow-lg transition-all",i&&"bg-destructive text-destructive-foreground border-destructive",c&&"bg-amber-500/90 text-amber-950 border-amber-600/50",!i&&!c&&"bg-card text-card-foreground border-border");return s.jsxs(ur,{to:"/requests",className:je("block shrink-0 p-3 hover:opacity-95",d),children:[s.jsxs("div",{className:"flex items-start justify-between gap-2",children:[s.jsxs("div",{className:"flex min-w-0 flex-1 items-center gap-2",children:[i?s.jsx(t2,{className:"h-4 w-4 shrink-0"}):o.success?s.jsx(Ac,{className:"h-4 w-4 shrink-0"}):s.jsx(S2,{className:"h-4 w-4 shrink-0 opacity-70"}),s.jsx("div",{className:"min-w-0 truncate text-sm font-medium",title:o.requestedModel,children:o.requestedModel})]}),s.jsx("button",{className:"shrink-0 opacity-60 hover:opacity-100",onClick:h=>{h.preventDefault(),h.stopPropagation(),l(o.id)},"aria-label":"Dismiss",type:"button",children:s.jsx(Dc,{className:"h-3.5 w-3.5"})})]}),s.jsxs("div",{className:"mt-1 text-xs",children:[o.success?"Thành công":"Thất bại",!o.success&&o.errorType&&s.jsx("span",{className:"ml-1 inline-block rounded bg-black/15 px-1 py-0.5 align-text-bottom text-[10px]",children:o.errorType})]}),s.jsxs("div",{className:"mt-1 text-[11px] opacity-90",children:["in ",At(o.inputTokens)," · out ",At(o.outputTokens),(o.cacheReadTokens>0||o.cacheWriteTokens>0)&&s.jsxs(s.Fragment,{children:[" · cache ",o.cacheReadTokens>0&&s.jsxs("span",{children:["r",At(o.cacheReadTokens)]}),o.cacheReadTokens>0&&o.cacheWriteTokens>0&&"/",o.cacheWriteTokens>0&&s.jsxs("span",{children:["w",At(o.cacheWriteTokens)]})]})]}),s.jsxs("div",{className:"mt-1 text-[11px] opacity-90",children:[dr(o.totalLatencyMs),o.ttftMs!=null&&o.ttftMs>=0&&s.jsxs("span",{children:[" · TTFT ",dr(o.ttftMs)]})]})]},o.id)})}):null}const sD=5e3,oD=8,iD=3e3;let fc=null;function cD(){try{fc||(fc=new Audio("/notification.mp3")),fc.currentTime=0,fc.play().catch(()=>{})}catch{}}function uD(){const[a,l]=p.useState([]),o=p.useRef(null),i=p.useRef(new Map),c=p.useRef(Date.now()),d=k1(),h=p.useRef(d.sound);h.current=d.sound,p.useEffect(()=>{O1()},[]);const m=d.enabled;return p.useEffect(()=>{var x;if(!m){(x=o.current)==null||x.close(),o.current=null;const w=i.current;for(const E of w.values())clearTimeout(E);w.clear(),l([]);return}let v=!1;const b=i.current,S=()=>{if(v)return;const w=new EventSource(`/api/admin/requests/stream?since=${c.current}`);o.current=w,w.addEventListener("request",E=>{if(!v)try{const j=JSON.parse(E.data),C=new Date(j.createdAt).getTime();Number.isFinite(C)&&(c.current=Math.max(c.current,C)),l(N=>N.some(M=>M.id===j.id)?N:[j,...N].slice(0,oD));const T=setTimeout(()=>{l(N=>N.filter(M=>M.id!==j.id)),b.delete(j.id)},sD);b.set(j.id,T),h.current&&cD()}catch{}}),w.onerror=()=>{w.close(),o.current=null,v||setTimeout(S,iD)}};return S(),()=>{var w;v=!0,(w=o.current)==null||w.close(),o.current=null;for(const E of b.values())clearTimeout(E);b.clear()}},[m]),{items:a,dismiss:v=>{const b=i.current.get(v);b&&(clearTimeout(b),i.current.delete(v)),l(S=>S.filter(x=>x.id!==v))}}}function dD({children:a}){const{user:l,loading:o}=Rh(),i=un();return o?s.jsx("div",{className:"flex h-screen items-center justify-center text-muted-foreground",children:"Loading…"}):l?s.jsx(s.Fragment,{children:a}):s.jsx(qf,{to:"/login",state:{from:i},replace:!0})}function fD(){const{items:a,dismiss:l}=uD();return s.jsxs("div",{className:"flex h-screen bg-background text-foreground",children:[s.jsx(aE,{}),s.jsxs("div",{className:"flex flex-1 flex-col overflow-hidden",children:[s.jsx(lM,{}),s.jsx("main",{className:"flex-1 overflow-auto p-6",children:s.jsxs(By,{children:[s.jsx(rn,{index:!0,element:s.jsx(HM,{})}),s.jsx(rn,{path:"/providers",element:s.jsx(d_,{})}),s.jsx(rn,{path:"/models",element:s.jsx(S_,{})}),s.jsx(rn,{path:"/combos",element:s.jsx(w_,{})}),s.jsx(rn,{path:"/aliases",element:s.jsx(j_,{})}),s.jsx(rn,{path:"/api-keys",element:s.jsx(C_,{})}),s.jsx(rn,{path:"/requests",element:s.jsx(N_,{})}),s.jsx(rn,{path:"/statistics",element:s.jsx(eD,{})}),s.jsx(rn,{path:"/audit",element:s.jsx(tD,{})}),s.jsx(rn,{path:"/settings/*",element:s.jsx(aD,{})})]})})]}),s.jsx(rD,{items:a,onDismiss:l})]})}function hD({children:a}){const[l,o]=p.useState(null),i=un();return p.useEffect(()=>{Se.get("/api/admin/setup/status").then(c=>o(c.setupComplete)).catch(()=>o(!0))},[]),l===null?s.jsx("div",{className:"flex h-screen items-center justify-center text-muted-foreground",children:"Loading…"}):!l&&i.pathname!=="/setup"?s.jsx(qf,{to:"/setup",replace:!0}):l&&i.pathname==="/setup"?s.jsx(qf,{to:"/",replace:!0}):s.jsx(s.Fragment,{children:a})}function mD(){return s.jsx($C,{children:s.jsx(hD,{children:s.jsxs(By,{children:[s.jsx(rn,{path:"/setup",element:s.jsx(LM,{})}),s.jsx(rn,{path:"/login",element:s.jsx(zM,{})}),s.jsx(rn,{path:"/*",element:s.jsx(dD,{children:s.jsx(fD,{})})})]})})})}const pD=kM;var gD=Object.defineProperty,on=(a,l)=>gD(a,"name",{value:l,configurable:!0}),[jm,XD]=dn("Tooltip",[Cs]),vD=Cs(),xD="TooltipProvider",yD=700,yy="tooltip.open",[bD,SD]=jm(xD),wD=on(a=>{const{__scopeTooltip:l,delayDuration:o=yD,skipDelayDuration:i=300,disableHoverableContent:c=!1,children:d}=a,h=p.useRef(!0),m=p.useRef(!1),g=p.useRef(0);return p.useEffect(()=>{const v=g.current;return()=>window.clearTimeout(v)},[]),s.jsx(bD,{scope:l,isOpenDelayedRef:h,delayDuration:o,onOpen:p.useCallback(()=>{i<=0||(window.clearTimeout(g.current),h.current=!1)},[i]),onClose:p.useCallback(()=>{i<=0||(window.clearTimeout(g.current),g.current=window.setTimeout(()=>h.current=!0,i))},[i]),isPointerInTransitRef:m,onPointerInTransitChange:p.useCallback(v=>{m.current=v},[]),disableHoverableContent:c,children:d})},"TooltipProvider"),jD="Tooltip",[FD,Cm]=jm(jD),CD="TooltipPortal",[QD,ED]=jm(CD,{forceMount:void 0}),Mo="TooltipContent",RD=p.forwardRef(on(function(l,o){const i=ED(Mo,l.__scopeTooltip),{forceMount:c=i.forceMount,side:d="top",...h}=l,m=Cm(Mo,l.__scopeTooltip);return s.jsx(nl,{present:c||m.open,children:m.disableHoverableContent?s.jsx(z1,{side:d,...h,ref:o}):s.jsx(ND,{side:d,...h,ref:o})})},"TooltipContent")),ND=p.forwardRef(on(function(l,o){const i=Cm(Mo,l.__scopeTooltip),c=SD(Mo,l.__scopeTooltip),d=p.useRef(null),h=Ve(o,d),[m,g]=p.useState(null),{trigger:v,onClose:b}=i,S=d.current,{onPointerInTransitChange:x}=c,w=p.useCallback(()=>{g(null),x(!1)},[x]),E=p.useCallback((j,C)=>{const T=j.currentTarget,N={x:j.clientX,y:j.clientY},M=L1(N,T.getBoundingClientRect()),A=U1(N,M),_=H1(C.getBoundingClientRect()),z=P1([...A,..._]);g(z),x(!0)},[x]);return p.useEffect(()=>()=>w(),[w]),p.useEffect(()=>{if(v&&S){const j=on(T=>E(T,S),"handleTriggerLeave"),C=on(T=>E(T,v),"handleContentLeave");return v.addEventListener("pointerleave",j),S.addEventListener("pointerleave",C),()=>{v.removeEventListener("pointerleave",j),S.removeEventListener("pointerleave",C)}}},[v,S,E,w]),p.useEffect(()=>{if(m){const j=on(C=>{const T=C.target,N={x:C.clientX,y:C.clientY},M=(v==null?void 0:v.contains(T))||(S==null?void 0:S.contains(T)),A=!B1(N,m);M?w():A&&(w(),b())},"handleTrackPointerGrace");return document.addEventListener("pointermove",j),()=>document.removeEventListener("pointermove",j)}},[v,S,m,b,w]),s.jsx(z1,{...l,ref:h})},"TooltipContentHoverable")),TD=ib("TooltipContent"),z1=p.forwardRef(on(function(l,o){const{__scopeTooltip:i,children:c,"aria-label":d,id:h,onEscapeKeyDown:m,onPointerDownOutside:g,...v}=l,b=Cm(Mo,i),S=vD(i),{onClose:x}=b;p.useEffect(()=>(document.addEventListener(yy,x),()=>document.removeEventListener(yy,x)),[x]),p.useEffect(()=>{if(b.trigger){const E=on(j=>{j.target instanceof Node&&j.target.contains(b.trigger)&&x()},"handleScroll");return window.addEventListener("scroll",E,{capture:!0}),()=>window.removeEventListener("scroll",E,{capture:!0})}},[b.trigger,x]);const{setContentId:w}=b;return _t(()=>(w(h),()=>{w(void 0)}),[h,w]),s.jsx(zc,{asChild:!0,disableOutsidePointerEvents:!1,onEscapeKeyDown:m,onPointerDownOutside:g,onFocusOutside:E=>E.preventDefault(),onDismiss:x,children:s.jsxs(Vh,{"data-state":b.stateAttribute,role:d?void 0:"tooltip",id:d?void 0:b.contentId,...S,...v,ref:o,style:{...v.style,"--radix-tooltip-content-transform-origin":"var(--radix-popper-transform-origin)","--radix-tooltip-content-available-width":"var(--radix-popper-available-width)","--radix-tooltip-content-available-height":"var(--radix-popper-available-height)","--radix-tooltip-trigger-width":"var(--radix-popper-anchor-width)","--radix-tooltip-trigger-height":"var(--radix-popper-anchor-height)"},children:[s.jsx(TD,{children:c}),d?s.jsx(EA,{id:b.contentId,role:"tooltip",children:d}):null]})})},"TooltipContentImpl"));function L1(a,l){const o=Math.abs(l.top-a.y),i=Math.abs(l.bottom-a.y),c=Math.abs(l.right-a.x),d=Math.abs(l.left-a.x);switch(Math.min(o,i,c,d)){case d:return"left";case c:return"right";case o:return"top";case i:return"bottom";default:throw new Error("unreachable")}}on(L1,"getExitSideFromRect");function U1(a,l,o=5){const i=[];switch(l){case"top":i.push({x:a.x-o,y:a.y+o},{x:a.x+o,y:a.y+o});break;case"bottom":i.push({x:a.x-o,y:a.y-o},{x:a.x+o,y:a.y-o});break;case"left":i.push({x:a.x+o,y:a.y-o},{x:a.x+o,y:a.y+o});break;case"right":i.push({x:a.x-o,y:a.y-o},{x:a.x-o,y:a.y+o});break}return i}on(U1,"getPaddedExitPoints");function H1(a){const{top:l,right:o,bottom:i,left:c}=a;return[{x:c,y:l},{x:o,y:l},{x:o,y:i},{x:c,y:i}]}on(H1,"getPointsFromRect");function B1(a,l){const{x:o,y:i}=a;let c=!1;for(let d=0,h=l.length-1;d<l.length;h=d++){const m=l[d],g=l[h],v=m.x,b=m.y,S=g.x,x=g.y;b>i!=x>i&&o<(S-v)*(i-b)/(x-b)+v&&(c=!c)}return c}on(B1,"isPointInPolygon");function P1(a){const l=a.slice();return l.sort((o,i)=>o.x<i.x?-1:o.x>i.x?1:o.y<i.y?-1:o.y>i.y?1:0),q1(l)}on(P1,"getHull");function q1(a){if(a.length<=1)return a.slice();const l=[];for(let i=0;i<a.length;i++){const c=a[i];for(;l.length>=2;){const d=l[l.length-1],h=l[l.length-2];if((d.x-h.x)*(c.y-h.y)>=(d.y-h.y)*(c.x-h.x))l.pop();else break}l.push(c)}l.pop();const o=[];for(let i=a.length-1;i>=0;i--){const c=a[i];for(;o.length>=2;){const d=o[o.length-1],h=o[o.length-2];if((d.x-h.x)*(c.y-h.y)>=(d.y-h.y)*(c.x-h.x))o.pop();else break}o.push(c)}return o.pop(),l.length===1&&o.length===1&&l[0].x===o[0].x&&l[0].y===o[0].y?l:l.concat(o)}on(q1,"getHullPresorted");var MD=wD,V1=RD;const AD=MD,_D=p.forwardRef(({className:a,sideOffset:l=4,...o},i)=>s.jsx(V1,{ref:i,sideOffset:l,className:je("z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground animate-in fade-in-0 zoom-in-95",a),...o}));_D.displayName=V1.displayName;uj.createRoot(document.getElementById("root")).render(s.jsx(ue.StrictMode,{children:s.jsx(fE,{defaultTheme:"dark",storageKey:"latedev-theme",children:s.jsxs(AD,{children:[s.jsx(OC,{children:s.jsx(mD,{})}),s.jsx(pD,{position:"top-right"})]})})}));
|
|
324
|
+
`);let pt="",bt="";for(const St of mt)St.startsWith("event: ")?pt=St.slice(7):St.startsWith("data: ")&&(bt=St.slice(6));if(bt){if(pt===""||pt==="message")try{const Lt=(P=JSON.parse(bt).choices)==null?void 0:P[0];(Q=Lt==null?void 0:Lt.delta)!=null&&Q.content&&(ie+=Lt.delta.content),W(fn=>{if(!fn||fn.phase!=="streaming")return fn;const Qn=Date.now()-F,hn=fn.progress.ttftMs??Qn;return{...fn,text:ie,progress:{ttftMs:hn,elapsedMs:Qn}}})}catch{}if(pt==="test_meta")try{const St=JSON.parse(bt);W({phase:"done",model:H,result:St,text:ie})}catch{}if(pt==="test_error")try{const St=JSON.parse(bt);W({phase:"error",model:H,error:St.message})}catch{}}}}W(Re=>!Re||Re.phase==="streaming"?{phase:"error",model:H,error:"Stream ended unexpectedly"}:Re)}catch(ae){W({phase:"error",model:H,error:ae.message})}finally{_(null)}};return s.jsxs("div",{children:[s.jsx(wa,{title:"Models",description:"Physical models imported from providers",actions:s.jsxs(qn,{open:h,onOpenChange:m,children:[s.jsx(Ho,{asChild:!0,children:s.jsxs(he,{variant:"outline",children:[s.jsx(Ky,{className:"mr-1 h-4 w-4"})," Fetch models"]})}),s.jsxs(jn,{className:"max-w-2xl",children:[s.jsx(Cn,{children:s.jsx(En,{children:"Discover models"})}),s.jsxs("div",{className:"space-y-3",children:[s.jsxs("div",{className:"flex items-end gap-2",children:[s.jsx("div",{className:"flex-1",children:s.jsxs(In,{value:g,onValueChange:v,children:[s.jsx(Rn,{children:s.jsx(Gn,{placeholder:"Choose provider"})}),s.jsx(Nn,{children:o.map(H=>s.jsx(lt,{value:H.id,children:H.name},H.id))})]})}),s.jsx(he,{onClick:ce,disabled:!g||E,children:E?"Fetching…":"Fetch"})]}),b.length>0&&s.jsxs("div",{className:"space-y-2",children:[s.jsxs("div",{className:"flex items-center justify-between gap-2",children:[s.jsx("div",{className:"flex items-center gap-2 flex-1",children:s.jsxs("div",{className:"relative flex-1",children:[s.jsx(Jy,{className:"absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground"}),s.jsx(Ne,{className:"pl-8",placeholder:"Search models…",value:N,onChange:H=>M(H.target.value)}),N&&s.jsx("button",{className:"absolute right-2 top-2.5 text-muted-foreground hover:text-foreground",onClick:()=>M(""),children:s.jsx(Dc,{className:"h-4 w-4"})})]})}),s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsxs("span",{className:"text-sm text-muted-foreground",children:[se.length," / ",b.length," · ",x.size," selected"]}),s.jsx(he,{variant:"outline",size:"sm",onClick:()=>w(new Set(se.filter(H=>!H.alreadyImported).map(H=>H.upstreamId))),children:"Select All (new)"}),s.jsx(he,{variant:"outline",size:"sm",onClick:()=>w(new Set),children:"Clear"})]})]}),s.jsx("div",{className:"max-h-80 space-y-1 overflow-auto rounded border p-2",children:se.length===0&&b.length>0?s.jsx("div",{className:"text-center text-sm text-muted-foreground py-4",children:"No models match your search."}):se.map(H=>s.jsxs("label",{className:"flex items-center gap-2 rounded p-1 text-sm hover:bg-accent",children:[s.jsx(vm,{checked:x.has(H.upstreamId),onCheckedChange:F=>{const D=new Set(x);F?D.add(H.upstreamId):D.delete(H.upstreamId),w(D)}}),s.jsx("span",{className:"font-mono text-xs",children:H.upstreamId}),H.alreadyImported&&s.jsx(Qe,{variant:"secondary",children:"imported"})]},H.upstreamId))})]})]}),s.jsxs(Vn,{children:[s.jsx(he,{variant:"outline",onClick:()=>m(!1),children:"Cancel"}),s.jsxs(he,{disabled:x.size===0,onClick:U,children:["Import ",x.size||""]})]})]})]})}),s.jsxs(Ze,{children:[s.jsxs(Je,{children:[s.jsx(We,{className:"text-base",children:"All models"}),s.jsxs(wn,{children:[a.length," total"]})]}),s.jsxs(et,{children:[s.jsxs("div",{className:"mb-3 flex items-center gap-2",children:[s.jsxs(In,{value:c,onValueChange:d,children:[s.jsx(Rn,{className:"w-56",children:s.jsx(Gn,{})}),s.jsxs(Nn,{children:[s.jsx(lt,{value:"all",children:"All providers"}),o.map(H=>s.jsx(lt,{value:H.id,children:H.name},H.id))]})]}),s.jsx(Ne,{className:"max-w-xs",placeholder:"Search public ID",value:C,onChange:H=>T(H.target.value)})]}),s.jsxs(Kn,{children:[s.jsx(Xn,{children:s.jsxs(Ye,{children:[s.jsx(pe,{children:"Public ID"}),s.jsx(pe,{children:"Provider"}),s.jsx(pe,{children:"Upstream ID"}),s.jsx(pe,{children:"Capabilities"}),s.jsx(pe,{children:"Available"}),s.jsx(pe,{children:"Enabled"}),s.jsx(pe,{})]})}),s.jsxs(Fn,{children:[le.length===0&&s.jsx(Ye,{children:s.jsx(fe,{colSpan:7,className:"text-center text-muted-foreground",children:"No models"})}),le.map(H=>s.jsxs(Ye,{children:[s.jsx(fe,{className:"font-mono text-xs",children:H.publicModelId}),s.jsx(fe,{children:H.providerSlug}),s.jsx(fe,{className:"text-xs text-muted-foreground",children:H.upstreamModelId}),s.jsx(fe,{className:"space-x-1",children:Object.entries(H.capabilities).filter(([,F])=>F===!0).slice(0,4).map(([F])=>s.jsx(Qe,{variant:"outline",className:"mr-1",children:F},F))}),s.jsx(fe,{children:H.upstreamAvailable?s.jsx(Qe,{variant:"success",children:"up"}):s.jsx(Qe,{variant:"destructive",children:"down"})}),s.jsx(fe,{children:H.enabled?"Yes":"No"}),s.jsx(fe,{className:"text-right",children:s.jsxs("div",{className:"flex items-center justify-end gap-1",children:[s.jsxs(he,{size:"sm",variant:"outline",onClick:()=>void ne(H.id),disabled:A!==null,children:[A===H.id?s.jsx(jo,{className:"h-3.5 w-3.5 animate-spin"}):s.jsx(c2,{className:"h-3.5 w-3.5"})," Test"]}),s.jsxs(he,{size:"sm",variant:"destructive",onClick:()=>K(H),disabled:A!==null,children:[s.jsx(_c,{className:"h-3.5 w-3.5"})," Xoá"]})]})})]},H.id))]})]})]})]}),s.jsx(qn,{open:!!re,onOpenChange:H=>{H||K(null)},children:s.jsxs(jn,{className:"max-w-md",children:[s.jsx(Cn,{children:s.jsx(En,{children:"Xoá model"})}),s.jsxs("div",{className:"space-y-2 text-sm",children:[s.jsxs("p",{children:["Bạn có chắc muốn xoá model ",s.jsx("span",{className:"font-mono",children:re==null?void 0:re.publicModelId}),"?"]}),s.jsx("p",{className:"text-muted-foreground",children:"Model đang được dùng trong combo sẽ bị soft-disable (vô hiệu hoá) thay vì xoá hẳn, để giữ lịch sử và tham chiếu combo."})]}),s.jsxs(Vn,{children:[s.jsx(he,{variant:"outline",onClick:()=>K(null),children:"Huỷ"}),s.jsx(he,{variant:"destructive",onClick:$,children:"Xoá"})]})]})}),s.jsx(qn,{open:z,onOpenChange:q,children:s.jsxs(jn,{className:"max-w-2xl",children:[s.jsx(Cn,{children:s.jsx(En,{children:"Kết quả test model"})}),k&&k.phase==="streaming"&&s.jsxs("div",{className:"space-y-3 text-sm",children:[s.jsxs("div",{className:"flex items-center gap-2 text-muted-foreground",children:[s.jsx(jo,{className:"h-4 w-4 animate-spin"})," Đang stream…",s.jsxs("span",{className:"font-mono text-xs text-muted-foreground/60",children:["TTFT ",k.progress.ttftMs!=null?`${k.progress.ttftMs} ms`:"…"]}),s.jsxs("span",{className:"font-mono text-xs text-muted-foreground/60",children:["· ",k.progress.elapsedMs!=null?`${k.progress.elapsedMs} ms`:"…"]})]}),s.jsxs("div",{children:[s.jsx("div",{className:"text-xs text-muted-foreground mb-1",children:"Phản hồi (streaming)"}),s.jsxs("div",{className:"max-h-60 overflow-auto whitespace-pre-wrap rounded border bg-muted p-3 font-mono text-xs",children:[k.text||s.jsx("span",{className:"text-muted-foreground/60 animate-pulse",children:"waiting for first token…"}),k.phase==="streaming"&&s.jsx("span",{className:"ml-0.5 inline-block h-3.5 w-1.5 animate-pulse bg-primary/70"})]})]})]}),k&&k.phase==="done"&&s.jsxs("div",{className:"space-y-3 text-sm",children:[s.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[s.jsx(Qe,{variant:k.result.success?"success":"destructive",children:k.result.success?"Thành công":"Thất bại"}),s.jsxs("div",{children:[s.jsx("div",{className:"text-xs text-muted-foreground",children:"Thời gian phản hồi"}),s.jsxs("div",{className:"font-mono",children:[k.result.latencyMs," ms"]})]}),s.jsxs("div",{children:[s.jsx("div",{className:"text-xs text-muted-foreground",children:"TTFT"}),s.jsx("div",{className:"font-mono",children:k.result.ttftMs!=null?`${k.result.ttftMs} ms`:"—"})]}),s.jsxs("div",{children:[s.jsx("div",{className:"text-xs text-muted-foreground",children:"Tokens (in / out)"}),s.jsxs("div",{className:"font-mono",children:[k.result.usage.input," / ",k.result.usage.output]})]})]}),s.jsxs("div",{children:[s.jsx("div",{className:"text-xs text-muted-foreground mb-1",children:"Phản hồi của model"}),s.jsx("div",{className:"max-h-60 overflow-auto whitespace-pre-wrap rounded border bg-muted p-3 font-mono text-xs",children:k.text||k.result.text||"(trống)"})]}),k.result.attempts.length>0&&s.jsxs("div",{children:[s.jsx("div",{className:"text-xs text-muted-foreground mb-1",children:"Attempts"}),s.jsx("div",{className:"space-y-1",children:k.result.attempts.map((H,F)=>s.jsxs("div",{className:"flex items-center gap-2 rounded border p-2 text-xs",children:[s.jsx(Qe,{variant:H.success?"success":"destructive",children:H.success?"OK":"FAIL"}),s.jsxs("span",{className:"font-mono",children:[H.providerName," / ",H.modelId]}),s.jsxs("span",{className:"text-muted-foreground",children:[H.latencyMs," ms"]}),H.failureReason&&s.jsx("span",{className:"text-destructive",children:H.failureReason})]},F))})]})]}),k&&k.phase==="error"&&s.jsxs("div",{className:"space-y-2 text-sm",children:[s.jsx(Qe,{variant:"destructive",children:"Thất bại"}),s.jsx("p",{className:"text-destructive",children:k.error})]}),s.jsx(Vn,{children:s.jsx(he,{variant:"outline",onClick:()=>q(!1),children:"Đóng"})})]})})]})}function w_(){const[a,l]=p.useState([]),[o,i]=p.useState([]),[c,d]=p.useState(!1),[h,m]=p.useState(!1),[g,v]=p.useState(null),[b,S]=p.useState(!1),[x,w]=p.useState(!1),[E,j]=p.useState({name:"",slug:"",mode:"fallback",enabled:!0,members:[]}),[C,T]=p.useState({name:"",slug:"",mode:"fallback",enabled:!0,members:[]}),N=async()=>{const[K,V]=await Promise.all([Se.get("/api/admin/combos"),Se.get("/api/admin/models")]);l(K.combos),i(V.models)};p.useEffect(()=>{N()},[]);const M=K=>{j(V=>({...V,members:[...V.members,{modelId:K,weight:1,position:V.members.length,enabled:!0}]}))},A=K=>{j(V=>({...V,members:V.members.filter((le,se)=>se!==K).map((le,se)=>({...le,position:se}))}))},_=async()=>{if(E.members.length===0){xe.error("Add at least one member");return}S(!0);try{await Se.post("/api/admin/combos",{name:E.name,slug:E.slug||void 0,mode:E.mode,enabled:E.enabled,members:E.members}),xe.success("Combo created"),d(!1),j({name:"",slug:"",mode:"fallback",enabled:!0,members:[]}),N()}catch(K){xe.error(K.message)}finally{S(!1)}},z=async K=>{try{const le=(await Se.get(`/api/admin/combos/${K.id}`)).combo;v(le.id),T({name:le.name,slug:le.slug??"",mode:le.mode,enabled:le.enabled,members:le.members.map(se=>({modelId:se.modelId,weight:se.weight,position:se.position,enabled:se.enabled}))}),m(!0)}catch(V){xe.error(V.message)}},q=async()=>{if(g){if(C.members.length===0){xe.error("Add at least one member");return}w(!0);try{await Se.patch("/api/admin/combos",{id:g,name:C.name,slug:C.slug||void 0,mode:C.mode,enabled:C.enabled,members:C.members}),xe.success("Combo updated"),m(!1),v(null),N()}catch(K){xe.error(K.message)}finally{w(!1)}}},k=K=>{T(V=>({...V,members:[...V.members,{modelId:K,weight:1,position:V.members.length,enabled:!0}]}))},W=K=>{T(V=>({...V,members:V.members.filter((le,se)=>se!==K).map((le,se)=>({...le,position:se}))}))},re=async K=>{if(confirm("Delete this combo?"))try{await Se.del(`/api/admin/combos/${K}`),xe.success("Combo removed"),N()}catch(V){xe.error(V.message)}};return s.jsxs("div",{children:[s.jsx(wa,{title:"Combos",description:"Virtual models combining physical models",actions:s.jsxs(qn,{open:c,onOpenChange:d,children:[s.jsx(Ho,{asChild:!0,children:s.jsxs(he,{children:[s.jsx(Oo,{className:"mr-1 h-4 w-4"})," New combo"]})}),s.jsxs(jn,{className:"max-w-2xl",children:[s.jsx(Cn,{children:s.jsx(En,{children:"New combo"})}),s.jsxs("div",{className:"space-y-3",children:[s.jsxs("div",{children:[s.jsx(ye,{children:"Name"}),s.jsx(Ne,{value:E.name,onChange:K=>j({...E,name:K.target.value})})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"Slug (optional — leave empty to use the name as the model ID)"}),s.jsx(Ne,{value:E.slug,onChange:K=>j({...E,slug:K.target.value}),placeholder:"empty → gpt-5.5 · set → combo/gpt-5.5"})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"Mode"}),s.jsxs(In,{value:E.mode,onValueChange:K=>j({...E,mode:K}),children:[s.jsx(Rn,{children:s.jsx(Gn,{})}),s.jsxs(Nn,{children:[s.jsx(lt,{value:"fallback",children:"Fallback (ordered)"}),s.jsx(lt,{value:"weighted_round_robin",children:"Weighted round-robin"})]})]})]}),s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsx(ba,{checked:E.enabled,onCheckedChange:K=>j({...E,enabled:K})}),s.jsx(ye,{children:"Enabled"})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"Members"}),s.jsx(my,{models:o,addedIds:E.members.map(K=>K.modelId),onAdd:M}),s.jsx("div",{className:"mt-2 space-y-1",children:E.members.map((K,V)=>{var le;return s.jsxs("div",{className:"flex items-center gap-2 rounded border p-2 text-sm",children:[s.jsx("span",{className:"font-mono text-xs",children:(le=o.find(se=>se.id===K.modelId))==null?void 0:le.publicModelId}),s.jsx(Ne,{type:"number",min:1,value:K.weight,onChange:se=>{const ce=Number(se.target.value);j(U=>({...U,members:U.members.map(($,ne)=>ne===V?{...$,weight:ce}:$)}))},className:"w-20"}),s.jsx(he,{size:"sm",variant:"outline",onClick:()=>A(V),children:"Remove"})]},V)})})]})]}),s.jsxs(Vn,{children:[s.jsx(he,{variant:"outline",onClick:()=>d(!1),children:"Cancel"}),s.jsx(he,{disabled:!E.name||b,onClick:_,children:b?"Creating…":"Create"})]})]})]})}),s.jsxs(Ze,{children:[s.jsxs(Je,{children:[s.jsx(We,{className:"text-base",children:"All combos"}),s.jsxs(wn,{children:[a.length," total"]})]}),s.jsx(et,{children:s.jsxs(Kn,{children:[s.jsx(Xn,{children:s.jsxs(Ye,{children:[s.jsx(pe,{children:"Public ID"}),s.jsx(pe,{children:"Mode"}),s.jsx(pe,{children:"Members"}),s.jsx(pe,{children:"Healthy"}),s.jsx(pe,{children:"Enabled"}),s.jsx(pe,{})]})}),s.jsxs(Fn,{children:[a.length===0&&s.jsx(Ye,{children:s.jsx(fe,{colSpan:6,className:"text-center text-muted-foreground",children:"No combos yet."})}),a.map(K=>s.jsxs(Ye,{children:[s.jsx(fe,{className:"font-mono text-xs",children:K.publicModelId}),s.jsx(fe,{children:s.jsx(Qe,{variant:"outline",children:K.mode})}),s.jsx(fe,{children:K.memberCount}),s.jsx(fe,{children:K.healthyMemberCount}),s.jsx(fe,{children:K.enabled?"Yes":"No"}),s.jsx(fe,{className:"text-right",children:s.jsxs("div",{className:"flex items-center justify-end gap-1",children:[s.jsxs(he,{size:"sm",variant:"outline",onClick:()=>void z(K),children:[s.jsx(v2,{className:"h-3.5 w-3.5"})," Sửa"]}),s.jsxs(he,{size:"sm",variant:"destructive",onClick:()=>re(K.id),children:[s.jsx(_c,{className:"h-3.5 w-3.5"})," Xoá"]})]})})]},K.id))]})]})})]}),s.jsx(qn,{open:h,onOpenChange:m,children:s.jsxs(jn,{className:"max-w-2xl",children:[s.jsx(Cn,{children:s.jsx(En,{children:"Edit combo"})}),s.jsxs("div",{className:"space-y-3",children:[s.jsxs("div",{children:[s.jsx(ye,{children:"Name"}),s.jsx(Ne,{value:C.name,onChange:K=>T({...C,name:K.target.value})})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"Slug (optional — leave empty to use the name as the model ID)"}),s.jsx(Ne,{value:C.slug,onChange:K=>T({...C,slug:K.target.value}),placeholder:"empty → gpt-5.5 · set → combo/gpt-5.5"})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"Mode"}),s.jsxs(In,{value:C.mode,onValueChange:K=>T({...C,mode:K}),children:[s.jsx(Rn,{children:s.jsx(Gn,{})}),s.jsxs(Nn,{children:[s.jsx(lt,{value:"fallback",children:"Fallback (ordered)"}),s.jsx(lt,{value:"weighted_round_robin",children:"Weighted round-robin"})]})]})]}),s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsx(ba,{checked:C.enabled,onCheckedChange:K=>T({...C,enabled:K})}),s.jsx(ye,{children:"Enabled"})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"Members"}),s.jsx(my,{models:o,addedIds:C.members.map(K=>K.modelId),onAdd:k}),s.jsx("div",{className:"mt-2 space-y-1",children:C.members.map((K,V)=>{var le;return s.jsxs("div",{className:"flex items-center gap-2 rounded border p-2 text-sm",children:[s.jsx("span",{className:"font-mono text-xs",children:(le=o.find(se=>se.id===K.modelId))==null?void 0:le.publicModelId}),s.jsx(Ne,{type:"number",min:1,value:K.weight,onChange:se=>{const ce=Number(se.target.value);T(U=>({...U,members:U.members.map(($,ne)=>ne===V?{...$,weight:ce}:$)}))},className:"w-20"}),s.jsx(he,{size:"sm",variant:"outline",onClick:()=>W(V),children:"Remove"})]},V)})})]})]}),s.jsxs(Vn,{children:[s.jsx(he,{variant:"outline",onClick:()=>m(!1),children:"Cancel"}),s.jsx(he,{disabled:!C.name||x,onClick:q,children:x?"Saving…":"Save"})]})]})})]})}function my({models:a,addedIds:l,onAdd:o}){const[i,c]=p.useState(""),h=(i?a.filter(m=>{const g=i.toLowerCase();return m.publicModelId.toLowerCase().includes(g)||m.displayName.toLowerCase().includes(g)}):a).filter(m=>!l.includes(m.id));return s.jsxs("div",{className:"space-y-1",children:[s.jsxs("div",{className:"relative",children:[s.jsx(Jy,{className:"absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground"}),s.jsx(Ne,{className:"pl-8",placeholder:"Search models…",value:i,onChange:m=>c(m.target.value)}),i&&s.jsx("button",{className:"absolute right-2 top-2.5 text-muted-foreground hover:text-foreground",onClick:()=>c(""),children:s.jsx(Dc,{className:"h-4 w-4"})})]}),h.length===0?s.jsx("p",{className:"text-xs text-muted-foreground",children:"No models match."}):s.jsx("div",{className:"max-h-40 space-y-1 overflow-auto rounded border p-1",children:h.map(m=>s.jsxs("div",{className:"flex items-center justify-between rounded p-1 text-sm hover:bg-accent",children:[s.jsx("span",{className:"font-mono text-xs",children:m.publicModelId}),s.jsx(he,{size:"sm",variant:"ghost",onClick:()=>o(m.id),children:"+ Add"})]},m.id))})]})}function j_(){const[a,l]=p.useState([]),[o,i]=p.useState([]),[c,d]=p.useState([]),[h,m]=p.useState(!1),[g,v]=p.useState({alias:"",targetKind:"model",targetId:"",enabled:!0}),b=async()=>{const[x,w,E]=await Promise.all([Se.get("/api/admin/aliases"),Se.get("/api/admin/models"),Se.get("/api/admin/combos")]);l(x.aliases),i(w.models),d(E.combos)};p.useEffect(()=>{b()},[]);const S=async()=>{try{await Se.post("/api/admin/aliases",g),xe.success("Alias created"),m(!1),v({alias:"",targetKind:"model",targetId:"",enabled:!0}),b()}catch(x){xe.error(x.message)}};return s.jsxs("div",{children:[s.jsx(wa,{title:"Aliases",description:"Stable client-visible names for models or combos",actions:s.jsxs(qn,{open:h,onOpenChange:m,children:[s.jsx(Ho,{asChild:!0,children:s.jsxs(he,{children:[s.jsx(Oo,{className:"mr-1 h-4 w-4"})," New alias"]})}),s.jsxs(jn,{children:[s.jsx(Cn,{children:s.jsx(En,{children:"New alias"})}),s.jsxs("div",{className:"space-y-3",children:[s.jsxs("div",{children:[s.jsx(ye,{children:"Alias"}),s.jsx(Ne,{value:g.alias,onChange:x=>v({...g,alias:x.target.value}),placeholder:"coding"})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"Target type"}),s.jsxs(In,{value:g.targetKind,onValueChange:x=>v({...g,targetKind:x}),children:[s.jsx(Rn,{children:s.jsx(Gn,{})}),s.jsxs(Nn,{children:[s.jsx(lt,{value:"model",children:"Model"}),s.jsx(lt,{value:"combo",children:"Combo"})]})]})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"Target"}),s.jsxs(In,{value:g.targetId,onValueChange:x=>v({...g,targetId:x}),children:[s.jsx(Rn,{children:s.jsx(Gn,{placeholder:"Choose target"})}),s.jsx(Nn,{children:(g.targetKind==="model"?o:c).map(x=>s.jsx(lt,{value:x.id,children:x.publicModelId},x.id))})]})]}),s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsx(ba,{checked:g.enabled,onCheckedChange:x=>v({...g,enabled:x})}),s.jsx(ye,{children:"Enabled"})]})]}),s.jsxs(Vn,{children:[s.jsx(he,{variant:"outline",onClick:()=>m(!1),children:"Cancel"}),s.jsx(he,{disabled:!g.alias||!g.targetId,onClick:S,children:"Create"})]})]})]})}),s.jsxs(Ze,{children:[s.jsxs(Je,{children:[s.jsx(We,{className:"text-base",children:"All aliases"}),s.jsxs(wn,{children:[a.length," total"]})]}),s.jsx(et,{children:s.jsxs(Kn,{children:[s.jsx(Xn,{children:s.jsxs(Ye,{children:[s.jsx(pe,{children:"Alias"}),s.jsx(pe,{children:"Target"}),s.jsx(pe,{children:"Type"}),s.jsx(pe,{children:"Enabled"}),s.jsx(pe,{})]})}),s.jsxs(Fn,{children:[a.length===0&&s.jsx(Ye,{children:s.jsx(fe,{colSpan:5,className:"text-center text-muted-foreground",children:"No aliases yet."})}),a.map(x=>s.jsxs(Ye,{children:[s.jsx(fe,{className:"font-mono text-xs",children:x.alias}),s.jsx(fe,{className:"font-mono text-xs",children:x.targetName??x.targetId}),s.jsx(fe,{children:s.jsx(Qe,{variant:"outline",children:x.targetKind})}),s.jsx(fe,{children:x.enabled?"Yes":"No"}),s.jsx(fe,{className:"text-right",children:s.jsx(he,{size:"sm",variant:"outline",onClick:async()=>{await Se.del(`/api/admin/aliases/${x.id}`),xe.success("Removed"),b()},children:"Delete"})})]},x.id))]})]})})]})]})}function C_(){const[a,l]=p.useState([]),[o,i]=p.useState([]),[c,d]=p.useState([]),[h,m]=p.useState(!1),[g,v]=p.useState(null),[b,S]=p.useState(null),[x,w]=p.useState({name:"",expiresAt:"",allowAll:!0,permissions:[],rpmLimit:"",tpmLimit:"",concurrency:"",customSecret:""}),E=async()=>{const[N,M,A]=await Promise.all([Se.get("/api/admin/api-keys"),Se.get("/api/admin/models"),Se.get("/api/admin/combos")]);l(N.apiKeys),i(M.models),d(A.combos)};p.useEffect(()=>{E()},[]);const j=async()=>{try{const N=await Se.post("/api/admin/api-keys",{name:x.name,expiresAt:x.expiresAt||null,allowAllModels:x.allowAll,permissions:x.allowAll?void 0:x.permissions,rpmLimit:x.rpmLimit?Number(x.rpmLimit):null,tpmLimit:x.tpmLimit?Number(x.tpmLimit):null,maxConcurrent:x.concurrency?Number(x.concurrency):null,...x.customSecret.trim()?{secret:x.customSecret.trim()}:{}});m(!1),v({secret:N.secret,name:N.name}),w({name:"",expiresAt:"",allowAll:!0,permissions:[],rpmLimit:"",tpmLimit:"",concurrency:"",customSecret:""}),E()}catch(N){xe.error(N.message)}},C=async(N,M)=>{try{await Se.patch("/api/admin/api-keys",{id:N,enabled:!M}),xe.success(M?"Key disabled":"Key enabled"),E()}catch(A){xe.error(A.message)}},T=async N=>{if(window.confirm("Delete this API key? This cannot be undone."))try{await Se.del(`/api/admin/api-keys/${N}`),xe.success("Key deleted"),E()}catch(M){xe.error(M.message)}};return s.jsxs("div",{children:[s.jsx(wa,{title:"API Keys",description:"Gateway bearer keys for client applications",actions:s.jsxs(qn,{open:h,onOpenChange:m,children:[s.jsx(Ho,{asChild:!0,children:s.jsxs(he,{children:[s.jsx(Oo,{className:"mr-1 h-4 w-4"})," New key"]})}),s.jsxs(jn,{className:"max-w-2xl",children:[s.jsx(Cn,{children:s.jsx(En,{children:"New API key"})}),s.jsxs("div",{className:"space-y-3",children:[s.jsxs("div",{children:[s.jsx(ye,{children:"Name"}),s.jsx(Ne,{value:x.name,onChange:N=>w({...x,name:N.target.value})})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"Expires (optional)"}),s.jsx(Ne,{type:"datetime-local",value:x.expiresAt,onChange:N=>w({...x,expiresAt:N.target.value})})]}),s.jsxs("div",{className:"grid grid-cols-3 gap-2",children:[s.jsxs("div",{children:[s.jsx(ye,{children:"RPM limit"}),s.jsx(Ne,{value:x.rpmLimit,onChange:N=>w({...x,rpmLimit:N.target.value}),type:"number"})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"TPM limit"}),s.jsx(Ne,{value:x.tpmLimit,onChange:N=>w({...x,tpmLimit:N.target.value}),type:"number"})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"Concurrency"}),s.jsx(Ne,{value:x.concurrency,onChange:N=>w({...x,concurrency:N.target.value}),type:"number"})]})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"Key value (optional)"}),s.jsx(Ne,{value:x.customSecret,onChange:N=>w({...x,customSecret:N.target.value}),placeholder:"Leave empty to auto-generate ld-…"}),s.jsx("p",{className:"text-xs text-muted-foreground",children:"If provided, this exact value is stored as the key. Otherwise a random ld-… key is generated."})]}),s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsx(ba,{checked:x.allowAll,onCheckedChange:N=>w({...x,allowAll:N})}),s.jsx(ye,{children:"Allow all current and future models"})]}),!x.allowAll&&s.jsxs("div",{children:[s.jsx(ye,{children:"Scope"}),s.jsx("div",{className:"max-h-48 space-y-1 overflow-auto rounded border p-2",children:[...o.map(N=>({targetKind:"model",targetId:N.id,label:N.publicModelId})),...c.map(N=>({targetKind:"combo",targetId:N.id,label:N.publicModelId}))].map(N=>{const M=x.permissions.some(A=>A.targetKind===N.targetKind&&A.targetId===N.targetId);return s.jsxs("label",{className:"flex items-center gap-2 rounded p-1 text-sm hover:bg-accent",children:[s.jsx(vm,{checked:M,onCheckedChange:A=>{w(_=>({..._,permissions:A?[..._.permissions,{targetKind:N.targetKind,targetId:N.targetId}]:_.permissions.filter(z=>!(z.targetKind===N.targetKind&&z.targetId===N.targetId))}))}}),s.jsx("span",{className:"font-mono text-xs",children:N.label}),s.jsx(Qe,{variant:"outline",className:"ml-1",children:N.targetKind})]},`${N.targetKind}:${N.targetId}`)})})]})]}),s.jsxs(Vn,{children:[s.jsx(he,{variant:"outline",onClick:()=>m(!1),children:"Cancel"}),s.jsx(he,{disabled:!x.name,onClick:j,children:"Create"})]})]})]})}),s.jsxs(Ze,{children:[s.jsxs(Je,{children:[s.jsx(We,{className:"text-base",children:"All keys"}),s.jsxs(wn,{children:[a.length," total"]})]}),s.jsx(et,{children:s.jsxs(Kn,{children:[s.jsx(Xn,{children:s.jsxs(Ye,{children:[s.jsx(pe,{children:"Name"}),s.jsx(pe,{children:"Prefix"}),s.jsx(pe,{children:"Status"}),s.jsx(pe,{children:"Scope"}),s.jsx(pe,{children:"RPM/TPM/Conc"}),s.jsx(pe,{})]})}),s.jsxs(Fn,{children:[a.length===0&&s.jsx(Ye,{children:s.jsx(fe,{colSpan:6,className:"text-center text-muted-foreground",children:"No API keys yet."})}),a.map(N=>s.jsxs(Ye,{children:[s.jsx(fe,{className:"font-medium",children:N.name}),s.jsxs(fe,{className:"font-mono text-xs",children:[N.keyPrefix,"…"]}),s.jsx(fe,{children:N.enabled?s.jsx(Qe,{variant:"success",children:"enabled"}):s.jsx(Qe,{variant:"destructive",children:"disabled"})}),s.jsx(fe,{children:N.allowAllModels?"all":`${N.modelScopeCount} scoped`}),s.jsx(fe,{className:"text-xs",children:[N.rpmLimit,N.tpmLimit,N.concurrencyLimit].map((M,A)=>M?["","RPM","TPM","Conc"][A+1]:null).filter(Boolean).join(" / ")||"—"}),s.jsx(fe,{className:"text-right",children:s.jsxs("div",{className:"flex items-center justify-end gap-1",children:[N.secret&&s.jsxs(s.Fragment,{children:[s.jsx(he,{size:"sm",variant:"ghost",title:"Copy secret",onClick:()=>{navigator.clipboard.writeText(N.secret),xe.success("Copied")},children:s.jsx(Cf,{className:"h-3.5 w-3.5"})}),s.jsx(he,{size:"sm",variant:"ghost",title:"Show secret",onClick:()=>S({secret:N.secret,name:N.name}),children:s.jsx(o2,{className:"h-3.5 w-3.5"})})]}),s.jsxs(he,{size:"sm",variant:"outline",onClick:()=>C(N.id,N.enabled),children:[N.enabled?s.jsx(QC,{className:"mr-1 h-3.5 w-3.5"}):s.jsx(Ac,{className:"mr-1 h-3.5 w-3.5"}),N.enabled?"Disable":"Enable"]}),s.jsx(he,{size:"sm",variant:"destructive",onClick:()=>T(N.id),children:s.jsx(_c,{className:"h-3.5 w-3.5"})})]})})]},N.id))]})]})})]}),s.jsx(qn,{open:!!g,onOpenChange:N=>{N||v(null)},children:s.jsxs(jn,{children:[s.jsxs(Cn,{children:[s.jsx(En,{children:"API key created"}),s.jsx(ch,{children:"Copy now — this secret will not be shown again."})]}),s.jsx("div",{className:"rounded border bg-muted p-3 font-mono text-xs break-all",children:g==null?void 0:g.secret}),s.jsxs(Vn,{children:[s.jsxs(he,{onClick:()=>{g&&(navigator.clipboard.writeText(g.secret),xe.success("Copied"))},children:[s.jsx(Cf,{className:"mr-1 h-4 w-4"})," Copy"]}),s.jsx(he,{variant:"outline",onClick:()=>v(null),children:"I have saved it"})]})]})}),s.jsx(qn,{open:!!b,onOpenChange:N=>{N||S(null)},children:s.jsxs(jn,{children:[s.jsxs(Cn,{children:[s.jsxs(En,{children:["API key: ",b==null?void 0:b.name]}),s.jsx(ch,{children:"Full secret for this key, readable any time."})]}),s.jsx("div",{className:"rounded border bg-muted p-3 font-mono text-xs break-all",children:b==null?void 0:b.secret}),s.jsxs(Vn,{children:[s.jsxs(he,{onClick:()=>{b&&(navigator.clipboard.writeText(b.secret),xe.success("Copied"))},children:[s.jsx(Cf,{className:"mr-1 h-4 w-4"})," Copy"]}),s.jsx(he,{variant:"outline",onClick:()=>S(null),children:"Close"})]})]})})]})}const E_=3e3;function R_(a,l){return!(l.success!=="all"&&a.success!==(l.success==="true")||l.protocol!=="all"&&a.protocol!==l.protocol||l.streaming!=="all"&&a.streaming!==(l.streaming==="true")||l.model&&!a.requestedModel.toLowerCase().includes(l.model.toLowerCase()))}function N_(){const[a,l]=p.useState([]),[o,i]=p.useState(0),[c,d]=p.useState(0),[h,m]=p.useState({success:"all",protocol:"all",streaming:"all",model:""}),[g,v]=p.useState(null),[b,S]=p.useState(null),[x,w]=p.useState(0),E=50,j=p.useRef(Date.now()),C=p.useRef(new Set),T=p.useRef(h);T.current=h;const N=p.useRef(c);N.current=c;const M=p.useCallback(async()=>{const _=new URLSearchParams;_.set("limit",String(E)),_.set("offset",String(c)),h.success!=="all"&&_.set("success",h.success),h.protocol!=="all"&&_.set("protocol",h.protocol),h.streaming!=="all"&&_.set("streaming",h.streaming),h.model&&_.set("requestedModel",h.model);const z=await Se.get(`/api/admin/requests?${_.toString()}`);l(z.requests),i(z.total);for(const q of z.requests)C.current.add(q.id)},[c,h]);p.useEffect(()=>{M()},[M]),p.useEffect(()=>{w(0)},[c,h]),p.useEffect(()=>{let _=!1,z=null;const q=new Set,k=()=>{_||(z=new EventSource(`/api/admin/requests/stream?since=${j.current}`),z.addEventListener("request",W=>{if(!_)try{const re=JSON.parse(W.data),K=new Date(re.createdAt).getTime();if(Number.isFinite(K)&&(j.current=Math.max(j.current,K)),C.current.has(re.id))return;C.current.add(re.id),w(V=>V+1),N.current===0&&R_(re,T.current)&&(l(V=>V.some(le=>le.id===re.id)?V:[re,...V].slice(0,E)),i(V=>V+1))}catch{}}),z.onerror=()=>{z==null||z.close(),z=null,_||q.add(setTimeout(k,E_))})};return k(),()=>{_=!0,z==null||z.close();for(const W of q)clearTimeout(W);q.clear()}},[]);const A=async _=>{v(_);const z=await Se.get(`/api/admin/requests/${_}`);S(z)};return s.jsxs("div",{children:[s.jsx(wa,{title:"Requests",description:`${o} matching · live updates`}),s.jsxs(Ze,{children:[s.jsxs(Je,{children:[s.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[s.jsxs(In,{value:h.success,onValueChange:_=>{d(0),m({...h,success:_})},children:[s.jsx(Rn,{className:"w-36",children:s.jsx(Gn,{})}),s.jsxs(Nn,{children:[s.jsx(lt,{value:"all",children:"All"}),s.jsx(lt,{value:"true",children:"Success"}),s.jsx(lt,{value:"false",children:"Failed"})]})]}),s.jsxs(In,{value:h.protocol,onValueChange:_=>{d(0),m({...h,protocol:_})},children:[s.jsx(Rn,{className:"w-32",children:s.jsx(Gn,{})}),s.jsxs(Nn,{children:[s.jsx(lt,{value:"all",children:"Any protocol"}),s.jsx(lt,{value:"openai",children:"OpenAI"}),s.jsx(lt,{value:"anthropic",children:"Anthropic"})]})]}),s.jsxs(In,{value:h.streaming,onValueChange:_=>{d(0),m({...h,streaming:_})},children:[s.jsx(Rn,{className:"w-32",children:s.jsx(Gn,{})}),s.jsxs(Nn,{children:[s.jsx(lt,{value:"all",children:"Any"}),s.jsx(lt,{value:"true",children:"Streaming"}),s.jsx(lt,{value:"false",children:"Non-stream"})]})]}),s.jsx(Ne,{className:"max-w-xs",placeholder:"Model contains…",value:h.model,onChange:_=>{d(0),m({...h,model:_.target.value})}}),x>0&&s.jsxs(he,{size:"sm",variant:"secondary",onClick:()=>{w(0),M()},children:[x," new request",x>1?"s":""," — refresh"]})]}),s.jsx(We,{className:"mt-3 text-base",children:"Results"})]}),s.jsxs(et,{children:[s.jsxs(Kn,{children:[s.jsx(Xn,{children:s.jsxs(Ye,{children:[s.jsx(pe,{children:"Time"}),s.jsx(pe,{children:"Status"}),s.jsx(pe,{children:"Requested"}),s.jsx(pe,{children:"Final"}),s.jsx(pe,{children:"Tokens"}),s.jsx(pe,{children:"Latency"}),s.jsx(pe,{children:"Attempts"}),s.jsx(pe,{children:"Key"}),s.jsx(pe,{children:"IP"}),s.jsx(pe,{})]})}),s.jsxs(Fn,{children:[a.length===0&&s.jsx(Ye,{children:s.jsx(fe,{colSpan:10,className:"text-center text-muted-foreground",children:"No requests yet."})}),a.map(_=>s.jsxs(Ye,{className:"cursor-pointer",onClick:()=>A(_.id),children:[s.jsx(fe,{className:"text-xs",children:Th(_.createdAt)}),s.jsx(fe,{children:_.success?s.jsx(Qe,{variant:"success",children:_.httpStatus}):s.jsx(Qe,{variant:"destructive",children:_.httpStatus})}),s.jsx(fe,{className:"font-mono text-xs",children:_.requestedModel}),s.jsx(fe,{className:"font-mono text-xs text-muted-foreground",children:_.finalModelPublicId??"—"}),s.jsxs(fe,{className:"text-xs",children:[At(_.inputTokens+_.outputTokens)," ",_.cacheReadTokens?s.jsxs("span",{className:"text-amber-600",children:["(+",_.cacheReadTokens," cache)"]}):null]}),s.jsxs(fe,{className:"text-xs",children:[dr(_.totalLatencyMs),_.ttftMs?s.jsxs("span",{className:"text-muted-foreground",children:[" · ttft ",_.ttftMs,"ms"]}):null]}),s.jsxs(fe,{className:"text-xs",children:[_.attemptsCount,_.gatewayCacheHit?s.jsx(Qe,{variant:"secondary",className:"ml-1",children:"cache"}):null]}),s.jsx(fe,{className:"text-xs",children:_.apiKeyName??"—"}),s.jsx(fe,{className:"text-xs",children:_.clientIp}),s.jsx(fe,{className:"text-right",children:s.jsx(he,{size:"sm",variant:"ghost",children:"View"})})]},_.id))]})]}),s.jsxs("div",{className:"mt-3 flex items-center justify-between",children:[s.jsxs("span",{className:"text-xs text-muted-foreground",children:["Showing ",c+1,"–",Math.min(c+E,o)," of ",o]}),s.jsxs("div",{className:"flex gap-2",children:[s.jsx(he,{size:"sm",variant:"outline",disabled:c===0,onClick:()=>d(Math.max(0,c-E)),children:"Prev"}),s.jsx(he,{size:"sm",variant:"outline",disabled:c+E>=o,onClick:()=>d(c+E),children:"Next"})]})]})]})]}),s.jsx(qn,{open:!!g,onOpenChange:_=>{_||(v(null),S(null))},children:s.jsxs(jn,{className:"max-w-3xl",children:[s.jsx(Cn,{children:s.jsxs(En,{children:["Request ",eE(g,16)]})}),b?s.jsxs("div",{className:"space-y-3 text-sm",children:[s.jsxs("div",{className:"grid grid-cols-2 gap-2",children:[s.jsxs("div",{children:[s.jsx("div",{className:"text-muted-foreground text-xs",children:"Status"}),b.request.success?s.jsx(Qe,{variant:"success",children:b.request.httpStatus}):s.jsx(Qe,{variant:"destructive",children:b.request.httpStatus})]}),s.jsxs("div",{children:[s.jsx("div",{className:"text-muted-foreground text-xs",children:"Latency"}),dr(b.request.totalLatencyMs)]}),s.jsxs("div",{children:[s.jsx("div",{className:"text-muted-foreground text-xs",children:"Tokens"}),"in ",At(b.request.inputTokens)," · out ",At(b.request.outputTokens)," · cache ",At(b.request.cacheReadTokens)]}),s.jsxs("div",{children:[s.jsx("div",{className:"text-muted-foreground text-xs",children:"Attempts"}),b.request.attemptsCount]})]}),b.request.errorType&&s.jsxs("div",{className:"rounded border border-destructive/40 bg-destructive/10 p-2",children:[s.jsx("div",{className:"text-xs text-muted-foreground",children:"Error"}),s.jsxs("div",{className:"font-mono text-xs",children:[b.request.errorType,": ",b.request.errorMessage]})]}),b.request.requestPayload&&s.jsxs("div",{children:[s.jsx("div",{className:"text-xs text-muted-foreground",children:"Request content"}),s.jsx("pre",{className:"max-h-60 overflow-auto rounded bg-muted p-2 font-mono text-xs whitespace-pre-wrap",children:b.request.requestPayload})]}),b.request.responsePayload&&s.jsxs("div",{children:[s.jsx("div",{className:"text-xs text-muted-foreground",children:"Response content"}),s.jsx("pre",{className:"max-h-60 overflow-auto rounded bg-muted p-2 font-mono text-xs whitespace-pre-wrap",children:b.request.responsePayload})]}),b.attempts.length>0&&s.jsxs("div",{children:[s.jsx("div",{className:"text-xs text-muted-foreground",children:"Attempts"}),s.jsxs(Kn,{children:[s.jsx(Xn,{children:s.jsxs(Ye,{children:[s.jsx(pe,{children:"#"}),s.jsx(pe,{children:"Provider"}),s.jsx(pe,{children:"Model"}),s.jsx(pe,{children:"Status"}),s.jsx(pe,{children:"Latency"}),s.jsx(pe,{children:"Reason"})]})}),s.jsx(Fn,{children:b.attempts.map(_=>s.jsxs(Ye,{children:[s.jsx(fe,{children:_.attemptNumber}),s.jsx(fe,{children:_.providerName}),s.jsx(fe,{className:"font-mono text-xs",children:_.modelPublicId}),s.jsx(fe,{children:_.success?s.jsx(Qe,{variant:"success",children:String(_.statusCode??"OK")}):s.jsx(Qe,{variant:"destructive",children:String(_.statusCode??"err")})}),s.jsx(fe,{className:"text-xs",children:dr(_.latencyMs)}),s.jsx(fe,{className:"text-xs",children:_.failureReason??_.selectionReason})]},_.id))})]})]})]}):s.jsx("div",{className:"text-muted-foreground",children:"Loading…"})]})})]})}var T_=Object.defineProperty,Es=(a,l)=>T_(a,"name",{value:l,configurable:!0}),xm="Tabs",[M_,KD]=dn(xm,[Gc]),E1=Gc(),[A_,ym]=M_(xm),__=p.forwardRef(Es(function(l,o){const{__scopeTabs:i,value:c,onValueChange:d,defaultValue:h,orientation:m="horizontal",dir:g,activationMode:v="automatic",...b}=l,S=zo(g),[x,w]=Za({prop:c,onChange:d,defaultProp:h??"",caller:xm});return s.jsx(A_,{scope:i,baseId:ga(),value:x,onValueChange:w,orientation:m,dir:S,activationMode:v,children:s.jsx(Ue.div,{dir:S,"data-orientation":m,...b,ref:o})})},"Tabs")),D_="TabsList",O_=p.forwardRef(Es(function(l,o){const{__scopeTabs:i,loop:c=!0,...d}=l,h=ym(D_,i),m=E1(i);return s.jsx(f0,{asChild:!0,...m,orientation:h.orientation,dir:h.dir,loop:c,children:s.jsx(Ue.div,{role:"tablist","aria-orientation":h.orientation,...d,ref:o})})},"TabsList")),k_="TabsTrigger",z_=p.forwardRef(Es(function(l,o){const{__scopeTabs:i,value:c,disabled:d=!1,...h}=l,m=ym(k_,i),g=E1(i),v=bm(m.baseId,c),b=Sm(m.baseId,c),S=c===m.value;return s.jsx(h0,{asChild:!0,...g,focusable:!d,active:S,children:s.jsx(Ue.button,{type:"button",role:"tab","aria-selected":S,"aria-controls":b,"data-state":S?"active":"inactive","data-disabled":d?"":void 0,disabled:d,id:v,...h,ref:o,onMouseDown:we(l.onMouseDown,x=>{!d&&x.button===0&&x.ctrlKey===!1?m.onValueChange(c):x.preventDefault()}),onKeyDown:we(l.onKeyDown,x=>{d||x.target!==x.currentTarget||[" ","Enter"].includes(x.key)&&m.onValueChange(c)}),onFocus:we(l.onFocus,()=>{const x=m.activationMode!=="manual";!S&&!d&&x&&m.onValueChange(c)})})})},"TabsTrigger")),L_="TabsContent",U_=p.forwardRef(Es(function(l,o){const{__scopeTabs:i,value:c,forceMount:d,children:h,...m}=l,g=ym(L_,i),v=bm(g.baseId,c),b=Sm(g.baseId,c),S=c===g.value,x=p.useRef(S);return p.useEffect(()=>{const w=requestAnimationFrame(()=>x.current=!1);return()=>cancelAnimationFrame(w)},[]),s.jsx(nl,{present:d||S,children:({present:w})=>s.jsx(Ue.div,{"data-state":S?"active":"inactive","data-orientation":g.orientation,role:"tabpanel","aria-labelledby":v,hidden:!w,id:b,tabIndex:0,...m,ref:o,style:{...l.style,animationDuration:x.current?"0s":void 0},children:w&&h})})},"TabsContent"));function bm(a,l){return`${a}-trigger-${l}`}Es(bm,"makeTriggerId");function Sm(a,l){return`${a}-content-${l}`}Es(Sm,"makeContentId");var H_=__,R1=O_,N1=z_,T1=U_;const M1=H_,wm=p.forwardRef(({className:a,...l},o)=>s.jsx(R1,{ref:o,className:je("inline-flex h-9 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground",a),...l}));wm.displayName=R1.displayName;const Ol=p.forwardRef(({className:a,...l},o)=>s.jsx(N1,{ref:o,className:je("inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow",a),...l}));Ol.displayName=N1.displayName;const wo=p.forwardRef(({className:a,...l},o)=>s.jsx(T1,{ref:o,className:je("mt-2 ring-offset-background focus-visible:outline-none",a),...l}));wo.displayName=T1.displayName;const B_=3e3,P_=1600,q_=10,V_=3;function I_(a,l){return{...a,totalRequests:a.totalRequests+1,successfulRequests:a.successfulRequests+(l.success?1:0),failedRequests:a.failedRequests+(l.success?0:1),successRate:a.totalRequests+1?(a.successfulRequests+(l.success?1:0))/(a.totalRequests+1):0,inputTokens:a.inputTokens+l.inputTokens,outputTokens:a.outputTokens+l.outputTokens,totalTokens:a.totalTokens+l.inputTokens+l.outputTokens,cacheReadTokens:a.cacheReadTokens+l.cacheReadTokens,averageLatencyMs:(a.averageLatencyMs*a.totalRequests+l.totalLatencyMs)/(a.totalRequests+1)}}function G_(a){const[l,o]=p.useState(null),[i,c]=p.useState(null),[d,h]=p.useState([]),[m,g]=p.useState([]),[v,b]=p.useState([]),[S,x]=p.useState(!0),[w,E]=p.useState(null),j=p.useRef([]),C=p.useRef(null),T=p.useRef(new Set),N=p.useRef(Date.now()),M=p.useRef(0),A=p.useRef([]);return p.useEffect(()=>{let _=!1;return x(!0),E(null),T.current=new Set,N.current=Date.now(),Se.get(`/api/admin/stats?preset=${a}`).then(z=>{if(!_){o(z),c(z.summary),C.current=z.summary,h(z.recent),g(z.providers),j.current=z.providers;for(const q of z.recent)T.current.add(q.id);x(!1)}}).catch(z=>{_||(E(z.message),x(!1))}),()=>{_=!0}},[a]),p.useEffect(()=>{let _=!1,z=null;const q=new Set,k=()=>{_||(z=new EventSource(`/api/admin/requests/stream?since=${N.current}`),z.addEventListener("request",W=>{if(!_)try{const re=JSON.parse(W.data),K=new Date(re.createdAt).getTime();if(Number.isFinite(K)&&(N.current=Math.max(N.current,K)),T.current.has(re.id))return;if(T.current.add(re.id),C.current&&c(I_(C.current,re)),h(V=>V.some(le=>le.id===re.id)?V:[re,...V].slice(0,q_)),re.providerId){j.current=j.current.map(ce=>ce.id===re.providerId?{...ce,requests:ce.requests+1,errorRate:ce.requests+1?(ce.errorRate*ce.requests+(re.success?0:1))/(ce.requests+1):0}:ce),g(j.current);const V=`p${++M.current}`,le={id:V,providerId:re.providerId,success:re.success};A.current=[...A.current.slice(-(V_*4)),le],b(A.current);const se=setTimeout(()=>{A.current=A.current.filter(ce=>ce.id!==V),b(A.current)},P_);q.add(se)}}catch{}}),z.onerror=()=>{z==null||z.close(),z=null,_||q.add(setTimeout(k,B_))})};return k(),()=>{_=!0,z==null||z.close();for(const W of q)clearTimeout(W);q.clear()}},[]),p.useEffect(()=>{const _=setInterval(()=>{Se.get("/api/admin/providers").then(z=>{const q=new Map(z.providers.map(k=>[k.id,k]));j.current=j.current.map(k=>{const W=q.get(k.id);return W?{...k,health:W.health,enabled:W.enabled}:k}),g(j.current)}).catch(()=>{})},3e4);return()=>clearInterval(_)},[]),{snapshot:l,live:i??(l==null?void 0:l.summary)??Y_,recent:d,providers:m,pulses:v,loading:S,error:w}}const Y_={totalRequests:0,successfulRequests:0,failedRequests:0,successRate:0,inputTokens:0,outputTokens:0,totalTokens:0,cacheReadTokens:0,cacheWriteTokens:0,reasoningTokens:0,averageLatencyMs:0,p95LatencyMs:0,averageTtftMs:null,p95TtftMs:null,cacheHitRate:0,gatewayCacheHitRate:0,fallbackRate:0};function A1({data:a,className:l,strokeClass:o="stroke-primary",fillClass:i}){if(a.length===0)return s.jsx("svg",{className:je("h-6 w-20",l),viewBox:"0 0 80 24"});const h=Math.max(...a),m=Math.min(...a),g=h-m||1,b=a.map((S,x)=>{const w=x/(a.length-1)*78+1,E=22-(S-m)/g*20;return`${w.toFixed(1)},${E.toFixed(1)}`}).join(" ");return s.jsxs("svg",{className:je("h-6 w-20",l),viewBox:"0 0 80 24",preserveAspectRatio:"none",children:[i&&s.jsx("polygon",{points:`1,23 ${b} 79,23`,className:i}),s.jsx("polyline",{points:b,fill:"none",strokeWidth:1.5,strokeLinecap:"round",strokeLinejoin:"round",className:o})]})}function $_(a,l,o){const i=performance.now();let c=0;const d=h=>{const m=Math.min((h-i)/l,1),g=Math.round(a*m);g!==c&&(c=g,o(g)),m<1&&requestAnimationFrame(d)};requestAnimationFrame(d)}function K_({delta:a,inverse:l}){if(Math.abs(a)<.005)return null;const o=a>0,i=l?!o:o,c=`${(Math.abs(a)*100).toFixed(1)}%`;return s.jsxs("span",{className:je("ml-1.5 inline-flex items-center rounded-full px-1.5 py-0.5 text-[10px] font-semibold leading-none",i?"bg-emerald-100 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300":"bg-red-100 text-red-700 dark:bg-red-900/40 dark:text-red-300"),children:[s.jsx("span",{className:"mr-0.5",children:o?"▲":"▼"}),c]})}function Dl({icon:a,label:l,value:o,format:i="number",delta:c,deltaInverse:d,sparkData:h,sparkStroke:m}){const[g,v]=p.useState(0),b=p.useRef(0);p.useEffect(()=>{const x=b.current,w=o;b.current=o,x!==w&&$_(Math.abs(w-x),600,E=>v(x+(w>x?E:-E)))},[o]);const S=i==="percent"?Oc(g):i==="latency"?dr(g):At(Math.round(g));return s.jsxs(Ze,{children:[s.jsxs(Je,{className:"flex flex-row items-center justify-between pb-1",children:[s.jsxs(We,{className:"flex items-center gap-2 text-sm font-medium text-muted-foreground",children:[s.jsx(a,{className:"h-4 w-4"}),l]}),c!==void 0&&s.jsx(K_,{delta:c,inverse:d})]}),s.jsxs(et,{className:"flex items-end justify-between",children:[s.jsx("span",{className:"text-2xl font-semibold tabular-nums",children:S}),h&&h.length>1&&s.jsx(A1,{data:h,strokeClass:m??"stroke-primary",fillClass:"fill-primary/10"})]})]})}const _1=1e3,py=380,uc=60,ir=_1/2,cr=720,Hf=62,X_=260;function F_(a){return a==="healthy"?"fill-emerald-400":a==="degraded"?"fill-amber-400":"fill-red-400"}function Bf(a,l,o,i){const c=a+(o-a)*.45,d=a+(o-a)*.55;return`M${a},${l} C${c},${l} ${d},${i} ${o},${i}`}function Q_({liveRequests:a,successRate:l,providers:o,pulses:i}){const c=py/2,d=c,h=Math.max(1,o.reduce((m,g)=>m+g.requests,0));return s.jsxs(Ze,{children:[s.jsx(Je,{className:"pb-2",children:s.jsxs("div",{className:"flex items-center justify-between",children:[s.jsx(We,{className:"text-base",children:"Real-time Request Routing"}),s.jsxs("div",{className:"flex items-center gap-3 text-xs text-muted-foreground",children:[s.jsxs("span",{className:"flex items-center gap-1",children:[s.jsx("span",{className:"inline-block h-2 w-2 rounded-full bg-emerald-400"})," healthy"]}),s.jsxs("span",{className:"flex items-center gap-1",children:[s.jsx("span",{className:"inline-block h-2 w-2 rounded-full bg-amber-400"})," degraded"]}),s.jsxs("span",{className:"flex items-center gap-1",children:[s.jsx("span",{className:"inline-block h-2 w-2 rounded-full bg-red-400"})," down"]})]})]})}),s.jsx(et,{className:"pt-0",children:s.jsx("div",{className:"relative w-full",children:s.jsxs("svg",{viewBox:`0 0 ${_1} ${py}`,className:"w-full h-auto",preserveAspectRatio:"xMidYMid meet",children:[s.jsx("defs",{children:s.jsxs("filter",{id:"glow",x:"-50%",y:"-50%",width:"200%",height:"200%",children:[s.jsx("feGaussianBlur",{stdDeviation:"3",result:"blur"}),s.jsxs("feMerge",{children:[s.jsx("feMergeNode",{in:"blur"}),s.jsx("feMergeNode",{in:"SourceGraphic"})]})]})}),o.map(m=>{const v=60+o.indexOf(m)*Hf,b=m.requests/h,S=Math.max(1.5,Math.min(6,2+b*8));return s.jsx("path",{d:Bf(ir,c,cr-20,v),fill:"none",stroke:"hsl(var(--border))",strokeWidth:S,strokeLinecap:"round",opacity:.6},m.id)}),s.jsx("path",{d:Bf(uc+30,d,ir-30,c),fill:"none",stroke:"hsl(var(--border))",strokeWidth:3,strokeLinecap:"round",strokeDasharray:"6 3",opacity:.5}),i.map(m=>{const g=o.findIndex(x=>x.id===m.providerId);if(g===-1)return null;const v=60+g*Hf,b=Bf(ir,c,cr-20,v),S=m.success?"var(--primary)":"#f87171";return s.jsxs("g",{filter:"url(#glow)",children:[s.jsx("circle",{r:5,fill:S,opacity:.9,children:s.jsx("animateMotion",{dur:"1.4s",fill:"freeze",path:b})}),s.jsx("circle",{r:9,fill:S,opacity:.25,children:s.jsx("animateMotion",{dur:"1.4s",fill:"freeze",path:b})})]},m.id)}),s.jsx("circle",{cx:uc,cy:d,r:28,fill:"hsl(var(--card))",stroke:"hsl(var(--border))",strokeWidth:1.5}),s.jsx("text",{x:uc,y:d-4,textAnchor:"middle",className:"fill-foreground",fontSize:12,fontWeight:600,children:gy(a)}),s.jsx("text",{x:uc,y:d+10,textAnchor:"middle",className:"fill-muted-foreground",fontSize:9,children:"requests"}),s.jsx("circle",{cx:ir,cy:c,r:36,fill:"hsl(var(--card))",stroke:"var(--primary)",strokeWidth:2}),s.jsx("image",{x:ir-12,y:c-16,width:24,height:24,href:"/logo.png"}),s.jsx("text",{x:ir,y:c+28,textAnchor:"middle",className:"fill-muted-foreground",fontSize:9,children:"AI Gateway"}),s.jsxs("text",{x:ir,y:c+38,textAnchor:"middle",className:"fill-emerald-500",fontSize:10,fontWeight:600,children:[(l*100).toFixed(1),"%"]}),o.map((m,g)=>{const v=60+g*Hf,b=m.requests/h,S=!m.enabled||m.requests===0;return s.jsxs("g",{opacity:S?.4:1,children:[s.jsx("rect",{x:cr-20,y:v-14,width:X_,height:50,rx:8,fill:"hsl(var(--card))",stroke:"hsl(var(--border))",strokeWidth:1}),s.jsx("circle",{cx:cr-6,cy:v+10,r:4,className:F_(m.health)}),s.jsx("text",{x:cr+6,y:v-2,className:"fill-foreground",fontSize:12,fontWeight:500,children:m.name}),s.jsxs("text",{x:cr+6,y:v+12,className:"fill-muted-foreground",fontSize:10,children:[m.modelCount," model",m.modelCount!==1?"s":""," · ",gy(m.requests)," req"]}),s.jsxs("text",{x:cr+6,y:v+25,className:"fill-muted-foreground",fontSize:10,children:[(b*100).toFixed(1),"% traffic · ",m.avgLatencyMs<1e3?`${Math.round(m.avgLatencyMs)}ms`:`${(m.avgLatencyMs/1e3).toFixed(1)}s`," avg",m.errorRate>0&&s.jsxs("tspan",{className:"fill-red-500",children:[" · ",(m.errorRate*100).toFixed(0),"% err"]})]})]},m.id)})]})})})]})}function gy(a){return a>=1e6?`${(a/1e6).toFixed(1)}M`:a>=1e3?`${(a/1e3).toFixed(1)}K`:String(a)}function Z_({rows:a}){return s.jsxs(Ze,{children:[s.jsx(Je,{className:"pb-2",children:s.jsx(We,{className:"text-base",children:"Recent Requests"})}),s.jsx(et,{children:a.length===0?s.jsx("div",{className:"py-6 text-center text-sm text-muted-foreground",children:"No requests yet — traffic will appear here live."}):s.jsxs(Kn,{children:[s.jsx(Xn,{children:s.jsxs(Ye,{children:[s.jsx(pe,{children:"Model"}),s.jsx(pe,{children:"Provider"}),s.jsx(pe,{children:"Tokens"}),s.jsx(pe,{children:"Status"}),s.jsx(pe,{children:"Time"})]})}),s.jsx(Fn,{children:a.map(l=>s.jsxs(Ye,{children:[s.jsx(fe,{className:"font-mono text-xs",children:l.requestedModel}),s.jsx(fe,{className:"text-xs text-muted-foreground",children:l.providerName??"—"}),s.jsxs(fe,{className:"text-xs",children:[s.jsxs("span",{className:"font-mono",children:["in ",At(l.inputTokens)," · out ",At(l.outputTokens)]}),l.cacheReadTokens>0&&s.jsxs("span",{className:"ml-1 text-amber-600",children:["(+",At(l.cacheReadTokens)," cache)"]})]}),s.jsx(fe,{children:s.jsxs("span",{className:"inline-flex items-center gap-1.5",children:[s.jsx("span",{className:l.success?"h-2 w-2 rounded-full bg-emerald-400":"h-2 w-2 rounded-full bg-red-400"}),s.jsx("span",{className:"text-xs",children:l.success?l.httpStatus:`${l.httpStatus} err`})]})}),s.jsx(fe,{className:"text-xs text-muted-foreground",children:tE(l.createdAt)})]},l.id))})]})})]})}const fh=34,vy=2*Math.PI*fh;function J_(a){return a>=.95?{stroke:"#4ade80",text:"text-emerald-500"}:a>=.8?{stroke:"#fbbf24",text:"text-amber-500"}:{stroke:"#f87171",text:"text-red-500"}}function W_({successRate:a,averageLatencyMs:l,latencySpark:o}){const{stroke:i,text:c}=J_(a),d=Math.min(1,Math.max(0,a)),h=vy*(1-d);return s.jsxs("div",{className:"grid gap-4 md:grid-cols-2",children:[s.jsxs(Ze,{children:[s.jsx(Je,{className:"pb-2",children:s.jsx(We,{className:"text-base",children:"Success Rate"})}),s.jsxs(et,{className:"flex items-center gap-4",children:[s.jsxs("div",{className:"relative h-20 w-20",children:[s.jsxs("svg",{viewBox:"0 0 80 80",className:"h-20 w-20 -rotate-90",children:[s.jsx("circle",{cx:"40",cy:"40",r:fh,fill:"none",stroke:"hsl(var(--border))",strokeWidth:7}),s.jsx("circle",{cx:"40",cy:"40",r:fh,fill:"none",stroke:i,strokeWidth:7,strokeLinecap:"round",strokeDasharray:vy,strokeDashoffset:h,style:{transition:"stroke-dashoffset 0.6s ease, stroke 0.4s ease"}})]}),s.jsx("span",{className:`absolute inset-0 flex items-center justify-center text-sm font-semibold tabular-nums ${c}`,children:Oc(a)})]}),s.jsx("p",{className:"text-sm text-muted-foreground",children:"Share of requests that completed successfully over the selected window. Updated in real time."})]})]}),s.jsxs(Ze,{children:[s.jsx(Je,{className:"pb-2",children:s.jsx(We,{className:"text-base",children:"Average Latency"})}),s.jsxs(et,{className:"flex items-end justify-between",children:[s.jsxs("div",{children:[s.jsx("div",{className:"text-2xl font-semibold tabular-nums",children:dr(l)}),s.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"Live average across the selected window"})]}),s.jsx(A1,{data:o,strokeClass:"stroke-amber-500",fillClass:"fill-amber-500/10",className:"h-10 w-28"})]})]})]})}function eD(){const[a,l]=p.useState("7d"),{snapshot:o,live:i,recent:c,providers:d,pulses:h,loading:m,error:g}=G_(a);if(m)return s.jsx("div",{className:"text-muted-foreground",children:"Loading…"});if(g||!o)return s.jsxs("div",{className:"text-destructive",children:["Failed to load statistics: ",g??"unknown error"]});const v=i,b=o.previous,S=o.series;function x(j,C){return C>0?(j-C)/C:void 0}const w=S.map(j=>j.requests),E=S.map(j=>j.avgLatency);return s.jsxs("div",{children:[s.jsx(wa,{title:"Statistics",description:"Real-time monitoring dashboard",actions:s.jsx(M1,{value:a,onValueChange:j=>void l(j),children:s.jsxs(wm,{children:[s.jsx(Ol,{value:"today",children:"Today"}),s.jsx(Ol,{value:"7d",children:"7 days"}),s.jsx(Ol,{value:"30d",children:"30 days"})]})})}),s.jsxs("div",{className:"grid gap-4 md:grid-cols-2 lg:grid-cols-4",children:[s.jsx(Dl,{icon:Yy,label:"Requests",value:v.totalRequests,delta:x(v.totalRequests,b.totalRequests),sparkData:w}),s.jsx(Dl,{icon:Ac,label:"Success rate",format:"percent",value:v.successRate,delta:x(v.successRate,b.successRate),sparkData:w,sparkStroke:"stroke-emerald-500"}),s.jsx(Dl,{icon:r2,label:"Total tokens",value:v.totalTokens,delta:x(v.totalTokens,b.totalTokens),sparkData:S.map(j=>j.inputTokens+j.outputTokens)}),s.jsx(Dl,{icon:s2,label:"Cache hit rate",format:"percent",value:v.cacheHitRate,delta:x(v.cacheHitRate,b.cacheHitRate),sparkData:S.map(j=>j.cacheRead)}),s.jsx(Dl,{icon:n2,label:"Avg latency",format:"latency",value:v.averageLatencyMs,delta:x(v.averageLatencyMs,b.averageLatencyMs),deltaInverse:!0,sparkData:E,sparkStroke:"stroke-amber-500"}),s.jsx(Dl,{icon:Xy,label:"p95 latency",format:"latency",value:v.p95LatencyMs}),s.jsx(Dl,{icon:y2,label:"Avg TTFT",format:"latency",value:v.averageTtftMs??0}),s.jsx(Dl,{icon:m2,label:"Fallback rate",format:"percent",value:v.fallbackRate,delta:x(v.fallbackRate,b.fallbackRate),deltaInverse:!0})]}),s.jsx("div",{className:"mt-6",children:s.jsx(Q_,{liveRequests:v.totalRequests,successRate:v.successRate,providers:d,pulses:h})}),s.jsxs("div",{className:"mt-6 grid gap-4 lg:grid-cols-3",children:[s.jsx("div",{className:"lg:col-span-2",children:s.jsx(Z_,{rows:c})}),s.jsxs("div",{className:"space-y-4",children:[s.jsxs(Ze,{children:[s.jsx(Je,{className:"pb-2",children:s.jsx(We,{className:"text-base",children:"Top Models"})}),s.jsx(et,{children:s.jsxs(Kn,{children:[s.jsx(Xn,{children:s.jsxs(Ye,{children:[s.jsx(pe,{children:"Model"}),s.jsx(pe,{children:"Req"}),s.jsx(pe,{children:"Errors"}),s.jsx(pe,{children:"Tokens"})]})}),s.jsxs(Fn,{children:[o.topModels.length===0&&s.jsx(Ye,{children:s.jsx(fe,{colSpan:4,className:"text-muted-foreground text-center",children:"No data"})}),o.topModels.map(j=>s.jsxs(Ye,{children:[s.jsx(fe,{className:"font-mono text-xs",children:j.publicId}),s.jsx(fe,{className:"text-xs",children:At(j.requests)}),s.jsx(fe,{className:"text-xs",children:s.jsx("span",{className:j.errorRate>.1?"text-destructive":"text-muted-foreground",children:Oc(j.errorRate)})}),s.jsx(fe,{className:"text-xs",children:At(j.totalTokens)})]},j.publicId))]})]})})]}),s.jsxs(Ze,{children:[s.jsx(Je,{className:"pb-2",children:s.jsx(We,{className:"text-base",children:"Top API Keys"})}),s.jsx(et,{children:s.jsxs(Kn,{children:[s.jsx(Xn,{children:s.jsxs(Ye,{children:[s.jsx(pe,{children:"Key"}),s.jsx(pe,{children:"Requests"}),s.jsx(pe,{children:"Tokens"})]})}),s.jsxs(Fn,{children:[o.topApiKeys.length===0&&s.jsx(Ye,{children:s.jsx(fe,{colSpan:3,className:"text-muted-foreground text-center",children:"No data"})}),o.topApiKeys.map((j,C)=>s.jsxs(Ye,{children:[s.jsx(fe,{className:"text-xs",children:j.name}),s.jsx(fe,{className:"text-xs",children:At(j.requests)}),s.jsx(fe,{className:"text-xs",children:At(j.totalTokens)})]},C))]})]})})]})]})]}),s.jsx("div",{className:"mt-6",children:s.jsx(W_,{successRate:v.successRate,averageLatencyMs:v.averageLatencyMs,latencySpark:E})})]})}function tD(){const[a,l]=p.useState([]),[o,i]=p.useState(0);return p.useEffect(()=>{Se.get("/api/admin/audit?limit=200").then(c=>{l(c.rows),i(c.total)})},[]),s.jsxs("div",{children:[s.jsx(wa,{title:"Audit Logs",description:`${o} entries · immutable`}),s.jsxs(Ze,{children:[s.jsx(Je,{children:s.jsx(We,{className:"text-base",children:"All entries"})}),s.jsx(et,{children:s.jsxs(Kn,{children:[s.jsx(Xn,{children:s.jsxs(Ye,{children:[s.jsx(pe,{children:"Time"}),s.jsx(pe,{children:"Action"}),s.jsx(pe,{children:"Status"}),s.jsx(pe,{children:"Target"}),s.jsx(pe,{children:"IP"}),s.jsx(pe,{children:"Actor"})]})}),s.jsxs(Fn,{children:[a.length===0&&s.jsx(Ye,{children:s.jsx(fe,{colSpan:6,className:"text-center text-muted-foreground",children:"No audit events yet."})}),a.map(c=>s.jsxs(Ye,{children:[s.jsx(fe,{className:"text-xs",children:Th(c.createdAt)}),s.jsx(fe,{className:"font-mono text-xs",children:c.action}),s.jsx(fe,{children:c.success?s.jsx(Qe,{variant:"success",children:"ok"}):s.jsx(Qe,{variant:"destructive",children:"fail"})}),s.jsx(fe,{className:"text-xs",children:c.targetName??c.targetId??"—"}),s.jsx(fe,{className:"text-xs",children:c.ip}),s.jsx(fe,{className:"text-xs",children:c.actor})]},c.id))]})]})})]})]})}const hh={enabled:!0,sound:!0};let To=hh,mh=!1,dc=null;const ph=new Set;function D1(){for(const a of ph)a()}function O1(a=!1){return mh&&!a?Promise.resolve():(!a&&dc||(dc=(async()=>{try{const l=await Se.get("/api/admin/settings");To={enabled:l.settings.notificationsEnabled??hh.enabled,sound:l.settings.notificationSoundEnabled??hh.sound},mh=!0,D1()}catch{}})()),dc)}async function xy(a){const l={};a.enabled!==void 0&&(l.notificationsEnabled=a.enabled),a.sound!==void 0&&(l.notificationSoundEnabled=a.sound),await Se.patch("/api/admin/settings",l),To={...To,...a},mh=!0,D1()}function nD(a){return ph.add(a),()=>ph.delete(a)}function k1(){return p.useSyncExternalStore(nD,()=>To,()=>To)}function aD(){const[a]=UC(),[l,o]=p.useState(null),[i,c]=p.useState(null),[d,h]=p.useState({current:"",next:""}),[m,g]=p.useState(null),[v,b]=p.useState(!1),[S,x]=p.useState("idle"),[w,E]=p.useState(null),j=async(Z=!1)=>{x("checking"),E(null);try{const oe=await Se.get(`/api/admin/update/check${Z?"?force=1":""}`);g(oe),x("idle")}catch(oe){E(oe.message),x("error")}},C=async()=>{b(!0),x("installing"),E(null);try{const Z=await Se.post("/api/admin/update/run");x("restarting"),xe.success(Z.message||"Update started — the gateway will restart shortly.");const oe=setInterval(()=>{fetch("/health").then(ie=>{ie.ok&&(clearInterval(oe),window.location.reload())}).catch(()=>{})},3e3);setTimeout(()=>clearInterval(oe),12e4)}catch(Z){xe.error(Z.message),E(Z.message),x("error")}finally{b(!1)}},[T,N]=p.useState("disabled"),[M,A]=p.useState(""),[_,z]=p.useState(""),[q,k]=p.useState(""),[W,re]=p.useState([]),[K,V]=p.useState(""),[le,se]=p.useState(""),[ce,U]=p.useState(!1),[$,ne]=p.useState(null),H=async()=>{const Z=await Se.get("/api/admin/settings");o(Z.settings);const oe=await Se.get("/api/admin/settings/system");c(oe);try{const ie=await Se.get("/api/admin/me");N(ie.totpEnabled?"enabled":"disabled")}catch{}};if(p.useEffect(()=>{O1(!0)},[]),p.useEffect(()=>{H(),j()},[]),!l)return s.jsx("div",{className:"text-muted-foreground",children:"Loading…"});const F=async Z=>{try{await Se.patch("/api/admin/settings",Z),xe.success("Saved"),H()}catch(oe){xe.error(oe.message)}},D=async()=>{try{const Z=await Se.post("/api/admin/account/totp/begin");A(Z.secret),z(Z.qr),N("setup"),xe.info("Scan the QR code with your authenticator app")}catch(Z){xe.error(Z.message)}},P=async()=>{if(!q||q.length!==6){xe.error("Enter a 6-digit code");return}try{const Z=await Se.post("/api/admin/account/totp/verify",{code:q});re(Z.recoveryCodes),N("showingRecovery"),xe.success("TOTP enabled successfully")}catch(Z){xe.error(Z.message)}},Q=async()=>{if(!K){xe.error("Enter your password");return}if(!le){xe.error("Enter a TOTP code or recovery code");return}try{await Se.post("/api/admin/account/totp/disable",{password:K,totp:le}),N("disabled"),V(""),se(""),xe.success("TOTP disabled"),H()}catch(Z){xe.error(Z.message)}},ae=async()=>{U(!0);try{const Z=await Se.post("/api/admin/account/totp/recovery/regenerate",{password:K,totp:le});re(Z.recoveryCodes),N("showingRecovery"),xe.success("Recovery codes regenerated")}catch(Z){xe.error(Z.message)}U(!1)},de=a.get("tab")||"logging";return s.jsxs("div",{children:[s.jsx(wa,{title:"Settings",description:"Logging, security, backup, and system info"}),s.jsxs(M1,{defaultValue:de,children:[s.jsxs(wm,{children:[s.jsx(Ol,{value:"logging",children:"Logging"}),s.jsx(Ol,{value:"security",children:"Security"}),s.jsx(Ol,{value:"backup",children:"Backup"}),s.jsx(Ol,{value:"system",children:"System"})]}),s.jsx(wo,{value:"logging",children:s.jsxs(Ze,{children:[s.jsx(Je,{children:s.jsx(We,{className:"text-base",children:"Logging policy"})}),s.jsxs(et,{className:"space-y-3",children:[s.jsxs("div",{className:"space-y-1",children:[s.jsx(ye,{children:"Request-content logging"}),s.jsxs(In,{value:l.contentLogMode,onValueChange:Z=>F({contentLogMode:Z}),children:[s.jsx(Rn,{children:s.jsx(Gn,{})}),s.jsxs(Nn,{children:[s.jsx(lt,{value:"off",children:"Off"}),s.jsx(lt,{value:"metadata",children:"Metadata only (default)"}),s.jsx(lt,{value:"prompt",children:"Prompt (sanitized)"}),s.jsx(lt,{value:"prompt_and_response",children:"Prompt + response (sanitized)"})]})]})]}),s.jsxs("div",{className:"space-y-1",children:[s.jsx(ye,{children:"Retention (days)"}),s.jsx(Ne,{type:"number",min:1,max:3650,value:l.retentionDays,onChange:Z=>F({retentionDays:Number(Z.target.value)})})]}),s.jsxs("div",{className:"space-y-1",children:[s.jsx(ye,{children:"Database size limit (MB)"}),s.jsx(Ne,{type:"number",min:64,value:l.dbSizeLimitMb,onChange:Z=>F({dbSizeLimitMb:Number(Z.target.value)})})]}),s.jsx("div",{className:"flex items-center gap-2 pt-2",children:s.jsx(he,{onClick:async()=>{const Z=await Se.post("/api/admin/settings/cleanup");xe.success(`Deleted ${Z.deletedRequests} old requests`)},children:"Run cleanup now"})})]})]})}),s.jsx(wo,{value:"security",children:s.jsxs(Ze,{children:[s.jsxs(Je,{children:[s.jsx(We,{className:"text-base",children:"Security"}),s.jsx(wn,{children:"Change password, 2FA, and trusted proxy configuration"})]}),s.jsxs(et,{className:"space-y-4",children:[s.jsxs("div",{className:"space-y-2",children:[s.jsx(ye,{children:"Trusted proxy hops"}),s.jsx(Ne,{type:"number",min:0,max:8,value:l.trustProxyHops,onChange:Z=>F({trustProxyHops:Number(Z.target.value)})}),s.jsx("p",{className:"text-xs text-muted-foreground",children:"0 = never trust X-Forwarded-For (direct exposure). 1+ only when behind a single trusted reverse proxy."})]}),s.jsxs("div",{className:"space-y-2 border-t pt-4",children:[s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsx(ye,{className:"text-base",children:"TOTP 2FA"}),T==="enabled"?s.jsx("span",{className:"rounded bg-green-100 px-2 py-0.5 text-xs font-medium text-green-800 dark:bg-green-900 dark:text-green-200",children:"Enabled"}):null,T==="disabled"?s.jsx("span",{className:"rounded bg-muted px-2 py-0.5 text-xs font-medium text-muted-foreground",children:"Disabled"}):null]}),T==="disabled"&&s.jsx(he,{variant:"outline",onClick:D,children:"Enable TOTP"}),T==="setup"&&s.jsxs("div",{className:"space-y-3 rounded border p-3",children:[s.jsx("p",{className:"text-sm text-muted-foreground",children:"Scan this QR code with your authenticator app, or enter the secret manually."}),_&&s.jsx("img",{src:_,alt:"TOTP QR code",className:"h-40 w-40"}),s.jsxs("div",{className:"text-xs font-mono text-muted-foreground",children:["Secret: ",M]}),s.jsxs("div",{className:"flex items-end gap-2",children:[s.jsxs("div",{className:"flex-1",children:[s.jsx(ye,{children:"Verify code"}),s.jsx(Ne,{value:q,onChange:Z=>k(Z.target.value),placeholder:"123456",maxLength:6})]}),s.jsx(he,{disabled:q.length<6,onClick:P,children:"Verify & enable"})]})]}),T==="showingRecovery"&&s.jsxs("div",{className:"space-y-3 rounded border border-amber-500/40 bg-amber-50 p-3 dark:bg-amber-950/20",children:[s.jsx("p",{className:"text-sm font-medium",children:"Recovery codes — save these now!"}),s.jsx("p",{className:"text-xs text-muted-foreground",children:"Each code can be used once to log in without your TOTP device. They will not be shown again."}),s.jsx("div",{className:"space-y-1",children:W.map((Z,oe)=>s.jsx("div",{className:"font-mono text-xs",children:Z},oe))}),s.jsx(he,{onClick:()=>{N("enabled"),xe.success("Recovery codes saved")},children:"I have saved them"})]}),T==="enabled"&&s.jsxs("div",{className:"space-y-3 rounded border p-3",children:[s.jsxs("div",{className:"grid gap-2 sm:grid-cols-2",children:[s.jsxs("div",{children:[s.jsx(ye,{children:"Password"}),s.jsx(Ne,{type:"password",value:K,onChange:Z=>V(Z.target.value),placeholder:"Current password"})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"TOTP code"}),s.jsx(Ne,{value:le,onChange:Z=>se(Z.target.value),placeholder:"123456",maxLength:6})]})]}),s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsx(he,{variant:"outline",size:"sm",disabled:ce||!K||le.length<6,onClick:ae,children:"Regenerate recovery codes"}),s.jsx(he,{variant:"destructive",size:"sm",disabled:!K||le.length<6,onClick:Q,children:"Disable TOTP"})]})]})]}),s.jsxs("div",{className:"space-y-2 border-t pt-4",children:[s.jsx(ye,{children:"Change password"}),s.jsx(Ne,{type:"password",placeholder:"Current password",value:d.current,onChange:Z=>h({...d,current:Z.target.value})}),s.jsx(Ne,{type:"password",placeholder:"New password (12+ chars)",value:d.next,onChange:Z=>h({...d,next:Z.target.value})}),s.jsx(he,{disabled:!d.current||d.next.length<12,onClick:async()=>{try{await Se.post("/api/admin/account/password",{currentPassword:d.current,newPassword:d.next}),xe.success("Password changed"),h({current:"",next:""})}catch(Z){xe.error(Z.message)}},children:"Change password"})]})]})]})}),s.jsx(wo,{value:"backup",children:s.jsxs(Ze,{children:[s.jsxs(Je,{children:[s.jsx(We,{className:"text-base",children:"Backup & restore"}),s.jsx(wn,{children:"Download a snapshot or restore from a previous backup"})]}),s.jsxs(et,{className:"space-y-3",children:[s.jsx(he,{onClick:async()=>{try{const Z=await fetch("/api/admin/backup/create",{method:"POST",credentials:"include"});if(!Z.ok)throw new Error("Backup failed");const oe=await Z.blob(),ie=URL.createObjectURL(oe),me=document.createElement("a");me.href=ie,me.download="latedev-backup.json",me.click(),URL.revokeObjectURL(ie),xe.success("Backup downloaded")}catch(Z){xe.error(Z.message)}},children:"Download backup"}),s.jsxs(r1,{open:$!==null,onOpenChange:Z=>{Z||ne(null)},children:[s.jsx(gA,{asChild:!0,children:s.jsxs("div",{children:[s.jsx(ye,{children:"Restore from backup file"}),s.jsx(Ne,{type:"file",accept:".json,application/json","data-testid":"restore-file",onChange:Z=>{var ie;const oe=(ie=Z.target.files)==null?void 0:ie[0];ne(oe??null)}})]})}),s.jsxs(nm,{children:[s.jsxs(o1,{children:[s.jsx(am,{children:"Restore backup?"}),s.jsxs(lm,{children:["Restoring will replace the entire current database with the selected backup (",($==null?void 0:$.name)??"file","). This cannot be undone. A snapshot of the current database is kept for rollback only if validation fails."]})]}),s.jsxs(i1,{children:[s.jsx(sm,{children:"Cancel"}),s.jsx(rm,{onClick:async()=>{var oe,ie;const Z=$;if(Z)try{const me=await fetch("/api/admin/backup/restore",{method:"POST",body:Z,credentials:"include",headers:{"content-type":"application/json"}});if(!me.ok)throw new Error(((ie=(oe=await me.json())==null?void 0:oe.error)==null?void 0:ie.message)??"Restore failed");xe.success("Restored. Reloading…"),ne(null),setTimeout(()=>location.reload(),600)}catch(me){xe.error(me.message)}},children:"Restore"})]})]})]})]})]})}),s.jsxs(wo,{value:"system",children:[s.jsxs(Ze,{children:[s.jsx(Je,{children:s.jsx(We,{className:"text-base",children:"System"})}),s.jsxs(et,{className:"space-y-2 text-sm",children:[s.jsxs("div",{children:[s.jsx("span",{className:"text-muted-foreground",children:"App version:"})," ",i==null?void 0:i.appVersion]}),s.jsxs("div",{children:[s.jsx("span",{className:"text-muted-foreground",children:"Data directory:"})," ",s.jsx("span",{className:"font-mono",children:i==null?void 0:i.dataDir})]}),s.jsxs("div",{children:[s.jsx("span",{className:"text-muted-foreground",children:"Encryption:"})," ",i!=null&&i.masterKeyConfigured?"Configured":"Not configured"," (v",i==null?void 0:i.masterKeyVersion,")"]}),s.jsxs("div",{children:[s.jsx("span",{className:"text-muted-foreground",children:"Environment:"})," ",i==null?void 0:i.environment]}),s.jsxs("div",{className:"flex items-center gap-2 pt-2",children:[s.jsx(ba,{checked:l.gatewayCacheEnabled,onCheckedChange:Z=>F({gatewayCacheEnabled:Z})}),s.jsx(ye,{children:"Gateway response cache (disabled by default)"})]}),s.jsxs("div",{className:"grid grid-cols-2 gap-2",children:[s.jsxs("div",{children:[s.jsx(ye,{children:"Cache TTL (s)"}),s.jsx(Ne,{type:"number",min:1,value:l.gatewayCacheDefaultTtlSeconds,onChange:Z=>F({gatewayCacheDefaultTtlSeconds:Number(Z.target.value)})})]}),s.jsxs("div",{children:[s.jsx(ye,{children:"Cache max size (MB)"}),s.jsx(Ne,{type:"number",min:1,value:l.gatewayCacheMaxSizeMb,onChange:Z=>F({gatewayCacheMaxSizeMb:Number(Z.target.value)})})]})]}),s.jsx(he,{variant:"outline",onClick:async()=>{const Z=await Se.post("/api/admin/settings/cache/clear");xe.success(`Cleared ${Z.deleted} entries`)},children:"Clear gateway cache"})]})]}),s.jsx(lD,{}),s.jsxs(Ze,{className:"mt-4",children:[s.jsxs(Je,{children:[s.jsx(We,{className:"text-base",children:"Updates"}),s.jsx(wn,{children:"Automatic updates from the npm registry"})]}),s.jsxs(et,{className:"space-y-3 text-sm",children:[S==="checking"&&!m&&s.jsxs("div",{className:"flex items-center gap-2 text-muted-foreground",children:[s.jsx(jo,{className:"h-4 w-4 animate-spin"})," Checking for updates…"]}),m&&s.jsxs(s.Fragment,{children:[s.jsxs("div",{className:"flex flex-wrap items-center gap-4",children:[s.jsxs("div",{children:[s.jsx("div",{className:"text-xs text-muted-foreground",children:"Current version"}),s.jsxs("div",{className:"font-mono",children:["v",m.currentVersion]})]}),s.jsx("span",{className:"text-muted-foreground",children:"→"}),s.jsxs("div",{children:[s.jsx("div",{className:"text-xs text-muted-foreground",children:"Latest version"}),s.jsx("div",{className:"font-mono",children:m.latestVersion?`v${m.latestVersion}`:"—"})]}),m.status.docker?s.jsx(Qe,{variant:"secondary",children:m.status.watchtower?"Docker + Watchtower":"Docker"}):m.latestVersion===null?s.jsx(Qe,{variant:"secondary",children:"Registry unreachable"}):m.hasUpdate?s.jsx(Qe,{variant:"success",children:"Update available"}):s.jsxs(Qe,{variant:"outline",children:[s.jsx(Ac,{className:"mr-1 h-3 w-3"})," Up to date"]})]}),m.status.docker&&m.status.watchtower&&m.watchtowerReachable&&s.jsx("p",{className:"text-muted-foreground",children:"Watchtower pulls new images automatically every hour — or use Update now for an instant update."}),m.status.docker&&m.status.watchtower&&m.watchtowerReachable===!1&&s.jsxs("p",{className:"text-muted-foreground",children:["The Watchtower sidecar is configured but not running — start it with ",s.jsx("code",{className:"rounded bg-muted px-1 text-xs",children:"docker compose --profile updater up -d"}),"."]}),m.status.docker&&!m.status.watchtower&&s.jsx("p",{className:"text-muted-foreground",children:m.status.reason??"This instance runs in Docker — update by pulling the new image tag."}),!m.status.docker&&m.latestVersion===null&&s.jsxs("p",{className:"text-muted-foreground",children:["Could not reach the npm registry (offline or blocked). ",w&&s.jsx("span",{className:"text-destructive",children:w})]}),S==="installing"&&s.jsxs("div",{className:"flex items-center gap-2 text-muted-foreground",children:[s.jsx(jo,{className:"h-4 w-4 animate-spin"})," Applying the update… this can take a minute."]}),S==="restarting"&&s.jsxs("div",{className:"flex items-center gap-2 text-muted-foreground",children:[s.jsx(jo,{className:"h-4 w-4 animate-spin"})," Update applied — the gateway is restarting on the new version. This page reloads automatically."]}),s.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[m.hasUpdate&&S==="idle"&&(!m.status.docker||m.status.watchtower&&m.watchtowerReachable!==!1)&&s.jsxs(he,{disabled:v||m.status.docker&&m.watchtowerReachable===!1,onClick:C,children:[s.jsx(Ky,{className:"mr-1 h-4 w-4"})," Update now"]}),m.hasUpdate&&m.changelogUrl&&s.jsx(he,{variant:"outline",asChild:!0,children:s.jsx("a",{href:m.changelogUrl,target:"_blank",rel:"noreferrer",children:"View changes"})}),S==="idle"&&s.jsx(he,{variant:"ghost",disabled:v,onClick:()=>j(!0),children:"Check again"})]})]})]})]})]})]})]})}function lD(){const a=k1();return s.jsxs(Ze,{className:"mt-4",children:[s.jsx(Je,{children:s.jsxs(We,{className:"text-base flex items-center gap-2",children:[s.jsx(ZC,{className:"h-4 w-4"})," Notifications"]})}),s.jsxs(et,{className:"space-y-3 text-sm",children:[s.jsxs("div",{className:"flex items-center justify-between",children:[s.jsx("span",{children:"Show request notifications"}),s.jsx(ba,{checked:a.enabled,onCheckedChange:l=>void xy({enabled:l})})]}),s.jsxs("div",{className:"flex items-center justify-between",children:[s.jsxs("span",{className:"flex items-center gap-1",children:[s.jsx(b2,{className:"h-3 w-3"})," Play notification sound"]}),s.jsx(ba,{checked:a.sound,onCheckedChange:l=>void xy({sound:l})})]}),s.jsx("p",{className:"text-xs text-muted-foreground mt-2",children:"Notifications are disabled while muted. Changes apply immediately."})]})]})}function rD({items:a,onDismiss:l}){return a.length?s.jsx("div",{className:"fixed top-16 right-4 z-50 flex max-h-[calc(100vh-8rem)] w-80 flex-col gap-2 overflow-y-auto",children:a.map(o=>{const i=!o.success,c=o.success&&o.totalLatencyMs>15e3,d=je("rounded-md border shadow-lg transition-all",i&&"bg-destructive text-destructive-foreground border-destructive",c&&"bg-amber-500/90 text-amber-950 border-amber-600/50",!i&&!c&&"bg-card text-card-foreground border-border");return s.jsxs(ur,{to:"/requests",className:je("block shrink-0 p-3 hover:opacity-95",d),children:[s.jsxs("div",{className:"flex items-start justify-between gap-2",children:[s.jsxs("div",{className:"flex min-w-0 flex-1 items-center gap-2",children:[i?s.jsx(t2,{className:"h-4 w-4 shrink-0"}):o.success?s.jsx(Ac,{className:"h-4 w-4 shrink-0"}):s.jsx(S2,{className:"h-4 w-4 shrink-0 opacity-70"}),s.jsx("div",{className:"min-w-0 truncate text-sm font-medium",title:o.requestedModel,children:o.requestedModel})]}),s.jsx("button",{className:"shrink-0 opacity-60 hover:opacity-100",onClick:h=>{h.preventDefault(),h.stopPropagation(),l(o.id)},"aria-label":"Dismiss",type:"button",children:s.jsx(Dc,{className:"h-3.5 w-3.5"})})]}),s.jsxs("div",{className:"mt-1 text-xs",children:[o.success?"Thành công":"Thất bại",!o.success&&o.errorType&&s.jsx("span",{className:"ml-1 inline-block rounded bg-black/15 px-1 py-0.5 align-text-bottom text-[10px]",children:o.errorType})]}),s.jsxs("div",{className:"mt-1 text-[11px] opacity-90",children:["in ",At(o.inputTokens)," · out ",At(o.outputTokens),(o.cacheReadTokens>0||o.cacheWriteTokens>0)&&s.jsxs(s.Fragment,{children:[" · cache ",o.cacheReadTokens>0&&s.jsxs("span",{children:["r",At(o.cacheReadTokens)]}),o.cacheReadTokens>0&&o.cacheWriteTokens>0&&"/",o.cacheWriteTokens>0&&s.jsxs("span",{children:["w",At(o.cacheWriteTokens)]})]})]}),s.jsxs("div",{className:"mt-1 text-[11px] opacity-90",children:[dr(o.totalLatencyMs),o.ttftMs!=null&&o.ttftMs>=0&&s.jsxs("span",{children:[" · TTFT ",dr(o.ttftMs)]})]})]},o.id)})}):null}const sD=5e3,oD=8,iD=3e3;let fc=null;function cD(){try{fc||(fc=new Audio("/notification.mp3")),fc.currentTime=0,fc.play().catch(()=>{})}catch{}}function uD(){const[a,l]=p.useState([]),o=p.useRef(null),i=p.useRef(new Map),c=p.useRef(Date.now()),d=k1(),h=p.useRef(d.sound);h.current=d.sound,p.useEffect(()=>{O1()},[]);const m=d.enabled;return p.useEffect(()=>{var x;if(!m){(x=o.current)==null||x.close(),o.current=null;const w=i.current;for(const E of w.values())clearTimeout(E);w.clear(),l([]);return}let v=!1;const b=i.current,S=()=>{if(v)return;const w=new EventSource(`/api/admin/requests/stream?since=${c.current}`);o.current=w,w.addEventListener("request",E=>{if(!v)try{const j=JSON.parse(E.data),C=new Date(j.createdAt).getTime();Number.isFinite(C)&&(c.current=Math.max(c.current,C)),l(N=>N.some(M=>M.id===j.id)?N:[j,...N].slice(0,oD));const T=setTimeout(()=>{l(N=>N.filter(M=>M.id!==j.id)),b.delete(j.id)},sD);b.set(j.id,T),h.current&&cD()}catch{}}),w.onerror=()=>{w.close(),o.current=null,v||setTimeout(S,iD)}};return S(),()=>{var w;v=!0,(w=o.current)==null||w.close(),o.current=null;for(const E of b.values())clearTimeout(E);b.clear()}},[m]),{items:a,dismiss:v=>{const b=i.current.get(v);b&&(clearTimeout(b),i.current.delete(v)),l(S=>S.filter(x=>x.id!==v))}}}function dD({children:a}){const{user:l,loading:o}=Rh(),i=un();return o?s.jsx("div",{className:"flex h-screen items-center justify-center text-muted-foreground",children:"Loading…"}):l?s.jsx(s.Fragment,{children:a}):s.jsx(qf,{to:"/login",state:{from:i},replace:!0})}function fD(){const{items:a,dismiss:l}=uD();return s.jsxs("div",{className:"flex h-screen bg-background text-foreground",children:[s.jsx(aE,{}),s.jsxs("div",{className:"flex flex-1 flex-col overflow-hidden",children:[s.jsx(lM,{}),s.jsx("main",{className:"flex-1 overflow-auto p-6",children:s.jsxs(By,{children:[s.jsx(rn,{index:!0,element:s.jsx(HM,{})}),s.jsx(rn,{path:"/providers",element:s.jsx(d_,{})}),s.jsx(rn,{path:"/models",element:s.jsx(S_,{})}),s.jsx(rn,{path:"/combos",element:s.jsx(w_,{})}),s.jsx(rn,{path:"/aliases",element:s.jsx(j_,{})}),s.jsx(rn,{path:"/api-keys",element:s.jsx(C_,{})}),s.jsx(rn,{path:"/requests",element:s.jsx(N_,{})}),s.jsx(rn,{path:"/statistics",element:s.jsx(eD,{})}),s.jsx(rn,{path:"/audit",element:s.jsx(tD,{})}),s.jsx(rn,{path:"/settings/*",element:s.jsx(aD,{})})]})})]}),s.jsx(rD,{items:a,onDismiss:l})]})}function hD({children:a}){const[l,o]=p.useState(null),i=un();return p.useEffect(()=>{Se.get("/api/admin/setup/status").then(c=>o(c.setupComplete)).catch(()=>o(!0))},[]),l===null?s.jsx("div",{className:"flex h-screen items-center justify-center text-muted-foreground",children:"Loading…"}):!l&&i.pathname!=="/setup"?s.jsx(qf,{to:"/setup",replace:!0}):l&&i.pathname==="/setup"?s.jsx(qf,{to:"/",replace:!0}):s.jsx(s.Fragment,{children:a})}function mD(){return s.jsx($C,{children:s.jsx(hD,{children:s.jsxs(By,{children:[s.jsx(rn,{path:"/setup",element:s.jsx(LM,{})}),s.jsx(rn,{path:"/login",element:s.jsx(zM,{})}),s.jsx(rn,{path:"/*",element:s.jsx(dD,{children:s.jsx(fD,{})})})]})})})}const pD=kM;var gD=Object.defineProperty,on=(a,l)=>gD(a,"name",{value:l,configurable:!0}),[jm,XD]=dn("Tooltip",[Cs]),vD=Cs(),xD="TooltipProvider",yD=700,yy="tooltip.open",[bD,SD]=jm(xD),wD=on(a=>{const{__scopeTooltip:l,delayDuration:o=yD,skipDelayDuration:i=300,disableHoverableContent:c=!1,children:d}=a,h=p.useRef(!0),m=p.useRef(!1),g=p.useRef(0);return p.useEffect(()=>{const v=g.current;return()=>window.clearTimeout(v)},[]),s.jsx(bD,{scope:l,isOpenDelayedRef:h,delayDuration:o,onOpen:p.useCallback(()=>{i<=0||(window.clearTimeout(g.current),h.current=!1)},[i]),onClose:p.useCallback(()=>{i<=0||(window.clearTimeout(g.current),g.current=window.setTimeout(()=>h.current=!0,i))},[i]),isPointerInTransitRef:m,onPointerInTransitChange:p.useCallback(v=>{m.current=v},[]),disableHoverableContent:c,children:d})},"TooltipProvider"),jD="Tooltip",[FD,Cm]=jm(jD),CD="TooltipPortal",[QD,ED]=jm(CD,{forceMount:void 0}),Mo="TooltipContent",RD=p.forwardRef(on(function(l,o){const i=ED(Mo,l.__scopeTooltip),{forceMount:c=i.forceMount,side:d="top",...h}=l,m=Cm(Mo,l.__scopeTooltip);return s.jsx(nl,{present:c||m.open,children:m.disableHoverableContent?s.jsx(z1,{side:d,...h,ref:o}):s.jsx(ND,{side:d,...h,ref:o})})},"TooltipContent")),ND=p.forwardRef(on(function(l,o){const i=Cm(Mo,l.__scopeTooltip),c=SD(Mo,l.__scopeTooltip),d=p.useRef(null),h=Ve(o,d),[m,g]=p.useState(null),{trigger:v,onClose:b}=i,S=d.current,{onPointerInTransitChange:x}=c,w=p.useCallback(()=>{g(null),x(!1)},[x]),E=p.useCallback((j,C)=>{const T=j.currentTarget,N={x:j.clientX,y:j.clientY},M=L1(N,T.getBoundingClientRect()),A=U1(N,M),_=H1(C.getBoundingClientRect()),z=P1([...A,..._]);g(z),x(!0)},[x]);return p.useEffect(()=>()=>w(),[w]),p.useEffect(()=>{if(v&&S){const j=on(T=>E(T,S),"handleTriggerLeave"),C=on(T=>E(T,v),"handleContentLeave");return v.addEventListener("pointerleave",j),S.addEventListener("pointerleave",C),()=>{v.removeEventListener("pointerleave",j),S.removeEventListener("pointerleave",C)}}},[v,S,E,w]),p.useEffect(()=>{if(m){const j=on(C=>{const T=C.target,N={x:C.clientX,y:C.clientY},M=(v==null?void 0:v.contains(T))||(S==null?void 0:S.contains(T)),A=!B1(N,m);M?w():A&&(w(),b())},"handleTrackPointerGrace");return document.addEventListener("pointermove",j),()=>document.removeEventListener("pointermove",j)}},[v,S,m,b,w]),s.jsx(z1,{...l,ref:h})},"TooltipContentHoverable")),TD=ib("TooltipContent"),z1=p.forwardRef(on(function(l,o){const{__scopeTooltip:i,children:c,"aria-label":d,id:h,onEscapeKeyDown:m,onPointerDownOutside:g,...v}=l,b=Cm(Mo,i),S=vD(i),{onClose:x}=b;p.useEffect(()=>(document.addEventListener(yy,x),()=>document.removeEventListener(yy,x)),[x]),p.useEffect(()=>{if(b.trigger){const E=on(j=>{j.target instanceof Node&&j.target.contains(b.trigger)&&x()},"handleScroll");return window.addEventListener("scroll",E,{capture:!0}),()=>window.removeEventListener("scroll",E,{capture:!0})}},[b.trigger,x]);const{setContentId:w}=b;return _t(()=>(w(h),()=>{w(void 0)}),[h,w]),s.jsx(zc,{asChild:!0,disableOutsidePointerEvents:!1,onEscapeKeyDown:m,onPointerDownOutside:g,onFocusOutside:E=>E.preventDefault(),onDismiss:x,children:s.jsxs(Vh,{"data-state":b.stateAttribute,role:d?void 0:"tooltip",id:d?void 0:b.contentId,...S,...v,ref:o,style:{...v.style,"--radix-tooltip-content-transform-origin":"var(--radix-popper-transform-origin)","--radix-tooltip-content-available-width":"var(--radix-popper-available-width)","--radix-tooltip-content-available-height":"var(--radix-popper-available-height)","--radix-tooltip-trigger-width":"var(--radix-popper-anchor-width)","--radix-tooltip-trigger-height":"var(--radix-popper-anchor-height)"},children:[s.jsx(TD,{children:c}),d?s.jsx(EA,{id:b.contentId,role:"tooltip",children:d}):null]})})},"TooltipContentImpl"));function L1(a,l){const o=Math.abs(l.top-a.y),i=Math.abs(l.bottom-a.y),c=Math.abs(l.right-a.x),d=Math.abs(l.left-a.x);switch(Math.min(o,i,c,d)){case d:return"left";case c:return"right";case o:return"top";case i:return"bottom";default:throw new Error("unreachable")}}on(L1,"getExitSideFromRect");function U1(a,l,o=5){const i=[];switch(l){case"top":i.push({x:a.x-o,y:a.y+o},{x:a.x+o,y:a.y+o});break;case"bottom":i.push({x:a.x-o,y:a.y-o},{x:a.x+o,y:a.y-o});break;case"left":i.push({x:a.x+o,y:a.y-o},{x:a.x+o,y:a.y+o});break;case"right":i.push({x:a.x-o,y:a.y-o},{x:a.x-o,y:a.y+o});break}return i}on(U1,"getPaddedExitPoints");function H1(a){const{top:l,right:o,bottom:i,left:c}=a;return[{x:c,y:l},{x:o,y:l},{x:o,y:i},{x:c,y:i}]}on(H1,"getPointsFromRect");function B1(a,l){const{x:o,y:i}=a;let c=!1;for(let d=0,h=l.length-1;d<l.length;h=d++){const m=l[d],g=l[h],v=m.x,b=m.y,S=g.x,x=g.y;b>i!=x>i&&o<(S-v)*(i-b)/(x-b)+v&&(c=!c)}return c}on(B1,"isPointInPolygon");function P1(a){const l=a.slice();return l.sort((o,i)=>o.x<i.x?-1:o.x>i.x?1:o.y<i.y?-1:o.y>i.y?1:0),q1(l)}on(P1,"getHull");function q1(a){if(a.length<=1)return a.slice();const l=[];for(let i=0;i<a.length;i++){const c=a[i];for(;l.length>=2;){const d=l[l.length-1],h=l[l.length-2];if((d.x-h.x)*(c.y-h.y)>=(d.y-h.y)*(c.x-h.x))l.pop();else break}l.push(c)}l.pop();const o=[];for(let i=a.length-1;i>=0;i--){const c=a[i];for(;o.length>=2;){const d=o[o.length-1],h=o[o.length-2];if((d.x-h.x)*(c.y-h.y)>=(d.y-h.y)*(c.x-h.x))o.pop();else break}o.push(c)}return o.pop(),l.length===1&&o.length===1&&l[0].x===o[0].x&&l[0].y===o[0].y?l:l.concat(o)}on(q1,"getHullPresorted");var MD=wD,V1=RD;const AD=MD,_D=p.forwardRef(({className:a,sideOffset:l=4,...o},i)=>s.jsx(V1,{ref:i,sideOffset:l,className:je("z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground animate-in fade-in-0 zoom-in-95",a),...o}));_D.displayName=V1.displayName;uj.createRoot(document.getElementById("root")).render(s.jsx(ue.StrictMode,{children:s.jsx(fE,{defaultTheme:"dark",storageKey:"latedev-theme",children:s.jsxs(AD,{children:[s.jsx(OC,{children:s.jsx(mD,{})}),s.jsx(pD,{position:"top-right"})]})})}));
|
package/dist/web/index.html
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
<meta name="color-scheme" content="light dark" />
|
|
8
8
|
<title>LateDev Router</title>
|
|
9
|
-
<script type="module" crossorigin src="/assets/index-
|
|
9
|
+
<script type="module" crossorigin src="/assets/index-CHg2RW0K.js"></script>
|
|
10
10
|
<link rel="stylesheet" crossorigin href="/assets/index-BprlMazL.css">
|
|
11
11
|
</head>
|
|
12
12
|
<body>
|