diff --git a/docs/dashboard.md b/docs/dashboard.md index cdc4d53b..24009c24 100644 --- a/docs/dashboard.md +++ b/docs/dashboard.md @@ -157,6 +157,10 @@ gateway. - **Activity**: the per-request log of what the gateway served, with filters. Use it to inspect individual requests, their models, and their outcomes. + Requests the gateway refused are logged too, so filtering to the `error` + status shows what is being dropped, including requests rejected for having no + pricing under `require_pricing`. Diagnostic detail stays in the gateway logs + rather than the browser. - **Usage**: aggregate usage and analytics, showing spend and volume over time, broken down by model and by user. diff --git a/src/gateway/api/routes/_passthrough.py b/src/gateway/api/routes/_passthrough.py index 18b9fc11..ea64d0ff 100644 --- a/src/gateway/api/routes/_passthrough.py +++ b/src/gateway/api/routes/_passthrough.py @@ -219,9 +219,28 @@ async def run_passthrough( and pricing_required_but_missing(pricing, require_pricing=config.require_pricing) ): await refund_reservation(db, reservation) + no_pricing_detail = no_pricing_error_detail(model) + # Record the rejection so dropped traffic is visible in the activity + # log and countable as an error, rather than only reaching the + # operator as a user complaint. cost stays null: nothing was spent. + await log_writer.put( + UsageLog( + id=str(uuid.uuid4()), + api_key_id=api_key_id, + user_id=user_id, + timestamp=datetime.now(UTC), + model=resolved.model, + provider=resolved.instance, + endpoint=endpoint, + status="error", + error_message=no_pricing_detail, + latency_ms=_elapsed_ms(started_at), + counts_toward_budget=not budget_exempt, + ) + ) raise HTTPException( status_code=status.HTTP_402_PAYMENT_REQUIRED, - detail=no_pricing_error_detail(model), + detail=no_pricing_detail, ) # Model access control (per-key). The reservation is already taken above (the diff --git a/src/gateway/api/routes/_pipeline.py b/src/gateway/api/routes/_pipeline.py index 95c3a262..b9a92469 100644 --- a/src/gateway/api/routes/_pipeline.py +++ b/src/gateway/api/routes/_pipeline.py @@ -710,9 +710,28 @@ async def resolve_request_context( # cost=null when unpriced. if not budget_exempt and pricing_required_but_missing(gate_pricing, require_pricing=config.require_pricing): await refund_reservation(db, reservation) + no_pricing_detail = no_pricing_error_detail(model) + # Record the rejection before raising. Gateway-side rejections used to + # leave no trace, so an operator who flipped require_pricing on had no + # way to see that live traffic was being dropped (only a user complaint + # would tell them). The row carries cost=null: nothing was spent, so it + # never affects spend or the budget, it just makes the drop visible in + # the activity log and countable as an error. + await log_usage( + db=db, + log_writer=log_writer, + api_key_id=api_key_id, + model=model, + provider=gate_instance, + endpoint=adapter.endpoint, + user_id=user_id, + error=no_pricing_detail, + latency_ms=_elapsed_ms(started_at), + counts_toward_budget=not budget_exempt, + ) raise adapter.error( 402, - no_pricing_error_detail(model), + no_pricing_detail, ErrorKind.INVALID_REQUEST, ) diff --git a/src/gateway/static/dashboard/assets/ActivityPage-C5gSmqNJ.js b/src/gateway/static/dashboard/assets/ActivityPage-C5gSmqNJ.js new file mode 100644 index 00000000..03b61aa5 --- /dev/null +++ b/src/gateway/static/dashboard/assets/ActivityPage-C5gSmqNJ.js @@ -0,0 +1 @@ +import{j as s}from"./tanstack-query-1t81HyiD.js";import{u as Ve,r as i}from"./react-dgEcD0HR.js";import{u as Ze,a as Je,b as Qe,c as fe,d as _e,f as w,e as Xe,A as L,g as et,h as tt,P as st,E as at,C as ye,i as j,R as rt,F as ve,j as H,k as je,Y as lt}from"./index-Bi2hajrg.js";import{A as nt,F as ot}from"./FilterChips-Dqy1SR3R.js";import{u as it,r as ct,B as dt}from"./tableSelection-9hV37uhu.js";import{C as ut}from"./ConfirmDialog-ChuHp-Qm.js";import{D as mt}from"./DataTable-Bmn_eYSV.js";import{T as pt,S as gt,P as ht}from"./TablePagination-8CBn4us4.js";import{B as V}from"./heroui-BI50yK5B.js";import"./recharts-C4kRDmvS.js";function xt(t){const[l,n]=Ve(),a=i.useCallback(g=>l.get(g)??t[g],[l,t]),o=i.useCallback(g=>{const u=Number.parseInt(l.get(g)??"",10);if(!Number.isNaN(u))return u;const c=Number.parseInt(t[g],10);return Number.isNaN(c)?0:c},[l,t]),k=i.useCallback(g=>{n(u=>{const c=new URLSearchParams(u);for(const[p,x]of Object.entries(g)){const f=String(x);f===""||f===t[p]?c.delete(p):c.set(p,f)}return c},{replace:!0})},[n,t]);return{get:a,getNumber:o,patch:k}}const bt=new Intl.NumberFormat(void 0,{style:"currency",currency:"USD",maximumFractionDigits:4});function O(t){return t===null?"—":bt.format(t)}function v(t){return t===null?"—":t.toLocaleString()}function we(t){return t===null?"—":t<1e3?`${t} ms`:`${(t/1e3).toFixed(t<1e4?2:1)} s`}function ft(t){const l=new Date(t);return Number.isNaN(l.getTime())?t:l.toLocaleString()}function _t(t){const l=new Date(t).getTime();if(Number.isNaN(l))return t;const n=Math.max(0,Math.round((Date.now()-l)/1e3));if(n<60)return`${n}s ago`;const a=Math.round(n/60);if(a<60)return`${a}m ago`;const o=Math.round(a/60);return o<24?`${o}h ago`:`${Math.round(o/24)}d ago`}const vt=t=>t.id,kt=t=>t.status==="error"?"bg-red-50":void 0,ke=[{label:"All",value:""},{label:"Success",value:"success"},{label:"Error",value:"error"}],Se=[{label:"All",value:""},{label:"Priced",value:"true"},{label:"Unpriced",value:"false"}],St=50,yt={range:L,start_date:"",end_date:"",status:"",model:"",user_id:"",api_key_id:"",priced:"",source:"",page:"0",size:String(St)};function U(t,l,n){if(l||n)return{start:l||void 0,end:n||void 0};if(t===ye)return{};const a=w(j,t)??w(j,L),o=(a==null?void 0:a.seconds)??null;return{start:o==null?void 0:je(o),end:void 0}}function Z(t){const l=U(t,"","");if(l.start)return l;const n=w(j,t);return(n==null?void 0:n.seconds)==null?{start:je(lt)}:l}function jt({status:t}){const l=t==="error"?"border-red-200 bg-red-50 text-red-700":"border-[var(--otari-line)] bg-[var(--otari-brand-tint)] text-[var(--otari-brand-dark)]";return s.jsx("span",{className:`inline-flex items-center rounded-full border px-2 py-0.5 text-xs font-medium ${l}`,children:t})}const wt={gateway:"Gateway",claude_code:"Claude Code",codex:"Codex"};function Ce(t){return wt[t]??t}function d({label:t,children:l}){return s.jsxs("div",{className:"flex flex-col gap-0.5",children:[s.jsx("span",{className:"text-[11px] font-medium uppercase tracking-wide text-[var(--otari-muted)]",children:t}),s.jsx("span",{className:"text-sm text-[var(--otari-ink)] break-all",children:l})]})}function Ct({entry:t}){var l;return s.jsxs("div",{className:"flex flex-col gap-4 px-4 py-4",children:[t.error_message?s.jsxs("div",{className:"flex flex-col gap-1.5",children:[s.jsx("span",{className:"text-[11px] font-medium uppercase tracking-wide text-[var(--otari-muted)]",children:"Error"}),s.jsx("pre",{className:"max-h-48 overflow-auto rounded-lg border border-red-200 bg-red-50 p-3 text-xs whitespace-pre-wrap break-all text-red-700",children:"This request failed. Inspect gateway logs for details."})]}):null,s.jsxs("div",{className:"grid gap-4 sm:grid-cols-2 lg:grid-cols-4",children:[s.jsx(d,{label:"Provider",children:t.provider??"—"}),s.jsx(d,{label:"Endpoint",children:t.endpoint}),s.jsx(d,{label:"Source",children:Ce(t.source)}),t.source_label?s.jsx(d,{label:"Session",children:t.source_label}):null,s.jsx(d,{label:"User",children:t.user_id??"—"}),s.jsx(d,{label:"API key",children:t.api_key_id??"—"}),s.jsx(d,{label:"Prompt tokens",children:v(t.prompt_tokens)}),s.jsx(d,{label:"Completion tokens",children:v(t.completion_tokens)}),s.jsx(d,{label:"Total tokens",children:v(t.total_tokens)}),s.jsx(d,{label:"Cost",children:O(t.cost)}),s.jsx(d,{label:"Cache read tokens",children:v(t.cache_read_tokens)}),s.jsx(d,{label:"Cache write tokens",children:v(t.cache_write_tokens)}),s.jsx(d,{label:"1h cache writes",children:v(t.cache_write_1h_tokens??null)}),s.jsx(d,{label:"Total time",children:we(t.latency_ms)}),s.jsx(d,{label:"Request ID",children:t.id})]}),(l=t.pricing_breakdown)!=null&&l.length?s.jsxs("div",{className:"flex flex-col gap-2",children:[s.jsx("span",{className:"text-[11px] font-medium uppercase tracking-wide text-[var(--otari-muted)]",children:"Billed meters"}),s.jsx("div",{className:"grid gap-2 sm:grid-cols-2 lg:grid-cols-3",children:t.pricing_breakdown.map(n=>s.jsxs(d,{label:n.meter.replaceAll("_"," "),children:[v(n.units)," at ",O(n.rate_per_million)," / 1M, ",O(n.cost)]},n.meter))})]}):null]})}function Rt(){var me,pe,ge,he,xe;const t=Ze(),l=Je(),n=i.useMemo(()=>{const e=new Map;for(const r of l.data??[])e.set(r.id,r.key_name??`${r.id.slice(0,8)}…`);return e},[l.data]),a=xt(yt),o=a.get("range"),k=a.get("start_date"),g=a.get("end_date"),u=a.get("status"),c=a.get("model"),p=a.get("user_id"),x=a.get("api_key_id"),f=a.get("priced"),_=a.get("source"),J=Math.max(0,a.getNumber("page")),Q=a.getNumber("size"),R=ht.reduce((e,r)=>Math.abs(r-Q)U(o,k,g));i.useEffect(()=>{X(U(o,k,g))},[o,k,g]);const[E,ee]=i.useState(()=>Z(o));i.useEffect(()=>{ee(Z(o))},[o]);const F=f==="true"?!0:f==="false"?!1:void 0,b=i.useMemo(()=>({start_date:m.start,end_date:m.end,status:u||void 0,model:c.trim()||void 0,user_id:p||void 0,api_key_id:x||void 0,source:_||void 0,priced:F}),[m,u,c,p,x,_,F]),h=it(),M=JSON.stringify(b),te=i.useRef(M);i.useEffect(()=>{te.current!==M&&(te.current=M,a.patch({page:0}),h.clear())},[M,a,h]);const S=Qe(b,J,R),C=fe(b),Pe=i.useMemo(()=>({start_date:m.start,end_date:m.end,status:u||void 0,user_id:p||void 0,api_key_id:x||void 0,source:_||void 0}),[m,u,p,x,_]),se=_e(Pe,"day"),K=((pe=(me=se.data)==null?void 0:me.by_model)==null?void 0:pe.filter(e=>!e.is_other&&e.key!==null).map(e=>e.key))??[],ae=(l.data??[]).map(e=>({value:e.id,label:e.key_name??`${e.id.slice(0,8)}…`})),P=w(j,o)??w(j,L),N=!!(m.start&&E.start&&new Date(m.start).getTime()({start_date:N?m.start:E.start,end_date:N?m.end:void 0,status:u||void 0,model:c.trim()||void 0,user_id:p||void 0,api_key_id:x||void 0,source:_||void 0,priced:F}),[N,m,E,u,c,p,x,_,F]),B=_e(Ae,re),Ee=(((ge=B.data)==null?void 0:ge.series)??[]).map(e=>({bucketStart:e.bucket_start,requests:e.requests})),y=S.data??[],Fe=C.isSuccess&&!C.isPlaceholderData?((he=C.data)==null?void 0:he.total)??0:null,$=w(j,o),Me=!!(k||g)||o!==L&&($==null?void 0:$.seconds)!=null,Te=!!(u||c.trim()||p||x||f||_||Me),T=(e,r)=>{var be;return((be=e.find(He=>He.value===r))==null?void 0:be.label)??r},le=(t.data??[]).map(e=>({value:e.user_id,label:e.alias?`${e.alias} (${e.user_id})`:e.user_id})),De=()=>a.patch({status:"",priced:"",model:"",user_id:"",api_key_id:"",source:""}),Ie=[...u?[{key:"status",label:"Status",value:T(ke,u),onClear:()=>a.patch({status:""})}]:[],...f?[{key:"priced",label:"Priced",value:T(Se,f),onClear:()=>a.patch({priced:""})}]:[],...p?[{key:"user",label:"User",value:T(le,p),onClear:()=>a.patch({user_id:""})}]:[],...c.trim()?[{key:"model",label:"Model",value:c.trim(),onClear:()=>a.patch({model:""})}]:[],...x?[{key:"key",label:"API key",value:T(ae,x),onClear:()=>a.patch({api_key_id:""})}]:[],..._?[{key:"source",label:"Source",value:Ce(_),onClear:()=>a.patch({source:""})}]:[]],q=i.useMemo(()=>y.filter(e=>!e.counts_toward_budget).map(e=>e.id),[y]),Oe=i.useMemo(()=>y.filter(e=>e.counts_toward_budget).map(e=>e.id),[y]),ne=ct(h.selectedKeys,q),A=ne.length,oe=h.allMatching||A>0,Ue=i.useMemo(()=>({...b,counts_toward_budget:!1}),[b]),ie=fe(Ue,oe),D=ie.isSuccess?((xe=ie.data)==null?void 0:xe.total)??null:null,Le=q.length>0&&A===q.length&&D!=null&&D>A,I=h.allMatching?D??A:A,z=et(),W=tt(),[Re,Y]=i.useState(!1),[Ke,G]=i.useState(!1),[Be,ce]=i.useState(null),$e=i.useCallback(e=>s.jsxs("div",{children:[s.jsxs("div",{className:"flex items-center justify-between border-b border-[var(--otari-line)] px-4 py-2",children:[s.jsx("span",{className:"text-sm font-medium text-[var(--otari-ink)]",children:"Request detail"}),s.jsx(V,{size:"sm",variant:"ghost",onPress:()=>ce(null),children:"Close"})]}),s.jsx(Ct,{entry:e})]}),[]),de=()=>h.allMatching?{by_filter:!0,model:b.model,user_id:b.user_id,api_key_id:b.api_key_id,status:b.status,start_date:b.start_date,end_date:b.end_date,priced:b.priced}:{ids:ne},qe=()=>{z.mutate(de(),{onSuccess:()=>{Y(!1),h.clear()}})},ze=e=>{W.mutate({...de(),...e},{onSuccess:()=>{G(!1),h.clear()}})},We=()=>{X(U(o,k,g)),ee(Z(o)),S.refetch(),C.refetch(),B.refetch(),se.refetch()},ue=e=>a.patch({range:e.key,start_date:"",end_date:""}),Ye=(e,r)=>a.patch({start_date:e,end_date:r}),Ge=i.useMemo(()=>{const e=r=>r===null?"—":n.get(r)??`${r.slice(0,8)}…`;return[{id:"time",header:"Time",cell:r=>s.jsx("span",{title:ft(r.timestamp),className:"text-[var(--otari-muted)]",children:_t(r.timestamp)})},{id:"user",header:"User",cell:r=>r.user_id??"—"},{id:"model",header:"Model",isRowHeader:!0,cell:r=>r.model},{id:"api_key",header:"API key",cell:r=>s.jsx("span",{className:"text-[var(--otari-muted)]",children:e(r.api_key_id)})},{id:"tokens",header:"Tokens",align:"end",cell:r=>v(r.total_tokens)},{id:"cost",header:"Cost",align:"end",cell:r=>O(r.cost)},{id:"latency",header:"Total time",align:"end",cell:r=>we(r.latency_ms)},{id:"status",header:"Status",cell:r=>s.jsx(jt,{status:r.status})}]},[n]);return s.jsxs("div",{className:"flex flex-col gap-6",children:[s.jsx(st,{title:"Activity",description:"A per-request log of what the gateway served: tokens, cost, latency, and failures. No request or response content is stored."}),s.jsx(at,{error:S.error??C.error}),s.jsxs("div",{className:"flex flex-col gap-3",children:[s.jsx(nt,{presets:j,extentKey:Ne,onPreset:ue,onSelectRange:Ye,onSelectFull:()=>P?ue(P):void 0,series:Ee,bucket:re,windowStart:m.start,windowEnd:m.end,loading:B.isLoading,ariaLabel:"Activity request volume over the selected window",action:s.jsx(rt,{onRefresh:We,isFetching:S.isFetching,updatedAt:S.dataUpdatedAt})}),s.jsxs(ot,{chips:Ie,onClearAll:De,children:[s.jsx(ve,{id:"filter-status",label:"Status",value:u,onChange:e=>a.patch({status:e}),children:ke.map(e=>s.jsx("option",{value:e.value,children:e.label},e.value))}),s.jsx(ve,{id:"filter-priced",label:"Priced?",value:f,onChange:e=>a.patch({priced:e}),children:Se.map(e=>s.jsx("option",{value:e.value,children:e.label},e.value))}),s.jsx(H,{label:"API key",value:x,onChange:e=>a.patch({api_key_id:e}),placeholder:"All keys",options:ae}),s.jsx(H,{label:"User",value:p,onChange:e=>a.patch({user_id:e}),placeholder:"All users",options:le}),s.jsx(H,{label:"Model",value:c,onChange:e=>a.patch({model:e}),allowsCustom:!0,placeholder:"Any model",options:(c&&!K.includes(c)?[c,...K]:K).map(e=>({value:e,label:e}))})]})]}),oe?s.jsxs(dt,{selectedCount:I,allMatching:h.allMatching,matchingTotal:D,canSelectAllMatching:Le,onSelectAllMatching:h.enableAllMatching,onClear:h.clear,children:[s.jsx(V,{size:"sm",variant:"primary",onPress:()=>G(!0),children:"Set price"}),s.jsx(V,{size:"sm",variant:"danger",onPress:()=>Y(!0),children:"Delete"})]}):null,s.jsx(mt,{ariaLabel:"Activity log",columns:Ge,rows:y,getRowKey:vt,isLoading:S.isLoading,emptyContent:Te?"No requests match these filters.":"No requests recorded yet.",selectionMode:"multiple",selectedKeys:h.selectedKeys,onSelectionChange:h.onSelectionChange,disabledKeys:Oe,onRowAction:e=>ce(r=>r===e?null:e),rowClassName:kt,detailKey:Be,renderDetail:$e}),s.jsx(pt,{page:J,pageSize:R,total:Fe,rowsOnPage:y.length,onPageChange:e=>a.patch({page:e}),onPageSizeChange:e=>a.patch({size:e,page:0}),isFetching:S.isFetching,hasNextFallback:y.length===R}),s.jsx(ut,{isOpen:Re,onOpenChange:Y,heading:"Delete usage rows",body:`Delete ${I.toLocaleString()} imported ${I===1?"row":"rows"}? Only imported rows are removed, and this cannot be undone.`,confirmLabel:"Delete",isPending:z.isPending,error:z.error,onConfirm:qe}),s.jsx(gt,{isOpen:Ke,onOpenChange:G,targetCount:I,isPending:W.isPending,error:W.error,onSubmit:ze})]})}export{Rt as ActivityPage}; diff --git a/src/gateway/static/dashboard/assets/ActivityPage-DsPiQv1J.js b/src/gateway/static/dashboard/assets/ActivityPage-DsPiQv1J.js deleted file mode 100644 index a8cf9a2a..00000000 --- a/src/gateway/static/dashboard/assets/ActivityPage-DsPiQv1J.js +++ /dev/null @@ -1 +0,0 @@ -import{j as s}from"./tanstack-query-1t81HyiD.js";import{u as Ge,r as i}from"./react-dgEcD0HR.js";import{u as He,a as Ve,b as Ze,c as be,d as fe,e as Je,f as Qe,P as Xe,E as et,R as tt,F as _e,g as G}from"./index-D4f8RVEq.js";import{f as j,b as st,A as U,a as at,C as ke,c as y,F as rt,i as ye,Y as lt}from"./FilterChips-DtSH11eU.js";import{u as nt,r as ot,B as it}from"./tableSelection-9hV37uhu.js";import{C as ct}from"./ConfirmDialog-a8LQxZuS.js";import{D as dt}from"./DataTable-Bmn_eYSV.js";import{T as ut,S as mt,P as pt}from"./TablePagination-BTOqrUVz.js";import{B as H}from"./heroui-BI50yK5B.js";import"./recharts-C4kRDmvS.js";function gt(t){const[l,n]=Ge(),a=i.useCallback(g=>l.get(g)??t[g],[l,t]),o=i.useCallback(g=>{const u=Number.parseInt(l.get(g)??"",10);if(!Number.isNaN(u))return u;const c=Number.parseInt(t[g],10);return Number.isNaN(c)?0:c},[l,t]),v=i.useCallback(g=>{n(u=>{const c=new URLSearchParams(u);for(const[p,x]of Object.entries(g)){const f=String(x);f===""||f===t[p]?c.delete(p):c.set(p,f)}return c},{replace:!0})},[n,t]);return{get:a,getNumber:o,patch:v}}const ht=new Intl.NumberFormat(void 0,{style:"currency",currency:"USD",maximumFractionDigits:4});function I(t){return t===null?"—":ht.format(t)}function _(t){return t===null?"—":t.toLocaleString()}function je(t){return t===null?"—":t<1e3?`${t} ms`:`${(t/1e3).toFixed(t<1e4?2:1)} s`}function xt(t){const l=new Date(t);return Number.isNaN(l.getTime())?t:l.toLocaleString()}function bt(t){const l=new Date(t).getTime();if(Number.isNaN(l))return t;const n=Math.max(0,Math.round((Date.now()-l)/1e3));if(n<60)return`${n}s ago`;const a=Math.round(n/60);if(a<60)return`${a}m ago`;const o=Math.round(a/60);return o<24?`${o}h ago`:`${Math.round(o/24)}d ago`}const ft=t=>t.id,_t=t=>t.status==="error"?"bg-red-50":void 0,ve=[{label:"All",value:""},{label:"Success",value:"success"},{label:"Error",value:"error"}],Se=[{label:"All",value:""},{label:"Priced",value:"true"},{label:"Unpriced",value:"false"}],vt=50,St={range:U,start_date:"",end_date:"",status:"",model:"",user_id:"",api_key_id:"",priced:"",page:"0",size:String(vt)};function O(t,l,n){if(l||n)return{start:l||void 0,end:n||void 0};if(t===ke)return{};const a=j(y,t)??j(y,U),o=(a==null?void 0:a.seconds)??null;return{start:o==null?void 0:ye(o),end:void 0}}function V(t){const l=O(t,"","");if(l.start)return l;const n=j(y,t);return(n==null?void 0:n.seconds)==null?{start:ye(lt)}:l}function kt({status:t}){const l=t==="error"?"border-red-200 bg-red-50 text-red-700":"border-[var(--otari-line)] bg-[var(--otari-brand-tint)] text-[var(--otari-brand-dark)]";return s.jsx("span",{className:`inline-flex items-center rounded-full border px-2 py-0.5 text-xs font-medium ${l}`,children:t})}const yt={gateway:"Gateway",claude_code:"Claude Code",codex:"Codex"};function jt(t){return yt[t]??t}function d({label:t,children:l}){return s.jsxs("div",{className:"flex flex-col gap-0.5",children:[s.jsx("span",{className:"text-[11px] font-medium uppercase tracking-wide text-[var(--otari-muted)]",children:t}),s.jsx("span",{className:"text-sm text-[var(--otari-ink)] break-all",children:l})]})}function wt({entry:t}){var l;return s.jsxs("div",{className:"flex flex-col gap-4 px-4 py-4",children:[t.error_message?s.jsxs("div",{className:"flex flex-col gap-1.5",children:[s.jsx("span",{className:"text-[11px] font-medium uppercase tracking-wide text-[var(--otari-muted)]",children:"Error"}),s.jsx("pre",{className:"max-h-48 overflow-auto rounded-lg border border-red-200 bg-red-50 p-3 text-xs whitespace-pre-wrap break-all text-red-700",children:"The provider returned an error. Inspect gateway logs for details."})]}):null,s.jsxs("div",{className:"grid gap-4 sm:grid-cols-2 lg:grid-cols-4",children:[s.jsx(d,{label:"Provider",children:t.provider??"—"}),s.jsx(d,{label:"Endpoint",children:t.endpoint}),s.jsx(d,{label:"Source",children:jt(t.source)}),t.source_label?s.jsx(d,{label:"Session",children:t.source_label}):null,s.jsx(d,{label:"User",children:t.user_id??"—"}),s.jsx(d,{label:"API key",children:t.api_key_id??"—"}),s.jsx(d,{label:"Prompt tokens",children:_(t.prompt_tokens)}),s.jsx(d,{label:"Completion tokens",children:_(t.completion_tokens)}),s.jsx(d,{label:"Total tokens",children:_(t.total_tokens)}),s.jsx(d,{label:"Cost",children:I(t.cost)}),s.jsx(d,{label:"Cache read tokens",children:_(t.cache_read_tokens)}),s.jsx(d,{label:"Cache write tokens",children:_(t.cache_write_tokens)}),s.jsx(d,{label:"1h cache writes",children:_(t.cache_write_1h_tokens??null)}),s.jsx(d,{label:"Total time",children:je(t.latency_ms)}),s.jsx(d,{label:"Request ID",children:t.id})]}),(l=t.pricing_breakdown)!=null&&l.length?s.jsxs("div",{className:"flex flex-col gap-2",children:[s.jsx("span",{className:"text-[11px] font-medium uppercase tracking-wide text-[var(--otari-muted)]",children:"Billed meters"}),s.jsx("div",{className:"grid gap-2 sm:grid-cols-2 lg:grid-cols-3",children:t.pricing_breakdown.map(n=>s.jsxs(d,{label:n.meter.replaceAll("_"," "),children:[_(n.units)," at ",I(n.rate_per_million)," / 1M, ",I(n.cost)]},n.meter))})]}):null]})}function Lt(){var ue,me,pe,ge,he;const t=He(),l=Ve(),n=i.useMemo(()=>{const e=new Map;for(const r of l.data??[])e.set(r.id,r.key_name??`${r.id.slice(0,8)}…`);return e},[l.data]),a=gt(St),o=a.get("range"),v=a.get("start_date"),g=a.get("end_date"),u=a.get("status"),c=a.get("model"),p=a.get("user_id"),x=a.get("api_key_id"),f=a.get("priced"),Z=Math.max(0,a.getNumber("page")),J=a.getNumber("size"),L=pt.reduce((e,r)=>Math.abs(r-J)O(o,v,g));i.useEffect(()=>{Q(O(o,v,g))},[o,v,g]);const[A,X]=i.useState(()=>V(o));i.useEffect(()=>{X(V(o))},[o]);const E=f==="true"?!0:f==="false"?!1:void 0,b=i.useMemo(()=>({start_date:m.start,end_date:m.end,status:u||void 0,model:c.trim()||void 0,user_id:p||void 0,api_key_id:x||void 0,priced:E}),[m,u,c,p,x,E]),h=nt(),F=JSON.stringify(b),ee=i.useRef(F);i.useEffect(()=>{ee.current!==F&&(ee.current=F,a.patch({page:0}),h.clear())},[F,a,h]);const S=Ze(b,Z,L),w=be(b),we=i.useMemo(()=>({start_date:m.start,end_date:m.end,status:u||void 0,user_id:p||void 0,api_key_id:x||void 0}),[m,u,p,x]),te=fe(we,"day"),R=((me=(ue=te.data)==null?void 0:ue.by_model)==null?void 0:me.filter(e=>!e.is_other&&e.key!==null).map(e=>e.key))??[],se=(l.data??[]).map(e=>({value:e.id,label:e.key_name??`${e.id.slice(0,8)}…`})),C=j(y,o)??j(y,U),P=!!(m.start&&A.start&&new Date(m.start).getTime()({start_date:P?m.start:A.start,end_date:P?m.end:void 0,status:u||void 0,model:c.trim()||void 0,user_id:p||void 0,api_key_id:x||void 0,priced:E}),[P,m,A,u,c,p,x,E]),K=fe(Pe,ae),Ne=(((pe=K.data)==null?void 0:pe.series)??[]).map(e=>({bucketStart:e.bucket_start,requests:e.requests})),k=S.data??[],Ae=w.isSuccess&&!w.isPlaceholderData?((ge=w.data)==null?void 0:ge.total)??0:null,B=j(y,o),Ee=!!(v||g)||o!==U&&(B==null?void 0:B.seconds)!=null,Fe=!!(u||c.trim()||p||x||f||Ee),M=(e,r)=>{var xe;return((xe=e.find(Ye=>Ye.value===r))==null?void 0:xe.label)??r},re=(t.data??[]).map(e=>({value:e.user_id,label:e.alias?`${e.alias} (${e.user_id})`:e.user_id})),Me=()=>a.patch({status:"",priced:"",model:"",user_id:"",api_key_id:""}),Te=[...u?[{key:"status",label:"Status",value:M(ve,u),onClear:()=>a.patch({status:""})}]:[],...f?[{key:"priced",label:"Priced",value:M(Se,f),onClear:()=>a.patch({priced:""})}]:[],...p?[{key:"user",label:"User",value:M(re,p),onClear:()=>a.patch({user_id:""})}]:[],...c.trim()?[{key:"model",label:"Model",value:c.trim(),onClear:()=>a.patch({model:""})}]:[],...x?[{key:"key",label:"API key",value:M(se,x),onClear:()=>a.patch({api_key_id:""})}]:[]],$=i.useMemo(()=>k.filter(e=>!e.counts_toward_budget).map(e=>e.id),[k]),De=i.useMemo(()=>k.filter(e=>e.counts_toward_budget).map(e=>e.id),[k]),le=ot(h.selectedKeys,$),N=le.length,ne=h.allMatching||N>0,Ie=i.useMemo(()=>({...b,counts_toward_budget:!1}),[b]),oe=be(Ie,ne),T=oe.isSuccess?((he=oe.data)==null?void 0:he.total)??null:null,Oe=$.length>0&&N===$.length&&T!=null&&T>N,D=h.allMatching?T??N:N,q=Je(),z=Qe(),[Ue,W]=i.useState(!1),[Le,Y]=i.useState(!1),[Re,ie]=i.useState(null),Ke=i.useCallback(e=>s.jsxs("div",{children:[s.jsxs("div",{className:"flex items-center justify-between border-b border-[var(--otari-line)] px-4 py-2",children:[s.jsx("span",{className:"text-sm font-medium text-[var(--otari-ink)]",children:"Request detail"}),s.jsx(H,{size:"sm",variant:"ghost",onPress:()=>ie(null),children:"Close"})]}),s.jsx(wt,{entry:e})]}),[]),ce=()=>h.allMatching?{by_filter:!0,model:b.model,user_id:b.user_id,api_key_id:b.api_key_id,status:b.status,start_date:b.start_date,end_date:b.end_date,priced:b.priced}:{ids:le},Be=()=>{q.mutate(ce(),{onSuccess:()=>{W(!1),h.clear()}})},$e=e=>{z.mutate({...ce(),...e},{onSuccess:()=>{Y(!1),h.clear()}})},qe=()=>{Q(O(o,v,g)),X(V(o)),S.refetch(),w.refetch(),K.refetch(),te.refetch()},de=e=>a.patch({range:e.key,start_date:"",end_date:""}),ze=(e,r)=>a.patch({start_date:e,end_date:r}),We=i.useMemo(()=>{const e=r=>r===null?"—":n.get(r)??`${r.slice(0,8)}…`;return[{id:"time",header:"Time",cell:r=>s.jsx("span",{title:xt(r.timestamp),className:"text-[var(--otari-muted)]",children:bt(r.timestamp)})},{id:"user",header:"User",cell:r=>r.user_id??"—"},{id:"model",header:"Model",isRowHeader:!0,cell:r=>r.model},{id:"api_key",header:"API key",cell:r=>s.jsx("span",{className:"text-[var(--otari-muted)]",children:e(r.api_key_id)})},{id:"tokens",header:"Tokens",align:"end",cell:r=>_(r.total_tokens)},{id:"cost",header:"Cost",align:"end",cell:r=>I(r.cost)},{id:"latency",header:"Total time",align:"end",cell:r=>je(r.latency_ms)},{id:"status",header:"Status",cell:r=>s.jsx(kt,{status:r.status})}]},[n]);return s.jsxs("div",{className:"flex flex-col gap-6",children:[s.jsx(Xe,{title:"Activity",description:"A per-request log of what the gateway served: tokens, cost, latency, and failures. No request or response content is stored."}),s.jsx(et,{error:S.error??w.error}),s.jsxs("div",{className:"flex flex-col gap-3",children:[s.jsx(at,{presets:y,extentKey:Ce,onPreset:de,onSelectRange:ze,onSelectFull:()=>C?de(C):void 0,series:Ne,bucket:ae,windowStart:m.start,windowEnd:m.end,loading:K.isLoading,ariaLabel:"Activity request volume over the selected window",action:s.jsx(tt,{onRefresh:qe,isFetching:S.isFetching,updatedAt:S.dataUpdatedAt})}),s.jsxs(rt,{chips:Te,onClearAll:Me,children:[s.jsx(_e,{id:"filter-status",label:"Status",value:u,onChange:e=>a.patch({status:e}),children:ve.map(e=>s.jsx("option",{value:e.value,children:e.label},e.value))}),s.jsx(_e,{id:"filter-priced",label:"Priced?",value:f,onChange:e=>a.patch({priced:e}),children:Se.map(e=>s.jsx("option",{value:e.value,children:e.label},e.value))}),s.jsx(G,{label:"API key",value:x,onChange:e=>a.patch({api_key_id:e}),placeholder:"All keys",options:se}),s.jsx(G,{label:"User",value:p,onChange:e=>a.patch({user_id:e}),placeholder:"All users",options:re}),s.jsx(G,{label:"Model",value:c,onChange:e=>a.patch({model:e}),allowsCustom:!0,placeholder:"Any model",options:(c&&!R.includes(c)?[c,...R]:R).map(e=>({value:e,label:e}))})]})]}),ne?s.jsxs(it,{selectedCount:D,allMatching:h.allMatching,matchingTotal:T,canSelectAllMatching:Oe,onSelectAllMatching:h.enableAllMatching,onClear:h.clear,children:[s.jsx(H,{size:"sm",variant:"primary",onPress:()=>Y(!0),children:"Set price"}),s.jsx(H,{size:"sm",variant:"danger",onPress:()=>W(!0),children:"Delete"})]}):null,s.jsx(dt,{ariaLabel:"Activity log",columns:We,rows:k,getRowKey:ft,isLoading:S.isLoading,emptyContent:Fe?"No requests match these filters.":"No requests recorded yet.",selectionMode:"multiple",selectedKeys:h.selectedKeys,onSelectionChange:h.onSelectionChange,disabledKeys:De,onRowAction:e=>ie(r=>r===e?null:e),rowClassName:_t,detailKey:Re,renderDetail:Ke}),s.jsx(ut,{page:Z,pageSize:L,total:Ae,rowsOnPage:k.length,onPageChange:e=>a.patch({page:e}),onPageSizeChange:e=>a.patch({size:e,page:0}),isFetching:S.isFetching,hasNextFallback:k.length===L}),s.jsx(ct,{isOpen:Ue,onOpenChange:W,heading:"Delete usage rows",body:`Delete ${D.toLocaleString()} imported ${D===1?"row":"rows"}? Only imported rows are removed, and this cannot be undone.`,confirmLabel:"Delete",isPending:q.isPending,error:q.error,onConfirm:Be}),s.jsx(mt,{isOpen:Le,onOpenChange:Y,targetCount:D,isPending:z.isPending,error:z.error,onSubmit:$e})]})}export{Lt as ActivityPage}; diff --git a/src/gateway/static/dashboard/assets/AliasesPage-BTmc50Jm.js b/src/gateway/static/dashboard/assets/AliasesPage-D7ZKXX3I.js similarity index 92% rename from src/gateway/static/dashboard/assets/AliasesPage-BTmc50Jm.js rename to src/gateway/static/dashboard/assets/AliasesPage-D7ZKXX3I.js index dcbd0115..860365f5 100644 --- a/src/gateway/static/dashboard/assets/AliasesPage-BTmc50Jm.js +++ b/src/gateway/static/dashboard/assets/AliasesPage-D7ZKXX3I.js @@ -1 +1 @@ -import{j as e}from"./tanstack-query-1t81HyiD.js";import{r as u,u as L}from"./react-dgEcD0HR.js";import{h as T,i as I,j as M,C as R,P as K,E as w,k as P,u as F}from"./index-D4f8RVEq.js";import{u as O,r as $,B as U}from"./tableSelection-9hV37uhu.js";import{C as q}from"./ConfirmDialog-a8LQxZuS.js";import{D as H}from"./DataTable-Bmn_eYSV.js";import{F as V}from"./Field-Dwp6u3t8.js";import{C as k,L as z,I as G,a as J,b as W,f as X,B as j,d as A}from"./heroui-BI50yK5B.js";import{U as Q}from"./UserComboBox-a9wxf8eF.js";const Y=50;function B({label:t,value:a,onChange:n,description:r,placeholder:c="provider:model",autoFocus:l,isRequired:d}){const o=T(),{visible:m,total:h,failed:x}=u.useMemo(()=>{var N;const i=a.trim().toLowerCase(),v=((N=o.data)==null?void 0:N.providers)??[],b=v.flatMap(f=>f.models),p=i?b.filter(f=>f.key.toLowerCase().includes(i)):b;return{visible:p.slice(0,Y),total:p.length,failed:v.filter(f=>!f.ok)}},[o.data,a]),g=o.isLoading?"Loading models from your providers…":x.length>0?`Could not list models for ${x.map(v=>v.provider).join(", ")}. Check that provider's credentials, or type the model key directly.`:h>m.length?`Showing ${m.length} of ${h} matches. Keep typing to narrow them.`:r;return e.jsxs(k.Root,{allowsCustomValue:!0,allowsEmptyCollection:!0,menuTrigger:"input",inputValue:a,onInputChange:n,onSelectionChange:i=>{i!=null&&n(String(i))},isRequired:d,className:"flex max-w-md flex-col gap-1",children:[e.jsx(z,{className:"text-sm font-medium text-[var(--otari-ink)]",children:t}),e.jsxs(k.InputGroup,{children:[e.jsx(G,{placeholder:c,autoFocus:l}),e.jsx(k.Trigger,{})]}),e.jsx(k.Popover,{children:e.jsx(J,{items:m,className:"max-h-72 overflow-auto",children:i=>e.jsx(W,{id:i.key,textValue:i.key,children:i.key})})}),g?e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:g}):null]})}const S=t=>JSON.stringify([t.user_id,t.name]);function Z({userId:t,onChange:a}){const n=F(),r=t!==null,c=(l,d)=>e.jsx("button",{type:"button","aria-pressed":r===l,onClick:()=>a(l?"":null),className:r===l?"rounded-md bg-white px-3 py-1.5 text-sm font-medium text-[var(--otari-ink)] shadow-sm":"rounded-md px-3 py-1.5 text-sm text-[var(--otari-muted)] hover:text-[var(--otari-ink)]",children:d});return e.jsxs("div",{className:"flex flex-col gap-3",children:[e.jsxs("div",{children:[e.jsx("span",{className:"text-sm font-medium text-[var(--otari-ink)]",children:"Applies to"}),e.jsx("p",{className:"text-xs text-[var(--otari-muted)]",children:"A global alias resolves for every caller. A user-scoped one resolves only for that user, and takes precedence over a global alias of the same name."})]}),e.jsxs("div",{className:"flex w-fit items-center gap-1 rounded-lg bg-[var(--otari-bg)] p-1",children:[c(!1,"Every caller"),c(!0,"One user")]}),r?e.jsx(Q,{label:"User",value:t??"",onChange:a,users:n.data??[],placeholder:"Pick a user…",description:"Only this user resolves the alias.",unknownHint:e.jsx("span",{className:"text-red-700",children:"No such user. Pick an existing one."})}):null]})}function ee({alias:t,onClose:a}){const n=P(),[r,c]=u.useState(t.target),l=r.trim()!==""&&r.trim()!==t.target,d=()=>{l&&n.mutate({name:t.name,target:r.trim(),user_id:t.user_id},{onSuccess:a})};return e.jsx(A,{children:e.jsxs(A.Content,{className:"flex flex-col gap-4 p-5",children:[e.jsxs("div",{className:"text-sm font-semibold text-[var(--otari-ink)]",children:["Edit alias ",e.jsx("code",{children:t.name}),t.user_id?e.jsxs(e.Fragment,{children:[" for user ",e.jsx("code",{children:t.user_id})]}):null]}),e.jsx(w,{error:n.error}),e.jsxs("div",{className:"grid gap-4 sm:grid-cols-2",children:[e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx("span",{className:"text-sm font-medium text-[var(--otari-ink)]",children:"Alias name"}),e.jsx("code",{className:"text-sm text-[var(--otari-muted)]",children:t.name}),e.jsxs("span",{className:"text-xs text-[var(--otari-muted)]",children:["The alias name and who it applies to (",t.user_id?e.jsx("code",{children:t.user_id}):"every caller",") are the key and cannot be changed here. Delete and recreate to change either."]})]}),e.jsx(B,{label:"Target",value:r,onChange:c,isRequired:!0,description:"The real model this resolves to. Callers never see it."})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(j,{variant:"primary",isDisabled:!l||n.isPending,onPress:d,children:n.isPending?"Saving…":"Save changes"}),e.jsx(j,{variant:"ghost",onPress:a,children:"Cancel"})]})]})})}function se({onClose:t,initialTarget:a=""}){const n=P(),[r,c]=u.useState(""),[l,d]=u.useState(a),[o,m]=u.useState(null),h=/[:/]/.test(r),x=o===null||o.trim()!=="",g=r.trim()!==""&&l.trim()!==""&&!h&&x,i=()=>{g&&n.mutate({name:r.trim(),target:l.trim(),user_id:o===null?null:o.trim()},{onSuccess:t})};return e.jsx(A,{children:e.jsxs(A.Content,{className:"flex flex-col gap-4 p-5",children:[e.jsx("div",{className:"text-sm font-semibold text-[var(--otari-ink)]",children:"New alias"}),e.jsx(w,{error:n.error}),e.jsxs("div",{className:"grid gap-4 sm:grid-cols-2",children:[e.jsx(V,{label:"Alias name",value:r,onChange:c,placeholder:"fast-model",isRequired:!0,autoFocus:!0,description:h?e.jsx("span",{className:"text-red-700",children:"An alias name cannot contain “:” or “/”."}):"What callers send as `model`."}),e.jsx(B,{label:"Target",value:l,onChange:d,isRequired:!0,description:"The real model this resolves to. Callers never see it."})]}),e.jsx(Z,{userId:o,onChange:m}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(j,{variant:"primary",isDisabled:!g||n.isPending,onPress:i,children:n.isPending?"Creating…":"Create alias"}),e.jsx(j,{variant:"ghost",onPress:t,children:"Cancel"})]})]})})}function me(){const t=I(),a=M(),[n]=L(),r=n.get("target")??"",[c,l]=u.useState(r!==""),[d,o]=u.useState(null),m=O(),[h,x]=u.useState(!1),[g,i]=u.useState(void 0),[v,b]=u.useState(!1),p=[...t.data??[]].sort((s,C)=>s.name.localeCompare(C.name)||(s.user_id??"").localeCompare(C.user_id??"")),N=p.filter(s=>s.source==="stored").map(S),f=p.filter(s=>s.source!=="stored").map(S),y=$(m.selectedKeys,N),D=new Map(p.map(s=>[S(s),s])),_=async()=>{b(!0),i(void 0);try{for(const s of y){const C=D.get(s);C!==void 0&&await a.mutateAsync({name:C.name,userId:C.user_id})}m.clear(),x(!1)}catch(s){i(s)}finally{b(!1)}},E=u.useMemo(()=>[{id:"alias",header:"Alias",isRowHeader:!0,cell:s=>e.jsx("span",{className:"font-medium break-all text-[var(--otari-ink)]",children:s.name})},{id:"target",header:"Target",cell:s=>e.jsx("span",{className:"break-all text-[var(--otari-muted)]",children:s.target})},{id:"scope",header:"Applies to",cell:s=>s.user_id?e.jsx("code",{className:"break-all text-xs text-[var(--otari-ink)]",children:s.user_id}):e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"Every caller"})},{id:"source",header:"Source",cell:s=>e.jsx(X,{size:"sm",color:s.source==="stored"?"accent":"default",children:s.source})},{id:"actions",header:"Actions",align:"end",cell:s=>s.source==="stored"?e.jsxs("span",{className:"inline-flex items-center gap-2 whitespace-nowrap",children:[e.jsx(j,{size:"sm",variant:"ghost",onPress:()=>{l(!1),o(s)},children:"Edit"}),e.jsx(R,{confirmLabel:"Delete",isPending:a.isPending,onConfirm:()=>a.mutate({name:s.name,userId:s.user_id}),children:"Delete"})]}):e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"set in config.yml"})}],[a.isPending,a.mutate]);return e.jsxs("div",{className:"flex flex-col gap-6",children:[e.jsx(K,{title:"Aliases",description:"Friendly names that map to a real provider:model. Callers send the alias as the model; pricing, budgets, and usage key on the target.",action:c||d?null:e.jsx(j,{variant:"primary",onPress:()=>{o(null),l(!0)},children:"New alias"})}),e.jsx(w,{error:t.error}),c?e.jsx(se,{initialTarget:r,onClose:()=>l(!1)}):null,d?e.jsx(ee,{alias:d,onClose:()=>o(null)}):null,a.error?e.jsx(w,{error:a.error}):null,y.length>0?e.jsx(U,{selectedCount:y.length,allMatching:!1,matchingTotal:null,canSelectAllMatching:!1,onSelectAllMatching:()=>{},onClear:m.clear,children:e.jsx(j,{size:"sm",variant:"danger",onPress:()=>x(!0),children:"Delete"})}):null,e.jsx(H,{ariaLabel:"Aliases",columns:E,rows:p,getRowKey:S,isLoading:t.isLoading,emptyContent:"No aliases yet. Create one to give a model a friendly name.",selectionMode:"multiple",selectedKeys:m.selectedKeys,onSelectionChange:m.onSelectionChange,disabledKeys:f}),e.jsx(q,{isOpen:h,onOpenChange:x,heading:"Delete aliases",body:`Delete ${y.length} stored ${y.length===1?"alias":"aliases"}? Callers using ${y.length===1?"it":"them"} will get a model-not-found error.`,confirmLabel:"Delete",isPending:v,error:g,onConfirm:_})]})}export{me as AliasesPage}; +import{j as e}from"./tanstack-query-1t81HyiD.js";import{r as u,u as L}from"./react-dgEcD0HR.js";import{l as T,m as I,n as M,o as R,P as K,E as w,p as P,u as F}from"./index-Bi2hajrg.js";import{u as O,r as $,B as U}from"./tableSelection-9hV37uhu.js";import{C as q}from"./ConfirmDialog-ChuHp-Qm.js";import{D as H}from"./DataTable-Bmn_eYSV.js";import{F as V}from"./Field-Dwp6u3t8.js";import{C as k,L as z,I as G,a as J,b as W,f as X,B as j,d as A}from"./heroui-BI50yK5B.js";import{U as Q}from"./UserComboBox-a9wxf8eF.js";const Y=50;function B({label:t,value:a,onChange:n,description:r,placeholder:c="provider:model",autoFocus:l,isRequired:d}){const o=T(),{visible:m,total:h,failed:x}=u.useMemo(()=>{var N;const i=a.trim().toLowerCase(),v=((N=o.data)==null?void 0:N.providers)??[],C=v.flatMap(f=>f.models),p=i?C.filter(f=>f.key.toLowerCase().includes(i)):C;return{visible:p.slice(0,Y),total:p.length,failed:v.filter(f=>!f.ok)}},[o.data,a]),g=o.isLoading?"Loading models from your providers…":x.length>0?`Could not list models for ${x.map(v=>v.provider).join(", ")}. Check that provider's credentials, or type the model key directly.`:h>m.length?`Showing ${m.length} of ${h} matches. Keep typing to narrow them.`:r;return e.jsxs(k.Root,{allowsCustomValue:!0,allowsEmptyCollection:!0,menuTrigger:"input",inputValue:a,onInputChange:n,onSelectionChange:i=>{i!=null&&n(String(i))},isRequired:d,className:"flex max-w-md flex-col gap-1",children:[e.jsx(z,{className:"text-sm font-medium text-[var(--otari-ink)]",children:t}),e.jsxs(k.InputGroup,{children:[e.jsx(G,{placeholder:c,autoFocus:l}),e.jsx(k.Trigger,{})]}),e.jsx(k.Popover,{children:e.jsx(J,{items:m,className:"max-h-72 overflow-auto",children:i=>e.jsx(W,{id:i.key,textValue:i.key,children:i.key})})}),g?e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:g}):null]})}const S=t=>JSON.stringify([t.user_id,t.name]);function Z({userId:t,onChange:a}){const n=F(),r=t!==null,c=(l,d)=>e.jsx("button",{type:"button","aria-pressed":r===l,onClick:()=>a(l?"":null),className:r===l?"rounded-md bg-white px-3 py-1.5 text-sm font-medium text-[var(--otari-ink)] shadow-sm":"rounded-md px-3 py-1.5 text-sm text-[var(--otari-muted)] hover:text-[var(--otari-ink)]",children:d});return e.jsxs("div",{className:"flex flex-col gap-3",children:[e.jsxs("div",{children:[e.jsx("span",{className:"text-sm font-medium text-[var(--otari-ink)]",children:"Applies to"}),e.jsx("p",{className:"text-xs text-[var(--otari-muted)]",children:"A global alias resolves for every caller. A user-scoped one resolves only for that user, and takes precedence over a global alias of the same name."})]}),e.jsxs("div",{className:"flex w-fit items-center gap-1 rounded-lg bg-[var(--otari-bg)] p-1",children:[c(!1,"Every caller"),c(!0,"One user")]}),r?e.jsx(Q,{label:"User",value:t??"",onChange:a,users:n.data??[],placeholder:"Pick a user…",description:"Only this user resolves the alias.",unknownHint:e.jsx("span",{className:"text-red-700",children:"No such user. Pick an existing one."})}):null]})}function ee({alias:t,onClose:a}){const n=P(),[r,c]=u.useState(t.target),l=r.trim()!==""&&r.trim()!==t.target,d=()=>{l&&n.mutate({name:t.name,target:r.trim(),user_id:t.user_id},{onSuccess:a})};return e.jsx(A,{children:e.jsxs(A.Content,{className:"flex flex-col gap-4 p-5",children:[e.jsxs("div",{className:"text-sm font-semibold text-[var(--otari-ink)]",children:["Edit alias ",e.jsx("code",{children:t.name}),t.user_id?e.jsxs(e.Fragment,{children:[" for user ",e.jsx("code",{children:t.user_id})]}):null]}),e.jsx(w,{error:n.error}),e.jsxs("div",{className:"grid gap-4 sm:grid-cols-2",children:[e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx("span",{className:"text-sm font-medium text-[var(--otari-ink)]",children:"Alias name"}),e.jsx("code",{className:"text-sm text-[var(--otari-muted)]",children:t.name}),e.jsxs("span",{className:"text-xs text-[var(--otari-muted)]",children:["The alias name and who it applies to (",t.user_id?e.jsx("code",{children:t.user_id}):"every caller",") are the key and cannot be changed here. Delete and recreate to change either."]})]}),e.jsx(B,{label:"Target",value:r,onChange:c,isRequired:!0,description:"The real model this resolves to. Callers never see it."})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(j,{variant:"primary",isDisabled:!l||n.isPending,onPress:d,children:n.isPending?"Saving…":"Save changes"}),e.jsx(j,{variant:"ghost",onPress:a,children:"Cancel"})]})]})})}function se({onClose:t,initialTarget:a=""}){const n=P(),[r,c]=u.useState(""),[l,d]=u.useState(a),[o,m]=u.useState(null),h=/[:/]/.test(r),x=o===null||o.trim()!=="",g=r.trim()!==""&&l.trim()!==""&&!h&&x,i=()=>{g&&n.mutate({name:r.trim(),target:l.trim(),user_id:o===null?null:o.trim()},{onSuccess:t})};return e.jsx(A,{children:e.jsxs(A.Content,{className:"flex flex-col gap-4 p-5",children:[e.jsx("div",{className:"text-sm font-semibold text-[var(--otari-ink)]",children:"New alias"}),e.jsx(w,{error:n.error}),e.jsxs("div",{className:"grid gap-4 sm:grid-cols-2",children:[e.jsx(V,{label:"Alias name",value:r,onChange:c,placeholder:"fast-model",isRequired:!0,autoFocus:!0,description:h?e.jsx("span",{className:"text-red-700",children:"An alias name cannot contain “:” or “/”."}):"What callers send as `model`."}),e.jsx(B,{label:"Target",value:l,onChange:d,isRequired:!0,description:"The real model this resolves to. Callers never see it."})]}),e.jsx(Z,{userId:o,onChange:m}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(j,{variant:"primary",isDisabled:!g||n.isPending,onPress:i,children:n.isPending?"Creating…":"Create alias"}),e.jsx(j,{variant:"ghost",onPress:t,children:"Cancel"})]})]})})}function me(){const t=I(),a=M(),[n]=L(),r=n.get("target")??"",[c,l]=u.useState(r!==""),[d,o]=u.useState(null),m=O(),[h,x]=u.useState(!1),[g,i]=u.useState(void 0),[v,C]=u.useState(!1),p=[...t.data??[]].sort((s,b)=>s.name.localeCompare(b.name)||(s.user_id??"").localeCompare(b.user_id??"")),N=p.filter(s=>s.source==="stored").map(S),f=p.filter(s=>s.source!=="stored").map(S),y=$(m.selectedKeys,N),D=new Map(p.map(s=>[S(s),s])),_=async()=>{C(!0),i(void 0);try{for(const s of y){const b=D.get(s);b!==void 0&&await a.mutateAsync({name:b.name,userId:b.user_id})}m.clear(),x(!1)}catch(s){i(s)}finally{C(!1)}},E=u.useMemo(()=>[{id:"alias",header:"Alias",isRowHeader:!0,cell:s=>e.jsx("span",{className:"font-medium break-all text-[var(--otari-ink)]",children:s.name})},{id:"target",header:"Target",cell:s=>e.jsx("span",{className:"break-all text-[var(--otari-muted)]",children:s.target})},{id:"scope",header:"Applies to",cell:s=>s.user_id?e.jsx("code",{className:"break-all text-xs text-[var(--otari-ink)]",children:s.user_id}):e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"Every caller"})},{id:"source",header:"Source",cell:s=>e.jsx(X,{size:"sm",color:s.source==="stored"?"accent":"default",children:s.source})},{id:"actions",header:"Actions",align:"end",cell:s=>s.source==="stored"?e.jsxs("span",{className:"inline-flex items-center gap-2 whitespace-nowrap",children:[e.jsx(j,{size:"sm",variant:"ghost",onPress:()=>{l(!1),o(s)},children:"Edit"}),e.jsx(R,{confirmLabel:"Delete",isPending:a.isPending,onConfirm:()=>a.mutate({name:s.name,userId:s.user_id}),children:"Delete"})]}):e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"set in config.yml"})}],[a.isPending,a.mutate]);return e.jsxs("div",{className:"flex flex-col gap-6",children:[e.jsx(K,{title:"Aliases",description:"Friendly names that map to a real provider:model. Callers send the alias as the model; pricing, budgets, and usage key on the target.",action:c||d?null:e.jsx(j,{variant:"primary",onPress:()=>{o(null),l(!0)},children:"New alias"})}),e.jsx(w,{error:t.error}),c?e.jsx(se,{initialTarget:r,onClose:()=>l(!1)}):null,d?e.jsx(ee,{alias:d,onClose:()=>o(null)}):null,a.error?e.jsx(w,{error:a.error}):null,y.length>0?e.jsx(U,{selectedCount:y.length,allMatching:!1,matchingTotal:null,canSelectAllMatching:!1,onSelectAllMatching:()=>{},onClear:m.clear,children:e.jsx(j,{size:"sm",variant:"danger",onPress:()=>x(!0),children:"Delete"})}):null,e.jsx(H,{ariaLabel:"Aliases",columns:E,rows:p,getRowKey:S,isLoading:t.isLoading,emptyContent:"No aliases yet. Create one to give a model a friendly name.",selectionMode:"multiple",selectedKeys:m.selectedKeys,onSelectionChange:m.onSelectionChange,disabledKeys:f}),e.jsx(q,{isOpen:h,onOpenChange:x,heading:"Delete aliases",body:`Delete ${y.length} stored ${y.length===1?"alias":"aliases"}? Callers using ${y.length===1?"it":"them"} will get a model-not-found error.`,confirmLabel:"Delete",isPending:v,error:g,onConfirm:_})]})}export{me as AliasesPage}; diff --git a/src/gateway/static/dashboard/assets/BudgetsPage-hf0SYw2U.js b/src/gateway/static/dashboard/assets/BudgetsPage-DanpEezo.js similarity index 98% rename from src/gateway/static/dashboard/assets/BudgetsPage-hf0SYw2U.js rename to src/gateway/static/dashboard/assets/BudgetsPage-DanpEezo.js index 2127a291..ab70b611 100644 --- a/src/gateway/static/dashboard/assets/BudgetsPage-hf0SYw2U.js +++ b/src/gateway/static/dashboard/assets/BudgetsPage-DanpEezo.js @@ -1 +1 @@ -import{j as e}from"./tanstack-query-1t81HyiD.js";import{r as i}from"./react-dgEcD0HR.js";import{l as ae,u as re,m as le,n as ie,o as oe,p as de,P as ue,E as T,I as ce,q as me,r as xe}from"./index-D4f8RVEq.js";import{u as ge,r as he,B as pe}from"./tableSelection-9hV37uhu.js";import{C as fe}from"./ConfirmDialog-a8LQxZuS.js";import{D as be}from"./DataTable-Bmn_eYSV.js";import{F as z}from"./Field-Dwp6u3t8.js";import{C as E,I as je,a as ve,b as ye,B as x,d as k,S as Ne}from"./heroui-BI50yK5B.js";const Se=50;function _e({value:t,onChange:r,users:a,label:o,description:l}){const[g,h]=i.useState(""),d=i.useMemo(()=>a.filter(s=>!s.user_id.startsWith("apikey-")).map(s=>({id:s.user_id,label:s.alias?`${s.user_id} (${s.alias})`:s.user_id})),[a]),p=i.useMemo(()=>{const s=g.trim().toLowerCase();return d.filter(u=>!t.includes(u.id)).filter(u=>!s||u.id.toLowerCase().includes(s)||u.label.toLowerCase().includes(s)).slice(0,Se)},[d,t,g]),c=s=>{t.includes(s)||r([...t,s]),h("")},m=s=>r(t.filter(u=>u!==s));return e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsxs("div",{children:[e.jsx("span",{className:"text-sm font-medium text-[var(--otari-ink)]",children:o}),l?e.jsx("p",{className:"text-xs text-[var(--otari-muted)]",children:l}):null]}),t.length>0?e.jsx("div",{className:"flex flex-wrap gap-1.5",children:t.map(s=>e.jsxs("span",{className:"inline-flex items-center gap-1 rounded-full bg-[var(--otari-brand-tint)] px-2.5 py-1 font-mono text-xs text-[var(--otari-brand-dark)]",children:[s,e.jsx("button",{type:"button","aria-label":`Remove ${s}`,onClick:()=>m(s),className:"text-[var(--otari-brand-dark)] hover:text-red-700",children:"×"})]},s))}):null,d.length===0?e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"No users yet. Create users first, then assign them here or from the Users page."}):e.jsxs(E.Root,{allowsEmptyCollection:!0,menuTrigger:"input",inputValue:g,onInputChange:h,selectedKey:null,onSelectionChange:s=>{s!=null&&c(String(s))},className:"flex flex-col gap-1",children:[e.jsxs(E.InputGroup,{children:[e.jsx(je,{"aria-label":"Add a user",placeholder:"Search users…",autoComplete:"off"}),e.jsx(E.Trigger,{})]}),e.jsx(E.Popover,{children:e.jsx(ve,{items:p,className:"max-h-72 overflow-auto",children:s=>e.jsx(ye,{id:s.id,textValue:s.label,children:s.label})})})]})]})}const Ce=new Intl.NumberFormat(void 0,{style:"currency",currency:"USD",maximumFractionDigits:2});function D(t){return Ce.format(t)}const j=86400,q=3600,O=[{label:"No reset",seconds:null},{label:"Daily",seconds:j},{label:"Weekly",seconds:7*j},{label:"Monthly",seconds:30*j}];function we(t){if(t===null)return"No reset";const r=O.find(a=>a.seconds===t);return r?r.label:t%j===0?`Every ${t/j} days`:t%q===0?`Every ${t/q} hours`:`Every ${t}s`}function W(t){if(!t)return"—";const r=new Date(t);return Number.isNaN(r.getTime())?"—":r.toLocaleString()}function De(t){const r=t.trim();if(r==="")return{value:null,valid:!0};const a=Number(r);return!Number.isFinite(a)||a<0?{value:null,valid:!1}:{value:a,valid:!0}}function Y(t){return t!==null&&t%j===0?String(t/j):""}function Be({value:t,onChange:r,onInvalidChange:a}){const o=O.some(s=>s.seconds===t),[l,g]=i.useState(!o),[h,d]=i.useState(()=>Y(t)),p=h.trim(),c=Number(p),m=p!==""&&(!Number.isSafeInteger(c)||c<=0);return i.useEffect(()=>{a==null||a(m)},[m,a]),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("span",{className:"text-sm font-medium text-[var(--otari-ink)]",children:"Reset period"}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[O.map(s=>e.jsx(x,{size:"sm",variant:!l&&t===s.seconds?"primary":"outline",onPress:()=>{g(!1),d(Y(s.seconds)),r(s.seconds)},children:s.label},s.label)),e.jsx(x,{size:"sm",variant:l?"primary":"outline",onPress:()=>g(!0),children:"Custom"})]}),l?e.jsx("div",{className:"flex items-end gap-2",children:e.jsx(z,{label:"Every N days",value:h,onChange:s=>{d(s);const u=Number(s.trim());r(s.trim()===""||!Number.isSafeInteger(u)||u<=0?null:u*j)},placeholder:"14",description:m?e.jsx("span",{className:"text-red-700",children:"Enter a whole number of days."}):"Whole days between resets."})}):null,e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"Spend returns to zero each period. A user’s clock starts when the budget is assigned to them."})]})}function G({title:t,submitLabel:r,initial:a,error:o,isPending:l,onSubmit:g,onClose:h,assignUsers:d}){const[p,c]=i.useState(a.name??""),[m,s]=i.useState(a.max_budget===null?"":String(a.max_budget)),[u,b]=i.useState(a.budget_duration_sec),[S,v]=i.useState(!1),[B,P]=i.useState([]),f=De(m),A=!l&&f.valid&&!S,C=()=>{A&&g({name:p.trim()||null,max_budget:f.value,budget_duration_sec:u},B)};return e.jsx(k,{children:e.jsxs(k.Content,{className:"flex flex-col gap-4 p-5",children:[e.jsx("div",{className:"text-sm font-semibold text-[var(--otari-ink)]",children:t}),e.jsx(T,{error:o}),e.jsx(z,{label:"Name (optional)",value:p,onChange:c,autoFocus:!0,placeholder:"team-free-tier",description:"A label to recognize this budget later."}),e.jsx(z,{label:"Spending limit (USD)",value:m,onChange:s,placeholder:"100.00",description:f.valid?"The most a single user on this budget may spend per period. Leave blank for no limit.":e.jsx("span",{className:"text-red-700",children:"Enter a non-negative number, or leave blank for no limit."})}),e.jsx(Be,{value:u,onChange:b,onInvalidChange:v}),d?e.jsx(_e,{label:"Assign to users (optional)",description:"Attach this budget to existing users now. You can also manage assignments later on the Users page.",value:B,onChange:P,users:d}):null,e.jsxs("div",{className:"flex gap-2",children:[e.jsx(x,{variant:"primary",isDisabled:!A,onPress:C,children:l?"Saving…":r}),e.jsx(x,{variant:"ghost",isDisabled:l,onPress:h,children:"Cancel"})]})]})})}function Pe({budget:t}){if(t.user_count===0)return e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"No users assigned"});const r=t.total_spend;if(t.max_budget===null)return e.jsxs("span",{className:"text-xs text-[var(--otari-ink)]",children:[D(r)," spent",e.jsx("span",{className:"text-[var(--otari-muted)]",children:" · no limit"})]});const a=t.max_budget*t.user_count,o=a>0?Math.min(100,r/a*100):0,l=r>a;return e.jsxs("div",{className:"flex min-w-[140px] flex-col gap-1",children:[e.jsxs("div",{className:"flex items-baseline justify-between gap-2 text-xs",children:[e.jsx("span",{className:"text-[var(--otari-ink)]",children:D(r)}),e.jsxs("span",{className:"text-[var(--otari-muted)]",children:["of ",D(a)]})]}),e.jsx("div",{className:"h-1.5 w-full overflow-hidden rounded-full bg-[var(--otari-line)]",role:"progressbar","aria-valuenow":Math.round(o),"aria-valuemin":0,"aria-valuemax":100,"aria-label":"Aggregate spend against total allocation",children:e.jsx("div",{className:`h-full rounded-full ${l?"bg-red-500":"bg-[var(--otari-brand)]"}`,style:{width:`${Math.max(o,l?100:2)}%`}})})]})}function Ae({budgetId:t}){const r=xe(t);if(r.isLoading)return e.jsxs("div",{className:"flex items-center gap-2 px-4 py-4 text-sm text-[var(--otari-muted)]",children:[e.jsx(Ne,{size:"sm"})," Loading reset history…"]});if(r.error)return e.jsx("div",{className:"px-4 py-4",children:e.jsx(T,{error:r.error})});const a=r.data??[];return a.length===0?e.jsx("div",{className:"px-4 py-4 text-sm text-[var(--otari-muted)]",children:"No resets recorded yet for this budget."}):e.jsx("div",{className:"overflow-x-auto px-4 py-3",children:e.jsxs("table",{className:"w-full border-collapse text-xs",children:[e.jsx("thead",{className:"text-left text-[var(--otari-muted)]",children:e.jsxs("tr",{children:[e.jsx("th",{className:"py-1.5 pr-4 font-medium",children:"User"}),e.jsx("th",{className:"py-1.5 pr-4 font-medium",children:"Spend cleared"}),e.jsx("th",{className:"py-1.5 pr-4 font-medium",children:"Reset at"}),e.jsx("th",{className:"py-1.5 font-medium",children:"Next reset"})]})}),e.jsx("tbody",{children:a.map(o=>e.jsxs("tr",{className:"border-t border-[var(--otari-line)]",children:[e.jsx("td",{className:"py-1.5 pr-4",children:e.jsx("code",{children:o.user_id??"—"})}),e.jsx("td",{className:"py-1.5 pr-4 text-[var(--otari-ink)]",children:D(o.previous_spend)}),e.jsx("td",{className:"py-1.5 pr-4 text-[var(--otari-muted)]",children:W(o.reset_at)}),e.jsx("td",{className:"py-1.5 text-[var(--otari-muted)]",children:W(o.next_reset_at)})]},o.id))})]})})}function Ee({label:t,isPending:r,onConfirm:a}){const[o,l]=i.useState(!1);return o?e.jsxs("div",{className:"flex flex-col items-end gap-1.5 rounded-lg border border-amber-200 bg-amber-50 p-2 text-right",children:[e.jsxs("span",{className:"max-w-xs text-xs text-amber-800",children:["Delete ",e.jsx("strong",{children:t}),"? Users keep their spend but lose this limit. Cannot be undone."]}),e.jsxs("span",{className:"inline-flex gap-1",children:[e.jsx(x,{size:"sm",variant:"danger",isDisabled:r,onPress:a,children:"Delete permanently"}),e.jsx(x,{size:"sm",variant:"ghost",isDisabled:r,onPress:()=>l(!1),children:"Cancel"})]})]}):e.jsx(x,{size:"sm",variant:"danger-soft",onPress:()=>l(!0),children:"Delete"})}const ke=t=>t.budget_id;function Q(t){return t.split("-")[0]}function $(t){return t.name??Q(t.budget_id)}function Te(){const t=ae(),r=re(),a=le(),o=ie(),l=oe(),g=de(),[h,d]=i.useState(!1),[p,c]=i.useState(null),[m,s]=i.useState(null),[u,b]=i.useState(null),[S,v]=i.useState(null),[B,P]=i.useState(!1),f=ge(),[A,C]=i.useState(!1),[X,F]=i.useState(void 0),[J,H]=i.useState(!1),w=t.data??[],K=t.isLoading,y=w.find(n=>n.budget_id===p)??null,U=w.find(n=>n.budget_id===m)??null,L=!K&&w.length===0&&!h,Z=w.map(n=>n.budget_id),_=he(f.selectedKeys,Z),ee=async()=>{H(!0),F(void 0);try{for(const n of _)await l.mutateAsync(n);f.clear(),C(!1)}catch(n){F(n)}finally{H(!1)}},te=i.useMemo(()=>[{id:"budget",header:"Budget",isRowHeader:!0,cell:n=>e.jsxs("div",{className:"flex flex-col gap-0.5",children:[e.jsx("span",{className:"font-medium text-[var(--otari-ink)]",children:n.name??e.jsx("span",{className:"text-[var(--otari-muted)]",children:"(unnamed)"})}),e.jsx("code",{className:"text-[11px] text-[var(--otari-muted)]",title:n.budget_id,children:Q(n.budget_id)})]})},{id:"limit",header:"Limit (per user)",cell:n=>n.max_budget===null?e.jsx("span",{className:"text-[var(--otari-muted)]",children:"Unlimited"}):D(n.max_budget)},{id:"reset",header:"Reset",cell:n=>e.jsx("span",{className:"text-[var(--otari-muted)]",children:we(n.budget_duration_sec)})},{id:"users",header:"Users",cell:n=>e.jsx("span",{className:"text-[var(--otari-muted)]",children:n.user_count})},{id:"usage",header:"Usage",cell:n=>e.jsx(Pe,{budget:n})},{id:"actions",header:"Actions",align:"end",cell:n=>e.jsxs("div",{className:"flex items-center justify-end gap-1.5",children:[e.jsx(x,{size:"sm",variant:"ghost",onPress:()=>s(N=>N===n.budget_id?null:n.budget_id),children:m===n.budget_id?"Hide history":"History"}),e.jsx(x,{size:"sm",variant:"ghost",onPress:()=>{d(!1),c(n.budget_id)},children:"Edit"}),e.jsx(Ee,{label:$(n),isPending:l.isPending,onConfirm:()=>l.mutate(n.budget_id)})]})}],[m,l.isPending,l.mutate]),V=async(n,N)=>{P(!0),b(null);const I=await Promise.allSettled(N.map(M=>g.mutateAsync({id:M,body:{budget_id:n}})));P(!1);const R=I.flatMap((M,ne)=>M.status==="rejected"?[N[ne]]:[]);if(R.length>0){v({budgetId:n,userIds:R}),b(new Error(`Budget created, but could not assign it to: ${R.join(", ")}. Retry to try again.`));return}v(null),d(!1)},se=(n,N)=>{if(S){V(S.budgetId,S.userIds);return}b(null),a.mutate(n,{onSuccess:async I=>{if(N.length>0){await V(I.budget_id,N);return}d(!1)}})};return e.jsxs("div",{className:"flex flex-col gap-6",children:[e.jsx(ue,{title:"Budgets",description:"Define spending limits and reset schedules. Assign a budget to users to enforce it.",action:h||L?null:e.jsx(x,{variant:"primary",onPress:()=>{c(null),b(null),v(null),d(!0)},children:"Create budget"})}),e.jsx(T,{error:t.error??a.error??o.error??l.error??g.error}),e.jsx(ce,{children:"Assign a budget to users when you create it, or later from the Users page. Each row’s usage aggregates the spend of the users currently on that budget."}),L?e.jsx(me,{title:"No budgets yet",description:"A budget caps how much a user may spend and, optionally, resets that spend on a schedule. Create one, then assign it to users to enforce a limit.",actionLabel:"Create your first budget",onAction:()=>{c(null),b(null),v(null),d(!0)}}):null,h?e.jsx(G,{title:"Create budget",submitLabel:S?"Retry assignments":"Create budget",initial:{name:null,max_budget:null,budget_duration_sec:null},error:a.error??u,isPending:a.isPending||B,assignUsers:r.data??[],onSubmit:se,onClose:()=>{b(null),v(null),d(!1)}}):null,y?e.jsx(G,{title:`Edit budget ${$(y)}`,submitLabel:"Save changes",initial:{name:y.name,max_budget:y.max_budget,budget_duration_sec:y.budget_duration_sec},error:o.error,isPending:o.isPending,onSubmit:n=>o.mutate({id:y.budget_id,body:n},{onSuccess:()=>c(null)}),onClose:()=>c(null)},y.budget_id):null,_.length>0?e.jsx(pe,{selectedCount:_.length,allMatching:!1,matchingTotal:null,canSelectAllMatching:!1,onSelectAllMatching:()=>{},onClear:f.clear,children:e.jsx(x,{size:"sm",variant:"danger",onPress:()=>C(!0),children:"Delete"})}):null,L?null:e.jsx(be,{ariaLabel:"Budgets",columns:te,rows:w,getRowKey:ke,isLoading:K,emptyContent:"No budgets yet. Create one to cap spending.",selectionMode:"multiple",selectedKeys:f.selectedKeys,onSelectionChange:f.onSelectionChange}),U?e.jsx(k,{children:e.jsxs(k.Content,{className:"p-0",children:[e.jsxs("div",{className:"flex items-center justify-between border-b border-[var(--otari-line)] px-4 py-2",children:[e.jsxs("span",{className:"text-sm font-medium text-[var(--otari-ink)]",children:["Reset history — ",$(U)]}),e.jsx(x,{size:"sm",variant:"ghost",onPress:()=>s(null),children:"Close"})]}),e.jsx(Ae,{budgetId:U.budget_id})]})}):null,e.jsx(fe,{isOpen:A,onOpenChange:C,heading:"Delete budgets",body:`Delete ${_.length} ${_.length===1?"budget":"budgets"}? Users on ${_.length===1?"it":"them"} will no longer be capped.`,confirmLabel:"Delete",isPending:J,error:X,onConfirm:ee})]})}export{Te as BudgetsPage}; +import{j as e}from"./tanstack-query-1t81HyiD.js";import{r as i}from"./react-dgEcD0HR.js";import{q as ae,u as re,r as le,s as ie,t as oe,v as de,P as ue,E as T,I as ce,w as me,x as xe}from"./index-Bi2hajrg.js";import{u as ge,r as he,B as pe}from"./tableSelection-9hV37uhu.js";import{C as fe}from"./ConfirmDialog-ChuHp-Qm.js";import{D as be}from"./DataTable-Bmn_eYSV.js";import{F as z}from"./Field-Dwp6u3t8.js";import{C as E,I as je,a as ve,b as ye,B as x,d as k,S as Ne}from"./heroui-BI50yK5B.js";const Se=50;function _e({value:t,onChange:r,users:a,label:o,description:l}){const[g,h]=i.useState(""),d=i.useMemo(()=>a.filter(s=>!s.user_id.startsWith("apikey-")).map(s=>({id:s.user_id,label:s.alias?`${s.user_id} (${s.alias})`:s.user_id})),[a]),p=i.useMemo(()=>{const s=g.trim().toLowerCase();return d.filter(u=>!t.includes(u.id)).filter(u=>!s||u.id.toLowerCase().includes(s)||u.label.toLowerCase().includes(s)).slice(0,Se)},[d,t,g]),c=s=>{t.includes(s)||r([...t,s]),h("")},m=s=>r(t.filter(u=>u!==s));return e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsxs("div",{children:[e.jsx("span",{className:"text-sm font-medium text-[var(--otari-ink)]",children:o}),l?e.jsx("p",{className:"text-xs text-[var(--otari-muted)]",children:l}):null]}),t.length>0?e.jsx("div",{className:"flex flex-wrap gap-1.5",children:t.map(s=>e.jsxs("span",{className:"inline-flex items-center gap-1 rounded-full bg-[var(--otari-brand-tint)] px-2.5 py-1 font-mono text-xs text-[var(--otari-brand-dark)]",children:[s,e.jsx("button",{type:"button","aria-label":`Remove ${s}`,onClick:()=>m(s),className:"text-[var(--otari-brand-dark)] hover:text-red-700",children:"×"})]},s))}):null,d.length===0?e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"No users yet. Create users first, then assign them here or from the Users page."}):e.jsxs(E.Root,{allowsEmptyCollection:!0,menuTrigger:"input",inputValue:g,onInputChange:h,selectedKey:null,onSelectionChange:s=>{s!=null&&c(String(s))},className:"flex flex-col gap-1",children:[e.jsxs(E.InputGroup,{children:[e.jsx(je,{"aria-label":"Add a user",placeholder:"Search users…",autoComplete:"off"}),e.jsx(E.Trigger,{})]}),e.jsx(E.Popover,{children:e.jsx(ve,{items:p,className:"max-h-72 overflow-auto",children:s=>e.jsx(ye,{id:s.id,textValue:s.label,children:s.label})})})]})]})}const Ce=new Intl.NumberFormat(void 0,{style:"currency",currency:"USD",maximumFractionDigits:2});function D(t){return Ce.format(t)}const j=86400,q=3600,O=[{label:"No reset",seconds:null},{label:"Daily",seconds:j},{label:"Weekly",seconds:7*j},{label:"Monthly",seconds:30*j}];function we(t){if(t===null)return"No reset";const r=O.find(a=>a.seconds===t);return r?r.label:t%j===0?`Every ${t/j} days`:t%q===0?`Every ${t/q} hours`:`Every ${t}s`}function W(t){if(!t)return"—";const r=new Date(t);return Number.isNaN(r.getTime())?"—":r.toLocaleString()}function De(t){const r=t.trim();if(r==="")return{value:null,valid:!0};const a=Number(r);return!Number.isFinite(a)||a<0?{value:null,valid:!1}:{value:a,valid:!0}}function Y(t){return t!==null&&t%j===0?String(t/j):""}function Be({value:t,onChange:r,onInvalidChange:a}){const o=O.some(s=>s.seconds===t),[l,g]=i.useState(!o),[h,d]=i.useState(()=>Y(t)),p=h.trim(),c=Number(p),m=p!==""&&(!Number.isSafeInteger(c)||c<=0);return i.useEffect(()=>{a==null||a(m)},[m,a]),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("span",{className:"text-sm font-medium text-[var(--otari-ink)]",children:"Reset period"}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[O.map(s=>e.jsx(x,{size:"sm",variant:!l&&t===s.seconds?"primary":"outline",onPress:()=>{g(!1),d(Y(s.seconds)),r(s.seconds)},children:s.label},s.label)),e.jsx(x,{size:"sm",variant:l?"primary":"outline",onPress:()=>g(!0),children:"Custom"})]}),l?e.jsx("div",{className:"flex items-end gap-2",children:e.jsx(z,{label:"Every N days",value:h,onChange:s=>{d(s);const u=Number(s.trim());r(s.trim()===""||!Number.isSafeInteger(u)||u<=0?null:u*j)},placeholder:"14",description:m?e.jsx("span",{className:"text-red-700",children:"Enter a whole number of days."}):"Whole days between resets."})}):null,e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"Spend returns to zero each period. A user’s clock starts when the budget is assigned to them."})]})}function G({title:t,submitLabel:r,initial:a,error:o,isPending:l,onSubmit:g,onClose:h,assignUsers:d}){const[p,c]=i.useState(a.name??""),[m,s]=i.useState(a.max_budget===null?"":String(a.max_budget)),[u,b]=i.useState(a.budget_duration_sec),[S,v]=i.useState(!1),[B,P]=i.useState([]),f=De(m),A=!l&&f.valid&&!S,C=()=>{A&&g({name:p.trim()||null,max_budget:f.value,budget_duration_sec:u},B)};return e.jsx(k,{children:e.jsxs(k.Content,{className:"flex flex-col gap-4 p-5",children:[e.jsx("div",{className:"text-sm font-semibold text-[var(--otari-ink)]",children:t}),e.jsx(T,{error:o}),e.jsx(z,{label:"Name (optional)",value:p,onChange:c,autoFocus:!0,placeholder:"team-free-tier",description:"A label to recognize this budget later."}),e.jsx(z,{label:"Spending limit (USD)",value:m,onChange:s,placeholder:"100.00",description:f.valid?"The most a single user on this budget may spend per period. Leave blank for no limit.":e.jsx("span",{className:"text-red-700",children:"Enter a non-negative number, or leave blank for no limit."})}),e.jsx(Be,{value:u,onChange:b,onInvalidChange:v}),d?e.jsx(_e,{label:"Assign to users (optional)",description:"Attach this budget to existing users now. You can also manage assignments later on the Users page.",value:B,onChange:P,users:d}):null,e.jsxs("div",{className:"flex gap-2",children:[e.jsx(x,{variant:"primary",isDisabled:!A,onPress:C,children:l?"Saving…":r}),e.jsx(x,{variant:"ghost",isDisabled:l,onPress:h,children:"Cancel"})]})]})})}function Pe({budget:t}){if(t.user_count===0)return e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"No users assigned"});const r=t.total_spend;if(t.max_budget===null)return e.jsxs("span",{className:"text-xs text-[var(--otari-ink)]",children:[D(r)," spent",e.jsx("span",{className:"text-[var(--otari-muted)]",children:" · no limit"})]});const a=t.max_budget*t.user_count,o=a>0?Math.min(100,r/a*100):0,l=r>a;return e.jsxs("div",{className:"flex min-w-[140px] flex-col gap-1",children:[e.jsxs("div",{className:"flex items-baseline justify-between gap-2 text-xs",children:[e.jsx("span",{className:"text-[var(--otari-ink)]",children:D(r)}),e.jsxs("span",{className:"text-[var(--otari-muted)]",children:["of ",D(a)]})]}),e.jsx("div",{className:"h-1.5 w-full overflow-hidden rounded-full bg-[var(--otari-line)]",role:"progressbar","aria-valuenow":Math.round(o),"aria-valuemin":0,"aria-valuemax":100,"aria-label":"Aggregate spend against total allocation",children:e.jsx("div",{className:`h-full rounded-full ${l?"bg-red-500":"bg-[var(--otari-brand)]"}`,style:{width:`${Math.max(o,l?100:2)}%`}})})]})}function Ae({budgetId:t}){const r=xe(t);if(r.isLoading)return e.jsxs("div",{className:"flex items-center gap-2 px-4 py-4 text-sm text-[var(--otari-muted)]",children:[e.jsx(Ne,{size:"sm"})," Loading reset history…"]});if(r.error)return e.jsx("div",{className:"px-4 py-4",children:e.jsx(T,{error:r.error})});const a=r.data??[];return a.length===0?e.jsx("div",{className:"px-4 py-4 text-sm text-[var(--otari-muted)]",children:"No resets recorded yet for this budget."}):e.jsx("div",{className:"overflow-x-auto px-4 py-3",children:e.jsxs("table",{className:"w-full border-collapse text-xs",children:[e.jsx("thead",{className:"text-left text-[var(--otari-muted)]",children:e.jsxs("tr",{children:[e.jsx("th",{className:"py-1.5 pr-4 font-medium",children:"User"}),e.jsx("th",{className:"py-1.5 pr-4 font-medium",children:"Spend cleared"}),e.jsx("th",{className:"py-1.5 pr-4 font-medium",children:"Reset at"}),e.jsx("th",{className:"py-1.5 font-medium",children:"Next reset"})]})}),e.jsx("tbody",{children:a.map(o=>e.jsxs("tr",{className:"border-t border-[var(--otari-line)]",children:[e.jsx("td",{className:"py-1.5 pr-4",children:e.jsx("code",{children:o.user_id??"—"})}),e.jsx("td",{className:"py-1.5 pr-4 text-[var(--otari-ink)]",children:D(o.previous_spend)}),e.jsx("td",{className:"py-1.5 pr-4 text-[var(--otari-muted)]",children:W(o.reset_at)}),e.jsx("td",{className:"py-1.5 text-[var(--otari-muted)]",children:W(o.next_reset_at)})]},o.id))})]})})}function Ee({label:t,isPending:r,onConfirm:a}){const[o,l]=i.useState(!1);return o?e.jsxs("div",{className:"flex flex-col items-end gap-1.5 rounded-lg border border-amber-200 bg-amber-50 p-2 text-right",children:[e.jsxs("span",{className:"max-w-xs text-xs text-amber-800",children:["Delete ",e.jsx("strong",{children:t}),"? Users keep their spend but lose this limit. Cannot be undone."]}),e.jsxs("span",{className:"inline-flex gap-1",children:[e.jsx(x,{size:"sm",variant:"danger",isDisabled:r,onPress:a,children:"Delete permanently"}),e.jsx(x,{size:"sm",variant:"ghost",isDisabled:r,onPress:()=>l(!1),children:"Cancel"})]})]}):e.jsx(x,{size:"sm",variant:"danger-soft",onPress:()=>l(!0),children:"Delete"})}const ke=t=>t.budget_id;function Q(t){return t.split("-")[0]}function $(t){return t.name??Q(t.budget_id)}function Te(){const t=ae(),r=re(),a=le(),o=ie(),l=oe(),g=de(),[h,d]=i.useState(!1),[p,c]=i.useState(null),[m,s]=i.useState(null),[u,b]=i.useState(null),[S,v]=i.useState(null),[B,P]=i.useState(!1),f=ge(),[A,C]=i.useState(!1),[X,F]=i.useState(void 0),[J,H]=i.useState(!1),w=t.data??[],K=t.isLoading,y=w.find(n=>n.budget_id===p)??null,U=w.find(n=>n.budget_id===m)??null,L=!K&&w.length===0&&!h,Z=w.map(n=>n.budget_id),_=he(f.selectedKeys,Z),ee=async()=>{H(!0),F(void 0);try{for(const n of _)await l.mutateAsync(n);f.clear(),C(!1)}catch(n){F(n)}finally{H(!1)}},te=i.useMemo(()=>[{id:"budget",header:"Budget",isRowHeader:!0,cell:n=>e.jsxs("div",{className:"flex flex-col gap-0.5",children:[e.jsx("span",{className:"font-medium text-[var(--otari-ink)]",children:n.name??e.jsx("span",{className:"text-[var(--otari-muted)]",children:"(unnamed)"})}),e.jsx("code",{className:"text-[11px] text-[var(--otari-muted)]",title:n.budget_id,children:Q(n.budget_id)})]})},{id:"limit",header:"Limit (per user)",cell:n=>n.max_budget===null?e.jsx("span",{className:"text-[var(--otari-muted)]",children:"Unlimited"}):D(n.max_budget)},{id:"reset",header:"Reset",cell:n=>e.jsx("span",{className:"text-[var(--otari-muted)]",children:we(n.budget_duration_sec)})},{id:"users",header:"Users",cell:n=>e.jsx("span",{className:"text-[var(--otari-muted)]",children:n.user_count})},{id:"usage",header:"Usage",cell:n=>e.jsx(Pe,{budget:n})},{id:"actions",header:"Actions",align:"end",cell:n=>e.jsxs("div",{className:"flex items-center justify-end gap-1.5",children:[e.jsx(x,{size:"sm",variant:"ghost",onPress:()=>s(N=>N===n.budget_id?null:n.budget_id),children:m===n.budget_id?"Hide history":"History"}),e.jsx(x,{size:"sm",variant:"ghost",onPress:()=>{d(!1),c(n.budget_id)},children:"Edit"}),e.jsx(Ee,{label:$(n),isPending:l.isPending,onConfirm:()=>l.mutate(n.budget_id)})]})}],[m,l.isPending,l.mutate]),V=async(n,N)=>{P(!0),b(null);const I=await Promise.allSettled(N.map(M=>g.mutateAsync({id:M,body:{budget_id:n}})));P(!1);const R=I.flatMap((M,ne)=>M.status==="rejected"?[N[ne]]:[]);if(R.length>0){v({budgetId:n,userIds:R}),b(new Error(`Budget created, but could not assign it to: ${R.join(", ")}. Retry to try again.`));return}v(null),d(!1)},se=(n,N)=>{if(S){V(S.budgetId,S.userIds);return}b(null),a.mutate(n,{onSuccess:async I=>{if(N.length>0){await V(I.budget_id,N);return}d(!1)}})};return e.jsxs("div",{className:"flex flex-col gap-6",children:[e.jsx(ue,{title:"Budgets",description:"Define spending limits and reset schedules. Assign a budget to users to enforce it.",action:h||L?null:e.jsx(x,{variant:"primary",onPress:()=>{c(null),b(null),v(null),d(!0)},children:"Create budget"})}),e.jsx(T,{error:t.error??a.error??o.error??l.error??g.error}),e.jsx(ce,{children:"Assign a budget to users when you create it, or later from the Users page. Each row’s usage aggregates the spend of the users currently on that budget."}),L?e.jsx(me,{title:"No budgets yet",description:"A budget caps how much a user may spend and, optionally, resets that spend on a schedule. Create one, then assign it to users to enforce a limit.",actionLabel:"Create your first budget",onAction:()=>{c(null),b(null),v(null),d(!0)}}):null,h?e.jsx(G,{title:"Create budget",submitLabel:S?"Retry assignments":"Create budget",initial:{name:null,max_budget:null,budget_duration_sec:null},error:a.error??u,isPending:a.isPending||B,assignUsers:r.data??[],onSubmit:se,onClose:()=>{b(null),v(null),d(!1)}}):null,y?e.jsx(G,{title:`Edit budget ${$(y)}`,submitLabel:"Save changes",initial:{name:y.name,max_budget:y.max_budget,budget_duration_sec:y.budget_duration_sec},error:o.error,isPending:o.isPending,onSubmit:n=>o.mutate({id:y.budget_id,body:n},{onSuccess:()=>c(null)}),onClose:()=>c(null)},y.budget_id):null,_.length>0?e.jsx(pe,{selectedCount:_.length,allMatching:!1,matchingTotal:null,canSelectAllMatching:!1,onSelectAllMatching:()=>{},onClear:f.clear,children:e.jsx(x,{size:"sm",variant:"danger",onPress:()=>C(!0),children:"Delete"})}):null,L?null:e.jsx(be,{ariaLabel:"Budgets",columns:te,rows:w,getRowKey:ke,isLoading:K,emptyContent:"No budgets yet. Create one to cap spending.",selectionMode:"multiple",selectedKeys:f.selectedKeys,onSelectionChange:f.onSelectionChange}),U?e.jsx(k,{children:e.jsxs(k.Content,{className:"p-0",children:[e.jsxs("div",{className:"flex items-center justify-between border-b border-[var(--otari-line)] px-4 py-2",children:[e.jsxs("span",{className:"text-sm font-medium text-[var(--otari-ink)]",children:["Reset history — ",$(U)]}),e.jsx(x,{size:"sm",variant:"ghost",onPress:()=>s(null),children:"Close"})]}),e.jsx(Ae,{budgetId:U.budget_id})]})}):null,e.jsx(fe,{isOpen:A,onOpenChange:C,heading:"Delete budgets",body:`Delete ${_.length} ${_.length===1?"budget":"budgets"}? Users on ${_.length===1?"it":"them"} will no longer be capped.`,confirmLabel:"Delete",isPending:J,error:X,onConfirm:ee})]})}export{Te as BudgetsPage}; diff --git a/src/gateway/static/dashboard/assets/ConfirmDialog-a8LQxZuS.js b/src/gateway/static/dashboard/assets/ConfirmDialog-ChuHp-Qm.js similarity index 92% rename from src/gateway/static/dashboard/assets/ConfirmDialog-a8LQxZuS.js rename to src/gateway/static/dashboard/assets/ConfirmDialog-ChuHp-Qm.js index 47d30625..f9f9b935 100644 --- a/src/gateway/static/dashboard/assets/ConfirmDialog-a8LQxZuS.js +++ b/src/gateway/static/dashboard/assets/ConfirmDialog-ChuHp-Qm.js @@ -1 +1 @@ -import{j as r}from"./tanstack-query-1t81HyiD.js";import{E as j}from"./index-D4f8RVEq.js";import{A as e,B as l}from"./heroui-BI50yK5B.js";function p({isOpen:s,onOpenChange:a,heading:n,body:o,confirmLabel:t,confirmVariant:c="danger",isPending:i,error:d,onConfirm:x}){return r.jsx(e,{isOpen:s,onOpenChange:a,children:s?r.jsx(e.Backdrop,{children:r.jsx(e.Container,{placement:"center",size:"md",children:r.jsxs(e.Dialog,{children:[r.jsx(e.Header,{children:r.jsx(e.Heading,{children:n})}),r.jsxs(e.Body,{className:"flex flex-col gap-4",children:[r.jsx("div",{className:"text-sm text-[var(--otari-muted)]",children:o}),r.jsx(j,{error:d})]}),r.jsxs(e.Footer,{children:[r.jsx(l,{variant:"ghost",isDisabled:i,onPress:()=>a(!1),children:"Cancel"}),r.jsx(l,{variant:c,isPending:i,onPress:x,children:t})]})]})})}):null})}export{p as C}; +import{j as r}from"./tanstack-query-1t81HyiD.js";import{E as j}from"./index-Bi2hajrg.js";import{A as e,B as l}from"./heroui-BI50yK5B.js";function p({isOpen:s,onOpenChange:a,heading:n,body:o,confirmLabel:t,confirmVariant:c="danger",isPending:i,error:d,onConfirm:x}){return r.jsx(e,{isOpen:s,onOpenChange:a,children:s?r.jsx(e.Backdrop,{children:r.jsx(e.Container,{placement:"center",size:"md",children:r.jsxs(e.Dialog,{children:[r.jsx(e.Header,{children:r.jsx(e.Heading,{children:n})}),r.jsxs(e.Body,{className:"flex flex-col gap-4",children:[r.jsx("div",{className:"text-sm text-[var(--otari-muted)]",children:o}),r.jsx(j,{error:d})]}),r.jsxs(e.Footer,{children:[r.jsx(l,{variant:"ghost",isDisabled:i,onPress:()=>a(!1),children:"Cancel"}),r.jsx(l,{variant:c,isPending:i,onPress:x,children:t})]})]})})}):null})}export{p as C}; diff --git a/src/gateway/static/dashboard/assets/DocsPage-CUNhOocN.js b/src/gateway/static/dashboard/assets/DocsPage-DkHyFdGF.js similarity index 82% rename from src/gateway/static/dashboard/assets/DocsPage-CUNhOocN.js rename to src/gateway/static/dashboard/assets/DocsPage-DkHyFdGF.js index 1e2a9e3e..984c8169 100644 --- a/src/gateway/static/dashboard/assets/DocsPage-CUNhOocN.js +++ b/src/gateway/static/dashboard/assets/DocsPage-DkHyFdGF.js @@ -1,32 +1,32 @@ -import{j as re}from"./tanstack-query-1t81HyiD.js";import{P as gi}from"./index-D4f8RVEq.js";import{d as ct}from"./heroui-BI50yK5B.js";import{g as nr}from"./react-dgEcD0HR.js";function yi(e,t){const n={};return(e[e.length-1]===""?[...e,""]:e).join((n.padRight?" ":"")+","+(n.padLeft===!1?"":" ")).trim()}const ki=/^[$_\p{ID_Start}][$_\u{200C}\u{200D}\p{ID_Continue}]*$/u,xi=/^[$_\p{ID_Start}][-$_\u{200C}\u{200D}\p{ID_Continue}]*$/u,bi={};function ft(e,t){return(bi.jsx?xi:ki).test(e)}const wi=/[ \t\n\f\r]/g;function Si(e){return typeof e=="object"?e.type==="text"?ht(e.value):!1:ht(e)}function ht(e){return e.replace(wi,"")===""}class Ke{constructor(t,n,r){this.normal=n,this.property=t,r&&(this.space=r)}}Ke.prototype.normal={};Ke.prototype.property={};Ke.prototype.space=void 0;function tr(e,t){const n={},r={};for(const i of e)Object.assign(n,i.property),Object.assign(r,i.normal);return new Ke(n,r,t)}function zn(e){return e.toLowerCase()}class ee{constructor(t,n){this.attribute=n,this.property=t}}ee.prototype.attribute="";ee.prototype.booleanish=!1;ee.prototype.boolean=!1;ee.prototype.commaOrSpaceSeparated=!1;ee.prototype.commaSeparated=!1;ee.prototype.defined=!1;ee.prototype.mustUseProperty=!1;ee.prototype.number=!1;ee.prototype.overloadedBoolean=!1;ee.prototype.property="";ee.prototype.spaceSeparated=!1;ee.prototype.space=void 0;let Ci=0;const L=Te(),Y=Te(),Dn=Te(),E=Te(),$=Te(),Ie=Te(),te=Te();function Te(){return 2**++Ci}const Ln=Object.freeze(Object.defineProperty({__proto__:null,boolean:L,booleanish:Y,commaOrSpaceSeparated:te,commaSeparated:Ie,number:E,overloadedBoolean:Dn,spaceSeparated:$},Symbol.toStringTag,{value:"Module"})),pn=Object.keys(Ln);class Hn extends ee{constructor(t,n,r,i){let o=-1;if(super(t,n),pt(this,"space",i),typeof r=="number")for(;++o4&&n.slice(0,4)==="data"&&Ai.test(t)){if(t.charAt(4)==="-"){const o=t.slice(5).replace(mt,Di);r="data"+o.charAt(0).toUpperCase()+o.slice(1)}else{const o=t.slice(4);if(!mt.test(o)){let l=o.replace(Ti,zi);l.charAt(0)!=="-"&&(l="-"+l),t="data"+l}}i=Hn}return new i(r,t)}function zi(e){return"-"+e.toLowerCase()}function Di(e){return e.charAt(1).toUpperCase()}const Li=tr([rr,Ei,or,ar,sr],"html"),Un=tr([rr,Ii,or,ar,sr],"svg");function _i(e){return e.join(" ").trim()}var De={},mn,dt;function Ri(){if(dt)return mn;dt=1;var e=/\/\*[^*]*\*+([^/*][^*]*\*+)*\//g,t=/\n/g,n=/^\s*/,r=/^(\*?[-#/*\\\w]+(\[[0-9a-z_-]+\])?)\s*/,i=/^:\s*/,o=/^((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^)]*?\)|[^};])+)/,l=/^[;\s]*/,a=/^\s+|\s+$/g,s=` -`,u="/",f="*",c="",p="comment",h="declaration";function g(S,y){if(typeof S!="string")throw new TypeError("First argument must be a string");if(!S)return[];y=y||{};var I=1,C=1;function R(D){var T=D.match(t);T&&(I+=T.length);var q=D.lastIndexOf(s);C=~q?D.length-q:C+D.length}function F(){var D={line:I,column:C};return function(T){return T.position=new b(D),j(),T}}function b(D){this.start=D,this.end={line:I,column:C},this.source=y.source}b.prototype.content=S;function M(D){var T=new Error(y.source+":"+I+":"+C+": "+D);if(T.reason=D,T.filename=y.source,T.line=I,T.column=C,T.source=S,!y.silent)throw T}function H(D){var T=D.exec(S);if(T){var q=T[0];return R(q),S=S.slice(q.length),T}}function j(){H(n)}function k(D){var T;for(D=D||[];T=A();)T!==!1&&D.push(T);return D}function A(){var D=F();if(!(u!=S.charAt(0)||f!=S.charAt(1))){for(var T=2;c!=S.charAt(T)&&(f!=S.charAt(T)||u!=S.charAt(T+1));)++T;if(T+=2,c===S.charAt(T-1))return M("End of comment missing");var q=S.slice(2,T-2);return C+=2,R(q),S=S.slice(T),C+=2,D({type:p,comment:q})}}function P(){var D=F(),T=H(r);if(T){if(A(),!H(i))return M("property missing ':'");var q=H(o),K=D({type:h,property:w(T[0].replace(e,c)),value:q?w(q[0].replace(e,c)):c});return H(l),K}}function U(){var D=[];k(D);for(var T;T=P();)T!==!1&&(D.push(T),k(D));return D}return j(),U()}function w(S){return S?S.replace(a,c):c}return mn=g,mn}var gt;function Fi(){if(gt)return De;gt=1;var e=De&&De.__importDefault||function(r){return r&&r.__esModule?r:{default:r}};Object.defineProperty(De,"__esModule",{value:!0}),De.default=n;const t=e(Ri());function n(r,i){let o=null;if(!r||typeof r!="string")return o;const l=(0,t.default)(r),a=typeof i=="function";return l.forEach(s=>{if(s.type!=="declaration")return;const{property:u,value:f}=s;a?i(u,f,s):f&&(o=o||{},o[u]=f)}),o}return De}var Be={},yt;function Oi(){if(yt)return Be;yt=1,Object.defineProperty(Be,"__esModule",{value:!0}),Be.camelCase=void 0;var e=/^--[a-zA-Z0-9_-]+$/,t=/-([a-z])/g,n=/^[^-]+$/,r=/^-(webkit|moz|ms|o|khtml)-/,i=/^-(ms)-/,o=function(u){return!u||n.test(u)||e.test(u)},l=function(u,f){return f.toUpperCase()},a=function(u,f){return"".concat(f,"-")},s=function(u,f){return f===void 0&&(f={}),o(u)?u:(u=u.toLowerCase(),f.reactCompat?u=u.replace(i,a):u=u.replace(r,a),u.replace(t,l))};return Be.camelCase=s,Be}var je,kt;function Mi(){if(kt)return je;kt=1;var e=je&&je.__importDefault||function(i){return i&&i.__esModule?i:{default:i}},t=e(Fi()),n=Oi();function r(i,o){var l={};return!i||typeof i!="string"||(0,t.default)(i,function(a,s){a&&s&&(l[(0,n.camelCase)(a,o)]=s)}),l}return r.default=r,je=r,je}var Ni=Mi();const Bi=nr(Ni),ur=cr("end"),qn=cr("start");function cr(e){return t;function t(n){const r=n&&n.position&&n.position[e]||{};if(typeof r.line=="number"&&r.line>0&&typeof r.column=="number"&&r.column>0)return{line:r.line,column:r.column,offset:typeof r.offset=="number"&&r.offset>-1?r.offset:void 0}}}function ji(e){const t=qn(e),n=ur(e);if(t&&n)return{start:t,end:n}}function qe(e){return!e||typeof e!="object"?"":"position"in e||"type"in e?xt(e.position):"start"in e||"end"in e?xt(e):"line"in e||"column"in e?_n(e):""}function _n(e){return bt(e&&e.line)+":"+bt(e&&e.column)}function xt(e){return _n(e&&e.start)+"-"+_n(e&&e.end)}function bt(e){return e&&typeof e=="number"?e:1}class G extends Error{constructor(t,n,r){super(),typeof n=="string"&&(r=n,n=void 0);let i="",o={},l=!1;if(n&&("line"in n&&"column"in n?o={place:n}:"start"in n&&"end"in n?o={place:n}:"type"in n?o={ancestors:[n],place:n.position}:o={...n}),typeof t=="string"?i=t:!o.cause&&t&&(l=!0,i=t.message,o.cause=t),!o.ruleId&&!o.source&&typeof r=="string"){const s=r.indexOf(":");s===-1?o.ruleId=r:(o.source=r.slice(0,s),o.ruleId=r.slice(s+1))}if(!o.place&&o.ancestors&&o.ancestors){const s=o.ancestors[o.ancestors.length-1];s&&(o.place=s.position)}const a=o.place&&"start"in o.place?o.place.start:o.place;this.ancestors=o.ancestors||void 0,this.cause=o.cause||void 0,this.column=a?a.column:void 0,this.fatal=void 0,this.file="",this.message=i,this.line=a?a.line:void 0,this.name=qe(o.place)||"1:1",this.place=o.place||void 0,this.reason=this.message,this.ruleId=o.ruleId||void 0,this.source=o.source||void 0,this.stack=l&&o.cause&&typeof o.cause.stack=="string"?o.cause.stack:"",this.actual=void 0,this.expected=void 0,this.note=void 0,this.url=void 0}}G.prototype.file="";G.prototype.name="";G.prototype.reason="";G.prototype.message="";G.prototype.stack="";G.prototype.column=void 0;G.prototype.line=void 0;G.prototype.ancestors=void 0;G.prototype.cause=void 0;G.prototype.fatal=void 0;G.prototype.place=void 0;G.prototype.ruleId=void 0;G.prototype.source=void 0;const Vn={}.hasOwnProperty,Hi=new Map,Ui=/[A-Z]/g,qi=new Set(["table","tbody","thead","tfoot","tr"]),Vi=new Set(["td","th"]),fr="https://github.com/syntax-tree/hast-util-to-jsx-runtime";function $i(e,t){if(!t||t.Fragment===void 0)throw new TypeError("Expected `Fragment` in options");const n=t.filePath||void 0;let r;if(t.development){if(typeof t.jsxDEV!="function")throw new TypeError("Expected `jsxDEV` in options when `development: true`");r=Zi(n,t.jsxDEV)}else{if(typeof t.jsx!="function")throw new TypeError("Expected `jsx` in production options");if(typeof t.jsxs!="function")throw new TypeError("Expected `jsxs` in production options");r=Ji(n,t.jsx,t.jsxs)}const i={Fragment:t.Fragment,ancestors:[],components:t.components||{},create:r,elementAttributeNameCase:t.elementAttributeNameCase||"react",evaluater:t.createEvaluater?t.createEvaluater():void 0,filePath:n,ignoreInvalidStyle:t.ignoreInvalidStyle||!1,passKeys:t.passKeys!==!1,passNode:t.passNode||!1,schema:t.space==="svg"?Un:Li,stylePropertyNameCase:t.stylePropertyNameCase||"dom",tableCellAlignToStyle:t.tableCellAlignToStyle!==!1},o=hr(i,e,void 0);return o&&typeof o!="string"?o:i.create(e,i.Fragment,{children:o||void 0},void 0)}function hr(e,t,n){if(t.type==="element")return Wi(e,t,n);if(t.type==="mdxFlowExpression"||t.type==="mdxTextExpression")return Yi(e,t);if(t.type==="mdxJsxFlowElement"||t.type==="mdxJsxTextElement")return Qi(e,t,n);if(t.type==="mdxjsEsm")return Ki(e,t);if(t.type==="root")return Xi(e,t,n);if(t.type==="text")return Gi(e,t)}function Wi(e,t,n){const r=e.schema;let i=r;t.tagName.toLowerCase()==="svg"&&r.space==="html"&&(i=Un,e.schema=i),e.ancestors.push(t);const o=mr(e,t.tagName,!1),l=el(e,t);let a=Wn(e,t);return qi.has(t.tagName)&&(a=a.filter(function(s){return typeof s=="string"?!Si(s):!0})),pr(e,l,o,t),$n(l,a),e.ancestors.pop(),e.schema=r,e.create(t,o,l,n)}function Yi(e,t){if(t.data&&t.data.estree&&e.evaluater){const r=t.data.estree.body[0];return r.type,e.evaluater.evaluateExpression(r.expression)}We(e,t.position)}function Ki(e,t){if(t.data&&t.data.estree&&e.evaluater)return e.evaluater.evaluateProgram(t.data.estree);We(e,t.position)}function Qi(e,t,n){const r=e.schema;let i=r;t.name==="svg"&&r.space==="html"&&(i=Un,e.schema=i),e.ancestors.push(t);const o=t.name===null?e.Fragment:mr(e,t.name,!0),l=nl(e,t),a=Wn(e,t);return pr(e,l,o,t),$n(l,a),e.ancestors.pop(),e.schema=r,e.create(t,o,l,n)}function Xi(e,t,n){const r={};return $n(r,Wn(e,t)),e.create(t,e.Fragment,r,n)}function Gi(e,t){return t.value}function pr(e,t,n,r){typeof n!="string"&&n!==e.Fragment&&e.passNode&&(t.node=r)}function $n(e,t){if(t.length>0){const n=t.length>1?t:t[0];n&&(e.children=n)}}function Ji(e,t,n){return r;function r(i,o,l,a){const u=Array.isArray(l.children)?n:t;return a?u(o,l,a):u(o,l)}}function Zi(e,t){return n;function n(r,i,o,l){const a=Array.isArray(o.children),s=qn(r);return t(i,o,l,a,{columnNumber:s?s.column-1:void 0,fileName:e,lineNumber:s?s.line:void 0},void 0)}}function el(e,t){const n={};let r,i;for(i in t.properties)if(i!=="children"&&Vn.call(t.properties,i)){const o=tl(e,i,t.properties[i]);if(o){const[l,a]=o;e.tableCellAlignToStyle&&l==="align"&&typeof a=="string"&&Vi.has(t.tagName)?r=a:n[l]=a}}if(r){const o=n.style||(n.style={});o[e.stylePropertyNameCase==="css"?"text-align":"textAlign"]=r}return n}function nl(e,t){const n={};for(const r of t.attributes)if(r.type==="mdxJsxExpressionAttribute")if(r.data&&r.data.estree&&e.evaluater){const o=r.data.estree.body[0];o.type;const l=o.expression;l.type;const a=l.properties[0];a.type,Object.assign(n,e.evaluater.evaluateExpression(a.argument))}else We(e,t.position);else{const i=r.name;let o;if(r.value&&typeof r.value=="object")if(r.value.data&&r.value.data.estree&&e.evaluater){const a=r.value.data.estree.body[0];a.type,o=e.evaluater.evaluateExpression(a.expression)}else We(e,t.position);else o=r.value===null?!0:r.value;n[i]=o}return n}function Wn(e,t){const n=[];let r=-1;const i=e.passKeys?new Map:Hi;for(;++ri?0:i+t:t=t>i?i:t,n=n>0?n:0,r.length<1e4)l=Array.from(r),l.unshift(t,n),e.splice(...l);else for(n&&e.splice(t,n);o0?(ie(e,e.length,0,t),e):t}const Ct={}.hasOwnProperty;function gr(e){const t={};let n=-1;for(;++n13&&n<32||n>126&&n<160||n>55295&&n<57344||n>64975&&n<65008||(n&65535)===65535||(n&65535)===65534||n>1114111?"�":String.fromCodePoint(n)}function ce(e){return e.replace(/[\t\n\r ]+/g," ").replace(/^ | $/g,"").toLowerCase().toUpperCase()}const J=be(/[A-Za-z]/),X=be(/[\dA-Za-z]/),fl=be(/[#-'*+\--9=?A-Z^-~]/);function rn(e){return e!==null&&(e<32||e===127)}const Rn=be(/\d/),hl=be(/[\dA-Fa-f]/),pl=be(/[!-/:-@[-`{-~]/);function z(e){return e!==null&&e<-2}function W(e){return e!==null&&(e<0||e===32)}function O(e){return e===-2||e===-1||e===32}const sn=be(new RegExp("\\p{P}|\\p{S}","u")),ve=be(/\s/);function be(e){return t;function t(n){return n!==null&&n>-1&&e.test(String.fromCharCode(n))}}function Fe(e){const t=[];let n=-1,r=0,i=0;for(;++n55295&&o<57344){const a=e.charCodeAt(n+1);o<56320&&a>56319&&a<57344?(l=String.fromCharCode(o,a),i=1):l="�"}else l=String.fromCharCode(o);l&&(t.push(e.slice(r,n),encodeURIComponent(l)),r=n+i+1,l=""),i&&(n+=i,i=0)}return t.join("")+e.slice(r)}function B(e,t,n,r){const i=r?r-1:Number.POSITIVE_INFINITY;let o=0;return l;function l(s){return O(s)?(e.enter(n),a(s)):t(s)}function a(s){return O(s)&&o++l))return;const M=t.events.length;let H=M,j,k;for(;H--;)if(t.events[H][0]==="exit"&&t.events[H][1].type==="chunkFlow"){if(j){k=t.events[H][1].end;break}j=!0}for(y(r),b=M;bC;){const F=n[R];t.containerState=F[1],F[0].exit.call(t,e)}n.length=C}function I(){i.write([null]),o=void 0,i=void 0,t.containerState._closeFlow=void 0}}function kl(e,t,n){return B(e,e.attempt(this.parser.constructs.document,t,n),"linePrefix",this.parser.constructs.disable.null.includes("codeIndented")?void 0:4)}function _e(e){if(e===null||W(e)||ve(e))return 1;if(sn(e))return 2}function un(e,t,n){const r=[];let i=-1;for(;++i1&&e[n][1].end.offset-e[n][1].start.offset>1?2:1;const c={...e[r][1].end},p={...e[n][1].start};It(c,-s),It(p,s),l={type:s>1?"strongSequence":"emphasisSequence",start:c,end:{...e[r][1].end}},a={type:s>1?"strongSequence":"emphasisSequence",start:{...e[n][1].start},end:p},o={type:s>1?"strongText":"emphasisText",start:{...e[r][1].end},end:{...e[n][1].start}},i={type:s>1?"strong":"emphasis",start:{...l.start},end:{...a.end}},e[r][1].end={...l.start},e[n][1].start={...a.end},u=[],e[r][1].end.offset-e[r][1].start.offset&&(u=le(u,[["enter",e[r][1],t],["exit",e[r][1],t]])),u=le(u,[["enter",i,t],["enter",l,t],["exit",l,t],["enter",o,t]]),u=le(u,un(t.parser.constructs.insideSpan.null,e.slice(r+1,n),t)),u=le(u,[["exit",o,t],["enter",a,t],["exit",a,t],["exit",i,t]]),e[n][1].end.offset-e[n][1].start.offset?(f=2,u=le(u,[["enter",e[n][1],t],["exit",e[n][1],t]])):f=0,ie(e,r-1,n-r+3,u),n=r+u.length-f-2;break}}for(n=-1;++n0&&O(b)?B(e,I,"linePrefix",o+1)(b):I(b)}function I(b){return b===null||z(b)?e.check(vt,w,R)(b):(e.enter("codeFlowValue"),C(b))}function C(b){return b===null||z(b)?(e.exit("codeFlowValue"),I(b)):(e.consume(b),C)}function R(b){return e.exit("codeFenced"),t(b)}function F(b,M,H){let j=0;return k;function k(T){return b.enter("lineEnding"),b.consume(T),b.exit("lineEnding"),A}function A(T){return b.enter("codeFencedFence"),O(T)?B(b,P,"linePrefix",r.parser.constructs.disable.null.includes("codeIndented")?void 0:4)(T):P(T)}function P(T){return T===a?(b.enter("codeFencedFenceSequence"),U(T)):H(T)}function U(T){return T===a?(j++,b.consume(T),U):j>=l?(b.exit("codeFencedFenceSequence"),O(T)?B(b,D,"whitespace")(T):D(T)):H(T)}function D(T){return T===null||z(T)?(b.exit("codeFencedFence"),M(T)):H(T)}}}function zl(e,t,n){const r=this;return i;function i(l){return l===null?n(l):(e.enter("lineEnding"),e.consume(l),e.exit("lineEnding"),o)}function o(l){return r.parser.lazy[r.now().line]?n(l):t(l)}}const gn={name:"codeIndented",tokenize:Ll},Dl={partial:!0,tokenize:_l};function Ll(e,t,n){const r=this;return i;function i(u){return e.enter("codeIndented"),B(e,o,"linePrefix",5)(u)}function o(u){const f=r.events[r.events.length-1];return f&&f[1].type==="linePrefix"&&f[2].sliceSerialize(f[1],!0).length>=4?l(u):n(u)}function l(u){return u===null?s(u):z(u)?e.attempt(Dl,l,s)(u):(e.enter("codeFlowValue"),a(u))}function a(u){return u===null||z(u)?(e.exit("codeFlowValue"),l(u)):(e.consume(u),a)}function s(u){return e.exit("codeIndented"),t(u)}}function _l(e,t,n){const r=this;return i;function i(l){return r.parser.lazy[r.now().line]?n(l):z(l)?(e.enter("lineEnding"),e.consume(l),e.exit("lineEnding"),i):B(e,o,"linePrefix",5)(l)}function o(l){const a=r.events[r.events.length-1];return a&&a[1].type==="linePrefix"&&a[2].sliceSerialize(a[1],!0).length>=4?t(l):z(l)?i(l):n(l)}}const Rl={name:"codeText",previous:Ol,resolve:Fl,tokenize:Ml};function Fl(e){let t=e.length-4,n=3,r,i;if((e[n][1].type==="lineEnding"||e[n][1].type==="space")&&(e[t][1].type==="lineEnding"||e[t][1].type==="space")){for(r=n;++r=this.left.length+this.right.length)throw new RangeError("Cannot access index `"+t+"` in a splice buffer of size `"+(this.left.length+this.right.length)+"`");return tthis.left.length?this.right.slice(this.right.length-r+this.left.length,this.right.length-t+this.left.length).reverse():this.left.slice(t).concat(this.right.slice(this.right.length-r+this.left.length).reverse())}splice(t,n,r){const i=n||0;this.setCursor(Math.trunc(t));const o=this.right.splice(this.right.length-i,Number.POSITIVE_INFINITY);return r&&He(this.left,r),o.reverse()}pop(){return this.setCursor(Number.POSITIVE_INFINITY),this.left.pop()}push(t){this.setCursor(Number.POSITIVE_INFINITY),this.left.push(t)}pushMany(t){this.setCursor(Number.POSITIVE_INFINITY),He(this.left,t)}unshift(t){this.setCursor(0),this.right.push(t)}unshiftMany(t){this.setCursor(0),He(this.right,t.reverse())}setCursor(t){if(!(t===this.left.length||t>this.left.length&&this.right.length===0||t<0&&this.left.length===0))if(t=4?t(l):e.interrupt(r.parser.constructs.flow,n,t)(l)}}function Sr(e,t,n,r,i,o,l,a,s){const u=s||Number.POSITIVE_INFINITY;let f=0;return c;function c(y){return y===60?(e.enter(r),e.enter(i),e.enter(o),e.consume(y),e.exit(o),p):y===null||y===32||y===41||rn(y)?n(y):(e.enter(r),e.enter(l),e.enter(a),e.enter("chunkString",{contentType:"string"}),w(y))}function p(y){return y===62?(e.enter(o),e.consume(y),e.exit(o),e.exit(i),e.exit(r),t):(e.enter(a),e.enter("chunkString",{contentType:"string"}),h(y))}function h(y){return y===62?(e.exit("chunkString"),e.exit(a),p(y)):y===null||y===60||z(y)?n(y):(e.consume(y),y===92?g:h)}function g(y){return y===60||y===62||y===92?(e.consume(y),h):h(y)}function w(y){return!f&&(y===null||y===41||W(y))?(e.exit("chunkString"),e.exit(a),e.exit(l),e.exit(r),t(y)):f999||h===null||h===91||h===93&&!s||h===94&&!a&&"_hiddenFootnoteSupport"in l.parser.constructs?n(h):h===93?(e.exit(o),e.enter(i),e.consume(h),e.exit(i),e.exit(r),t):z(h)?(e.enter("lineEnding"),e.consume(h),e.exit("lineEnding"),f):(e.enter("chunkString",{contentType:"string"}),c(h))}function c(h){return h===null||h===91||h===93||z(h)||a++>999?(e.exit("chunkString"),f(h)):(e.consume(h),s||(s=!O(h)),h===92?p:c)}function p(h){return h===91||h===92||h===93?(e.consume(h),a++,c):c(h)}}function Er(e,t,n,r,i,o){let l;return a;function a(p){return p===34||p===39||p===40?(e.enter(r),e.enter(i),e.consume(p),e.exit(i),l=p===40?41:p,s):n(p)}function s(p){return p===l?(e.enter(i),e.consume(p),e.exit(i),e.exit(r),t):(e.enter(o),u(p))}function u(p){return p===l?(e.exit(o),s(l)):p===null?n(p):z(p)?(e.enter("lineEnding"),e.consume(p),e.exit("lineEnding"),B(e,u,"linePrefix")):(e.enter("chunkString",{contentType:"string"}),f(p))}function f(p){return p===l||p===null||z(p)?(e.exit("chunkString"),u(p)):(e.consume(p),p===92?c:f)}function c(p){return p===l||p===92?(e.consume(p),f):f(p)}}function Ve(e,t){let n;return r;function r(i){return z(i)?(e.enter("lineEnding"),e.consume(i),e.exit("lineEnding"),n=!0,r):O(i)?B(e,r,n?"linePrefix":"lineSuffix")(i):t(i)}}const $l={name:"definition",tokenize:Yl},Wl={partial:!0,tokenize:Kl};function Yl(e,t,n){const r=this;let i;return o;function o(h){return e.enter("definition"),l(h)}function l(h){return Cr.call(r,e,a,n,"definitionLabel","definitionLabelMarker","definitionLabelString")(h)}function a(h){return i=ce(r.sliceSerialize(r.events[r.events.length-1][1]).slice(1,-1)),h===58?(e.enter("definitionMarker"),e.consume(h),e.exit("definitionMarker"),s):n(h)}function s(h){return W(h)?Ve(e,u)(h):u(h)}function u(h){return Sr(e,f,n,"definitionDestination","definitionDestinationLiteral","definitionDestinationLiteralMarker","definitionDestinationRaw","definitionDestinationString")(h)}function f(h){return e.attempt(Wl,c,c)(h)}function c(h){return O(h)?B(e,p,"whitespace")(h):p(h)}function p(h){return h===null||z(h)?(e.exit("definition"),r.parser.defined.push(i),t(h)):n(h)}}function Kl(e,t,n){return r;function r(a){return W(a)?Ve(e,i)(a):n(a)}function i(a){return Er(e,o,n,"definitionTitle","definitionTitleMarker","definitionTitleString")(a)}function o(a){return O(a)?B(e,l,"whitespace")(a):l(a)}function l(a){return a===null||z(a)?t(a):n(a)}}const Ql={name:"hardBreakEscape",tokenize:Xl};function Xl(e,t,n){return r;function r(o){return e.enter("hardBreakEscape"),e.consume(o),i}function i(o){return z(o)?(e.exit("hardBreakEscape"),t(o)):n(o)}}const Gl={name:"headingAtx",resolve:Jl,tokenize:Zl};function Jl(e,t){let n=e.length-2,r=3,i,o;return e[r][1].type==="whitespace"&&(r+=2),n-2>r&&e[n][1].type==="whitespace"&&(n-=2),e[n][1].type==="atxHeadingSequence"&&(r===n-1||n-4>r&&e[n-2][1].type==="whitespace")&&(n-=r+1===n?2:4),n>r&&(i={type:"atxHeadingText",start:e[r][1].start,end:e[n][1].end},o={type:"chunkText",start:e[r][1].start,end:e[n][1].end,contentType:"text"},ie(e,r,n-r+1,[["enter",i,t],["enter",o,t],["exit",o,t],["exit",i,t]])),e}function Zl(e,t,n){let r=0;return i;function i(f){return e.enter("atxHeading"),o(f)}function o(f){return e.enter("atxHeadingSequence"),l(f)}function l(f){return f===35&&r++<6?(e.consume(f),l):f===null||W(f)?(e.exit("atxHeadingSequence"),a(f)):n(f)}function a(f){return f===35?(e.enter("atxHeadingSequence"),s(f)):f===null||z(f)?(e.exit("atxHeading"),t(f)):O(f)?B(e,a,"whitespace")(f):(e.enter("atxHeadingText"),u(f))}function s(f){return f===35?(e.consume(f),s):(e.exit("atxHeadingSequence"),a(f))}function u(f){return f===null||f===35||W(f)?(e.exit("atxHeadingText"),a(f)):(e.consume(f),u)}}const eo=["address","article","aside","base","basefont","blockquote","body","caption","center","col","colgroup","dd","details","dialog","dir","div","dl","dt","fieldset","figcaption","figure","footer","form","frame","frameset","h1","h2","h3","h4","h5","h6","head","header","hr","html","iframe","legend","li","link","main","menu","menuitem","nav","noframes","ol","optgroup","option","p","param","search","section","summary","table","tbody","td","tfoot","th","thead","title","tr","track","ul"],At=["pre","script","style","textarea"],no={concrete:!0,name:"htmlFlow",resolveTo:io,tokenize:lo},to={partial:!0,tokenize:ao},ro={partial:!0,tokenize:oo};function io(e){let t=e.length;for(;t--&&!(e[t][0]==="enter"&&e[t][1].type==="htmlFlow"););return t>1&&e[t-2][1].type==="linePrefix"&&(e[t][1].start=e[t-2][1].start,e[t+1][1].start=e[t-2][1].start,e.splice(t-2,2)),e}function lo(e,t,n){const r=this;let i,o,l,a,s;return u;function u(d){return f(d)}function f(d){return e.enter("htmlFlow"),e.enter("htmlFlowData"),e.consume(d),c}function c(d){return d===33?(e.consume(d),p):d===47?(e.consume(d),o=!0,w):d===63?(e.consume(d),i=3,r.interrupt?t:m):J(d)?(e.consume(d),l=String.fromCharCode(d),S):n(d)}function p(d){return d===45?(e.consume(d),i=2,h):d===91?(e.consume(d),i=5,a=0,g):J(d)?(e.consume(d),i=4,r.interrupt?t:m):n(d)}function h(d){return d===45?(e.consume(d),r.interrupt?t:m):n(d)}function g(d){const se="CDATA[";return d===se.charCodeAt(a++)?(e.consume(d),a===se.length?r.interrupt?t:P:g):n(d)}function w(d){return J(d)?(e.consume(d),l=String.fromCharCode(d),S):n(d)}function S(d){if(d===null||d===47||d===62||W(d)){const se=d===47,we=l.toLowerCase();return!se&&!o&&At.includes(we)?(i=1,r.interrupt?t(d):P(d)):eo.includes(l.toLowerCase())?(i=6,se?(e.consume(d),y):r.interrupt?t(d):P(d)):(i=7,r.interrupt&&!r.parser.lazy[r.now().line]?n(d):o?I(d):C(d))}return d===45||X(d)?(e.consume(d),l+=String.fromCharCode(d),S):n(d)}function y(d){return d===62?(e.consume(d),r.interrupt?t:P):n(d)}function I(d){return O(d)?(e.consume(d),I):k(d)}function C(d){return d===47?(e.consume(d),k):d===58||d===95||J(d)?(e.consume(d),R):O(d)?(e.consume(d),C):k(d)}function R(d){return d===45||d===46||d===58||d===95||X(d)?(e.consume(d),R):F(d)}function F(d){return d===61?(e.consume(d),b):O(d)?(e.consume(d),F):C(d)}function b(d){return d===null||d===60||d===61||d===62||d===96?n(d):d===34||d===39?(e.consume(d),s=d,M):O(d)?(e.consume(d),b):H(d)}function M(d){return d===s?(e.consume(d),s=null,j):d===null||z(d)?n(d):(e.consume(d),M)}function H(d){return d===null||d===34||d===39||d===47||d===60||d===61||d===62||d===96||W(d)?F(d):(e.consume(d),H)}function j(d){return d===47||d===62||O(d)?C(d):n(d)}function k(d){return d===62?(e.consume(d),A):n(d)}function A(d){return d===null||z(d)?P(d):O(d)?(e.consume(d),A):n(d)}function P(d){return d===45&&i===2?(e.consume(d),q):d===60&&i===1?(e.consume(d),K):d===62&&i===4?(e.consume(d),ae):d===63&&i===3?(e.consume(d),m):d===93&&i===5?(e.consume(d),pe):z(d)&&(i===6||i===7)?(e.exit("htmlFlowData"),e.check(to,me,U)(d)):d===null||z(d)?(e.exit("htmlFlowData"),U(d)):(e.consume(d),P)}function U(d){return e.check(ro,D,me)(d)}function D(d){return e.enter("lineEnding"),e.consume(d),e.exit("lineEnding"),T}function T(d){return d===null||z(d)?U(d):(e.enter("htmlFlowData"),P(d))}function q(d){return d===45?(e.consume(d),m):P(d)}function K(d){return d===47?(e.consume(d),l="",oe):P(d)}function oe(d){if(d===62){const se=l.toLowerCase();return At.includes(se)?(e.consume(d),ae):P(d)}return J(d)&&l.length<8?(e.consume(d),l+=String.fromCharCode(d),oe):P(d)}function pe(d){return d===93?(e.consume(d),m):P(d)}function m(d){return d===62?(e.consume(d),ae):d===45&&i===2?(e.consume(d),m):P(d)}function ae(d){return d===null||z(d)?(e.exit("htmlFlowData"),me(d)):(e.consume(d),ae)}function me(d){return e.exit("htmlFlow"),t(d)}}function oo(e,t,n){const r=this;return i;function i(l){return z(l)?(e.enter("lineEnding"),e.consume(l),e.exit("lineEnding"),o):n(l)}function o(l){return r.parser.lazy[r.now().line]?n(l):t(l)}}function ao(e,t,n){return r;function r(i){return e.enter("lineEnding"),e.consume(i),e.exit("lineEnding"),e.attempt(Qe,t,n)}}const so={name:"htmlText",tokenize:uo};function uo(e,t,n){const r=this;let i,o,l;return a;function a(m){return e.enter("htmlText"),e.enter("htmlTextData"),e.consume(m),s}function s(m){return m===33?(e.consume(m),u):m===47?(e.consume(m),F):m===63?(e.consume(m),C):J(m)?(e.consume(m),H):n(m)}function u(m){return m===45?(e.consume(m),f):m===91?(e.consume(m),o=0,g):J(m)?(e.consume(m),I):n(m)}function f(m){return m===45?(e.consume(m),h):n(m)}function c(m){return m===null?n(m):m===45?(e.consume(m),p):z(m)?(l=c,K(m)):(e.consume(m),c)}function p(m){return m===45?(e.consume(m),h):c(m)}function h(m){return m===62?q(m):m===45?p(m):c(m)}function g(m){const ae="CDATA[";return m===ae.charCodeAt(o++)?(e.consume(m),o===ae.length?w:g):n(m)}function w(m){return m===null?n(m):m===93?(e.consume(m),S):z(m)?(l=w,K(m)):(e.consume(m),w)}function S(m){return m===93?(e.consume(m),y):w(m)}function y(m){return m===62?q(m):m===93?(e.consume(m),y):w(m)}function I(m){return m===null||m===62?q(m):z(m)?(l=I,K(m)):(e.consume(m),I)}function C(m){return m===null?n(m):m===63?(e.consume(m),R):z(m)?(l=C,K(m)):(e.consume(m),C)}function R(m){return m===62?q(m):C(m)}function F(m){return J(m)?(e.consume(m),b):n(m)}function b(m){return m===45||X(m)?(e.consume(m),b):M(m)}function M(m){return z(m)?(l=M,K(m)):O(m)?(e.consume(m),M):q(m)}function H(m){return m===45||X(m)?(e.consume(m),H):m===47||m===62||W(m)?j(m):n(m)}function j(m){return m===47?(e.consume(m),q):m===58||m===95||J(m)?(e.consume(m),k):z(m)?(l=j,K(m)):O(m)?(e.consume(m),j):q(m)}function k(m){return m===45||m===46||m===58||m===95||X(m)?(e.consume(m),k):A(m)}function A(m){return m===61?(e.consume(m),P):z(m)?(l=A,K(m)):O(m)?(e.consume(m),A):j(m)}function P(m){return m===null||m===60||m===61||m===62||m===96?n(m):m===34||m===39?(e.consume(m),i=m,U):z(m)?(l=P,K(m)):O(m)?(e.consume(m),P):(e.consume(m),D)}function U(m){return m===i?(e.consume(m),i=void 0,T):m===null?n(m):z(m)?(l=U,K(m)):(e.consume(m),U)}function D(m){return m===null||m===34||m===39||m===60||m===61||m===96?n(m):m===47||m===62||W(m)?j(m):(e.consume(m),D)}function T(m){return m===47||m===62||W(m)?j(m):n(m)}function q(m){return m===62?(e.consume(m),e.exit("htmlTextData"),e.exit("htmlText"),t):n(m)}function K(m){return e.exit("htmlTextData"),e.enter("lineEnding"),e.consume(m),e.exit("lineEnding"),oe}function oe(m){return O(m)?B(e,pe,"linePrefix",r.parser.constructs.disable.null.includes("codeIndented")?void 0:4)(m):pe(m)}function pe(m){return e.enter("htmlTextData"),l(m)}}const Qn={name:"labelEnd",resolveAll:po,resolveTo:mo,tokenize:go},co={tokenize:yo},fo={tokenize:ko},ho={tokenize:xo};function po(e){let t=-1;const n=[];for(;++t=3&&(u===null||z(u))?(e.exit("thematicBreak"),t(u)):n(u)}function s(u){return u===i?(e.consume(u),r++,s):(e.exit("thematicBreakSequence"),O(u)?B(e,a,"whitespace")(u):a(u))}}const Z={continuation:{tokenize:Po},exit:Do,name:"list",tokenize:Ao},vo={partial:!0,tokenize:Lo},To={partial:!0,tokenize:zo};function Ao(e,t,n){const r=this,i=r.events[r.events.length-1];let o=i&&i[1].type==="linePrefix"?i[2].sliceSerialize(i[1],!0).length:0,l=0;return a;function a(h){const g=r.containerState.type||(h===42||h===43||h===45?"listUnordered":"listOrdered");if(g==="listUnordered"?!r.containerState.marker||h===r.containerState.marker:Rn(h)){if(r.containerState.type||(r.containerState.type=g,e.enter(g,{_container:!0})),g==="listUnordered")return e.enter("listItemPrefix"),h===42||h===45?e.check(tn,n,u)(h):u(h);if(!r.interrupt||h===49)return e.enter("listItemPrefix"),e.enter("listItemValue"),s(h)}return n(h)}function s(h){return Rn(h)&&++l<10?(e.consume(h),s):(!r.interrupt||l<2)&&(r.containerState.marker?h===r.containerState.marker:h===41||h===46)?(e.exit("listItemValue"),u(h)):n(h)}function u(h){return e.enter("listItemMarker"),e.consume(h),e.exit("listItemMarker"),r.containerState.marker=r.containerState.marker||h,e.check(Qe,r.interrupt?n:f,e.attempt(vo,p,c))}function f(h){return r.containerState.initialBlankLine=!0,o++,p(h)}function c(h){return O(h)?(e.enter("listItemPrefixWhitespace"),e.consume(h),e.exit("listItemPrefixWhitespace"),p):n(h)}function p(h){return r.containerState.size=o+r.sliceSerialize(e.exit("listItemPrefix"),!0).length,t(h)}}function Po(e,t,n){const r=this;return r.containerState._closeFlow=void 0,e.check(Qe,i,o);function i(a){return r.containerState.furtherBlankLines=r.containerState.furtherBlankLines||r.containerState.initialBlankLine,B(e,t,"listItemIndent",r.containerState.size+1)(a)}function o(a){return r.containerState.furtherBlankLines||!O(a)?(r.containerState.furtherBlankLines=void 0,r.containerState.initialBlankLine=void 0,l(a)):(r.containerState.furtherBlankLines=void 0,r.containerState.initialBlankLine=void 0,e.attempt(To,t,l)(a))}function l(a){return r.containerState._closeFlow=!0,r.interrupt=void 0,B(e,e.attempt(Z,t,n),"linePrefix",r.parser.constructs.disable.null.includes("codeIndented")?void 0:4)(a)}}function zo(e,t,n){const r=this;return B(e,i,"listItemIndent",r.containerState.size+1);function i(o){const l=r.events[r.events.length-1];return l&&l[1].type==="listItemIndent"&&l[2].sliceSerialize(l[1],!0).length===r.containerState.size?t(o):n(o)}}function Do(e){e.exit(this.containerState.type)}function Lo(e,t,n){const r=this;return B(e,i,"listItemPrefixWhitespace",r.parser.constructs.disable.null.includes("codeIndented")?void 0:5);function i(o){const l=r.events[r.events.length-1];return!O(o)&&l&&l[1].type==="listItemPrefixWhitespace"?t(o):n(o)}}const Pt={name:"setextUnderline",resolveTo:_o,tokenize:Ro};function _o(e,t){let n=e.length,r,i,o;for(;n--;)if(e[n][0]==="enter"){if(e[n][1].type==="content"){r=n;break}e[n][1].type==="paragraph"&&(i=n)}else e[n][1].type==="content"&&e.splice(n,1),!o&&e[n][1].type==="definition"&&(o=n);const l={type:"setextHeading",start:{...e[r][1].start},end:{...e[e.length-1][1].end}};return e[i][1].type="setextHeadingText",o?(e.splice(i,0,["enter",l,t]),e.splice(o+1,0,["exit",e[r][1],t]),e[r][1].end={...e[o][1].end}):e[r][1]=l,e.push(["exit",l,t]),e}function Ro(e,t,n){const r=this;let i;return o;function o(u){let f=r.events.length,c;for(;f--;)if(r.events[f][1].type!=="lineEnding"&&r.events[f][1].type!=="linePrefix"&&r.events[f][1].type!=="content"){c=r.events[f][1].type==="paragraph";break}return!r.parser.lazy[r.now().line]&&(r.interrupt||c)?(e.enter("setextHeadingLine"),i=u,l(u)):n(u)}function l(u){return e.enter("setextHeadingLineSequence"),a(u)}function a(u){return u===i?(e.consume(u),a):(e.exit("setextHeadingLineSequence"),O(u)?B(e,s,"lineSuffix")(u):s(u))}function s(u){return u===null||z(u)?(e.exit("setextHeadingLine"),t(u)):n(u)}}const Fo={tokenize:Oo};function Oo(e){const t=this,n=e.attempt(Qe,r,e.attempt(this.parser.constructs.flowInitial,i,B(e,e.attempt(this.parser.constructs.flow,i,e.attempt(jl,i)),"linePrefix")));return n;function r(o){if(o===null){e.consume(o);return}return e.enter("lineEndingBlank"),e.consume(o),e.exit("lineEndingBlank"),t.currentConstruct=void 0,n}function i(o){if(o===null){e.consume(o);return}return e.enter("lineEnding"),e.consume(o),e.exit("lineEnding"),t.currentConstruct=void 0,n}}const Mo={resolveAll:vr()},No=Ir("string"),Bo=Ir("text");function Ir(e){return{resolveAll:vr(e==="text"?jo:void 0),tokenize:t};function t(n){const r=this,i=this.parser.constructs[e],o=n.attempt(i,l,a);return l;function l(f){return u(f)?o(f):a(f)}function a(f){if(f===null){n.consume(f);return}return n.enter("data"),n.consume(f),s}function s(f){return u(f)?(n.exit("data"),o(f)):(n.consume(f),s)}function u(f){if(f===null)return!0;const c=i[f];let p=-1;if(c)for(;++p-1){const a=l[0];typeof a=="string"?l[0]=a.slice(r):l.shift()}o>0&&l.push(e[i].slice(0,o))}return l}function Zo(e,t){let n=-1;const r=[];let i;for(;++n4&&n.slice(0,4)==="data"&&Ai.test(t)){if(t.charAt(4)==="-"){const o=t.slice(5).replace(mt,Di);r="data"+o.charAt(0).toUpperCase()+o.slice(1)}else{const o=t.slice(4);if(!mt.test(o)){let l=o.replace(Ti,zi);l.charAt(0)!=="-"&&(l="-"+l),t="data"+l}}i=Hn}return new i(r,t)}function zi(e){return"-"+e.toLowerCase()}function Di(e){return e.charAt(1).toUpperCase()}const Li=tr([rr,Ei,or,ar,sr],"html"),qn=tr([rr,Ii,or,ar,sr],"svg");function _i(e){return e.join(" ").trim()}var De={},mn,dt;function Ri(){if(dt)return mn;dt=1;var e=/\/\*[^*]*\*+([^/*][^*]*\*+)*\//g,t=/\n/g,n=/^\s*/,r=/^(\*?[-#/*\\\w]+(\[[0-9a-z_-]+\])?)\s*/,i=/^:\s*/,o=/^((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^)]*?\)|[^};])+)/,l=/^[;\s]*/,a=/^\s+|\s+$/g,s=` +`,u="/",h="*",c="",p="comment",f="declaration";function g(S,y){if(typeof S!="string")throw new TypeError("First argument must be a string");if(!S)return[];y=y||{};var I=1,C=1;function R(D){var T=D.match(t);T&&(I+=T.length);var U=D.lastIndexOf(s);C=~U?D.length-U:C+D.length}function F(){var D={line:I,column:C};return function(T){return T.position=new b(D),j(),T}}function b(D){this.start=D,this.end={line:I,column:C},this.source=y.source}b.prototype.content=S;function M(D){var T=new Error(y.source+":"+I+":"+C+": "+D);if(T.reason=D,T.filename=y.source,T.line=I,T.column=C,T.source=S,!y.silent)throw T}function H(D){var T=D.exec(S);if(T){var U=T[0];return R(U),S=S.slice(U.length),T}}function j(){H(n)}function k(D){var T;for(D=D||[];T=A();)T!==!1&&D.push(T);return D}function A(){var D=F();if(!(u!=S.charAt(0)||h!=S.charAt(1))){for(var T=2;c!=S.charAt(T)&&(h!=S.charAt(T)||u!=S.charAt(T+1));)++T;if(T+=2,c===S.charAt(T-1))return M("End of comment missing");var U=S.slice(2,T-2);return C+=2,R(U),S=S.slice(T),C+=2,D({type:p,comment:U})}}function P(){var D=F(),T=H(r);if(T){if(A(),!H(i))return M("property missing ':'");var U=H(o),K=D({type:f,property:w(T[0].replace(e,c)),value:U?w(U[0].replace(e,c)):c});return H(l),K}}function q(){var D=[];k(D);for(var T;T=P();)T!==!1&&(D.push(T),k(D));return D}return j(),q()}function w(S){return S?S.replace(a,c):c}return mn=g,mn}var gt;function Fi(){if(gt)return De;gt=1;var e=De&&De.__importDefault||function(r){return r&&r.__esModule?r:{default:r}};Object.defineProperty(De,"__esModule",{value:!0}),De.default=n;const t=e(Ri());function n(r,i){let o=null;if(!r||typeof r!="string")return o;const l=(0,t.default)(r),a=typeof i=="function";return l.forEach(s=>{if(s.type!=="declaration")return;const{property:u,value:h}=s;a?i(u,h,s):h&&(o=o||{},o[u]=h)}),o}return De}var Be={},yt;function Oi(){if(yt)return Be;yt=1,Object.defineProperty(Be,"__esModule",{value:!0}),Be.camelCase=void 0;var e=/^--[a-zA-Z0-9_-]+$/,t=/-([a-z])/g,n=/^[^-]+$/,r=/^-(webkit|moz|ms|o|khtml)-/,i=/^-(ms)-/,o=function(u){return!u||n.test(u)||e.test(u)},l=function(u,h){return h.toUpperCase()},a=function(u,h){return"".concat(h,"-")},s=function(u,h){return h===void 0&&(h={}),o(u)?u:(u=u.toLowerCase(),h.reactCompat?u=u.replace(i,a):u=u.replace(r,a),u.replace(t,l))};return Be.camelCase=s,Be}var je,kt;function Mi(){if(kt)return je;kt=1;var e=je&&je.__importDefault||function(i){return i&&i.__esModule?i:{default:i}},t=e(Fi()),n=Oi();function r(i,o){var l={};return!i||typeof i!="string"||(0,t.default)(i,function(a,s){a&&s&&(l[(0,n.camelCase)(a,o)]=s)}),l}return r.default=r,je=r,je}var Ni=Mi();const Bi=nr(Ni),ur=cr("end"),Un=cr("start");function cr(e){return t;function t(n){const r=n&&n.position&&n.position[e]||{};if(typeof r.line=="number"&&r.line>0&&typeof r.column=="number"&&r.column>0)return{line:r.line,column:r.column,offset:typeof r.offset=="number"&&r.offset>-1?r.offset:void 0}}}function ji(e){const t=Un(e),n=ur(e);if(t&&n)return{start:t,end:n}}function Ue(e){return!e||typeof e!="object"?"":"position"in e||"type"in e?xt(e.position):"start"in e||"end"in e?xt(e):"line"in e||"column"in e?_n(e):""}function _n(e){return bt(e&&e.line)+":"+bt(e&&e.column)}function xt(e){return _n(e&&e.start)+"-"+_n(e&&e.end)}function bt(e){return e&&typeof e=="number"?e:1}class G extends Error{constructor(t,n,r){super(),typeof n=="string"&&(r=n,n=void 0);let i="",o={},l=!1;if(n&&("line"in n&&"column"in n?o={place:n}:"start"in n&&"end"in n?o={place:n}:"type"in n?o={ancestors:[n],place:n.position}:o={...n}),typeof t=="string"?i=t:!o.cause&&t&&(l=!0,i=t.message,o.cause=t),!o.ruleId&&!o.source&&typeof r=="string"){const s=r.indexOf(":");s===-1?o.ruleId=r:(o.source=r.slice(0,s),o.ruleId=r.slice(s+1))}if(!o.place&&o.ancestors&&o.ancestors){const s=o.ancestors[o.ancestors.length-1];s&&(o.place=s.position)}const a=o.place&&"start"in o.place?o.place.start:o.place;this.ancestors=o.ancestors||void 0,this.cause=o.cause||void 0,this.column=a?a.column:void 0,this.fatal=void 0,this.file="",this.message=i,this.line=a?a.line:void 0,this.name=Ue(o.place)||"1:1",this.place=o.place||void 0,this.reason=this.message,this.ruleId=o.ruleId||void 0,this.source=o.source||void 0,this.stack=l&&o.cause&&typeof o.cause.stack=="string"?o.cause.stack:"",this.actual=void 0,this.expected=void 0,this.note=void 0,this.url=void 0}}G.prototype.file="";G.prototype.name="";G.prototype.reason="";G.prototype.message="";G.prototype.stack="";G.prototype.column=void 0;G.prototype.line=void 0;G.prototype.ancestors=void 0;G.prototype.cause=void 0;G.prototype.fatal=void 0;G.prototype.place=void 0;G.prototype.ruleId=void 0;G.prototype.source=void 0;const Vn={}.hasOwnProperty,Hi=new Map,qi=/[A-Z]/g,Ui=new Set(["table","tbody","thead","tfoot","tr"]),Vi=new Set(["td","th"]),hr="https://github.com/syntax-tree/hast-util-to-jsx-runtime";function $i(e,t){if(!t||t.Fragment===void 0)throw new TypeError("Expected `Fragment` in options");const n=t.filePath||void 0;let r;if(t.development){if(typeof t.jsxDEV!="function")throw new TypeError("Expected `jsxDEV` in options when `development: true`");r=Zi(n,t.jsxDEV)}else{if(typeof t.jsx!="function")throw new TypeError("Expected `jsx` in production options");if(typeof t.jsxs!="function")throw new TypeError("Expected `jsxs` in production options");r=Ji(n,t.jsx,t.jsxs)}const i={Fragment:t.Fragment,ancestors:[],components:t.components||{},create:r,elementAttributeNameCase:t.elementAttributeNameCase||"react",evaluater:t.createEvaluater?t.createEvaluater():void 0,filePath:n,ignoreInvalidStyle:t.ignoreInvalidStyle||!1,passKeys:t.passKeys!==!1,passNode:t.passNode||!1,schema:t.space==="svg"?qn:Li,stylePropertyNameCase:t.stylePropertyNameCase||"dom",tableCellAlignToStyle:t.tableCellAlignToStyle!==!1},o=fr(i,e,void 0);return o&&typeof o!="string"?o:i.create(e,i.Fragment,{children:o||void 0},void 0)}function fr(e,t,n){if(t.type==="element")return Wi(e,t,n);if(t.type==="mdxFlowExpression"||t.type==="mdxTextExpression")return Yi(e,t);if(t.type==="mdxJsxFlowElement"||t.type==="mdxJsxTextElement")return Qi(e,t,n);if(t.type==="mdxjsEsm")return Ki(e,t);if(t.type==="root")return Xi(e,t,n);if(t.type==="text")return Gi(e,t)}function Wi(e,t,n){const r=e.schema;let i=r;t.tagName.toLowerCase()==="svg"&&r.space==="html"&&(i=qn,e.schema=i),e.ancestors.push(t);const o=mr(e,t.tagName,!1),l=el(e,t);let a=Wn(e,t);return Ui.has(t.tagName)&&(a=a.filter(function(s){return typeof s=="string"?!Si(s):!0})),pr(e,l,o,t),$n(l,a),e.ancestors.pop(),e.schema=r,e.create(t,o,l,n)}function Yi(e,t){if(t.data&&t.data.estree&&e.evaluater){const r=t.data.estree.body[0];return r.type,e.evaluater.evaluateExpression(r.expression)}We(e,t.position)}function Ki(e,t){if(t.data&&t.data.estree&&e.evaluater)return e.evaluater.evaluateProgram(t.data.estree);We(e,t.position)}function Qi(e,t,n){const r=e.schema;let i=r;t.name==="svg"&&r.space==="html"&&(i=qn,e.schema=i),e.ancestors.push(t);const o=t.name===null?e.Fragment:mr(e,t.name,!0),l=nl(e,t),a=Wn(e,t);return pr(e,l,o,t),$n(l,a),e.ancestors.pop(),e.schema=r,e.create(t,o,l,n)}function Xi(e,t,n){const r={};return $n(r,Wn(e,t)),e.create(t,e.Fragment,r,n)}function Gi(e,t){return t.value}function pr(e,t,n,r){typeof n!="string"&&n!==e.Fragment&&e.passNode&&(t.node=r)}function $n(e,t){if(t.length>0){const n=t.length>1?t:t[0];n&&(e.children=n)}}function Ji(e,t,n){return r;function r(i,o,l,a){const u=Array.isArray(l.children)?n:t;return a?u(o,l,a):u(o,l)}}function Zi(e,t){return n;function n(r,i,o,l){const a=Array.isArray(o.children),s=Un(r);return t(i,o,l,a,{columnNumber:s?s.column-1:void 0,fileName:e,lineNumber:s?s.line:void 0},void 0)}}function el(e,t){const n={};let r,i;for(i in t.properties)if(i!=="children"&&Vn.call(t.properties,i)){const o=tl(e,i,t.properties[i]);if(o){const[l,a]=o;e.tableCellAlignToStyle&&l==="align"&&typeof a=="string"&&Vi.has(t.tagName)?r=a:n[l]=a}}if(r){const o=n.style||(n.style={});o[e.stylePropertyNameCase==="css"?"text-align":"textAlign"]=r}return n}function nl(e,t){const n={};for(const r of t.attributes)if(r.type==="mdxJsxExpressionAttribute")if(r.data&&r.data.estree&&e.evaluater){const o=r.data.estree.body[0];o.type;const l=o.expression;l.type;const a=l.properties[0];a.type,Object.assign(n,e.evaluater.evaluateExpression(a.argument))}else We(e,t.position);else{const i=r.name;let o;if(r.value&&typeof r.value=="object")if(r.value.data&&r.value.data.estree&&e.evaluater){const a=r.value.data.estree.body[0];a.type,o=e.evaluater.evaluateExpression(a.expression)}else We(e,t.position);else o=r.value===null?!0:r.value;n[i]=o}return n}function Wn(e,t){const n=[];let r=-1;const i=e.passKeys?new Map:Hi;for(;++ri?0:i+t:t=t>i?i:t,n=n>0?n:0,r.length<1e4)l=Array.from(r),l.unshift(t,n),e.splice(...l);else for(n&&e.splice(t,n);o0?(ie(e,e.length,0,t),e):t}const Ct={}.hasOwnProperty;function gr(e){const t={};let n=-1;for(;++n13&&n<32||n>126&&n<160||n>55295&&n<57344||n>64975&&n<65008||(n&65535)===65535||(n&65535)===65534||n>1114111?"�":String.fromCodePoint(n)}function ce(e){return e.replace(/[\t\n\r ]+/g," ").replace(/^ | $/g,"").toLowerCase().toUpperCase()}const J=be(/[A-Za-z]/),X=be(/[\dA-Za-z]/),hl=be(/[#-'*+\--9=?A-Z^-~]/);function rn(e){return e!==null&&(e<32||e===127)}const Rn=be(/\d/),fl=be(/[\dA-Fa-f]/),pl=be(/[!-/:-@[-`{-~]/);function z(e){return e!==null&&e<-2}function W(e){return e!==null&&(e<0||e===32)}function O(e){return e===-2||e===-1||e===32}const sn=be(new RegExp("\\p{P}|\\p{S}","u")),ve=be(/\s/);function be(e){return t;function t(n){return n!==null&&n>-1&&e.test(String.fromCharCode(n))}}function Fe(e){const t=[];let n=-1,r=0,i=0;for(;++n55295&&o<57344){const a=e.charCodeAt(n+1);o<56320&&a>56319&&a<57344?(l=String.fromCharCode(o,a),i=1):l="�"}else l=String.fromCharCode(o);l&&(t.push(e.slice(r,n),encodeURIComponent(l)),r=n+i+1,l=""),i&&(n+=i,i=0)}return t.join("")+e.slice(r)}function B(e,t,n,r){const i=r?r-1:Number.POSITIVE_INFINITY;let o=0;return l;function l(s){return O(s)?(e.enter(n),a(s)):t(s)}function a(s){return O(s)&&o++l))return;const M=t.events.length;let H=M,j,k;for(;H--;)if(t.events[H][0]==="exit"&&t.events[H][1].type==="chunkFlow"){if(j){k=t.events[H][1].end;break}j=!0}for(y(r),b=M;bC;){const F=n[R];t.containerState=F[1],F[0].exit.call(t,e)}n.length=C}function I(){i.write([null]),o=void 0,i=void 0,t.containerState._closeFlow=void 0}}function kl(e,t,n){return B(e,e.attempt(this.parser.constructs.document,t,n),"linePrefix",this.parser.constructs.disable.null.includes("codeIndented")?void 0:4)}function _e(e){if(e===null||W(e)||ve(e))return 1;if(sn(e))return 2}function un(e,t,n){const r=[];let i=-1;for(;++i1&&e[n][1].end.offset-e[n][1].start.offset>1?2:1;const c={...e[r][1].end},p={...e[n][1].start};It(c,-s),It(p,s),l={type:s>1?"strongSequence":"emphasisSequence",start:c,end:{...e[r][1].end}},a={type:s>1?"strongSequence":"emphasisSequence",start:{...e[n][1].start},end:p},o={type:s>1?"strongText":"emphasisText",start:{...e[r][1].end},end:{...e[n][1].start}},i={type:s>1?"strong":"emphasis",start:{...l.start},end:{...a.end}},e[r][1].end={...l.start},e[n][1].start={...a.end},u=[],e[r][1].end.offset-e[r][1].start.offset&&(u=le(u,[["enter",e[r][1],t],["exit",e[r][1],t]])),u=le(u,[["enter",i,t],["enter",l,t],["exit",l,t],["enter",o,t]]),u=le(u,un(t.parser.constructs.insideSpan.null,e.slice(r+1,n),t)),u=le(u,[["exit",o,t],["enter",a,t],["exit",a,t],["exit",i,t]]),e[n][1].end.offset-e[n][1].start.offset?(h=2,u=le(u,[["enter",e[n][1],t],["exit",e[n][1],t]])):h=0,ie(e,r-1,n-r+3,u),n=r+u.length-h-2;break}}for(n=-1;++n0&&O(b)?B(e,I,"linePrefix",o+1)(b):I(b)}function I(b){return b===null||z(b)?e.check(vt,w,R)(b):(e.enter("codeFlowValue"),C(b))}function C(b){return b===null||z(b)?(e.exit("codeFlowValue"),I(b)):(e.consume(b),C)}function R(b){return e.exit("codeFenced"),t(b)}function F(b,M,H){let j=0;return k;function k(T){return b.enter("lineEnding"),b.consume(T),b.exit("lineEnding"),A}function A(T){return b.enter("codeFencedFence"),O(T)?B(b,P,"linePrefix",r.parser.constructs.disable.null.includes("codeIndented")?void 0:4)(T):P(T)}function P(T){return T===a?(b.enter("codeFencedFenceSequence"),q(T)):H(T)}function q(T){return T===a?(j++,b.consume(T),q):j>=l?(b.exit("codeFencedFenceSequence"),O(T)?B(b,D,"whitespace")(T):D(T)):H(T)}function D(T){return T===null||z(T)?(b.exit("codeFencedFence"),M(T)):H(T)}}}function zl(e,t,n){const r=this;return i;function i(l){return l===null?n(l):(e.enter("lineEnding"),e.consume(l),e.exit("lineEnding"),o)}function o(l){return r.parser.lazy[r.now().line]?n(l):t(l)}}const gn={name:"codeIndented",tokenize:Ll},Dl={partial:!0,tokenize:_l};function Ll(e,t,n){const r=this;return i;function i(u){return e.enter("codeIndented"),B(e,o,"linePrefix",5)(u)}function o(u){const h=r.events[r.events.length-1];return h&&h[1].type==="linePrefix"&&h[2].sliceSerialize(h[1],!0).length>=4?l(u):n(u)}function l(u){return u===null?s(u):z(u)?e.attempt(Dl,l,s)(u):(e.enter("codeFlowValue"),a(u))}function a(u){return u===null||z(u)?(e.exit("codeFlowValue"),l(u)):(e.consume(u),a)}function s(u){return e.exit("codeIndented"),t(u)}}function _l(e,t,n){const r=this;return i;function i(l){return r.parser.lazy[r.now().line]?n(l):z(l)?(e.enter("lineEnding"),e.consume(l),e.exit("lineEnding"),i):B(e,o,"linePrefix",5)(l)}function o(l){const a=r.events[r.events.length-1];return a&&a[1].type==="linePrefix"&&a[2].sliceSerialize(a[1],!0).length>=4?t(l):z(l)?i(l):n(l)}}const Rl={name:"codeText",previous:Ol,resolve:Fl,tokenize:Ml};function Fl(e){let t=e.length-4,n=3,r,i;if((e[n][1].type==="lineEnding"||e[n][1].type==="space")&&(e[t][1].type==="lineEnding"||e[t][1].type==="space")){for(r=n;++r=this.left.length+this.right.length)throw new RangeError("Cannot access index `"+t+"` in a splice buffer of size `"+(this.left.length+this.right.length)+"`");return tthis.left.length?this.right.slice(this.right.length-r+this.left.length,this.right.length-t+this.left.length).reverse():this.left.slice(t).concat(this.right.slice(this.right.length-r+this.left.length).reverse())}splice(t,n,r){const i=n||0;this.setCursor(Math.trunc(t));const o=this.right.splice(this.right.length-i,Number.POSITIVE_INFINITY);return r&&He(this.left,r),o.reverse()}pop(){return this.setCursor(Number.POSITIVE_INFINITY),this.left.pop()}push(t){this.setCursor(Number.POSITIVE_INFINITY),this.left.push(t)}pushMany(t){this.setCursor(Number.POSITIVE_INFINITY),He(this.left,t)}unshift(t){this.setCursor(0),this.right.push(t)}unshiftMany(t){this.setCursor(0),He(this.right,t.reverse())}setCursor(t){if(!(t===this.left.length||t>this.left.length&&this.right.length===0||t<0&&this.left.length===0))if(t=4?t(l):e.interrupt(r.parser.constructs.flow,n,t)(l)}}function Sr(e,t,n,r,i,o,l,a,s){const u=s||Number.POSITIVE_INFINITY;let h=0;return c;function c(y){return y===60?(e.enter(r),e.enter(i),e.enter(o),e.consume(y),e.exit(o),p):y===null||y===32||y===41||rn(y)?n(y):(e.enter(r),e.enter(l),e.enter(a),e.enter("chunkString",{contentType:"string"}),w(y))}function p(y){return y===62?(e.enter(o),e.consume(y),e.exit(o),e.exit(i),e.exit(r),t):(e.enter(a),e.enter("chunkString",{contentType:"string"}),f(y))}function f(y){return y===62?(e.exit("chunkString"),e.exit(a),p(y)):y===null||y===60||z(y)?n(y):(e.consume(y),y===92?g:f)}function g(y){return y===60||y===62||y===92?(e.consume(y),f):f(y)}function w(y){return!h&&(y===null||y===41||W(y))?(e.exit("chunkString"),e.exit(a),e.exit(l),e.exit(r),t(y)):h999||f===null||f===91||f===93&&!s||f===94&&!a&&"_hiddenFootnoteSupport"in l.parser.constructs?n(f):f===93?(e.exit(o),e.enter(i),e.consume(f),e.exit(i),e.exit(r),t):z(f)?(e.enter("lineEnding"),e.consume(f),e.exit("lineEnding"),h):(e.enter("chunkString",{contentType:"string"}),c(f))}function c(f){return f===null||f===91||f===93||z(f)||a++>999?(e.exit("chunkString"),h(f)):(e.consume(f),s||(s=!O(f)),f===92?p:c)}function p(f){return f===91||f===92||f===93?(e.consume(f),a++,c):c(f)}}function Er(e,t,n,r,i,o){let l;return a;function a(p){return p===34||p===39||p===40?(e.enter(r),e.enter(i),e.consume(p),e.exit(i),l=p===40?41:p,s):n(p)}function s(p){return p===l?(e.enter(i),e.consume(p),e.exit(i),e.exit(r),t):(e.enter(o),u(p))}function u(p){return p===l?(e.exit(o),s(l)):p===null?n(p):z(p)?(e.enter("lineEnding"),e.consume(p),e.exit("lineEnding"),B(e,u,"linePrefix")):(e.enter("chunkString",{contentType:"string"}),h(p))}function h(p){return p===l||p===null||z(p)?(e.exit("chunkString"),u(p)):(e.consume(p),p===92?c:h)}function c(p){return p===l||p===92?(e.consume(p),h):h(p)}}function Ve(e,t){let n;return r;function r(i){return z(i)?(e.enter("lineEnding"),e.consume(i),e.exit("lineEnding"),n=!0,r):O(i)?B(e,r,n?"linePrefix":"lineSuffix")(i):t(i)}}const $l={name:"definition",tokenize:Yl},Wl={partial:!0,tokenize:Kl};function Yl(e,t,n){const r=this;let i;return o;function o(f){return e.enter("definition"),l(f)}function l(f){return Cr.call(r,e,a,n,"definitionLabel","definitionLabelMarker","definitionLabelString")(f)}function a(f){return i=ce(r.sliceSerialize(r.events[r.events.length-1][1]).slice(1,-1)),f===58?(e.enter("definitionMarker"),e.consume(f),e.exit("definitionMarker"),s):n(f)}function s(f){return W(f)?Ve(e,u)(f):u(f)}function u(f){return Sr(e,h,n,"definitionDestination","definitionDestinationLiteral","definitionDestinationLiteralMarker","definitionDestinationRaw","definitionDestinationString")(f)}function h(f){return e.attempt(Wl,c,c)(f)}function c(f){return O(f)?B(e,p,"whitespace")(f):p(f)}function p(f){return f===null||z(f)?(e.exit("definition"),r.parser.defined.push(i),t(f)):n(f)}}function Kl(e,t,n){return r;function r(a){return W(a)?Ve(e,i)(a):n(a)}function i(a){return Er(e,o,n,"definitionTitle","definitionTitleMarker","definitionTitleString")(a)}function o(a){return O(a)?B(e,l,"whitespace")(a):l(a)}function l(a){return a===null||z(a)?t(a):n(a)}}const Ql={name:"hardBreakEscape",tokenize:Xl};function Xl(e,t,n){return r;function r(o){return e.enter("hardBreakEscape"),e.consume(o),i}function i(o){return z(o)?(e.exit("hardBreakEscape"),t(o)):n(o)}}const Gl={name:"headingAtx",resolve:Jl,tokenize:Zl};function Jl(e,t){let n=e.length-2,r=3,i,o;return e[r][1].type==="whitespace"&&(r+=2),n-2>r&&e[n][1].type==="whitespace"&&(n-=2),e[n][1].type==="atxHeadingSequence"&&(r===n-1||n-4>r&&e[n-2][1].type==="whitespace")&&(n-=r+1===n?2:4),n>r&&(i={type:"atxHeadingText",start:e[r][1].start,end:e[n][1].end},o={type:"chunkText",start:e[r][1].start,end:e[n][1].end,contentType:"text"},ie(e,r,n-r+1,[["enter",i,t],["enter",o,t],["exit",o,t],["exit",i,t]])),e}function Zl(e,t,n){let r=0;return i;function i(h){return e.enter("atxHeading"),o(h)}function o(h){return e.enter("atxHeadingSequence"),l(h)}function l(h){return h===35&&r++<6?(e.consume(h),l):h===null||W(h)?(e.exit("atxHeadingSequence"),a(h)):n(h)}function a(h){return h===35?(e.enter("atxHeadingSequence"),s(h)):h===null||z(h)?(e.exit("atxHeading"),t(h)):O(h)?B(e,a,"whitespace")(h):(e.enter("atxHeadingText"),u(h))}function s(h){return h===35?(e.consume(h),s):(e.exit("atxHeadingSequence"),a(h))}function u(h){return h===null||h===35||W(h)?(e.exit("atxHeadingText"),a(h)):(e.consume(h),u)}}const eo=["address","article","aside","base","basefont","blockquote","body","caption","center","col","colgroup","dd","details","dialog","dir","div","dl","dt","fieldset","figcaption","figure","footer","form","frame","frameset","h1","h2","h3","h4","h5","h6","head","header","hr","html","iframe","legend","li","link","main","menu","menuitem","nav","noframes","ol","optgroup","option","p","param","search","section","summary","table","tbody","td","tfoot","th","thead","title","tr","track","ul"],At=["pre","script","style","textarea"],no={concrete:!0,name:"htmlFlow",resolveTo:io,tokenize:lo},to={partial:!0,tokenize:ao},ro={partial:!0,tokenize:oo};function io(e){let t=e.length;for(;t--&&!(e[t][0]==="enter"&&e[t][1].type==="htmlFlow"););return t>1&&e[t-2][1].type==="linePrefix"&&(e[t][1].start=e[t-2][1].start,e[t+1][1].start=e[t-2][1].start,e.splice(t-2,2)),e}function lo(e,t,n){const r=this;let i,o,l,a,s;return u;function u(d){return h(d)}function h(d){return e.enter("htmlFlow"),e.enter("htmlFlowData"),e.consume(d),c}function c(d){return d===33?(e.consume(d),p):d===47?(e.consume(d),o=!0,w):d===63?(e.consume(d),i=3,r.interrupt?t:m):J(d)?(e.consume(d),l=String.fromCharCode(d),S):n(d)}function p(d){return d===45?(e.consume(d),i=2,f):d===91?(e.consume(d),i=5,a=0,g):J(d)?(e.consume(d),i=4,r.interrupt?t:m):n(d)}function f(d){return d===45?(e.consume(d),r.interrupt?t:m):n(d)}function g(d){const se="CDATA[";return d===se.charCodeAt(a++)?(e.consume(d),a===se.length?r.interrupt?t:P:g):n(d)}function w(d){return J(d)?(e.consume(d),l=String.fromCharCode(d),S):n(d)}function S(d){if(d===null||d===47||d===62||W(d)){const se=d===47,we=l.toLowerCase();return!se&&!o&&At.includes(we)?(i=1,r.interrupt?t(d):P(d)):eo.includes(l.toLowerCase())?(i=6,se?(e.consume(d),y):r.interrupt?t(d):P(d)):(i=7,r.interrupt&&!r.parser.lazy[r.now().line]?n(d):o?I(d):C(d))}return d===45||X(d)?(e.consume(d),l+=String.fromCharCode(d),S):n(d)}function y(d){return d===62?(e.consume(d),r.interrupt?t:P):n(d)}function I(d){return O(d)?(e.consume(d),I):k(d)}function C(d){return d===47?(e.consume(d),k):d===58||d===95||J(d)?(e.consume(d),R):O(d)?(e.consume(d),C):k(d)}function R(d){return d===45||d===46||d===58||d===95||X(d)?(e.consume(d),R):F(d)}function F(d){return d===61?(e.consume(d),b):O(d)?(e.consume(d),F):C(d)}function b(d){return d===null||d===60||d===61||d===62||d===96?n(d):d===34||d===39?(e.consume(d),s=d,M):O(d)?(e.consume(d),b):H(d)}function M(d){return d===s?(e.consume(d),s=null,j):d===null||z(d)?n(d):(e.consume(d),M)}function H(d){return d===null||d===34||d===39||d===47||d===60||d===61||d===62||d===96||W(d)?F(d):(e.consume(d),H)}function j(d){return d===47||d===62||O(d)?C(d):n(d)}function k(d){return d===62?(e.consume(d),A):n(d)}function A(d){return d===null||z(d)?P(d):O(d)?(e.consume(d),A):n(d)}function P(d){return d===45&&i===2?(e.consume(d),U):d===60&&i===1?(e.consume(d),K):d===62&&i===4?(e.consume(d),ae):d===63&&i===3?(e.consume(d),m):d===93&&i===5?(e.consume(d),pe):z(d)&&(i===6||i===7)?(e.exit("htmlFlowData"),e.check(to,me,q)(d)):d===null||z(d)?(e.exit("htmlFlowData"),q(d)):(e.consume(d),P)}function q(d){return e.check(ro,D,me)(d)}function D(d){return e.enter("lineEnding"),e.consume(d),e.exit("lineEnding"),T}function T(d){return d===null||z(d)?q(d):(e.enter("htmlFlowData"),P(d))}function U(d){return d===45?(e.consume(d),m):P(d)}function K(d){return d===47?(e.consume(d),l="",oe):P(d)}function oe(d){if(d===62){const se=l.toLowerCase();return At.includes(se)?(e.consume(d),ae):P(d)}return J(d)&&l.length<8?(e.consume(d),l+=String.fromCharCode(d),oe):P(d)}function pe(d){return d===93?(e.consume(d),m):P(d)}function m(d){return d===62?(e.consume(d),ae):d===45&&i===2?(e.consume(d),m):P(d)}function ae(d){return d===null||z(d)?(e.exit("htmlFlowData"),me(d)):(e.consume(d),ae)}function me(d){return e.exit("htmlFlow"),t(d)}}function oo(e,t,n){const r=this;return i;function i(l){return z(l)?(e.enter("lineEnding"),e.consume(l),e.exit("lineEnding"),o):n(l)}function o(l){return r.parser.lazy[r.now().line]?n(l):t(l)}}function ao(e,t,n){return r;function r(i){return e.enter("lineEnding"),e.consume(i),e.exit("lineEnding"),e.attempt(Qe,t,n)}}const so={name:"htmlText",tokenize:uo};function uo(e,t,n){const r=this;let i,o,l;return a;function a(m){return e.enter("htmlText"),e.enter("htmlTextData"),e.consume(m),s}function s(m){return m===33?(e.consume(m),u):m===47?(e.consume(m),F):m===63?(e.consume(m),C):J(m)?(e.consume(m),H):n(m)}function u(m){return m===45?(e.consume(m),h):m===91?(e.consume(m),o=0,g):J(m)?(e.consume(m),I):n(m)}function h(m){return m===45?(e.consume(m),f):n(m)}function c(m){return m===null?n(m):m===45?(e.consume(m),p):z(m)?(l=c,K(m)):(e.consume(m),c)}function p(m){return m===45?(e.consume(m),f):c(m)}function f(m){return m===62?U(m):m===45?p(m):c(m)}function g(m){const ae="CDATA[";return m===ae.charCodeAt(o++)?(e.consume(m),o===ae.length?w:g):n(m)}function w(m){return m===null?n(m):m===93?(e.consume(m),S):z(m)?(l=w,K(m)):(e.consume(m),w)}function S(m){return m===93?(e.consume(m),y):w(m)}function y(m){return m===62?U(m):m===93?(e.consume(m),y):w(m)}function I(m){return m===null||m===62?U(m):z(m)?(l=I,K(m)):(e.consume(m),I)}function C(m){return m===null?n(m):m===63?(e.consume(m),R):z(m)?(l=C,K(m)):(e.consume(m),C)}function R(m){return m===62?U(m):C(m)}function F(m){return J(m)?(e.consume(m),b):n(m)}function b(m){return m===45||X(m)?(e.consume(m),b):M(m)}function M(m){return z(m)?(l=M,K(m)):O(m)?(e.consume(m),M):U(m)}function H(m){return m===45||X(m)?(e.consume(m),H):m===47||m===62||W(m)?j(m):n(m)}function j(m){return m===47?(e.consume(m),U):m===58||m===95||J(m)?(e.consume(m),k):z(m)?(l=j,K(m)):O(m)?(e.consume(m),j):U(m)}function k(m){return m===45||m===46||m===58||m===95||X(m)?(e.consume(m),k):A(m)}function A(m){return m===61?(e.consume(m),P):z(m)?(l=A,K(m)):O(m)?(e.consume(m),A):j(m)}function P(m){return m===null||m===60||m===61||m===62||m===96?n(m):m===34||m===39?(e.consume(m),i=m,q):z(m)?(l=P,K(m)):O(m)?(e.consume(m),P):(e.consume(m),D)}function q(m){return m===i?(e.consume(m),i=void 0,T):m===null?n(m):z(m)?(l=q,K(m)):(e.consume(m),q)}function D(m){return m===null||m===34||m===39||m===60||m===61||m===96?n(m):m===47||m===62||W(m)?j(m):(e.consume(m),D)}function T(m){return m===47||m===62||W(m)?j(m):n(m)}function U(m){return m===62?(e.consume(m),e.exit("htmlTextData"),e.exit("htmlText"),t):n(m)}function K(m){return e.exit("htmlTextData"),e.enter("lineEnding"),e.consume(m),e.exit("lineEnding"),oe}function oe(m){return O(m)?B(e,pe,"linePrefix",r.parser.constructs.disable.null.includes("codeIndented")?void 0:4)(m):pe(m)}function pe(m){return e.enter("htmlTextData"),l(m)}}const Qn={name:"labelEnd",resolveAll:po,resolveTo:mo,tokenize:go},co={tokenize:yo},ho={tokenize:ko},fo={tokenize:xo};function po(e){let t=-1;const n=[];for(;++t=3&&(u===null||z(u))?(e.exit("thematicBreak"),t(u)):n(u)}function s(u){return u===i?(e.consume(u),r++,s):(e.exit("thematicBreakSequence"),O(u)?B(e,a,"whitespace")(u):a(u))}}const Z={continuation:{tokenize:Po},exit:Do,name:"list",tokenize:Ao},vo={partial:!0,tokenize:Lo},To={partial:!0,tokenize:zo};function Ao(e,t,n){const r=this,i=r.events[r.events.length-1];let o=i&&i[1].type==="linePrefix"?i[2].sliceSerialize(i[1],!0).length:0,l=0;return a;function a(f){const g=r.containerState.type||(f===42||f===43||f===45?"listUnordered":"listOrdered");if(g==="listUnordered"?!r.containerState.marker||f===r.containerState.marker:Rn(f)){if(r.containerState.type||(r.containerState.type=g,e.enter(g,{_container:!0})),g==="listUnordered")return e.enter("listItemPrefix"),f===42||f===45?e.check(tn,n,u)(f):u(f);if(!r.interrupt||f===49)return e.enter("listItemPrefix"),e.enter("listItemValue"),s(f)}return n(f)}function s(f){return Rn(f)&&++l<10?(e.consume(f),s):(!r.interrupt||l<2)&&(r.containerState.marker?f===r.containerState.marker:f===41||f===46)?(e.exit("listItemValue"),u(f)):n(f)}function u(f){return e.enter("listItemMarker"),e.consume(f),e.exit("listItemMarker"),r.containerState.marker=r.containerState.marker||f,e.check(Qe,r.interrupt?n:h,e.attempt(vo,p,c))}function h(f){return r.containerState.initialBlankLine=!0,o++,p(f)}function c(f){return O(f)?(e.enter("listItemPrefixWhitespace"),e.consume(f),e.exit("listItemPrefixWhitespace"),p):n(f)}function p(f){return r.containerState.size=o+r.sliceSerialize(e.exit("listItemPrefix"),!0).length,t(f)}}function Po(e,t,n){const r=this;return r.containerState._closeFlow=void 0,e.check(Qe,i,o);function i(a){return r.containerState.furtherBlankLines=r.containerState.furtherBlankLines||r.containerState.initialBlankLine,B(e,t,"listItemIndent",r.containerState.size+1)(a)}function o(a){return r.containerState.furtherBlankLines||!O(a)?(r.containerState.furtherBlankLines=void 0,r.containerState.initialBlankLine=void 0,l(a)):(r.containerState.furtherBlankLines=void 0,r.containerState.initialBlankLine=void 0,e.attempt(To,t,l)(a))}function l(a){return r.containerState._closeFlow=!0,r.interrupt=void 0,B(e,e.attempt(Z,t,n),"linePrefix",r.parser.constructs.disable.null.includes("codeIndented")?void 0:4)(a)}}function zo(e,t,n){const r=this;return B(e,i,"listItemIndent",r.containerState.size+1);function i(o){const l=r.events[r.events.length-1];return l&&l[1].type==="listItemIndent"&&l[2].sliceSerialize(l[1],!0).length===r.containerState.size?t(o):n(o)}}function Do(e){e.exit(this.containerState.type)}function Lo(e,t,n){const r=this;return B(e,i,"listItemPrefixWhitespace",r.parser.constructs.disable.null.includes("codeIndented")?void 0:5);function i(o){const l=r.events[r.events.length-1];return!O(o)&&l&&l[1].type==="listItemPrefixWhitespace"?t(o):n(o)}}const Pt={name:"setextUnderline",resolveTo:_o,tokenize:Ro};function _o(e,t){let n=e.length,r,i,o;for(;n--;)if(e[n][0]==="enter"){if(e[n][1].type==="content"){r=n;break}e[n][1].type==="paragraph"&&(i=n)}else e[n][1].type==="content"&&e.splice(n,1),!o&&e[n][1].type==="definition"&&(o=n);const l={type:"setextHeading",start:{...e[r][1].start},end:{...e[e.length-1][1].end}};return e[i][1].type="setextHeadingText",o?(e.splice(i,0,["enter",l,t]),e.splice(o+1,0,["exit",e[r][1],t]),e[r][1].end={...e[o][1].end}):e[r][1]=l,e.push(["exit",l,t]),e}function Ro(e,t,n){const r=this;let i;return o;function o(u){let h=r.events.length,c;for(;h--;)if(r.events[h][1].type!=="lineEnding"&&r.events[h][1].type!=="linePrefix"&&r.events[h][1].type!=="content"){c=r.events[h][1].type==="paragraph";break}return!r.parser.lazy[r.now().line]&&(r.interrupt||c)?(e.enter("setextHeadingLine"),i=u,l(u)):n(u)}function l(u){return e.enter("setextHeadingLineSequence"),a(u)}function a(u){return u===i?(e.consume(u),a):(e.exit("setextHeadingLineSequence"),O(u)?B(e,s,"lineSuffix")(u):s(u))}function s(u){return u===null||z(u)?(e.exit("setextHeadingLine"),t(u)):n(u)}}const Fo={tokenize:Oo};function Oo(e){const t=this,n=e.attempt(Qe,r,e.attempt(this.parser.constructs.flowInitial,i,B(e,e.attempt(this.parser.constructs.flow,i,e.attempt(jl,i)),"linePrefix")));return n;function r(o){if(o===null){e.consume(o);return}return e.enter("lineEndingBlank"),e.consume(o),e.exit("lineEndingBlank"),t.currentConstruct=void 0,n}function i(o){if(o===null){e.consume(o);return}return e.enter("lineEnding"),e.consume(o),e.exit("lineEnding"),t.currentConstruct=void 0,n}}const Mo={resolveAll:vr()},No=Ir("string"),Bo=Ir("text");function Ir(e){return{resolveAll:vr(e==="text"?jo:void 0),tokenize:t};function t(n){const r=this,i=this.parser.constructs[e],o=n.attempt(i,l,a);return l;function l(h){return u(h)?o(h):a(h)}function a(h){if(h===null){n.consume(h);return}return n.enter("data"),n.consume(h),s}function s(h){return u(h)?(n.exit("data"),o(h)):(n.consume(h),s)}function u(h){if(h===null)return!0;const c=i[h];let p=-1;if(c)for(;++p-1){const a=l[0];typeof a=="string"?l[0]=a.slice(r):l.shift()}o>0&&l.push(e[i].slice(0,o))}return l}function Zo(e,t){let n=-1;const r=[];let i;for(;++n0){const ue=_.tokenStack[_.tokenStack.length-1];(ue[1]||Dt).call(_,void 0,ue[0])}for(v.position={start:xe(x.length>0?x[0][1].start:{line:1,column:1,offset:0}),end:xe(x.length>0?x[x.length-2][1].end:{line:1,column:1,offset:0})},V=-1;++V0&&(r.className=["language-"+i[0]]);let o={type:"element",tagName:"code",properties:r,children:[{type:"text",value:n}]};return t.meta&&(o.data={meta:t.meta}),e.patch(t,o),o=e.applyData(t,o),o={type:"element",tagName:"pre",properties:{},children:[o]},e.patch(t,o),o}function pa(e,t){const n={type:"element",tagName:"del",properties:{},children:e.all(t)};return e.patch(t,n),e.applyData(t,n)}function ma(e,t){const n={type:"element",tagName:"em",properties:{},children:e.all(t)};return e.patch(t,n),e.applyData(t,n)}function da(e,t){const n=typeof e.options.clobberPrefix=="string"?e.options.clobberPrefix:"user-content-",r=String(t.identifier).toUpperCase(),i=Fe(r.toLowerCase()),o=e.footnoteOrder.indexOf(r);let l,a=e.footnoteCounts.get(r);a===void 0?(a=0,e.footnoteOrder.push(r),l=e.footnoteOrder.length):l=o+1,a+=1,e.footnoteCounts.set(r,a);const s={type:"element",tagName:"a",properties:{href:"#"+n+"fn-"+i,id:n+"fnref-"+i+(a>1?"-"+a:""),dataFootnoteRef:!0,ariaDescribedBy:["footnote-label"]},children:[{type:"text",value:String(l)}]};e.patch(t,s);const u={type:"element",tagName:"sup",properties:{},children:[s]};return e.patch(t,u),e.applyData(t,u)}function ga(e,t){const n={type:"element",tagName:"h"+t.depth,properties:{},children:e.all(t)};return e.patch(t,n),e.applyData(t,n)}function ya(e,t){if(e.options.allowDangerousHtml){const n={type:"raw",value:t.value};return e.patch(t,n),e.applyData(t,n)}}function Pr(e,t){const n=t.referenceType;let r="]";if(n==="collapsed"?r+="[]":n==="full"&&(r+="["+(t.label||t.identifier)+"]"),t.type==="imageReference")return[{type:"text",value:"!["+t.alt+r}];const i=e.all(t),o=i[0];o&&o.type==="text"?o.value="["+o.value:i.unshift({type:"text",value:"["});const l=i[i.length-1];return l&&l.type==="text"?l.value+=r:i.push({type:"text",value:r}),i}function ka(e,t){const n=String(t.identifier).toUpperCase(),r=e.definitionById.get(n);if(!r)return Pr(e,t);const i={src:Fe(r.url||""),alt:t.alt};r.title!==null&&r.title!==void 0&&(i.title=r.title);const o={type:"element",tagName:"img",properties:i,children:[]};return e.patch(t,o),e.applyData(t,o)}function xa(e,t){const n={src:Fe(t.url)};t.alt!==null&&t.alt!==void 0&&(n.alt=t.alt),t.title!==null&&t.title!==void 0&&(n.title=t.title);const r={type:"element",tagName:"img",properties:n,children:[]};return e.patch(t,r),e.applyData(t,r)}function ba(e,t){const n={type:"text",value:t.value.replace(/\r?\n|\r/g," ")};e.patch(t,n);const r={type:"element",tagName:"code",properties:{},children:[n]};return e.patch(t,r),e.applyData(t,r)}function wa(e,t){const n=String(t.identifier).toUpperCase(),r=e.definitionById.get(n);if(!r)return Pr(e,t);const i={href:Fe(r.url||"")};r.title!==null&&r.title!==void 0&&(i.title=r.title);const o={type:"element",tagName:"a",properties:i,children:e.all(t)};return e.patch(t,o),e.applyData(t,o)}function Sa(e,t){const n={href:Fe(t.url)};t.title!==null&&t.title!==void 0&&(n.title=t.title);const r={type:"element",tagName:"a",properties:n,children:e.all(t)};return e.patch(t,r),e.applyData(t,r)}function Ca(e,t,n){const r=e.all(t),i=n?Ea(n):zr(t),o={},l=[];if(typeof t.checked=="boolean"){const f=r[0];let c;f&&f.type==="element"&&f.tagName==="p"?c=f:(c={type:"element",tagName:"p",properties:{},children:[]},r.unshift(c)),c.children.length>0&&c.children.unshift({type:"text",value:" "}),c.children.unshift({type:"element",tagName:"input",properties:{type:"checkbox",checked:t.checked,disabled:!0},children:[]}),o.className=["task-list-item"]}let a=-1;for(;++a1}function Ia(e,t){const n={},r=e.all(t);let i=-1;for(typeof t.start=="number"&&t.start!==1&&(n.start=t.start);++i0){const l={type:"element",tagName:"tbody",properties:{},children:e.wrap(n,!0)},a=qn(t.children[1]),s=ur(t.children[t.children.length-1]);a&&s&&(l.position={start:a,end:s}),i.push(l)}const o={type:"element",tagName:"table",properties:{},children:e.wrap(i,!0)};return e.patch(t,o),e.applyData(t,o)}function za(e,t,n){const r=n?n.children:void 0,o=(r?r.indexOf(t):1)===0?"th":"td",l=n&&n.type==="table"?n.align:void 0,a=l?l.length:t.children.length;let s=-1;const u=[];for(;++s0,!0),r[0]),i=r.index+r[0].length,r=n.exec(t);return o.push(Rt(t.slice(i),i>0,!1)),o.join("")}function Rt(e,t,n){let r=0,i=e.length;if(t){let o=e.codePointAt(r);for(;o===Lt||o===_t;)r++,o=e.codePointAt(r)}if(n){let o=e.codePointAt(i-1);for(;o===Lt||o===_t;)i--,o=e.codePointAt(i-1)}return i>r?e.slice(r,i):""}function _a(e,t){const n={type:"text",value:La(String(t.value))};return e.patch(t,n),e.applyData(t,n)}function Ra(e,t){const n={type:"element",tagName:"hr",properties:{},children:[]};return e.patch(t,n),e.applyData(t,n)}const Fa={blockquote:ca,break:fa,code:ha,delete:pa,emphasis:ma,footnoteReference:da,heading:ga,html:ya,imageReference:ka,image:xa,inlineCode:ba,linkReference:wa,link:Sa,listItem:Ca,list:Ia,paragraph:va,root:Ta,strong:Aa,table:Pa,tableCell:Da,tableRow:za,text:_a,thematicBreak:Ra,toml:Je,yaml:Je,definition:Je,footnoteDefinition:Je};function Je(){}const Dr=-1,cn=0,$e=1,ln=2,Xn=3,Gn=4,Jn=5,Zn=6,Lr=7,_r=8,Rr=typeof self=="object"?self:globalThis,Ft=(e,t)=>{switch(e){case"Function":case"SharedWorker":case"Worker":case"eval":case"setInterval":case"setTimeout":throw new TypeError("unable to deserialize "+e)}return new Rr[e](t)},Oa=(e,t)=>{const n=(i,o)=>(e.set(o,i),i),r=i=>{if(e.has(i))return e.get(i);const[o,l]=t[i];switch(o){case cn:case Dr:return n(l,i);case $e:{const a=n([],i);for(const s of l)a.push(r(s));return a}case ln:{const a=n({},i);for(const[s,u]of l)a[r(s)]=r(u);return a}case Xn:return n(new Date(l),i);case Gn:{const{source:a,flags:s}=l;return n(new RegExp(a,s),i)}case Jn:{const a=n(new Map,i);for(const[s,u]of l)a.set(r(s),r(u));return a}case Zn:{const a=n(new Set,i);for(const s of l)a.add(r(s));return a}case Lr:{const{name:a,message:s}=l;return n(typeof Rr[a]=="function"?Ft(a,s):new Error(s),i)}case _r:return n(BigInt(l),i);case"BigInt":return n(Object(BigInt(l)),i);case"ArrayBuffer":return n(new Uint8Array(l).buffer,l);case"DataView":{const{buffer:a}=new Uint8Array(l);return n(new DataView(a),l)}}return n(Ft(o,l),i)};return r},Ot=e=>Oa(new Map,e)(0),Ee="",{toString:Ma}={},{keys:Na}=Object,Ue=e=>{const t=typeof e;if(t!=="object"||!e)return[cn,t];const n=Ma.call(e).slice(8,-1);switch(n){case"Array":return[$e,Ee];case"Object":return[ln,Ee];case"Date":return[Xn,Ee];case"RegExp":return[Gn,Ee];case"Map":return[Jn,Ee];case"Set":return[Zn,Ee];case"DataView":return[$e,n]}return n.includes("Array")?[$e,n]:e instanceof Error?[Lr,e.name||"Error"]:[ln,n]},Ze=([e,t])=>e===cn&&(t==="function"||t==="symbol"),Ba=(e,t,n,r)=>{const i=(l,a)=>{const s=r.push(l)-1;return n.set(a,s),s},o=l=>{if(n.has(l))return n.get(l);let[a,s]=Ue(l);switch(a){case cn:{let f=l;switch(s){case"bigint":a=_r,f=l.toString();break;case"function":case"symbol":if(e)throw new TypeError("unable to serialize "+s);f=null;break;case"undefined":return i([Dr],l)}return i([a,f],l)}case $e:{if(s){let p=l;return s==="DataView"?p=new Uint8Array(l.buffer):s==="ArrayBuffer"&&(p=new Uint8Array(l)),i([s,[...p]],l)}const f=[],c=i([a,f],l);for(const p of l)f.push(o(p));return c}case ln:{if(s)switch(s){case"BigInt":return i([s,l.toString()],l);case"Boolean":case"Number":case"String":return i([s,l.valueOf()],l)}if(t&&"toJSON"in l)return o(l.toJSON());const f=[],c=i([a,f],l);for(const p of Na(l))(e||!Ze(Ue(l[p])))&&f.push([o(p),o(l[p])]);return c}case Xn:return i([a,isNaN(l.getTime())?Ee:l.toISOString()],l);case Gn:{const{source:f,flags:c}=l;return i([a,{source:f,flags:c}],l)}case Jn:{const f=[],c=i([a,f],l);for(const[p,h]of l)(e||!(Ze(Ue(p))||Ze(Ue(h))))&&f.push([o(p),o(h)]);return c}case Zn:{const f=[],c=i([a,f],l);for(const p of l)(e||!Ze(Ue(p)))&&f.push(o(p));return c}}const{message:u}=l;return i([a,{name:s,message:u}],l)};return o},Mt=(e,{json:t,lossy:n}={})=>{const r=[];return Ba(!(t||n),!!t,new Map,r)(e),r},on=typeof structuredClone=="function"?(e,t)=>t&&("json"in t||"lossy"in t)?Ot(Mt(e,t)):structuredClone(e):(e,t)=>Ot(Mt(e,t));function ja(e,t){const n=[{type:"text",value:"↩"}];return t>1&&n.push({type:"element",tagName:"sup",properties:{},children:[{type:"text",value:String(t)}]}),n}function Ha(e,t){return"Back to reference "+(e+1)+(t>1?"-"+t:"")}function Ua(e){const t=typeof e.options.clobberPrefix=="string"?e.options.clobberPrefix:"user-content-",n=e.options.footnoteBackContent||ja,r=e.options.footnoteBackLabel||Ha,i=e.options.footnoteLabel||"Footnotes",o=e.options.footnoteLabelTagName||"h2",l=e.options.footnoteLabelProperties||{className:["sr-only"]},a=[];let s=-1;for(;++s0&&g.push({type:"text",value:" "});let I=typeof n=="string"?n:n(s,h);typeof I=="string"&&(I={type:"text",value:I}),g.push({type:"element",tagName:"a",properties:{href:"#"+t+"fnref-"+p+(h>1?"-"+h:""),dataFootnoteBackref:"",ariaLabel:typeof r=="string"?r:r(s,h),className:["data-footnote-backref"]},children:Array.isArray(I)?I:[I]})}const S=f[f.length-1];if(S&&S.type==="element"&&S.tagName==="p"){const I=S.children[S.children.length-1];I&&I.type==="text"?I.value+=" ":S.children.push({type:"text",value:" "}),S.children.push(...g)}else f.push(...g);const y={type:"element",tagName:"li",properties:{id:t+"fn-"+p},children:e.wrap(f,!0)};e.patch(u,y),a.push(y)}if(a.length!==0)return{type:"element",tagName:"section",properties:{dataFootnotes:!0,className:["footnotes"]},children:[{type:"element",tagName:o,properties:{...on(l),id:"footnote-label"},children:[{type:"text",value:i}]},{type:"text",value:` +`;break}case-2:{l=t?" ":" ";break}case-1:{if(!t&&i)continue;l=" ";break}default:l=String.fromCharCode(o)}i=o===-2,r.push(l)}return r.join("")}function ea(e){const r={constructs:gr([Xo,...(e||{}).extensions||[]]),content:i(ml),defined:[],document:i(gl),flow:i(Fo),lazy:{},string:i(No),text:i(Bo)};return r;function i(o){return l;function l(a){return Go(r,o,a)}}}function na(e){for(;!wr(e););return e}const zt=/[\0\t\n\r]/g;function ta(){let e=1,t="",n=!0,r;return i;function i(o,l,a){const s=[];let u,h,c,p,f;for(o=t+(typeof o=="string"?o.toString():new TextDecoder(l||void 0).decode(o)),c=0,t="",n&&(o.charCodeAt(0)===65279&&c++,n=void 0);c0){const ue=_.tokenStack[_.tokenStack.length-1];(ue[1]||Dt).call(_,void 0,ue[0])}for(v.position={start:xe(x.length>0?x[0][1].start:{line:1,column:1,offset:0}),end:xe(x.length>0?x[x.length-2][1].end:{line:1,column:1,offset:0})},V=-1;++V0&&(r.className=["language-"+i[0]]);let o={type:"element",tagName:"code",properties:r,children:[{type:"text",value:n}]};return t.meta&&(o.data={meta:t.meta}),e.patch(t,o),o=e.applyData(t,o),o={type:"element",tagName:"pre",properties:{},children:[o]},e.patch(t,o),o}function pa(e,t){const n={type:"element",tagName:"del",properties:{},children:e.all(t)};return e.patch(t,n),e.applyData(t,n)}function ma(e,t){const n={type:"element",tagName:"em",properties:{},children:e.all(t)};return e.patch(t,n),e.applyData(t,n)}function da(e,t){const n=typeof e.options.clobberPrefix=="string"?e.options.clobberPrefix:"user-content-",r=String(t.identifier).toUpperCase(),i=Fe(r.toLowerCase()),o=e.footnoteOrder.indexOf(r);let l,a=e.footnoteCounts.get(r);a===void 0?(a=0,e.footnoteOrder.push(r),l=e.footnoteOrder.length):l=o+1,a+=1,e.footnoteCounts.set(r,a);const s={type:"element",tagName:"a",properties:{href:"#"+n+"fn-"+i,id:n+"fnref-"+i+(a>1?"-"+a:""),dataFootnoteRef:!0,ariaDescribedBy:["footnote-label"]},children:[{type:"text",value:String(l)}]};e.patch(t,s);const u={type:"element",tagName:"sup",properties:{},children:[s]};return e.patch(t,u),e.applyData(t,u)}function ga(e,t){const n={type:"element",tagName:"h"+t.depth,properties:{},children:e.all(t)};return e.patch(t,n),e.applyData(t,n)}function ya(e,t){if(e.options.allowDangerousHtml){const n={type:"raw",value:t.value};return e.patch(t,n),e.applyData(t,n)}}function Pr(e,t){const n=t.referenceType;let r="]";if(n==="collapsed"?r+="[]":n==="full"&&(r+="["+(t.label||t.identifier)+"]"),t.type==="imageReference")return[{type:"text",value:"!["+t.alt+r}];const i=e.all(t),o=i[0];o&&o.type==="text"?o.value="["+o.value:i.unshift({type:"text",value:"["});const l=i[i.length-1];return l&&l.type==="text"?l.value+=r:i.push({type:"text",value:r}),i}function ka(e,t){const n=String(t.identifier).toUpperCase(),r=e.definitionById.get(n);if(!r)return Pr(e,t);const i={src:Fe(r.url||""),alt:t.alt};r.title!==null&&r.title!==void 0&&(i.title=r.title);const o={type:"element",tagName:"img",properties:i,children:[]};return e.patch(t,o),e.applyData(t,o)}function xa(e,t){const n={src:Fe(t.url)};t.alt!==null&&t.alt!==void 0&&(n.alt=t.alt),t.title!==null&&t.title!==void 0&&(n.title=t.title);const r={type:"element",tagName:"img",properties:n,children:[]};return e.patch(t,r),e.applyData(t,r)}function ba(e,t){const n={type:"text",value:t.value.replace(/\r?\n|\r/g," ")};e.patch(t,n);const r={type:"element",tagName:"code",properties:{},children:[n]};return e.patch(t,r),e.applyData(t,r)}function wa(e,t){const n=String(t.identifier).toUpperCase(),r=e.definitionById.get(n);if(!r)return Pr(e,t);const i={href:Fe(r.url||"")};r.title!==null&&r.title!==void 0&&(i.title=r.title);const o={type:"element",tagName:"a",properties:i,children:e.all(t)};return e.patch(t,o),e.applyData(t,o)}function Sa(e,t){const n={href:Fe(t.url)};t.title!==null&&t.title!==void 0&&(n.title=t.title);const r={type:"element",tagName:"a",properties:n,children:e.all(t)};return e.patch(t,r),e.applyData(t,r)}function Ca(e,t,n){const r=e.all(t),i=n?Ea(n):zr(t),o={},l=[];if(typeof t.checked=="boolean"){const h=r[0];let c;h&&h.type==="element"&&h.tagName==="p"?c=h:(c={type:"element",tagName:"p",properties:{},children:[]},r.unshift(c)),c.children.length>0&&c.children.unshift({type:"text",value:" "}),c.children.unshift({type:"element",tagName:"input",properties:{type:"checkbox",checked:t.checked,disabled:!0},children:[]}),o.className=["task-list-item"]}let a=-1;for(;++a1}function Ia(e,t){const n={},r=e.all(t);let i=-1;for(typeof t.start=="number"&&t.start!==1&&(n.start=t.start);++i0){const l={type:"element",tagName:"tbody",properties:{},children:e.wrap(n,!0)},a=Un(t.children[1]),s=ur(t.children[t.children.length-1]);a&&s&&(l.position={start:a,end:s}),i.push(l)}const o={type:"element",tagName:"table",properties:{},children:e.wrap(i,!0)};return e.patch(t,o),e.applyData(t,o)}function za(e,t,n){const r=n?n.children:void 0,o=(r?r.indexOf(t):1)===0?"th":"td",l=n&&n.type==="table"?n.align:void 0,a=l?l.length:t.children.length;let s=-1;const u=[];for(;++s0,!0),r[0]),i=r.index+r[0].length,r=n.exec(t);return o.push(Rt(t.slice(i),i>0,!1)),o.join("")}function Rt(e,t,n){let r=0,i=e.length;if(t){let o=e.codePointAt(r);for(;o===Lt||o===_t;)r++,o=e.codePointAt(r)}if(n){let o=e.codePointAt(i-1);for(;o===Lt||o===_t;)i--,o=e.codePointAt(i-1)}return i>r?e.slice(r,i):""}function _a(e,t){const n={type:"text",value:La(String(t.value))};return e.patch(t,n),e.applyData(t,n)}function Ra(e,t){const n={type:"element",tagName:"hr",properties:{},children:[]};return e.patch(t,n),e.applyData(t,n)}const Fa={blockquote:ca,break:ha,code:fa,delete:pa,emphasis:ma,footnoteReference:da,heading:ga,html:ya,imageReference:ka,image:xa,inlineCode:ba,linkReference:wa,link:Sa,listItem:Ca,list:Ia,paragraph:va,root:Ta,strong:Aa,table:Pa,tableCell:Da,tableRow:za,text:_a,thematicBreak:Ra,toml:Je,yaml:Je,definition:Je,footnoteDefinition:Je};function Je(){}const Dr=-1,cn=0,$e=1,ln=2,Xn=3,Gn=4,Jn=5,Zn=6,Lr=7,_r=8,Rr=typeof self=="object"?self:globalThis,Ft=(e,t)=>{switch(e){case"Function":case"SharedWorker":case"Worker":case"eval":case"setInterval":case"setTimeout":throw new TypeError("unable to deserialize "+e)}return new Rr[e](t)},Oa=(e,t)=>{const n=(i,o)=>(e.set(o,i),i),r=i=>{if(e.has(i))return e.get(i);const[o,l]=t[i];switch(o){case cn:case Dr:return n(l,i);case $e:{const a=n([],i);for(const s of l)a.push(r(s));return a}case ln:{const a=n({},i);for(const[s,u]of l)a[r(s)]=r(u);return a}case Xn:return n(new Date(l),i);case Gn:{const{source:a,flags:s}=l;return n(new RegExp(a,s),i)}case Jn:{const a=n(new Map,i);for(const[s,u]of l)a.set(r(s),r(u));return a}case Zn:{const a=n(new Set,i);for(const s of l)a.add(r(s));return a}case Lr:{const{name:a,message:s}=l;return n(typeof Rr[a]=="function"?Ft(a,s):new Error(s),i)}case _r:return n(BigInt(l),i);case"BigInt":return n(Object(BigInt(l)),i);case"ArrayBuffer":return n(new Uint8Array(l).buffer,l);case"DataView":{const{buffer:a}=new Uint8Array(l);return n(new DataView(a),l)}}return n(Ft(o,l),i)};return r},Ot=e=>Oa(new Map,e)(0),Ee="",{toString:Ma}={},{keys:Na}=Object,qe=e=>{const t=typeof e;if(t!=="object"||!e)return[cn,t];const n=Ma.call(e).slice(8,-1);switch(n){case"Array":return[$e,Ee];case"Object":return[ln,Ee];case"Date":return[Xn,Ee];case"RegExp":return[Gn,Ee];case"Map":return[Jn,Ee];case"Set":return[Zn,Ee];case"DataView":return[$e,n]}return n.includes("Array")?[$e,n]:e instanceof Error?[Lr,e.name||"Error"]:[ln,n]},Ze=([e,t])=>e===cn&&(t==="function"||t==="symbol"),Ba=(e,t,n,r)=>{const i=(l,a)=>{const s=r.push(l)-1;return n.set(a,s),s},o=l=>{if(n.has(l))return n.get(l);let[a,s]=qe(l);switch(a){case cn:{let h=l;switch(s){case"bigint":a=_r,h=l.toString();break;case"function":case"symbol":if(e)throw new TypeError("unable to serialize "+s);h=null;break;case"undefined":return i([Dr],l)}return i([a,h],l)}case $e:{if(s){let p=l;return s==="DataView"?p=new Uint8Array(l.buffer):s==="ArrayBuffer"&&(p=new Uint8Array(l)),i([s,[...p]],l)}const h=[],c=i([a,h],l);for(const p of l)h.push(o(p));return c}case ln:{if(s)switch(s){case"BigInt":return i([s,l.toString()],l);case"Boolean":case"Number":case"String":return i([s,l.valueOf()],l)}if(t&&"toJSON"in l)return o(l.toJSON());const h=[],c=i([a,h],l);for(const p of Na(l))(e||!Ze(qe(l[p])))&&h.push([o(p),o(l[p])]);return c}case Xn:return i([a,isNaN(l.getTime())?Ee:l.toISOString()],l);case Gn:{const{source:h,flags:c}=l;return i([a,{source:h,flags:c}],l)}case Jn:{const h=[],c=i([a,h],l);for(const[p,f]of l)(e||!(Ze(qe(p))||Ze(qe(f))))&&h.push([o(p),o(f)]);return c}case Zn:{const h=[],c=i([a,h],l);for(const p of l)(e||!Ze(qe(p)))&&h.push(o(p));return c}}const{message:u}=l;return i([a,{name:s,message:u}],l)};return o},Mt=(e,{json:t,lossy:n}={})=>{const r=[];return Ba(!(t||n),!!t,new Map,r)(e),r},on=typeof structuredClone=="function"?(e,t)=>t&&("json"in t||"lossy"in t)?Ot(Mt(e,t)):structuredClone(e):(e,t)=>Ot(Mt(e,t));function ja(e,t){const n=[{type:"text",value:"↩"}];return t>1&&n.push({type:"element",tagName:"sup",properties:{},children:[{type:"text",value:String(t)}]}),n}function Ha(e,t){return"Back to reference "+(e+1)+(t>1?"-"+t:"")}function qa(e){const t=typeof e.options.clobberPrefix=="string"?e.options.clobberPrefix:"user-content-",n=e.options.footnoteBackContent||ja,r=e.options.footnoteBackLabel||Ha,i=e.options.footnoteLabel||"Footnotes",o=e.options.footnoteLabelTagName||"h2",l=e.options.footnoteLabelProperties||{className:["sr-only"]},a=[];let s=-1;for(;++s0&&g.push({type:"text",value:" "});let I=typeof n=="string"?n:n(s,f);typeof I=="string"&&(I={type:"text",value:I}),g.push({type:"element",tagName:"a",properties:{href:"#"+t+"fnref-"+p+(f>1?"-"+f:""),dataFootnoteBackref:"",ariaLabel:typeof r=="string"?r:r(s,f),className:["data-footnote-backref"]},children:Array.isArray(I)?I:[I]})}const S=h[h.length-1];if(S&&S.type==="element"&&S.tagName==="p"){const I=S.children[S.children.length-1];I&&I.type==="text"?I.value+=" ":S.children.push({type:"text",value:" "}),S.children.push(...g)}else h.push(...g);const y={type:"element",tagName:"li",properties:{id:t+"fn-"+p},children:e.wrap(h,!0)};e.patch(u,y),a.push(y)}if(a.length!==0)return{type:"element",tagName:"section",properties:{dataFootnotes:!0,className:["footnotes"]},children:[{type:"element",tagName:o,properties:{...on(l),id:"footnote-label"},children:[{type:"text",value:i}]},{type:"text",value:` `},{type:"element",tagName:"ol",properties:{},children:e.wrap(a,!0)},{type:"text",value:` -`}]}}const fn=(function(e){if(e==null)return Wa;if(typeof e=="function")return hn(e);if(typeof e=="object")return Array.isArray(e)?qa(e):Va(e);if(typeof e=="string")return $a(e);throw new Error("Expected function, string, or object as test")});function qa(e){const t=[];let n=-1;for(;++n":""))+")"})}return p;function p(){let h=Fr,g,w,S;if((!t||o(s,u,f[f.length-1]||void 0))&&(h=Xa(n(s,f)),h[0]===On))return h;if("children"in s&&s.children){const y=s;if(y.children&&h[0]!==Qa)for(w=(r?y.children.length:-1)+l,S=f.concat(y);w>-1&&w":""))+")"})}return p;function p(){let f=Fr,g,w,S;if((!t||o(s,u,h[h.length-1]||void 0))&&(f=Xa(n(s,h)),f[0]===On))return f;if("children"in s&&s.children){const y=s;if(y.children&&f[0]!==Qa)for(w=(r?y.children.length:-1)+l,S=h.concat(y);w>-1&&w0&&n.push({type:"text",value:` -`}),n}function Nt(e){let t=0,n=e.charCodeAt(t);for(;n===9||n===32;)t++,n=e.charCodeAt(t);return e.slice(t)}function Bt(e,t){const n=Ja(e,t),r=n.one(e,void 0),i=Ua(n),o=Array.isArray(r)?{type:"root",children:r}:r||{type:"root",children:[]};return i&&o.children.push({type:"text",value:` -`},i),o}function rs(e,t){return e&&"run"in e?async function(n,r){const i=Bt(n,{file:r,...t});await e.run(i,r)}:function(n,r){return Bt(n,{file:r,...e||t})}}function jt(e){if(e)throw e}var kn,Ht;function is(){if(Ht)return kn;Ht=1;var e=Object.prototype.hasOwnProperty,t=Object.prototype.toString,n=Object.defineProperty,r=Object.getOwnPropertyDescriptor,i=function(u){return typeof Array.isArray=="function"?Array.isArray(u):t.call(u)==="[object Array]"},o=function(u){if(!u||t.call(u)!=="[object Object]")return!1;var f=e.call(u,"constructor"),c=u.constructor&&u.constructor.prototype&&e.call(u.constructor.prototype,"isPrototypeOf");if(u.constructor&&!f&&!c)return!1;var p;for(p in u);return typeof p>"u"||e.call(u,p)},l=function(u,f){n&&f.name==="__proto__"?n(u,f.name,{enumerable:!0,configurable:!0,value:f.newValue,writable:!0}):u[f.name]=f.newValue},a=function(u,f){if(f==="__proto__")if(e.call(u,f)){if(r)return r(u,f).value}else return;return u[f]};return kn=function s(){var u,f,c,p,h,g,w=arguments[0],S=1,y=arguments.length,I=!1;for(typeof w=="boolean"&&(I=w,w=arguments[1]||{},S=2),(w==null||typeof w!="object"&&typeof w!="function")&&(w={});Sl.length;let s;a&&l.push(i);try{s=e.apply(this,l)}catch(u){const f=u;if(a&&n)throw f;return i(f)}a||(s&&s.then&&typeof s.then=="function"?s.then(o,i):s instanceof Error?i(s):o(s))}function i(l,...a){n||(n=!0,t(l,...a))}function o(l){i(null,l)}}const fe={basename:ss,dirname:us,extname:cs,join:fs,sep:"/"};function ss(e,t){if(t!==void 0&&typeof t!="string")throw new TypeError('"ext" argument must be a string');Xe(e);let n=0,r=-1,i=e.length,o;if(t===void 0||t.length===0||t.length>e.length){for(;i--;)if(e.codePointAt(i)===47){if(o){n=i+1;break}}else r<0&&(o=!0,r=i+1);return r<0?"":e.slice(n,r)}if(t===e)return"";let l=-1,a=t.length-1;for(;i--;)if(e.codePointAt(i)===47){if(o){n=i+1;break}}else l<0&&(o=!0,l=i+1),a>-1&&(e.codePointAt(i)===t.codePointAt(a--)?a<0&&(r=i):(a=-1,r=l));return n===r?r=l:r<0&&(r=e.length),e.slice(n,r)}function us(e){if(Xe(e),e.length===0)return".";let t=-1,n=e.length,r;for(;--n;)if(e.codePointAt(n)===47){if(r){t=n;break}}else r||(r=!0);return t<0?e.codePointAt(0)===47?"/":".":t===1&&e.codePointAt(0)===47?"//":e.slice(0,t)}function cs(e){Xe(e);let t=e.length,n=-1,r=0,i=-1,o=0,l;for(;t--;){const a=e.codePointAt(t);if(a===47){if(l){r=t+1;break}continue}n<0&&(l=!0,n=t+1),a===46?i<0?i=t:o!==1&&(o=1):i>-1&&(o=-1)}return i<0||n<0||o===0||o===1&&i===n-1&&i===r+1?"":e.slice(i,n)}function fs(...e){let t=-1,n;for(;++t0&&e.codePointAt(e.length-1)===47&&(n+="/"),t?"/"+n:n}function ps(e,t){let n="",r=0,i=-1,o=0,l=-1,a,s;for(;++l<=e.length;){if(l2){if(s=n.lastIndexOf("/"),s!==n.length-1){s<0?(n="",r=0):(n=n.slice(0,s),r=n.length-1-n.lastIndexOf("/")),i=l,o=0;continue}}else if(n.length>0){n="",r=0,i=l,o=0;continue}}t&&(n=n.length>0?n+"/..":"..",r=2)}else n.length>0?n+="/"+e.slice(i+1,l):n=e.slice(i+1,l),r=l-i-1;i=l,o=0}else a===46&&o>-1?o++:o=-1}return n}function Xe(e){if(typeof e!="string")throw new TypeError("Path must be a string. Received "+JSON.stringify(e))}const ms={cwd:ds};function ds(){return"/"}function Bn(e){return!!(e!==null&&typeof e=="object"&&"href"in e&&e.href&&"protocol"in e&&e.protocol&&e.auth===void 0)}function gs(e){if(typeof e=="string")e=new URL(e);else if(!Bn(e)){const t=new TypeError('The "path" argument must be of type string or an instance of URL. Received `'+e+"`");throw t.code="ERR_INVALID_ARG_TYPE",t}if(e.protocol!=="file:"){const t=new TypeError("The URL must be of scheme file");throw t.code="ERR_INVALID_URL_SCHEME",t}return ys(e)}function ys(e){if(e.hostname!==""){const r=new TypeError('File URL host must be "localhost" or empty on darwin');throw r.code="ERR_INVALID_FILE_URL_HOST",r}const t=e.pathname;let n=-1;for(;++n0){let[h,...g]=f;const w=r[p][1];Nn(w)&&Nn(h)&&(h=xn(!0,w,h)),r[p]=[u,h,...g]}}}}const ws=new nt().freeze();function Cn(e,t){if(typeof t!="function")throw new TypeError("Cannot `"+e+"` without `parser`")}function En(e,t){if(typeof t!="function")throw new TypeError("Cannot `"+e+"` without `compiler`")}function In(e,t){if(t)throw new Error("Cannot call `"+e+"` on a frozen processor.\nCreate a new processor first, by calling it: use `processor()` instead of `processor`.")}function qt(e){if(!Nn(e)||typeof e.type!="string")throw new TypeError("Expected node, got `"+e+"`")}function Vt(e,t,n){if(!n)throw new Error("`"+e+"` finished async. Use `"+t+"` instead")}function en(e){return Ss(e)?e:new Mr(e)}function Ss(e){return!!(e&&typeof e=="object"&&"message"in e&&"messages"in e)}function Cs(e){return typeof e=="string"||Es(e)}function Es(e){return!!(e&&typeof e=="object"&&"byteLength"in e&&"byteOffset"in e)}const Is="https://github.com/remarkjs/react-markdown/blob/main/changelog.md",$t=[],Wt={allowDangerousHtml:!0},vs=/^(https?|ircs?|mailto|xmpp)$/i,Ts=[{from:"astPlugins",id:"remove-buggy-html-in-markdown-parser"},{from:"allowDangerousHtml",id:"remove-buggy-html-in-markdown-parser"},{from:"allowNode",id:"replace-allownode-allowedtypes-and-disallowedtypes",to:"allowElement"},{from:"allowedTypes",id:"replace-allownode-allowedtypes-and-disallowedtypes",to:"allowedElements"},{from:"disallowedTypes",id:"replace-allownode-allowedtypes-and-disallowedtypes",to:"disallowedElements"},{from:"escapeHtml",id:"remove-buggy-html-in-markdown-parser"},{from:"includeElementIndex",id:"#remove-includeelementindex"},{from:"includeNodeIndex",id:"change-includenodeindex-to-includeelementindex"},{from:"linkTarget",id:"remove-linktarget"},{from:"plugins",id:"change-plugins-to-remarkplugins",to:"remarkPlugins"},{from:"rawSourcePos",id:"#remove-rawsourcepos"},{from:"renderers",id:"change-renderers-to-components",to:"components"},{from:"source",id:"change-source-to-children",to:"children"},{from:"sourcePos",id:"#remove-sourcepos"},{from:"transformImageUri",id:"#add-urltransform",to:"urlTransform"},{from:"transformLinkUri",id:"#add-urltransform",to:"urlTransform"}];function As(e){const t=Ps(e),n=zs(e);return Ds(t.runSync(t.parse(n),n),e)}function Ps(e){const t=e.rehypePlugins||$t,n=e.remarkPlugins||$t,r=e.remarkRehypeOptions?{...e.remarkRehypeOptions,...Wt}:Wt;return ws().use(ua).use(n).use(rs,r).use(t)}function zs(e){const t=e.children||"",n=new Mr;return typeof t=="string"&&(n.value=t),n}function Ds(e,t){const n=t.allowedElements,r=t.allowElement,i=t.components,o=t.disallowedElements,l=t.skipHtml,a=t.unwrapDisallowed,s=t.urlTransform||Ls;for(const f of Ts)Object.hasOwn(t,f.from)&&(""+f.from+(f.to?"use `"+f.to+"` instead":"remove it")+Is+f.id,void 0);return t.className&&(e={type:"element",tagName:"div",properties:{className:t.className},children:e.type==="root"?e.children:[e]}),et(e,u),$i(e,{Fragment:re.Fragment,components:i,ignoreInvalidStyle:!0,jsx:re.jsx,jsxs:re.jsxs,passKeys:!0,passNode:!0});function u(f,c,p){if(f.type==="raw"&&p&&typeof c=="number")return l?p.children.splice(c,1):p.children[c]={type:"text",value:f.value},c;if(f.type==="element"){let h;for(h in dn)if(Object.hasOwn(dn,h)&&Object.hasOwn(f.properties,h)){const g=f.properties[h],w=dn[h];(w===null||w.includes(f.tagName))&&(f.properties[h]=s(String(g||""),h,f))}}if(f.type==="element"){let h=n?!n.includes(f.tagName):o?o.includes(f.tagName):!1;if(!h&&r&&typeof c=="number"&&(h=!r(f,c,p)),h&&p&&typeof c=="number")return a&&f.children?p.children.splice(c,1,...f.children):p.children.splice(c,1),c}}}function Ls(e){const t=e.indexOf(":"),n=e.indexOf("?"),r=e.indexOf("#"),i=e.indexOf("/");return t===-1||i!==-1&&t>i||n!==-1&&t>n||r!==-1&&t>r||vs.test(e.slice(0,t))?e:""}function Yt(e,t){const n=String(e);if(typeof t!="string")throw new TypeError("Expected character");let r=0,i=n.indexOf(t);for(;i!==-1;)r++,i=n.indexOf(t,i+t.length);return r}function _s(e){if(typeof e!="string")throw new TypeError("Expected a string");return e.replace(/[|\\{}()[\]^$+*?.]/g,"\\$&").replace(/-/g,"\\x2d")}function Rs(e,t,n){const i=fn((n||{}).ignore||[]),o=Fs(t);let l=-1;for(;++l0?{type:"text",value:b}:void 0),b===!1?p.lastIndex=R+1:(g!==R&&I.push({type:"text",value:u.value.slice(g,R)}),Array.isArray(b)?I.push(...b):b&&I.push(b),g=R+C[0].length,y=!0),!p.global)break;C=p.exec(u.value)}return y?(g?\]}]+$/.exec(e);if(!t)return[e,void 0];e=e.slice(0,t.index);let n=t[0],r=n.indexOf(")");const i=Yt(e,"(");let o=Yt(e,")");for(;r!==-1&&i>o;)e+=n.slice(0,r+1),n=n.slice(r+1),r=n.indexOf(")"),o++;return[e,n]}function Nr(e,t){const n=e.input.charCodeAt(e.index-1);return(e.index===0||ve(n)||sn(n))&&(!t||n!==47)}Br.peek=iu;function Xs(){this.buffer()}function Gs(e){this.enter({type:"footnoteReference",identifier:"",label:""},e)}function Js(){this.buffer()}function Zs(e){this.enter({type:"footnoteDefinition",identifier:"",label:"",children:[]},e)}function eu(e){const t=this.resume(),n=this.stack[this.stack.length-1];n.type,n.identifier=ce(this.sliceSerialize(e)).toLowerCase(),n.label=t}function nu(e){this.exit(e)}function tu(e){const t=this.resume(),n=this.stack[this.stack.length-1];n.type,n.identifier=ce(this.sliceSerialize(e)).toLowerCase(),n.label=t}function ru(e){this.exit(e)}function iu(){return"["}function Br(e,t,n,r){const i=n.createTracker(r);let o=i.move("[^");const l=n.enter("footnoteReference"),a=n.enter("reference");return o+=i.move(n.safe(n.associationId(e),{after:"]",before:o})),a(),l(),o+=i.move("]"),o}function lu(){return{enter:{gfmFootnoteCallString:Xs,gfmFootnoteCall:Gs,gfmFootnoteDefinitionLabelString:Js,gfmFootnoteDefinition:Zs},exit:{gfmFootnoteCallString:eu,gfmFootnoteCall:nu,gfmFootnoteDefinitionLabelString:tu,gfmFootnoteDefinition:ru}}}function ou(e){let t=!1;return e&&e.firstLineBlank&&(t=!0),{handlers:{footnoteDefinition:n,footnoteReference:Br},unsafe:[{character:"[",inConstruct:["label","phrasing","reference"]}]};function n(r,i,o,l){const a=o.createTracker(l);let s=a.move("[^");const u=o.enter("footnoteDefinition"),f=o.enter("label");return s+=a.move(o.safe(o.associationId(r),{before:s,after:"]"})),f(),s+=a.move("]:"),r.children&&r.children.length>0&&(a.shift(4),s+=a.move((t?` -`:" ")+o.indentLines(o.containerFlow(r,a.current()),t?jr:au))),u(),s}}function au(e,t,n){return t===0?e:jr(e,t,n)}function jr(e,t,n){return(n?"":" ")+e}const su=["autolink","destinationLiteral","destinationRaw","reference","titleQuote","titleApostrophe"];Hr.peek=pu;function uu(){return{canContainEols:["delete"],enter:{strikethrough:fu},exit:{strikethrough:hu}}}function cu(){return{unsafe:[{character:"~",inConstruct:"phrasing",notInConstruct:su}],handlers:{delete:Hr}}}function fu(e){this.enter({type:"delete",children:[]},e)}function hu(e){this.exit(e)}function Hr(e,t,n,r){const i=n.createTracker(r),o=n.enter("strikethrough");let l=i.move("~~");return l+=n.containerPhrasing(e,{...i.current(),before:l,after:"~"}),l+=i.move("~~"),o(),l}function pu(){return"~"}function mu(e){return e.length}function du(e,t){const n=t||{},r=(n.align||[]).concat(),i=n.stringLength||mu,o=[],l=[],a=[],s=[];let u=0,f=-1;for(;++fu&&(u=e[f].length);++ys[y])&&(s[y]=C)}w.push(I)}l[f]=w,a[f]=S}let c=-1;if(typeof r=="object"&&"length"in r)for(;++cs[c]&&(s[c]=I),h[c]=I),p[c]=C}l.splice(1,0,p),a.splice(1,0,h),f=-1;const g=[];for(;++f"u"||e.call(u,p)},l=function(u,h){n&&h.name==="__proto__"?n(u,h.name,{enumerable:!0,configurable:!0,value:h.newValue,writable:!0}):u[h.name]=h.newValue},a=function(u,h){if(h==="__proto__")if(e.call(u,h)){if(r)return r(u,h).value}else return;return u[h]};return kn=function s(){var u,h,c,p,f,g,w=arguments[0],S=1,y=arguments.length,I=!1;for(typeof w=="boolean"&&(I=w,w=arguments[1]||{},S=2),(w==null||typeof w!="object"&&typeof w!="function")&&(w={});Sl.length;let s;a&&l.push(i);try{s=e.apply(this,l)}catch(u){const h=u;if(a&&n)throw h;return i(h)}a||(s&&s.then&&typeof s.then=="function"?s.then(o,i):s instanceof Error?i(s):o(s))}function i(l,...a){n||(n=!0,t(l,...a))}function o(l){i(null,l)}}const he={basename:ss,dirname:us,extname:cs,join:hs,sep:"/"};function ss(e,t){if(t!==void 0&&typeof t!="string")throw new TypeError('"ext" argument must be a string');Xe(e);let n=0,r=-1,i=e.length,o;if(t===void 0||t.length===0||t.length>e.length){for(;i--;)if(e.codePointAt(i)===47){if(o){n=i+1;break}}else r<0&&(o=!0,r=i+1);return r<0?"":e.slice(n,r)}if(t===e)return"";let l=-1,a=t.length-1;for(;i--;)if(e.codePointAt(i)===47){if(o){n=i+1;break}}else l<0&&(o=!0,l=i+1),a>-1&&(e.codePointAt(i)===t.codePointAt(a--)?a<0&&(r=i):(a=-1,r=l));return n===r?r=l:r<0&&(r=e.length),e.slice(n,r)}function us(e){if(Xe(e),e.length===0)return".";let t=-1,n=e.length,r;for(;--n;)if(e.codePointAt(n)===47){if(r){t=n;break}}else r||(r=!0);return t<0?e.codePointAt(0)===47?"/":".":t===1&&e.codePointAt(0)===47?"//":e.slice(0,t)}function cs(e){Xe(e);let t=e.length,n=-1,r=0,i=-1,o=0,l;for(;t--;){const a=e.codePointAt(t);if(a===47){if(l){r=t+1;break}continue}n<0&&(l=!0,n=t+1),a===46?i<0?i=t:o!==1&&(o=1):i>-1&&(o=-1)}return i<0||n<0||o===0||o===1&&i===n-1&&i===r+1?"":e.slice(i,n)}function hs(...e){let t=-1,n;for(;++t0&&e.codePointAt(e.length-1)===47&&(n+="/"),t?"/"+n:n}function ps(e,t){let n="",r=0,i=-1,o=0,l=-1,a,s;for(;++l<=e.length;){if(l2){if(s=n.lastIndexOf("/"),s!==n.length-1){s<0?(n="",r=0):(n=n.slice(0,s),r=n.length-1-n.lastIndexOf("/")),i=l,o=0;continue}}else if(n.length>0){n="",r=0,i=l,o=0;continue}}t&&(n=n.length>0?n+"/..":"..",r=2)}else n.length>0?n+="/"+e.slice(i+1,l):n=e.slice(i+1,l),r=l-i-1;i=l,o=0}else a===46&&o>-1?o++:o=-1}return n}function Xe(e){if(typeof e!="string")throw new TypeError("Path must be a string. Received "+JSON.stringify(e))}const ms={cwd:ds};function ds(){return"/"}function Bn(e){return!!(e!==null&&typeof e=="object"&&"href"in e&&e.href&&"protocol"in e&&e.protocol&&e.auth===void 0)}function gs(e){if(typeof e=="string")e=new URL(e);else if(!Bn(e)){const t=new TypeError('The "path" argument must be of type string or an instance of URL. Received `'+e+"`");throw t.code="ERR_INVALID_ARG_TYPE",t}if(e.protocol!=="file:"){const t=new TypeError("The URL must be of scheme file");throw t.code="ERR_INVALID_URL_SCHEME",t}return ys(e)}function ys(e){if(e.hostname!==""){const r=new TypeError('File URL host must be "localhost" or empty on darwin');throw r.code="ERR_INVALID_FILE_URL_HOST",r}const t=e.pathname;let n=-1;for(;++n0){let[f,...g]=h;const w=r[p][1];Nn(w)&&Nn(f)&&(f=xn(!0,w,f)),r[p]=[u,f,...g]}}}}const ws=new nt().freeze();function Cn(e,t){if(typeof t!="function")throw new TypeError("Cannot `"+e+"` without `parser`")}function En(e,t){if(typeof t!="function")throw new TypeError("Cannot `"+e+"` without `compiler`")}function In(e,t){if(t)throw new Error("Cannot call `"+e+"` on a frozen processor.\nCreate a new processor first, by calling it: use `processor()` instead of `processor`.")}function Ut(e){if(!Nn(e)||typeof e.type!="string")throw new TypeError("Expected node, got `"+e+"`")}function Vt(e,t,n){if(!n)throw new Error("`"+e+"` finished async. Use `"+t+"` instead")}function en(e){return Ss(e)?e:new Mr(e)}function Ss(e){return!!(e&&typeof e=="object"&&"message"in e&&"messages"in e)}function Cs(e){return typeof e=="string"||Es(e)}function Es(e){return!!(e&&typeof e=="object"&&"byteLength"in e&&"byteOffset"in e)}const Is="https://github.com/remarkjs/react-markdown/blob/main/changelog.md",$t=[],Wt={allowDangerousHtml:!0},vs=/^(https?|ircs?|mailto|xmpp)$/i,Ts=[{from:"astPlugins",id:"remove-buggy-html-in-markdown-parser"},{from:"allowDangerousHtml",id:"remove-buggy-html-in-markdown-parser"},{from:"allowNode",id:"replace-allownode-allowedtypes-and-disallowedtypes",to:"allowElement"},{from:"allowedTypes",id:"replace-allownode-allowedtypes-and-disallowedtypes",to:"allowedElements"},{from:"disallowedTypes",id:"replace-allownode-allowedtypes-and-disallowedtypes",to:"disallowedElements"},{from:"escapeHtml",id:"remove-buggy-html-in-markdown-parser"},{from:"includeElementIndex",id:"#remove-includeelementindex"},{from:"includeNodeIndex",id:"change-includenodeindex-to-includeelementindex"},{from:"linkTarget",id:"remove-linktarget"},{from:"plugins",id:"change-plugins-to-remarkplugins",to:"remarkPlugins"},{from:"rawSourcePos",id:"#remove-rawsourcepos"},{from:"renderers",id:"change-renderers-to-components",to:"components"},{from:"source",id:"change-source-to-children",to:"children"},{from:"sourcePos",id:"#remove-sourcepos"},{from:"transformImageUri",id:"#add-urltransform",to:"urlTransform"},{from:"transformLinkUri",id:"#add-urltransform",to:"urlTransform"}];function As(e){const t=Ps(e),n=zs(e);return Ds(t.runSync(t.parse(n),n),e)}function Ps(e){const t=e.rehypePlugins||$t,n=e.remarkPlugins||$t,r=e.remarkRehypeOptions?{...e.remarkRehypeOptions,...Wt}:Wt;return ws().use(ua).use(n).use(rs,r).use(t)}function zs(e){const t=e.children||"",n=new Mr;return typeof t=="string"&&(n.value=t),n}function Ds(e,t){const n=t.allowedElements,r=t.allowElement,i=t.components,o=t.disallowedElements,l=t.skipHtml,a=t.unwrapDisallowed,s=t.urlTransform||Ls;for(const h of Ts)Object.hasOwn(t,h.from)&&(""+h.from+(h.to?"use `"+h.to+"` instead":"remove it")+Is+h.id,void 0);return t.className&&(e={type:"element",tagName:"div",properties:{className:t.className},children:e.type==="root"?e.children:[e]}),et(e,u),$i(e,{Fragment:re.Fragment,components:i,ignoreInvalidStyle:!0,jsx:re.jsx,jsxs:re.jsxs,passKeys:!0,passNode:!0});function u(h,c,p){if(h.type==="raw"&&p&&typeof c=="number")return l?p.children.splice(c,1):p.children[c]={type:"text",value:h.value},c;if(h.type==="element"){let f;for(f in dn)if(Object.hasOwn(dn,f)&&Object.hasOwn(h.properties,f)){const g=h.properties[f],w=dn[f];(w===null||w.includes(h.tagName))&&(h.properties[f]=s(String(g||""),f,h))}}if(h.type==="element"){let f=n?!n.includes(h.tagName):o?o.includes(h.tagName):!1;if(!f&&r&&typeof c=="number"&&(f=!r(h,c,p)),f&&p&&typeof c=="number")return a&&h.children?p.children.splice(c,1,...h.children):p.children.splice(c,1),c}}}function Ls(e){const t=e.indexOf(":"),n=e.indexOf("?"),r=e.indexOf("#"),i=e.indexOf("/");return t===-1||i!==-1&&t>i||n!==-1&&t>n||r!==-1&&t>r||vs.test(e.slice(0,t))?e:""}function Yt(e,t){const n=String(e);if(typeof t!="string")throw new TypeError("Expected character");let r=0,i=n.indexOf(t);for(;i!==-1;)r++,i=n.indexOf(t,i+t.length);return r}function _s(e){if(typeof e!="string")throw new TypeError("Expected a string");return e.replace(/[|\\{}()[\]^$+*?.]/g,"\\$&").replace(/-/g,"\\x2d")}function Rs(e,t,n){const i=hn((n||{}).ignore||[]),o=Fs(t);let l=-1;for(;++l0?{type:"text",value:b}:void 0),b===!1?p.lastIndex=R+1:(g!==R&&I.push({type:"text",value:u.value.slice(g,R)}),Array.isArray(b)?I.push(...b):b&&I.push(b),g=R+C[0].length,y=!0),!p.global)break;C=p.exec(u.value)}return y?(g?\]}]+$/.exec(e);if(!t)return[e,void 0];e=e.slice(0,t.index);let n=t[0],r=n.indexOf(")");const i=Yt(e,"(");let o=Yt(e,")");for(;r!==-1&&i>o;)e+=n.slice(0,r+1),n=n.slice(r+1),r=n.indexOf(")"),o++;return[e,n]}function Nr(e,t){const n=e.input.charCodeAt(e.index-1);return(e.index===0||ve(n)||sn(n))&&(!t||n!==47)}Br.peek=iu;function Xs(){this.buffer()}function Gs(e){this.enter({type:"footnoteReference",identifier:"",label:""},e)}function Js(){this.buffer()}function Zs(e){this.enter({type:"footnoteDefinition",identifier:"",label:"",children:[]},e)}function eu(e){const t=this.resume(),n=this.stack[this.stack.length-1];n.type,n.identifier=ce(this.sliceSerialize(e)).toLowerCase(),n.label=t}function nu(e){this.exit(e)}function tu(e){const t=this.resume(),n=this.stack[this.stack.length-1];n.type,n.identifier=ce(this.sliceSerialize(e)).toLowerCase(),n.label=t}function ru(e){this.exit(e)}function iu(){return"["}function Br(e,t,n,r){const i=n.createTracker(r);let o=i.move("[^");const l=n.enter("footnoteReference"),a=n.enter("reference");return o+=i.move(n.safe(n.associationId(e),{after:"]",before:o})),a(),l(),o+=i.move("]"),o}function lu(){return{enter:{gfmFootnoteCallString:Xs,gfmFootnoteCall:Gs,gfmFootnoteDefinitionLabelString:Js,gfmFootnoteDefinition:Zs},exit:{gfmFootnoteCallString:eu,gfmFootnoteCall:nu,gfmFootnoteDefinitionLabelString:tu,gfmFootnoteDefinition:ru}}}function ou(e){let t=!1;return e&&e.firstLineBlank&&(t=!0),{handlers:{footnoteDefinition:n,footnoteReference:Br},unsafe:[{character:"[",inConstruct:["label","phrasing","reference"]}]};function n(r,i,o,l){const a=o.createTracker(l);let s=a.move("[^");const u=o.enter("footnoteDefinition"),h=o.enter("label");return s+=a.move(o.safe(o.associationId(r),{before:s,after:"]"})),h(),s+=a.move("]:"),r.children&&r.children.length>0&&(a.shift(4),s+=a.move((t?` +`:" ")+o.indentLines(o.containerFlow(r,a.current()),t?jr:au))),u(),s}}function au(e,t,n){return t===0?e:jr(e,t,n)}function jr(e,t,n){return(n?"":" ")+e}const su=["autolink","destinationLiteral","destinationRaw","reference","titleQuote","titleApostrophe"];Hr.peek=pu;function uu(){return{canContainEols:["delete"],enter:{strikethrough:hu},exit:{strikethrough:fu}}}function cu(){return{unsafe:[{character:"~",inConstruct:"phrasing",notInConstruct:su}],handlers:{delete:Hr}}}function hu(e){this.enter({type:"delete",children:[]},e)}function fu(e){this.exit(e)}function Hr(e,t,n,r){const i=n.createTracker(r),o=n.enter("strikethrough");let l=i.move("~~");return l+=n.containerPhrasing(e,{...i.current(),before:l,after:"~"}),l+=i.move("~~"),o(),l}function pu(){return"~"}function mu(e){return e.length}function du(e,t){const n=t||{},r=(n.align||[]).concat(),i=n.stringLength||mu,o=[],l=[],a=[],s=[];let u=0,h=-1;for(;++hu&&(u=e[h].length);++ys[y])&&(s[y]=C)}w.push(I)}l[h]=w,a[h]=S}let c=-1;if(typeof r=="object"&&"length"in r)for(;++cs[c]&&(s[c]=I),f[c]=I),p[c]=C}l.splice(1,0,p),a.splice(1,0,f),h=-1;const g=[];for(;++h "),o.shift(2);const l=n.indentLines(n.containerFlow(e,o.current()),ku);return i(),l}function ku(e,t,n){return">"+(n?"":" ")+e}function xu(e,t){return Qt(e,t.inConstruct,!0)&&!Qt(e,t.notInConstruct,!1)}function Qt(e,t,n){if(typeof t=="string"&&(t=[t]),!t||t.length===0)return n;let r=-1;for(;++rl&&(l=o):o=1,i=r+t.length,r=n.indexOf(t,i);return l}function wu(e,t){return!!(t.options.fences===!1&&e.value&&!e.lang&&/[^ \r\n]/.test(e.value)&&!/^[\t ]*(?:[\r\n]|$)|(?:^|[\r\n])[\t ]*$/.test(e.value))}function Su(e){const t=e.options.fence||"`";if(t!=="`"&&t!=="~")throw new Error("Cannot serialize code with `"+t+"` for `options.fence`, expected `` ` `` or `~`");return t}function Cu(e,t,n,r){const i=Su(n),o=e.value||"",l=i==="`"?"GraveAccent":"Tilde";if(wu(e,n)){const c=n.enter("codeIndented"),p=n.indentLines(o,Eu);return c(),p}const a=n.createTracker(r),s=i.repeat(Math.max(bu(o,i)+1,3)),u=n.enter("codeFenced");let f=a.move(s);if(e.lang){const c=n.enter(`codeFencedLang${l}`);f+=a.move(n.safe(e.lang,{before:f,after:" ",encode:["`"],...a.current()})),c()}if(e.lang&&e.meta){const c=n.enter(`codeFencedMeta${l}`);f+=a.move(" "),f+=a.move(n.safe(e.meta,{before:f,after:` -`,encode:["`"],...a.current()})),c()}return f+=a.move(` -`),o&&(f+=a.move(o+` -`)),f+=a.move(s),u(),f}function Eu(e,t,n){return(n?"":" ")+e}function tt(e){const t=e.options.quote||'"';if(t!=='"'&&t!=="'")throw new Error("Cannot serialize title with `"+t+"` for `options.quote`, expected `\"`, or `'`");return t}function Iu(e,t,n,r){const i=tt(n),o=i==='"'?"Quote":"Apostrophe",l=n.enter("definition");let a=n.enter("label");const s=n.createTracker(r);let u=s.move("[");return u+=s.move(n.safe(n.associationId(e),{before:u,after:"]",...s.current()})),u+=s.move("]: "),a(),!e.url||/[\0- \u007F]/.test(e.url)?(a=n.enter("destinationLiteral"),u+=s.move("<"),u+=s.move(n.safe(e.url,{before:u,after:">",...s.current()})),u+=s.move(">")):(a=n.enter("destinationRaw"),u+=s.move(n.safe(e.url,{before:u,after:e.title?" ":` -`,...s.current()}))),a(),e.title&&(a=n.enter(`title${o}`),u+=s.move(" "+i),u+=s.move(n.safe(e.title,{before:u,after:i,...s.current()})),u+=s.move(i),a()),l(),u}function vu(e){const t=e.options.emphasis||"*";if(t!=="*"&&t!=="_")throw new Error("Cannot serialize emphasis with `"+t+"` for `options.emphasis`, expected `*`, or `_`");return t}function Ye(e){return"&#x"+e.toString(16).toUpperCase()+";"}function an(e,t,n){const r=_e(e),i=_e(t);return r===void 0?i===void 0?n==="_"?{inside:!0,outside:!0}:{inside:!1,outside:!1}:i===1?{inside:!0,outside:!0}:{inside:!1,outside:!0}:r===1?i===void 0?{inside:!1,outside:!1}:i===1?{inside:!0,outside:!0}:{inside:!1,outside:!1}:i===void 0?{inside:!1,outside:!1}:i===1?{inside:!0,outside:!1}:{inside:!1,outside:!1}}Ur.peek=Tu;function Ur(e,t,n,r){const i=vu(n),o=n.enter("emphasis"),l=n.createTracker(r),a=l.move(i);let s=l.move(n.containerPhrasing(e,{after:i,before:a,...l.current()}));const u=s.charCodeAt(0),f=an(r.before.charCodeAt(r.before.length-1),u,i);f.inside&&(s=Ye(u)+s.slice(1));const c=s.charCodeAt(s.length-1),p=an(r.after.charCodeAt(0),c,i);p.inside&&(s=s.slice(0,-1)+Ye(c));const h=l.move(i);return o(),n.attentionEncodeSurroundingInfo={after:p.outside,before:f.outside},a+s+h}function Tu(e,t,n){return n.options.emphasis||"*"}function Au(e,t){let n=!1;return et(e,function(r){if("value"in r&&/\r?\n|\r/.test(r.value)||r.type==="break")return n=!0,On}),!!((!e.depth||e.depth<3)&&Yn(e)&&(t.options.setext||n))}function Pu(e,t,n,r){const i=Math.max(Math.min(6,e.depth||1),1),o=n.createTracker(r);if(Au(e,n)){const f=n.enter("headingSetext"),c=n.enter("phrasing"),p=n.containerPhrasing(e,{...o.current(),before:` +`}function bu(e,t){const n=String(e);let r=n.indexOf(t),i=r,o=0,l=0;if(typeof t!="string")throw new TypeError("Expected substring");for(;r!==-1;)r===i?++o>l&&(l=o):o=1,i=r+t.length,r=n.indexOf(t,i);return l}function wu(e,t){return!!(t.options.fences===!1&&e.value&&!e.lang&&/[^ \r\n]/.test(e.value)&&!/^[\t ]*(?:[\r\n]|$)|(?:^|[\r\n])[\t ]*$/.test(e.value))}function Su(e){const t=e.options.fence||"`";if(t!=="`"&&t!=="~")throw new Error("Cannot serialize code with `"+t+"` for `options.fence`, expected `` ` `` or `~`");return t}function Cu(e,t,n,r){const i=Su(n),o=e.value||"",l=i==="`"?"GraveAccent":"Tilde";if(wu(e,n)){const c=n.enter("codeIndented"),p=n.indentLines(o,Eu);return c(),p}const a=n.createTracker(r),s=i.repeat(Math.max(bu(o,i)+1,3)),u=n.enter("codeFenced");let h=a.move(s);if(e.lang){const c=n.enter(`codeFencedLang${l}`);h+=a.move(n.safe(e.lang,{before:h,after:" ",encode:["`"],...a.current()})),c()}if(e.lang&&e.meta){const c=n.enter(`codeFencedMeta${l}`);h+=a.move(" "),h+=a.move(n.safe(e.meta,{before:h,after:` +`,encode:["`"],...a.current()})),c()}return h+=a.move(` +`),o&&(h+=a.move(o+` +`)),h+=a.move(s),u(),h}function Eu(e,t,n){return(n?"":" ")+e}function tt(e){const t=e.options.quote||'"';if(t!=='"'&&t!=="'")throw new Error("Cannot serialize title with `"+t+"` for `options.quote`, expected `\"`, or `'`");return t}function Iu(e,t,n,r){const i=tt(n),o=i==='"'?"Quote":"Apostrophe",l=n.enter("definition");let a=n.enter("label");const s=n.createTracker(r);let u=s.move("[");return u+=s.move(n.safe(n.associationId(e),{before:u,after:"]",...s.current()})),u+=s.move("]: "),a(),!e.url||/[\0- \u007F]/.test(e.url)?(a=n.enter("destinationLiteral"),u+=s.move("<"),u+=s.move(n.safe(e.url,{before:u,after:">",...s.current()})),u+=s.move(">")):(a=n.enter("destinationRaw"),u+=s.move(n.safe(e.url,{before:u,after:e.title?" ":` +`,...s.current()}))),a(),e.title&&(a=n.enter(`title${o}`),u+=s.move(" "+i),u+=s.move(n.safe(e.title,{before:u,after:i,...s.current()})),u+=s.move(i),a()),l(),u}function vu(e){const t=e.options.emphasis||"*";if(t!=="*"&&t!=="_")throw new Error("Cannot serialize emphasis with `"+t+"` for `options.emphasis`, expected `*`, or `_`");return t}function Ye(e){return"&#x"+e.toString(16).toUpperCase()+";"}function an(e,t,n){const r=_e(e),i=_e(t);return r===void 0?i===void 0?n==="_"?{inside:!0,outside:!0}:{inside:!1,outside:!1}:i===1?{inside:!0,outside:!0}:{inside:!1,outside:!0}:r===1?i===void 0?{inside:!1,outside:!1}:i===1?{inside:!0,outside:!0}:{inside:!1,outside:!1}:i===void 0?{inside:!1,outside:!1}:i===1?{inside:!0,outside:!1}:{inside:!1,outside:!1}}qr.peek=Tu;function qr(e,t,n,r){const i=vu(n),o=n.enter("emphasis"),l=n.createTracker(r),a=l.move(i);let s=l.move(n.containerPhrasing(e,{after:i,before:a,...l.current()}));const u=s.charCodeAt(0),h=an(r.before.charCodeAt(r.before.length-1),u,i);h.inside&&(s=Ye(u)+s.slice(1));const c=s.charCodeAt(s.length-1),p=an(r.after.charCodeAt(0),c,i);p.inside&&(s=s.slice(0,-1)+Ye(c));const f=l.move(i);return o(),n.attentionEncodeSurroundingInfo={after:p.outside,before:h.outside},a+s+f}function Tu(e,t,n){return n.options.emphasis||"*"}function Au(e,t){let n=!1;return et(e,function(r){if("value"in r&&/\r?\n|\r/.test(r.value)||r.type==="break")return n=!0,On}),!!((!e.depth||e.depth<3)&&Yn(e)&&(t.options.setext||n))}function Pu(e,t,n,r){const i=Math.max(Math.min(6,e.depth||1),1),o=n.createTracker(r);if(Au(e,n)){const h=n.enter("headingSetext"),c=n.enter("phrasing"),p=n.containerPhrasing(e,{...o.current(),before:` `,after:` -`});return c(),f(),p+` +`});return c(),h(),p+` `+(i===1?"=":"-").repeat(p.length-(Math.max(p.lastIndexOf("\r"),p.lastIndexOf(` `))+1))}const l="#".repeat(i),a=n.enter("headingAtx"),s=n.enter("phrasing");o.move(l+" ");let u=n.containerPhrasing(e,{before:"# ",after:` -`,...o.current()});return/^[\t ]/.test(u)&&(u=Ye(u.charCodeAt(0))+u.slice(1)),u=u?l+" "+u:l,n.options.closeAtx&&(u+=" "+l),s(),a(),u}qr.peek=zu;function qr(e){return e.value||""}function zu(){return"<"}Vr.peek=Du;function Vr(e,t,n,r){const i=tt(n),o=i==='"'?"Quote":"Apostrophe",l=n.enter("image");let a=n.enter("label");const s=n.createTracker(r);let u=s.move("![");return u+=s.move(n.safe(e.alt,{before:u,after:"]",...s.current()})),u+=s.move("]("),a(),!e.url&&e.title||/[\0- \u007F]/.test(e.url)?(a=n.enter("destinationLiteral"),u+=s.move("<"),u+=s.move(n.safe(e.url,{before:u,after:">",...s.current()})),u+=s.move(">")):(a=n.enter("destinationRaw"),u+=s.move(n.safe(e.url,{before:u,after:e.title?" ":")",...s.current()}))),a(),e.title&&(a=n.enter(`title${o}`),u+=s.move(" "+i),u+=s.move(n.safe(e.title,{before:u,after:i,...s.current()})),u+=s.move(i),a()),u+=s.move(")"),l(),u}function Du(){return"!"}$r.peek=Lu;function $r(e,t,n,r){const i=e.referenceType,o=n.enter("imageReference");let l=n.enter("label");const a=n.createTracker(r);let s=a.move("![");const u=n.safe(e.alt,{before:s,after:"]",...a.current()});s+=a.move(u+"]["),l();const f=n.stack;n.stack=[],l=n.enter("reference");const c=n.safe(n.associationId(e),{before:s,after:"]",...a.current()});return l(),n.stack=f,o(),i==="full"||!u||u!==c?s+=a.move(c+"]"):i==="shortcut"?s=s.slice(0,-1):s+=a.move("]"),s}function Lu(){return"!"}Wr.peek=_u;function Wr(e,t,n){let r=e.value||"",i="`",o=-1;for(;new RegExp("(^|[^`])"+i+"([^`]|$)").test(r);)i+="`";for(/[^ \r\n]/.test(r)&&(/^[ \r\n]/.test(r)&&/[ \r\n]$/.test(r)||/^`|`$/.test(r))&&(r=" "+r+" ");++o\u007F]/.test(e.url))}Kr.peek=Ru;function Kr(e,t,n,r){const i=tt(n),o=i==='"'?"Quote":"Apostrophe",l=n.createTracker(r);let a,s;if(Yr(e,n)){const f=n.stack;n.stack=[],a=n.enter("autolink");let c=l.move("<");return c+=l.move(n.containerPhrasing(e,{before:c,after:">",...l.current()})),c+=l.move(">"),a(),n.stack=f,c}a=n.enter("link"),s=n.enter("label");let u=l.move("[");return u+=l.move(n.containerPhrasing(e,{before:u,after:"](",...l.current()})),u+=l.move("]("),s(),!e.url&&e.title||/[\0- \u007F]/.test(e.url)?(s=n.enter("destinationLiteral"),u+=l.move("<"),u+=l.move(n.safe(e.url,{before:u,after:">",...l.current()})),u+=l.move(">")):(s=n.enter("destinationRaw"),u+=l.move(n.safe(e.url,{before:u,after:e.title?" ":")",...l.current()}))),s(),e.title&&(s=n.enter(`title${o}`),u+=l.move(" "+i),u+=l.move(n.safe(e.title,{before:u,after:i,...l.current()})),u+=l.move(i),s()),u+=l.move(")"),a(),u}function Ru(e,t,n){return Yr(e,n)?"<":"["}Qr.peek=Fu;function Qr(e,t,n,r){const i=e.referenceType,o=n.enter("linkReference");let l=n.enter("label");const a=n.createTracker(r);let s=a.move("[");const u=n.containerPhrasing(e,{before:s,after:"]",...a.current()});s+=a.move(u+"]["),l();const f=n.stack;n.stack=[],l=n.enter("reference");const c=n.safe(n.associationId(e),{before:s,after:"]",...a.current()});return l(),n.stack=f,o(),i==="full"||!u||u!==c?s+=a.move(c+"]"):i==="shortcut"?s=s.slice(0,-1):s+=a.move("]"),s}function Fu(){return"["}function rt(e){const t=e.options.bullet||"*";if(t!=="*"&&t!=="+"&&t!=="-")throw new Error("Cannot serialize items with `"+t+"` for `options.bullet`, expected `*`, `+`, or `-`");return t}function Ou(e){const t=rt(e),n=e.options.bulletOther;if(!n)return t==="*"?"-":"*";if(n!=="*"&&n!=="+"&&n!=="-")throw new Error("Cannot serialize items with `"+n+"` for `options.bulletOther`, expected `*`, `+`, or `-`");if(n===t)throw new Error("Expected `bullet` (`"+t+"`) and `bulletOther` (`"+n+"`) to be different");return n}function Mu(e){const t=e.options.bulletOrdered||".";if(t!=="."&&t!==")")throw new Error("Cannot serialize items with `"+t+"` for `options.bulletOrdered`, expected `.` or `)`");return t}function Xr(e){const t=e.options.rule||"*";if(t!=="*"&&t!=="-"&&t!=="_")throw new Error("Cannot serialize rules with `"+t+"` for `options.rule`, expected `*`, `-`, or `_`");return t}function Nu(e,t,n,r){const i=n.enter("list"),o=n.bulletCurrent;let l=e.ordered?Mu(n):rt(n);const a=e.ordered?l==="."?")":".":Ou(n);let s=t&&n.bulletLastUsed?l===n.bulletLastUsed:!1;if(!e.ordered){const f=e.children?e.children[0]:void 0;if((l==="*"||l==="-")&&f&&(!f.children||!f.children[0])&&n.stack[n.stack.length-1]==="list"&&n.stack[n.stack.length-2]==="listItem"&&n.stack[n.stack.length-3]==="list"&&n.stack[n.stack.length-4]==="listItem"&&n.indexStack[n.indexStack.length-1]===0&&n.indexStack[n.indexStack.length-2]===0&&n.indexStack[n.indexStack.length-3]===0&&(s=!0),Xr(n)===l&&f){let c=-1;for(;++c-1?t.start:1)+(n.options.incrementListMarker===!1?0:t.children.indexOf(e))+o);let l=o.length+1;(i==="tab"||i==="mixed"&&(t&&t.type==="list"&&t.spread||e.spread))&&(l=Math.ceil(l/4)*4);const a=n.createTracker(r);a.move(o+" ".repeat(l-o.length)),a.shift(l);const s=n.enter("listItem"),u=n.indentLines(n.containerFlow(e,a.current()),f);return s(),u;function f(c,p,h){return p?(h?"":" ".repeat(l))+c:(h?o:o+" ".repeat(l-o.length))+c}}function Hu(e,t,n,r){const i=n.enter("paragraph"),o=n.enter("phrasing"),l=n.containerPhrasing(e,r);return o(),i(),l}const Uu=fn(["break","delete","emphasis","footnote","footnoteReference","image","imageReference","inlineCode","inlineMath","link","linkReference","mdxJsxTextElement","mdxTextExpression","strong","text","textDirective"]);function qu(e,t,n,r){return(e.children.some(function(l){return Uu(l)})?n.containerPhrasing:n.containerFlow).call(n,e,r)}function Vu(e){const t=e.options.strong||"*";if(t!=="*"&&t!=="_")throw new Error("Cannot serialize strong with `"+t+"` for `options.strong`, expected `*`, or `_`");return t}Gr.peek=$u;function Gr(e,t,n,r){const i=Vu(n),o=n.enter("strong"),l=n.createTracker(r),a=l.move(i+i);let s=l.move(n.containerPhrasing(e,{after:i,before:a,...l.current()}));const u=s.charCodeAt(0),f=an(r.before.charCodeAt(r.before.length-1),u,i);f.inside&&(s=Ye(u)+s.slice(1));const c=s.charCodeAt(s.length-1),p=an(r.after.charCodeAt(0),c,i);p.inside&&(s=s.slice(0,-1)+Ye(c));const h=l.move(i+i);return o(),n.attentionEncodeSurroundingInfo={after:p.outside,before:f.outside},a+s+h}function $u(e,t,n){return n.options.strong||"*"}function Wu(e,t,n,r){return n.safe(e.value,r)}function Yu(e){const t=e.options.ruleRepetition||3;if(t<3)throw new Error("Cannot serialize rules with repetition `"+t+"` for `options.ruleRepetition`, expected `3` or more");return t}function Ku(e,t,n){const r=(Xr(n)+(n.options.ruleSpaces?" ":"")).repeat(Yu(n));return n.options.ruleSpaces?r.slice(0,-1):r}const Jr={blockquote:yu,break:Xt,code:Cu,definition:Iu,emphasis:Ur,hardBreak:Xt,heading:Pu,html:qr,image:Vr,imageReference:$r,inlineCode:Wr,link:Kr,linkReference:Qr,list:Nu,listItem:ju,paragraph:Hu,root:qu,strong:Gr,text:Wu,thematicBreak:Ku};function Qu(){return{enter:{table:Xu,tableData:Gt,tableHeader:Gt,tableRow:Ju},exit:{codeText:Zu,table:Gu,tableData:Pn,tableHeader:Pn,tableRow:Pn}}}function Xu(e){const t=e._align;this.enter({type:"table",align:t.map(function(n){return n==="none"?null:n}),children:[]},e),this.data.inTable=!0}function Gu(e){this.exit(e),this.data.inTable=void 0}function Ju(e){this.enter({type:"tableRow",children:[]},e)}function Pn(e){this.exit(e)}function Gt(e){this.enter({type:"tableCell",children:[]},e)}function Zu(e){let t=this.resume();this.data.inTable&&(t=t.replace(/\\([\\|])/g,ec));const n=this.stack[this.stack.length-1];n.type,n.value=t,this.exit(e)}function ec(e,t){return t==="|"?t:e}function nc(e){const t=e||{},n=t.tableCellPadding,r=t.tablePipeAlign,i=t.stringLength,o=n?" ":"|";return{unsafe:[{character:"\r",inConstruct:"tableCell"},{character:` -`,inConstruct:"tableCell"},{atBreak:!0,character:"|",after:"[ :-]"},{character:"|",inConstruct:"tableCell"},{atBreak:!0,character:":",after:"-"},{atBreak:!0,character:"-",after:"[:|-]"}],handlers:{inlineCode:p,table:l,tableCell:s,tableRow:a}};function l(h,g,w,S){return u(f(h,w,S),h.align)}function a(h,g,w,S){const y=c(h,w,S),I=u([y]);return I.slice(0,I.indexOf(` -`))}function s(h,g,w,S){const y=w.enter("tableCell"),I=w.enter("phrasing"),C=w.containerPhrasing(h,{...S,before:o,after:o});return I(),y(),C}function u(h,g){return du(h,{align:g,alignDelimiters:r,padding:n,stringLength:i})}function f(h,g,w){const S=h.children;let y=-1;const I=[],C=g.enter("table");for(;++y0&&!n&&(e[e.length-1][1]._gfmAutolinkLiteralWalkedInto=!0),n}const xc={tokenize:Tc,partial:!0};function bc(){return{document:{91:{name:"gfmFootnoteDefinition",tokenize:Ec,continuation:{tokenize:Ic},exit:vc}},text:{91:{name:"gfmFootnoteCall",tokenize:Cc},93:{name:"gfmPotentialFootnoteCall",add:"after",tokenize:wc,resolveTo:Sc}}}}function wc(e,t,n){const r=this;let i=r.events.length;const o=r.parser.gfmFootnotes||(r.parser.gfmFootnotes=[]);let l;for(;i--;){const s=r.events[i][1];if(s.type==="labelImage"){l=s;break}if(s.type==="gfmFootnoteCall"||s.type==="labelLink"||s.type==="label"||s.type==="image"||s.type==="link")break}return a;function a(s){if(!l||!l._balanced)return n(s);const u=ce(r.sliceSerialize({start:l.end,end:r.now()}));return u.codePointAt(0)!==94||!o.includes(u.slice(1))?n(s):(e.enter("gfmFootnoteCallLabelMarker"),e.consume(s),e.exit("gfmFootnoteCallLabelMarker"),t(s))}}function Sc(e,t){let n=e.length;for(;n--;)if(e[n][1].type==="labelImage"&&e[n][0]==="enter"){e[n][1];break}e[n+1][1].type="data",e[n+3][1].type="gfmFootnoteCallLabelMarker";const r={type:"gfmFootnoteCall",start:Object.assign({},e[n+3][1].start),end:Object.assign({},e[e.length-1][1].end)},i={type:"gfmFootnoteCallMarker",start:Object.assign({},e[n+3][1].end),end:Object.assign({},e[n+3][1].end)};i.end.column++,i.end.offset++,i.end._bufferIndex++;const o={type:"gfmFootnoteCallString",start:Object.assign({},i.end),end:Object.assign({},e[e.length-1][1].start)},l={type:"chunkString",contentType:"string",start:Object.assign({},o.start),end:Object.assign({},o.end)},a=[e[n+1],e[n+2],["enter",r,t],e[n+3],e[n+4],["enter",i,t],["exit",i,t],["enter",o,t],["enter",l,t],["exit",l,t],["exit",o,t],e[e.length-2],e[e.length-1],["exit",r,t]];return e.splice(n,e.length-n+1,...a),e}function Cc(e,t,n){const r=this,i=r.parser.gfmFootnotes||(r.parser.gfmFootnotes=[]);let o=0,l;return a;function a(c){return e.enter("gfmFootnoteCall"),e.enter("gfmFootnoteCallLabelMarker"),e.consume(c),e.exit("gfmFootnoteCallLabelMarker"),s}function s(c){return c!==94?n(c):(e.enter("gfmFootnoteCallMarker"),e.consume(c),e.exit("gfmFootnoteCallMarker"),e.enter("gfmFootnoteCallString"),e.enter("chunkString").contentType="string",u)}function u(c){if(o>999||c===93&&!l||c===null||c===91||W(c))return n(c);if(c===93){e.exit("chunkString");const p=e.exit("gfmFootnoteCallString");return i.includes(ce(r.sliceSerialize(p)))?(e.enter("gfmFootnoteCallLabelMarker"),e.consume(c),e.exit("gfmFootnoteCallLabelMarker"),e.exit("gfmFootnoteCall"),t):n(c)}return W(c)||(l=!0),o++,e.consume(c),c===92?f:u}function f(c){return c===91||c===92||c===93?(e.consume(c),o++,u):u(c)}}function Ec(e,t,n){const r=this,i=r.parser.gfmFootnotes||(r.parser.gfmFootnotes=[]);let o,l=0,a;return s;function s(g){return e.enter("gfmFootnoteDefinition")._container=!0,e.enter("gfmFootnoteDefinitionLabel"),e.enter("gfmFootnoteDefinitionLabelMarker"),e.consume(g),e.exit("gfmFootnoteDefinitionLabelMarker"),u}function u(g){return g===94?(e.enter("gfmFootnoteDefinitionMarker"),e.consume(g),e.exit("gfmFootnoteDefinitionMarker"),e.enter("gfmFootnoteDefinitionLabelString"),e.enter("chunkString").contentType="string",f):n(g)}function f(g){if(l>999||g===93&&!a||g===null||g===91||W(g))return n(g);if(g===93){e.exit("chunkString");const w=e.exit("gfmFootnoteDefinitionLabelString");return o=ce(r.sliceSerialize(w)),e.enter("gfmFootnoteDefinitionLabelMarker"),e.consume(g),e.exit("gfmFootnoteDefinitionLabelMarker"),e.exit("gfmFootnoteDefinitionLabel"),p}return W(g)||(a=!0),l++,e.consume(g),g===92?c:f}function c(g){return g===91||g===92||g===93?(e.consume(g),l++,f):f(g)}function p(g){return g===58?(e.enter("definitionMarker"),e.consume(g),e.exit("definitionMarker"),i.includes(o)||i.push(o),B(e,h,"gfmFootnoteDefinitionWhitespace")):n(g)}function h(g){return t(g)}}function Ic(e,t,n){return e.check(Qe,t,e.attempt(xc,t,n))}function vc(e){e.exit("gfmFootnoteDefinition")}function Tc(e,t,n){const r=this;return B(e,i,"gfmFootnoteDefinitionIndent",5);function i(o){const l=r.events[r.events.length-1];return l&&l[1].type==="gfmFootnoteDefinitionIndent"&&l[2].sliceSerialize(l[1],!0).length===4?t(o):n(o)}}function Ac(e){let n=(e||{}).singleTilde;const r={name:"strikethrough",tokenize:o,resolveAll:i};return n==null&&(n=!0),{text:{126:r},insideSpan:{null:[r]},attentionMarkers:{null:[126]}};function i(l,a){let s=-1;for(;++s1?s(g):(l.consume(g),c++,h);if(c<2&&!n)return s(g);const S=l.exit("strikethroughSequenceTemporary"),y=_e(g);return S._open=!y||y===2&&!!w,S._close=!w||w===2&&!!y,a(g)}}}class Pc{constructor(){this.map=[]}add(t,n,r){zc(this,t,n,r)}consume(t){if(this.map.sort(function(o,l){return o[0]-l[0]}),this.map.length===0)return;let n=this.map.length;const r=[];for(;n>0;)n-=1,r.push(t.slice(this.map[n][0]+this.map[n][1]),this.map[n][2]),t.length=this.map[n][0];r.push(t.slice()),t.length=0;let i=r.pop();for(;i;){for(const o of i)t.push(o);i=r.pop()}this.map.length=0}}function zc(e,t,n,r){let i=0;if(!(n===0&&r.length===0)){for(;i-1;){const D=r.events[A][1].type;if(D==="lineEnding"||D==="linePrefix")A--;else break}const P=A>-1?r.events[A][1].type:null,U=P==="tableHead"||P==="tableRow"?b:s;return U===b&&r.parser.lazy[r.now().line]?n(k):U(k)}function s(k){return e.enter("tableHead"),e.enter("tableRow"),u(k)}function u(k){return k===124||(l=!0,o+=1),f(k)}function f(k){return k===null?n(k):z(k)?o>1?(o=0,r.interrupt=!0,e.exit("tableRow"),e.enter("lineEnding"),e.consume(k),e.exit("lineEnding"),h):n(k):O(k)?B(e,f,"whitespace")(k):(o+=1,l&&(l=!1,i+=1),k===124?(e.enter("tableCellDivider"),e.consume(k),e.exit("tableCellDivider"),l=!0,f):(e.enter("data"),c(k)))}function c(k){return k===null||k===124||W(k)?(e.exit("data"),f(k)):(e.consume(k),k===92?p:c)}function p(k){return k===92||k===124?(e.consume(k),c):c(k)}function h(k){return r.interrupt=!1,r.parser.lazy[r.now().line]?n(k):(e.enter("tableDelimiterRow"),l=!1,O(k)?B(e,g,"linePrefix",r.parser.constructs.disable.null.includes("codeIndented")?void 0:4)(k):g(k))}function g(k){return k===45||k===58?S(k):k===124?(l=!0,e.enter("tableCellDivider"),e.consume(k),e.exit("tableCellDivider"),w):F(k)}function w(k){return O(k)?B(e,S,"whitespace")(k):S(k)}function S(k){return k===58?(o+=1,l=!0,e.enter("tableDelimiterMarker"),e.consume(k),e.exit("tableDelimiterMarker"),y):k===45?(o+=1,y(k)):k===null||z(k)?R(k):F(k)}function y(k){return k===45?(e.enter("tableDelimiterFiller"),I(k)):F(k)}function I(k){return k===45?(e.consume(k),I):k===58?(l=!0,e.exit("tableDelimiterFiller"),e.enter("tableDelimiterMarker"),e.consume(k),e.exit("tableDelimiterMarker"),C):(e.exit("tableDelimiterFiller"),C(k))}function C(k){return O(k)?B(e,R,"whitespace")(k):R(k)}function R(k){return k===124?g(k):k===null||z(k)?!l||i!==o?F(k):(e.exit("tableDelimiterRow"),e.exit("tableHead"),t(k)):F(k)}function F(k){return n(k)}function b(k){return e.enter("tableRow"),M(k)}function M(k){return k===124?(e.enter("tableCellDivider"),e.consume(k),e.exit("tableCellDivider"),M):k===null||z(k)?(e.exit("tableRow"),t(k)):O(k)?B(e,M,"whitespace")(k):(e.enter("data"),H(k))}function H(k){return k===null||k===124||W(k)?(e.exit("data"),M(k)):(e.consume(k),k===92?j:H)}function j(k){return k===92||k===124?(e.consume(k),H):H(k)}}function Rc(e,t){let n=-1,r=!0,i=0,o=[0,0,0,0],l=[0,0,0,0],a=!1,s=0,u,f,c;const p=new Pc;for(;++nn[2]+1){const g=n[2]+1,w=n[3]-n[2]-1;e.add(g,w,[])}}e.add(n[3]+1,0,[["exit",c,t]])}return i!==void 0&&(o.end=Object.assign({},Le(t.events,i)),e.add(i,0,[["exit",o,t]]),o=void 0),o}function Zt(e,t,n,r,i){const o=[],l=Le(t.events,n);i&&(i.end=Object.assign({},l),o.push(["exit",i,t])),r.end=Object.assign({},l),o.push(["exit",r,t]),e.add(n+1,0,o)}function Le(e,t){const n=e[t],r=n[0]==="enter"?"start":"end";return n[1][r]}const Fc={name:"tasklistCheck",tokenize:Mc};function Oc(){return{text:{91:Fc}}}function Mc(e,t,n){const r=this;return i;function i(s){return r.previous!==null||!r._gfmTasklistFirstContentOfListItem?n(s):(e.enter("taskListCheck"),e.enter("taskListCheckMarker"),e.consume(s),e.exit("taskListCheckMarker"),o)}function o(s){return W(s)?(e.enter("taskListCheckValueUnchecked"),e.consume(s),e.exit("taskListCheckValueUnchecked"),l):s===88||s===120?(e.enter("taskListCheckValueChecked"),e.consume(s),e.exit("taskListCheckValueChecked"),l):n(s)}function l(s){return s===93?(e.enter("taskListCheckMarker"),e.consume(s),e.exit("taskListCheckMarker"),e.exit("taskListCheck"),a):n(s)}function a(s){return z(s)?t(s):O(s)?e.check({tokenize:Nc},t,n)(s):n(s)}}function Nc(e,t,n){return B(e,r,"whitespace");function r(i){return i===null?n(i):t(i)}}function Bc(e){return gr([cc(),bc(),Ac(e),Lc(),Oc()])}const jc={};function Hc(e){const t=this,n=e||jc,r=t.data(),i=r.micromarkExtensions||(r.micromarkExtensions=[]),o=r.fromMarkdownExtensions||(r.fromMarkdownExtensions=[]),l=r.toMarkdownExtensions||(r.toMarkdownExtensions=[]);i.push(Bc(n)),o.push(oc()),l.push(ac(n))}const Uc=`# Admin dashboard +`,...o.current()});return/^[\t ]/.test(u)&&(u=Ye(u.charCodeAt(0))+u.slice(1)),u=u?l+" "+u:l,n.options.closeAtx&&(u+=" "+l),s(),a(),u}Ur.peek=zu;function Ur(e){return e.value||""}function zu(){return"<"}Vr.peek=Du;function Vr(e,t,n,r){const i=tt(n),o=i==='"'?"Quote":"Apostrophe",l=n.enter("image");let a=n.enter("label");const s=n.createTracker(r);let u=s.move("![");return u+=s.move(n.safe(e.alt,{before:u,after:"]",...s.current()})),u+=s.move("]("),a(),!e.url&&e.title||/[\0- \u007F]/.test(e.url)?(a=n.enter("destinationLiteral"),u+=s.move("<"),u+=s.move(n.safe(e.url,{before:u,after:">",...s.current()})),u+=s.move(">")):(a=n.enter("destinationRaw"),u+=s.move(n.safe(e.url,{before:u,after:e.title?" ":")",...s.current()}))),a(),e.title&&(a=n.enter(`title${o}`),u+=s.move(" "+i),u+=s.move(n.safe(e.title,{before:u,after:i,...s.current()})),u+=s.move(i),a()),u+=s.move(")"),l(),u}function Du(){return"!"}$r.peek=Lu;function $r(e,t,n,r){const i=e.referenceType,o=n.enter("imageReference");let l=n.enter("label");const a=n.createTracker(r);let s=a.move("![");const u=n.safe(e.alt,{before:s,after:"]",...a.current()});s+=a.move(u+"]["),l();const h=n.stack;n.stack=[],l=n.enter("reference");const c=n.safe(n.associationId(e),{before:s,after:"]",...a.current()});return l(),n.stack=h,o(),i==="full"||!u||u!==c?s+=a.move(c+"]"):i==="shortcut"?s=s.slice(0,-1):s+=a.move("]"),s}function Lu(){return"!"}Wr.peek=_u;function Wr(e,t,n){let r=e.value||"",i="`",o=-1;for(;new RegExp("(^|[^`])"+i+"([^`]|$)").test(r);)i+="`";for(/[^ \r\n]/.test(r)&&(/^[ \r\n]/.test(r)&&/[ \r\n]$/.test(r)||/^`|`$/.test(r))&&(r=" "+r+" ");++o\u007F]/.test(e.url))}Kr.peek=Ru;function Kr(e,t,n,r){const i=tt(n),o=i==='"'?"Quote":"Apostrophe",l=n.createTracker(r);let a,s;if(Yr(e,n)){const h=n.stack;n.stack=[],a=n.enter("autolink");let c=l.move("<");return c+=l.move(n.containerPhrasing(e,{before:c,after:">",...l.current()})),c+=l.move(">"),a(),n.stack=h,c}a=n.enter("link"),s=n.enter("label");let u=l.move("[");return u+=l.move(n.containerPhrasing(e,{before:u,after:"](",...l.current()})),u+=l.move("]("),s(),!e.url&&e.title||/[\0- \u007F]/.test(e.url)?(s=n.enter("destinationLiteral"),u+=l.move("<"),u+=l.move(n.safe(e.url,{before:u,after:">",...l.current()})),u+=l.move(">")):(s=n.enter("destinationRaw"),u+=l.move(n.safe(e.url,{before:u,after:e.title?" ":")",...l.current()}))),s(),e.title&&(s=n.enter(`title${o}`),u+=l.move(" "+i),u+=l.move(n.safe(e.title,{before:u,after:i,...l.current()})),u+=l.move(i),s()),u+=l.move(")"),a(),u}function Ru(e,t,n){return Yr(e,n)?"<":"["}Qr.peek=Fu;function Qr(e,t,n,r){const i=e.referenceType,o=n.enter("linkReference");let l=n.enter("label");const a=n.createTracker(r);let s=a.move("[");const u=n.containerPhrasing(e,{before:s,after:"]",...a.current()});s+=a.move(u+"]["),l();const h=n.stack;n.stack=[],l=n.enter("reference");const c=n.safe(n.associationId(e),{before:s,after:"]",...a.current()});return l(),n.stack=h,o(),i==="full"||!u||u!==c?s+=a.move(c+"]"):i==="shortcut"?s=s.slice(0,-1):s+=a.move("]"),s}function Fu(){return"["}function rt(e){const t=e.options.bullet||"*";if(t!=="*"&&t!=="+"&&t!=="-")throw new Error("Cannot serialize items with `"+t+"` for `options.bullet`, expected `*`, `+`, or `-`");return t}function Ou(e){const t=rt(e),n=e.options.bulletOther;if(!n)return t==="*"?"-":"*";if(n!=="*"&&n!=="+"&&n!=="-")throw new Error("Cannot serialize items with `"+n+"` for `options.bulletOther`, expected `*`, `+`, or `-`");if(n===t)throw new Error("Expected `bullet` (`"+t+"`) and `bulletOther` (`"+n+"`) to be different");return n}function Mu(e){const t=e.options.bulletOrdered||".";if(t!=="."&&t!==")")throw new Error("Cannot serialize items with `"+t+"` for `options.bulletOrdered`, expected `.` or `)`");return t}function Xr(e){const t=e.options.rule||"*";if(t!=="*"&&t!=="-"&&t!=="_")throw new Error("Cannot serialize rules with `"+t+"` for `options.rule`, expected `*`, `-`, or `_`");return t}function Nu(e,t,n,r){const i=n.enter("list"),o=n.bulletCurrent;let l=e.ordered?Mu(n):rt(n);const a=e.ordered?l==="."?")":".":Ou(n);let s=t&&n.bulletLastUsed?l===n.bulletLastUsed:!1;if(!e.ordered){const h=e.children?e.children[0]:void 0;if((l==="*"||l==="-")&&h&&(!h.children||!h.children[0])&&n.stack[n.stack.length-1]==="list"&&n.stack[n.stack.length-2]==="listItem"&&n.stack[n.stack.length-3]==="list"&&n.stack[n.stack.length-4]==="listItem"&&n.indexStack[n.indexStack.length-1]===0&&n.indexStack[n.indexStack.length-2]===0&&n.indexStack[n.indexStack.length-3]===0&&(s=!0),Xr(n)===l&&h){let c=-1;for(;++c-1?t.start:1)+(n.options.incrementListMarker===!1?0:t.children.indexOf(e))+o);let l=o.length+1;(i==="tab"||i==="mixed"&&(t&&t.type==="list"&&t.spread||e.spread))&&(l=Math.ceil(l/4)*4);const a=n.createTracker(r);a.move(o+" ".repeat(l-o.length)),a.shift(l);const s=n.enter("listItem"),u=n.indentLines(n.containerFlow(e,a.current()),h);return s(),u;function h(c,p,f){return p?(f?"":" ".repeat(l))+c:(f?o:o+" ".repeat(l-o.length))+c}}function Hu(e,t,n,r){const i=n.enter("paragraph"),o=n.enter("phrasing"),l=n.containerPhrasing(e,r);return o(),i(),l}const qu=hn(["break","delete","emphasis","footnote","footnoteReference","image","imageReference","inlineCode","inlineMath","link","linkReference","mdxJsxTextElement","mdxTextExpression","strong","text","textDirective"]);function Uu(e,t,n,r){return(e.children.some(function(l){return qu(l)})?n.containerPhrasing:n.containerFlow).call(n,e,r)}function Vu(e){const t=e.options.strong||"*";if(t!=="*"&&t!=="_")throw new Error("Cannot serialize strong with `"+t+"` for `options.strong`, expected `*`, or `_`");return t}Gr.peek=$u;function Gr(e,t,n,r){const i=Vu(n),o=n.enter("strong"),l=n.createTracker(r),a=l.move(i+i);let s=l.move(n.containerPhrasing(e,{after:i,before:a,...l.current()}));const u=s.charCodeAt(0),h=an(r.before.charCodeAt(r.before.length-1),u,i);h.inside&&(s=Ye(u)+s.slice(1));const c=s.charCodeAt(s.length-1),p=an(r.after.charCodeAt(0),c,i);p.inside&&(s=s.slice(0,-1)+Ye(c));const f=l.move(i+i);return o(),n.attentionEncodeSurroundingInfo={after:p.outside,before:h.outside},a+s+f}function $u(e,t,n){return n.options.strong||"*"}function Wu(e,t,n,r){return n.safe(e.value,r)}function Yu(e){const t=e.options.ruleRepetition||3;if(t<3)throw new Error("Cannot serialize rules with repetition `"+t+"` for `options.ruleRepetition`, expected `3` or more");return t}function Ku(e,t,n){const r=(Xr(n)+(n.options.ruleSpaces?" ":"")).repeat(Yu(n));return n.options.ruleSpaces?r.slice(0,-1):r}const Jr={blockquote:yu,break:Xt,code:Cu,definition:Iu,emphasis:qr,hardBreak:Xt,heading:Pu,html:Ur,image:Vr,imageReference:$r,inlineCode:Wr,link:Kr,linkReference:Qr,list:Nu,listItem:ju,paragraph:Hu,root:Uu,strong:Gr,text:Wu,thematicBreak:Ku};function Qu(){return{enter:{table:Xu,tableData:Gt,tableHeader:Gt,tableRow:Ju},exit:{codeText:Zu,table:Gu,tableData:Pn,tableHeader:Pn,tableRow:Pn}}}function Xu(e){const t=e._align;this.enter({type:"table",align:t.map(function(n){return n==="none"?null:n}),children:[]},e),this.data.inTable=!0}function Gu(e){this.exit(e),this.data.inTable=void 0}function Ju(e){this.enter({type:"tableRow",children:[]},e)}function Pn(e){this.exit(e)}function Gt(e){this.enter({type:"tableCell",children:[]},e)}function Zu(e){let t=this.resume();this.data.inTable&&(t=t.replace(/\\([\\|])/g,ec));const n=this.stack[this.stack.length-1];n.type,n.value=t,this.exit(e)}function ec(e,t){return t==="|"?t:e}function nc(e){const t=e||{},n=t.tableCellPadding,r=t.tablePipeAlign,i=t.stringLength,o=n?" ":"|";return{unsafe:[{character:"\r",inConstruct:"tableCell"},{character:` +`,inConstruct:"tableCell"},{atBreak:!0,character:"|",after:"[ :-]"},{character:"|",inConstruct:"tableCell"},{atBreak:!0,character:":",after:"-"},{atBreak:!0,character:"-",after:"[:|-]"}],handlers:{inlineCode:p,table:l,tableCell:s,tableRow:a}};function l(f,g,w,S){return u(h(f,w,S),f.align)}function a(f,g,w,S){const y=c(f,w,S),I=u([y]);return I.slice(0,I.indexOf(` +`))}function s(f,g,w,S){const y=w.enter("tableCell"),I=w.enter("phrasing"),C=w.containerPhrasing(f,{...S,before:o,after:o});return I(),y(),C}function u(f,g){return du(f,{align:g,alignDelimiters:r,padding:n,stringLength:i})}function h(f,g,w){const S=f.children;let y=-1;const I=[],C=g.enter("table");for(;++y0&&!n&&(e[e.length-1][1]._gfmAutolinkLiteralWalkedInto=!0),n}const xc={tokenize:Tc,partial:!0};function bc(){return{document:{91:{name:"gfmFootnoteDefinition",tokenize:Ec,continuation:{tokenize:Ic},exit:vc}},text:{91:{name:"gfmFootnoteCall",tokenize:Cc},93:{name:"gfmPotentialFootnoteCall",add:"after",tokenize:wc,resolveTo:Sc}}}}function wc(e,t,n){const r=this;let i=r.events.length;const o=r.parser.gfmFootnotes||(r.parser.gfmFootnotes=[]);let l;for(;i--;){const s=r.events[i][1];if(s.type==="labelImage"){l=s;break}if(s.type==="gfmFootnoteCall"||s.type==="labelLink"||s.type==="label"||s.type==="image"||s.type==="link")break}return a;function a(s){if(!l||!l._balanced)return n(s);const u=ce(r.sliceSerialize({start:l.end,end:r.now()}));return u.codePointAt(0)!==94||!o.includes(u.slice(1))?n(s):(e.enter("gfmFootnoteCallLabelMarker"),e.consume(s),e.exit("gfmFootnoteCallLabelMarker"),t(s))}}function Sc(e,t){let n=e.length;for(;n--;)if(e[n][1].type==="labelImage"&&e[n][0]==="enter"){e[n][1];break}e[n+1][1].type="data",e[n+3][1].type="gfmFootnoteCallLabelMarker";const r={type:"gfmFootnoteCall",start:Object.assign({},e[n+3][1].start),end:Object.assign({},e[e.length-1][1].end)},i={type:"gfmFootnoteCallMarker",start:Object.assign({},e[n+3][1].end),end:Object.assign({},e[n+3][1].end)};i.end.column++,i.end.offset++,i.end._bufferIndex++;const o={type:"gfmFootnoteCallString",start:Object.assign({},i.end),end:Object.assign({},e[e.length-1][1].start)},l={type:"chunkString",contentType:"string",start:Object.assign({},o.start),end:Object.assign({},o.end)},a=[e[n+1],e[n+2],["enter",r,t],e[n+3],e[n+4],["enter",i,t],["exit",i,t],["enter",o,t],["enter",l,t],["exit",l,t],["exit",o,t],e[e.length-2],e[e.length-1],["exit",r,t]];return e.splice(n,e.length-n+1,...a),e}function Cc(e,t,n){const r=this,i=r.parser.gfmFootnotes||(r.parser.gfmFootnotes=[]);let o=0,l;return a;function a(c){return e.enter("gfmFootnoteCall"),e.enter("gfmFootnoteCallLabelMarker"),e.consume(c),e.exit("gfmFootnoteCallLabelMarker"),s}function s(c){return c!==94?n(c):(e.enter("gfmFootnoteCallMarker"),e.consume(c),e.exit("gfmFootnoteCallMarker"),e.enter("gfmFootnoteCallString"),e.enter("chunkString").contentType="string",u)}function u(c){if(o>999||c===93&&!l||c===null||c===91||W(c))return n(c);if(c===93){e.exit("chunkString");const p=e.exit("gfmFootnoteCallString");return i.includes(ce(r.sliceSerialize(p)))?(e.enter("gfmFootnoteCallLabelMarker"),e.consume(c),e.exit("gfmFootnoteCallLabelMarker"),e.exit("gfmFootnoteCall"),t):n(c)}return W(c)||(l=!0),o++,e.consume(c),c===92?h:u}function h(c){return c===91||c===92||c===93?(e.consume(c),o++,u):u(c)}}function Ec(e,t,n){const r=this,i=r.parser.gfmFootnotes||(r.parser.gfmFootnotes=[]);let o,l=0,a;return s;function s(g){return e.enter("gfmFootnoteDefinition")._container=!0,e.enter("gfmFootnoteDefinitionLabel"),e.enter("gfmFootnoteDefinitionLabelMarker"),e.consume(g),e.exit("gfmFootnoteDefinitionLabelMarker"),u}function u(g){return g===94?(e.enter("gfmFootnoteDefinitionMarker"),e.consume(g),e.exit("gfmFootnoteDefinitionMarker"),e.enter("gfmFootnoteDefinitionLabelString"),e.enter("chunkString").contentType="string",h):n(g)}function h(g){if(l>999||g===93&&!a||g===null||g===91||W(g))return n(g);if(g===93){e.exit("chunkString");const w=e.exit("gfmFootnoteDefinitionLabelString");return o=ce(r.sliceSerialize(w)),e.enter("gfmFootnoteDefinitionLabelMarker"),e.consume(g),e.exit("gfmFootnoteDefinitionLabelMarker"),e.exit("gfmFootnoteDefinitionLabel"),p}return W(g)||(a=!0),l++,e.consume(g),g===92?c:h}function c(g){return g===91||g===92||g===93?(e.consume(g),l++,h):h(g)}function p(g){return g===58?(e.enter("definitionMarker"),e.consume(g),e.exit("definitionMarker"),i.includes(o)||i.push(o),B(e,f,"gfmFootnoteDefinitionWhitespace")):n(g)}function f(g){return t(g)}}function Ic(e,t,n){return e.check(Qe,t,e.attempt(xc,t,n))}function vc(e){e.exit("gfmFootnoteDefinition")}function Tc(e,t,n){const r=this;return B(e,i,"gfmFootnoteDefinitionIndent",5);function i(o){const l=r.events[r.events.length-1];return l&&l[1].type==="gfmFootnoteDefinitionIndent"&&l[2].sliceSerialize(l[1],!0).length===4?t(o):n(o)}}function Ac(e){let n=(e||{}).singleTilde;const r={name:"strikethrough",tokenize:o,resolveAll:i};return n==null&&(n=!0),{text:{126:r},insideSpan:{null:[r]},attentionMarkers:{null:[126]}};function i(l,a){let s=-1;for(;++s1?s(g):(l.consume(g),c++,f);if(c<2&&!n)return s(g);const S=l.exit("strikethroughSequenceTemporary"),y=_e(g);return S._open=!y||y===2&&!!w,S._close=!w||w===2&&!!y,a(g)}}}class Pc{constructor(){this.map=[]}add(t,n,r){zc(this,t,n,r)}consume(t){if(this.map.sort(function(o,l){return o[0]-l[0]}),this.map.length===0)return;let n=this.map.length;const r=[];for(;n>0;)n-=1,r.push(t.slice(this.map[n][0]+this.map[n][1]),this.map[n][2]),t.length=this.map[n][0];r.push(t.slice()),t.length=0;let i=r.pop();for(;i;){for(const o of i)t.push(o);i=r.pop()}this.map.length=0}}function zc(e,t,n,r){let i=0;if(!(n===0&&r.length===0)){for(;i-1;){const D=r.events[A][1].type;if(D==="lineEnding"||D==="linePrefix")A--;else break}const P=A>-1?r.events[A][1].type:null,q=P==="tableHead"||P==="tableRow"?b:s;return q===b&&r.parser.lazy[r.now().line]?n(k):q(k)}function s(k){return e.enter("tableHead"),e.enter("tableRow"),u(k)}function u(k){return k===124||(l=!0,o+=1),h(k)}function h(k){return k===null?n(k):z(k)?o>1?(o=0,r.interrupt=!0,e.exit("tableRow"),e.enter("lineEnding"),e.consume(k),e.exit("lineEnding"),f):n(k):O(k)?B(e,h,"whitespace")(k):(o+=1,l&&(l=!1,i+=1),k===124?(e.enter("tableCellDivider"),e.consume(k),e.exit("tableCellDivider"),l=!0,h):(e.enter("data"),c(k)))}function c(k){return k===null||k===124||W(k)?(e.exit("data"),h(k)):(e.consume(k),k===92?p:c)}function p(k){return k===92||k===124?(e.consume(k),c):c(k)}function f(k){return r.interrupt=!1,r.parser.lazy[r.now().line]?n(k):(e.enter("tableDelimiterRow"),l=!1,O(k)?B(e,g,"linePrefix",r.parser.constructs.disable.null.includes("codeIndented")?void 0:4)(k):g(k))}function g(k){return k===45||k===58?S(k):k===124?(l=!0,e.enter("tableCellDivider"),e.consume(k),e.exit("tableCellDivider"),w):F(k)}function w(k){return O(k)?B(e,S,"whitespace")(k):S(k)}function S(k){return k===58?(o+=1,l=!0,e.enter("tableDelimiterMarker"),e.consume(k),e.exit("tableDelimiterMarker"),y):k===45?(o+=1,y(k)):k===null||z(k)?R(k):F(k)}function y(k){return k===45?(e.enter("tableDelimiterFiller"),I(k)):F(k)}function I(k){return k===45?(e.consume(k),I):k===58?(l=!0,e.exit("tableDelimiterFiller"),e.enter("tableDelimiterMarker"),e.consume(k),e.exit("tableDelimiterMarker"),C):(e.exit("tableDelimiterFiller"),C(k))}function C(k){return O(k)?B(e,R,"whitespace")(k):R(k)}function R(k){return k===124?g(k):k===null||z(k)?!l||i!==o?F(k):(e.exit("tableDelimiterRow"),e.exit("tableHead"),t(k)):F(k)}function F(k){return n(k)}function b(k){return e.enter("tableRow"),M(k)}function M(k){return k===124?(e.enter("tableCellDivider"),e.consume(k),e.exit("tableCellDivider"),M):k===null||z(k)?(e.exit("tableRow"),t(k)):O(k)?B(e,M,"whitespace")(k):(e.enter("data"),H(k))}function H(k){return k===null||k===124||W(k)?(e.exit("data"),M(k)):(e.consume(k),k===92?j:H)}function j(k){return k===92||k===124?(e.consume(k),H):H(k)}}function Rc(e,t){let n=-1,r=!0,i=0,o=[0,0,0,0],l=[0,0,0,0],a=!1,s=0,u,h,c;const p=new Pc;for(;++nn[2]+1){const g=n[2]+1,w=n[3]-n[2]-1;e.add(g,w,[])}}e.add(n[3]+1,0,[["exit",c,t]])}return i!==void 0&&(o.end=Object.assign({},Le(t.events,i)),e.add(i,0,[["exit",o,t]]),o=void 0),o}function Zt(e,t,n,r,i){const o=[],l=Le(t.events,n);i&&(i.end=Object.assign({},l),o.push(["exit",i,t])),r.end=Object.assign({},l),o.push(["exit",r,t]),e.add(n+1,0,o)}function Le(e,t){const n=e[t],r=n[0]==="enter"?"start":"end";return n[1][r]}const Fc={name:"tasklistCheck",tokenize:Mc};function Oc(){return{text:{91:Fc}}}function Mc(e,t,n){const r=this;return i;function i(s){return r.previous!==null||!r._gfmTasklistFirstContentOfListItem?n(s):(e.enter("taskListCheck"),e.enter("taskListCheckMarker"),e.consume(s),e.exit("taskListCheckMarker"),o)}function o(s){return W(s)?(e.enter("taskListCheckValueUnchecked"),e.consume(s),e.exit("taskListCheckValueUnchecked"),l):s===88||s===120?(e.enter("taskListCheckValueChecked"),e.consume(s),e.exit("taskListCheckValueChecked"),l):n(s)}function l(s){return s===93?(e.enter("taskListCheckMarker"),e.consume(s),e.exit("taskListCheckMarker"),e.exit("taskListCheck"),a):n(s)}function a(s){return z(s)?t(s):O(s)?e.check({tokenize:Nc},t,n)(s):n(s)}}function Nc(e,t,n){return B(e,r,"whitespace");function r(i){return i===null?n(i):t(i)}}function Bc(e){return gr([cc(),bc(),Ac(e),Lc(),Oc()])}const jc={};function Hc(e){const t=this,n=e||jc,r=t.data(),i=r.micromarkExtensions||(r.micromarkExtensions=[]),o=r.fromMarkdownExtensions||(r.fromMarkdownExtensions=[]),l=r.toMarkdownExtensions||(r.toMarkdownExtensions=[]);i.push(Bc(n)),o.push(oc()),l.push(ac(n))}const qc=`# Admin dashboard Otari ships with a web admin dashboard for operators. It browses the model catalogue, sets model pricing, manages aliases, adds and edits provider API @@ -185,6 +185,10 @@ gateway. - **Activity**: the per-request log of what the gateway served, with filters. Use it to inspect individual requests, their models, and their outcomes. + Requests the gateway refused are logged too, so filtering to the \`error\` + status shows what is being dropped, including requests rejected for having no + pricing under \`require_pricing\`. Diagnostic detail stays in the gateway logs + rather than the browser. - **Usage**: aggregate usage and analytics, showing spend and volume over time, broken down by model and by user. @@ -275,8 +279,8 @@ put it behind HTTPS, as the security notes below describe. request. - [Modes](modes.md): standalone versus hybrid, and why the dashboard is standalone-only. -`,er="https://github.com/mozilla-ai/otari/blob/main/docs/",qc="dashboard.md";function Vc(e){return!e||/^[a-z][a-z0-9+.-]*:/i.test(e)||e.startsWith("//")?e:e.startsWith("#")?er+qc+e:er+e.replace(/^\.\//,"")}function $c(e){return!!e&&(/^https?:\/\//i.test(e)||e.startsWith("//"))}function Wc(e,t){const n=e.split(` +`,er="https://github.com/mozilla-ai/otari/blob/main/docs/",Uc="dashboard.md";function Vc(e){return!e||/^[a-z][a-z0-9+.-]*:/i.test(e)||e.startsWith("//")?e:e.startsWith("#")?er+Uc+e:er+e.replace(/^\.\//,"")}function $c(e){return!!e&&(/^https?:\/\//i.test(e)||e.startsWith("//"))}function Wc(e,t){const n=e.split(` `),r=n.findIndex(l=>l.trim()===`## ${t}`);if(r===-1)return e;let i=n.length,o=!1;for(let l=r+1;l{const i=Vc(t),o=$c(i);return re.jsx("a",{href:i,...o?{target:"_blank",rel:"noreferrer"}:{},...r,children:n})},table:({node:e,...t})=>re.jsx("div",{className:"otari-markdown-scroll",tabIndex:0,role:"region","aria-label":"Table",children:re.jsx("table",{...t})}),pre:({node:e,...t})=>re.jsx("pre",{tabIndex:0,role:"region","aria-label":"Code",...t})};function Zc(){return re.jsxs("div",{className:"flex flex-col gap-6",children:[re.jsx(gi,{title:"User guide",description:"A reference for operating this dashboard, bundled with and version-matched to the running gateway. New here? The get-started walkthrough lives at /welcome."}),re.jsx(ct,{children:re.jsx(ct.Content,{className:"p-5 sm:p-6",children:re.jsx("div",{className:"otari-markdown",children:re.jsx(As,{remarkPlugins:[Hc],components:Kc,children:Yc})})})})]})}export{Zc as DocsPage}; +`)}const Yc=Wc(qc.replace(/^#{1,6}[ \t]+.*\r?\n+/,""),"First-run walkthrough"),Kc={a:({node:e,href:t,children:n,...r})=>{const i=Vc(t),o=$c(i);return re.jsx("a",{href:i,...o?{target:"_blank",rel:"noreferrer"}:{},...r,children:n})},table:({node:e,...t})=>re.jsx("div",{className:"otari-markdown-scroll",tabIndex:0,role:"region","aria-label":"Table",children:re.jsx("table",{...t})}),pre:({node:e,...t})=>re.jsx("pre",{tabIndex:0,role:"region","aria-label":"Code",...t})};function Zc(){return re.jsxs("div",{className:"flex flex-col gap-6",children:[re.jsx(gi,{title:"User guide",description:"A reference for operating this dashboard, bundled with and version-matched to the running gateway. New here? The get-started walkthrough lives at /welcome."}),re.jsx(ct,{children:re.jsx(ct.Content,{className:"p-5 sm:p-6",children:re.jsx("div",{className:"otari-markdown",children:re.jsx(As,{remarkPlugins:[Hc],components:Kc,children:Yc})})})})]})}export{Zc as DocsPage}; diff --git a/src/gateway/static/dashboard/assets/FilterChips-Dqy1SR3R.js b/src/gateway/static/dashboard/assets/FilterChips-Dqy1SR3R.js new file mode 100644 index 00000000..9064060d --- /dev/null +++ b/src/gateway/static/dashboard/assets/FilterChips-Dqy1SR3R.js @@ -0,0 +1 @@ +import{j as t}from"./tanstack-query-1t81HyiD.js";import{r as p}from"./react-dgEcD0HR.js";import{B as M,S as ae,$ as ne,h as se,i as ie}from"./heroui-BI50yK5B.js";import{an as oe,ao as le,ap as ce,aq as de}from"./index-Bi2hajrg.js";import{R as ue,B as me,X as xe,T as he,a as fe}from"./recharts-C4kRDmvS.js";const pe="var(--otari-brand)",ge=10,ve=22;function $(o,m){const c=new Date(o);return Number.isNaN(c.getTime())?o:m==="hour"?c.toLocaleTimeString(void 0,{hour:"2-digit",minute:"2-digit",timeZone:"UTC"}):c.toLocaleDateString(void 0,{month:"short",day:"numeric",timeZone:"UTC"})}function be({active:o,label:m,payload:c,bucket:g}){var x;const j=(x=c==null?void 0:c[0])==null?void 0:x.value;return!o||typeof j!="number"||typeof m!="string"?null:t.jsxs("div",{className:"rounded-md border border-[var(--otari-line)] bg-[var(--otari-surface)] px-2 py-1 text-xs shadow-sm",children:[t.jsxs("div",{className:"text-[var(--otari-muted)]",children:[$(m,g)," · UTC"]}),t.jsxs("div",{className:"font-medium tabular-nums text-[var(--otari-ink)]",children:[j.toLocaleString()," requests"]})]})}const je="group top-1/2 h-full w-3 cursor-ew-resize outline-none",F=["Window start","Window end"];function W({index:o}){return t.jsxs(ie,{index:o,"aria-label":F[o],className:`${je} pointer-events-auto`,children:[t.jsx("span",{"aria-hidden":!0,className:"absolute inset-y-0 left-1/2 w-0.5 -translate-x-1/2 bg-[var(--otari-brand)]"}),t.jsx("span",{"aria-hidden":!0,className:"absolute left-1/2 top-1/2 h-6 w-2 -translate-x-1/2 -translate-y-1/2 rounded-full border border-[var(--otari-brand)] bg-[var(--otari-surface)] shadow-sm group-focus-visible:ring-2 group-focus-visible:ring-[var(--otari-brand)]"})]})}function Pe({presets:o,extentKey:m,onPreset:c,onSelectRange:g,onSelectFull:j,series:x,bucket:l,windowStart:C,windowEnd:S,loading:K=!1,ariaLabel:_="Request volume over the selected window",action:O}){const w=x.map(e=>e.bucketStart),X=x.map(e=>({x:e.bucketStart,requests:e.requests})),r=x.length,H=oe(C,S),z=()=>{if(r===0)return[0,1];const{startIndex:e,endIndex:s}=ce(w,C,S);return[e,s+1]},[T,Z]=p.useState(z),y=p.useRef(T),v=e=>{y.current=e,Z(e)},N=p.useRef(!1);p.useEffect(()=>{N.current||v(z())},[C,S,r,w[0],w[r-1]]);const b=([e,s])=>{if(N.current=!1,r===0)return;const i=Math.max(0,Math.min(r-1,Math.floor(e+1e-6))),a=Math.max(i,Math.min(r-1,Math.ceil(s-1e-6)-1));if(i===0&&a===r-1){j(),v([0,r]);return}const n=de(w,i,a,l);n&&g(n.startIso,n.endIso)},k=o.findIndex(e=>e.key===m),B=k>=0?o[k].seconds:r*le(l)/1e3,A=k>=0?o[k+1]:o.find(e=>e.seconds===null||B!==null&&e.seconds>B),[d,u]=T,P=d<=.01&&u>=r-.01,L=e=>{const s=Math.max(1,Math.min(r,e)),i=(d+u)/2;let a=i-s/2,n=i+s/2;a<0&&(n-=a,a=0),n>r&&(a-=n-r,n=r);const f=[Math.max(0,a),Math.min(r,n)];v(f),b(f)},V=()=>{if(P){A&&c(A);return}L((u-d)*2)},G=()=>L((u-d)/2),J=(e,s)=>{const[i,a]=y.current,n=e===0?[Math.max(0,Math.min(a-1,Math.round(i)+s)),a]:[i,Math.min(r,Math.max(i+1,Math.round(a)+s))];v(n),b(n)},Q=e=>{var n,f;const s=e.key==="ArrowRight"||e.key==="ArrowUp"?1:e.key==="ArrowLeft"||e.key==="ArrowDown"?-1:0;if(s===0)return;const i=(f=(n=e.target).getAttribute)==null?void 0:f.call(n,"aria-label"),a=F.indexOf(i);a<0||(e.preventDefault(),e.stopPropagation(),J(a,s))},R=p.useRef(null),h=p.useRef(null),Y=e=>{if(!h.current||!R.current)return;const s=R.current.getBoundingClientRect().width;if(s<=0)return;const i=(e.clientX-h.current.x)/s*r,a=h.current.sel[1]-h.current.sel[0],n=Math.max(0,Math.min(r-a,h.current.sel[0]+i));v([n,n+a])},ee=e=>{const[s,i]=y.current,a=i-s,n=Math.max(0,Math.min(r-a,Math.round(s)+e)),f=[n,n+a];v(f),b(f)},te=e=>{if(P)return;const[s,i]=y.current,a=Math.max(1,Math.round(i-s)),n=e.key==="ArrowRight"||e.key==="ArrowUp"?1:e.key==="ArrowLeft"||e.key==="ArrowDown"?-1:e.key==="PageUp"?a:e.key==="PageDown"?-a:e.key==="Home"?-r:e.key==="End"?r:0;n!==0&&(e.preventDefault(),ee(n))},I=r?Math.min(d,u)/r*100:0,E=r?Math.max(d,u)/r*100:100,D=!P,re=Math.max(1,Math.round(u-d)),U=Math.max(0,r-re),q=Math.min(Math.max(0,Math.round(Math.min(d,u))),U);return t.jsxs("div",{className:"flex flex-col gap-2",children:[t.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[o.map(e=>t.jsx(M,{size:"sm",variant:m===e.key?"primary":"outline",onPress:()=>c(e),children:e.label},e.key)),t.jsxs("div",{className:"ml-auto flex items-center gap-3",children:[t.jsxs("span",{className:"text-xs text-[var(--otari-muted)]",children:["Showing ",H," · UTC"]}),O]})]}),t.jsxs("div",{className:"rounded-xl border border-[var(--otari-line)] bg-[var(--otari-surface)] p-2",children:[t.jsxs("div",{className:"flex items-center justify-between gap-2 px-1 pb-1",children:[t.jsxs("span",{className:"text-[11px] font-medium uppercase tracking-wide text-[var(--otari-muted)]",children:["Requests / ",l==="hour"?"hour":"day"]}),t.jsxs("div",{className:"flex items-center gap-1.5",children:[t.jsx("span",{className:"hidden text-[11px] text-[var(--otari-muted)] sm:inline",children:"drag the edges to zoom · the bottom strip to pan"}),t.jsx(M,{size:"sm",variant:"ghost",isIconOnly:!0,"aria-label":"Zoom in",isDisabled:r===0,onPress:G,children:t.jsx("svg",{viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",className:"h-4 w-4","aria-hidden":"true",children:t.jsx("path",{d:"M12 5v14M5 12h14",strokeLinecap:"round"})})}),t.jsx(M,{size:"sm",variant:"ghost",isIconOnly:!0,"aria-label":"Zoom out",isDisabled:r===0||P&&!A,onPress:V,children:t.jsx("svg",{viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",className:"h-4 w-4","aria-hidden":"true",children:t.jsx("path",{d:"M5 12h14",strokeLinecap:"round"})})}),D?t.jsx(M,{size:"sm",variant:"ghost",onPress:()=>b([0,r]),children:"Reset"}):null]})]}),K&&r===0?t.jsx("div",{className:"flex h-[90px] items-center justify-center",children:t.jsx(ae,{size:"sm"})}):r===0?t.jsx("div",{className:"flex h-[90px] items-center justify-center text-xs text-[var(--otari-muted)]",children:"No activity in this range."}):t.jsxs("div",{ref:R,className:"relative w-full",children:[t.jsx("div",{role:"img","aria-label":_,className:"w-full touch-pan-y select-none",children:t.jsx(ue,{width:"100%",height:90,children:t.jsxs(me,{data:X,margin:{top:4,right:0,left:0,bottom:0},children:[t.jsx(xe,{dataKey:"x",tickLine:!1,axisLine:!1,interval:"preserveStartEnd",minTickGap:40,tickFormatter:e=>$(e,l),tick:{fontSize:10,fill:"var(--otari-muted)"}}),t.jsx(he,{cursor:{fill:"var(--otari-line)",opacity:.35},content:t.jsx(be,{bucket:l})}),t.jsx(fe,{dataKey:"requests",fill:pe,radius:[2,2,0,0],isAnimationActive:!1})]})})}),D?t.jsxs(t.Fragment,{children:[t.jsx("div",{"aria-hidden":!0,className:"pointer-events-none absolute inset-y-0 left-0 bg-[var(--otari-bg)] opacity-70",style:{width:`${I}%`}}),t.jsx("div",{"aria-hidden":!0,className:"pointer-events-none absolute inset-y-0 right-0 bg-[var(--otari-bg)] opacity-70",style:{width:`${100-E}%`}})]}):null,t.jsx("div",{role:"slider","aria-label":"Pan the selected window","aria-valuemin":0,"aria-valuemax":U,"aria-valuenow":q,"aria-valuetext":`Window starting at ${$(w[Math.min(q,r-1)]??w[0],l)}`,"aria-disabled":!D,tabIndex:0,className:"absolute bottom-0 z-[1] cursor-grab touch-none rounded bg-[var(--otari-brand)]/10 outline-none hover:bg-[var(--otari-brand)]/20 focus-visible:ring-2 focus-visible:ring-[var(--otari-brand)] active:cursor-grabbing",style:{left:`${I}%`,width:`${Math.max(0,E-I)}%`,height:ve},onKeyDown:te,onPointerDown:e=>{e.stopPropagation(),e.preventDefault(),N.current=!0,h.current={x:e.clientX,sel:[Math.min(d,u),Math.max(d,u)]},e.currentTarget.setPointerCapture(e.pointerId)},onPointerMove:Y,onPointerUp:e=>{e.currentTarget.releasePointerCapture(e.pointerId),h.current=null,b(y.current)},onPointerCancel:e=>{e.currentTarget.hasPointerCapture(e.pointerId)&&e.currentTarget.releasePointerCapture(e.pointerId),h.current=null,b(y.current)}}),t.jsx("div",{className:"pointer-events-none absolute inset-0 z-[2]",onKeyDownCapture:Q,children:t.jsx(ne,{"aria-label":"Selected time range",minValue:0,maxValue:r,step:1/ge,value:T,onChange:e=>{N.current=!0,Array.isArray(e)&&e.length===2&&v([e[0],e[1]])},onChangeEnd:e=>{Array.isArray(e)&&e.length===2&&b([e[0],e[1]])},className:"pointer-events-none h-full w-full",children:t.jsxs(se,{className:"pointer-events-none relative h-full w-full",children:[t.jsx(W,{index:0}),t.jsx(W,{index:1})]})})})]})]})]})}function Ce({chips:o,children:m,onClearAll:c}){const[g,j]=p.useState(!1),x=p.useId();return t.jsxs("div",{className:"flex flex-col gap-2",children:[t.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[t.jsx(M,{size:"sm",variant:"outline",onPress:()=>j(l=>!l),"aria-expanded":g,"aria-controls":x,children:g?"Done":"Add filter"}),o.map(l=>t.jsxs("span",{className:"inline-flex items-center gap-1 rounded-full border border-[var(--otari-line)] bg-[var(--otari-brand-tint)] py-0.5 pl-2.5 pr-1 text-xs text-[var(--otari-brand-dark)]",children:[t.jsxs("span",{className:"text-[var(--otari-muted)]",children:[l.label,":"]}),t.jsx("span",{className:"font-medium",children:l.value}),t.jsx("button",{type:"button",onClick:l.onClear,"aria-label":`Remove ${l.label} filter`,className:"ml-0.5 inline-flex h-4 w-4 items-center justify-center rounded-full text-[var(--otari-muted)] outline-none hover:bg-[var(--otari-line)] hover:text-[var(--otari-ink)] focus-visible:ring-2 focus-visible:ring-[var(--otari-brand)]",children:t.jsx("svg",{viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2.5",className:"h-3 w-3","aria-hidden":"true",children:t.jsx("path",{d:"M6 6l12 12M18 6L6 18",strokeLinecap:"round"})})})]},l.key)),o.length>0&&c?t.jsx(M,{size:"sm",variant:"ghost",onPress:c,children:"Clear all"}):null]}),t.jsx("div",{id:x,className:g?"flex flex-wrap items-end gap-3":"hidden",children:m})]})}export{Pe as A,Ce as F}; diff --git a/src/gateway/static/dashboard/assets/FilterChips-DtSH11eU.js b/src/gateway/static/dashboard/assets/FilterChips-DtSH11eU.js deleted file mode 100644 index 76503e8a..00000000 --- a/src/gateway/static/dashboard/assets/FilterChips-DtSH11eU.js +++ /dev/null @@ -1 +0,0 @@ -import{j as t}from"./tanstack-query-1t81HyiD.js";import{r as w}from"./react-dgEcD0HR.js";import{B as N,S as oe,$ as le,h as ce,i as de}from"./heroui-BI50yK5B.js";import{R as ue,B as me,X as he,T as xe,a as fe}from"./recharts-C4kRDmvS.js";const L=3600,b=86400,ge=365*b,Ae=[{key:"1h",label:"Last hour",seconds:L,bucket:"hour"},{key:"24h",label:"24h",seconds:b,bucket:"hour"},{key:"7d",label:"7d",seconds:7*b,bucket:"day"},{key:"30d",label:"30d",seconds:30*b,bucket:"day"},{key:"90d",label:"90d",seconds:90*b,bucket:"day"},{key:"12mo",label:"12mo",seconds:ge,bucket:"day"}],Pe="30d",Ce=[{key:"1h",label:"1h",seconds:L,bucket:"hour"},{key:"24h",label:"24h",seconds:b,bucket:"hour"},{key:"7d",label:"7d",seconds:7*b,bucket:"day"},{key:"30d",label:"30d",seconds:30*b,bucket:"day"},{key:"all",label:"All",seconds:null,bucket:"day"}],Re="24h",Ee="custom";function Ie(n,a){return n.find(s=>s.key===a)}function Ue(n,a=Date.now()){return new Date(a-n*1e3).toISOString()}function W(n){return(n==="hour"?L:b)*1e3}function $e(n,a,s=Date.now()){const c=new Date(n).getTime();return(a?new Date(a).getTime():s)-c<=b*1e3?"hour":"day"}function pe(n,a,s,c){if(n.length===0)return null;const h=Math.max(0,Math.min(a,s)),u=Math.min(n.length-1,Math.max(a,s)),l=new Date(n[h]).getTime(),f=new Date(n[u]).getTime()+W(c);return{startIso:new Date(l).toISOString(),endIso:new Date(f).toISOString()}}function be(n,a,s){const c=n.length;if(c===0)return{startIndex:0,endIndex:0};const h=n.map(f=>new Date(f).getTime());let u=0;if(a){const f=new Date(a).getTime();for(let x=0;xe.bucketStart),V=u.map(e=>({x:e.bucketStart,requests:e.requests})),r=u.length,G=ve(f,x),_=()=>{if(r===0)return[0,1];const{startIndex:e,endIndex:d}=be(T,f,x);return[e,d+1]},[C,J]=w.useState(_),D=w.useRef(C),j=e=>{D.current=e,J(e)},S=w.useRef(!1);w.useEffect(()=>{S.current||j(_())},[f,x,r,T[0],T[r-1]]);const k=([e,d])=>{if(S.current=!1,r===0)return;const m=Math.max(0,Math.min(r-1,Math.floor(e+1e-6))),i=Math.max(m,Math.min(r-1,Math.ceil(d-1e-6)-1));if(m===0&&i===r-1){h(),j([0,r]);return}const o=pe(T,m,i,l);o&&c(o.startIso,o.endIso)},A=n.findIndex(e=>e.key===a),z=A>=0?n[A].seconds:r*W(l)/1e3,R=A>=0?n[A+1]:n.find(e=>e.seconds===null||z!==null&&e.seconds>z),[g,p]=C,P=g<=.01&&p>=r-.01,B=e=>{const d=Math.max(1,Math.min(r,e)),m=(g+p)/2;let i=m-d/2,o=m+d/2;i<0&&(o-=i,i=0),o>r&&(i-=o-r,o=r);const y=[Math.max(0,i),Math.min(r,o)];j(y),k(y)},Q=()=>{if(P){R&&s(R);return}B((p-g)*2)},ee=()=>B((p-g)/2),te=(e,d)=>{const[m,i]=D.current,o=e===0?[Math.max(0,Math.min(i-1,Math.round(m)+d)),i]:[m,Math.min(r,Math.max(m+1,Math.round(i)+d))];j(o),k(o)},ne=e=>{var o,y;const d=e.key==="ArrowRight"||e.key==="ArrowUp"?1:e.key==="ArrowLeft"||e.key==="ArrowDown"?-1:0;if(d===0)return;const m=(y=(o=e.target).getAttribute)==null?void 0:y.call(o,"aria-label"),i=q.indexOf(m);i<0||(e.preventDefault(),e.stopPropagation(),te(i,d))},E=w.useRef(null),v=w.useRef(null),re=e=>{if(!v.current||!E.current)return;const d=E.current.getBoundingClientRect().width;if(d<=0)return;const m=(e.clientX-v.current.x)/d*r,i=v.current.sel[1]-v.current.sel[0],o=Math.max(0,Math.min(r-i,v.current.sel[0]+m));j([o,o+i])},ae=e=>{const[d,m]=D.current,i=m-d,o=Math.max(0,Math.min(r-i,Math.round(d)+e)),y=[o,o+i];j(y),k(y)},se=e=>{if(P)return;const[d,m]=D.current,i=Math.max(1,Math.round(m-d)),o=e.key==="ArrowRight"||e.key==="ArrowUp"?1:e.key==="ArrowLeft"||e.key==="ArrowDown"?-1:e.key==="PageUp"?i:e.key==="PageDown"?-i:e.key==="Home"?-r:e.key==="End"?r:0;o!==0&&(e.preventDefault(),ae(o))},I=r?Math.min(g,p)/r*100:0,F=r?Math.max(g,p)/r*100:100,U=!P,ie=Math.max(1,Math.round(p-g)),Y=Math.max(0,r-ie),O=Math.min(Math.max(0,Math.round(Math.min(g,p))),Y);return t.jsxs("div",{className:"flex flex-col gap-2",children:[t.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[n.map(e=>t.jsx(N,{size:"sm",variant:a===e.key?"primary":"outline",onPress:()=>s(e),children:e.label},e.key)),t.jsxs("div",{className:"ml-auto flex items-center gap-3",children:[t.jsxs("span",{className:"text-xs text-[var(--otari-muted)]",children:["Showing ",G," · UTC"]}),Z]})]}),t.jsxs("div",{className:"rounded-xl border border-[var(--otari-line)] bg-[var(--otari-surface)] p-2",children:[t.jsxs("div",{className:"flex items-center justify-between gap-2 px-1 pb-1",children:[t.jsxs("span",{className:"text-[11px] font-medium uppercase tracking-wide text-[var(--otari-muted)]",children:["Requests / ",l==="hour"?"hour":"day"]}),t.jsxs("div",{className:"flex items-center gap-1.5",children:[t.jsx("span",{className:"hidden text-[11px] text-[var(--otari-muted)] sm:inline",children:"drag the edges to zoom · the bottom strip to pan"}),t.jsx(N,{size:"sm",variant:"ghost",isIconOnly:!0,"aria-label":"Zoom in",isDisabled:r===0,onPress:ee,children:t.jsx("svg",{viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",className:"h-4 w-4","aria-hidden":"true",children:t.jsx("path",{d:"M12 5v14M5 12h14",strokeLinecap:"round"})})}),t.jsx(N,{size:"sm",variant:"ghost",isIconOnly:!0,"aria-label":"Zoom out",isDisabled:r===0||P&&!R,onPress:Q,children:t.jsx("svg",{viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",className:"h-4 w-4","aria-hidden":"true",children:t.jsx("path",{d:"M5 12h14",strokeLinecap:"round"})})}),U?t.jsx(N,{size:"sm",variant:"ghost",onPress:()=>k([0,r]),children:"Reset"}):null]})]}),H&&r===0?t.jsx("div",{className:"flex h-[90px] items-center justify-center",children:t.jsx(oe,{size:"sm"})}):r===0?t.jsx("div",{className:"flex h-[90px] items-center justify-center text-xs text-[var(--otari-muted)]",children:"No activity in this range."}):t.jsxs("div",{ref:E,className:"relative w-full",children:[t.jsx("div",{role:"img","aria-label":X,className:"w-full touch-pan-y select-none",children:t.jsx(ue,{width:"100%",height:90,children:t.jsxs(me,{data:V,margin:{top:4,right:0,left:0,bottom:0},children:[t.jsx(he,{dataKey:"x",tickLine:!1,axisLine:!1,interval:"preserveStartEnd",minTickGap:40,tickFormatter:e=>$(e,l),tick:{fontSize:10,fill:"var(--otari-muted)"}}),t.jsx(xe,{cursor:{fill:"var(--otari-line)",opacity:.35},content:t.jsx(ke,{bucket:l})}),t.jsx(fe,{dataKey:"requests",fill:ye,radius:[2,2,0,0],isAnimationActive:!1})]})})}),U?t.jsxs(t.Fragment,{children:[t.jsx("div",{"aria-hidden":!0,className:"pointer-events-none absolute inset-y-0 left-0 bg-[var(--otari-bg)] opacity-70",style:{width:`${I}%`}}),t.jsx("div",{"aria-hidden":!0,className:"pointer-events-none absolute inset-y-0 right-0 bg-[var(--otari-bg)] opacity-70",style:{width:`${100-F}%`}})]}):null,t.jsx("div",{role:"slider","aria-label":"Pan the selected window","aria-valuemin":0,"aria-valuemax":Y,"aria-valuenow":O,"aria-valuetext":`Window starting at ${$(T[Math.min(O,r-1)]??T[0],l)}`,"aria-disabled":!U,tabIndex:0,className:"absolute bottom-0 z-[1] cursor-grab touch-none rounded bg-[var(--otari-brand)]/10 outline-none hover:bg-[var(--otari-brand)]/20 focus-visible:ring-2 focus-visible:ring-[var(--otari-brand)] active:cursor-grabbing",style:{left:`${I}%`,width:`${Math.max(0,F-I)}%`,height:je},onKeyDown:se,onPointerDown:e=>{e.stopPropagation(),e.preventDefault(),S.current=!0,v.current={x:e.clientX,sel:[Math.min(g,p),Math.max(g,p)]},e.currentTarget.setPointerCapture(e.pointerId)},onPointerMove:re,onPointerUp:e=>{e.currentTarget.releasePointerCapture(e.pointerId),v.current=null,k(D.current)},onPointerCancel:e=>{e.currentTarget.hasPointerCapture(e.pointerId)&&e.currentTarget.releasePointerCapture(e.pointerId),v.current=null,k(D.current)}}),t.jsx("div",{className:"pointer-events-none absolute inset-0 z-[2]",onKeyDownCapture:ne,children:t.jsx(le,{"aria-label":"Selected time range",minValue:0,maxValue:r,step:1/we,value:C,onChange:e=>{S.current=!0,Array.isArray(e)&&e.length===2&&j([e[0],e[1]])},onChangeEnd:e=>{Array.isArray(e)&&e.length===2&&k([e[0],e[1]])},className:"pointer-events-none h-full w-full",children:t.jsxs(ce,{className:"pointer-events-none relative h-full w-full",children:[t.jsx(K,{index:0}),t.jsx(K,{index:1})]})})})]})]})]})}function _e({chips:n,children:a,onClearAll:s}){const[c,h]=w.useState(!1),u=w.useId();return t.jsxs("div",{className:"flex flex-col gap-2",children:[t.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[t.jsx(N,{size:"sm",variant:"outline",onPress:()=>h(l=>!l),"aria-expanded":c,"aria-controls":u,children:c?"Done":"Add filter"}),n.map(l=>t.jsxs("span",{className:"inline-flex items-center gap-1 rounded-full border border-[var(--otari-line)] bg-[var(--otari-brand-tint)] py-0.5 pl-2.5 pr-1 text-xs text-[var(--otari-brand-dark)]",children:[t.jsxs("span",{className:"text-[var(--otari-muted)]",children:[l.label,":"]}),t.jsx("span",{className:"font-medium",children:l.value}),t.jsx("button",{type:"button",onClick:l.onClear,"aria-label":`Remove ${l.label} filter`,className:"ml-0.5 inline-flex h-4 w-4 items-center justify-center rounded-full text-[var(--otari-muted)] outline-none hover:bg-[var(--otari-line)] hover:text-[var(--otari-ink)] focus-visible:ring-2 focus-visible:ring-[var(--otari-brand)]",children:t.jsx("svg",{viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2.5",className:"h-3 w-3","aria-hidden":"true",children:t.jsx("path",{d:"M6 6l12 12M18 6L6 18",strokeLinecap:"round"})})})]},l.key)),n.length>0&&s?t.jsx(N,{size:"sm",variant:"ghost",onPress:s,children:"Clear all"}):null]}),t.jsx("div",{id:u,className:c?"flex flex-wrap items-end gap-3":"hidden",children:a})]})}export{Re as A,Ee as C,_e as F,Pe as U,ge as Y,Le as a,$e as b,Ce as c,Ae as d,Ie as f,Ue as i}; diff --git a/src/gateway/static/dashboard/assets/KeysPage-Dnb7jGCb.js b/src/gateway/static/dashboard/assets/KeysPage-D4g9XrFY.js similarity index 96% rename from src/gateway/static/dashboard/assets/KeysPage-Dnb7jGCb.js rename to src/gateway/static/dashboard/assets/KeysPage-D4g9XrFY.js index d244ef3e..ddf0a285 100644 --- a/src/gateway/static/dashboard/assets/KeysPage-Dnb7jGCb.js +++ b/src/gateway/static/dashboard/assets/KeysPage-D4g9XrFY.js @@ -1,4 +1,4 @@ -import{j as e}from"./tanstack-query-1t81HyiD.js";import{r as i}from"./react-dgEcD0HR.js";import{a as J,s as U,t as Q,v as X,P as Z,E as O,q as ee,w as te,u as q,I as se}from"./index-D4f8RVEq.js";import{u as ae,r as ne,B as re}from"./tableSelection-9hV37uhu.js";import{C as ie}from"./ConfirmDialog-a8LQxZuS.js";import{D as le}from"./DataTable-Bmn_eYSV.js";import{F as A}from"./Field-Dwp6u3t8.js";import{a as F,M as V}from"./ModelScopeControl-CVWeyWke.js";import{U as oe}from"./UserComboBox-a9wxf8eF.js";import{f as P,B as f,d as D}from"./heroui-BI50yK5B.js";function $(t){if(!t)return"—";const a=new Date(t);return Number.isNaN(a.getTime())?"—":a.toLocaleDateString()}function ce(t){if(!t)return null;const a=new Date(t).getTime();if(Number.isNaN(a))return null;const n=Math.round((a-Date.now())/1e3),r=Math.abs(n),d=[["day",86400],["hour",3600],["minute",60]],o=new Intl.RelativeTimeFormat(void 0,{numeric:"auto"});for(const[l,x]of d)if(r>=x)return o.format(Math.round(n/x),l);return o.format(n,"second")}function de(t){if(!t.expires_at)return!1;const a=new Date(t.expires_at).getTime();return!Number.isNaN(a)&&aString(r).padStart(2,"0");return`${a.getFullYear()}-${n(a.getMonth()+1)}-${n(a.getDate())}T${n(a.getHours())}:${n(a.getMinutes())}`}const me=t=>(t??"").startsWith("apikey-"),M=t=>t.key_name??t.id,xe=t=>t.id;function K({label:t,value:a,multiline:n=!1,fieldRef:r}){const d=i.useRef(null),o=r??d,[l,x]=i.useState(!1),[g,p]=i.useState(!1),c=async()=>{var m,y,h;(m=o.current)==null||m.focus(),(y=o.current)==null||y.select();try{if((h=navigator.clipboard)!=null&&h.writeText){await navigator.clipboard.writeText(a),x(!0),p(!1),window.setTimeout(()=>x(!1),2e3);return}}catch{}p(!0)},u="w-full rounded-lg border border-[var(--otari-line)] bg-[var(--otari-bg)] px-3 py-2 font-mono text-xs text-[var(--otari-ink)]";return e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{className:"text-xs font-medium text-[var(--otari-muted)]",children:t}),e.jsx(f,{size:"sm",variant:"outline",onPress:c,children:l?"Copied":"Copy"})]}),n?e.jsx("textarea",{ref:o,readOnly:!0,rows:a.split(` +import{j as e}from"./tanstack-query-1t81HyiD.js";import{r as i}from"./react-dgEcD0HR.js";import{a as J,y as U,z as Q,B as X,P as Z,E as O,w as ee,D as te,u as V,I as se}from"./index-Bi2hajrg.js";import{u as ae,r as ne,B as re}from"./tableSelection-9hV37uhu.js";import{C as ie}from"./ConfirmDialog-ChuHp-Qm.js";import{D as le}from"./DataTable-Bmn_eYSV.js";import{F as A}from"./Field-Dwp6u3t8.js";import{a as F,M as q}from"./ModelScopeControl-DNcVzk1f.js";import{U as oe}from"./UserComboBox-a9wxf8eF.js";import{f as P,B as f,d as D}from"./heroui-BI50yK5B.js";function $(t){if(!t)return"—";const a=new Date(t);return Number.isNaN(a.getTime())?"—":a.toLocaleDateString()}function ce(t){if(!t)return null;const a=new Date(t).getTime();if(Number.isNaN(a))return null;const n=Math.round((a-Date.now())/1e3),r=Math.abs(n),d=[["day",86400],["hour",3600],["minute",60]],o=new Intl.RelativeTimeFormat(void 0,{numeric:"auto"});for(const[l,x]of d)if(r>=x)return o.format(Math.round(n/x),l);return o.format(n,"second")}function de(t){if(!t.expires_at)return!1;const a=new Date(t.expires_at).getTime();return!Number.isNaN(a)&&aString(r).padStart(2,"0");return`${a.getFullYear()}-${n(a.getMonth()+1)}-${n(a.getDate())}T${n(a.getHours())}:${n(a.getMinutes())}`}const me=t=>(t??"").startsWith("apikey-"),M=t=>t.key_name??t.id,xe=t=>t.id;function K({label:t,value:a,multiline:n=!1,fieldRef:r}){const d=i.useRef(null),o=r??d,[l,x]=i.useState(!1),[g,p]=i.useState(!1),c=async()=>{var m,y,h;(m=o.current)==null||m.focus(),(y=o.current)==null||y.select();try{if((h=navigator.clipboard)!=null&&h.writeText){await navigator.clipboard.writeText(a),x(!0),p(!1),window.setTimeout(()=>x(!1),2e3);return}}catch{}p(!0)},u="w-full rounded-lg border border-[var(--otari-line)] bg-[var(--otari-bg)] px-3 py-2 font-mono text-xs text-[var(--otari-ink)]";return e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{className:"text-xs font-medium text-[var(--otari-muted)]",children:t}),e.jsx(f,{size:"sm",variant:"outline",onPress:c,children:l?"Copied":"Copy"})]}),n?e.jsx("textarea",{ref:o,readOnly:!0,rows:a.split(` `).length,value:a,onFocus:m=>m.currentTarget.select(),className:`${u} resize-none whitespace-pre`}):e.jsx("input",{ref:o,readOnly:!0,value:a,onFocus:m=>m.currentTarget.select(),className:u}),e.jsx("span",{"aria-live":"polite",className:"text-xs text-green-700",children:l?"Copied to clipboard.":""}),g?e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"Selected. Press Ctrl/Cmd-C to copy."}):null]})}function he({title:t,result:a,onClose:n}){const r=i.useRef(null),d=i.useRef(null),o=typeof window<"u"?window.location.origin:"",l=a.key;i.useEffect(()=>{var c,u;(c=d.current)==null||c.focus(),(u=d.current)==null||u.select()},[]);const x=c=>{var h;if(c.key!=="Tab")return;const u=(h=r.current)==null?void 0:h.querySelectorAll('button, input, textarea, a[href], [tabindex]:not([tabindex="-1"])');if(!u||u.length===0)return;const m=u[0],y=u[u.length-1];c.shiftKey&&document.activeElement===m?(c.preventDefault(),y.focus()):!c.shiftKey&&document.activeElement===y&&(c.preventDefault(),m.focus())},g=[`curl ${o}/v1/chat/completions \\`,` -H "Otari-Key: ${l}" \\`,' -H "Content-Type: application/json" \\',` -d '{"model": "your-model", "messages": [{"role": "user", "content": "Hello"}]}'`].join(` `),p=["from openai import OpenAI","",`client = OpenAI(base_url="${o}/v1", api_key="${l}")`,"resp = client.chat.completions.create(",' model="your-model",',' messages=[{"role": "user", "content": "Hello"}],',")","print(resp.choices[0].message.content)"].join(` -`);return e.jsx("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4",role:"presentation",children:e.jsxs("div",{ref:r,role:"dialog","aria-modal":"true","aria-labelledby":"reveal-title",onKeyDown:x,className:"flex max-h-[90vh] w-full max-w-2xl flex-col gap-4 overflow-y-auto rounded-xl bg-[var(--otari-surface)] p-6 shadow-xl",children:[e.jsx("h2",{id:"reveal-title",className:"text-lg font-semibold text-[var(--otari-ink)]",children:t}),e.jsx(se,{tone:"warning",children:"Copy this key now. For security it is shown only once and cannot be retrieved later. If you lose it, use Regenerate to issue a new secret."}),e.jsxs("p",{className:"text-xs text-[var(--otari-muted)]",children:["Model access: ",F(a.allowed_models).text,"."]}),e.jsx(K,{label:"Secret key",value:l,fieldRef:d}),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-medium text-[var(--otari-ink)]",children:"Make your first call"}),e.jsxs("p",{className:"text-xs text-[var(--otari-muted)]",children:["Replace ",e.jsx("code",{children:"your-model"})," with a model from the Models page."]})]}),e.jsx(K,{label:"curl",value:g,multiline:!0}),e.jsx(K,{label:"Python (OpenAI SDK)",value:p,multiline:!0})]}),e.jsx("div",{className:"flex justify-end",children:e.jsx(f,{variant:"primary",onPress:n,children:"I’ve saved this key"})})]})})}function H({trigger:t,message:a,confirmLabel:n,isPending:r,onConfirm:d}){const[o,l]=i.useState(!1);return o?e.jsxs("div",{className:"flex flex-col items-end gap-1.5 rounded-lg border border-amber-200 bg-amber-50 p-2 text-right",children:[e.jsx("span",{className:"max-w-xs text-xs text-amber-800",children:a}),e.jsxs("span",{className:"inline-flex gap-1",children:[e.jsx(f,{size:"sm",variant:"danger",isDisabled:r,onPress:d,children:n}),e.jsx(f,{size:"sm",variant:"ghost",isDisabled:r,onPress:()=>l(!1),children:"Cancel"})]})]}):e.jsx(f,{size:"sm",variant:"danger-soft",onPress:()=>l(!0),children:t})}function W({userId:t,users:a}){const n=t.trim();if(n==="")return e.jsx("p",{className:"text-xs text-[var(--otari-muted)]",children:"Choose an owner above to see the models this key can inherit."});const r=a.find(l=>l.user_id===n);if(!r)return e.jsxs("p",{className:"text-xs text-[var(--otari-muted)]",children:["New user ",e.jsx("code",{children:n})," starts unrestricted, so this key may allow any model."]});const{text:d}=F(r.allowed_models),o=r.allowed_models&&r.allowed_models.length>0?r.allowed_models.join(", "):null;return e.jsxs("p",{className:"text-xs text-[var(--otari-muted)]",children:["Owner ",e.jsx("code",{children:n})," allows ",e.jsx("span",{className:"font-medium text-[var(--otari-ink)]",children:d.toLowerCase()}),o?e.jsxs(e.Fragment,{children:[" (",e.jsx("span",{className:"font-mono",children:o}),")"]}):null,". This key inherits that, or narrows within it."]})}function Y({checked:t,onChange:a}){return e.jsxs("label",{className:"flex items-start gap-2 rounded-lg border border-[var(--otari-line)] p-3 text-sm",children:[e.jsx("input",{type:"checkbox",checked:t,onChange:n=>a(n.target.checked),className:"mt-0.5 h-4 w-4 accent-[var(--otari-brand)]","aria-label":"Exempt this key from budget"}),e.jsxs("span",{className:"flex flex-col gap-0.5",children:[e.jsx("span",{className:"font-medium text-[var(--otari-ink)]",children:"Exempt from budget"}),e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"Requests on this key are logged with their cost but never counted toward the owner's budget or spend, and never blocked by it."})]})]})}function fe({onClose:t,onCreated:a}){const n=te(),r=q(),[d,o]=i.useState(""),[l,x]=i.useState(""),[g,p]=i.useState(!1),[c,u]=i.useState(""),[m,y]=i.useState(null),[h,N]=i.useState(!1),[v,I]=i.useState(!0),C=l!==""&&new Date(l).getTime(){if(n.isPending||!v||w)return;const b={key_name:d.trim()||null,user_id:c.trim(),expires_at:l?new Date(l).toISOString():null,allowed_models:m,exclude_from_budget:h};n.mutate(b,{onSuccess:j=>{a(j),t()}})};return e.jsx(D,{children:e.jsxs(D.Content,{className:"flex flex-col gap-4 p-5",children:[e.jsx("div",{className:"text-sm font-semibold text-[var(--otari-ink)]",children:"Create API key"}),e.jsx(O,{error:n.error}),e.jsxs("div",{className:"grid gap-4 sm:grid-cols-2",children:[e.jsx(A,{label:"Name",value:d,onChange:o,placeholder:"ci-bot",autoFocus:!0,description:"A label to recognize this key later."}),e.jsx(A,{label:"Expires (optional)",value:l,onChange:x,type:"datetime-local",description:C?e.jsx("span",{className:"text-red-700",children:"That time is in the past; the key would be rejected immediately."}):"Leave blank for a key that never expires."})]}),e.jsx(oe,{value:c,onChange:u,users:r.data??[]}),e.jsx("button",{type:"button",className:"self-start text-xs font-medium text-[var(--otari-brand-dark)]",onClick:()=>p(b=>!b),children:g?"Hide advanced":"Advanced"}),g?e.jsxs("div",{className:"flex flex-col gap-4 rounded-lg border border-[var(--otari-line)] p-4",children:[e.jsx(W,{userId:c,users:r.data??[]}),e.jsx(V,{title:"Restrict this key's models",description:"By default this key inherits its owner's access. Optionally narrow it to a subset; a key can never exceed its owner's allowed models.",anyLabel:"Inherit owner access",initial:null,onChange:(b,j)=>{y(b),I(j)}}),e.jsx(Y,{checked:h,onChange:N})]}):null,e.jsxs("div",{className:"flex gap-2",children:[e.jsx(f,{variant:"primary",isDisabled:n.isPending||!v||w,onPress:S,children:n.isPending?"Creating…":"Create key"}),e.jsx(f,{variant:"ghost",onPress:t,children:"Cancel"})]})]})})}function ge({apiKey:t,onClose:a}){const n=U(),r=q(),[d,o]=i.useState(t.key_name??""),[l,x]=i.useState(ue(t.expires_at)),[g,p]=i.useState(t.allowed_models),[c,u]=i.useState(t.exclude_from_budget),[m,y]=i.useState(!0),h=()=>{n.isPending||!m||n.mutate({id:t.id,body:{key_name:d.trim()||null,expires_at:l?new Date(l).toISOString():null,allowed_models:g,exclude_from_budget:c}},{onSuccess:a})};return e.jsx(D,{children:e.jsxs(D.Content,{className:"flex flex-col gap-4 p-5",children:[e.jsxs("div",{className:"text-sm font-semibold text-[var(--otari-ink)]",children:["Edit ",e.jsx("code",{children:t.key_name??t.id})]}),e.jsx(O,{error:n.error}),e.jsxs("div",{className:"grid gap-4 sm:grid-cols-2",children:[e.jsx(A,{label:"Name",value:d,onChange:o,placeholder:"ci-bot"}),e.jsx(A,{label:"Expires",value:l,onChange:x,type:"datetime-local",description:"Blank clears the expiry."})]}),t.user_id?e.jsx(W,{userId:t.user_id,users:r.data??[]}):null,e.jsx(V,{title:"Restrict this key's models",description:"This key inherits its owner's access by default. Narrow it to a subset here; it can never exceed the owner's allowed models.",anyLabel:"Inherit owner access",initial:t.allowed_models,onChange:(N,v)=>{p(N),y(v)}}),e.jsx(Y,{checked:c,onChange:u}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(f,{variant:"primary",isDisabled:n.isPending||!m,onPress:h,children:n.isPending?"Saving…":"Save changes"}),e.jsx(f,{variant:"ghost",onPress:a,children:"Cancel"})]})]})})}function pe({apiKey:t}){return t.is_active?de(t)?e.jsx(P,{size:"sm",color:"warning",children:"Expired"}):e.jsx(P,{size:"sm",color:"accent",children:"Active"}):e.jsx(P,{size:"sm",color:"default",children:"Disabled"})}function ye({allowed:t}){const{text:a,tone:n}=F(t),r=n==="danger"?"text-red-700 font-medium":n==="muted"?"text-[var(--otari-muted)]":"text-[var(--otari-brand-dark)] font-medium",d=t&&t.length>0?t.join(", "):void 0;return e.jsx("span",{className:`text-xs ${r}`,title:d,children:a})}function Ae(){const t=J(),a=U(),n=Q(),r=X(),[d,o]=i.useState(!1),[l,x]=i.useState(null),[g,p]=i.useState(null),c=t.data??[],u=t.isLoading,m=c.find(s=>s.id===l)??null,y=!u&&c.length===0&&!d,h=ae(),[N,v]=i.useState(!1),[I,C]=i.useState(void 0),[w,S]=i.useState(!1),b=c.map(s=>s.id),j=ne(h.selectedKeys,b),E=c.filter(s=>j.includes(s.id)),z=i.useCallback((s,k)=>a.mutate({id:s.id,body:{is_active:k}}),[a.mutate]),L=i.useCallback(s=>n.mutate(s.id,{onSuccess:k=>p({title:`New secret for ${M(s)}`,result:k})}),[n.mutate]),R=async(s,k,T)=>{S(!0),C(void 0);try{for(const B of s)await k(B);h.clear(),T==null||T()}catch(B){C(B)}finally{S(!1)}},G=i.useMemo(()=>[{id:"name",header:"Name",isRowHeader:!0,cell:s=>e.jsxs("div",{className:"flex flex-col gap-0.5",children:[e.jsx("span",{className:"font-medium text-[var(--otari-ink)]",children:s.key_name??e.jsx("span",{className:"text-[var(--otari-muted)]",children:"(unnamed)"})}),e.jsxs("div",{className:"flex flex-wrap items-center gap-1",children:[e.jsx(ye,{allowed:s.allowed_models}),s.exclude_from_budget?e.jsx("span",{className:"inline-flex items-center rounded-full border border-[var(--otari-line)] bg-[var(--otari-brand-tint)] px-2 py-0.5 text-xs font-medium text-[var(--otari-brand-dark)]",title:"Requests on this key are logged with cost but never counted toward budget",children:"Budget-exempt"}):null]})]})},{id:"status",header:"Status",cell:s=>e.jsx(pe,{apiKey:s})},{id:"owner",header:"Owner",cell:s=>me(s.user_id)?e.jsx(P,{size:"sm",color:"default",children:"virtual"}):e.jsx("code",{className:"text-xs text-[var(--otari-muted)]",children:s.user_id??"—"})},{id:"key",header:"Key",cell:s=>e.jsx("code",{className:"text-xs text-[var(--otari-muted)]",children:s.key_prefix?`${s.key_prefix}…`:"—"})},{id:"created",header:"Created",cell:s=>e.jsx("span",{className:"text-[var(--otari-muted)]",children:$(s.created_at)})},{id:"last_used",header:"Last used",cell:s=>e.jsx("span",{className:"text-[var(--otari-muted)]",children:ce(s.last_used_at)??"never"})},{id:"expires",header:"Expires",cell:s=>e.jsx("span",{className:"text-[var(--otari-muted)]",title:s.expires_at?new Date(s.expires_at).toLocaleString():void 0,children:s.expires_at?$(s.expires_at):"never"})},{id:"actions",header:"Actions",align:"end",cell:s=>e.jsxs("div",{className:"flex items-center justify-end gap-1.5",children:[e.jsx(f,{size:"sm",variant:"outline",isDisabled:a.isPending,onPress:()=>z(s,!s.is_active),children:s.is_active?"Disable":"Enable"}),e.jsx(f,{size:"sm",variant:"ghost",onPress:()=>{o(!1),x(s.id)},children:"Edit"}),e.jsx(H,{trigger:"Regenerate",confirmLabel:"Regenerate",isPending:n.isPending,message:e.jsxs(e.Fragment,{children:["Regenerate the secret for ",e.jsx("strong",{children:M(s)}),"? The current secret stops working immediately, with no grace period."]}),onConfirm:()=>L(s)}),s.is_active?null:e.jsx(H,{trigger:"Delete",confirmLabel:"Delete permanently",isPending:r.isPending,message:e.jsxs(e.Fragment,{children:["Permanently delete ",e.jsx("strong",{children:M(s)}),"? This removes the key and unlinks its usage history. Cannot be undone."]}),onConfirm:()=>r.mutate(s.id)})]})}],[a.isPending,n.isPending,r.isPending,r.mutate,z,L]),_=E.filter(s=>!s.is_active);return e.jsxs("div",{className:"flex flex-col gap-6",children:[e.jsx(Z,{title:"API keys",description:"Issue and revoke the keys that authenticate callers to this gateway. Secrets are shown once at creation.",action:d?null:e.jsx(f,{variant:"primary",onPress:()=>{x(null),o(!0)},children:"Create key"})}),e.jsx(O,{error:t.error??a.error??n.error??r.error}),y?e.jsx(ee,{title:"No API keys yet",description:"An API key authenticates callers to this gateway. Create one to make your first request; the secret is shown once, so keep it somewhere safe.",actionLabel:"Create your first key",onAction:()=>{x(null),o(!0)}}):null,d?e.jsx(fe,{onClose:()=>o(!1),onCreated:s=>p({title:"API key created",result:s})}):null,m?e.jsx(ge,{apiKey:m,onClose:()=>x(null)},m.id):null,j.length>0?e.jsxs(re,{selectedCount:j.length,allMatching:!1,matchingTotal:null,canSelectAllMatching:!1,onSelectAllMatching:()=>{},onClear:h.clear,children:[e.jsx(f,{size:"sm",variant:"outline",isDisabled:w,onPress:()=>void R(E,s=>a.mutateAsync({id:s.id,body:{is_active:!1}})),children:"Disable"}),e.jsx(f,{size:"sm",variant:"outline",isDisabled:w,onPress:()=>void R(E,s=>a.mutateAsync({id:s.id,body:{exclude_from_budget:!0}})),children:"Budget-exempt"}),e.jsx(f,{size:"sm",variant:"danger",isDisabled:_.length===0,onPress:()=>v(!0),children:"Delete"})]}):null,y?null:e.jsx(le,{ariaLabel:"API keys",columns:G,rows:c,getRowKey:xe,isLoading:u,emptyContent:"No API keys yet. Create one to authenticate a caller.",selectionMode:"multiple",selectedKeys:h.selectedKeys,onSelectionChange:h.onSelectionChange}),e.jsx(ie,{isOpen:N,onOpenChange:v,heading:"Delete API keys",body:`Permanently delete ${_.length} disabled ${_.length===1?"key":"keys"}? This removes them and unlinks their usage history. Cannot be undone. Active keys in the selection are skipped; disable them first.`,confirmLabel:"Delete permanently",isPending:w,error:I,onConfirm:()=>void R(_,s=>r.mutateAsync(s.id),()=>v(!1))}),g?e.jsx(he,{title:g.title,result:g.result,onClose:()=>{p(null),n.reset()}}):null]})}export{Ae as KeysPage}; +`);return e.jsx("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4",role:"presentation",children:e.jsxs("div",{ref:r,role:"dialog","aria-modal":"true","aria-labelledby":"reveal-title",onKeyDown:x,className:"flex max-h-[90vh] w-full max-w-2xl flex-col gap-4 overflow-y-auto rounded-xl bg-[var(--otari-surface)] p-6 shadow-xl",children:[e.jsx("h2",{id:"reveal-title",className:"text-lg font-semibold text-[var(--otari-ink)]",children:t}),e.jsx(se,{tone:"warning",children:"Copy this key now. For security it is shown only once and cannot be retrieved later. If you lose it, use Regenerate to issue a new secret."}),e.jsxs("p",{className:"text-xs text-[var(--otari-muted)]",children:["Model access: ",F(a.allowed_models).text,"."]}),e.jsx(K,{label:"Secret key",value:l,fieldRef:d}),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-medium text-[var(--otari-ink)]",children:"Make your first call"}),e.jsxs("p",{className:"text-xs text-[var(--otari-muted)]",children:["Replace ",e.jsx("code",{children:"your-model"})," with a model from the Models page."]})]}),e.jsx(K,{label:"curl",value:g,multiline:!0}),e.jsx(K,{label:"Python (OpenAI SDK)",value:p,multiline:!0})]}),e.jsx("div",{className:"flex justify-end",children:e.jsx(f,{variant:"primary",onPress:n,children:"I’ve saved this key"})})]})})}function H({trigger:t,message:a,confirmLabel:n,isPending:r,onConfirm:d}){const[o,l]=i.useState(!1);return o?e.jsxs("div",{className:"flex flex-col items-end gap-1.5 rounded-lg border border-amber-200 bg-amber-50 p-2 text-right",children:[e.jsx("span",{className:"max-w-xs text-xs text-amber-800",children:a}),e.jsxs("span",{className:"inline-flex gap-1",children:[e.jsx(f,{size:"sm",variant:"danger",isDisabled:r,onPress:d,children:n}),e.jsx(f,{size:"sm",variant:"ghost",isDisabled:r,onPress:()=>l(!1),children:"Cancel"})]})]}):e.jsx(f,{size:"sm",variant:"danger-soft",onPress:()=>l(!0),children:t})}function W({userId:t,users:a}){const n=t.trim();if(n==="")return e.jsx("p",{className:"text-xs text-[var(--otari-muted)]",children:"Choose an owner above to see the models this key can inherit."});const r=a.find(l=>l.user_id===n);if(!r)return e.jsxs("p",{className:"text-xs text-[var(--otari-muted)]",children:["New user ",e.jsx("code",{children:n})," starts unrestricted, so this key may allow any model."]});const{text:d}=F(r.allowed_models),o=r.allowed_models&&r.allowed_models.length>0?r.allowed_models.join(", "):null;return e.jsxs("p",{className:"text-xs text-[var(--otari-muted)]",children:["Owner ",e.jsx("code",{children:n})," allows ",e.jsx("span",{className:"font-medium text-[var(--otari-ink)]",children:d.toLowerCase()}),o?e.jsxs(e.Fragment,{children:[" (",e.jsx("span",{className:"font-mono",children:o}),")"]}):null,". This key inherits that, or narrows within it."]})}function Y({checked:t,onChange:a}){return e.jsxs("label",{className:"flex items-start gap-2 rounded-lg border border-[var(--otari-line)] p-3 text-sm",children:[e.jsx("input",{type:"checkbox",checked:t,onChange:n=>a(n.target.checked),className:"mt-0.5 h-4 w-4 accent-[var(--otari-brand)]","aria-label":"Exempt this key from budget"}),e.jsxs("span",{className:"flex flex-col gap-0.5",children:[e.jsx("span",{className:"font-medium text-[var(--otari-ink)]",children:"Exempt from budget"}),e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"Requests on this key are logged with their cost but never counted toward the owner's budget or spend, and never blocked by it."})]})]})}function fe({onClose:t,onCreated:a}){const n=te(),r=V(),[d,o]=i.useState(""),[l,x]=i.useState(""),[g,p]=i.useState(!1),[c,u]=i.useState(""),[m,y]=i.useState(null),[h,N]=i.useState(!1),[v,I]=i.useState(!0),C=l!==""&&new Date(l).getTime(){if(n.isPending||!v||w)return;const b={key_name:d.trim()||null,user_id:c.trim(),expires_at:l?new Date(l).toISOString():null,allowed_models:m,exclude_from_budget:h};n.mutate(b,{onSuccess:j=>{a(j),t()}})};return e.jsx(D,{children:e.jsxs(D.Content,{className:"flex flex-col gap-4 p-5",children:[e.jsx("div",{className:"text-sm font-semibold text-[var(--otari-ink)]",children:"Create API key"}),e.jsx(O,{error:n.error}),e.jsxs("div",{className:"grid gap-4 sm:grid-cols-2",children:[e.jsx(A,{label:"Name",value:d,onChange:o,placeholder:"ci-bot",autoFocus:!0,description:"A label to recognize this key later."}),e.jsx(A,{label:"Expires (optional)",value:l,onChange:x,type:"datetime-local",description:C?e.jsx("span",{className:"text-red-700",children:"That time is in the past; the key would be rejected immediately."}):"Leave blank for a key that never expires."})]}),e.jsx(oe,{value:c,onChange:u,users:r.data??[]}),e.jsx("button",{type:"button",className:"self-start text-xs font-medium text-[var(--otari-brand-dark)]",onClick:()=>p(b=>!b),children:g?"Hide advanced":"Advanced"}),g?e.jsxs("div",{className:"flex flex-col gap-4 rounded-lg border border-[var(--otari-line)] p-4",children:[e.jsx(W,{userId:c,users:r.data??[]}),e.jsx(q,{title:"Restrict this key's models",description:"By default this key inherits its owner's access. Optionally narrow it to a subset; a key can never exceed its owner's allowed models.",anyLabel:"Inherit owner access",initial:null,onChange:(b,j)=>{y(b),I(j)}}),e.jsx(Y,{checked:h,onChange:N})]}):null,e.jsxs("div",{className:"flex gap-2",children:[e.jsx(f,{variant:"primary",isDisabled:n.isPending||!v||w,onPress:S,children:n.isPending?"Creating…":"Create key"}),e.jsx(f,{variant:"ghost",onPress:t,children:"Cancel"})]})]})})}function ge({apiKey:t,onClose:a}){const n=U(),r=V(),[d,o]=i.useState(t.key_name??""),[l,x]=i.useState(ue(t.expires_at)),[g,p]=i.useState(t.allowed_models),[c,u]=i.useState(t.exclude_from_budget),[m,y]=i.useState(!0),h=()=>{n.isPending||!m||n.mutate({id:t.id,body:{key_name:d.trim()||null,expires_at:l?new Date(l).toISOString():null,allowed_models:g,exclude_from_budget:c}},{onSuccess:a})};return e.jsx(D,{children:e.jsxs(D.Content,{className:"flex flex-col gap-4 p-5",children:[e.jsxs("div",{className:"text-sm font-semibold text-[var(--otari-ink)]",children:["Edit ",e.jsx("code",{children:t.key_name??t.id})]}),e.jsx(O,{error:n.error}),e.jsxs("div",{className:"grid gap-4 sm:grid-cols-2",children:[e.jsx(A,{label:"Name",value:d,onChange:o,placeholder:"ci-bot"}),e.jsx(A,{label:"Expires",value:l,onChange:x,type:"datetime-local",description:"Blank clears the expiry."})]}),t.user_id?e.jsx(W,{userId:t.user_id,users:r.data??[]}):null,e.jsx(q,{title:"Restrict this key's models",description:"This key inherits its owner's access by default. Narrow it to a subset here; it can never exceed the owner's allowed models.",anyLabel:"Inherit owner access",initial:t.allowed_models,onChange:(N,v)=>{p(N),y(v)}}),e.jsx(Y,{checked:c,onChange:u}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(f,{variant:"primary",isDisabled:n.isPending||!m,onPress:h,children:n.isPending?"Saving…":"Save changes"}),e.jsx(f,{variant:"ghost",onPress:a,children:"Cancel"})]})]})})}function pe({apiKey:t}){return t.is_active?de(t)?e.jsx(P,{size:"sm",color:"warning",children:"Expired"}):e.jsx(P,{size:"sm",color:"accent",children:"Active"}):e.jsx(P,{size:"sm",color:"default",children:"Disabled"})}function ye({allowed:t}){const{text:a,tone:n}=F(t),r=n==="danger"?"text-red-700 font-medium":n==="muted"?"text-[var(--otari-muted)]":"text-[var(--otari-brand-dark)] font-medium",d=t&&t.length>0?t.join(", "):void 0;return e.jsx("span",{className:`text-xs ${r}`,title:d,children:a})}function Ae(){const t=J(),a=U(),n=Q(),r=X(),[d,o]=i.useState(!1),[l,x]=i.useState(null),[g,p]=i.useState(null),c=t.data??[],u=t.isLoading,m=c.find(s=>s.id===l)??null,y=!u&&c.length===0&&!d,h=ae(),[N,v]=i.useState(!1),[I,C]=i.useState(void 0),[w,S]=i.useState(!1),b=c.map(s=>s.id),j=ne(h.selectedKeys,b),E=c.filter(s=>j.includes(s.id)),z=i.useCallback((s,k)=>a.mutate({id:s.id,body:{is_active:k}}),[a.mutate]),L=i.useCallback(s=>n.mutate(s.id,{onSuccess:k=>p({title:`New secret for ${M(s)}`,result:k})}),[n.mutate]),R=async(s,k,T)=>{S(!0),C(void 0);try{for(const B of s)await k(B);h.clear(),T==null||T()}catch(B){C(B)}finally{S(!1)}},G=i.useMemo(()=>[{id:"name",header:"Name",isRowHeader:!0,cell:s=>e.jsxs("div",{className:"flex flex-col gap-0.5",children:[e.jsx("span",{className:"font-medium text-[var(--otari-ink)]",children:s.key_name??e.jsx("span",{className:"text-[var(--otari-muted)]",children:"(unnamed)"})}),e.jsxs("div",{className:"flex flex-wrap items-center gap-1",children:[e.jsx(ye,{allowed:s.allowed_models}),s.exclude_from_budget?e.jsx("span",{className:"inline-flex items-center rounded-full border border-[var(--otari-line)] bg-[var(--otari-brand-tint)] px-2 py-0.5 text-xs font-medium text-[var(--otari-brand-dark)]",title:"Requests on this key are logged with cost but never counted toward budget",children:"Budget-exempt"}):null]})]})},{id:"status",header:"Status",cell:s=>e.jsx(pe,{apiKey:s})},{id:"owner",header:"Owner",cell:s=>me(s.user_id)?e.jsx(P,{size:"sm",color:"default",children:"virtual"}):e.jsx("code",{className:"text-xs text-[var(--otari-muted)]",children:s.user_id??"—"})},{id:"key",header:"Key",cell:s=>e.jsx("code",{className:"text-xs text-[var(--otari-muted)]",children:s.key_prefix?`${s.key_prefix}…`:"—"})},{id:"created",header:"Created",cell:s=>e.jsx("span",{className:"text-[var(--otari-muted)]",children:$(s.created_at)})},{id:"last_used",header:"Last used",cell:s=>e.jsx("span",{className:"text-[var(--otari-muted)]",children:ce(s.last_used_at)??"never"})},{id:"expires",header:"Expires",cell:s=>e.jsx("span",{className:"text-[var(--otari-muted)]",title:s.expires_at?new Date(s.expires_at).toLocaleString():void 0,children:s.expires_at?$(s.expires_at):"never"})},{id:"actions",header:"Actions",align:"end",cell:s=>e.jsxs("div",{className:"flex items-center justify-end gap-1.5",children:[e.jsx(f,{size:"sm",variant:"outline",isDisabled:a.isPending,onPress:()=>z(s,!s.is_active),children:s.is_active?"Disable":"Enable"}),e.jsx(f,{size:"sm",variant:"ghost",onPress:()=>{o(!1),x(s.id)},children:"Edit"}),e.jsx(H,{trigger:"Regenerate",confirmLabel:"Regenerate",isPending:n.isPending,message:e.jsxs(e.Fragment,{children:["Regenerate the secret for ",e.jsx("strong",{children:M(s)}),"? The current secret stops working immediately, with no grace period."]}),onConfirm:()=>L(s)}),s.is_active?null:e.jsx(H,{trigger:"Delete",confirmLabel:"Delete permanently",isPending:r.isPending,message:e.jsxs(e.Fragment,{children:["Permanently delete ",e.jsx("strong",{children:M(s)}),"? This removes the key and unlinks its usage history. Cannot be undone."]}),onConfirm:()=>r.mutate(s.id)})]})}],[a.isPending,n.isPending,r.isPending,r.mutate,z,L]),_=E.filter(s=>!s.is_active);return e.jsxs("div",{className:"flex flex-col gap-6",children:[e.jsx(Z,{title:"API keys",description:"Issue and revoke the keys that authenticate callers to this gateway. Secrets are shown once at creation.",action:d?null:e.jsx(f,{variant:"primary",onPress:()=>{x(null),o(!0)},children:"Create key"})}),e.jsx(O,{error:t.error??a.error??n.error??r.error}),y?e.jsx(ee,{title:"No API keys yet",description:"An API key authenticates callers to this gateway. Create one to make your first request; the secret is shown once, so keep it somewhere safe.",actionLabel:"Create your first key",onAction:()=>{x(null),o(!0)}}):null,d?e.jsx(fe,{onClose:()=>o(!1),onCreated:s=>p({title:"API key created",result:s})}):null,m?e.jsx(ge,{apiKey:m,onClose:()=>x(null)},m.id):null,j.length>0?e.jsxs(re,{selectedCount:j.length,allMatching:!1,matchingTotal:null,canSelectAllMatching:!1,onSelectAllMatching:()=>{},onClear:h.clear,children:[e.jsx(f,{size:"sm",variant:"outline",isDisabled:w,onPress:()=>void R(E,s=>a.mutateAsync({id:s.id,body:{is_active:!1}})),children:"Disable"}),e.jsx(f,{size:"sm",variant:"outline",isDisabled:w,onPress:()=>void R(E,s=>a.mutateAsync({id:s.id,body:{exclude_from_budget:!0}})),children:"Budget-exempt"}),e.jsx(f,{size:"sm",variant:"danger",isDisabled:_.length===0,onPress:()=>v(!0),children:"Delete"})]}):null,y?null:e.jsx(le,{ariaLabel:"API keys",columns:G,rows:c,getRowKey:xe,isLoading:u,emptyContent:"No API keys yet. Create one to authenticate a caller.",selectionMode:"multiple",selectedKeys:h.selectedKeys,onSelectionChange:h.onSelectionChange}),e.jsx(ie,{isOpen:N,onOpenChange:v,heading:"Delete API keys",body:`Permanently delete ${_.length} disabled ${_.length===1?"key":"keys"}? This removes them and unlinks their usage history. Cannot be undone. Active keys in the selection are skipped; disable them first.`,confirmLabel:"Delete permanently",isPending:w,error:I,onConfirm:()=>void R(_,s=>r.mutateAsync(s.id),()=>v(!1))}),g?e.jsx(he,{title:g.title,result:g.result,onClose:()=>{p(null),n.reset()}}):null]})}export{Ae as KeysPage}; diff --git a/src/gateway/static/dashboard/assets/ModelScopeControl-CVWeyWke.js b/src/gateway/static/dashboard/assets/ModelScopeControl-DNcVzk1f.js similarity index 88% rename from src/gateway/static/dashboard/assets/ModelScopeControl-CVWeyWke.js rename to src/gateway/static/dashboard/assets/ModelScopeControl-DNcVzk1f.js index 5ec7858b..29a3fa63 100644 --- a/src/gateway/static/dashboard/assets/ModelScopeControl-CVWeyWke.js +++ b/src/gateway/static/dashboard/assets/ModelScopeControl-DNcVzk1f.js @@ -1 +1 @@ -import{j as t}from"./tanstack-query-1t81HyiD.js";import{r as n}from"./react-dgEcD0HR.js";import{L as A,h as $,i as P}from"./index-D4f8RVEq.js";import{C as d,I as R,a as T,b as V}from"./heroui-BI50yK5B.js";function q(r){return r===null?"any":r.length===0?"block":"only"}const O=50;function W({initial:r,onChange:m,title:N="Model access",description:w,anyLabel:C="Any model"}){const x=A(),u=$(),v=P(),[i,L]=n.useState(q(r)),[a,g]=n.useState(r??[]),[p,y]=n.useState(""),f=n.useMemo(()=>{var j,k;const e=new Set,s=[],l=(o,c)=>{o&&!e.has(o)&&(e.add(o),s.push({id:o,label:c}))};for(const o of((j=x.data)==null?void 0:j.providers)??[])l(`${o.instance}:*`,`${o.instance}:* · all ${o.instance} models`);for(const o of((k=u.data)==null?void 0:k.providers)??[])for(const c of o.models)l(c.key,c.key);for(const o of v.data??[])l(o.target,`${o.name} · alias`);return s},[x.data,u.data,v.data]),S=n.useMemo(()=>{const e=p.trim().toLowerCase();return f.filter(s=>!a.includes(s.id)).filter(s=>!e||s.id.toLowerCase().includes(e)||s.label.toLowerCase().includes(e)).slice(0,O)},[f,a,p]),h=(e,s)=>{e==="any"?m(null,!0):e==="block"?m([],!0):m(s,s.length>0)},B=e=>{L(e),h(e,a)},M=e=>{const s=a.includes(e)?a:[...a,e];g(s),y(""),h("only",s)},E=e=>{const s=a.filter(l=>l!==e);g(s),h("only",s)},b=(e,s)=>t.jsx("button",{type:"button","aria-pressed":i===e,onClick:()=>B(e),className:i===e?"rounded-md bg-white px-3 py-1.5 text-sm font-medium text-[var(--otari-ink)] shadow-sm":"rounded-md px-3 py-1.5 text-sm text-[var(--otari-muted)] hover:text-[var(--otari-ink)]",children:s}),I=!u.isLoading&&!x.isLoading&&f.length===0;return t.jsxs("div",{className:"flex flex-col gap-3",children:[t.jsxs("div",{children:[t.jsx("span",{className:"text-sm font-medium text-[var(--otari-ink)]",children:N}),t.jsx("p",{className:"text-xs text-[var(--otari-muted)]",children:w??"Which models this key may list and call. The master key is never restricted, so blocking a key cannot lock you out of the dashboard."})]}),t.jsxs("div",{className:"flex w-fit items-center gap-1 rounded-lg bg-[var(--otari-bg)] p-1",children:[b("any",C),b("only","Only selected"),b("block","Block all")]}),i==="block"?t.jsxs("div",{className:"rounded-lg border border-amber-200 bg-amber-50 px-3 py-2 text-xs text-amber-800",children:["Blocked from ",t.jsx("strong",{children:"every"})," model until you change this access."]}):null,i==="only"?t.jsxs("div",{className:"flex flex-col gap-2",children:[t.jsx("div",{className:"flex flex-wrap gap-1.5",children:a.length===0?t.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"Pick at least one model below, or choose “Block all”."}):a.map(e=>t.jsxs("span",{className:"inline-flex items-center gap-1 rounded-full bg-[var(--otari-brand-tint)] px-2.5 py-1 font-mono text-xs text-[var(--otari-brand-dark)]",children:[e,t.jsx("button",{type:"button","aria-label":`Remove ${e}`,onClick:()=>E(e),className:"text-[var(--otari-brand-dark)] hover:text-red-700",children:"×"})]},e))}),I?t.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"No providers or models discovered yet. Configure a provider first, then scope this key."}):t.jsxs(d.Root,{allowsEmptyCollection:!0,menuTrigger:"input",inputValue:p,onInputChange:y,selectedKey:null,onSelectionChange:e=>{e!=null&&M(String(e))},className:"flex max-w-md flex-col gap-1",children:[t.jsxs(d.InputGroup,{children:[t.jsx(R,{"aria-label":"Add a model",placeholder:"Search providers, models, aliases…",autoComplete:"off"}),t.jsx(d.Trigger,{})]}),t.jsx(d.Popover,{children:t.jsx(T,{items:S,className:"max-h-72 overflow-auto",children:e=>t.jsx(V,{id:e.id,textValue:e.label,children:e.label})})})]})]}):null]})}function X(r){return r===null?{text:"All models",tone:"muted"}:r.length===0?{text:"No models",tone:"danger"}:{text:"Selected models",tone:"normal"}}export{W as M,X as a}; +import{j as t}from"./tanstack-query-1t81HyiD.js";import{r as n}from"./react-dgEcD0HR.js";import{T as A,l as $,m as T}from"./index-Bi2hajrg.js";import{C as d,I as P,a as R,b as V}from"./heroui-BI50yK5B.js";function q(r){return r===null?"any":r.length===0?"block":"only"}const O=50;function W({initial:r,onChange:m,title:N="Model access",description:w,anyLabel:C="Any model"}){const x=A(),u=$(),v=T(),[i,S]=n.useState(q(r)),[a,g]=n.useState(r??[]),[p,y]=n.useState(""),f=n.useMemo(()=>{var j,k;const e=new Set,s=[],l=(o,c)=>{o&&!e.has(o)&&(e.add(o),s.push({id:o,label:c}))};for(const o of((j=x.data)==null?void 0:j.providers)??[])l(`${o.instance}:*`,`${o.instance}:* · all ${o.instance} models`);for(const o of((k=u.data)==null?void 0:k.providers)??[])for(const c of o.models)l(c.key,c.key);for(const o of v.data??[])l(o.target,`${o.name} · alias`);return s},[x.data,u.data,v.data]),L=n.useMemo(()=>{const e=p.trim().toLowerCase();return f.filter(s=>!a.includes(s.id)).filter(s=>!e||s.id.toLowerCase().includes(e)||s.label.toLowerCase().includes(e)).slice(0,O)},[f,a,p]),h=(e,s)=>{e==="any"?m(null,!0):e==="block"?m([],!0):m(s,s.length>0)},B=e=>{S(e),h(e,a)},M=e=>{const s=a.includes(e)?a:[...a,e];g(s),y(""),h("only",s)},E=e=>{const s=a.filter(l=>l!==e);g(s),h("only",s)},b=(e,s)=>t.jsx("button",{type:"button","aria-pressed":i===e,onClick:()=>B(e),className:i===e?"rounded-md bg-white px-3 py-1.5 text-sm font-medium text-[var(--otari-ink)] shadow-sm":"rounded-md px-3 py-1.5 text-sm text-[var(--otari-muted)] hover:text-[var(--otari-ink)]",children:s}),I=!u.isLoading&&!x.isLoading&&f.length===0;return t.jsxs("div",{className:"flex flex-col gap-3",children:[t.jsxs("div",{children:[t.jsx("span",{className:"text-sm font-medium text-[var(--otari-ink)]",children:N}),t.jsx("p",{className:"text-xs text-[var(--otari-muted)]",children:w??"Which models this key may list and call. The master key is never restricted, so blocking a key cannot lock you out of the dashboard."})]}),t.jsxs("div",{className:"flex w-fit items-center gap-1 rounded-lg bg-[var(--otari-bg)] p-1",children:[b("any",C),b("only","Only selected"),b("block","Block all")]}),i==="block"?t.jsxs("div",{className:"rounded-lg border border-amber-200 bg-amber-50 px-3 py-2 text-xs text-amber-800",children:["Blocked from ",t.jsx("strong",{children:"every"})," model until you change this access."]}):null,i==="only"?t.jsxs("div",{className:"flex flex-col gap-2",children:[t.jsx("div",{className:"flex flex-wrap gap-1.5",children:a.length===0?t.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"Pick at least one model below, or choose “Block all”."}):a.map(e=>t.jsxs("span",{className:"inline-flex items-center gap-1 rounded-full bg-[var(--otari-brand-tint)] px-2.5 py-1 font-mono text-xs text-[var(--otari-brand-dark)]",children:[e,t.jsx("button",{type:"button","aria-label":`Remove ${e}`,onClick:()=>E(e),className:"text-[var(--otari-brand-dark)] hover:text-red-700",children:"×"})]},e))}),I?t.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"No providers or models discovered yet. Configure a provider first, then scope this key."}):t.jsxs(d.Root,{allowsEmptyCollection:!0,menuTrigger:"input",inputValue:p,onInputChange:y,selectedKey:null,onSelectionChange:e=>{e!=null&&M(String(e))},className:"flex max-w-md flex-col gap-1",children:[t.jsxs(d.InputGroup,{children:[t.jsx(P,{"aria-label":"Add a model",placeholder:"Search providers, models, aliases…",autoComplete:"off"}),t.jsx(d.Trigger,{})]}),t.jsx(d.Popover,{children:t.jsx(R,{items:L,className:"max-h-72 overflow-auto",children:e=>t.jsx(V,{id:e.id,textValue:e.label,children:e.label})})})]})]}):null]})}function X(r){return r===null?{text:"All models",tone:"muted"}:r.length===0?{text:"No models",tone:"danger"}:{text:"Selected models",tone:"normal"}}export{W as M,X as a}; diff --git a/src/gateway/static/dashboard/assets/ModelsPage-BMeU3W4u.js b/src/gateway/static/dashboard/assets/ModelsPage-r0TNjwml.js similarity index 83% rename from src/gateway/static/dashboard/assets/ModelsPage-BMeU3W4u.js rename to src/gateway/static/dashboard/assets/ModelsPage-r0TNjwml.js index 47a58e8e..dd8bd8b1 100644 --- a/src/gateway/static/dashboard/assets/ModelsPage-BMeU3W4u.js +++ b/src/gateway/static/dashboard/assets/ModelsPage-r0TNjwml.js @@ -1 +1 @@ -import{j as e}from"./tanstack-query-1t81HyiD.js";import{i as gt,u as vt,r as c}from"./react-dgEcD0HR.js";import{x as _t,y as bt,h as jt,z as yt,A as je,P as Pt,E as Nt,F as B,I as St,B as ae,D as Re,C as ze,G as be,H as Ct,J as kt,K as E}from"./index-D4f8RVEq.js";import{u as Mt,r as Wt,B as It}from"./tableSelection-9hV37uhu.js";import{D as Tt}from"./DataTable-Bmn_eYSV.js";import{T as Lt,S as At}from"./TablePagination-BTOqrUVz.js";import{B as A,d as se,f as V}from"./heroui-BI50yK5B.js";function Oe(t){const i=t.indexOf(":");return i>0?t.slice(0,i):"—"}function $t(t,i=Date.now()){const r=new Map;for(const n of t){const l=r.get(n.model_key)??[];l.push(n),r.set(n.model_key,l)}const s=[];for(const n of r.values()){const l=[...n].sort((p,u)=>Date.parse(p.effective_at)-Date.parse(u.effective_at)),m=[...l].reverse().find(p=>Date.parse(p.effective_at)<=i);s.push(m??l[0])}return s.sort((n,l)=>n.model_key.localeCompare(l.model_key))}const Et="otari",De=[{value:"vision",label:"Vision",test:t=>Array.isArray(t.input_modalities)&&t.input_modalities.includes("image")},{value:"tool_call",label:"Tool calling",test:t=>!!t.tool_call},{value:"reasoning",label:"Reasoning",test:t=>!!t.reasoning},{value:"structured_output",label:"Structured output",test:t=>!!t.structured_output},{value:"attachment",label:"Attachments",test:t=>!!t.attachment},{value:"audio",label:"Audio",test:t=>Array.isArray(t.input_modalities)&&t.input_modalities.includes("audio")},{value:"pdf",label:"PDF",test:t=>Array.isArray(t.input_modalities)&&t.input_modalities.includes("pdf")}],Ot=[{key:"reasoning",label:"Reasoning"},{key:"tool_call",label:"Tool calling"},{key:"structured_output",label:"Structured output"},{key:"attachment",label:"Attachments"},{key:"temperature",label:"Temperature"}],Fe={text:"Text",image:"Image",audio:"Audio",video:"Video",pdf:"PDF"},Dt=[{value:"0",label:"Any context"},{value:"8000",label:"≥ 8K"},{value:"32000",label:"≥ 32K"},{value:"128000",label:"≥ 128K"},{value:"200000",label:"≥ 200K"},{value:"1000000",label:"≥ 1M"}],Ft=[{value:"",label:"Any price"},{value:"1",label:"≤ $1 / 1M in"},{value:"3",label:"≤ $3 / 1M in"},{value:"10",label:"≤ $10 / 1M in"},{value:"30",label:"≤ $30 / 1M in"}],Bt=[{value:"",label:"Base prices"},{value:"8000",label:"Compare at 8K"},{value:"128000",label:"Compare at 128K"},{value:"200000",label:"Compare at 200K"},{value:"500000",label:"Compare at 500K"},{value:"1000000",label:"Compare at 1M"}],Kt=[{value:"all",label:"Any release date"},{value:"365",label:"Past year"},{value:"730",label:"Past 2 years"},{value:"1095",label:"Past 3 years"}],Rt=1440*60*1e3,zt=t=>t.key;function Be(t,i){const r=`${i}:`;return t.startsWith(r)?t.slice(r.length):t}function Ke(t,i){const r={inputPrice:t.inputPrice,outputPrice:t.outputPrice,cacheReadPrice:t.cacheReadPrice,cacheWritePrice:t.cacheWritePrice,cacheWrite1hPrice:t.cacheWrite1hPrice};if(i==null)return r;const s=t.pricingTiers.filter(n=>n.min_input_tokens<=i).sort((n,l)=>l.min_input_tokens-n.min_input_tokens)[0];return s?{inputPrice:s.input_price_per_million??r.inputPrice,outputPrice:s.output_price_per_million??r.outputPrice,cacheReadPrice:s.cache_read_price_per_million??r.cacheReadPrice,cacheWritePrice:s.cache_write_price_per_million??r.cacheWritePrice,cacheWrite1hPrice:s.cache_write_1h_price_per_million??r.cacheWrite1hPrice}:r}function ce(t){const i=Number(t);return t.trim()!==""&&Number.isFinite(i)&&i>=0}function w(t){if(t.trim()==="")return!0;const i=Number(t);return Number.isFinite(i)&&i>=0}function Y(t){return t.trim()===""?null:Number(t)}function we(t){return t.map((i,r)=>({id:r,minInputTokens:String(i.min_input_tokens),input:i.input_price_per_million==null?"":String(i.input_price_per_million),output:i.output_price_per_million==null?"":String(i.output_price_per_million),cacheRead:i.cache_read_price_per_million==null?"":String(i.cache_read_price_per_million),cacheWrite:i.cache_write_price_per_million==null?"":String(i.cache_write_price_per_million),cacheWrite1h:i.cache_write_1h_price_per_million==null?"":String(i.cache_write_1h_price_per_million)}))}function Ve(t){const i=new Set;return t.every(r=>{const s=Number(r.minInputTokens),n=[r.input,r.output,r.cacheRead,r.cacheWrite,r.cacheWrite1h].some(l=>l.trim()!=="");return!Number.isInteger(s)||s<=0||i.has(s)||!n?!1:(i.add(s),[r.input,r.output,r.cacheRead,r.cacheWrite,r.cacheWrite1h].every(w))})}function Ye(t){return t.map(i=>({min_input_tokens:Number(i.minInputTokens),...i.input.trim()===""?{}:{input_price_per_million:Number(i.input)},...i.output.trim()===""?{}:{output_price_per_million:Number(i.output)},...i.cacheRead.trim()===""?{}:{cache_read_price_per_million:Number(i.cacheRead)},...i.cacheWrite.trim()===""?{}:{cache_write_price_per_million:Number(i.cacheWrite)},...i.cacheWrite1h.trim()===""?{}:{cache_write_1h_price_per_million:Number(i.cacheWrite1h)}}))}function b({value:t,onChange:i,ariaLabel:r}){return e.jsx("input",{type:"number",step:"any",min:"0",inputMode:"decimal","aria-label":r,value:t,onChange:s=>i(s.target.value),className:"w-28 rounded-md border border-[var(--otari-line)] bg-white px-2 py-1 text-right text-sm tabular-nums focus:border-[var(--otari-brand)] focus:outline-none"})}function qe({tiers:t,onChange:i}){const r=(n,l,m)=>{i(t.map(p=>p.id===n?{...p,[l]:m}:p))},s=()=>{const n=t.reduce((l,m)=>Math.max(l,m.id),-1)+1;i([...t,{id:n,minInputTokens:"128000",input:"",output:"",cacheRead:"",cacheWrite:"",cacheWrite1h:""}])};return e.jsxs("div",{className:"flex flex-col gap-2 rounded-lg border border-[var(--otari-line)] p-3",children:[e.jsxs("div",{className:"flex items-center justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-xs font-medium text-[var(--otari-ink)]",children:"Long-context price tiers"}),e.jsx("p",{className:"text-xs text-[var(--otari-muted)]",children:"At a threshold, listed rates replace the base rate for the whole request."})]}),e.jsx(A,{size:"sm",variant:"outline",onPress:s,children:"Add tier"})]}),t.map(n=>e.jsxs("div",{className:"flex flex-wrap items-end gap-2 border-t border-[var(--otari-line)] pt-2",children:[e.jsxs("label",{className:"flex flex-col gap-1 text-xs text-[var(--otari-muted)]",children:["Context ≥ tokens",e.jsx("input",{type:"number",min:"1",step:"1",inputMode:"numeric","aria-label":"Tier context threshold",value:n.minInputTokens,onChange:l=>r(n.id,"minInputTokens",l.target.value),className:"w-28 rounded-md border border-[var(--otari-line)] bg-white px-2 py-1 text-right text-sm tabular-nums focus:border-[var(--otari-brand)] focus:outline-none"})]}),e.jsxs("label",{className:"flex flex-col gap-1 text-xs text-[var(--otari-muted)]",children:["Input",e.jsx(b,{value:n.input,onChange:l=>r(n.id,"input",l),ariaLabel:"Tier input price"})]}),e.jsxs("label",{className:"flex flex-col gap-1 text-xs text-[var(--otari-muted)]",children:["Output",e.jsx(b,{value:n.output,onChange:l=>r(n.id,"output",l),ariaLabel:"Tier output price"})]}),e.jsxs("label",{className:"flex flex-col gap-1 text-xs text-[var(--otari-muted)]",children:["Cache read",e.jsx(b,{value:n.cacheRead,onChange:l=>r(n.id,"cacheRead",l),ariaLabel:"Tier cache read price"})]}),e.jsxs("label",{className:"flex flex-col gap-1 text-xs text-[var(--otari-muted)]",children:["Cache write",e.jsx(b,{value:n.cacheWrite,onChange:l=>r(n.id,"cacheWrite",l),ariaLabel:"Tier cache write price"})]}),e.jsxs("label",{className:"flex flex-col gap-1 text-xs text-[var(--otari-muted)]",children:["1h write",e.jsx(b,{value:n.cacheWrite1h,onChange:l=>r(n.id,"cacheWrite1h",l),ariaLabel:"Tier 1 hour cache write price"})]}),e.jsx(A,{size:"sm",variant:"ghost",onPress:()=>i(t.filter(l=>l.id!==n.id)),children:"Remove"})]},n.id))]})}function wt({source:t}){return t==="configured"?e.jsx(V,{size:"sm",color:"default",children:"configured"}):t==="default"||t==="alias"?e.jsx(V,{size:"sm",color:"accent",children:t}):e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"not priced"})}function oe({label:t,tone:i="info",children:r}){const s=c.useId();return e.jsxs("span",{className:"group relative inline-flex items-center font-normal normal-case",children:[e.jsx("button",{type:"button","aria-label":t,"aria-describedby":s,className:`inline-flex h-4 w-4 items-center justify-center rounded-full border text-[10px] leading-none ${i==="warning"?"border-[#c2843a] text-[#b45309]":"border-[var(--otari-line)] text-[var(--otari-muted)] hover:border-[var(--otari-brand)] hover:text-[var(--otari-brand)]"}`,children:"i"}),e.jsx("span",{id:s,role:"tooltip",className:"pointer-events-none absolute top-full right-0 z-20 mt-1.5 w-72 rounded-lg border border-[var(--otari-line)] bg-[var(--otari-surface)] px-3 py-2 text-left text-xs font-normal whitespace-normal break-words text-[var(--otari-ink)] opacity-0 shadow-lg transition-opacity group-hover:opacity-100 group-focus-within:opacity-100",children:r})]})}function Vt(){const t=kt();return t.data?t.data.default_pricing?e.jsx(oe,{label:"How unpriced models are metered",tone:"info",children:"Default pricing is on: models without a configured price are metered using community-maintained rates (the bundled genai-prices dataset). Set a price to override the fallback."}):e.jsxs(oe,{label:"How unpriced models are metered",tone:"warning",children:["Default pricing is off: only models with a configured price are metered.",t.data.require_pricing?" Requests for any other model are rejected (HTTP 402) because require_pricing is on.":" Other models are served without cost tracking."]}):null}function I({label:t,value:i}){return e.jsxs("div",{className:"flex items-baseline justify-between gap-3",children:[e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:t}),e.jsx("span",{className:"text-right text-sm text-[var(--otari-ink)] tabular-nums",children:i})]})}function le({title:t,children:i}){return e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("span",{className:"text-xs font-semibold uppercase tracking-wide text-[var(--otari-muted)]",children:t}),i]})}function Yt({row:t}){const i=je(),r=Re(),[s,n]=c.useState(!1),[l,m]=c.useState(""),[p,u]=c.useState(""),[P,j]=c.useState(""),[k,T]=c.useState(""),[y,h]=c.useState(""),[N,O]=c.useState([]),S=()=>{m(t.inputPrice==null?"":String(t.inputPrice)),u(t.outputPrice==null?"":String(t.outputPrice)),j(t.cacheReadPrice==null?"":String(t.cacheReadPrice)),T(t.cacheWritePrice==null?"":String(t.cacheWritePrice)),h(t.cacheWrite1hPrice==null?"":String(t.cacheWrite1hPrice)),O(we(t.pricingTiers)),n(!0)},Z=ce(l)&&ce(p)&&w(P)&&w(k)&&w(y)&&Ve(N),W=()=>{Z&&i.mutate({model_key:t.key,input_price_per_million:Number(l),output_price_per_million:Number(p),cache_read_price_per_million:Y(P),cache_write_price_per_million:Y(k),cache_write_1h_price_per_million:Y(y),pricing_tiers:Ye(N)},{onSuccess:()=>n(!1)})};return s?e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsxs("div",{className:"flex items-center justify-between gap-2",children:[e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"Input $ / 1M"}),e.jsx(b,{value:l,onChange:m,ariaLabel:`Input price for ${t.key}`})]}),e.jsxs("div",{className:"flex items-center justify-between gap-2",children:[e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"Output $ / 1M"}),e.jsx(b,{value:p,onChange:u,ariaLabel:`Output price for ${t.key}`})]}),e.jsxs("div",{className:"flex items-center justify-between gap-2",children:[e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"Cache read $ / 1M"}),e.jsx(b,{value:P,onChange:j,ariaLabel:`Cache read price for ${t.key}`})]}),e.jsxs("div",{className:"flex items-center justify-between gap-2",children:[e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"Cache write $ / 1M"}),e.jsx(b,{value:k,onChange:T,ariaLabel:`Cache write price for ${t.key}`})]}),e.jsxs("div",{className:"flex items-center justify-between gap-2",children:[e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"1h cache write $ / 1M"}),e.jsx(b,{value:y,onChange:h,ariaLabel:`1 hour cache write price for ${t.key}`})]}),e.jsx(qe,{tiers:N,onChange:O}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(A,{size:"sm",variant:"primary",isDisabled:i.isPending||!Z,onPress:W,children:"Save"}),e.jsx(A,{size:"sm",variant:"ghost",isDisabled:i.isPending,onPress:()=>n(!1),children:"Cancel"})]}),i.error?e.jsx("span",{className:"text-xs text-red-700",children:be(i.error)}):null]}):e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx(I,{label:"Input",value:t.inputPrice==null?"—":`${E(t.inputPrice)} / 1M`}),e.jsx(I,{label:"Output",value:t.outputPrice==null?"—":`${E(t.outputPrice)} / 1M`}),e.jsx(I,{label:"Cache read",value:t.cacheReadPrice==null?"—":`${E(t.cacheReadPrice)} / 1M`}),e.jsx(I,{label:"Cache write",value:t.cacheWritePrice==null?"—":`${E(t.cacheWritePrice)} / 1M`}),e.jsx(I,{label:"1h cache write",value:t.cacheWrite1hPrice==null?"—":`${E(t.cacheWrite1hPrice)} / 1M`}),e.jsx(I,{label:"Context tiers",value:t.pricingTiers.length?`${t.pricingTiers.length} configured`:"—"}),e.jsxs("div",{className:"flex items-center gap-2 pt-1",children:[e.jsx(A,{size:"sm",variant:"outline",onPress:S,children:t.source==="configured"?"Edit price":"Set price"}),t.source==="configured"?e.jsxs(e.Fragment,{children:[e.jsx(ze,{confirmLabel:"Reset",isPending:r.isPending,onConfirm:()=>r.mutate(t.key),children:"Reset"}),e.jsx(oe,{label:"What reset does",children:"Removes the custom price. The model reverts to the default rate (genai-prices) when default pricing is on, otherwise it is metered at no cost."})]}):null,r.error?e.jsx("span",{className:"text-xs text-red-700",children:be(r.error)}):null]})]})}function qt({row:t,metadata:i,metadataAvailable:r,onMakeAlias:s,onClose:n}){const l=(i==null?void 0:i.input_modalities)??[],m=(i==null?void 0:i.output_modalities)??[],p=Ot.filter(({key:u})=>i==null?void 0:i[u]);return e.jsx(se,{children:e.jsxs(se.Content,{className:"flex flex-col gap-5 p-5",children:[e.jsxs("div",{className:"flex items-start justify-between gap-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("h2",{className:"text-base font-semibold break-all text-[var(--otari-ink)]",children:t.model}),i!=null&&i.deprecated?e.jsx(V,{size:"sm",color:"danger",children:"deprecated"}):null]}),e.jsxs("p",{className:"mt-1 text-xs break-all text-[var(--otari-muted)]",children:["Selector: ",e.jsx("code",{children:t.key})]}),i!=null&&i.family?e.jsx("p",{className:"text-xs text-[var(--otari-muted)]",children:i.family}):null]}),e.jsx("button",{type:"button","aria-label":"Close model details",onClick:n,className:"-mt-1 -mr-1 shrink-0 rounded-md px-1.5 py-0.5 text-lg leading-none text-[var(--otari-muted)] hover:bg-[var(--otari-bg)] hover:text-[var(--otari-ink)]",children:"✕"})]}),i!=null&&i.description?e.jsx("p",{className:"text-sm text-[var(--otari-ink)]",children:i.description}):null,e.jsxs(le,{title:"Pricing",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(wt,{source:t.source}),t.isDiscovered?null:e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"not discovered"})]}),e.jsx(Yt,{row:t},t.key),e.jsx(A,{size:"sm",variant:"outline",onPress:()=>s(t.key),children:"Make an alias"})]}),e.jsxs(le,{title:"Specs",children:[e.jsx(I,{label:"Context window",value:ae(t.contextWindow)}),e.jsx(I,{label:"Max output",value:ae((i==null?void 0:i.max_output_tokens)??null)}),e.jsx(I,{label:"Knowledge cutoff",value:(i==null?void 0:i.knowledge_cutoff)??"—"}),e.jsx(I,{label:"Released",value:Ct(i==null?void 0:i.release_date)}),e.jsx(I,{label:"Open weights",value:i?i.open_weights?"Yes":"No":"—"})]}),e.jsx(le,{title:"Modalities",children:l.length===0&&m.length===0?e.jsx("span",{className:"text-sm text-[var(--otari-muted)]",children:"Unknown."}):e.jsxs("div",{className:"flex flex-col gap-1.5 text-xs text-[var(--otari-muted)]",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-1",children:[e.jsx("span",{children:"In:"}),l.map(u=>e.jsx(V,{size:"sm",color:"default",children:Fe[u]??u},u))]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-1",children:[e.jsx("span",{children:"Out:"}),m.map(u=>e.jsx(V,{size:"sm",color:"default",children:Fe[u]??u},u))]})]})}),e.jsx(le,{title:"Capabilities",children:p.length>0?e.jsx("div",{className:"flex flex-wrap gap-1.5",children:p.map(({key:u,label:P})=>e.jsx(V,{size:"sm",color:"default",children:P},u))}):e.jsx("span",{className:"text-sm text-[var(--otari-muted)]",children:r?"None reported.":"Extended metadata unavailable (models.dev disabled or unreachable)."})})]})})}const Ht=15;function Ut({value:t,onChange:i,placeholder:r}){return e.jsx("input",{type:"search",value:t,onChange:s=>i(s.target.value),placeholder:r,"aria-label":r,className:"w-full max-w-xs rounded-md border border-[var(--otari-line)] bg-white px-3 py-1.5 text-sm focus:border-[var(--otari-brand)] focus:outline-none"})}const He="otari.dashboard.modelsSort",_e={col:"model",dir:"asc"},Gt=["model","released","input","output"];function Jt(){if(typeof window>"u")return _e;try{const t=window.localStorage.getItem(He);if(!t)return _e;const i=JSON.parse(t);if(Gt.includes(i.col)&&(i.dir==="asc"||i.dir==="desc"))return{col:i.col,dir:i.dir}}catch{}return _e}function Xt({row:t,onClose:i}){const r=je(),s=Re(),[n,l]=c.useState(t.inputPrice==null?"":String(t.inputPrice)),[m,p]=c.useState(t.outputPrice==null?"":String(t.outputPrice)),[u,P]=c.useState(t.cacheReadPrice==null?"":String(t.cacheReadPrice)),[j,k]=c.useState(t.cacheWritePrice==null?"":String(t.cacheWritePrice)),[T,y]=c.useState(t.cacheWrite1hPrice==null?"":String(t.cacheWrite1hPrice)),[h,N]=c.useState(we(t.pricingTiers)),O=ce(n)&&ce(m)&&w(u)&&w(j)&&w(T)&&Ve(h),S=()=>{O&&r.mutate({model_key:t.key,input_price_per_million:Number(n),output_price_per_million:Number(m),cache_read_price_per_million:Y(u),cache_write_price_per_million:Y(j),cache_write_1h_price_per_million:Y(T),pricing_tiers:Ye(h)},{onSuccess:i})};return e.jsxs("div",{className:"flex flex-col gap-3 px-4 py-3",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsx("span",{className:"text-xs font-medium break-all text-[var(--otari-muted)]",children:t.key}),e.jsxs("label",{className:"flex items-center gap-1.5 text-xs text-[var(--otari-muted)]",children:["Input $ / 1M",e.jsx(b,{value:n,onChange:l,ariaLabel:`Input price for ${t.key}`})]}),e.jsxs("label",{className:"flex items-center gap-1.5 text-xs text-[var(--otari-muted)]",children:["Output $ / 1M",e.jsx(b,{value:m,onChange:p,ariaLabel:`Output price for ${t.key}`})]}),e.jsxs("label",{className:"flex items-center gap-1.5 text-xs text-[var(--otari-muted)]",children:["Cache read $ / 1M",e.jsx(b,{value:u,onChange:P,ariaLabel:`Cache read price for ${t.key}`})]}),e.jsxs("label",{className:"flex items-center gap-1.5 text-xs text-[var(--otari-muted)]",children:["Cache write $ / 1M",e.jsx(b,{value:j,onChange:k,ariaLabel:`Cache write price for ${t.key}`})]}),e.jsxs("label",{className:"flex items-center gap-1.5 text-xs text-[var(--otari-muted)]",children:["1h cache write $ / 1M",e.jsx(b,{value:T,onChange:y,ariaLabel:`1 hour cache write price for ${t.key}`})]}),e.jsx(A,{size:"sm",variant:"primary",isDisabled:r.isPending||!O,onPress:S,children:r.isPending?"Saving…":"Save"}),e.jsx(A,{size:"sm",variant:"ghost",isDisabled:r.isPending,onPress:i,children:"Cancel"}),t.source==="configured"?e.jsxs("span",{className:"inline-flex items-center gap-1",children:[e.jsx(ze,{confirmLabel:"Reset",isPending:s.isPending,onConfirm:()=>s.mutate(t.key,{onSuccess:i}),children:"Reset"}),e.jsx(oe,{label:"What reset does",children:"Removes the custom price. The model reverts to the default rate (genai-prices) when default pricing is on, otherwise it is metered at no cost."})]}):null,r.error||s.error?e.jsx("span",{className:"text-xs text-red-700",children:be(r.error??s.error)}):null]}),e.jsx(qe,{tiers:h,onChange:N})]})}function Zt({primary:t,secondary:i,rowKey:r,primaryLabel:s,secondaryLabel:n,onEdit:l}){const m=(p,u)=>e.jsx("button",{type:"button","aria-label":`Edit ${u} price for ${r}`,className:"tabular-nums hover:text-[var(--otari-brand-dark)] hover:underline",onClick:P=>{P.stopPropagation(),l()},children:p==null?"—":E(p)});return e.jsxs("span",{className:"inline-flex items-center justify-end gap-1",children:[m(t,s),e.jsx("span",{className:"text-[var(--otari-muted)]",children:"/"}),m(i,n)]})}function Qt({rates:t,rowKey:i,onEdit:r}){const s=[t.cacheReadPrice==null?null:`R ${E(t.cacheReadPrice)}`,t.cacheWritePrice==null?null:`W ${E(t.cacheWritePrice)}`,t.cacheWrite1hPrice==null?null:`1h ${E(t.cacheWrite1hPrice)}`].filter(n=>n!==null);return e.jsx("button",{type:"button","aria-label":`Edit caching price for ${i}`,className:"max-w-44 text-right text-xs leading-5 text-[var(--otari-muted)] hover:text-[var(--otari-brand-dark)] hover:underline",onClick:n=>{n.stopPropagation(),r()},children:s.length>0?s.join(" · "):"Input-rate fallback"})}function ei({row:t,onEdit:i}){const r=[...t.pricingTiers].sort((n,l)=>n.min_input_tokens-l.min_input_tokens).map(n=>ae(n.min_input_tokens)),s=r.length===0?"Base only":`${r.length} tier${r.length===1?"":"s"} · ≥ ${r.join(", ")}`;return e.jsx("button",{type:"button","aria-label":`Edit pricing policy for ${t.key}`,className:"max-w-40 text-right text-xs leading-5 text-[var(--otari-muted)] hover:text-[var(--otari-brand-dark)] hover:underline",onClick:n=>{n.stopPropagation(),i()},children:s})}function ti({rows:t,isLoading:i,empty:r,sortDescriptor:s,onSortChange:n,selectedKey:l,onSelect:m,onEditPricing:p,comparisonContextTokens:u,selectedKeys:P,onSelectionChange:j}){const k=c.useMemo(()=>{const y=u==null?"Base":`at ${ae(u)}`;return[{id:"model",header:"Model",isRowHeader:!0,allowsSorting:!0,cell:h=>e.jsxs("span",{className:"font-medium break-all",children:[h.model,e.jsx("span",{className:"sr-only",children:h.key})]})},{id:"provider",header:"Provider",cell:h=>e.jsx("span",{className:"text-[var(--otari-muted)]",children:h.provider})},{id:"input",header:e.jsxs("span",{className:"inline-flex items-center gap-1",children:[`${y} in / out $ / 1M`,e.jsx(Vt,{})]}),align:"end",allowsSorting:!0,cell:h=>{const N=Ke(h,u);return e.jsx(Zt,{primary:N.inputPrice,secondary:N.outputPrice,rowKey:h.key,primaryLabel:"input",secondaryLabel:"output",onEdit:()=>p(h.key)})}},{id:"caching",header:`Caching ${u==null?"policy":y}`,align:"end",cell:h=>e.jsx(Qt,{rates:Ke(h,u),rowKey:h.key,onEdit:()=>p(h.key)})},{id:"policy",header:"Pricing policy",align:"end",cell:h=>e.jsx(ei,{row:h,onEdit:()=>p(h.key)})}]},[u,p]),T=c.useCallback(y=>y.key===l?"bg-[var(--otari-brand-tint)]":void 0,[l]);return e.jsx(Tt,{ariaLabel:"Models",columns:k,rows:t,getRowKey:zt,isLoading:i,emptyContent:r,selectionMode:"multiple",selectedKeys:P,onSelectionChange:j,sortDescriptor:s,onSortChange:n,onRowAction:m,rowClassName:T})}function ii({providers:t}){if(t.length===0)return null;const i=t.filter(l=>!l.discovery_unsupported),r=t.filter(l=>l.discovery_unsupported),s=l=>l.map(m=>m.provider).join(", "),n=l=>l.length===1;return e.jsxs(St,{tone:"warning",children:[i.length>0?e.jsxs("span",{className:"block",children:["Could not list ",s(i),". Check ",n(i)?"that provider's":"those providers'"," ","credentials in config.yml; ",n(i)?"its":"their"," models are missing from the list below."]}):null,r.length>0?e.jsxs("span",{className:"block",children:[s(r)," ",n(r)?"does":"do"," not offer model discovery, so"," ",n(r)?"its":"their"," models are missing from the list below."," ",n(r)?"The provider":"They"," may still serve requests; declare the model ids"," ",n(r)?"it serves":"they serve"," under the ",e.jsx("code",{children:"models:"})," key in config.yml to list them here."]}):null]})}function pi(){var Te,Le,Ae;const t=gt(),[i]=vt(),r=_t(),s=bt(),n=jt(),l=yt(),m=je(),[p,u]=c.useState(""),[P,j]=c.useState(0),[k,T]=c.useState(Ht),[y,h]=c.useState(null),[N,O]=c.useState(null),[S,Z]=c.useState(Jt),W=Mt(),[Ue,ue]=c.useState(!1),[Ge,ye]=c.useState(!1),[Je,Pe]=c.useState(void 0);c.useEffect(()=>{try{window.localStorage.setItem(He,JSON.stringify(S))}catch{}},[S]);const[D,Ne]=c.useState(i.get("provider")||"all"),[K,Xe]=c.useState("all"),[q,Ze]=c.useState("all"),[H,Qe]=c.useState("all"),[de,et]=c.useState("0"),[Q,tt]=c.useState(""),[ee,it]=c.useState("all"),[pe,rt]=c.useState(""),F=((Te=l.data)==null?void 0:Te.models)??{},nt=((Le=l.data)==null?void 0:Le.available)??!1,Se=c.useMemo(()=>{var a;return new Set((((a=n.data)==null?void 0:a.providers)??[]).flatMap(x=>x.models.map(o=>o.key)))},[n.data]),lt=a=>{u(a),j(0)},R=a=>x=>{a(x),j(0)},te=c.useMemo(()=>{var M,v,_,$,L,z,$e;const a=new Map($t(s.data??[]).map(d=>[d.model_key,d])),x=[],o=new Set,g=(d,ve,Ee,f)=>{if(o.has(d))return;o.add(d);const C=a.get(d);x.push({key:d,model:Be(ve,Ee),provider:Ee,isDiscovered:Se.has(d),contextWindow:(f==null?void 0:f.contextWindow)??null,inputPrice:C?C.input_price_per_million:(f==null?void 0:f.inputPrice)??null,outputPrice:C?C.output_price_per_million:(f==null?void 0:f.outputPrice)??null,cacheReadPrice:C?C.cache_read_price_per_million:(f==null?void 0:f.cacheReadPrice)??null,cacheWritePrice:C?C.cache_write_price_per_million:(f==null?void 0:f.cacheWritePrice)??null,cacheWrite1hPrice:C?C.cache_write_1h_price_per_million??null:(f==null?void 0:f.cacheWrite1hPrice)??null,pricingTiers:C?C.pricing_tiers??[]:(f==null?void 0:f.pricingTiers)??[],source:C?"configured":(f==null?void 0:f.source)??"none"})};for(const d of((M=r.data)==null?void 0:M.data)??[]){if(d.owned_by===Et)continue;const ve=d.pricing_source==="default"?"default":d.pricing?"configured":"none";g(d.id,d.id,d.owned_by||Oe(d.id),{key:d.id,model:d.id,provider:d.owned_by,contextWindow:d.context_window,inputPrice:((v=d.pricing)==null?void 0:v.input_price_per_million)??null,outputPrice:((_=d.pricing)==null?void 0:_.output_price_per_million)??null,cacheReadPrice:(($=d.pricing)==null?void 0:$.cache_read_price_per_million)??null,cacheWritePrice:((L=d.pricing)==null?void 0:L.cache_write_price_per_million)??null,cacheWrite1hPrice:((z=d.pricing)==null?void 0:z.cache_write_1h_price_per_million)??null,pricingTiers:(($e=d.pricing)==null?void 0:$e.pricing_tiers)??[],source:ve})}for(const d of a.keys())g(d,d,Oe(d));return x},[r.data,s.data,Se]),Ce=c.useMemo(()=>new Map(te.map(a=>[a.key,a])),[te]),ie=c.useMemo(()=>{var o,g,M;const a=te.map(v=>{var _,$;return{...v,contextWindow:v.contextWindow??((_=F[v.key])==null?void 0:_.context_window)??null,releaseDate:(($=F[v.key])==null?void 0:$.release_date)??null}}),x=new Set(a.map(v=>v.key));for(const v of((o=n.data)==null?void 0:o.providers)??[])for(const _ of v.models)x.has(_.key)||(x.add(_.key),a.push({key:_.key,model:Be(_.key,v.provider),provider:v.provider,isDiscovered:!0,contextWindow:((g=F[_.key])==null?void 0:g.context_window)??null,releaseDate:((M=F[_.key])==null?void 0:M.release_date)??null,inputPrice:null,outputPrice:null,cacheReadPrice:null,cacheWritePrice:null,cacheWrite1hPrice:null,pricingTiers:[],source:"none"}));return a},[te,n.data,F]),at=(((Ae=n.data)==null?void 0:Ae.providers)??[]).filter(a=>!a.ok),re=c.useMemo(()=>{const a=Array.from(new Set(ie.map(x=>x.provider))).sort((x,o)=>x.localeCompare(o));return[{value:"all",label:"All providers"},...a.map(x=>({value:x,label:x}))]},[ie]);c.useEffect(()=>{D==="all"||re.length<=1||re.some(a=>a.value===D)||Ne("all")},[re,D]);const U=p.trim().toLowerCase(),he=Number(de)||0,me=Q===""?Number.POSITIVE_INFINITY:Number(Q),st=pe===""?null:Number(pe),xe=ee==="all"?null:Date.now()-Number(ee)*Rt,G=c.useMemo(()=>{const a=o=>{if(U&&!o.key.toLowerCase().includes(U)&&!o.provider.toLowerCase().includes(U)||D!=="all"&&o.provider!==D||K==="configured"&&o.source!=="configured"||K==="default"&&o.source!=="default"||K==="priced"&&o.inputPrice==null||K==="unpriced"&&o.inputPrice!=null||q==="discovered"&&!o.isDiscovered||q==="custom"&&o.isDiscovered)return!1;if(H!=="all"){const g=De.find(v=>v.value===H),M=F[o.key];if(!g||!M||!g.test(M))return!1}if(he>0&&(o.contextWindow==null||o.contextWindowme))return!1;if(xe!=null){const g=o.releaseDate?Date.parse(o.releaseDate):Number.NaN;if(Number.isNaN(g)||g{const M=S.dir==="asc"?1:-1;if(S.col==="model")return o.model.localeCompare(g.model)*M;if(S.col==="released"){const L=o.releaseDate??null,z=g.releaseDate??null;return!L&&!z?o.model.localeCompare(g.model):L?z?(Lz?1:0)*M||o.model.localeCompare(g.model):-1:1}const v=L=>S.col==="input"?L.inputPrice:L.outputPrice,_=v(o),$=v(g);return _==null&&$==null?o.model.localeCompare(g.model):_==null?1:$==null?-1:(_-$)*M||o.model.localeCompare(g.model)};return ie.filter(a).sort(x)},[ie,U,D,K,q,H,he,me,xe,F,S]),J=G.length,ct=Math.max(1,Math.ceil(J/k)),ke=Math.min(P,ct-1),Me=ke*k,fe=G.slice(Me,Me+k),ot={column:S.col,direction:S.dir==="asc"?"ascending":"descending"},ut=a=>{Z({col:String(a.column),dir:a.direction==="ascending"?"asc":"desc"}),j(0)},dt=c.useCallback(a=>h(x=>x===a?null:a),[]),ge=fe.map(a=>a.key),X=Wt(W.selectedKeys,ge),pt=ge.length>0&&X.length===ge.length&&J>X.length,ht=W.allMatching?G.map(a=>a.key):X,We=W.allMatching?J:X.length,Ie=y?G.find(a=>a.key===y)??Ce.get(y)??null:null,mt=async a=>{ye(!0),Pe(void 0);try{for(const x of ht)await m.mutateAsync({model_key:x,input_price_per_million:a.input_price_per_million,output_price_per_million:a.output_price_per_million,cache_read_price_per_million:a.cache_read_price_per_million??null,cache_write_price_per_million:a.cache_write_price_per_million??null,cache_write_1h_price_per_million:null,pricing_tiers:[]});W.clear(),ue(!1)}catch(x){Pe(x)}finally{ye(!1)}},xt=r.isLoading||s.isLoading||n.isLoading,ft=U!==""||D!=="all"||K!=="all"||q!=="all"||H!=="all"||de!=="0"||Q!==""||ee!=="all"?"No models match your filters.":"No models yet. Add a provider on the Providers page, or price a model below.",ne=N?G.find(a=>a.key===N)??Ce.get(N)??null:null;return e.jsxs("div",{className:"flex flex-col gap-6",children:[e.jsx(Pt,{title:"Models",description:"Every model your providers can serve. Set a price on any model so budgets and usage tracking work."}),e.jsx(Nt,{error:r.error??s.error??n.error??l.error}),e.jsxs("div",{className:`grid gap-4 lg:items-start ${ne?"lg:grid-cols-[minmax(0,1fr)_360px]":"grid-cols-1"}`,children:[e.jsxs("div",{className:"flex min-w-0 flex-col gap-3",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx(Ut,{value:p,onChange:lt,placeholder:"Search models…"}),e.jsx(B,{ariaLabel:"Filter by provider",value:D,onChange:R(Ne),options:re}),e.jsx(B,{ariaLabel:"Filter by pricing",value:K,onChange:R(Xe),options:[{value:"all",label:"Any pricing"},{value:"configured",label:"Custom price"},{value:"default",label:"Default price"},{value:"priced",label:"Priced"},{value:"unpriced",label:"Unpriced"}]}),e.jsx(B,{ariaLabel:"Filter by source",value:q,onChange:R(Ze),options:[{value:"all",label:"Any source"},{value:"discovered",label:"Discovered"},{value:"custom",label:"Custom (not discovered)"}]}),e.jsx(B,{ariaLabel:"Filter by capability",value:H,onChange:R(Qe),options:[{value:"all",label:"Any capability"},...De.map(a=>({value:a.value,label:a.label}))]}),e.jsx(B,{ariaLabel:"Minimum context window",value:de,onChange:R(et),options:Dt}),e.jsx(B,{ariaLabel:"Maximum input price",value:Q,onChange:R(tt),options:Ft}),e.jsx(B,{ariaLabel:"Compare prices at context",value:pe,onChange:rt,options:Bt}),e.jsx(B,{ariaLabel:"Filter by release date",value:ee,onChange:R(it),options:Kt})]}),e.jsx(ii,{providers:at}),X.length>0?e.jsx(It,{selectedCount:We,allMatching:W.allMatching,matchingTotal:J,canSelectAllMatching:pt,onSelectAllMatching:W.enableAllMatching,onClear:W.clear,children:e.jsx(A,{size:"sm",variant:"primary",onPress:()=>ue(!0),children:"Set pricing"})}):null,e.jsx(ti,{rows:fe,isLoading:xt,empty:ft,sortDescriptor:ot,onSortChange:ut,selectedKey:N,onSelect:O,onEditPricing:dt,comparisonContextTokens:st,selectedKeys:W.selectedKeys,onSelectionChange:W.onSelectionChange}),Ie?e.jsx(se,{children:e.jsxs(se.Content,{className:"p-0",children:[e.jsxs("div",{className:"flex items-center justify-between border-b border-[var(--otari-line)] px-4 py-2",children:[e.jsx("span",{className:"text-sm font-medium text-[var(--otari-ink)]",children:"Edit pricing"}),e.jsx(A,{size:"sm",variant:"ghost",onPress:()=>h(null),children:"Close"})]}),e.jsx(Xt,{row:Ie,onClose:()=>h(null)})]})}):null,e.jsx(Lt,{page:ke,pageSize:k,total:J,rowsOnPage:fe.length,onPageChange:j,onPageSizeChange:a=>{T(a),j(0)},pageSizeOptions:[15,25,50]})]}),ne?e.jsx("aside",{className:"lg:sticky lg:top-4",children:e.jsx(qt,{row:ne,metadata:F[ne.key],metadataAvailable:nt,onMakeAlias:a=>t(`/aliases?target=${encodeURIComponent(a)}`),onClose:()=>O(null)})}):null]}),e.jsx(At,{isOpen:Ue,onOpenChange:ue,targetCount:We,isPending:Ge,error:Je,onSubmit:mt,title:"Set pricing",description:a=>`Apply these per-1M rates to ${a.toLocaleString()} selected ${a===1?"model":"models"}. This replaces each model's price; pricing tiers and the 1h cache rate are cleared. Edit a single model for tiers.`})]})}export{pi as ModelsPage}; +import{j as e}from"./tanstack-query-1t81HyiD.js";import{i as gt,u as vt,r as c}from"./react-dgEcD0HR.js";import{G as _t,H as bt,l as jt,J as yt,K as je,P as Pt,E as Nt,F as K,I as St,L as ae,M as Re,o as we,N as be,O as Ct,Q as kt,S as E}from"./index-Bi2hajrg.js";import{u as Mt,r as Wt,B as It}from"./tableSelection-9hV37uhu.js";import{D as Tt}from"./DataTable-Bmn_eYSV.js";import{T as Lt,S as $t}from"./TablePagination-8CBn4us4.js";import{B as $,d as se,f as V}from"./heroui-BI50yK5B.js";function Oe(t){const i=t.indexOf(":");return i>0?t.slice(0,i):"—"}function At(t,i=Date.now()){const r=new Map;for(const n of t){const l=r.get(n.model_key)??[];l.push(n),r.set(n.model_key,l)}const s=[];for(const n of r.values()){const l=[...n].sort((p,u)=>Date.parse(p.effective_at)-Date.parse(u.effective_at)),m=[...l].reverse().find(p=>Date.parse(p.effective_at)<=i);s.push(m??l[0])}return s.sort((n,l)=>n.model_key.localeCompare(l.model_key))}const Et="otari",De=[{value:"vision",label:"Vision",test:t=>Array.isArray(t.input_modalities)&&t.input_modalities.includes("image")},{value:"tool_call",label:"Tool calling",test:t=>!!t.tool_call},{value:"reasoning",label:"Reasoning",test:t=>!!t.reasoning},{value:"structured_output",label:"Structured output",test:t=>!!t.structured_output},{value:"attachment",label:"Attachments",test:t=>!!t.attachment},{value:"audio",label:"Audio",test:t=>Array.isArray(t.input_modalities)&&t.input_modalities.includes("audio")},{value:"pdf",label:"PDF",test:t=>Array.isArray(t.input_modalities)&&t.input_modalities.includes("pdf")}],Ot=[{key:"reasoning",label:"Reasoning"},{key:"tool_call",label:"Tool calling"},{key:"structured_output",label:"Structured output"},{key:"attachment",label:"Attachments"},{key:"temperature",label:"Temperature"}],Fe={text:"Text",image:"Image",audio:"Audio",video:"Video",pdf:"PDF"},Dt=[{value:"0",label:"Any context"},{value:"8000",label:"≥ 8K"},{value:"32000",label:"≥ 32K"},{value:"128000",label:"≥ 128K"},{value:"200000",label:"≥ 200K"},{value:"1000000",label:"≥ 1M"}],Ft=[{value:"",label:"Any price"},{value:"1",label:"≤ $1 / 1M in"},{value:"3",label:"≤ $3 / 1M in"},{value:"10",label:"≤ $10 / 1M in"},{value:"30",label:"≤ $30 / 1M in"}],Kt=[{value:"",label:"Base prices"},{value:"8000",label:"Compare at 8K"},{value:"128000",label:"Compare at 128K"},{value:"200000",label:"Compare at 200K"},{value:"500000",label:"Compare at 500K"},{value:"1000000",label:"Compare at 1M"}],Bt=[{value:"all",label:"Any release date"},{value:"365",label:"Past year"},{value:"730",label:"Past 2 years"},{value:"1095",label:"Past 3 years"}],Rt=1440*60*1e3,wt=t=>t.key;function Ke(t,i){const r=`${i}:`;return t.startsWith(r)?t.slice(r.length):t}function Be(t,i){const r={inputPrice:t.inputPrice,outputPrice:t.outputPrice,cacheReadPrice:t.cacheReadPrice,cacheWritePrice:t.cacheWritePrice,cacheWrite1hPrice:t.cacheWrite1hPrice};if(i==null)return r;const s=t.pricingTiers.filter(n=>n.min_input_tokens<=i).sort((n,l)=>l.min_input_tokens-n.min_input_tokens)[0];return s?{inputPrice:s.input_price_per_million??r.inputPrice,outputPrice:s.output_price_per_million??r.outputPrice,cacheReadPrice:s.cache_read_price_per_million??r.cacheReadPrice,cacheWritePrice:s.cache_write_price_per_million??r.cacheWritePrice,cacheWrite1hPrice:s.cache_write_1h_price_per_million??r.cacheWrite1hPrice}:r}function ce(t){const i=Number(t);return t.trim()!==""&&Number.isFinite(i)&&i>=0}function z(t){if(t.trim()==="")return!0;const i=Number(t);return Number.isFinite(i)&&i>=0}function Y(t){return t.trim()===""?null:Number(t)}function ze(t){return t.map((i,r)=>({id:r,minInputTokens:String(i.min_input_tokens),input:i.input_price_per_million==null?"":String(i.input_price_per_million),output:i.output_price_per_million==null?"":String(i.output_price_per_million),cacheRead:i.cache_read_price_per_million==null?"":String(i.cache_read_price_per_million),cacheWrite:i.cache_write_price_per_million==null?"":String(i.cache_write_price_per_million),cacheWrite1h:i.cache_write_1h_price_per_million==null?"":String(i.cache_write_1h_price_per_million)}))}function Ve(t){const i=new Set;return t.every(r=>{const s=Number(r.minInputTokens),n=[r.input,r.output,r.cacheRead,r.cacheWrite,r.cacheWrite1h].some(l=>l.trim()!=="");return!Number.isInteger(s)||s<=0||i.has(s)||!n?!1:(i.add(s),[r.input,r.output,r.cacheRead,r.cacheWrite,r.cacheWrite1h].every(z))})}function Ye(t){return t.map(i=>({min_input_tokens:Number(i.minInputTokens),...i.input.trim()===""?{}:{input_price_per_million:Number(i.input)},...i.output.trim()===""?{}:{output_price_per_million:Number(i.output)},...i.cacheRead.trim()===""?{}:{cache_read_price_per_million:Number(i.cacheRead)},...i.cacheWrite.trim()===""?{}:{cache_write_price_per_million:Number(i.cacheWrite)},...i.cacheWrite1h.trim()===""?{}:{cache_write_1h_price_per_million:Number(i.cacheWrite1h)}}))}function b({value:t,onChange:i,ariaLabel:r}){return e.jsx("input",{type:"number",step:"any",min:"0",inputMode:"decimal","aria-label":r,value:t,onChange:s=>i(s.target.value),className:"w-28 rounded-md border border-[var(--otari-line)] bg-white px-2 py-1 text-right text-sm tabular-nums focus:border-[var(--otari-brand)] focus:outline-none"})}function qe({tiers:t,onChange:i}){const r=(n,l,m)=>{i(t.map(p=>p.id===n?{...p,[l]:m}:p))},s=()=>{const n=t.reduce((l,m)=>Math.max(l,m.id),-1)+1;i([...t,{id:n,minInputTokens:"128000",input:"",output:"",cacheRead:"",cacheWrite:"",cacheWrite1h:""}])};return e.jsxs("div",{className:"flex flex-col gap-2 rounded-lg border border-[var(--otari-line)] p-3",children:[e.jsxs("div",{className:"flex items-center justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-xs font-medium text-[var(--otari-ink)]",children:"Long-context price tiers"}),e.jsx("p",{className:"text-xs text-[var(--otari-muted)]",children:"At a threshold, listed rates replace the base rate for the whole request."})]}),e.jsx($,{size:"sm",variant:"outline",onPress:s,children:"Add tier"})]}),t.map(n=>e.jsxs("div",{className:"flex flex-wrap items-end gap-2 border-t border-[var(--otari-line)] pt-2",children:[e.jsxs("label",{className:"flex flex-col gap-1 text-xs text-[var(--otari-muted)]",children:["Context ≥ tokens",e.jsx("input",{type:"number",min:"1",step:"1",inputMode:"numeric","aria-label":"Tier context threshold",value:n.minInputTokens,onChange:l=>r(n.id,"minInputTokens",l.target.value),className:"w-28 rounded-md border border-[var(--otari-line)] bg-white px-2 py-1 text-right text-sm tabular-nums focus:border-[var(--otari-brand)] focus:outline-none"})]}),e.jsxs("label",{className:"flex flex-col gap-1 text-xs text-[var(--otari-muted)]",children:["Input",e.jsx(b,{value:n.input,onChange:l=>r(n.id,"input",l),ariaLabel:"Tier input price"})]}),e.jsxs("label",{className:"flex flex-col gap-1 text-xs text-[var(--otari-muted)]",children:["Output",e.jsx(b,{value:n.output,onChange:l=>r(n.id,"output",l),ariaLabel:"Tier output price"})]}),e.jsxs("label",{className:"flex flex-col gap-1 text-xs text-[var(--otari-muted)]",children:["Cache read",e.jsx(b,{value:n.cacheRead,onChange:l=>r(n.id,"cacheRead",l),ariaLabel:"Tier cache read price"})]}),e.jsxs("label",{className:"flex flex-col gap-1 text-xs text-[var(--otari-muted)]",children:["Cache write",e.jsx(b,{value:n.cacheWrite,onChange:l=>r(n.id,"cacheWrite",l),ariaLabel:"Tier cache write price"})]}),e.jsxs("label",{className:"flex flex-col gap-1 text-xs text-[var(--otari-muted)]",children:["1h write",e.jsx(b,{value:n.cacheWrite1h,onChange:l=>r(n.id,"cacheWrite1h",l),ariaLabel:"Tier 1 hour cache write price"})]}),e.jsx($,{size:"sm",variant:"ghost",onPress:()=>i(t.filter(l=>l.id!==n.id)),children:"Remove"})]},n.id))]})}function zt({source:t}){return t==="configured"?e.jsx(V,{size:"sm",color:"default",children:"configured"}):t==="default"||t==="alias"?e.jsx(V,{size:"sm",color:"accent",children:t}):e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"not priced"})}function oe({label:t,tone:i="info",children:r}){const s=c.useId();return e.jsxs("span",{className:"group relative inline-flex items-center font-normal normal-case",children:[e.jsx("button",{type:"button","aria-label":t,"aria-describedby":s,className:`inline-flex h-4 w-4 items-center justify-center rounded-full border text-[10px] leading-none ${i==="warning"?"border-[#c2843a] text-[#b45309]":"border-[var(--otari-line)] text-[var(--otari-muted)] hover:border-[var(--otari-brand)] hover:text-[var(--otari-brand)]"}`,children:"i"}),e.jsx("span",{id:s,role:"tooltip",className:"pointer-events-none absolute top-full right-0 z-20 mt-1.5 w-72 rounded-lg border border-[var(--otari-line)] bg-[var(--otari-surface)] px-3 py-2 text-left text-xs font-normal whitespace-normal break-words text-[var(--otari-ink)] opacity-0 shadow-lg transition-opacity group-hover:opacity-100 group-focus-within:opacity-100",children:r})]})}function Vt(){const t=kt();return t.data?t.data.default_pricing?e.jsx(oe,{label:"How unpriced models are metered",tone:"info",children:"Default pricing is on: models without a configured price are metered using community-maintained rates (the bundled genai-prices dataset). Set a price to override the fallback."}):e.jsxs(oe,{label:"How unpriced models are metered",tone:"warning",children:["Default pricing is off: only models with a configured price are metered.",t.data.require_pricing?" Requests for any other model are rejected (HTTP 402) because require_pricing is on.":" Other models are served without cost tracking."]}):null}function I({label:t,value:i}){return e.jsxs("div",{className:"flex items-baseline justify-between gap-3",children:[e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:t}),e.jsx("span",{className:"text-right text-sm text-[var(--otari-ink)] tabular-nums",children:i})]})}function le({title:t,children:i}){return e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("span",{className:"text-xs font-semibold uppercase tracking-wide text-[var(--otari-muted)]",children:t}),i]})}function Yt({row:t}){const i=je(),r=Re(),[s,n]=c.useState(!1),[l,m]=c.useState(""),[p,u]=c.useState(""),[P,j]=c.useState(""),[k,T]=c.useState(""),[y,h]=c.useState(""),[N,O]=c.useState([]),S=()=>{m(t.inputPrice==null?"":String(t.inputPrice)),u(t.outputPrice==null?"":String(t.outputPrice)),j(t.cacheReadPrice==null?"":String(t.cacheReadPrice)),T(t.cacheWritePrice==null?"":String(t.cacheWritePrice)),h(t.cacheWrite1hPrice==null?"":String(t.cacheWrite1hPrice)),O(ze(t.pricingTiers)),n(!0)},X=ce(l)&&ce(p)&&z(P)&&z(k)&&z(y)&&Ve(N),W=()=>{X&&i.mutate({model_key:t.key,input_price_per_million:Number(l),output_price_per_million:Number(p),cache_read_price_per_million:Y(P),cache_write_price_per_million:Y(k),cache_write_1h_price_per_million:Y(y),pricing_tiers:Ye(N)},{onSuccess:()=>n(!1)})};return s?e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsxs("div",{className:"flex items-center justify-between gap-2",children:[e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"Input $ / 1M"}),e.jsx(b,{value:l,onChange:m,ariaLabel:`Input price for ${t.key}`})]}),e.jsxs("div",{className:"flex items-center justify-between gap-2",children:[e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"Output $ / 1M"}),e.jsx(b,{value:p,onChange:u,ariaLabel:`Output price for ${t.key}`})]}),e.jsxs("div",{className:"flex items-center justify-between gap-2",children:[e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"Cache read $ / 1M"}),e.jsx(b,{value:P,onChange:j,ariaLabel:`Cache read price for ${t.key}`})]}),e.jsxs("div",{className:"flex items-center justify-between gap-2",children:[e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"Cache write $ / 1M"}),e.jsx(b,{value:k,onChange:T,ariaLabel:`Cache write price for ${t.key}`})]}),e.jsxs("div",{className:"flex items-center justify-between gap-2",children:[e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"1h cache write $ / 1M"}),e.jsx(b,{value:y,onChange:h,ariaLabel:`1 hour cache write price for ${t.key}`})]}),e.jsx(qe,{tiers:N,onChange:O}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx($,{size:"sm",variant:"primary",isDisabled:i.isPending||!X,onPress:W,children:"Save"}),e.jsx($,{size:"sm",variant:"ghost",isDisabled:i.isPending,onPress:()=>n(!1),children:"Cancel"})]}),i.error?e.jsx("span",{className:"text-xs text-red-700",children:be(i.error)}):null]}):e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx(I,{label:"Input",value:t.inputPrice==null?"—":`${E(t.inputPrice)} / 1M`}),e.jsx(I,{label:"Output",value:t.outputPrice==null?"—":`${E(t.outputPrice)} / 1M`}),e.jsx(I,{label:"Cache read",value:t.cacheReadPrice==null?"—":`${E(t.cacheReadPrice)} / 1M`}),e.jsx(I,{label:"Cache write",value:t.cacheWritePrice==null?"—":`${E(t.cacheWritePrice)} / 1M`}),e.jsx(I,{label:"1h cache write",value:t.cacheWrite1hPrice==null?"—":`${E(t.cacheWrite1hPrice)} / 1M`}),e.jsx(I,{label:"Context tiers",value:t.pricingTiers.length?`${t.pricingTiers.length} configured`:"—"}),e.jsxs("div",{className:"flex items-center gap-2 pt-1",children:[e.jsx($,{size:"sm",variant:"outline",onPress:S,children:t.source==="configured"?"Edit price":"Set price"}),t.source==="configured"?e.jsxs(e.Fragment,{children:[e.jsx(we,{confirmLabel:"Reset",isPending:r.isPending,onConfirm:()=>r.mutate(t.key),children:"Reset"}),e.jsx(oe,{label:"What reset does",children:"Removes the custom price. The model reverts to the default rate (genai-prices) when default pricing is on, otherwise it is metered at no cost."})]}):null,r.error?e.jsx("span",{className:"text-xs text-red-700",children:be(r.error)}):null]})]})}function qt({row:t,metadata:i,metadataAvailable:r,onMakeAlias:s,onClose:n}){const l=(i==null?void 0:i.input_modalities)??[],m=(i==null?void 0:i.output_modalities)??[],p=Ot.filter(({key:u})=>i==null?void 0:i[u]);return e.jsx(se,{children:e.jsxs(se.Content,{className:"flex flex-col gap-5 p-5",children:[e.jsxs("div",{className:"flex items-start justify-between gap-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("h2",{className:"text-base font-semibold break-all text-[var(--otari-ink)]",children:t.model}),i!=null&&i.deprecated?e.jsx(V,{size:"sm",color:"danger",children:"deprecated"}):null]}),e.jsxs("p",{className:"mt-1 text-xs break-all text-[var(--otari-muted)]",children:["Selector: ",e.jsx("code",{children:t.key})]}),i!=null&&i.family?e.jsx("p",{className:"text-xs text-[var(--otari-muted)]",children:i.family}):null]}),e.jsx("button",{type:"button","aria-label":"Close model details",onClick:n,className:"-mt-1 -mr-1 shrink-0 rounded-md px-1.5 py-0.5 text-lg leading-none text-[var(--otari-muted)] hover:bg-[var(--otari-bg)] hover:text-[var(--otari-ink)]",children:"✕"})]}),i!=null&&i.description?e.jsx("p",{className:"text-sm text-[var(--otari-ink)]",children:i.description}):null,e.jsxs(le,{title:"Pricing",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(zt,{source:t.source}),t.isDiscovered?null:e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"not discovered"})]}),e.jsx(Yt,{row:t},t.key),e.jsx($,{size:"sm",variant:"outline",onPress:()=>s(t.key),children:"Make an alias"})]}),e.jsxs(le,{title:"Specs",children:[e.jsx(I,{label:"Context window",value:ae(t.contextWindow)}),e.jsx(I,{label:"Max output",value:ae((i==null?void 0:i.max_output_tokens)??null)}),e.jsx(I,{label:"Knowledge cutoff",value:(i==null?void 0:i.knowledge_cutoff)??"—"}),e.jsx(I,{label:"Released",value:Ct(i==null?void 0:i.release_date)}),e.jsx(I,{label:"Open weights",value:i?i.open_weights?"Yes":"No":"—"})]}),e.jsx(le,{title:"Modalities",children:l.length===0&&m.length===0?e.jsx("span",{className:"text-sm text-[var(--otari-muted)]",children:"Unknown."}):e.jsxs("div",{className:"flex flex-col gap-1.5 text-xs text-[var(--otari-muted)]",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-1",children:[e.jsx("span",{children:"In:"}),l.map(u=>e.jsx(V,{size:"sm",color:"default",children:Fe[u]??u},u))]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-1",children:[e.jsx("span",{children:"Out:"}),m.map(u=>e.jsx(V,{size:"sm",color:"default",children:Fe[u]??u},u))]})]})}),e.jsx(le,{title:"Capabilities",children:p.length>0?e.jsx("div",{className:"flex flex-wrap gap-1.5",children:p.map(({key:u,label:P})=>e.jsx(V,{size:"sm",color:"default",children:P},u))}):e.jsx("span",{className:"text-sm text-[var(--otari-muted)]",children:r?"None reported.":"Extended metadata unavailable (models.dev disabled or unreachable)."})})]})})}const Ht=15;function Ut({value:t,onChange:i,placeholder:r}){return e.jsx("input",{type:"search",value:t,onChange:s=>i(s.target.value),placeholder:r,"aria-label":r,className:"w-full max-w-xs rounded-md border border-[var(--otari-line)] bg-white px-3 py-1.5 text-sm focus:border-[var(--otari-brand)] focus:outline-none"})}const He="otari.dashboard.modelsSort",_e={col:"model",dir:"asc"},Gt=["model","released","input","output"];function Jt(){if(typeof window>"u")return _e;try{const t=window.localStorage.getItem(He);if(!t)return _e;const i=JSON.parse(t);if(Gt.includes(i.col)&&(i.dir==="asc"||i.dir==="desc"))return{col:i.col,dir:i.dir}}catch{}return _e}function Qt({row:t,onClose:i}){const r=je(),s=Re(),[n,l]=c.useState(t.inputPrice==null?"":String(t.inputPrice)),[m,p]=c.useState(t.outputPrice==null?"":String(t.outputPrice)),[u,P]=c.useState(t.cacheReadPrice==null?"":String(t.cacheReadPrice)),[j,k]=c.useState(t.cacheWritePrice==null?"":String(t.cacheWritePrice)),[T,y]=c.useState(t.cacheWrite1hPrice==null?"":String(t.cacheWrite1hPrice)),[h,N]=c.useState(ze(t.pricingTiers)),O=ce(n)&&ce(m)&&z(u)&&z(j)&&z(T)&&Ve(h),S=()=>{O&&r.mutate({model_key:t.key,input_price_per_million:Number(n),output_price_per_million:Number(m),cache_read_price_per_million:Y(u),cache_write_price_per_million:Y(j),cache_write_1h_price_per_million:Y(T),pricing_tiers:Ye(h)},{onSuccess:i})};return e.jsxs("div",{className:"flex flex-col gap-3 px-4 py-3",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsx("span",{className:"text-xs font-medium break-all text-[var(--otari-muted)]",children:t.key}),e.jsxs("label",{className:"flex items-center gap-1.5 text-xs text-[var(--otari-muted)]",children:["Input $ / 1M",e.jsx(b,{value:n,onChange:l,ariaLabel:`Input price for ${t.key}`})]}),e.jsxs("label",{className:"flex items-center gap-1.5 text-xs text-[var(--otari-muted)]",children:["Output $ / 1M",e.jsx(b,{value:m,onChange:p,ariaLabel:`Output price for ${t.key}`})]}),e.jsxs("label",{className:"flex items-center gap-1.5 text-xs text-[var(--otari-muted)]",children:["Cache read $ / 1M",e.jsx(b,{value:u,onChange:P,ariaLabel:`Cache read price for ${t.key}`})]}),e.jsxs("label",{className:"flex items-center gap-1.5 text-xs text-[var(--otari-muted)]",children:["Cache write $ / 1M",e.jsx(b,{value:j,onChange:k,ariaLabel:`Cache write price for ${t.key}`})]}),e.jsxs("label",{className:"flex items-center gap-1.5 text-xs text-[var(--otari-muted)]",children:["1h cache write $ / 1M",e.jsx(b,{value:T,onChange:y,ariaLabel:`1 hour cache write price for ${t.key}`})]}),e.jsx($,{size:"sm",variant:"primary",isDisabled:r.isPending||!O,onPress:S,children:r.isPending?"Saving…":"Save"}),e.jsx($,{size:"sm",variant:"ghost",isDisabled:r.isPending,onPress:i,children:"Cancel"}),t.source==="configured"?e.jsxs("span",{className:"inline-flex items-center gap-1",children:[e.jsx(we,{confirmLabel:"Reset",isPending:s.isPending,onConfirm:()=>s.mutate(t.key,{onSuccess:i}),children:"Reset"}),e.jsx(oe,{label:"What reset does",children:"Removes the custom price. The model reverts to the default rate (genai-prices) when default pricing is on, otherwise it is metered at no cost."})]}):null,r.error||s.error?e.jsx("span",{className:"text-xs text-red-700",children:be(r.error??s.error)}):null]}),e.jsx(qe,{tiers:h,onChange:N})]})}function Xt({primary:t,secondary:i,rowKey:r,primaryLabel:s,secondaryLabel:n,onEdit:l}){const m=(p,u)=>e.jsx("button",{type:"button","aria-label":`Edit ${u} price for ${r}`,className:"tabular-nums hover:text-[var(--otari-brand-dark)] hover:underline",onClick:P=>{P.stopPropagation(),l()},children:p==null?"—":E(p)});return e.jsxs("span",{className:"inline-flex items-center justify-end gap-1",children:[m(t,s),e.jsx("span",{className:"text-[var(--otari-muted)]",children:"/"}),m(i,n)]})}function Zt({rates:t,rowKey:i,onEdit:r}){const s=[t.cacheReadPrice==null?null:`R ${E(t.cacheReadPrice)}`,t.cacheWritePrice==null?null:`W ${E(t.cacheWritePrice)}`,t.cacheWrite1hPrice==null?null:`1h ${E(t.cacheWrite1hPrice)}`].filter(n=>n!==null);return e.jsx("button",{type:"button","aria-label":`Edit caching price for ${i}`,className:"max-w-44 text-right text-xs leading-5 text-[var(--otari-muted)] hover:text-[var(--otari-brand-dark)] hover:underline",onClick:n=>{n.stopPropagation(),r()},children:s.length>0?s.join(" · "):"Input-rate fallback"})}function ei({row:t,onEdit:i}){const r=[...t.pricingTiers].sort((n,l)=>n.min_input_tokens-l.min_input_tokens).map(n=>ae(n.min_input_tokens)),s=r.length===0?"Base only":`${r.length} tier${r.length===1?"":"s"} · ≥ ${r.join(", ")}`;return e.jsx("button",{type:"button","aria-label":`Edit pricing policy for ${t.key}`,className:"max-w-40 text-right text-xs leading-5 text-[var(--otari-muted)] hover:text-[var(--otari-brand-dark)] hover:underline",onClick:n=>{n.stopPropagation(),i()},children:s})}function ti({rows:t,isLoading:i,empty:r,sortDescriptor:s,onSortChange:n,selectedKey:l,onSelect:m,onEditPricing:p,comparisonContextTokens:u,selectedKeys:P,onSelectionChange:j}){const k=c.useMemo(()=>{const y=u==null?"Base":`at ${ae(u)}`;return[{id:"model",header:"Model",isRowHeader:!0,allowsSorting:!0,cell:h=>e.jsxs("span",{className:"font-medium break-all",children:[h.model,e.jsx("span",{className:"sr-only",children:h.key})]})},{id:"provider",header:"Provider",cell:h=>e.jsx("span",{className:"text-[var(--otari-muted)]",children:h.provider})},{id:"input",header:e.jsxs("span",{className:"inline-flex items-center gap-1",children:[`${y} in / out $ / 1M`,e.jsx(Vt,{})]}),align:"end",allowsSorting:!0,cell:h=>{const N=Be(h,u);return e.jsx(Xt,{primary:N.inputPrice,secondary:N.outputPrice,rowKey:h.key,primaryLabel:"input",secondaryLabel:"output",onEdit:()=>p(h.key)})}},{id:"caching",header:`Caching ${u==null?"policy":y}`,align:"end",cell:h=>e.jsx(Zt,{rates:Be(h,u),rowKey:h.key,onEdit:()=>p(h.key)})},{id:"policy",header:"Pricing policy",align:"end",cell:h=>e.jsx(ei,{row:h,onEdit:()=>p(h.key)})}]},[u,p]),T=c.useCallback(y=>y.key===l?"bg-[var(--otari-brand-tint)]":void 0,[l]);return e.jsx(Tt,{ariaLabel:"Models",columns:k,rows:t,getRowKey:wt,isLoading:i,emptyContent:r,selectionMode:"multiple",selectedKeys:P,onSelectionChange:j,sortDescriptor:s,onSortChange:n,onRowAction:m,rowClassName:T})}function ii({providers:t}){if(t.length===0)return null;const i=t.filter(l=>!l.discovery_unsupported),r=t.filter(l=>l.discovery_unsupported),s=l=>l.map(m=>m.provider).join(", "),n=l=>l.length===1;return e.jsxs(St,{tone:"warning",children:[i.length>0?e.jsxs("span",{className:"block",children:["Could not list ",s(i),". Check ",n(i)?"that provider's":"those providers'"," ","credentials in config.yml; ",n(i)?"its":"their"," models are missing from the list below."]}):null,r.length>0?e.jsxs("span",{className:"block",children:[s(r)," ",n(r)?"does":"do"," not offer model discovery, so"," ",n(r)?"its":"their"," models are missing from the list below."," ",n(r)?"The provider":"They"," may still serve requests; declare the model ids"," ",n(r)?"it serves":"they serve"," under the ",e.jsx("code",{children:"models:"})," key in config.yml to list them here."]}):null]})}function pi(){var Te,Le,$e;const t=gt(),[i]=vt(),r=_t(),s=bt(),n=jt(),l=yt(),m=je(),[p,u]=c.useState(""),[P,j]=c.useState(0),[k,T]=c.useState(Ht),[y,h]=c.useState(null),[N,O]=c.useState(null),[S,X]=c.useState(Jt),W=Mt(),[Ue,ue]=c.useState(!1),[Ge,ye]=c.useState(!1),[Je,Pe]=c.useState(void 0);c.useEffect(()=>{try{window.localStorage.setItem(He,JSON.stringify(S))}catch{}},[S]);const[D,Ne]=c.useState(i.get("provider")||"all"),[B,Qe]=c.useState("all"),[q,Xe]=c.useState("all"),[H,Ze]=c.useState("all"),[de,et]=c.useState("0"),[Z,tt]=c.useState(""),[ee,it]=c.useState("all"),[pe,rt]=c.useState(""),F=((Te=l.data)==null?void 0:Te.models)??{},nt=((Le=l.data)==null?void 0:Le.available)??!1,Se=c.useMemo(()=>{var a;return new Set((((a=n.data)==null?void 0:a.providers)??[]).flatMap(x=>x.models.map(o=>o.key)))},[n.data]),lt=a=>{u(a),j(0)},R=a=>x=>{a(x),j(0)},te=c.useMemo(()=>{var M,v,_,A,L,w,Ae;const a=new Map(At(s.data??[]).map(d=>[d.model_key,d])),x=[],o=new Set,g=(d,ve,Ee,f)=>{if(o.has(d))return;o.add(d);const C=a.get(d);x.push({key:d,model:Ke(ve,Ee),provider:Ee,isDiscovered:Se.has(d),contextWindow:(f==null?void 0:f.contextWindow)??null,inputPrice:C?C.input_price_per_million:(f==null?void 0:f.inputPrice)??null,outputPrice:C?C.output_price_per_million:(f==null?void 0:f.outputPrice)??null,cacheReadPrice:C?C.cache_read_price_per_million:(f==null?void 0:f.cacheReadPrice)??null,cacheWritePrice:C?C.cache_write_price_per_million:(f==null?void 0:f.cacheWritePrice)??null,cacheWrite1hPrice:C?C.cache_write_1h_price_per_million??null:(f==null?void 0:f.cacheWrite1hPrice)??null,pricingTiers:C?C.pricing_tiers??[]:(f==null?void 0:f.pricingTiers)??[],source:C?"configured":(f==null?void 0:f.source)??"none"})};for(const d of((M=r.data)==null?void 0:M.data)??[]){if(d.owned_by===Et)continue;const ve=d.pricing_source==="default"?"default":d.pricing?"configured":"none";g(d.id,d.id,d.owned_by||Oe(d.id),{key:d.id,model:d.id,provider:d.owned_by,contextWindow:d.context_window,inputPrice:((v=d.pricing)==null?void 0:v.input_price_per_million)??null,outputPrice:((_=d.pricing)==null?void 0:_.output_price_per_million)??null,cacheReadPrice:((A=d.pricing)==null?void 0:A.cache_read_price_per_million)??null,cacheWritePrice:((L=d.pricing)==null?void 0:L.cache_write_price_per_million)??null,cacheWrite1hPrice:((w=d.pricing)==null?void 0:w.cache_write_1h_price_per_million)??null,pricingTiers:((Ae=d.pricing)==null?void 0:Ae.pricing_tiers)??[],source:ve})}for(const d of a.keys())g(d,d,Oe(d));return x},[r.data,s.data,Se]),Ce=c.useMemo(()=>new Map(te.map(a=>[a.key,a])),[te]),ie=c.useMemo(()=>{var o,g,M;const a=te.map(v=>{var _,A;return{...v,contextWindow:v.contextWindow??((_=F[v.key])==null?void 0:_.context_window)??null,releaseDate:((A=F[v.key])==null?void 0:A.release_date)??null}}),x=new Set(a.map(v=>v.key));for(const v of((o=n.data)==null?void 0:o.providers)??[])for(const _ of v.models)x.has(_.key)||(x.add(_.key),a.push({key:_.key,model:Ke(_.key,v.provider),provider:v.provider,isDiscovered:!0,contextWindow:((g=F[_.key])==null?void 0:g.context_window)??null,releaseDate:((M=F[_.key])==null?void 0:M.release_date)??null,inputPrice:null,outputPrice:null,cacheReadPrice:null,cacheWritePrice:null,cacheWrite1hPrice:null,pricingTiers:[],source:"none"}));return a},[te,n.data,F]),at=((($e=n.data)==null?void 0:$e.providers)??[]).filter(a=>!a.ok),re=c.useMemo(()=>{const a=Array.from(new Set(ie.map(x=>x.provider))).sort((x,o)=>x.localeCompare(o));return[{value:"all",label:"All providers"},...a.map(x=>({value:x,label:x}))]},[ie]);c.useEffect(()=>{D==="all"||re.length<=1||re.some(a=>a.value===D)||Ne("all")},[re,D]);const U=p.trim().toLowerCase(),he=Number(de)||0,me=Z===""?Number.POSITIVE_INFINITY:Number(Z),st=pe===""?null:Number(pe),xe=ee==="all"?null:Date.now()-Number(ee)*Rt,G=c.useMemo(()=>{const a=o=>{if(U&&!o.key.toLowerCase().includes(U)&&!o.provider.toLowerCase().includes(U)||D!=="all"&&o.provider!==D||B==="configured"&&o.source!=="configured"||B==="default"&&o.source!=="default"||B==="priced"&&o.inputPrice==null||B==="unpriced"&&o.inputPrice!=null||q==="discovered"&&!o.isDiscovered||q==="custom"&&o.isDiscovered)return!1;if(H!=="all"){const g=De.find(v=>v.value===H),M=F[o.key];if(!g||!M||!g.test(M))return!1}if(he>0&&(o.contextWindow==null||o.contextWindowme))return!1;if(xe!=null){const g=o.releaseDate?Date.parse(o.releaseDate):Number.NaN;if(Number.isNaN(g)||g{const M=S.dir==="asc"?1:-1;if(S.col==="model")return o.model.localeCompare(g.model)*M;if(S.col==="released"){const L=o.releaseDate??null,w=g.releaseDate??null;return!L&&!w?o.model.localeCompare(g.model):L?w?(Lw?1:0)*M||o.model.localeCompare(g.model):-1:1}const v=L=>S.col==="input"?L.inputPrice:L.outputPrice,_=v(o),A=v(g);return _==null&&A==null?o.model.localeCompare(g.model):_==null?1:A==null?-1:(_-A)*M||o.model.localeCompare(g.model)};return ie.filter(a).sort(x)},[ie,U,D,B,q,H,he,me,xe,F,S]),J=G.length,ct=Math.max(1,Math.ceil(J/k)),ke=Math.min(P,ct-1),Me=ke*k,fe=G.slice(Me,Me+k),ot={column:S.col,direction:S.dir==="asc"?"ascending":"descending"},ut=a=>{X({col:String(a.column),dir:a.direction==="ascending"?"asc":"desc"}),j(0)},dt=c.useCallback(a=>h(x=>x===a?null:a),[]),ge=fe.map(a=>a.key),Q=Wt(W.selectedKeys,ge),pt=ge.length>0&&Q.length===ge.length&&J>Q.length,ht=W.allMatching?G.map(a=>a.key):Q,We=W.allMatching?J:Q.length,Ie=y?G.find(a=>a.key===y)??Ce.get(y)??null:null,mt=async a=>{ye(!0),Pe(void 0);try{for(const x of ht)await m.mutateAsync({model_key:x,input_price_per_million:a.input_price_per_million,output_price_per_million:a.output_price_per_million,cache_read_price_per_million:a.cache_read_price_per_million??null,cache_write_price_per_million:a.cache_write_price_per_million??null,cache_write_1h_price_per_million:null,pricing_tiers:[]});W.clear(),ue(!1)}catch(x){Pe(x)}finally{ye(!1)}},xt=r.isLoading||s.isLoading||n.isLoading,ft=U!==""||D!=="all"||B!=="all"||q!=="all"||H!=="all"||de!=="0"||Z!==""||ee!=="all"?"No models match your filters.":"No models yet. Add a provider on the Providers page, or price a model below.",ne=N?G.find(a=>a.key===N)??Ce.get(N)??null:null;return e.jsxs("div",{className:"flex flex-col gap-6",children:[e.jsx(Pt,{title:"Models",description:"Every model your providers can serve. Set a price on any model so budgets and usage tracking work."}),e.jsx(Nt,{error:r.error??s.error??n.error??l.error}),e.jsxs("div",{className:`grid gap-4 lg:items-start ${ne?"lg:grid-cols-[minmax(0,1fr)_360px]":"grid-cols-1"}`,children:[e.jsxs("div",{className:"flex min-w-0 flex-col gap-3",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx(Ut,{value:p,onChange:lt,placeholder:"Search models…"}),e.jsx(K,{ariaLabel:"Filter by provider",value:D,onChange:R(Ne),options:re}),e.jsx(K,{ariaLabel:"Filter by pricing",value:B,onChange:R(Qe),options:[{value:"all",label:"Any pricing"},{value:"configured",label:"Custom price"},{value:"default",label:"Default price"},{value:"priced",label:"Priced"},{value:"unpriced",label:"Unpriced"}]}),e.jsx(K,{ariaLabel:"Filter by source",value:q,onChange:R(Xe),options:[{value:"all",label:"Any source"},{value:"discovered",label:"Discovered"},{value:"custom",label:"Custom (not discovered)"}]}),e.jsx(K,{ariaLabel:"Filter by capability",value:H,onChange:R(Ze),options:[{value:"all",label:"Any capability"},...De.map(a=>({value:a.value,label:a.label}))]}),e.jsx(K,{ariaLabel:"Minimum context window",value:de,onChange:R(et),options:Dt}),e.jsx(K,{ariaLabel:"Maximum input price",value:Z,onChange:R(tt),options:Ft}),e.jsx(K,{ariaLabel:"Compare prices at context",value:pe,onChange:rt,options:Kt}),e.jsx(K,{ariaLabel:"Filter by release date",value:ee,onChange:R(it),options:Bt})]}),e.jsx(ii,{providers:at}),Q.length>0?e.jsx(It,{selectedCount:We,allMatching:W.allMatching,matchingTotal:J,canSelectAllMatching:pt,onSelectAllMatching:W.enableAllMatching,onClear:W.clear,children:e.jsx($,{size:"sm",variant:"primary",onPress:()=>ue(!0),children:"Set pricing"})}):null,e.jsx(ti,{rows:fe,isLoading:xt,empty:ft,sortDescriptor:ot,onSortChange:ut,selectedKey:N,onSelect:O,onEditPricing:dt,comparisonContextTokens:st,selectedKeys:W.selectedKeys,onSelectionChange:W.onSelectionChange}),Ie?e.jsx(se,{children:e.jsxs(se.Content,{className:"p-0",children:[e.jsxs("div",{className:"flex items-center justify-between border-b border-[var(--otari-line)] px-4 py-2",children:[e.jsx("span",{className:"text-sm font-medium text-[var(--otari-ink)]",children:"Edit pricing"}),e.jsx($,{size:"sm",variant:"ghost",onPress:()=>h(null),children:"Close"})]}),e.jsx(Qt,{row:Ie,onClose:()=>h(null)})]})}):null,e.jsx(Lt,{page:ke,pageSize:k,total:J,rowsOnPage:fe.length,onPageChange:j,onPageSizeChange:a=>{T(a),j(0)},pageSizeOptions:[15,25,50]})]}),ne?e.jsx("aside",{className:"lg:sticky lg:top-4",children:e.jsx(qt,{row:ne,metadata:F[ne.key],metadataAvailable:nt,onMakeAlias:a=>t(`/aliases?target=${encodeURIComponent(a)}`),onClose:()=>O(null)})}):null]}),e.jsx($t,{isOpen:Ue,onOpenChange:ue,targetCount:We,isPending:Ge,error:Je,onSubmit:mt,title:"Set pricing",description:a=>`Apply these per-1M rates to ${a.toLocaleString()} selected ${a===1?"model":"models"}. This replaces each model's price; pricing tiers and the 1h cache rate are cleared. Edit a single model for tiers.`})]})}export{pi as ModelsPage}; diff --git a/src/gateway/static/dashboard/assets/OverviewPage-CW42wjoO.js b/src/gateway/static/dashboard/assets/OverviewPage-CW42wjoO.js deleted file mode 100644 index 50fe10e0..00000000 --- a/src/gateway/static/dashboard/assets/OverviewPage-CW42wjoO.js +++ /dev/null @@ -1 +0,0 @@ -import{j as t}from"./tanstack-query-1t81HyiD.js";import{r as y,i as st,N as I}from"./react-dgEcD0HR.js";import{L as at,M as nt,d as j,N as ot,l as it,a as lt,u as dt,b as ct,O as w,P as ut,R as mt,E as Y,S as b,Q as _,T as N,U as R,V as D,W as vt}from"./index-D4f8RVEq.js";import{S as H}from"./charts-DIsd9m--.js";import{D as ht}from"./DataTable-Bmn_eYSV.js";import{d as M,B as xt}from"./heroui-BI50yK5B.js";import"./recharts-C4kRDmvS.js";function B(e){return e==="neutral"?void 0:e}const ft=.02,pt=.1;function W(e){if(!e||e.request_count===0)return{rate:null,status:"neutral"};const n=e.error_count/e.request_count,s=n>=pt?"alert":n>=ft?"warn":"ok";return{rate:n,status:s}}function gt(e){return!e||e.total===0?"neutral":e.healthy>=e.total?"ok":e.healthy+e.degraded===0?"alert":"warn"}const bt=.8;function yt(e){if(e.length===0)return{status:"neutral",label:"No budgets configured",overCount:0,nearCount:0,cappedCount:0};const n=e.filter(o=>o.max_budget!==null&&o.user_count>0);if(n.length===0)return{status:"neutral",label:"No capped budgets",overCount:0,nearCount:0,cappedCount:0};let s=0,l=0,r,m=-1;for(const o of n){const a=o.max_budget*o.user_count,i=a>0?o.total_spend/a:0;i>=1?s+=1:i>=bt&&(l+=1),i>m&&(m=i,r={name:o.name??o.budget_id,spent:o.total_spend,allocated:a,pct:i})}const d=s>0?"alert":l>0?"warn":"ok",h=s>0?`${s} over limit`:l>0?`${l} near limit`:"All within budget";return{status:d,label:h,overCount:s,nearCount:l,cappedCount:n.length,worst:r}}const K=864e5,T=30;function G(){const e=new Date;return`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,"0")}-${String(e.getDate()).padStart(2,"0")}`}function St(){const[e,n]=y.useState(G);return y.useEffect(()=>{const s=()=>{if(document.visibilityState==="visible"){const l=G();n(r=>r===l?r:l)}};return document.addEventListener("visibilitychange",s),window.addEventListener("focus",s),()=>{document.removeEventListener("visibilitychange",s),window.removeEventListener("focus",s)}},[]),y.useMemo(()=>{const s=Date.now(),l=new Date(s);return{today:new Date(l.getFullYear(),l.getMonth(),l.getDate()).toISOString(),periodStart:new Date(s-T*K).toISOString(),prevStart:new Date(s-2*T*K).toISOString()}},[e])}const jt={ok:"Healthy",warn:"Elevated",alert:"High"},wt={ok:"On track",warn:"Near limit",alert:"Over budget"};function Ut(){const e=at();return e.isLoading?t.jsx(nt,{}):t.jsx(Nt,{needsSetup:e.isSuccess&&e.data.providers.length===0})}function Nt({needsSetup:e=!1}){var L,O,$,A,F,P,U,q;const n=St(),s=y.useMemo(()=>({start_date:n.today}),[n]),l=y.useMemo(()=>({start_date:n.periodStart}),[n]),r=y.useMemo(()=>({start_date:n.prevStart,end_date:n.periodStart}),[n]),m=j(s,"hour"),d=j(l,"day"),h=j(r,"day"),o=ot(),a=it(),i=lt(),x=dt(),f=ct({},0,5),E=(L=m.data)==null?void 0:L.totals,v=(O=d.data)==null?void 0:O.totals,p=($=h.data)==null?void 0:$.totals,S=((A=d.data)==null?void 0:A.series)??[],C=S.length>1,c=W(v),k=W(p),V=c.rate!==null&&k.rate!==null?w(c.rate,k.rate):null,u=yt(a.data??[]),Q=gt(o.data),z=(i.data??[]).filter(g=>g.is_active).length,J=(x.data??[]).filter(g=>!g.blocked).length,X=(((F=f.data)==null?void 0:F.length)??0)>0,Z=e&&f.isSuccess&&!X,tt=m.error??d.error??o.error??a.error??i.error??x.error,et=()=>{m.refetch(),d.refetch(),h.refetch(),o.refetch(),a.refetch(),i.refetch(),x.refetch(),f.refetch()},rt=m.isFetching||d.isFetching||h.isFetching||o.isFetching||a.isFetching||i.isFetching||x.isFetching||f.isFetching;return t.jsxs("div",{className:"flex flex-col gap-6",children:[t.jsx(ut,{title:"Overview",description:"At-a-glance spend, traffic, and health across the gateway.",action:t.jsx(mt,{onRefresh:et,isFetching:rt,updatedAt:d.dataUpdatedAt})}),Z?t.jsx(Rt,{}):null,t.jsx(Y,{error:tt}),t.jsx(Dt,{providerHealth:Q,healthy:((P=o.data)==null?void 0:P.healthy)??0,degraded:((U=o.data)==null?void 0:U.degraded)??0,total:((q=o.data)==null?void 0:q.total)??0,budget:u,errStatus:c.status,errRate:c.rate,ready:o.isSuccess&&a.isSuccess&&d.isSuccess,failed:o.isError||a.isError||d.isError}),t.jsxs("div",{className:"grid grid-cols-2 gap-4 sm:grid-cols-3 xl:grid-cols-4",children:[t.jsx(b,{label:"Spend today",value:E?_(E.cost):"—"}),t.jsx(b,{label:"Spend, last 30 days",value:v?_(v.cost):"—",hint:v?t.jsx(N,{fraction:w(v.cost,p==null?void 0:p.cost)}):null,chart:C?t.jsx(H,{values:S.map(g=>g.cost),ariaLabel:"Spend trend over the last 30 days"}):void 0}),t.jsx(b,{label:"Requests, last 30 days",value:v?R(v.request_count):"—",hint:v?t.jsx(N,{fraction:w(v.request_count,p==null?void 0:p.request_count)}):null,chart:C?t.jsx(H,{values:S.map(g=>g.requests),ariaLabel:"Request volume trend over the last 30 days"}):void 0}),t.jsx(b,{label:"Error rate, last 30 days",value:c.rate===null?"—":D(c.rate),status:B(c.status),statusLabel:c.status==="neutral"?void 0:jt[c.status],hint:c.rate!==null?t.jsx(N,{fraction:V}):null}),t.jsx(b,{label:"Budget health",value:a.data&&u.worst?D(u.worst.pct):"—",status:a.data?B(u.status):void 0,statusLabel:a.data&&u.status!=="neutral"?wt[u.status]:void 0,hint:a.data?u.worst?`${u.label} · worst: ${u.worst.name}`:u.label:void 0,to:"/budgets"}),t.jsx(b,{label:"Active keys",value:i.data?R(z):"—",to:"/keys"}),t.jsx(b,{label:"Active users",value:x.data?R(J):"—",to:"/users"})]}),t.jsx(Ct,{entries:f.data??[],loading:f.isLoading,error:f.error})]})}function Rt(){const e=st();return t.jsx(M,{children:t.jsxs(M.Content,{className:"flex flex-col gap-3 p-6",children:[t.jsxs("div",{children:[t.jsx("h2",{className:"text-lg font-semibold text-[var(--otari-ink)]",children:"Get started with Otari"}),t.jsx("p",{className:"mt-1 text-sm text-[var(--otari-muted)]",children:"Add a provider to begin serving models. Once it is configured, this page will show your gateway’s traffic, spend, and health."})]}),t.jsx("div",{children:t.jsx(xt,{variant:"primary",onPress:()=>e("/providers"),children:"Add your first provider"})})]})})}function _t({text:e}){return t.jsx("div",{role:"status",className:"flex items-center gap-2 rounded-xl border border-[var(--otari-line)] bg-[var(--otari-bg)] px-4 py-3 text-sm text-[var(--otari-muted)]",children:e})}function Dt({providerHealth:e,healthy:n,degraded:s,total:l,budget:r,errStatus:m,errRate:d,ready:h,failed:o}){if(o)return t.jsx(_t,{text:"Some status data could not be loaded."});if(!h)return null;const a=[];if((e==="warn"||e==="alert")&&l>0){const i=l-n-s;i>0&&a.push({text:`${i} provider${i===1?"":"s"} unreachable`,to:"/providers"}),s>0&&a.push({text:`${s} provider${s===1?"":"s"} without model discovery`,to:"/providers"})}return r.overCount>0?a.push({text:`${r.overCount} budget${r.overCount===1?"":"s"} over limit`,to:"/budgets"}):r.nearCount>0&&a.push({text:`${r.nearCount} budget${r.nearCount===1?"":"s"} near limit`,to:"/budgets"}),m==="alert"&&d!==null&&a.push({text:`error rate ${D(d)}`,to:"/activity?status=error"}),a.length===0?null:t.jsxs("div",{role:"alert",className:"flex flex-col gap-2 rounded-xl border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-900 sm:flex-row sm:flex-wrap sm:items-center",children:[t.jsx("span",{className:"font-medium",children:"Needs attention:"}),a.map((i,x)=>t.jsxs("span",{className:"flex items-center gap-2",children:[x>0?t.jsx("span",{"aria-hidden":!0,className:"text-amber-400",children:"·"}):null,t.jsx(I,{to:i.to,className:"underline underline-offset-2 hover:text-amber-950",children:i.text})]},i.to+i.text))]})}function Et(e){return e==="error"?"error":"ok"}function Ct({entries:e,loading:n,error:s}){const l=[{id:"time",header:"Time",cell:r=>t.jsx("span",{className:"text-[var(--otari-muted)]",title:new Date(r.timestamp).toLocaleString(),children:vt(r.timestamp)})},{id:"model",header:"Model",isRowHeader:!0,cell:r=>t.jsx("span",{className:"text-[var(--otari-ink)]",children:r.model})},{id:"cost",header:"Cost",align:"end",cell:r=>r.cost===null?"—":_(r.cost)},{id:"status",header:"Status",cell:r=>t.jsx("span",{className:`inline-flex items-center rounded-full border px-2 py-0.5 text-xs font-medium ${r.status==="error"?"border-red-200 bg-red-50 text-red-700":"border-[var(--otari-line)] bg-[var(--otari-brand-tint)] text-[var(--otari-brand-dark)]"}`,children:Et(r.status)})}];return t.jsxs("div",{className:"flex flex-col gap-3",children:[t.jsxs("div",{className:"flex items-center justify-between",children:[t.jsx("h2",{className:"text-sm font-semibold text-[var(--otari-ink)]",children:"Recent activity"}),t.jsx(I,{to:"/activity",className:"text-sm text-[var(--otari-brand-dark)] hover:underline",children:"View all →"})]}),t.jsx(Y,{error:s}),t.jsx(ht,{ariaLabel:"Recent activity",columns:l,rows:e,getRowKey:r=>r.id,isLoading:n,emptyContent:"No requests yet. Once the gateway serves traffic, it appears here."})]})}export{Ut as OverviewIndex,Nt as OverviewPage,G as localDayKey}; diff --git a/src/gateway/static/dashboard/assets/OverviewPage-WmIAewmo.js b/src/gateway/static/dashboard/assets/OverviewPage-WmIAewmo.js new file mode 100644 index 00000000..33e85108 --- /dev/null +++ b/src/gateway/static/dashboard/assets/OverviewPage-WmIAewmo.js @@ -0,0 +1 @@ +import{j as t}from"./tanstack-query-1t81HyiD.js";import{r as y,i as st,N as I}from"./react-dgEcD0HR.js";import{T as at,U as nt,d as S,V as ot,q as it,a as lt,u as dt,b as ct,W as w,P as ut,R as mt,E as Y,X as b,Z as _,_ as N,$ as R,a0 as D,a1 as vt}from"./index-Bi2hajrg.js";import{S as H}from"./charts-DIsd9m--.js";import{D as ht}from"./DataTable-Bmn_eYSV.js";import{d as B,B as xt}from"./heroui-BI50yK5B.js";import"./recharts-C4kRDmvS.js";function M(e){return e==="neutral"?void 0:e}const ft=.02,pt=.1;function W(e){if(!e||e.request_count===0)return{rate:null,status:"neutral"};const n=e.error_count/e.request_count,s=n>=pt?"alert":n>=ft?"warn":"ok";return{rate:n,status:s}}function gt(e){return!e||e.total===0?"neutral":e.healthy>=e.total?"ok":e.healthy+e.degraded===0?"alert":"warn"}const bt=.8;function yt(e){if(e.length===0)return{status:"neutral",label:"No budgets configured",overCount:0,nearCount:0,cappedCount:0};const n=e.filter(o=>o.max_budget!==null&&o.user_count>0);if(n.length===0)return{status:"neutral",label:"No capped budgets",overCount:0,nearCount:0,cappedCount:0};let s=0,l=0,r,m=-1;for(const o of n){const a=o.max_budget*o.user_count,i=a>0?o.total_spend/a:0;i>=1?s+=1:i>=bt&&(l+=1),i>m&&(m=i,r={name:o.name??o.budget_id,spent:o.total_spend,allocated:a,pct:i})}const d=s>0?"alert":l>0?"warn":"ok",h=s>0?`${s} over limit`:l>0?`${l} near limit`:"All within budget";return{status:d,label:h,overCount:s,nearCount:l,cappedCount:n.length,worst:r}}const K=864e5,T=30;function G(){const e=new Date;return`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,"0")}-${String(e.getDate()).padStart(2,"0")}`}function jt(){const[e,n]=y.useState(G);return y.useEffect(()=>{const s=()=>{if(document.visibilityState==="visible"){const l=G();n(r=>r===l?r:l)}};return document.addEventListener("visibilitychange",s),window.addEventListener("focus",s),()=>{document.removeEventListener("visibilitychange",s),window.removeEventListener("focus",s)}},[]),y.useMemo(()=>{const s=Date.now(),l=new Date(s);return{today:new Date(l.getFullYear(),l.getMonth(),l.getDate()).toISOString(),periodStart:new Date(s-T*K).toISOString(),prevStart:new Date(s-2*T*K).toISOString()}},[e])}const St={ok:"Healthy",warn:"Elevated",alert:"High"},wt={ok:"On track",warn:"Near limit",alert:"Over budget"};function qt(){const e=at();return e.isLoading?t.jsx(nt,{}):t.jsx(Nt,{needsSetup:e.isSuccess&&e.data.providers.length===0})}function Nt({needsSetup:e=!1}){var $,L,O,A,F,P,q,U;const n=jt(),s=y.useMemo(()=>({start_date:n.today}),[n]),l=y.useMemo(()=>({start_date:n.periodStart}),[n]),r=y.useMemo(()=>({start_date:n.prevStart,end_date:n.periodStart}),[n]),m=S(s,"hour"),d=S(l,"day"),h=S(r,"day"),o=ot(),a=it(),i=lt(),x=dt(),f=ct({},0,5),E=($=m.data)==null?void 0:$.totals,v=(L=d.data)==null?void 0:L.totals,p=(O=h.data)==null?void 0:O.totals,j=((A=d.data)==null?void 0:A.series)??[],C=j.length>1,c=W(v),k=W(p),V=c.rate!==null&&k.rate!==null?w(c.rate,k.rate):null,u=yt(a.data??[]),X=gt(o.data),Z=(i.data??[]).filter(g=>g.is_active).length,z=(x.data??[]).filter(g=>!g.blocked).length,J=(((F=f.data)==null?void 0:F.length)??0)>0,Q=e&&f.isSuccess&&!J,tt=m.error??d.error??o.error??a.error??i.error??x.error,et=()=>{m.refetch(),d.refetch(),h.refetch(),o.refetch(),a.refetch(),i.refetch(),x.refetch(),f.refetch()},rt=m.isFetching||d.isFetching||h.isFetching||o.isFetching||a.isFetching||i.isFetching||x.isFetching||f.isFetching;return t.jsxs("div",{className:"flex flex-col gap-6",children:[t.jsx(ut,{title:"Overview",description:"At-a-glance spend, traffic, and health across the gateway.",action:t.jsx(mt,{onRefresh:et,isFetching:rt,updatedAt:d.dataUpdatedAt})}),Q?t.jsx(Rt,{}):null,t.jsx(Y,{error:tt}),t.jsx(Dt,{providerHealth:X,healthy:((P=o.data)==null?void 0:P.healthy)??0,degraded:((q=o.data)==null?void 0:q.degraded)??0,total:((U=o.data)==null?void 0:U.total)??0,budget:u,errStatus:c.status,errRate:c.rate,ready:o.isSuccess&&a.isSuccess&&d.isSuccess,failed:o.isError||a.isError||d.isError}),t.jsxs("div",{className:"grid grid-cols-2 gap-4 sm:grid-cols-3 xl:grid-cols-4",children:[t.jsx(b,{label:"Spend today",value:E?_(E.cost):"—"}),t.jsx(b,{label:"Spend, last 30 days",value:v?_(v.cost):"—",hint:v?t.jsx(N,{fraction:w(v.cost,p==null?void 0:p.cost)}):null,chart:C?t.jsx(H,{values:j.map(g=>g.cost),ariaLabel:"Spend trend over the last 30 days"}):void 0}),t.jsx(b,{label:"Requests, last 30 days",value:v?R(v.request_count):"—",hint:v?t.jsx(N,{fraction:w(v.request_count,p==null?void 0:p.request_count)}):null,chart:C?t.jsx(H,{values:j.map(g=>g.requests),ariaLabel:"Request volume trend over the last 30 days"}):void 0}),t.jsx(b,{label:"Error rate, last 30 days",value:c.rate===null?"—":D(c.rate),status:M(c.status),statusLabel:c.status==="neutral"?void 0:St[c.status],hint:c.rate!==null?t.jsx(N,{fraction:V}):null}),t.jsx(b,{label:"Budget health",value:a.data&&u.worst?D(u.worst.pct):"—",status:a.data?M(u.status):void 0,statusLabel:a.data&&u.status!=="neutral"?wt[u.status]:void 0,hint:a.data?u.worst?`${u.label} · worst: ${u.worst.name}`:u.label:void 0,to:"/budgets"}),t.jsx(b,{label:"Active keys",value:i.data?R(Z):"—",to:"/keys"}),t.jsx(b,{label:"Active users",value:x.data?R(z):"—",to:"/users"})]}),t.jsx(Ct,{entries:f.data??[],loading:f.isLoading,error:f.error})]})}function Rt(){const e=st();return t.jsx(B,{children:t.jsxs(B.Content,{className:"flex flex-col gap-3 p-6",children:[t.jsxs("div",{children:[t.jsx("h2",{className:"text-lg font-semibold text-[var(--otari-ink)]",children:"Get started with Otari"}),t.jsx("p",{className:"mt-1 text-sm text-[var(--otari-muted)]",children:"Add a provider to begin serving models. Once it is configured, this page will show your gateway’s traffic, spend, and health."})]}),t.jsx("div",{children:t.jsx(xt,{variant:"primary",onPress:()=>e("/providers"),children:"Add your first provider"})})]})})}function _t({text:e}){return t.jsx("div",{role:"status",className:"flex items-center gap-2 rounded-xl border border-[var(--otari-line)] bg-[var(--otari-bg)] px-4 py-3 text-sm text-[var(--otari-muted)]",children:e})}function Dt({providerHealth:e,healthy:n,degraded:s,total:l,budget:r,errStatus:m,errRate:d,ready:h,failed:o}){if(o)return t.jsx(_t,{text:"Some status data could not be loaded."});if(!h)return null;const a=[];if((e==="warn"||e==="alert")&&l>0){const i=l-n-s;i>0&&a.push({text:`${i} provider${i===1?"":"s"} unreachable`,to:"/providers"}),s>0&&a.push({text:`${s} provider${s===1?"":"s"} without model discovery`,to:"/providers"})}return r.overCount>0?a.push({text:`${r.overCount} budget${r.overCount===1?"":"s"} over limit`,to:"/budgets"}):r.nearCount>0&&a.push({text:`${r.nearCount} budget${r.nearCount===1?"":"s"} near limit`,to:"/budgets"}),m==="alert"&&d!==null&&a.push({text:`error rate ${D(d)}`,to:"/activity?status=error"}),a.length===0?null:t.jsxs("div",{role:"alert",className:"flex flex-col gap-2 rounded-xl border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-900 sm:flex-row sm:flex-wrap sm:items-center",children:[t.jsx("span",{className:"font-medium",children:"Needs attention:"}),a.map((i,x)=>t.jsxs("span",{className:"flex items-center gap-2",children:[x>0?t.jsx("span",{"aria-hidden":!0,className:"text-amber-400",children:"·"}):null,t.jsx(I,{to:i.to,className:"underline underline-offset-2 hover:text-amber-950",children:i.text})]},i.to+i.text))]})}function Et(e){return e==="error"?"error":"ok"}function Ct({entries:e,loading:n,error:s}){const l=[{id:"time",header:"Time",cell:r=>t.jsx("span",{className:"text-[var(--otari-muted)]",title:new Date(r.timestamp).toLocaleString(),children:vt(r.timestamp)})},{id:"model",header:"Model",isRowHeader:!0,cell:r=>t.jsx("span",{className:"text-[var(--otari-ink)]",children:r.model})},{id:"cost",header:"Cost",align:"end",cell:r=>r.cost===null?"—":_(r.cost)},{id:"status",header:"Status",cell:r=>t.jsx("span",{className:`inline-flex items-center rounded-full border px-2 py-0.5 text-xs font-medium ${r.status==="error"?"border-red-200 bg-red-50 text-red-700":"border-[var(--otari-line)] bg-[var(--otari-brand-tint)] text-[var(--otari-brand-dark)]"}`,children:Et(r.status)})}];return t.jsxs("div",{className:"flex flex-col gap-3",children:[t.jsxs("div",{className:"flex items-center justify-between",children:[t.jsx("h2",{className:"text-sm font-semibold text-[var(--otari-ink)]",children:"Recent activity"}),t.jsx(I,{to:"/activity",className:"text-sm text-[var(--otari-brand-dark)] hover:underline",children:"View all →"})]}),t.jsx(Y,{error:s}),t.jsx(ht,{ariaLabel:"Recent activity",columns:l,rows:e,getRowKey:r=>r.id,isLoading:n,emptyContent:"No requests yet. Once the gateway serves traffic, it appears here."})]})}export{qt as OverviewIndex,Nt as OverviewPage,G as localDayKey}; diff --git a/src/gateway/static/dashboard/assets/ProvidersPage-BRQCYCYu.js b/src/gateway/static/dashboard/assets/ProvidersPage-BRQCYCYu.js new file mode 100644 index 00000000..e623a355 --- /dev/null +++ b/src/gateway/static/dashboard/assets/ProvidersPage-BRQCYCYu.js @@ -0,0 +1 @@ +import{j as e}from"./tanstack-query-1t81HyiD.js";import{r as x,L as M}from"./react-dgEcD0HR.js";import{T as Y,a2 as V,Q as G,V as Q,a3 as W,a4 as J,a5 as X,P as Z,E as I,I as ee,a6 as te,a7 as se,a1 as q,o as ae,a8 as $,a9 as re,N as O,aa as ne,ab as ie}from"./index-Bi2hajrg.js";import{F as _}from"./Field-Dwp6u3t8.js";import{D as oe}from"./DataTable-Bmn_eYSV.js";import{B as f,d as S,f as de,T as le,L as F,I as H,D as ce,S as me,C as T,a as ue,b as xe}from"./heroui-BI50yK5B.js";function E({value:t,onChange:s,label:a,placeholder:n,description:i}){return e.jsxs(le,{value:t,onChange:s,className:"flex max-w-md flex-col gap-1",children:[e.jsx(F,{className:"text-sm font-medium text-[var(--otari-ink)]",children:a}),e.jsx(H,{type:"password",placeholder:n??"sk-…",autoComplete:"off",autoCorrect:"off",autoCapitalize:"off",spellCheck:!1,"data-1p-ignore":!0,"data-lpignore":"true"}),i?e.jsx(ce,{className:"text-xs text-[var(--otari-muted)]",children:i}):null]})}function z({label:t,value:s,onChange:a,description:n,placeholder:i,extra:d=[],includeCatalog:l=!0}){var k;const g=ne(),u=x.useMemo(()=>l?[...d,...(g.data??[]).map(o=>({id:o.id,name:o.name}))]:d,[g.data,d,l]),[p,m]=x.useState(()=>{var o;return((o=u.find(b=>b.id===s))==null?void 0:o.name)??""}),j=((k=u.find(o=>o.id===s))==null?void 0:k.name)??"",h=p.trim()===j.trim()?"":p.trim().toLowerCase(),c=u.filter(o=>!h||o.name.toLowerCase().includes(h)||o.id.toLowerCase().includes(h)).slice(0,50);return e.jsxs(T.Root,{allowsEmptyCollection:!0,menuTrigger:"focus",inputValue:p,onInputChange:m,onSelectionChange:o=>{var b;o!=null?(a(String(o)),m(((b=u.find(N=>N.id===String(o)))==null?void 0:b.name)??"")):(a(""),m(""))},className:"flex max-w-md flex-col gap-1",children:[e.jsx(F,{className:"text-sm font-medium text-[var(--otari-ink)]",children:t}),e.jsxs(T.InputGroup,{children:[e.jsx(H,{placeholder:i??"Search providers…",autoComplete:"off","data-1p-ignore":!0,"data-lpignore":"true",onFocus:o=>o.currentTarget.select()}),e.jsx(T.Trigger,{})]}),e.jsx(T.Popover,{children:e.jsx(ue,{items:c,className:"max-h-72 overflow-auto",children:o=>e.jsx(xe,{id:o.id,textValue:o.name,children:o.name})})}),n?e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:n}):null]})}function U({getPayload:t}){const s=ie(),a=t();return e.jsxs("div",{className:"flex flex-col gap-1.5",children:[e.jsx(f,{variant:"outline",isDisabled:a===null||s.isPending,onPress:()=>{a&&s.mutate(a)},children:s.isPending?"Testing…":"Test connection"}),e.jsx("span",{role:"status","aria-live":"polite",children:s.isPending?null:s.error?e.jsx("span",{className:"text-xs text-red-700",children:O(s.error)}):s.data?s.data.ok?e.jsxs("span",{className:"text-xs font-medium text-green-700",children:["Connected. ",s.data.model_count," model",s.data.model_count===1?"":"s"," available."]}):s.data.discovery_unsupported?e.jsxs("span",{className:"block max-w-md break-words text-xs text-amber-800",children:["This provider does not list models, so the key could not be verified here. Save it and use the provider; declare its model ids under ",e.jsx("code",{children:"models:"})," to have them show up in the catalogue. If you did not expect this, check the provider's reply below.",s.data.error?e.jsx("span",{className:"mt-0.5 block text-[var(--otari-muted)]",children:s.data.error}):null]}):e.jsx("span",{className:"block max-w-md break-words text-xs text-red-700",children:s.data.error??"Connection failed."}):null})]})}function pe({onClose:t}){var A;const s=$(),[a,n]=x.useState(""),[i,d]=x.useState(""),[l,g]=x.useState(!1),[u,p]=x.useState(""),[m,j]=x.useState(""),h=re(a),c=((A=h.data)==null?void 0:A.id)===a?h.data:void 0;x.useEffect(()=>{c&&p(c.default_api_base??"")},[c]);const k=(c==null?void 0:c.env_key_present)??!1,o=((c==null?void 0:c.requires_api_key)??!0)&&!k,b=m.trim()!==""&&m.trim()!==a,N=/[:/]/.test(m),P=a!==""&&!N&&(!o||i.trim()!=="")&&!s.isPending,C=()=>{P&&s.mutate({instance:b?m.trim():a,provider_type:b?a:null,api_base:u.trim()||null,api_key:i.trim()||null},{onSuccess:t})};return e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsx(I,{error:s.error}),e.jsx(z,{label:"Provider",value:a,onChange:w=>{n(w),j(""),p("")},description:"Its endpoint is built in."}),e.jsx(E,{value:i,onChange:d,label:c&&!o?"API key (optional)":"API key",description:c?o?`${c.name}'s endpoint is built in — just add your key.`:k?`${c.env_key} is set on the server, so a key is optional here. Paste one to override it.`:`${c.name} needs no API key.`:"Stored encrypted. Requires OTARI_SECRET_KEY on the server."}),e.jsx("button",{type:"button",className:"self-start text-xs font-medium text-[var(--otari-brand-dark)]",onClick:()=>g(w=>!w),children:l?"Hide advanced":"Advanced (API base, rename)"}),l?e.jsxs("div",{className:"grid gap-4 sm:grid-cols-2",children:[e.jsx(_,{label:"API base",value:u,onChange:p,placeholder:(c==null?void 0:c.default_api_base)??"https://…/v1",description:"Only if you route through a proxy. Blank uses the built-in default."}),e.jsx(_,{label:"Name",value:m,onChange:j,placeholder:a||"instance name",description:N?e.jsx("span",{className:"text-red-700",children:"A name cannot contain “:” or “/”."}):"Rename to run two instances of the same provider."})]}):null,e.jsxs("div",{className:"flex flex-wrap items-start gap-2",children:[e.jsx(f,{variant:"primary",isDisabled:!P,onPress:C,children:s.isPending?"Adding…":"Add provider"}),e.jsx(f,{variant:"ghost",onPress:t,children:"Cancel"}),e.jsx(U,{getPayload:()=>a===""?null:{instance:b?m.trim():a,provider_type:b?a:null,api_base:u.trim()||null,api_key:i.trim()||null}})]})]})}function he({onClose:t}){const s=$(),[a,n]=x.useState(""),[i,d]=x.useState("openai-compatible"),[l,g]=x.useState(""),[u,p]=x.useState(""),m=/[:/]/.test(a),j=a.trim()!==""&&!m&&l.trim()!==""&&!s.isPending,h=()=>{j&&s.mutate({instance:a.trim(),provider_type:i||"openai-compatible",api_base:l.trim(),api_key:u.trim()||null},{onSuccess:t})};return e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsx(I,{error:s.error}),e.jsxs("div",{className:"grid gap-4 sm:grid-cols-2",children:[e.jsx(_,{label:"Name",value:a,onChange:n,placeholder:"my-local-llm",isRequired:!0,autoFocus:!0,description:m?e.jsx("span",{className:"text-red-700",children:"A name cannot contain “:” or “/”."}):"Call it whatever you want."}),e.jsx(z,{label:"Compatible with",value:i,onChange:d,includeCatalog:!1,description:"The API this endpoint speaks.",extra:[{id:"openai-compatible",name:"OpenAI"},{id:"anthropic-compatible",name:"Anthropic"}]})]}),e.jsx(_,{label:"API base",value:l,onChange:g,placeholder:"http://localhost:8000/v1",isRequired:!0,description:"The endpoint URL of your server."}),e.jsx(E,{value:u,onChange:p,label:"API key (optional)",description:"Many local backends need none. Stored encrypted."}),e.jsxs("div",{className:"flex flex-wrap items-start gap-2",children:[e.jsx(f,{variant:"primary",isDisabled:!j,onPress:h,children:s.isPending?"Adding…":"Add provider"}),e.jsx(f,{variant:"ghost",onPress:t,children:"Cancel"}),e.jsx(U,{getPayload:()=>a.trim()===""||l.trim()===""?null:{instance:a.trim(),provider_type:i||"openai-compatible",api_base:l.trim(),api_key:u.trim()||null}})]})]})}function ve({onClose:t}){const[s,a]=x.useState("known");return e.jsx(S,{children:e.jsxs(S.Content,{className:"flex flex-col gap-4 p-5",children:[e.jsx("div",{className:"flex items-center justify-between",children:e.jsx("div",{className:"flex items-center gap-1 rounded-lg bg-[var(--otari-bg)] p-1",children:[["known","Known provider"],["custom","Custom endpoint"]].map(([n,i])=>e.jsx("button",{type:"button","aria-pressed":s===n,onClick:()=>a(n),className:s===n?"rounded-md bg-white px-3 py-1.5 text-sm font-medium text-[var(--otari-ink)] shadow-sm":"rounded-md px-3 py-1.5 text-sm text-[var(--otari-muted)] hover:text-[var(--otari-ink)]",children:i},n))})}),s==="known"?e.jsx(pe,{onClose:t}):e.jsx(he,{onClose:t})]})})}function ge({provider:t,onClose:s}){const a=te(),[n,i]=x.useState(t.provider_type??""),[d,l]=x.useState(t.api_base??""),[g,u]=x.useState(!1),[p,m]=x.useState(""),j=()=>{if(a.isPending)return;const h={provider_type:n.trim()||null,api_base:d.trim()||null,expected_updated_at:t.updated_at};g&&p.trim()&&(h.api_key=p.trim()),a.mutate({instance:t.instance,body:h},{onSuccess:s})};return e.jsx(S,{children:e.jsxs(S.Content,{className:"flex flex-col gap-4 p-5",children:[e.jsxs("div",{className:"text-sm font-semibold text-[var(--otari-ink)]",children:["Edit ",e.jsx("code",{children:t.instance})]}),e.jsx(I,{error:a.error}),e.jsxs("div",{className:"grid gap-4 sm:grid-cols-2",children:[e.jsx(_,{label:"Provider type",value:n,onChange:i,placeholder:"openai"}),e.jsx(_,{label:"API base",value:d,onChange:l,placeholder:"https://api.openai.com/v1"})]}),e.jsx("div",{className:"flex flex-col gap-2",children:g?e.jsxs(e.Fragment,{children:[e.jsx(E,{value:p,onChange:m,label:"New API key",description:"Stored encrypted. The old key is replaced when you save."}),e.jsx("button",{type:"button",className:"self-start text-xs font-medium text-[var(--otari-brand-dark)]",onClick:()=>{u(!1),m("")},children:"Keep the current key"})]}):e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsxs("span",{className:"text-sm text-[var(--otari-muted)]",children:["API key: ",e.jsx("code",{children:t.last4?`••••${t.last4}`:"none set"})]}),e.jsx(f,{size:"sm",variant:"outline",onPress:()=>u(!0),children:"Replace key"})]})}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(f,{variant:"primary",isDisabled:a.isPending,onPress:j,children:a.isPending?"Saving…":"Save changes"}),e.jsx(f,{variant:"ghost",onPress:s,children:"Cancel"})]})]})})}function fe(t,s){const a=new Map((s??[]).map(d=>[d.instance,d])),n=new Map((t??[]).map(d=>[d.instance,d]));return[...new Set([...a.keys(),...n.keys()])].sort().map(d=>{const l=a.get(d);return{instance:d,source:l?"stored":"config",stored:l,meta:n.get(d)}})}function je({state:t}){return t?t.status==="pending"?e.jsxs("span",{className:"inline-flex items-center gap-1.5 text-xs text-[var(--otari-muted)]",children:[e.jsx(me,{size:"sm"})," Testing…"]}):t.ok?e.jsxs("span",{className:"text-xs font-medium text-green-700",children:["Connected. ",t.model_count," model",t.model_count===1?"":"s"," available."]}):t.discovery_unsupported?e.jsxs("span",{className:"block max-w-xs break-words text-xs text-amber-800",children:["Could not list models, so the key could not be verified. It may still work for requests.",t.error?e.jsx("span",{className:"mt-0.5 block text-[var(--otari-muted)]",children:t.error}):null]}):e.jsx("span",{className:"block max-w-xs break-words text-xs text-red-700",children:t.error??"Connection failed."}):null}function be({health:t}){if(!t)return e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"—"});const s=!t.ok&&t.discovery_unsupported,a=t.ok?"border-green-200 bg-green-50 text-green-700":s?"border-amber-200 bg-amber-50 text-amber-800":"border-red-200 bg-red-50 text-red-700",n=t.ok?"bg-green-500":s?"bg-amber-500":"bg-red-500",i=t.checked_at?`Last checked ${q(t.checked_at)}`:"Not checked yet",d=s?`${t.error??"This provider does not list models."} Requests to it may still work.`:t.error??"Unreachable",l=t.ok?i:`${d} · ${i}`;return e.jsxs("span",{title:l,className:`inline-flex items-center gap-1.5 rounded-full border px-2.5 py-0.5 text-xs font-medium ${a}`,children:[e.jsx("span",{"aria-hidden":!0,className:`h-1.5 w-1.5 rounded-full ${n}`}),t.ok?"Reachable":s?"No model discovery":"Unreachable"]})}function ye({healthy:t,degraded:s,total:a,checkedAt:n}){const d=t===a?"bg-green-500":t+s===a?"bg-amber-500":"bg-red-500",l=se();return e.jsxs("div",{className:"flex flex-wrap items-center gap-3 rounded-xl border border-[var(--otari-line)] bg-[var(--otari-surface)] px-4 py-2.5 text-sm",children:[e.jsx("span",{"aria-hidden":!0,className:`h-2 w-2 rounded-full ${d}`}),e.jsxs("span",{className:"font-medium text-[var(--otari-ink)]",children:[t," of ",a," provider",a===1?"":"s"," reachable"]}),s>0?e.jsxs("span",{className:"text-amber-800",children:[s," without model discovery"]}):null,n?e.jsxs("span",{className:"text-[var(--otari-muted)]",children:["Last checked ",q(n)]}):null,e.jsx(f,{size:"sm",variant:"ghost",className:"ml-auto",isDisabled:l.isPending,onPress:()=>l.mutate(),children:l.isPending?"Re-checking…":"Re-check all"})]})}function R({n:t,title:s,children:a}){return e.jsxs("li",{className:"flex gap-3",children:[e.jsx("span",{className:"flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-[var(--otari-brand-tint)] text-xs font-semibold text-[var(--otari-brand-dark)]",children:t}),e.jsxs("div",{className:"text-sm",children:[e.jsx("div",{className:"font-medium text-[var(--otari-ink)]",children:s}),e.jsx("div",{className:"text-[var(--otari-muted)]",children:a})]})]})}function ke({onAddProvider:t,needsPricing:s,onEnablePricing:a,enabling:n,secretKeyConfigured:i}){return e.jsx(S,{children:e.jsxs(S.Content,{className:"flex flex-col gap-4 p-6",children:[e.jsxs("div",{children:[e.jsx("h2",{className:"text-lg font-semibold text-[var(--otari-ink)]",children:"Welcome to Otari"}),e.jsx("p",{className:"mt-1 text-sm text-[var(--otari-muted)]",children:"You are signed in. Add a provider to start serving models: three quick steps."})]}),e.jsxs("ol",{className:"flex flex-col gap-3",children:[e.jsxs(R,{n:1,title:"Add a provider",children:["Enter a provider name (like ",e.jsx("code",{children:"openai"}),") and its API key. Keys are encrypted at rest."]}),e.jsxs(R,{n:2,title:"Test the connection",children:["Use ",e.jsx("strong",{children:"Test"})," on the provider row to confirm the key works and see how many models it serves."]}),e.jsxs(R,{n:3,title:"Send your first request",children:["Point your app at ",e.jsx("code",{children:"/v1"})," on this gateway with the API key printed in the server logs (",e.jsx("code",{children:"gw-…"}),"). See the"," ",e.jsx("a",{href:"/welcome",className:"font-medium text-[var(--otari-brand-dark)]",children:"quickstart"}),"."]})]}),s?e.jsxs("p",{className:"text-sm text-[var(--otari-muted)]",children:["Tip: ",e.jsx("code",{children:"require_pricing"})," is on, so requests are rejected until pricing is set."," ",e.jsx("button",{type:"button",className:"font-medium text-[var(--otari-brand-dark)] disabled:opacity-50",disabled:n,onClick:a,children:"Enable default pricing"})," ","to meter new models with public rates."]}):null,e.jsx("div",{children:e.jsx(f,{variant:"primary",isDisabled:!i,onPress:t,children:"Add your first provider"})})]})})}function Ae(){var K,B,D,L;const t=Y(),s=V(),a=G(),n=Q(),i=W(),d=J(),l=X(),[g,u]=x.useState(!1),[p,m]=x.useState(null),[j,h]=x.useState({}),c=fe((K=t.data)==null?void 0:K.providers,s.data),k=new Map((((B=n.data)==null?void 0:B.providers)??[]).map(r=>[r.instance,r])),o=t.isLoading||s.isLoading,b=((D=s.data)==null?void 0:D.find(r=>r.instance===p))??null,N=((L=a.data)==null?void 0:L.require_pricing)===!0&&a.data.default_pricing===!1,P=a.data?a.data.secret_key_configured!==!1:!a.isError,C=!o&&c.length===0&&!g,A=r=>{h(v=>({...v,[r]:{status:"pending"}})),d.mutate(r,{onSuccess:v=>h(y=>({...y,[r]:{status:"done",...v}})),onError:v=>h(y=>({...y,[r]:{status:"done",ok:!1,model_count:0,error:O(v),discovery_unsupported:!1}}))})},w=[{id:"provider",header:"Provider",isRowHeader:!0,cell:r=>e.jsx(M,{to:`/models?provider=${encodeURIComponent(r.instance)}`,className:"font-medium text-[var(--otari-ink)] hover:text-[var(--otari-brand-dark)] hover:underline",children:r.instance})},{id:"type",header:"Type",cell:r=>{var v,y;return e.jsx("span",{className:"text-[var(--otari-muted)]",children:((v=r.meta)==null?void 0:v.provider_type)??((y=r.stored)==null?void 0:y.provider_type)??r.instance})}},{id:"source",header:"Source",cell:r=>e.jsx(de,{size:"sm",color:r.source==="stored"?"accent":"default",children:r.source==="stored"?"stored":"config"})},{id:"api_key",header:"API key",cell:r=>{var v,y;return e.jsx("span",{className:"text-[var(--otari-muted)]",children:r.source==="stored"?r.stored&&!r.stored.decryptable?e.jsx("span",{className:"text-amber-700",title:"This key can't be decrypted with the current OTARI_SECRET_KEY. Replace the key, or restore the original OTARI_SECRET_KEY.",children:"⚠ key unreadable"}):e.jsx("code",{children:(v=r.stored)!=null&&v.last4?`••••${r.stored.last4}`:"none set"}):(y=r.meta)!=null&&y.env_key?e.jsxs("span",{children:["via ",e.jsx("code",{children:r.meta.env_key})]}):"config.yml"})}},{id:"status",header:"Status",cell:r=>e.jsx(be,{health:k.get(r.instance)})},{id:"actions",header:"Actions",align:"end",cell:r=>{var v,y;return r.source==="stored"?e.jsxs("div",{className:"flex flex-col items-end gap-1.5",children:[e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx(f,{size:"sm",variant:"outline",isDisabled:((v=j[r.instance])==null?void 0:v.status)==="pending"||((y=r.stored)==null?void 0:y.decryptable)===!1,onPress:()=>A(r.instance),children:"Test"}),e.jsx(f,{size:"sm",variant:"ghost",onPress:()=>{u(!1),m(r.instance)},children:"Edit"}),e.jsx(ae,{confirmLabel:"Delete",isPending:i.isPending,onConfirm:()=>i.mutate(r.instance),children:"Delete"})]}),e.jsx(je,{state:j[r.instance]})]}):e.jsx("span",{className:"block text-right text-xs text-[var(--otari-muted)]",children:"managed in config.yml"})}}];return e.jsxs("div",{className:"flex flex-col gap-6",children:[e.jsx(Z,{title:"Providers",description:"Add provider API keys here to serve models without editing config.yml. Keys are encrypted at rest.",action:g||C?null:e.jsx(f,{variant:"primary",isDisabled:!P,onPress:()=>{m(null),u(!0)},children:"Add provider"})}),e.jsx(I,{error:t.error??s.error??a.error??n.error??l.error??i.error}),P?null:e.jsxs(ee,{tone:"warning",children:[e.jsx("code",{children:"OTARI_SECRET_KEY"})," is not set, so provider keys can't be encrypted at rest and adding providers from the dashboard is disabled. Set it on the server and restart to add providers here. Providers defined in"," ",e.jsx("code",{children:"config.yml"})," keep working without it."]}),C?e.jsx(ke,{onAddProvider:()=>{m(null),u(!0)},needsPricing:N,onEnablePricing:()=>l.mutate({default_pricing:!0}),enabling:l.isPending,secretKeyConfigured:P}):null,g&&P?e.jsx(ve,{onClose:()=>u(!1)}):null,b?e.jsx(ge,{provider:b,onClose:()=>m(null)}):null,!o&&c.length>0&&n.data&&n.data.total>0?e.jsx(ye,{healthy:n.data.healthy,degraded:n.data.degraded,total:n.data.total,checkedAt:n.data.checked_at}):null,C?null:e.jsx(oe,{ariaLabel:"Providers",columns:w,rows:c,getRowKey:r=>r.instance,isLoading:o,emptyContent:"No providers yet. Add your first provider to start serving models."})]})}export{Ae as ProvidersPage}; diff --git a/src/gateway/static/dashboard/assets/ProvidersPage-D2tIyvqh.js b/src/gateway/static/dashboard/assets/ProvidersPage-D2tIyvqh.js deleted file mode 100644 index 2d145d7b..00000000 --- a/src/gateway/static/dashboard/assets/ProvidersPage-D2tIyvqh.js +++ /dev/null @@ -1 +0,0 @@ -import{j as e}from"./tanstack-query-1t81HyiD.js";import{r as x,L as M}from"./react-dgEcD0HR.js";import{L as Y,X as G,J as V,N as W,Y as J,Z as X,_ as Z,P as Q,E as I,I as ee,$ as te,a0 as se,W as $,C as ae,a1 as q,a2 as re,G as O,a3 as ne,a4 as ie}from"./index-D4f8RVEq.js";import{F as _}from"./Field-Dwp6u3t8.js";import{D as oe}from"./DataTable-Bmn_eYSV.js";import{B as f,d as S,f as de,T as le,L as F,I as H,D as ce,S as me,C as T,a as ue,b as xe}from"./heroui-BI50yK5B.js";function E({value:t,onChange:s,label:a,placeholder:n,description:i}){return e.jsxs(le,{value:t,onChange:s,className:"flex max-w-md flex-col gap-1",children:[e.jsx(F,{className:"text-sm font-medium text-[var(--otari-ink)]",children:a}),e.jsx(H,{type:"password",placeholder:n??"sk-…",autoComplete:"off",autoCorrect:"off",autoCapitalize:"off",spellCheck:!1,"data-1p-ignore":!0,"data-lpignore":"true"}),i?e.jsx(ce,{className:"text-xs text-[var(--otari-muted)]",children:i}):null]})}function z({label:t,value:s,onChange:a,description:n,placeholder:i,extra:d=[],includeCatalog:l=!0}){var k;const g=ne(),u=x.useMemo(()=>l?[...d,...(g.data??[]).map(o=>({id:o.id,name:o.name}))]:d,[g.data,d,l]),[p,m]=x.useState(()=>{var o;return((o=u.find(b=>b.id===s))==null?void 0:o.name)??""}),j=((k=u.find(o=>o.id===s))==null?void 0:k.name)??"",h=p.trim()===j.trim()?"":p.trim().toLowerCase(),c=u.filter(o=>!h||o.name.toLowerCase().includes(h)||o.id.toLowerCase().includes(h)).slice(0,50);return e.jsxs(T.Root,{allowsEmptyCollection:!0,menuTrigger:"focus",inputValue:p,onInputChange:m,onSelectionChange:o=>{var b;o!=null?(a(String(o)),m(((b=u.find(N=>N.id===String(o)))==null?void 0:b.name)??"")):(a(""),m(""))},className:"flex max-w-md flex-col gap-1",children:[e.jsx(F,{className:"text-sm font-medium text-[var(--otari-ink)]",children:t}),e.jsxs(T.InputGroup,{children:[e.jsx(H,{placeholder:i??"Search providers…",autoComplete:"off","data-1p-ignore":!0,"data-lpignore":"true",onFocus:o=>o.currentTarget.select()}),e.jsx(T.Trigger,{})]}),e.jsx(T.Popover,{children:e.jsx(ue,{items:c,className:"max-h-72 overflow-auto",children:o=>e.jsx(xe,{id:o.id,textValue:o.name,children:o.name})})}),n?e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:n}):null]})}function U({getPayload:t}){const s=ie(),a=t();return e.jsxs("div",{className:"flex flex-col gap-1.5",children:[e.jsx(f,{variant:"outline",isDisabled:a===null||s.isPending,onPress:()=>{a&&s.mutate(a)},children:s.isPending?"Testing…":"Test connection"}),e.jsx("span",{role:"status","aria-live":"polite",children:s.isPending?null:s.error?e.jsx("span",{className:"text-xs text-red-700",children:O(s.error)}):s.data?s.data.ok?e.jsxs("span",{className:"text-xs font-medium text-green-700",children:["Connected. ",s.data.model_count," model",s.data.model_count===1?"":"s"," available."]}):s.data.discovery_unsupported?e.jsxs("span",{className:"block max-w-md break-words text-xs text-amber-800",children:["This provider does not list models, so the key could not be verified here. Save it and use the provider; declare its model ids under ",e.jsx("code",{children:"models:"})," to have them show up in the catalogue. If you did not expect this, check the provider's reply below.",s.data.error?e.jsx("span",{className:"mt-0.5 block text-[var(--otari-muted)]",children:s.data.error}):null]}):e.jsx("span",{className:"block max-w-md break-words text-xs text-red-700",children:s.data.error??"Connection failed."}):null})]})}function pe({onClose:t}){var A;const s=q(),[a,n]=x.useState(""),[i,d]=x.useState(""),[l,g]=x.useState(!1),[u,p]=x.useState(""),[m,j]=x.useState(""),h=re(a),c=((A=h.data)==null?void 0:A.id)===a?h.data:void 0;x.useEffect(()=>{c&&p(c.default_api_base??"")},[c]);const k=(c==null?void 0:c.env_key_present)??!1,o=((c==null?void 0:c.requires_api_key)??!0)&&!k,b=m.trim()!==""&&m.trim()!==a,N=/[:/]/.test(m),P=a!==""&&!N&&(!o||i.trim()!=="")&&!s.isPending,C=()=>{P&&s.mutate({instance:b?m.trim():a,provider_type:b?a:null,api_base:u.trim()||null,api_key:i.trim()||null},{onSuccess:t})};return e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsx(I,{error:s.error}),e.jsx(z,{label:"Provider",value:a,onChange:w=>{n(w),j(""),p("")},description:"Its endpoint is built in."}),e.jsx(E,{value:i,onChange:d,label:c&&!o?"API key (optional)":"API key",description:c?o?`${c.name}'s endpoint is built in — just add your key.`:k?`${c.env_key} is set on the server, so a key is optional here. Paste one to override it.`:`${c.name} needs no API key.`:"Stored encrypted. Requires OTARI_SECRET_KEY on the server."}),e.jsx("button",{type:"button",className:"self-start text-xs font-medium text-[var(--otari-brand-dark)]",onClick:()=>g(w=>!w),children:l?"Hide advanced":"Advanced (API base, rename)"}),l?e.jsxs("div",{className:"grid gap-4 sm:grid-cols-2",children:[e.jsx(_,{label:"API base",value:u,onChange:p,placeholder:(c==null?void 0:c.default_api_base)??"https://…/v1",description:"Only if you route through a proxy. Blank uses the built-in default."}),e.jsx(_,{label:"Name",value:m,onChange:j,placeholder:a||"instance name",description:N?e.jsx("span",{className:"text-red-700",children:"A name cannot contain “:” or “/”."}):"Rename to run two instances of the same provider."})]}):null,e.jsxs("div",{className:"flex flex-wrap items-start gap-2",children:[e.jsx(f,{variant:"primary",isDisabled:!P,onPress:C,children:s.isPending?"Adding…":"Add provider"}),e.jsx(f,{variant:"ghost",onPress:t,children:"Cancel"}),e.jsx(U,{getPayload:()=>a===""?null:{instance:b?m.trim():a,provider_type:b?a:null,api_base:u.trim()||null,api_key:i.trim()||null}})]})]})}function he({onClose:t}){const s=q(),[a,n]=x.useState(""),[i,d]=x.useState("openai-compatible"),[l,g]=x.useState(""),[u,p]=x.useState(""),m=/[:/]/.test(a),j=a.trim()!==""&&!m&&l.trim()!==""&&!s.isPending,h=()=>{j&&s.mutate({instance:a.trim(),provider_type:i||"openai-compatible",api_base:l.trim(),api_key:u.trim()||null},{onSuccess:t})};return e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsx(I,{error:s.error}),e.jsxs("div",{className:"grid gap-4 sm:grid-cols-2",children:[e.jsx(_,{label:"Name",value:a,onChange:n,placeholder:"my-local-llm",isRequired:!0,autoFocus:!0,description:m?e.jsx("span",{className:"text-red-700",children:"A name cannot contain “:” or “/”."}):"Call it whatever you want."}),e.jsx(z,{label:"Compatible with",value:i,onChange:d,includeCatalog:!1,description:"The API this endpoint speaks.",extra:[{id:"openai-compatible",name:"OpenAI"},{id:"anthropic-compatible",name:"Anthropic"}]})]}),e.jsx(_,{label:"API base",value:l,onChange:g,placeholder:"http://localhost:8000/v1",isRequired:!0,description:"The endpoint URL of your server."}),e.jsx(E,{value:u,onChange:p,label:"API key (optional)",description:"Many local backends need none. Stored encrypted."}),e.jsxs("div",{className:"flex flex-wrap items-start gap-2",children:[e.jsx(f,{variant:"primary",isDisabled:!j,onPress:h,children:s.isPending?"Adding…":"Add provider"}),e.jsx(f,{variant:"ghost",onPress:t,children:"Cancel"}),e.jsx(U,{getPayload:()=>a.trim()===""||l.trim()===""?null:{instance:a.trim(),provider_type:i||"openai-compatible",api_base:l.trim(),api_key:u.trim()||null}})]})]})}function ve({onClose:t}){const[s,a]=x.useState("known");return e.jsx(S,{children:e.jsxs(S.Content,{className:"flex flex-col gap-4 p-5",children:[e.jsx("div",{className:"flex items-center justify-between",children:e.jsx("div",{className:"flex items-center gap-1 rounded-lg bg-[var(--otari-bg)] p-1",children:[["known","Known provider"],["custom","Custom endpoint"]].map(([n,i])=>e.jsx("button",{type:"button","aria-pressed":s===n,onClick:()=>a(n),className:s===n?"rounded-md bg-white px-3 py-1.5 text-sm font-medium text-[var(--otari-ink)] shadow-sm":"rounded-md px-3 py-1.5 text-sm text-[var(--otari-muted)] hover:text-[var(--otari-ink)]",children:i},n))})}),s==="known"?e.jsx(pe,{onClose:t}):e.jsx(he,{onClose:t})]})})}function ge({provider:t,onClose:s}){const a=te(),[n,i]=x.useState(t.provider_type??""),[d,l]=x.useState(t.api_base??""),[g,u]=x.useState(!1),[p,m]=x.useState(""),j=()=>{if(a.isPending)return;const h={provider_type:n.trim()||null,api_base:d.trim()||null,expected_updated_at:t.updated_at};g&&p.trim()&&(h.api_key=p.trim()),a.mutate({instance:t.instance,body:h},{onSuccess:s})};return e.jsx(S,{children:e.jsxs(S.Content,{className:"flex flex-col gap-4 p-5",children:[e.jsxs("div",{className:"text-sm font-semibold text-[var(--otari-ink)]",children:["Edit ",e.jsx("code",{children:t.instance})]}),e.jsx(I,{error:a.error}),e.jsxs("div",{className:"grid gap-4 sm:grid-cols-2",children:[e.jsx(_,{label:"Provider type",value:n,onChange:i,placeholder:"openai"}),e.jsx(_,{label:"API base",value:d,onChange:l,placeholder:"https://api.openai.com/v1"})]}),e.jsx("div",{className:"flex flex-col gap-2",children:g?e.jsxs(e.Fragment,{children:[e.jsx(E,{value:p,onChange:m,label:"New API key",description:"Stored encrypted. The old key is replaced when you save."}),e.jsx("button",{type:"button",className:"self-start text-xs font-medium text-[var(--otari-brand-dark)]",onClick:()=>{u(!1),m("")},children:"Keep the current key"})]}):e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsxs("span",{className:"text-sm text-[var(--otari-muted)]",children:["API key: ",e.jsx("code",{children:t.last4?`••••${t.last4}`:"none set"})]}),e.jsx(f,{size:"sm",variant:"outline",onPress:()=>u(!0),children:"Replace key"})]})}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(f,{variant:"primary",isDisabled:a.isPending,onPress:j,children:a.isPending?"Saving…":"Save changes"}),e.jsx(f,{variant:"ghost",onPress:s,children:"Cancel"})]})]})})}function fe(t,s){const a=new Map((s??[]).map(d=>[d.instance,d])),n=new Map((t??[]).map(d=>[d.instance,d]));return[...new Set([...a.keys(),...n.keys()])].sort().map(d=>{const l=a.get(d);return{instance:d,source:l?"stored":"config",stored:l,meta:n.get(d)}})}function je({state:t}){return t?t.status==="pending"?e.jsxs("span",{className:"inline-flex items-center gap-1.5 text-xs text-[var(--otari-muted)]",children:[e.jsx(me,{size:"sm"})," Testing…"]}):t.ok?e.jsxs("span",{className:"text-xs font-medium text-green-700",children:["Connected. ",t.model_count," model",t.model_count===1?"":"s"," available."]}):t.discovery_unsupported?e.jsxs("span",{className:"block max-w-xs break-words text-xs text-amber-800",children:["Could not list models, so the key could not be verified. It may still work for requests.",t.error?e.jsx("span",{className:"mt-0.5 block text-[var(--otari-muted)]",children:t.error}):null]}):e.jsx("span",{className:"block max-w-xs break-words text-xs text-red-700",children:t.error??"Connection failed."}):null}function be({health:t}){if(!t)return e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"—"});const s=!t.ok&&t.discovery_unsupported,a=t.ok?"border-green-200 bg-green-50 text-green-700":s?"border-amber-200 bg-amber-50 text-amber-800":"border-red-200 bg-red-50 text-red-700",n=t.ok?"bg-green-500":s?"bg-amber-500":"bg-red-500",i=t.checked_at?`Last checked ${$(t.checked_at)}`:"Not checked yet",d=s?`${t.error??"This provider does not list models."} Requests to it may still work.`:t.error??"Unreachable",l=t.ok?i:`${d} · ${i}`;return e.jsxs("span",{title:l,className:`inline-flex items-center gap-1.5 rounded-full border px-2.5 py-0.5 text-xs font-medium ${a}`,children:[e.jsx("span",{"aria-hidden":!0,className:`h-1.5 w-1.5 rounded-full ${n}`}),t.ok?"Reachable":s?"No model discovery":"Unreachable"]})}function ye({healthy:t,degraded:s,total:a,checkedAt:n}){const d=t===a?"bg-green-500":t+s===a?"bg-amber-500":"bg-red-500",l=se();return e.jsxs("div",{className:"flex flex-wrap items-center gap-3 rounded-xl border border-[var(--otari-line)] bg-[var(--otari-surface)] px-4 py-2.5 text-sm",children:[e.jsx("span",{"aria-hidden":!0,className:`h-2 w-2 rounded-full ${d}`}),e.jsxs("span",{className:"font-medium text-[var(--otari-ink)]",children:[t," of ",a," provider",a===1?"":"s"," reachable"]}),s>0?e.jsxs("span",{className:"text-amber-800",children:[s," without model discovery"]}):null,n?e.jsxs("span",{className:"text-[var(--otari-muted)]",children:["Last checked ",$(n)]}):null,e.jsx(f,{size:"sm",variant:"ghost",className:"ml-auto",isDisabled:l.isPending,onPress:()=>l.mutate(),children:l.isPending?"Re-checking…":"Re-check all"})]})}function R({n:t,title:s,children:a}){return e.jsxs("li",{className:"flex gap-3",children:[e.jsx("span",{className:"flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-[var(--otari-brand-tint)] text-xs font-semibold text-[var(--otari-brand-dark)]",children:t}),e.jsxs("div",{className:"text-sm",children:[e.jsx("div",{className:"font-medium text-[var(--otari-ink)]",children:s}),e.jsx("div",{className:"text-[var(--otari-muted)]",children:a})]})]})}function ke({onAddProvider:t,needsPricing:s,onEnablePricing:a,enabling:n,secretKeyConfigured:i}){return e.jsx(S,{children:e.jsxs(S.Content,{className:"flex flex-col gap-4 p-6",children:[e.jsxs("div",{children:[e.jsx("h2",{className:"text-lg font-semibold text-[var(--otari-ink)]",children:"Welcome to Otari"}),e.jsx("p",{className:"mt-1 text-sm text-[var(--otari-muted)]",children:"You are signed in. Add a provider to start serving models: three quick steps."})]}),e.jsxs("ol",{className:"flex flex-col gap-3",children:[e.jsxs(R,{n:1,title:"Add a provider",children:["Enter a provider name (like ",e.jsx("code",{children:"openai"}),") and its API key. Keys are encrypted at rest."]}),e.jsxs(R,{n:2,title:"Test the connection",children:["Use ",e.jsx("strong",{children:"Test"})," on the provider row to confirm the key works and see how many models it serves."]}),e.jsxs(R,{n:3,title:"Send your first request",children:["Point your app at ",e.jsx("code",{children:"/v1"})," on this gateway with the API key printed in the server logs (",e.jsx("code",{children:"gw-…"}),"). See the"," ",e.jsx("a",{href:"/welcome",className:"font-medium text-[var(--otari-brand-dark)]",children:"quickstart"}),"."]})]}),s?e.jsxs("p",{className:"text-sm text-[var(--otari-muted)]",children:["Tip: ",e.jsx("code",{children:"require_pricing"})," is on, so requests are rejected until pricing is set."," ",e.jsx("button",{type:"button",className:"font-medium text-[var(--otari-brand-dark)] disabled:opacity-50",disabled:n,onClick:a,children:"Enable default pricing"})," ","to meter new models with public rates."]}):null,e.jsx("div",{children:e.jsx(f,{variant:"primary",isDisabled:!i,onPress:t,children:"Add your first provider"})})]})})}function Ae(){var K,B,D,L;const t=Y(),s=G(),a=V(),n=W(),i=J(),d=X(),l=Z(),[g,u]=x.useState(!1),[p,m]=x.useState(null),[j,h]=x.useState({}),c=fe((K=t.data)==null?void 0:K.providers,s.data),k=new Map((((B=n.data)==null?void 0:B.providers)??[]).map(r=>[r.instance,r])),o=t.isLoading||s.isLoading,b=((D=s.data)==null?void 0:D.find(r=>r.instance===p))??null,N=((L=a.data)==null?void 0:L.require_pricing)===!0&&a.data.default_pricing===!1,P=a.data?a.data.secret_key_configured!==!1:!a.isError,C=!o&&c.length===0&&!g,A=r=>{h(v=>({...v,[r]:{status:"pending"}})),d.mutate(r,{onSuccess:v=>h(y=>({...y,[r]:{status:"done",...v}})),onError:v=>h(y=>({...y,[r]:{status:"done",ok:!1,model_count:0,error:O(v),discovery_unsupported:!1}}))})},w=[{id:"provider",header:"Provider",isRowHeader:!0,cell:r=>e.jsx(M,{to:`/models?provider=${encodeURIComponent(r.instance)}`,className:"font-medium text-[var(--otari-ink)] hover:text-[var(--otari-brand-dark)] hover:underline",children:r.instance})},{id:"type",header:"Type",cell:r=>{var v,y;return e.jsx("span",{className:"text-[var(--otari-muted)]",children:((v=r.meta)==null?void 0:v.provider_type)??((y=r.stored)==null?void 0:y.provider_type)??r.instance})}},{id:"source",header:"Source",cell:r=>e.jsx(de,{size:"sm",color:r.source==="stored"?"accent":"default",children:r.source==="stored"?"stored":"config"})},{id:"api_key",header:"API key",cell:r=>{var v,y;return e.jsx("span",{className:"text-[var(--otari-muted)]",children:r.source==="stored"?r.stored&&!r.stored.decryptable?e.jsx("span",{className:"text-amber-700",title:"This key can't be decrypted with the current OTARI_SECRET_KEY. Replace the key, or restore the original OTARI_SECRET_KEY.",children:"⚠ key unreadable"}):e.jsx("code",{children:(v=r.stored)!=null&&v.last4?`••••${r.stored.last4}`:"none set"}):(y=r.meta)!=null&&y.env_key?e.jsxs("span",{children:["via ",e.jsx("code",{children:r.meta.env_key})]}):"config.yml"})}},{id:"status",header:"Status",cell:r=>e.jsx(be,{health:k.get(r.instance)})},{id:"actions",header:"Actions",align:"end",cell:r=>{var v,y;return r.source==="stored"?e.jsxs("div",{className:"flex flex-col items-end gap-1.5",children:[e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx(f,{size:"sm",variant:"outline",isDisabled:((v=j[r.instance])==null?void 0:v.status)==="pending"||((y=r.stored)==null?void 0:y.decryptable)===!1,onPress:()=>A(r.instance),children:"Test"}),e.jsx(f,{size:"sm",variant:"ghost",onPress:()=>{u(!1),m(r.instance)},children:"Edit"}),e.jsx(ae,{confirmLabel:"Delete",isPending:i.isPending,onConfirm:()=>i.mutate(r.instance),children:"Delete"})]}),e.jsx(je,{state:j[r.instance]})]}):e.jsx("span",{className:"block text-right text-xs text-[var(--otari-muted)]",children:"managed in config.yml"})}}];return e.jsxs("div",{className:"flex flex-col gap-6",children:[e.jsx(Q,{title:"Providers",description:"Add provider API keys here to serve models without editing config.yml. Keys are encrypted at rest.",action:g||C?null:e.jsx(f,{variant:"primary",isDisabled:!P,onPress:()=>{m(null),u(!0)},children:"Add provider"})}),e.jsx(I,{error:t.error??s.error??a.error??n.error??l.error??i.error}),P?null:e.jsxs(ee,{tone:"warning",children:[e.jsx("code",{children:"OTARI_SECRET_KEY"})," is not set, so provider keys can't be encrypted at rest and adding providers from the dashboard is disabled. Set it on the server and restart to add providers here. Providers defined in"," ",e.jsx("code",{children:"config.yml"})," keep working without it."]}),C?e.jsx(ke,{onAddProvider:()=>{m(null),u(!0)},needsPricing:N,onEnablePricing:()=>l.mutate({default_pricing:!0}),enabling:l.isPending,secretKeyConfigured:P}):null,g&&P?e.jsx(ve,{onClose:()=>u(!1)}):null,b?e.jsx(ge,{provider:b,onClose:()=>m(null)}):null,!o&&c.length>0&&n.data&&n.data.total>0?e.jsx(ye,{healthy:n.data.healthy,degraded:n.data.degraded,total:n.data.total,checkedAt:n.data.checked_at}):null,C?null:e.jsx(oe,{ariaLabel:"Providers",columns:w,rows:c,getRowKey:r=>r.instance,isLoading:o,emptyContent:"No providers yet. Add your first provider to start serving models."})]})}export{Ae as ProvidersPage}; diff --git a/src/gateway/static/dashboard/assets/SettingsPage-DjaTcy-f.js b/src/gateway/static/dashboard/assets/SettingsPage-DjaTcy-f.js new file mode 100644 index 00000000..f7086c77 --- /dev/null +++ b/src/gateway/static/dashboard/assets/SettingsPage-DjaTcy-f.js @@ -0,0 +1 @@ +import{j as e}from"./tanstack-query-1t81HyiD.js";import{r as u}from"./react-dgEcD0HR.js";import{Q as R,a5 as C,P,E as y,U as E,ac as T,ad as _,ae as D,F as A,af as O,a2 as F,ag as I,I as w}from"./index-Bi2hajrg.js";import{d as v,B as h,A as d,g as K,I as z}from"./heroui-BI50yK5B.js";function b(t,r){return{[t]:r}}function M(t,r){let s=0;for(const a of r)if(a===t[s]&&(s+=1),s===t.length)return!0;return t.length===0}function L(t,r){const s=r.trim().toLowerCase();if(s==="")return!0;const a=`${t.key} ${t.description??""} ${t.group}`.toLowerCase(),n=t.key.toLowerCase().replace(/[^a-z0-9]/g,"");return s.split(/\s+/).every(i=>a.includes(i)||M(i,n))}function B({checked:t,onChange:r,label:s,disabled:a}){return e.jsx("button",{type:"button",role:"switch","aria-checked":t,"aria-label":s,disabled:a,onClick:()=>r(!t),className:`relative inline-flex h-6 w-11 shrink-0 items-center rounded-full transition-colors disabled:opacity-50 ${t?"bg-[var(--otari-brand)]":"bg-[var(--otari-line)]"}`,children:e.jsx("span",{className:`inline-block h-5 w-5 transform rounded-full bg-white shadow transition-transform ${t?"translate-x-5":"translate-x-0.5"}`})})}function $({field:t,onSave:r,disabled:s}){const a=typeof t.value=="number"?t.value:0,[n,i]=u.useState(String(a)),o=t.type==="float";u.useEffect(()=>{i(String(a))},[a]);const c=Number(n),p=n.trim()!==""&&Number.isFinite(c)&&(o||Number.isInteger(c)),m=t.minimum??void 0,x=t.exclusive_minimum??void 0,g=x!==void 0?c>x:m!==void 0?c>=m:c>=0,l=p&&g&&c!==a;return e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(z,{type:"number",min:"0",step:o?"any":"1",inputMode:o?"decimal":"numeric","aria-label":t.key,value:n,disabled:s,onChange:f=>i(f.target.value),className:"w-28 rounded-md border border-[var(--otari-line)] bg-white px-2 py-1 text-right text-sm tabular-nums focus:border-[var(--otari-brand)] focus:outline-none disabled:opacity-50"}),e.jsx(h,{size:"sm",variant:"primary","aria-label":`Save ${t.key}`,isDisabled:s||!l,onPress:()=>r(c),children:"Save"})]})}function H({field:t,onSave:r,disabled:s}){const a=typeof t.value=="string"?t.value:"",[n,i]=u.useState(a);u.useEffect(()=>{i(a)},[a]);const o=n!==a;return e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"text","aria-label":t.key,value:n,disabled:s,placeholder:"unset",onChange:c=>i(c.target.value),className:"w-56 rounded-md border border-[var(--otari-line)] bg-white px-2 py-1 text-sm focus:border-[var(--otari-brand)] focus:outline-none disabled:opacity-50"}),e.jsx(h,{size:"sm",variant:"primary","aria-label":`Save ${t.key}`,isDisabled:s||!o,onPress:()=>r(n.trim()===""?null:n),children:"Save"})]})}function Y(t){const{value:r}=t;return r==null?"unset":typeof r=="boolean"?r?"on":"off":Array.isArray(r)?r.length?r.join(", "):"none":String(r)}function q({field:t,patch:r,disabled:s}){return t.settable?t.type==="bool"?e.jsx(B,{checked:t.value===!0,onChange:a=>r(b(t.key,a)),label:t.key,disabled:s}):t.options&&t.options.length>0?e.jsx(A,{ariaLabel:t.key,value:String(t.value??""),onChange:a=>r(b(t.key,a)),options:t.options.map(a=>({value:a,label:a}))}):t.type==="int"||t.type==="float"?e.jsx($,{field:t,onSave:a=>r(b(t.key,a)),disabled:s}):e.jsx(H,{field:t,onSave:a=>r(b(t.key,a)),disabled:s}):e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-sm tabular-nums text-[var(--otari-ink)]",children:Y(t)}),e.jsx("span",{className:"rounded-full border border-[var(--otari-line)] px-2 py-0.5 text-xs text-[var(--otari-muted)]",children:"startup-only"})]})}function U({field:t,patch:r,disabled:s}){return e.jsxs("div",{className:"flex items-start justify-between gap-6 py-4",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("code",{className:"text-sm font-medium text-[var(--otari-ink)]",children:t.key}),t.description?e.jsx("p",{className:"mt-1 text-sm text-[var(--otari-muted)]",children:t.description}):null]}),e.jsx("div",{className:"shrink-0 pt-0.5",children:e.jsx(q,{field:t,patch:r,disabled:s})})]})}function V({value:t,fieldRef:r}){const s=u.useRef(null),a=r??s,[n,i]=u.useState(!1),[o,c]=u.useState(!1),p=async()=>{var m,x,g;(m=a.current)==null||m.focus(),(x=a.current)==null||x.select();try{if((g=navigator.clipboard)!=null&&g.writeText){await navigator.clipboard.writeText(t),i(!0),c(!1),window.setTimeout(()=>i(!1),2e3);return}}catch{}c(!0)};return e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{className:"text-xs font-medium text-[var(--otari-muted)]",children:"New master key"}),e.jsx(h,{size:"sm",variant:"outline",onPress:p,children:n?"Copied":"Copy"})]}),e.jsx("input",{ref:a,readOnly:!0,value:t,onFocus:m=>m.currentTarget.select(),autoComplete:"off",autoCorrect:"off",autoCapitalize:"off",spellCheck:!1,"data-1p-ignore":!0,"data-lpignore":"true"}),e.jsx("span",{"aria-live":"polite",className:"text-xs text-[var(--otari-brand-dark)]",children:n?"Copied to clipboard.":""}),o?e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"Selected. Press Ctrl/Cmd-C to copy."}):null]})}function G({masterKey:t,error:r,isPending:s,onRegenerate:a,onClose:n}){const i=u.useRef(null);return u.useEffect(()=>{var o,c;t!==void 0&&((o=i.current)==null||o.focus(),(c=i.current)==null||c.select())},[t]),e.jsx(d.Backdrop,{children:e.jsx(d.Container,{placement:"center",size:"lg",children:e.jsxs(d.Dialog,{children:[e.jsx(d.Header,{children:e.jsx(d.Heading,{children:t!==void 0?"Master key regenerated":"Regenerate master key?"})}),e.jsx(d.Body,{className:"flex flex-col gap-4",children:t!==void 0?e.jsxs(e.Fragment,{children:[e.jsx(w,{tone:"warning",children:"Copy this key now. It is shown once and cannot be retrieved again after you close this dialog."}),e.jsx("p",{className:"text-sm text-[var(--otari-muted)]",children:"The previous master key has stopped working. This browser tab now uses the new key."}),e.jsx(V,{value:t,fieldRef:i})]}):e.jsxs(e.Fragment,{children:[e.jsx(w,{tone:"warning",children:"This immediately invalidates the current dashboard master key. Other signed-in dashboard sessions will need the new key to continue."}),e.jsx("p",{className:"text-sm text-[var(--otari-muted)]",children:"The replacement key will be shown once. Save it before closing the next screen."}),e.jsx(y,{error:r})]})}),e.jsx(d.Footer,{children:t!==void 0?e.jsx(h,{variant:"primary",onPress:n,children:"I’ve saved this key"}):e.jsxs(e.Fragment,{children:[e.jsx(h,{variant:"ghost",isDisabled:s,onPress:n,children:"Cancel"}),e.jsx(h,{variant:"danger",isPending:s,onPress:a,children:"Regenerate key"})]})})]})})})}function Q({source:t}){const r=O(),[s,a]=u.useState(!1),[n,i]=u.useState(),o=t==="generated",c=()=>r.mutate(void 0,{onSuccess:x=>{i(x.master_key)}}),p=()=>{a(!1),i(void 0),r.reset()},m=x=>{x?(r.reset(),a(!0)):n===void 0&&p()};return e.jsx("div",{className:"flex flex-col gap-4 py-4",children:e.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("code",{className:"text-sm font-medium text-[var(--otari-ink)]",children:"master_key"}),e.jsx("p",{className:"mt-1 max-w-3xl text-sm text-[var(--otari-muted)]",children:o?"This gateway uses its first-run generated dashboard key. Regeneration invalidates the current key immediately.":"This gateway uses a key managed through OTARI_MASTER_KEY or config.yml. Rotate it in configuration, then restart the gateway."})]}),e.jsxs(d,{isOpen:s,onOpenChange:m,children:[o?e.jsx(d.Trigger,{className:K({size:"sm",variant:"danger-soft"}),children:"Regenerate"}):e.jsx(h,{size:"sm",variant:"danger-soft",isDisabled:!0,children:"Managed in configuration"}),s?e.jsx(G,{masterKey:n,error:r.error,isPending:r.isPending,onRegenerate:c,onClose:p}):null]})]})})}function X(){var o;const t=F(),r=I(),s=r.data,a=((o=t.data)==null?void 0:o.length)??0,n=(t.data??[]).filter(c=>!c.decryptable).length,i=a>0;return e.jsxs("div",{className:"flex flex-col gap-4 py-4",children:[e.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("code",{className:"text-sm font-medium text-[var(--otari-ink)]",children:"OTARI_SECRET_KEY"}),e.jsxs("p",{className:"mt-1 max-w-3xl text-sm text-[var(--otari-muted)]",children:["Generate a new key with ",e.jsx("code",{children:"uv run otari gen-secret-key"}),", then restart with"," ",e.jsx("code",{children:"OTARI_SECRET_KEY=,"}),". Re-encrypt the stored provider keys, then restart with ",e.jsx("code",{children:"OTARI_SECRET_KEY="})," once none are unreadable."]})]}),e.jsx("div",{className:"shrink-0",children:e.jsx(h,{size:"sm",variant:"outline",isDisabled:!i||r.isPending,onPress:()=>r.mutate(),children:r.isPending?"Re-encrypting…":"Re-encrypt provider keys"})})]}),e.jsx(y,{error:t.error??r.error}),n>0?e.jsxs(w,{tone:"warning",children:[n," stored provider key",n===1?"":"s"," cannot be decrypted with the current"," ",e.jsx("code",{children:"OTARI_SECRET_KEY"}),". Restore the old secret key and re-encrypt, or edit each affected provider and replace its key."]}):null,s?e.jsxs("p",{className:"text-sm text-[var(--otari-muted)]",role:"status","aria-live":"polite",children:["Re-encrypted ",s.reencrypted," provider key",s.reencrypted===1?"":"s",".",s.unreadable>0?` ${s.unreadable} still need replacement.`:" All decryptable stored keys now use the primary secret key."]}):!t.isLoading&&!i?e.jsx("p",{className:"text-sm text-[var(--otari-muted)]",children:"No stored provider keys need re-encryption."}):null]})}function J({masterKeySource:t}){return e.jsxs("section",{className:"flex flex-col gap-2",children:[e.jsxs("h2",{className:"text-sm font-semibold text-[var(--otari-ink)]",children:["Credential security ",e.jsx("span",{className:"font-normal text-[var(--otari-muted)]",children:"(2)"})]}),e.jsx(v,{children:e.jsxs(v.Content,{className:"flex flex-col divide-y divide-[var(--otari-line)] px-5 py-1",children:[e.jsx(Q,{source:t}),e.jsx(X,{})]})})]})}function W({preview:t,error:r,isPending:s,onAccept:a,onReject:n}){return e.jsx(d.Backdrop,{children:e.jsx(d.Container,{placement:"center",size:"lg",children:e.jsxs(d.Dialog,{children:[e.jsx(d.Header,{children:e.jsx(d.Heading,{children:"Review default price updates"})}),e.jsxs(d.Body,{className:"flex flex-col gap-4",children:[e.jsxs("p",{className:"text-sm text-[var(--otari-muted)]",children:[t.added_count," added, ",t.changed_count," changed, and ",t.removed_count," removed upstream model prices. The accepted catalog is saved in the database with source ",e.jsx("code",{children:"genai-prices"})," and reloads after a restart. Your ",t.protected_model_count," custom model price",t.protected_model_count===1?"":"s"," remain unchanged."]}),t.changes.length>0?e.jsx("ul",{className:"max-h-60 list-disc overflow-auto pl-5 text-sm text-[var(--otari-ink)]",children:t.changes.map(i=>e.jsxs("li",{children:[i.model_key,": ",i.change]},i.model_key))}):null,t.changes_truncated?e.jsx("p",{className:"text-xs text-[var(--otari-muted)]",children:"Only the first 100 changes are shown."}):null,e.jsx(y,{error:r})]}),e.jsxs(d.Footer,{children:[e.jsx(h,{variant:"ghost",isDisabled:s,onPress:n,children:"Reject changes"}),e.jsx(h,{variant:"primary",isPending:s,onPress:a,children:"Accept price updates"})]})]})})})}function Z(){const t=T(),r=_(),s=D(),a=t.data,n=r.isPending||s.isPending,i=()=>{a===void 0||n||s.mutate(void 0,{onSuccess:t.reset})};return e.jsxs("section",{className:"flex flex-col gap-2",children:[e.jsx("h2",{className:"text-sm font-semibold text-[var(--otari-ink)]",children:"Default pricing catalog"}),e.jsx(v,{children:e.jsxs(v.Content,{className:"flex flex-col gap-4 p-5",children:[e.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("div",{className:"text-sm font-medium text-[var(--otari-ink)]",children:"genai-prices defaults"}),e.jsxs("p",{className:"mt-1 max-w-3xl text-sm text-[var(--otari-muted)]",children:["Fetch the latest upstream catalog, review the proposed change summary, then accept or reject it. Accepted data is stored as ",e.jsx("code",{children:"genai-prices"}),"; custom prices remain separate and always take precedence."]})]}),e.jsx(h,{size:"sm",variant:"outline",isDisabled:t.isPending||n,onPress:()=>t.mutate(),children:t.isPending?"Checking prices…":"Check for price updates"})]}),e.jsx(y,{error:t.error})]})}),e.jsxs(d,{isOpen:a!==void 0,onOpenChange:o=>o?void 0:i(),children:[e.jsx(d.Trigger,{className:"hidden",children:"Review price updates"}),a?e.jsx(W,{preview:a,error:r.error??s.error,isPending:n,onAccept:()=>r.mutate(void 0,{onSuccess:t.reset}),onReject:i}):null]})]})}function ee(t){const r=[],s=new Map;for(const a of t){let n=s.get(a.group);n||(n={name:a.group,fields:[]},s.set(a.group,n),r.push(n)),n.fields.push(a)}return r}function ne(){const t=R(),r=C(),s=t.data,a=r.isPending,[n,i]=u.useState(""),[o,c]=u.useState(!1),p=u.useRef(null);u.useEffect(()=>{function l(f){var N;const j=f.target,S=j&&(j.tagName==="INPUT"||j.tagName==="TEXTAREA"||j.tagName==="SELECT");f.key==="/"&&!S&&(f.preventDefault(),(N=p.current)==null||N.focus())}return window.addEventListener("keydown",l),()=>window.removeEventListener("keydown",l)},[]);const m=l=>r.mutate(l),x=(s==null?void 0:s.config)??[],g=x.filter(l=>(o?l.settable:!0)&&L(l,n)),k=ee(g);return e.jsxs("div",{className:"flex flex-col gap-6",children:[e.jsx(P,{title:"Settings",description:"Every effective gateway setting. Settable fields apply immediately and persist across restarts; startup-only fields are shown for reference and change only via config.yml or environment variables (then a restart)."}),e.jsx(y,{error:t.error??r.error}),e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsx("input",{ref:p,type:"search","aria-label":"Search settings",placeholder:"Search settings (press / to focus)…",value:n,onChange:l=>i(l.target.value),onKeyDown:l=>{l.key==="Escape"&&i("")},className:"min-w-0 flex-1 rounded-lg border border-[var(--otari-line)] bg-[var(--otari-bg)] px-3 py-2 text-sm text-[var(--otari-ink)] focus:border-[var(--otari-brand)] focus:outline-none"}),e.jsxs("label",{className:"flex items-center gap-2 text-sm text-[var(--otari-muted)]",children:[e.jsx("input",{type:"checkbox",checked:o,onChange:l=>c(l.target.checked),className:"h-4 w-4 accent-[var(--otari-brand)]"}),"Settable only"]})]}),s?e.jsxs("p",{className:"text-xs text-[var(--otari-muted)]",children:["Showing ",g.length," of ",x.length," settings"]}):null,s&&g.length===0?e.jsx("p",{className:"text-sm text-[var(--otari-muted)]",children:"No settings match your search."}):null,t.isLoading?e.jsx(E,{}):null,k.map(l=>e.jsxs("section",{className:"flex flex-col gap-2",children:[e.jsxs("h2",{className:"text-sm font-semibold text-[var(--otari-ink)]",children:[l.name," ",e.jsxs("span",{className:"font-normal text-[var(--otari-muted)]",children:["(",l.fields.length,")"]})]}),e.jsx(v,{children:e.jsx(v.Content,{className:"flex flex-col divide-y divide-[var(--otari-line)] px-5 py-1",children:l.fields.map(f=>e.jsx(U,{field:f,patch:m,disabled:!s||a},f.key))})})]},l.name)),s?e.jsx(Z,{}):null,s?e.jsx(J,{masterKeySource:s.master_key_source}):null,s?e.jsxs("p",{className:"text-xs text-[var(--otari-muted)]",children:["Mode: ",s.mode," · Version ",s.version,s.require_pricing?" · require_pricing on":""]}):null]})}export{ne as SettingsPage,L as fieldMatches}; diff --git a/src/gateway/static/dashboard/assets/SettingsPage-k4BcKpbT.js b/src/gateway/static/dashboard/assets/SettingsPage-k4BcKpbT.js deleted file mode 100644 index a3830b64..00000000 --- a/src/gateway/static/dashboard/assets/SettingsPage-k4BcKpbT.js +++ /dev/null @@ -1 +0,0 @@ -import{j as e}from"./tanstack-query-1t81HyiD.js";import{r as u}from"./react-dgEcD0HR.js";import{J as R,_ as C,P,E as y,M as E,a5 as T,a6 as _,a7 as D,F as A,a8 as O,X as F,a9 as I,I as w}from"./index-D4f8RVEq.js";import{d as v,B as h,A as d,g as K,I as M}from"./heroui-BI50yK5B.js";function b(t,r){return{[t]:r}}function z(t,r){let s=0;for(const a of r)if(a===t[s]&&(s+=1),s===t.length)return!0;return t.length===0}function L(t,r){const s=r.trim().toLowerCase();if(s==="")return!0;const a=`${t.key} ${t.description??""} ${t.group}`.toLowerCase(),n=t.key.toLowerCase().replace(/[^a-z0-9]/g,"");return s.split(/\s+/).every(i=>a.includes(i)||z(i,n))}function B({checked:t,onChange:r,label:s,disabled:a}){return e.jsx("button",{type:"button",role:"switch","aria-checked":t,"aria-label":s,disabled:a,onClick:()=>r(!t),className:`relative inline-flex h-6 w-11 shrink-0 items-center rounded-full transition-colors disabled:opacity-50 ${t?"bg-[var(--otari-brand)]":"bg-[var(--otari-line)]"}`,children:e.jsx("span",{className:`inline-block h-5 w-5 transform rounded-full bg-white shadow transition-transform ${t?"translate-x-5":"translate-x-0.5"}`})})}function $({field:t,onSave:r,disabled:s}){const a=typeof t.value=="number"?t.value:0,[n,i]=u.useState(String(a)),o=t.type==="float";u.useEffect(()=>{i(String(a))},[a]);const c=Number(n),p=n.trim()!==""&&Number.isFinite(c)&&(o||Number.isInteger(c)),m=t.minimum??void 0,x=t.exclusive_minimum??void 0,g=x!==void 0?c>x:m!==void 0?c>=m:c>=0,l=p&&g&&c!==a;return e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(M,{type:"number",min:"0",step:o?"any":"1",inputMode:o?"decimal":"numeric","aria-label":t.key,value:n,disabled:s,onChange:f=>i(f.target.value),className:"w-28 rounded-md border border-[var(--otari-line)] bg-white px-2 py-1 text-right text-sm tabular-nums focus:border-[var(--otari-brand)] focus:outline-none disabled:opacity-50"}),e.jsx(h,{size:"sm",variant:"primary","aria-label":`Save ${t.key}`,isDisabled:s||!l,onPress:()=>r(c),children:"Save"})]})}function H({field:t,onSave:r,disabled:s}){const a=typeof t.value=="string"?t.value:"",[n,i]=u.useState(a);u.useEffect(()=>{i(a)},[a]);const o=n!==a;return e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"text","aria-label":t.key,value:n,disabled:s,placeholder:"unset",onChange:c=>i(c.target.value),className:"w-56 rounded-md border border-[var(--otari-line)] bg-white px-2 py-1 text-sm focus:border-[var(--otari-brand)] focus:outline-none disabled:opacity-50"}),e.jsx(h,{size:"sm",variant:"primary","aria-label":`Save ${t.key}`,isDisabled:s||!o,onPress:()=>r(n.trim()===""?null:n),children:"Save"})]})}function Y(t){const{value:r}=t;return r==null?"unset":typeof r=="boolean"?r?"on":"off":Array.isArray(r)?r.length?r.join(", "):"none":String(r)}function q({field:t,patch:r,disabled:s}){return t.settable?t.type==="bool"?e.jsx(B,{checked:t.value===!0,onChange:a=>r(b(t.key,a)),label:t.key,disabled:s}):t.options&&t.options.length>0?e.jsx(A,{ariaLabel:t.key,value:String(t.value??""),onChange:a=>r(b(t.key,a)),options:t.options.map(a=>({value:a,label:a}))}):t.type==="int"||t.type==="float"?e.jsx($,{field:t,onSave:a=>r(b(t.key,a)),disabled:s}):e.jsx(H,{field:t,onSave:a=>r(b(t.key,a)),disabled:s}):e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-sm tabular-nums text-[var(--otari-ink)]",children:Y(t)}),e.jsx("span",{className:"rounded-full border border-[var(--otari-line)] px-2 py-0.5 text-xs text-[var(--otari-muted)]",children:"startup-only"})]})}function U({field:t,patch:r,disabled:s}){return e.jsxs("div",{className:"flex items-start justify-between gap-6 py-4",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("code",{className:"text-sm font-medium text-[var(--otari-ink)]",children:t.key}),t.description?e.jsx("p",{className:"mt-1 text-sm text-[var(--otari-muted)]",children:t.description}):null]}),e.jsx("div",{className:"shrink-0 pt-0.5",children:e.jsx(q,{field:t,patch:r,disabled:s})})]})}function V({value:t,fieldRef:r}){const s=u.useRef(null),a=r??s,[n,i]=u.useState(!1),[o,c]=u.useState(!1),p=async()=>{var m,x,g;(m=a.current)==null||m.focus(),(x=a.current)==null||x.select();try{if((g=navigator.clipboard)!=null&&g.writeText){await navigator.clipboard.writeText(t),i(!0),c(!1),window.setTimeout(()=>i(!1),2e3);return}}catch{}c(!0)};return e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{className:"text-xs font-medium text-[var(--otari-muted)]",children:"New master key"}),e.jsx(h,{size:"sm",variant:"outline",onPress:p,children:n?"Copied":"Copy"})]}),e.jsx("input",{ref:a,readOnly:!0,value:t,onFocus:m=>m.currentTarget.select(),autoComplete:"off",autoCorrect:"off",autoCapitalize:"off",spellCheck:!1,"data-1p-ignore":!0,"data-lpignore":"true"}),e.jsx("span",{"aria-live":"polite",className:"text-xs text-[var(--otari-brand-dark)]",children:n?"Copied to clipboard.":""}),o?e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"Selected. Press Ctrl/Cmd-C to copy."}):null]})}function G({masterKey:t,error:r,isPending:s,onRegenerate:a,onClose:n}){const i=u.useRef(null);return u.useEffect(()=>{var o,c;t!==void 0&&((o=i.current)==null||o.focus(),(c=i.current)==null||c.select())},[t]),e.jsx(d.Backdrop,{children:e.jsx(d.Container,{placement:"center",size:"lg",children:e.jsxs(d.Dialog,{children:[e.jsx(d.Header,{children:e.jsx(d.Heading,{children:t!==void 0?"Master key regenerated":"Regenerate master key?"})}),e.jsx(d.Body,{className:"flex flex-col gap-4",children:t!==void 0?e.jsxs(e.Fragment,{children:[e.jsx(w,{tone:"warning",children:"Copy this key now. It is shown once and cannot be retrieved again after you close this dialog."}),e.jsx("p",{className:"text-sm text-[var(--otari-muted)]",children:"The previous master key has stopped working. This browser tab now uses the new key."}),e.jsx(V,{value:t,fieldRef:i})]}):e.jsxs(e.Fragment,{children:[e.jsx(w,{tone:"warning",children:"This immediately invalidates the current dashboard master key. Other signed-in dashboard sessions will need the new key to continue."}),e.jsx("p",{className:"text-sm text-[var(--otari-muted)]",children:"The replacement key will be shown once. Save it before closing the next screen."}),e.jsx(y,{error:r})]})}),e.jsx(d.Footer,{children:t!==void 0?e.jsx(h,{variant:"primary",onPress:n,children:"I’ve saved this key"}):e.jsxs(e.Fragment,{children:[e.jsx(h,{variant:"ghost",isDisabled:s,onPress:n,children:"Cancel"}),e.jsx(h,{variant:"danger",isPending:s,onPress:a,children:"Regenerate key"})]})})]})})})}function X({source:t}){const r=O(),[s,a]=u.useState(!1),[n,i]=u.useState(),o=t==="generated",c=()=>r.mutate(void 0,{onSuccess:x=>{i(x.master_key)}}),p=()=>{a(!1),i(void 0),r.reset()},m=x=>{x?(r.reset(),a(!0)):n===void 0&&p()};return e.jsx("div",{className:"flex flex-col gap-4 py-4",children:e.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("code",{className:"text-sm font-medium text-[var(--otari-ink)]",children:"master_key"}),e.jsx("p",{className:"mt-1 max-w-3xl text-sm text-[var(--otari-muted)]",children:o?"This gateway uses its first-run generated dashboard key. Regeneration invalidates the current key immediately.":"This gateway uses a key managed through OTARI_MASTER_KEY or config.yml. Rotate it in configuration, then restart the gateway."})]}),e.jsxs(d,{isOpen:s,onOpenChange:m,children:[o?e.jsx(d.Trigger,{className:K({size:"sm",variant:"danger-soft"}),children:"Regenerate"}):e.jsx(h,{size:"sm",variant:"danger-soft",isDisabled:!0,children:"Managed in configuration"}),s?e.jsx(G,{masterKey:n,error:r.error,isPending:r.isPending,onRegenerate:c,onClose:p}):null]})]})})}function J(){var o;const t=F(),r=I(),s=r.data,a=((o=t.data)==null?void 0:o.length)??0,n=(t.data??[]).filter(c=>!c.decryptable).length,i=a>0;return e.jsxs("div",{className:"flex flex-col gap-4 py-4",children:[e.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("code",{className:"text-sm font-medium text-[var(--otari-ink)]",children:"OTARI_SECRET_KEY"}),e.jsxs("p",{className:"mt-1 max-w-3xl text-sm text-[var(--otari-muted)]",children:["Generate a new key with ",e.jsx("code",{children:"uv run otari gen-secret-key"}),", then restart with"," ",e.jsx("code",{children:"OTARI_SECRET_KEY=,"}),". Re-encrypt the stored provider keys, then restart with ",e.jsx("code",{children:"OTARI_SECRET_KEY="})," once none are unreadable."]})]}),e.jsx("div",{className:"shrink-0",children:e.jsx(h,{size:"sm",variant:"outline",isDisabled:!i||r.isPending,onPress:()=>r.mutate(),children:r.isPending?"Re-encrypting…":"Re-encrypt provider keys"})})]}),e.jsx(y,{error:t.error??r.error}),n>0?e.jsxs(w,{tone:"warning",children:[n," stored provider key",n===1?"":"s"," cannot be decrypted with the current"," ",e.jsx("code",{children:"OTARI_SECRET_KEY"}),". Restore the old secret key and re-encrypt, or edit each affected provider and replace its key."]}):null,s?e.jsxs("p",{className:"text-sm text-[var(--otari-muted)]",role:"status","aria-live":"polite",children:["Re-encrypted ",s.reencrypted," provider key",s.reencrypted===1?"":"s",".",s.unreadable>0?` ${s.unreadable} still need replacement.`:" All decryptable stored keys now use the primary secret key."]}):!t.isLoading&&!i?e.jsx("p",{className:"text-sm text-[var(--otari-muted)]",children:"No stored provider keys need re-encryption."}):null]})}function Q({masterKeySource:t}){return e.jsxs("section",{className:"flex flex-col gap-2",children:[e.jsxs("h2",{className:"text-sm font-semibold text-[var(--otari-ink)]",children:["Credential security ",e.jsx("span",{className:"font-normal text-[var(--otari-muted)]",children:"(2)"})]}),e.jsx(v,{children:e.jsxs(v.Content,{className:"flex flex-col divide-y divide-[var(--otari-line)] px-5 py-1",children:[e.jsx(X,{source:t}),e.jsx(J,{})]})})]})}function W({preview:t,error:r,isPending:s,onAccept:a,onReject:n}){return e.jsx(d.Backdrop,{children:e.jsx(d.Container,{placement:"center",size:"lg",children:e.jsxs(d.Dialog,{children:[e.jsx(d.Header,{children:e.jsx(d.Heading,{children:"Review default price updates"})}),e.jsxs(d.Body,{className:"flex flex-col gap-4",children:[e.jsxs("p",{className:"text-sm text-[var(--otari-muted)]",children:[t.added_count," added, ",t.changed_count," changed, and ",t.removed_count," removed upstream model prices. The accepted catalog is saved in the database with source ",e.jsx("code",{children:"genai-prices"})," and reloads after a restart. Your ",t.protected_model_count," custom model price",t.protected_model_count===1?"":"s"," remain unchanged."]}),t.changes.length>0?e.jsx("ul",{className:"max-h-60 list-disc overflow-auto pl-5 text-sm text-[var(--otari-ink)]",children:t.changes.map(i=>e.jsxs("li",{children:[i.model_key,": ",i.change]},i.model_key))}):null,t.changes_truncated?e.jsx("p",{className:"text-xs text-[var(--otari-muted)]",children:"Only the first 100 changes are shown."}):null,e.jsx(y,{error:r})]}),e.jsxs(d.Footer,{children:[e.jsx(h,{variant:"ghost",isDisabled:s,onPress:n,children:"Reject changes"}),e.jsx(h,{variant:"primary",isPending:s,onPress:a,children:"Accept price updates"})]})]})})})}function Z(){const t=T(),r=_(),s=D(),a=t.data,n=r.isPending||s.isPending,i=()=>{a===void 0||n||s.mutate(void 0,{onSuccess:t.reset})};return e.jsxs("section",{className:"flex flex-col gap-2",children:[e.jsx("h2",{className:"text-sm font-semibold text-[var(--otari-ink)]",children:"Default pricing catalog"}),e.jsx(v,{children:e.jsxs(v.Content,{className:"flex flex-col gap-4 p-5",children:[e.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("div",{className:"text-sm font-medium text-[var(--otari-ink)]",children:"genai-prices defaults"}),e.jsxs("p",{className:"mt-1 max-w-3xl text-sm text-[var(--otari-muted)]",children:["Fetch the latest upstream catalog, review the proposed change summary, then accept or reject it. Accepted data is stored as ",e.jsx("code",{children:"genai-prices"}),"; custom prices remain separate and always take precedence."]})]}),e.jsx(h,{size:"sm",variant:"outline",isDisabled:t.isPending||n,onPress:()=>t.mutate(),children:t.isPending?"Checking prices…":"Check for price updates"})]}),e.jsx(y,{error:t.error})]})}),e.jsxs(d,{isOpen:a!==void 0,onOpenChange:o=>o?void 0:i(),children:[e.jsx(d.Trigger,{className:"hidden",children:"Review price updates"}),a?e.jsx(W,{preview:a,error:r.error??s.error,isPending:n,onAccept:()=>r.mutate(void 0,{onSuccess:t.reset}),onReject:i}):null]})]})}function ee(t){const r=[],s=new Map;for(const a of t){let n=s.get(a.group);n||(n={name:a.group,fields:[]},s.set(a.group,n),r.push(n)),n.fields.push(a)}return r}function ne(){const t=R(),r=C(),s=t.data,a=r.isPending,[n,i]=u.useState(""),[o,c]=u.useState(!1),p=u.useRef(null);u.useEffect(()=>{function l(f){var N;const j=f.target,S=j&&(j.tagName==="INPUT"||j.tagName==="TEXTAREA"||j.tagName==="SELECT");f.key==="/"&&!S&&(f.preventDefault(),(N=p.current)==null||N.focus())}return window.addEventListener("keydown",l),()=>window.removeEventListener("keydown",l)},[]);const m=l=>r.mutate(l),x=(s==null?void 0:s.config)??[],g=x.filter(l=>(o?l.settable:!0)&&L(l,n)),k=ee(g);return e.jsxs("div",{className:"flex flex-col gap-6",children:[e.jsx(P,{title:"Settings",description:"Every effective gateway setting. Settable fields apply immediately and persist across restarts; startup-only fields are shown for reference and change only via config.yml or environment variables (then a restart)."}),e.jsx(y,{error:t.error??r.error}),e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsx("input",{ref:p,type:"search","aria-label":"Search settings",placeholder:"Search settings (press / to focus)…",value:n,onChange:l=>i(l.target.value),onKeyDown:l=>{l.key==="Escape"&&i("")},className:"min-w-0 flex-1 rounded-lg border border-[var(--otari-line)] bg-[var(--otari-bg)] px-3 py-2 text-sm text-[var(--otari-ink)] focus:border-[var(--otari-brand)] focus:outline-none"}),e.jsxs("label",{className:"flex items-center gap-2 text-sm text-[var(--otari-muted)]",children:[e.jsx("input",{type:"checkbox",checked:o,onChange:l=>c(l.target.checked),className:"h-4 w-4 accent-[var(--otari-brand)]"}),"Settable only"]})]}),s?e.jsxs("p",{className:"text-xs text-[var(--otari-muted)]",children:["Showing ",g.length," of ",x.length," settings"]}):null,s&&g.length===0?e.jsx("p",{className:"text-sm text-[var(--otari-muted)]",children:"No settings match your search."}):null,t.isLoading?e.jsx(E,{}):null,k.map(l=>e.jsxs("section",{className:"flex flex-col gap-2",children:[e.jsxs("h2",{className:"text-sm font-semibold text-[var(--otari-ink)]",children:[l.name," ",e.jsxs("span",{className:"font-normal text-[var(--otari-muted)]",children:["(",l.fields.length,")"]})]}),e.jsx(v,{children:e.jsx(v.Content,{className:"flex flex-col divide-y divide-[var(--otari-line)] px-5 py-1",children:l.fields.map(f=>e.jsx(U,{field:f,patch:m,disabled:!s||a},f.key))})})]},l.name)),s?e.jsx(Z,{}):null,s?e.jsx(Q,{masterKeySource:s.master_key_source}):null,s?e.jsxs("p",{className:"text-xs text-[var(--otari-muted)]",children:["Mode: ",s.mode," · Version ",s.version,s.require_pricing?" · require_pricing on":""]}):null]})}export{ne as SettingsPage,L as fieldMatches}; diff --git a/src/gateway/static/dashboard/assets/TablePagination-BTOqrUVz.js b/src/gateway/static/dashboard/assets/TablePagination-8CBn4us4.js similarity index 98% rename from src/gateway/static/dashboard/assets/TablePagination-BTOqrUVz.js rename to src/gateway/static/dashboard/assets/TablePagination-8CBn4us4.js index fb6d6b76..08fc1ac9 100644 --- a/src/gateway/static/dashboard/assets/TablePagination-BTOqrUVz.js +++ b/src/gateway/static/dashboard/assets/TablePagination-8CBn4us4.js @@ -1 +1 @@ -import{j as e}from"./tanstack-query-1t81HyiD.js";import{r as u}from"./react-dgEcD0HR.js";import{I as w,E as M,F as D}from"./index-D4f8RVEq.js";import{A as o,B as x,T as F,L as $,I as T,S as y}from"./heroui-BI50yK5B.js";function _({label:t,value:r,onChange:a,isRequired:c,autoFocus:i}){return e.jsxs(F,{value:r,onChange:a,isRequired:c,className:"flex flex-col gap-1",children:[e.jsx($,{className:"text-sm font-medium text-[var(--otari-ink)]",children:t}),e.jsx(T,{inputMode:"decimal",placeholder:"0.00",autoFocus:i})]})}function R(t){const r=t.trim();if(r==="")return null;const a=Number(r);return Number.isFinite(a)&&a>=0?a:Number.NaN}const C=t=>`Recompute cost for ${t.toLocaleString()} imported ${t===1?"row":"rows"} from each row's own token counts at these per-1M rates. Enforced gateway rows are never affected.`;function W({isOpen:t,onOpenChange:r,targetCount:a,isPending:c,error:i,onSubmit:E,title:I="Set price",description:L=C}){const[j,p]=u.useState(""),[n,h]=u.useState(""),[b,N]=u.useState(""),[f,v]=u.useState("");u.useEffect(()=>{t&&(p(""),h(""),N(""),v(""))},[t]);const m=R(j),l=R(n),d=R(b),s=R(f),g=m===null||Number.isNaN(m)||l===null||Number.isNaN(l)||Number.isNaN(d??0)||Number.isNaN(s??0),S=()=>{g||m===null||l===null||E({input_price_per_million:m,output_price_per_million:l,...d!==null&&!Number.isNaN(d)?{cache_read_price_per_million:d}:{},...s!==null&&!Number.isNaN(s)?{cache_write_price_per_million:s}:{}})};return e.jsx(o,{isOpen:t,onOpenChange:r,children:t?e.jsx(o.Backdrop,{children:e.jsx(o.Container,{placement:"center",size:"lg",children:e.jsxs(o.Dialog,{children:[e.jsx(o.Header,{children:e.jsx(o.Heading,{children:I})}),e.jsxs(o.Body,{className:"flex flex-col gap-4",children:[e.jsx("p",{className:"text-sm text-[var(--otari-muted)]",children:L(a)}),e.jsxs("div",{className:"grid gap-3 sm:grid-cols-2",children:[e.jsx(_,{label:"Input $ / 1M",value:j,onChange:p,isRequired:!0,autoFocus:!0}),e.jsx(_,{label:"Output $ / 1M",value:n,onChange:h,isRequired:!0}),e.jsx(_,{label:"Cache read $ / 1M",value:b,onChange:N}),e.jsx(_,{label:"Cache write $ / 1M",value:f,onChange:v})]}),e.jsx(w,{tone:"info",children:"Leave a cache rate blank to bill those tokens at the input rate."}),e.jsx(M,{error:i})]}),e.jsxs(o.Footer,{children:[e.jsx(x,{variant:"ghost",isDisabled:c,onPress:()=>r(!1),children:"Cancel"}),e.jsx(x,{variant:"primary",isDisabled:g,isPending:c,onPress:S,children:"Set price"})]})]})})}):null})}const P=[25,50,100];function q({page:t,pageSize:r,total:a,rowsOnPage:c,onPageChange:i,onPageSizeChange:E,pageSizeOptions:I=P,isFetching:L=!1,hasNextFallback:j=!1}){const p=u.useId(),n=a!=null?Math.max(1,Math.ceil(a/r)):null,h=t===0,b=n!=null?t>=n-1:!j,N=c>0?t*r+1:0,f=t*r+c,v=a!=null?a===0?"0 of 0":`${N.toLocaleString()}–${f.toLocaleString()} of ${a.toLocaleString()}`:c>0?`${N.toLocaleString()}–${f.toLocaleString()}`:"0",[m,l]=u.useState(String(t+1));u.useEffect(()=>{l(String(t+1))},[t]);const d=()=>{const s=Number.parseInt(m,10);if(Number.isNaN(s)){l(String(t+1));return}const g=n??Number.MAX_SAFE_INTEGER,S=Math.min(Math.max(s,1),g);S-1!==t?i(S-1):l(String(t+1))};return e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("label",{htmlFor:p,className:"text-sm text-[var(--otari-muted)]",children:"Rows"}),e.jsx(D,{id:p,ariaLabel:"Rows per page",value:String(r),onChange:s=>E(Number.parseInt(s,10)),options:I.map(s=>({value:String(s),label:String(s)}))}),L?e.jsx(y,{size:"sm"}):null]}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("span",{className:"text-sm text-[var(--otari-muted)] tabular-nums",children:v}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(x,{size:"sm",variant:"outline","aria-label":"First page",isDisabled:h,onPress:()=>i(0),children:"«"}),e.jsx(x,{size:"sm",variant:"outline","aria-label":"Previous page",isDisabled:h,onPress:()=>i(t-1),children:"‹"}),e.jsxs("span",{className:"inline-flex items-center gap-1 text-sm text-[var(--otari-muted)]",children:[e.jsx("input",{"aria-label":"Page number",inputMode:"numeric",value:m,onChange:s=>l(s.target.value.replace(/[^0-9]/g,"")),onKeyDown:s=>{s.key==="Enter"&&s.currentTarget.blur()},onBlur:d,className:"w-12 rounded-lg border border-[var(--otari-line)] bg-[var(--otari-bg)] px-2 py-1 text-center text-sm text-[var(--otari-ink)] tabular-nums focus:border-[var(--otari-brand)] focus:outline-none"}),n!=null?e.jsxs("span",{className:"tabular-nums",children:["/ ",n.toLocaleString()]}):null]}),e.jsx(x,{size:"sm",variant:"outline","aria-label":"Next page",isDisabled:b,onPress:()=>i(t+1),children:"›"}),e.jsx(x,{size:"sm",variant:"outline","aria-label":"Last page",isDisabled:n==null||b,onPress:()=>n!=null&&i(n-1),children:"»"})]})]})]})}export{P,W as S,q as T}; +import{j as e}from"./tanstack-query-1t81HyiD.js";import{r as u}from"./react-dgEcD0HR.js";import{I as w,E as M,F as D}from"./index-Bi2hajrg.js";import{A as o,B as x,T as F,L as $,I as T,S as y}from"./heroui-BI50yK5B.js";function _({label:t,value:r,onChange:a,isRequired:c,autoFocus:i}){return e.jsxs(F,{value:r,onChange:a,isRequired:c,className:"flex flex-col gap-1",children:[e.jsx($,{className:"text-sm font-medium text-[var(--otari-ink)]",children:t}),e.jsx(T,{inputMode:"decimal",placeholder:"0.00",autoFocus:i})]})}function R(t){const r=t.trim();if(r==="")return null;const a=Number(r);return Number.isFinite(a)&&a>=0?a:Number.NaN}const C=t=>`Recompute cost for ${t.toLocaleString()} imported ${t===1?"row":"rows"} from each row's own token counts at these per-1M rates. Enforced gateway rows are never affected.`;function W({isOpen:t,onOpenChange:r,targetCount:a,isPending:c,error:i,onSubmit:E,title:I="Set price",description:L=C}){const[j,p]=u.useState(""),[n,h]=u.useState(""),[b,N]=u.useState(""),[f,v]=u.useState("");u.useEffect(()=>{t&&(p(""),h(""),N(""),v(""))},[t]);const m=R(j),l=R(n),d=R(b),s=R(f),g=m===null||Number.isNaN(m)||l===null||Number.isNaN(l)||Number.isNaN(d??0)||Number.isNaN(s??0),S=()=>{g||m===null||l===null||E({input_price_per_million:m,output_price_per_million:l,...d!==null&&!Number.isNaN(d)?{cache_read_price_per_million:d}:{},...s!==null&&!Number.isNaN(s)?{cache_write_price_per_million:s}:{}})};return e.jsx(o,{isOpen:t,onOpenChange:r,children:t?e.jsx(o.Backdrop,{children:e.jsx(o.Container,{placement:"center",size:"lg",children:e.jsxs(o.Dialog,{children:[e.jsx(o.Header,{children:e.jsx(o.Heading,{children:I})}),e.jsxs(o.Body,{className:"flex flex-col gap-4",children:[e.jsx("p",{className:"text-sm text-[var(--otari-muted)]",children:L(a)}),e.jsxs("div",{className:"grid gap-3 sm:grid-cols-2",children:[e.jsx(_,{label:"Input $ / 1M",value:j,onChange:p,isRequired:!0,autoFocus:!0}),e.jsx(_,{label:"Output $ / 1M",value:n,onChange:h,isRequired:!0}),e.jsx(_,{label:"Cache read $ / 1M",value:b,onChange:N}),e.jsx(_,{label:"Cache write $ / 1M",value:f,onChange:v})]}),e.jsx(w,{tone:"info",children:"Leave a cache rate blank to bill those tokens at the input rate."}),e.jsx(M,{error:i})]}),e.jsxs(o.Footer,{children:[e.jsx(x,{variant:"ghost",isDisabled:c,onPress:()=>r(!1),children:"Cancel"}),e.jsx(x,{variant:"primary",isDisabled:g,isPending:c,onPress:S,children:"Set price"})]})]})})}):null})}const P=[25,50,100];function q({page:t,pageSize:r,total:a,rowsOnPage:c,onPageChange:i,onPageSizeChange:E,pageSizeOptions:I=P,isFetching:L=!1,hasNextFallback:j=!1}){const p=u.useId(),n=a!=null?Math.max(1,Math.ceil(a/r)):null,h=t===0,b=n!=null?t>=n-1:!j,N=c>0?t*r+1:0,f=t*r+c,v=a!=null?a===0?"0 of 0":`${N.toLocaleString()}–${f.toLocaleString()} of ${a.toLocaleString()}`:c>0?`${N.toLocaleString()}–${f.toLocaleString()}`:"0",[m,l]=u.useState(String(t+1));u.useEffect(()=>{l(String(t+1))},[t]);const d=()=>{const s=Number.parseInt(m,10);if(Number.isNaN(s)){l(String(t+1));return}const g=n??Number.MAX_SAFE_INTEGER,S=Math.min(Math.max(s,1),g);S-1!==t?i(S-1):l(String(t+1))};return e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("label",{htmlFor:p,className:"text-sm text-[var(--otari-muted)]",children:"Rows"}),e.jsx(D,{id:p,ariaLabel:"Rows per page",value:String(r),onChange:s=>E(Number.parseInt(s,10)),options:I.map(s=>({value:String(s),label:String(s)}))}),L?e.jsx(y,{size:"sm"}):null]}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("span",{className:"text-sm text-[var(--otari-muted)] tabular-nums",children:v}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(x,{size:"sm",variant:"outline","aria-label":"First page",isDisabled:h,onPress:()=>i(0),children:"«"}),e.jsx(x,{size:"sm",variant:"outline","aria-label":"Previous page",isDisabled:h,onPress:()=>i(t-1),children:"‹"}),e.jsxs("span",{className:"inline-flex items-center gap-1 text-sm text-[var(--otari-muted)]",children:[e.jsx("input",{"aria-label":"Page number",inputMode:"numeric",value:m,onChange:s=>l(s.target.value.replace(/[^0-9]/g,"")),onKeyDown:s=>{s.key==="Enter"&&s.currentTarget.blur()},onBlur:d,className:"w-12 rounded-lg border border-[var(--otari-line)] bg-[var(--otari-bg)] px-2 py-1 text-center text-sm text-[var(--otari-ink)] tabular-nums focus:border-[var(--otari-brand)] focus:outline-none"}),n!=null?e.jsxs("span",{className:"tabular-nums",children:["/ ",n.toLocaleString()]}):null]}),e.jsx(x,{size:"sm",variant:"outline","aria-label":"Next page",isDisabled:b,onPress:()=>i(t+1),children:"›"}),e.jsx(x,{size:"sm",variant:"outline","aria-label":"Last page",isDisabled:n==null||b,onPress:()=>n!=null&&i(n-1),children:"»"})]})]})]})}export{P,W as S,q as T}; diff --git a/src/gateway/static/dashboard/assets/ToolsGuardrailsPage-Cl0epDLn.js b/src/gateway/static/dashboard/assets/ToolsGuardrailsPage-B4MIR_ke.js similarity index 92% rename from src/gateway/static/dashboard/assets/ToolsGuardrailsPage-Cl0epDLn.js rename to src/gateway/static/dashboard/assets/ToolsGuardrailsPage-B4MIR_ke.js index a2d9fd48..39f7e3e5 100644 --- a/src/gateway/static/dashboard/assets/ToolsGuardrailsPage-Cl0epDLn.js +++ b/src/gateway/static/dashboard/assets/ToolsGuardrailsPage-B4MIR_ke.js @@ -1 +1 @@ -import{j as e}from"./tanstack-query-1t81HyiD.js";import{r as x}from"./react-dgEcD0HR.js";import{aa as L,ab as C,P,E,M as R,G as w,ac as D,F as M}from"./index-D4f8RVEq.js";import{d as N,B as g}from"./heroui-BI50yK5B.js";function U(s,t){return{[s]:t}}const B=[{key:"web_search",label:"Web search",blurb:"Backend for otari_web_search tools (a SearXNG instance or a search adapter).",order:["web_search_url","web_search_engines","web_search_max_results","web_search_extract","web_search_purpose_hint"]},{key:"sandbox",label:"Code execution",blurb:"Backend for otari_code_execution tools (the sandbox that runs generated code).",order:["sandbox_url","sandbox_purpose_hint"]},{key:"guardrails",label:"Guardrails",blurb:"Default input-guardrails service used when a request does not pass its own guardrail URL.",order:["guardrails_url"]}];function $(){const[s,t]=x.useState(null),a=x.useRef(void 0),n=r=>{t(r),window.clearTimeout(a.current),a.current=window.setTimeout(()=>t(null),2500)};return x.useEffect(()=>()=>window.clearTimeout(a.current),[]),[s,n]}function G({message:s}){return s?e.jsxs("div",{role:"status","aria-live":"polite",className:"fixed right-4 bottom-4 z-50 flex items-center gap-2 rounded-lg border border-green-200 bg-green-50 px-4 py-3 text-sm font-medium text-green-700 shadow-lg",children:[e.jsx("svg",{viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2","aria-hidden":!0,className:"h-5 w-5",children:e.jsx("path",{d:"M20 6 9 17l-5-5",strokeLinecap:"round",strokeLinejoin:"round"})}),s]}):null}const S="rounded-md border border-[var(--otari-line)] bg-[var(--otari-surface)] px-2 py-1 text-sm focus:border-[var(--otari-brand)] focus:outline-none disabled:opacity-50",b="grid gap-x-4 gap-y-1.5 py-4 sm:grid-cols-[minmax(0,1fr)_16rem_10rem] sm:items-start",_=`w-full sm:col-start-2 ${S}`,k="flex items-center gap-2 sm:col-start-3",f="flex flex-col gap-1 sm:col-span-2 sm:col-start-2";function j({message:s}){return s?e.jsx("span",{className:"break-words text-xs text-red-700",children:s}):null}function y({field:s,help:t}){return e.jsxs("div",{className:"min-w-0 sm:col-start-1",children:[e.jsx("code",{className:"text-sm font-medium text-[var(--otari-ink)]",children:s.key}),s.description?e.jsx("p",{className:"mt-1 text-sm text-[var(--otari-muted)]",children:s.description}):null,t?e.jsx("p",{className:"mt-1 text-xs text-[var(--otari-muted)]",children:t}):null]})}function z({field:s,onSave:t,saveError:a,disabled:n}){const r=typeof s.value=="string"?s.value:"",[l,i]=x.useState(r),[m,p]=x.useState(null),c=D();x.useEffect(()=>{i(r)},[r]);const o=l.trim()!==r,d=l.trim(),h=m!==null&&m===d;return e.jsxs("div",{className:b,children:[e.jsx(y,{field:s,help:"Leave blank and Save to fall back to the configured default."}),e.jsx("input",{type:"text",inputMode:"url","aria-label":s.key,value:l,disabled:n,placeholder:"unset",onChange:v=>{i(v.target.value),c.reset()},className:_}),e.jsxs("div",{className:k,children:[e.jsx(g,{size:"sm",variant:"primary","aria-label":`Save ${s.key}`,isDisabled:n||!o,onPress:()=>t(d===""?null:d),children:"Save"}),e.jsx(g,{size:"sm",variant:"outline","aria-label":`Test ${s.service}`,isDisabled:d===""||c.isPending,onPress:()=>{p(d),c.mutate({service:s.service,url:d})},children:c.isPending?"Testing…":"Test"})]}),e.jsxs("div",{className:f,children:[e.jsx("span",{role:"status","aria-live":"polite",className:"block break-words text-xs",children:c.isPending||!h?null:c.error?e.jsx("span",{className:"text-red-700",children:w(c.error)}):c.data?e.jsx("span",{className:c.data.ok?"font-medium text-green-700":"text-red-700",children:c.data.reason}):null}),e.jsx(j,{message:a})]})]})}function I({field:s,onSave:t,saveError:a,disabled:n}){const r=typeof s.value=="string"?s.value:"",[l,i]=x.useState(r);x.useEffect(()=>{i(r)},[r]);const m=l!==r;return e.jsxs("div",{className:b,children:[e.jsx(y,{field:s}),e.jsx("input",{type:"text","aria-label":s.key,value:l,disabled:n,placeholder:"default",onChange:p=>i(p.target.value),className:_}),e.jsx("div",{className:k,children:e.jsx(g,{size:"sm",variant:"primary","aria-label":`Save ${s.key}`,isDisabled:n||!m,onPress:()=>t(l.trim()===""?null:l.trim()),children:"Save"})}),a?e.jsx("div",{className:f,children:e.jsx(j,{message:a})}):null]})}function A({field:s,onSave:t,saveError:a,disabled:n}){const r=typeof s.value=="number"?String(s.value):"",[l,i]=x.useState(r);x.useEffect(()=>{i(r)},[r]);const m=l.trim(),p=Number(m),o=(m===""||Number.isInteger(p)&&p>=1)&&m!==r;return e.jsxs("div",{className:b,children:[e.jsx(y,{field:s,help:"Leave blank to use the backend default."}),e.jsx("input",{type:"number",min:"1",step:"1",inputMode:"numeric","aria-label":s.key,value:l,disabled:n,placeholder:"default",onChange:d=>i(d.target.value),className:`w-full text-right tabular-nums sm:col-start-2 sm:w-28 sm:justify-self-end ${S}`}),e.jsx("div",{className:k,children:e.jsx(g,{size:"sm",variant:"primary","aria-label":`Save ${s.key}`,isDisabled:n||!o,onPress:()=>t(m===""?null:p),children:"Save"})}),a?e.jsx("div",{className:f,children:e.jsx(j,{message:a})}):null]})}function F({field:s,onSave:t,saveError:a,disabled:n}){const r=s.value===!0?"on":s.value===!1?"off":"default";return e.jsxs("div",{className:b,children:[e.jsx(y,{field:s}),e.jsx("div",{className:"sm:col-start-2 sm:justify-self-start",children:e.jsx(M,{ariaLabel:s.key,value:r,onChange:l=>t(l==="default"?null:l==="on"),options:[{value:"default",label:"Default"},{value:"on",label:"On"},{value:"off",label:"Off"}],disabled:n})}),a?e.jsx("div",{className:f,children:e.jsx(j,{message:a})}):null]})}function O({field:s,onSave:t,saveError:a,disabled:n}){return s.type==="url"?e.jsx(z,{field:s,onSave:t,saveError:a,disabled:n}):s.type==="int"?e.jsx(A,{field:s,onSave:t,saveError:a,disabled:n}):s.type==="bool"?e.jsx(F,{field:s,onSave:t,saveError:a,disabled:n}):e.jsx(I,{field:s,onSave:t,saveError:a,disabled:n})}function V(){const s=L(),t=C(),[a,n]=$(),[r,l]=x.useState({}),i=s.data,m=!i||t.isPending,p=new Map(((i==null?void 0:i.fields)??[]).map(o=>[o.key,o])),c=(o,d)=>{l(h=>{const{[o.key]:v,...u}=h;return u}),t.mutate(U(o.key,d),{onSuccess:()=>n(`${o.key} saved`),onError:h=>l(v=>({...v,[o.key]:w(h)}))})};return e.jsxs("div",{className:"flex flex-col gap-6",children:[e.jsx(P,{title:"Tools & Guardrails",description:"Configure the built-in tool and guardrail service endpoints without a restart. Changes apply immediately and persist. URLs are validated for shape (http/https) and can be tested for reachability before saving; the network-safety gates for these services live on the Settings page."}),e.jsx(E,{error:s.error}),s.isLoading?e.jsx(R,{}):null,B.map(o=>{const d=o.order.map(u=>p.get(u)).filter(u=>u!==void 0),h=((i==null?void 0:i.fields)??[]).filter(u=>u.service===o.key&&!o.order.includes(u.key)),v=[...d,...h];return v.length===0?null:e.jsxs("section",{className:"flex flex-col gap-2",children:[e.jsx("h2",{className:"text-sm font-semibold text-[var(--otari-ink)]",children:o.label}),e.jsx("p",{className:"text-sm text-[var(--otari-muted)]",children:o.blurb}),e.jsx(N,{children:e.jsx(N.Content,{className:"flex flex-col divide-y divide-[var(--otari-line)] px-5 py-1",children:v.map(u=>e.jsx(O,{field:u,onSave:T=>c(u,T),saveError:r[u.key],disabled:m},u.key))})})]},o.key)}),e.jsx(G,{message:a})]})}export{V as ToolsGuardrailsPage}; +import{j as e}from"./tanstack-query-1t81HyiD.js";import{r as x}from"./react-dgEcD0HR.js";import{ah as L,ai as C,P,E,U as R,N as w,aj as D,F as U}from"./index-Bi2hajrg.js";import{d as N,B as g}from"./heroui-BI50yK5B.js";function M(s,t){return{[s]:t}}const B=[{key:"web_search",label:"Web search",blurb:"Backend for otari_web_search tools (a SearXNG instance or a search adapter).",order:["web_search_url","web_search_engines","web_search_max_results","web_search_extract","web_search_purpose_hint"]},{key:"sandbox",label:"Code execution",blurb:"Backend for otari_code_execution tools (the sandbox that runs generated code).",order:["sandbox_url","sandbox_purpose_hint"]},{key:"guardrails",label:"Guardrails",blurb:"Default input-guardrails service used when a request does not pass its own guardrail URL.",order:["guardrails_url"]}];function $(){const[s,t]=x.useState(null),a=x.useRef(void 0),n=r=>{t(r),window.clearTimeout(a.current),a.current=window.setTimeout(()=>t(null),2500)};return x.useEffect(()=>()=>window.clearTimeout(a.current),[]),[s,n]}function z({message:s}){return s?e.jsxs("div",{role:"status","aria-live":"polite",className:"fixed right-4 bottom-4 z-50 flex items-center gap-2 rounded-lg border border-green-200 bg-green-50 px-4 py-3 text-sm font-medium text-green-700 shadow-lg",children:[e.jsx("svg",{viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2","aria-hidden":!0,className:"h-5 w-5",children:e.jsx("path",{d:"M20 6 9 17l-5-5",strokeLinecap:"round",strokeLinejoin:"round"})}),s]}):null}const S="rounded-md border border-[var(--otari-line)] bg-[var(--otari-surface)] px-2 py-1 text-sm focus:border-[var(--otari-brand)] focus:outline-none disabled:opacity-50",b="grid gap-x-4 gap-y-1.5 py-4 sm:grid-cols-[minmax(0,1fr)_16rem_10rem] sm:items-start",_=`w-full sm:col-start-2 ${S}`,k="flex items-center gap-2 sm:col-start-3",f="flex flex-col gap-1 sm:col-span-2 sm:col-start-2";function j({message:s}){return s?e.jsx("span",{className:"break-words text-xs text-red-700",children:s}):null}function y({field:s,help:t}){return e.jsxs("div",{className:"min-w-0 sm:col-start-1",children:[e.jsx("code",{className:"text-sm font-medium text-[var(--otari-ink)]",children:s.key}),s.description?e.jsx("p",{className:"mt-1 text-sm text-[var(--otari-muted)]",children:s.description}):null,t?e.jsx("p",{className:"mt-1 text-xs text-[var(--otari-muted)]",children:t}):null]})}function G({field:s,onSave:t,saveError:a,disabled:n}){const r=typeof s.value=="string"?s.value:"",[l,i]=x.useState(r),[m,p]=x.useState(null),c=D();x.useEffect(()=>{i(r)},[r]);const o=l.trim()!==r,d=l.trim(),h=m!==null&&m===d;return e.jsxs("div",{className:b,children:[e.jsx(y,{field:s,help:"Leave blank and Save to fall back to the configured default."}),e.jsx("input",{type:"text",inputMode:"url","aria-label":s.key,value:l,disabled:n,placeholder:"unset",onChange:v=>{i(v.target.value),c.reset()},className:_}),e.jsxs("div",{className:k,children:[e.jsx(g,{size:"sm",variant:"primary","aria-label":`Save ${s.key}`,isDisabled:n||!o,onPress:()=>t(d===""?null:d),children:"Save"}),e.jsx(g,{size:"sm",variant:"outline","aria-label":`Test ${s.service}`,isDisabled:d===""||c.isPending,onPress:()=>{p(d),c.mutate({service:s.service,url:d})},children:c.isPending?"Testing…":"Test"})]}),e.jsxs("div",{className:f,children:[e.jsx("span",{role:"status","aria-live":"polite",className:"block break-words text-xs",children:c.isPending||!h?null:c.error?e.jsx("span",{className:"text-red-700",children:w(c.error)}):c.data?e.jsx("span",{className:c.data.ok?"font-medium text-green-700":"text-red-700",children:c.data.reason}):null}),e.jsx(j,{message:a})]})]})}function I({field:s,onSave:t,saveError:a,disabled:n}){const r=typeof s.value=="string"?s.value:"",[l,i]=x.useState(r);x.useEffect(()=>{i(r)},[r]);const m=l!==r;return e.jsxs("div",{className:b,children:[e.jsx(y,{field:s}),e.jsx("input",{type:"text","aria-label":s.key,value:l,disabled:n,placeholder:"default",onChange:p=>i(p.target.value),className:_}),e.jsx("div",{className:k,children:e.jsx(g,{size:"sm",variant:"primary","aria-label":`Save ${s.key}`,isDisabled:n||!m,onPress:()=>t(l.trim()===""?null:l.trim()),children:"Save"})}),a?e.jsx("div",{className:f,children:e.jsx(j,{message:a})}):null]})}function A({field:s,onSave:t,saveError:a,disabled:n}){const r=typeof s.value=="number"?String(s.value):"",[l,i]=x.useState(r);x.useEffect(()=>{i(r)},[r]);const m=l.trim(),p=Number(m),o=(m===""||Number.isInteger(p)&&p>=1)&&m!==r;return e.jsxs("div",{className:b,children:[e.jsx(y,{field:s,help:"Leave blank to use the backend default."}),e.jsx("input",{type:"number",min:"1",step:"1",inputMode:"numeric","aria-label":s.key,value:l,disabled:n,placeholder:"default",onChange:d=>i(d.target.value),className:`w-full text-right tabular-nums sm:col-start-2 sm:w-28 sm:justify-self-end ${S}`}),e.jsx("div",{className:k,children:e.jsx(g,{size:"sm",variant:"primary","aria-label":`Save ${s.key}`,isDisabled:n||!o,onPress:()=>t(m===""?null:p),children:"Save"})}),a?e.jsx("div",{className:f,children:e.jsx(j,{message:a})}):null]})}function F({field:s,onSave:t,saveError:a,disabled:n}){const r=s.value===!0?"on":s.value===!1?"off":"default";return e.jsxs("div",{className:b,children:[e.jsx(y,{field:s}),e.jsx("div",{className:"sm:col-start-2 sm:justify-self-start",children:e.jsx(U,{ariaLabel:s.key,value:r,onChange:l=>t(l==="default"?null:l==="on"),options:[{value:"default",label:"Default"},{value:"on",label:"On"},{value:"off",label:"Off"}],disabled:n})}),a?e.jsx("div",{className:f,children:e.jsx(j,{message:a})}):null]})}function O({field:s,onSave:t,saveError:a,disabled:n}){return s.type==="url"?e.jsx(G,{field:s,onSave:t,saveError:a,disabled:n}):s.type==="int"?e.jsx(A,{field:s,onSave:t,saveError:a,disabled:n}):s.type==="bool"?e.jsx(F,{field:s,onSave:t,saveError:a,disabled:n}):e.jsx(I,{field:s,onSave:t,saveError:a,disabled:n})}function V(){const s=L(),t=C(),[a,n]=$(),[r,l]=x.useState({}),i=s.data,m=!i||t.isPending,p=new Map(((i==null?void 0:i.fields)??[]).map(o=>[o.key,o])),c=(o,d)=>{l(h=>{const{[o.key]:v,...u}=h;return u}),t.mutate(M(o.key,d),{onSuccess:()=>n(`${o.key} saved`),onError:h=>l(v=>({...v,[o.key]:w(h)}))})};return e.jsxs("div",{className:"flex flex-col gap-6",children:[e.jsx(P,{title:"Tools & Guardrails",description:"Configure the built-in tool and guardrail service endpoints without a restart. Changes apply immediately and persist. URLs are validated for shape (http/https) and can be tested for reachability before saving; the network-safety gates for these services live on the Settings page."}),e.jsx(E,{error:s.error}),s.isLoading?e.jsx(R,{}):null,B.map(o=>{const d=o.order.map(u=>p.get(u)).filter(u=>u!==void 0),h=((i==null?void 0:i.fields)??[]).filter(u=>u.service===o.key&&!o.order.includes(u.key)),v=[...d,...h];return v.length===0?null:e.jsxs("section",{className:"flex flex-col gap-2",children:[e.jsx("h2",{className:"text-sm font-semibold text-[var(--otari-ink)]",children:o.label}),e.jsx("p",{className:"text-sm text-[var(--otari-muted)]",children:o.blurb}),e.jsx(N,{children:e.jsx(N.Content,{className:"flex flex-col divide-y divide-[var(--otari-line)] px-5 py-1",children:v.map(u=>e.jsx(O,{field:u,onSave:T=>c(u,T),saveError:r[u.key],disabled:m},u.key))})})]},o.key)}),e.jsx(z,{message:a})]})}export{V as ToolsGuardrailsPage}; diff --git a/src/gateway/static/dashboard/assets/UsagePage-B6Ow1D4j.js b/src/gateway/static/dashboard/assets/UsagePage-B6Ow1D4j.js deleted file mode 100644 index bdd9ba9e..00000000 --- a/src/gateway/static/dashboard/assets/UsagePage-B6Ow1D4j.js +++ /dev/null @@ -1 +0,0 @@ -import{j as e}from"./tanstack-query-1t81HyiD.js";import{i as Ue,r as i}from"./react-dgEcD0HR.js";import{u as Ae,a as Re,d as Y,O as T,P as Oe,E as ye,R as Ke,g as te,q as $e,S as q,T as U,Q as W,V as Be,ad as B,e as Ie,f as ze,b as He,c as xe}from"./index-D4f8RVEq.js";import{i as se,b as Ge,U as ke,a as Qe,d as je,F as Ve,f as Ye}from"./FilterChips-DtSH11eU.js";import{u as Ze,r as We,B as Je}from"./tableSelection-9hV37uhu.js";import{S as ae,B as Xe}from"./charts-DIsd9m--.js";import{C as et}from"./ConfirmDialog-a8LQxZuS.js";import{D as we}from"./DataTable-Bmn_eYSV.js";import{T as tt,S as st}from"./TablePagination-BTOqrUVz.js";import{B as I,S as pe}from"./heroui-BI50yK5B.js";import"./recharts-C4kRDmvS.js";function Z(t){return t.toLocaleString()}function at(t){return t===null?"—":t<1e3?`${Math.round(t)} ms`:`${(t/1e3).toFixed(2)} s`}const fe=Ye(je,ke),ne=15,_e="__other__",ve="__unknown__";function Se({title:t,rows:r,totalCost:h,emptyLabel:n,onDrill:v,loading:m}){const[c,x]=i.useState(!1),j=c?r:r.slice(0,ne),A=r.length-j.length,N=o=>o.is_other?_e:o.key??ve,R=[{id:"name",header:t.replace("Spend by ",""),isRowHeader:!0,cell:o=>{const d=h>0?o.cost/h:0;return e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx("span",{className:"truncate text-[var(--otari-ink)]",children:o.is_other?`Other (${o.requests.toLocaleString()} req)`:o.key===null?"(unknown)":o.key}),e.jsx("span",{className:"h-1 w-full overflow-hidden rounded-full bg-[var(--otari-line)]",children:e.jsx("span",{className:"block h-full rounded-full bg-[var(--otari-brand)]",style:{width:`${Math.min(100,d*100)}%`}})})]})}},{id:"requests",header:"Requests",align:"end",cell:o=>e.jsx("span",{className:"text-[var(--otari-muted)]",children:Z(o.requests)})},{id:"spend",header:"Spend",align:"end",cell:o=>e.jsx("span",{className:"text-[var(--otari-ink)]",children:W(o.cost)})}];return e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("h2",{className:"text-sm font-semibold text-[var(--otari-ink)]",children:t}),e.jsx(we,{ariaLabel:t,columns:R,rows:j,getRowKey:N,isLoading:m,emptyContent:n,onRowAction:o=>{o!==_e&&o!==ve&&v(o)}}),!m&&A>0?e.jsxs(I,{size:"sm",variant:"ghost",onPress:()=>x(!0),children:["Show all ",r.length]}):null,!m&&c&&r.length>ne?e.jsxs(I,{size:"sm",variant:"ghost",onPress:()=>x(!1),children:["Show top ",ne]}):null]})}const nt=[{key:"cost",label:"Cost"},{key:"tokens",label:"Tokens"},{key:"requests",label:"Requests"}];function ot(t,r){return r==="cost"?t.cost:r==="tokens"?t.tokens:t.requests}function be(t,r){return r==="cost"?W(t):r==="tokens"?B(t):Z(t)}function rt(t,r){const h=new Date(t);return Number.isNaN(h.getTime())?t:r==="hour"?h.toLocaleTimeString(void 0,{hour:"2-digit",minute:"2-digit",timeZone:"UTC"}):h.toLocaleDateString(void 0,{month:"short",day:"numeric",timeZone:"UTC"})}function lt(t,r,h){const n=t.map(m=>({label:rt(m.bucket_start,h),value:ot(m,r)})),v=n.length?Math.max(...n.map(m=>m.value)):0;return{points:n,peak:v,count:t.length}}const it=50;function ct(t){const r=new Date(t).getTime();if(Number.isNaN(r))return t;const h=Math.max(0,Math.round((Date.now()-r)/1e3));if(h<60)return`${h}s ago`;const n=Math.round(h/60);if(n<60)return`${n}m ago`;const v=Math.round(n/60);return v<24?`${v}h ago`:`${Math.round(v/24)}d ago`}function dt({status:t}){return e.jsx("span",{className:`inline-flex items-center rounded-full border px-2 py-0.5 text-xs font-medium ${t==="error"?"border-red-200 bg-red-50 text-red-700":"border-[var(--otari-line)] bg-[var(--otari-brand-tint)] text-[var(--otari-brand-dark)]"}`,children:t})}const ut=[{id:"time",header:"Time",isRowHeader:!0,cell:t=>e.jsx("span",{className:"text-[var(--otari-muted)]",title:new Date(t.timestamp).toLocaleString(),children:ct(t.timestamp)})},{id:"model",header:"Model",cell:t=>e.jsx("span",{className:"text-[var(--otari-ink)]",children:t.model})},{id:"user",header:"User",cell:t=>e.jsx("span",{className:"text-[var(--otari-muted)]",children:t.user_id??"—"})},{id:"tokens",header:"Tokens",align:"end",cell:t=>t.total_tokens===null?"—":t.total_tokens.toLocaleString()},{id:"cost",header:"Cost",align:"end",cell:t=>t.cost===null?"—":W(t.cost)},{id:"status",header:"Status",cell:t=>e.jsx(dt,{status:t.status})}],mt=t=>t.id;function ht({filters:t,anyFilter:r}){var $,H;const[h,n]=i.useState(0),[v,m]=i.useState(it),c=Ze(),x=Ie(),j=ze(),[A,N]=i.useState(!1),[R,o]=i.useState(!1),d=JSON.stringify(t),L=i.useRef(d);i.useEffect(()=>{L.current!==d&&(L.current=d,n(0),c.clear())},[d,c]);const p=He(t,h,v),C=xe(t),g=p.data??[],P=C.isSuccess&&!C.isPlaceholderData?(($=C.data)==null?void 0:$.total)??0:null,O=g.filter(_=>!_.counts_toward_budget).map(_=>_.id),f=g.filter(_=>_.counts_toward_budget).map(_=>_.id),S=We(c.selectedKeys,O),b=S.length,k=c.allMatching||b>0,D=i.useMemo(()=>({...t,counts_toward_budget:!1}),[t]),y=xe(D,k),E=y.isSuccess?((H=y.data)==null?void 0:H.total)??null:null,K=O.length>0&&b===O.length&&E!=null&&E>b,F=c.allMatching?E??b:b,l=()=>c.allMatching?{by_filter:!0,model:t.model,user_id:t.user_id,api_key_id:t.api_key_id,start_date:t.start_date,end_date:t.end_date,priced:t.priced}:{ids:S},a=()=>x.mutate(l(),{onSuccess:()=>{N(!1),c.clear()}}),u=_=>j.mutate({...l(),..._},{onSuccess:()=>{o(!1),c.clear()}});return e.jsxs("div",{className:"flex flex-col gap-3",children:[e.jsx("h2",{className:"text-sm font-semibold text-[var(--otari-ink)]",children:"Individual requests"}),e.jsx(ye,{error:p.error??C.error}),k?e.jsxs(Je,{selectedCount:F,allMatching:c.allMatching,matchingTotal:E,canSelectAllMatching:K,onSelectAllMatching:c.enableAllMatching,onClear:c.clear,children:[e.jsx(I,{size:"sm",variant:"primary",onPress:()=>o(!0),children:"Set price"}),e.jsx(I,{size:"sm",variant:"danger",onPress:()=>N(!0),children:"Delete"})]}):null,e.jsx(we,{ariaLabel:"Individual requests",columns:ut,rows:g,getRowKey:mt,isLoading:p.isLoading,emptyContent:r?"No requests match these filters.":"No requests recorded yet.",selectionMode:"multiple",selectedKeys:c.selectedKeys,onSelectionChange:c.onSelectionChange,disabledKeys:f}),e.jsx(tt,{page:h,pageSize:v,total:P,rowsOnPage:g.length,onPageChange:n,onPageSizeChange:_=>{m(_),n(0)},isFetching:p.isFetching,hasNextFallback:g.length===v}),e.jsx(et,{isOpen:A,onOpenChange:N,heading:"Delete usage rows",body:`Delete ${F.toLocaleString()} imported ${F===1?"row":"rows"}? Only imported rows are removed, and this cannot be undone.`,confirmLabel:"Delete",isPending:x.isPending,error:x.error,onConfirm:a}),e.jsx(st,{isOpen:R,onOpenChange:o,targetCount:F,isPending:j.isPending,error:j.error,onSubmit:u})]})}function wt(){var ue,me,he,ge;const t=Ue(),r=Ae(),h=Re(),[n,v]=i.useState(fe),[m,c]=i.useState(()=>se(fe.seconds??0)),[x,j]=i.useState(!1),[A,N]=i.useState(),[R,o]=i.useState(),[d,L]=i.useState(""),[p,C]=i.useState(""),[g,z]=i.useState(""),[P,O]=i.useState("cost"),f=x?A:m,S=x?R:void 0,b=x?f?Ge(f,S):"day":n.bucket,k=i.useMemo(()=>({start_date:f,end_date:S,model:d.trim()||void 0,user_id:p||void 0,api_key_id:g||void 0}),[f,S,d,p,g]),D=i.useMemo(()=>{if(x){if(!f||!S)return null;const s=new Date(S).getTime()-new Date(f).getTime();return s>0?{...k,start_date:new Date(new Date(f).getTime()-s).toISOString(),end_date:f}:null}return!m||n.seconds===null?null:{...k,start_date:new Date(new Date(m).getTime()-n.seconds*1e3).toISOString(),end_date:m}},[x,f,S,k,n.seconds,m]),y=Y(k,b),E=Y(D??k,b,D!==null),oe=i.useMemo(()=>({start_date:m,model:d.trim()||void 0,user_id:p||void 0,api_key_id:g||void 0}),[m,d,p,g]),K=Y(oe,n.bucket),F=(((ue=K.data)==null?void 0:ue.series)??[]).map(s=>({bucketStart:s.bucket_start,requests:s.requests})),l=y.data,a=l==null?void 0:l.totals,u=D!==null?(me=E.data)==null?void 0:me.totals:void 0,$=a?T(a.cost,u==null?void 0:u.cost):null,H=i.useMemo(()=>({...k,model:void 0}),[k]),_=Y(H,b),J=((ge=(he=_.data)==null?void 0:he.by_model)==null?void 0:ge.filter(s=>!s.is_other&&s.key!==null).map(s=>s.key))??[],re=(r.data??[]).map(s=>({value:s.user_id,label:s.alias?`${s.alias} (${s.user_id})`:s.user_id})),le=(h.data??[]).map(s=>({value:s.id,label:s.key_name??`${s.id.slice(0,8)}…`})),Ne=(d&&!J.includes(d)?[d,...J]:J).map(s=>({value:s,label:s})),Ce=x||n.key!==ke,G=!!(d.trim()||p||g||Ce),ie=(s,w)=>{var Q;return((Q=s.find(V=>V.value===w))==null?void 0:Q.label)??w},Pe=()=>{L(""),C(""),z("")},Ee=[...p?[{key:"user",label:"User",value:ie(re,p),onClear:()=>C("")}]:[],...d.trim()?[{key:"model",label:"Model",value:d.trim(),onClear:()=>L("")}]:[],...g?[{key:"key",label:"API key",value:ie(le,g),onClear:()=>z("")}]:[]],qe=!!(l&&a&&a.request_count===0&&!G),Le=(l==null?void 0:l.start_date)??f,De=(l==null?void 0:l.end_date)??S,ce=s=>{j(!1),v(s),c(se(s.seconds??0)),N(void 0),o(void 0)},Fe=(s,w)=>{j(!0),N(s),o(w)},Me=()=>{x||c(se(n.seconds??0)),y.refetch(),K.refetch(),_.refetch(),D!==null&&E.refetch()},de=s=>{const w=new URLSearchParams;f&&w.set("start_date",f),S&&w.set("end_date",S);for(const[Q,V]of Object.entries(s))V&&w.set(Q,V);t(`/activity?${w.toString()}`)},Te=a&&a.request_count>0?a.error_count/a.request_count:0,M=(l==null?void 0:l.series)??[],X=M.length>1,ee=lt(M,P,b);return e.jsxs("div",{className:"flex flex-col gap-6",children:[e.jsx(Oe,{title:"Usage & analytics",description:"Aggregate spend, tokens, and request volume over time. Click a model or user to drill into the request log."}),e.jsx(ye,{error:y.error}),e.jsxs("div",{className:"flex flex-col gap-3",children:[e.jsx(Qe,{presets:je,extentKey:n.key,onPreset:ce,onSelectRange:Fe,onSelectFull:()=>ce(n),series:F,bucket:n.bucket,windowStart:Le,windowEnd:De,loading:K.isLoading,ariaLabel:"Usage request volume over the selected window",action:e.jsx(Ke,{onRefresh:Me,isFetching:y.isFetching,updatedAt:y.dataUpdatedAt})}),e.jsxs(Ve,{chips:Ee,onClearAll:Pe,children:[e.jsx(te,{label:"User",value:p,onChange:C,options:re,placeholder:"All users"}),e.jsx(te,{label:"Model",value:d,onChange:L,options:Ne,placeholder:"All models"}),e.jsx(te,{label:"API key",value:g,onChange:z,options:le,placeholder:"All keys"})]})]}),qe?e.jsx($e,{title:"No usage yet",description:"Once the gateway serves requests, spend and volume appear here."}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"grid grid-cols-2 gap-4 sm:grid-cols-3 xl:grid-cols-4",children:[e.jsx(q,{label:"Tracked cost",value:a?W(a.cost):"—",hint:a?e.jsxs("span",{className:"text-[var(--otari-muted)]",children:[e.jsx(U,{fraction:$}),a.unpriced_requests?`${$!==null?" · ":""}${Z(a.unpriced_requests)} unpriced`:null]}):null,chart:X?e.jsx(ae,{values:M.map(s=>s.cost),ariaLabel:"Spend trend over the selected window"}):void 0}),e.jsx(q,{label:"Requests",value:a?Z(a.request_count):"—",hint:a?e.jsxs("span",{className:"text-[var(--otari-muted)]",children:[Be(Te)," errors",u?e.jsxs(e.Fragment,{children:[" · ",e.jsx(U,{fraction:T(a.request_count,u.request_count)})]}):null]}):null,chart:X?e.jsx(ae,{values:M.map(s=>s.requests),ariaLabel:"Request volume trend over the selected window"}):void 0}),e.jsx(q,{label:"Tokens",value:a?B(a.total_tokens):"—",hint:a?e.jsx(U,{fraction:T(a.total_tokens,u==null?void 0:u.total_tokens)}):null,chart:X?e.jsx(ae,{values:M.map(s=>s.tokens),ariaLabel:"Token usage trend over the selected window"}):void 0}),e.jsx(q,{label:"Cache read",value:a?B(a.cache_read_tokens):"—",hint:a?e.jsx(U,{fraction:T(a.cache_read_tokens,u==null?void 0:u.cache_read_tokens)}):null}),e.jsx(q,{label:"Cache write",value:a?B(a.cache_write_tokens):"—",hint:a?e.jsx(U,{fraction:T(a.cache_write_tokens,u==null?void 0:u.cache_write_tokens)}):null}),e.jsx(q,{label:"1h cache write",value:a?B(a.cache_write_1h_tokens??0):"—",hint:a?e.jsx(U,{fraction:T(a.cache_write_1h_tokens??0,(u==null?void 0:u.cache_write_1h_tokens)??0)}):null}),e.jsx(q,{label:"Avg latency",value:a?at(a.avg_latency_ms):"—"})]}),e.jsxs("div",{className:"grid gap-6 lg:grid-cols-2",children:[e.jsx(Se,{title:"Spend by model",rows:(l==null?void 0:l.by_model)??[],totalCost:(a==null?void 0:a.cost)??0,emptyLabel:G?"No usage matches these filters.":"No usage recorded yet.",onDrill:s=>de({model:s,user_id:p||void 0,api_key_id:g||void 0}),loading:y.isLoading}),e.jsx(Se,{title:"Spend by user",rows:(l==null?void 0:l.by_user)??[],totalCost:(a==null?void 0:a.cost)??0,emptyLabel:G?"No usage matches these filters.":"No usage recorded yet.",onDrill:s=>de({user_id:s,model:d.trim()||void 0,api_key_id:g||void 0}),loading:y.isLoading})]}),e.jsx(ht,{filters:k,anyFilter:G}),e.jsxs("div",{className:"flex flex-col gap-3 rounded-xl border border-[var(--otari-line)] bg-[var(--otari-surface)] p-4",children:[e.jsxs("div",{className:"flex items-center justify-between gap-3",children:[e.jsx("h2",{className:"text-sm font-semibold text-[var(--otari-ink)]",children:"Over time"}),e.jsxs("div",{className:"inline-flex gap-1.5",children:[nt.map(s=>e.jsx(I,{size:"sm",variant:P===s.key?"primary":"outline",onPress:()=>O(s.key),children:s.label},s.key)),y.isFetching?e.jsx(pe,{size:"sm"}):null]})]}),y.isLoading?e.jsx("div",{className:"flex h-48 items-center justify-center",children:e.jsx(pe,{size:"sm"})}):M.length===0?e.jsx("div",{className:"flex h-48 items-center justify-center text-sm text-[var(--otari-muted)]",children:"No data in this range."}):e.jsxs("figure",{className:"flex flex-col gap-2",children:[e.jsx(Xe,{data:ee.points,formatValue:s=>be(s,P),ariaLabel:`${P} per ${b}`}),e.jsxs("figcaption",{className:"text-xs text-[var(--otari-muted)]",children:[be(ee.peak,P)," peak · ",ee.count," ",b==="hour"?"hours":"days"," (times in UTC)"]})]})]})]})]})}export{wt as UsagePage}; diff --git a/src/gateway/static/dashboard/assets/UsagePage-CGU7s9AT.js b/src/gateway/static/dashboard/assets/UsagePage-CGU7s9AT.js new file mode 100644 index 00000000..37468516 --- /dev/null +++ b/src/gateway/static/dashboard/assets/UsagePage-CGU7s9AT.js @@ -0,0 +1 @@ +import{j as e}from"./tanstack-query-1t81HyiD.js";import{i as Ae,r as i}from"./react-dgEcD0HR.js";import{u as Ue,a as Re,k as te,e as Oe,d as Y,W as T,ak as ke,P as Ke,E as ye,al as je,R as $e,j as se,w as Be,X as q,_ as A,Z as V,a0 as Ie,am as B,f as ze,g as He,h as Ze,b as Ge,c as xe}from"./index-Bi2hajrg.js";import{A as We,F as Ye}from"./FilterChips-Dqy1SR3R.js";import{u as Qe,r as Ve,B as Je}from"./tableSelection-9hV37uhu.js";import{S as ae,B as Xe}from"./charts-DIsd9m--.js";import{C as et}from"./ConfirmDialog-ChuHp-Qm.js";import{D as we}from"./DataTable-Bmn_eYSV.js";import{T as tt,S as st}from"./TablePagination-8CBn4us4.js";import{B as I,S as pe}from"./heroui-BI50yK5B.js";import"./recharts-C4kRDmvS.js";function Q(t){return t.toLocaleString()}function at(t){return t===null?"—":t<1e3?`${Math.round(t)} ms`:`${(t/1e3).toFixed(2)} s`}const fe=ze(je,ke),ne=15,_e="__other__",ve="__unknown__";function Se({title:t,rows:r,totalCost:h,emptyLabel:n,onDrill:v,loading:m}){const[c,x]=i.useState(!1),j=c?r:r.slice(0,ne),U=r.length-j.length,N=o=>o.is_other?_e:o.key??ve,R=[{id:"name",header:t.replace("Spend by ",""),isRowHeader:!0,cell:o=>{const d=h>0?o.cost/h:0;return e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx("span",{className:"truncate text-[var(--otari-ink)]",children:o.is_other?`Other (${o.requests.toLocaleString()} req)`:o.key===null?"(unknown)":o.key}),e.jsx("span",{className:"h-1 w-full overflow-hidden rounded-full bg-[var(--otari-line)]",children:e.jsx("span",{className:"block h-full rounded-full bg-[var(--otari-brand)]",style:{width:`${Math.min(100,d*100)}%`}})})]})}},{id:"requests",header:"Requests",align:"end",cell:o=>e.jsx("span",{className:"text-[var(--otari-muted)]",children:Q(o.requests)})},{id:"spend",header:"Spend",align:"end",cell:o=>e.jsx("span",{className:"text-[var(--otari-ink)]",children:V(o.cost)})}];return e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("h2",{className:"text-sm font-semibold text-[var(--otari-ink)]",children:t}),e.jsx(we,{ariaLabel:t,columns:R,rows:j,getRowKey:N,isLoading:m,emptyContent:n,onRowAction:o=>{o!==_e&&o!==ve&&v(o)}}),!m&&U>0?e.jsxs(I,{size:"sm",variant:"ghost",onPress:()=>x(!0),children:["Show all ",r.length]}):null,!m&&c&&r.length>ne?e.jsxs(I,{size:"sm",variant:"ghost",onPress:()=>x(!1),children:["Show top ",ne]}):null]})}const nt=[{key:"cost",label:"Cost"},{key:"tokens",label:"Tokens"},{key:"requests",label:"Requests"}];function ot(t,r){return r==="cost"?t.cost:r==="tokens"?t.tokens:t.requests}function be(t,r){return r==="cost"?V(t):r==="tokens"?B(t):Q(t)}function rt(t,r){const h=new Date(t);return Number.isNaN(h.getTime())?t:r==="hour"?h.toLocaleTimeString(void 0,{hour:"2-digit",minute:"2-digit",timeZone:"UTC"}):h.toLocaleDateString(void 0,{month:"short",day:"numeric",timeZone:"UTC"})}function lt(t,r,h){const n=t.map(m=>({label:rt(m.bucket_start,h),value:ot(m,r)})),v=n.length?Math.max(...n.map(m=>m.value)):0;return{points:n,peak:v,count:t.length}}const it=50;function ct(t){const r=new Date(t).getTime();if(Number.isNaN(r))return t;const h=Math.max(0,Math.round((Date.now()-r)/1e3));if(h<60)return`${h}s ago`;const n=Math.round(h/60);if(n<60)return`${n}m ago`;const v=Math.round(n/60);return v<24?`${v}h ago`:`${Math.round(v/24)}d ago`}function dt({status:t}){return e.jsx("span",{className:`inline-flex items-center rounded-full border px-2 py-0.5 text-xs font-medium ${t==="error"?"border-red-200 bg-red-50 text-red-700":"border-[var(--otari-line)] bg-[var(--otari-brand-tint)] text-[var(--otari-brand-dark)]"}`,children:t})}const ut=[{id:"time",header:"Time",isRowHeader:!0,cell:t=>e.jsx("span",{className:"text-[var(--otari-muted)]",title:new Date(t.timestamp).toLocaleString(),children:ct(t.timestamp)})},{id:"model",header:"Model",cell:t=>e.jsx("span",{className:"text-[var(--otari-ink)]",children:t.model})},{id:"user",header:"User",cell:t=>e.jsx("span",{className:"text-[var(--otari-muted)]",children:t.user_id??"—"})},{id:"tokens",header:"Tokens",align:"end",cell:t=>t.total_tokens===null?"—":t.total_tokens.toLocaleString()},{id:"cost",header:"Cost",align:"end",cell:t=>t.cost===null?"—":V(t.cost)},{id:"status",header:"Status",cell:t=>e.jsx(dt,{status:t.status})}],mt=t=>t.id;function ht({filters:t,anyFilter:r}){var $,H;const[h,n]=i.useState(0),[v,m]=i.useState(it),c=Qe(),x=He(),j=Ze(),[U,N]=i.useState(!1),[R,o]=i.useState(!1),d=JSON.stringify(t),L=i.useRef(d);i.useEffect(()=>{L.current!==d&&(L.current=d,n(0),c.clear())},[d,c]);const p=Ge(t,h,v),C=xe(t),g=p.data??[],P=C.isSuccess&&!C.isPlaceholderData?(($=C.data)==null?void 0:$.total)??0:null,O=g.filter(_=>!_.counts_toward_budget).map(_=>_.id),f=g.filter(_=>_.counts_toward_budget).map(_=>_.id),S=Ve(c.selectedKeys,O),b=S.length,y=c.allMatching||b>0,D=i.useMemo(()=>({...t,counts_toward_budget:!1}),[t]),k=xe(D,y),E=k.isSuccess?((H=k.data)==null?void 0:H.total)??null:null,K=O.length>0&&b===O.length&&E!=null&&E>b,F=c.allMatching?E??b:b,l=()=>c.allMatching?{by_filter:!0,model:t.model,user_id:t.user_id,api_key_id:t.api_key_id,start_date:t.start_date,end_date:t.end_date,priced:t.priced}:{ids:S},a=()=>x.mutate(l(),{onSuccess:()=>{N(!1),c.clear()}}),u=_=>j.mutate({...l(),..._},{onSuccess:()=>{o(!1),c.clear()}});return e.jsxs("div",{className:"flex flex-col gap-3",children:[e.jsx("h2",{className:"text-sm font-semibold text-[var(--otari-ink)]",children:"Individual requests"}),e.jsx(ye,{error:p.error??C.error}),y?e.jsxs(Je,{selectedCount:F,allMatching:c.allMatching,matchingTotal:E,canSelectAllMatching:K,onSelectAllMatching:c.enableAllMatching,onClear:c.clear,children:[e.jsx(I,{size:"sm",variant:"primary",onPress:()=>o(!0),children:"Set price"}),e.jsx(I,{size:"sm",variant:"danger",onPress:()=>N(!0),children:"Delete"})]}):null,e.jsx(we,{ariaLabel:"Individual requests",columns:ut,rows:g,getRowKey:mt,isLoading:p.isLoading,emptyContent:r?"No requests match these filters.":"No requests recorded yet.",selectionMode:"multiple",selectedKeys:c.selectedKeys,onSelectionChange:c.onSelectionChange,disabledKeys:f}),e.jsx(tt,{page:h,pageSize:v,total:P,rowsOnPage:g.length,onPageChange:n,onPageSizeChange:_=>{m(_),n(0)},isFetching:p.isFetching,hasNextFallback:g.length===v}),e.jsx(et,{isOpen:U,onOpenChange:N,heading:"Delete usage rows",body:`Delete ${F.toLocaleString()} imported ${F===1?"row":"rows"}? Only imported rows are removed, and this cannot be undone.`,confirmLabel:"Delete",isPending:x.isPending,error:x.error,onConfirm:a}),e.jsx(st,{isOpen:R,onOpenChange:o,targetCount:F,isPending:j.isPending,error:j.error,onSubmit:u})]})}function wt(){var ue,me,he,ge;const t=Ae(),r=Ue(),h=Re(),[n,v]=i.useState(fe),[m,c]=i.useState(()=>te(fe.seconds??0)),[x,j]=i.useState(!1),[U,N]=i.useState(),[R,o]=i.useState(),[d,L]=i.useState(""),[p,C]=i.useState(""),[g,z]=i.useState(""),[P,O]=i.useState("cost"),f=x?U:m,S=x?R:void 0,b=x?f?Oe(f,S):"day":n.bucket,y=i.useMemo(()=>({start_date:f,end_date:S,model:d.trim()||void 0,user_id:p||void 0,api_key_id:g||void 0}),[f,S,d,p,g]),D=i.useMemo(()=>{if(x){if(!f||!S)return null;const s=new Date(S).getTime()-new Date(f).getTime();return s>0?{...y,start_date:new Date(new Date(f).getTime()-s).toISOString(),end_date:f}:null}return!m||n.seconds===null?null:{...y,start_date:new Date(new Date(m).getTime()-n.seconds*1e3).toISOString(),end_date:m}},[x,f,S,y,n.seconds,m]),k=Y(y,b),E=Y(D??y,b,D!==null),oe=i.useMemo(()=>({start_date:m,model:d.trim()||void 0,user_id:p||void 0,api_key_id:g||void 0}),[m,d,p,g]),K=Y(oe,n.bucket),F=(((ue=K.data)==null?void 0:ue.series)??[]).map(s=>({bucketStart:s.bucket_start,requests:s.requests})),l=k.data,a=l==null?void 0:l.totals,u=D!==null?(me=E.data)==null?void 0:me.totals:void 0,$=a?T(a.cost,u==null?void 0:u.cost):null,H=i.useMemo(()=>({...y,model:void 0}),[y]),_=Y(H,b),J=((ge=(he=_.data)==null?void 0:he.by_model)==null?void 0:ge.filter(s=>!s.is_other&&s.key!==null).map(s=>s.key))??[],re=(r.data??[]).map(s=>({value:s.user_id,label:s.alias?`${s.alias} (${s.user_id})`:s.user_id})),le=(h.data??[]).map(s=>({value:s.id,label:s.key_name??`${s.id.slice(0,8)}…`})),Ne=(d&&!J.includes(d)?[d,...J]:J).map(s=>({value:s,label:s})),Ce=x||n.key!==ke,Z=!!(d.trim()||p||g||Ce),ie=(s,w)=>{var G;return((G=s.find(W=>W.value===w))==null?void 0:G.label)??w},Pe=()=>{L(""),C(""),z("")},Ee=[...p?[{key:"user",label:"User",value:ie(re,p),onClear:()=>C("")}]:[],...d.trim()?[{key:"model",label:"Model",value:d.trim(),onClear:()=>L("")}]:[],...g?[{key:"key",label:"API key",value:ie(le,g),onClear:()=>z("")}]:[]],qe=!!(l&&a&&a.request_count===0&&!Z),Le=(l==null?void 0:l.start_date)??f,De=(l==null?void 0:l.end_date)??S,ce=s=>{j(!1),v(s),c(te(s.seconds??0)),N(void 0),o(void 0)},Fe=(s,w)=>{j(!0),N(s),o(w)},Me=()=>{x||c(te(n.seconds??0)),k.refetch(),K.refetch(),_.refetch(),D!==null&&E.refetch()},de=s=>{const w=new URLSearchParams;f&&w.set("start_date",f),S&&w.set("end_date",S);for(const[G,W]of Object.entries(s))W&&w.set(G,W);t(`/activity?${w.toString()}`)},Te=a&&a.request_count>0?a.error_count/a.request_count:0,M=(l==null?void 0:l.series)??[],X=M.length>1,ee=lt(M,P,b);return e.jsxs("div",{className:"flex flex-col gap-6",children:[e.jsx(Ke,{title:"Usage & analytics",description:"Aggregate spend, tokens, and request volume over time. Click a model or user to drill into the request log."}),e.jsx(ye,{error:k.error}),e.jsxs("div",{className:"flex flex-col gap-3",children:[e.jsx(We,{presets:je,extentKey:n.key,onPreset:ce,onSelectRange:Fe,onSelectFull:()=>ce(n),series:F,bucket:n.bucket,windowStart:Le,windowEnd:De,loading:K.isLoading,ariaLabel:"Usage request volume over the selected window",action:e.jsx($e,{onRefresh:Me,isFetching:k.isFetching,updatedAt:k.dataUpdatedAt})}),e.jsxs(Ye,{chips:Ee,onClearAll:Pe,children:[e.jsx(se,{label:"User",value:p,onChange:C,options:re,placeholder:"All users"}),e.jsx(se,{label:"Model",value:d,onChange:L,options:Ne,placeholder:"All models"}),e.jsx(se,{label:"API key",value:g,onChange:z,options:le,placeholder:"All keys"})]})]}),qe?e.jsx(Be,{title:"No usage yet",description:"Once the gateway serves requests, spend and volume appear here."}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"grid grid-cols-2 gap-4 sm:grid-cols-3 xl:grid-cols-4",children:[e.jsx(q,{label:"Tracked cost",value:a?V(a.cost):"—",hint:a?e.jsxs("span",{className:"text-[var(--otari-muted)]",children:[e.jsx(A,{fraction:$}),a.unpriced_requests?`${$!==null?" · ":""}${Q(a.unpriced_requests)} unpriced`:null]}):null,chart:X?e.jsx(ae,{values:M.map(s=>s.cost),ariaLabel:"Spend trend over the selected window"}):void 0}),e.jsx(q,{label:"Requests",value:a?Q(a.request_count):"—",hint:a?e.jsxs("span",{className:"text-[var(--otari-muted)]",children:[Ie(Te)," errors",u?e.jsxs(e.Fragment,{children:[" · ",e.jsx(A,{fraction:T(a.request_count,u.request_count)})]}):null]}):null,chart:X?e.jsx(ae,{values:M.map(s=>s.requests),ariaLabel:"Request volume trend over the selected window"}):void 0}),e.jsx(q,{label:"Tokens",value:a?B(a.total_tokens):"—",hint:a?e.jsx(A,{fraction:T(a.total_tokens,u==null?void 0:u.total_tokens)}):null,chart:X?e.jsx(ae,{values:M.map(s=>s.tokens),ariaLabel:"Token usage trend over the selected window"}):void 0}),e.jsx(q,{label:"Cache read",value:a?B(a.cache_read_tokens):"—",hint:a?e.jsx(A,{fraction:T(a.cache_read_tokens,u==null?void 0:u.cache_read_tokens)}):null}),e.jsx(q,{label:"Cache write",value:a?B(a.cache_write_tokens):"—",hint:a?e.jsx(A,{fraction:T(a.cache_write_tokens,u==null?void 0:u.cache_write_tokens)}):null}),e.jsx(q,{label:"1h cache write",value:a?B(a.cache_write_1h_tokens??0):"—",hint:a?e.jsx(A,{fraction:T(a.cache_write_1h_tokens??0,(u==null?void 0:u.cache_write_1h_tokens)??0)}):null}),e.jsx(q,{label:"Avg latency",value:a?at(a.avg_latency_ms):"—"})]}),e.jsxs("div",{className:"grid gap-6 lg:grid-cols-2",children:[e.jsx(Se,{title:"Spend by model",rows:(l==null?void 0:l.by_model)??[],totalCost:(a==null?void 0:a.cost)??0,emptyLabel:Z?"No usage matches these filters.":"No usage recorded yet.",onDrill:s=>de({model:s,user_id:p||void 0,api_key_id:g||void 0}),loading:k.isLoading}),e.jsx(Se,{title:"Spend by user",rows:(l==null?void 0:l.by_user)??[],totalCost:(a==null?void 0:a.cost)??0,emptyLabel:Z?"No usage matches these filters.":"No usage recorded yet.",onDrill:s=>de({user_id:s,model:d.trim()||void 0,api_key_id:g||void 0}),loading:k.isLoading})]}),e.jsx(ht,{filters:y,anyFilter:Z}),e.jsxs("div",{className:"flex flex-col gap-3 rounded-xl border border-[var(--otari-line)] bg-[var(--otari-surface)] p-4",children:[e.jsxs("div",{className:"flex items-center justify-between gap-3",children:[e.jsx("h2",{className:"text-sm font-semibold text-[var(--otari-ink)]",children:"Over time"}),e.jsxs("div",{className:"inline-flex gap-1.5",children:[nt.map(s=>e.jsx(I,{size:"sm",variant:P===s.key?"primary":"outline",onPress:()=>O(s.key),children:s.label},s.key)),k.isFetching?e.jsx(pe,{size:"sm"}):null]})]}),k.isLoading?e.jsx("div",{className:"flex h-48 items-center justify-center",children:e.jsx(pe,{size:"sm"})}):M.length===0?e.jsx("div",{className:"flex h-48 items-center justify-center text-sm text-[var(--otari-muted)]",children:"No data in this range."}):e.jsxs("figure",{className:"flex flex-col gap-2",children:[e.jsx(Xe,{data:ee.points,formatValue:s=>be(s,P),ariaLabel:`${P} per ${b}`}),e.jsxs("figcaption",{className:"text-xs text-[var(--otari-muted)]",children:[be(ee.peak,P)," peak · ",ee.count," ",b==="hour"?"hours":"days"," (times in UTC)"]})]})]})]})]})}export{wt as UsagePage}; diff --git a/src/gateway/static/dashboard/assets/UsersPage-d3EPlBj3.js b/src/gateway/static/dashboard/assets/UsersPage-CUF9BhT-.js similarity index 97% rename from src/gateway/static/dashboard/assets/UsersPage-d3EPlBj3.js rename to src/gateway/static/dashboard/assets/UsersPage-CUF9BhT-.js index acafadd2..7e094b9d 100644 --- a/src/gateway/static/dashboard/assets/UsersPage-d3EPlBj3.js +++ b/src/gateway/static/dashboard/assets/UsersPage-CUF9BhT-.js @@ -1 +1 @@ -import{j as e}from"./tanstack-query-1t81HyiD.js";import{r}from"./react-dgEcD0HR.js";import{u as Q,l as M,p as K,ae as X,P as Y,E as A,q as Z,af as ee,F as se}from"./index-D4f8RVEq.js";import{u as te,r as ae,B as ne}from"./tableSelection-9hV37uhu.js";import{C as re}from"./ConfirmDialog-a8LQxZuS.js";import{D as le}from"./DataTable-Bmn_eYSV.js";import{F as B}from"./Field-Dwp6u3t8.js";import{a as ie,M as R}from"./ModelScopeControl-CVWeyWke.js";import{f as I,B as d,d as S,A as f}from"./heroui-BI50yK5B.js";const de=new Intl.NumberFormat(void 0,{style:"currency",currency:"USD",maximumFractionDigits:4});function U(t){return de.format(t)}const oe=t=>t.user_id,D=t=>t.startsWith("apikey-");function H(t){return t.split("-")[0]}function E(t){return t.name??H(t.budget_id)}function $({value:t,onChange:l,budgets:n}){return e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx("label",{htmlFor:"user-budget",className:"text-sm font-medium text-[var(--otari-ink)]",children:"Budget"}),e.jsxs("select",{id:"user-budget",value:t??"",onChange:a=>l(a.target.value||null),className:"w-full rounded-lg border border-[var(--otari-line)] bg-[var(--otari-bg)] px-3 py-2 text-sm text-[var(--otari-ink)]",children:[e.jsx("option",{value:"",children:"No budget (unlimited)"}),n.map(a=>e.jsxs("option",{value:a.budget_id,children:[E(a),a.max_budget===null?" · no limit":` · ${U(a.max_budget)}`]},a.budget_id))]}),e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"The spending limit this user is held to. Manage budgets on the Budgets page."})]})}function ce({onClose:t}){const l=ee(),n=M(),[a,i]=r.useState(""),[o,u]=r.useState(""),[c,g]=r.useState(null),[p,m]=r.useState(null),[b,j]=r.useState(!0),x=()=>{if(l.isPending||!b||a.trim()==="")return;const h={user_id:a.trim(),alias:o.trim()||null,budget_id:c,allowed_models:p};l.mutate(h,{onSuccess:t})};return e.jsx(S,{children:e.jsxs(S.Content,{className:"flex flex-col gap-4 p-5",children:[e.jsx("div",{className:"text-sm font-semibold text-[var(--otari-ink)]",children:"Create user"}),e.jsx(A,{error:l.error}),e.jsxs("div",{className:"grid gap-4 sm:grid-cols-2",children:[e.jsx(B,{label:"User ID",value:a,onChange:i,placeholder:"alice@example.com",isRequired:!0,autoFocus:!0,description:"The identifier callers send as the `user` field; spend and budgets track against it."}),e.jsx(B,{label:"Alias (optional)",value:o,onChange:u,placeholder:"Alice"})]}),e.jsx($,{value:c,onChange:g,budgets:n.data??[]}),e.jsx(R,{title:"Model access (default for this user's keys)",description:"The models this user's keys may list and call by default. A key can narrow this, but never exceed it.",initial:null,onChange:(h,C)=>{m(h),j(C)}}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(d,{variant:"primary",isDisabled:l.isPending||!b||a.trim()==="",onPress:x,children:l.isPending?"Creating…":"Create user"}),e.jsx(d,{variant:"ghost",onPress:t,children:"Cancel"})]})]})})}function ue({user:t,onClose:l}){const n=K(),a=M(),[i,o]=r.useState(t.alias??""),[u,c]=r.useState(t.budget_id),[g,p]=r.useState(t.allowed_models),[m,b]=r.useState(!0),j=()=>{if(n.isPending||!m)return;const x={alias:i.trim()||null,budget_id:u,allowed_models:g};n.mutate({id:t.user_id,body:x},{onSuccess:l})};return e.jsx(S,{children:e.jsxs(S.Content,{className:"flex flex-col gap-4 p-5",children:[e.jsxs("div",{className:"text-sm font-semibold text-[var(--otari-ink)]",children:["Edit ",e.jsx("code",{children:t.user_id})]}),e.jsx(A,{error:n.error}),e.jsx(B,{label:"Alias",value:i,onChange:o,placeholder:"Alice"}),e.jsx($,{value:u,onChange:c,budgets:a.data??[]}),e.jsx(R,{title:"Model access (default for this user's keys)",description:"The models this user's keys may list and call by default. A key can narrow this, but never exceed it.",initial:t.allowed_models,onChange:(x,h)=>{p(x),b(h)}}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(d,{variant:"primary",isDisabled:n.isPending||!m,onPress:j,children:n.isPending?"Saving…":"Save changes"}),e.jsx(d,{variant:"ghost",onPress:l,children:"Cancel"})]})]})})}function ge({trigger:t,message:l,confirmLabel:n,isPending:a,onConfirm:i}){const[o,u]=r.useState(!1);return o?e.jsxs("div",{className:"flex flex-col items-end gap-1.5 rounded-lg border border-amber-200 bg-amber-50 p-2 text-right",children:[e.jsx("span",{className:"max-w-xs text-xs text-amber-800",children:l}),e.jsxs("span",{className:"inline-flex gap-1",children:[e.jsx(d,{size:"sm",variant:"danger",isDisabled:a,onPress:i,children:n}),e.jsx(d,{size:"sm",variant:"ghost",isDisabled:a,onPress:()=>u(!1),children:"Cancel"})]})]}):e.jsx(d,{size:"sm",variant:"danger-soft",onPress:()=>u(!0),children:t})}function me({user:t}){return t.blocked?e.jsx(I,{size:"sm",color:"warning",children:"Blocked"}):e.jsx(I,{size:"sm",color:"accent",children:"Active"})}function xe({allowed:t}){const{text:l,tone:n}=ie(t),a=n==="danger"?"text-red-700 font-medium":n==="muted"?"text-[var(--otari-muted)]":"text-[var(--otari-brand-dark)] font-medium",i=t&&t.length>0?t.join(", "):void 0;return e.jsx("span",{className:`text-xs ${a}`,title:i,children:l})}function he({isOpen:t,onOpenChange:l,budgets:n,count:a,isPending:i,error:o,onAssign:u}){const[c,g]=r.useState("");return r.useEffect(()=>{t&&g("")},[t]),e.jsx(f,{isOpen:t,onOpenChange:l,children:t?e.jsx(f.Backdrop,{children:e.jsx(f.Container,{placement:"center",size:"md",children:e.jsxs(f.Dialog,{children:[e.jsx(f.Header,{children:e.jsx(f.Heading,{children:"Assign budget"})}),e.jsxs(f.Body,{className:"flex flex-col gap-4",children:[e.jsxs("p",{className:"text-sm text-[var(--otari-muted)]",children:["Assign a budget to ",a," selected ",a===1?"user":"users","."]}),e.jsx(se,{label:"Budget",value:c,onChange:g,options:[{value:"",label:"Select a budget…"},...n.map(p=>({value:p.budget_id,label:E(p)}))]}),e.jsx(A,{error:o})]}),e.jsxs(f.Footer,{children:[e.jsx(d,{variant:"ghost",isDisabled:i,onPress:()=>l(!1),children:"Cancel"}),e.jsx(d,{variant:"primary",isDisabled:!c,isPending:i,onPress:()=>u(c),children:"Assign"})]})]})})}):null})}function Ae(){const t=Q(),l=M(),n=K(),a=X(),[i,o]=r.useState(!1),[u,c]=r.useState(null),[g,p]=r.useState(!1),m=t.data??[],b=t.isLoading,j=m.filter(s=>D(s.user_id)).length,x=g?m:m.filter(s=>!D(s.user_id)),h=m.find(s=>s.user_id===u)??null,C=!b&&x.length===0&&!i,P=r.useMemo(()=>new Map((l.data??[]).map(s=>[s.budget_id,s])),[l.data]),y=te(),[q,_]=r.useState(!1),[W,N]=r.useState(!1),[F,z]=r.useState(void 0),[T,L]=r.useState(!1),G=x.map(s=>s.user_id),v=ae(y.selectedKeys,G),O=r.useCallback((s,k)=>n.mutate({id:s.user_id,body:{blocked:k}}),[n.mutate]),V=async(s,k)=>{L(!0),z(void 0);try{for(const w of v)await s(w);y.clear(),k()}catch(w){z(w)}finally{L(!1)}},J=r.useMemo(()=>[{id:"user",header:"User",isRowHeader:!0,cell:s=>e.jsxs("div",{className:"flex flex-col gap-0.5",children:[e.jsxs("span",{className:"inline-flex items-center gap-1.5",children:[e.jsx("code",{className:"text-xs font-medium text-[var(--otari-ink)]",children:s.user_id}),D(s.user_id)?e.jsx(I,{size:"sm",color:"default",children:"virtual"}):null]}),s.alias?e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:s.alias}):null]})},{id:"status",header:"Status",cell:s=>e.jsx(me,{user:s})},{id:"budget",header:"Budget",cell:s=>s.budget_id?e.jsx("span",{className:"text-[var(--otari-muted)]",title:s.budget_id,children:P.get(s.budget_id)?E(P.get(s.budget_id)):H(s.budget_id)}):e.jsx("span",{className:"text-[var(--otari-muted)]",children:"—"})},{id:"spend",header:"Spend",cell:s=>e.jsxs("span",{className:"text-[var(--otari-muted)]",children:[U(s.spend),s.reserved>0?e.jsxs("span",{children:[" (+",U(s.reserved)," held)"]}):null]})},{id:"access",header:"Model access",cell:s=>e.jsx(xe,{allowed:s.allowed_models})},{id:"actions",header:"Actions",align:"end",cell:s=>e.jsxs("div",{className:"flex items-center justify-end gap-1.5",children:[e.jsx(d,{size:"sm",variant:"outline",isDisabled:n.isPending,onPress:()=>O(s,!s.blocked),children:s.blocked?"Unblock":"Block"}),e.jsx(d,{size:"sm",variant:"ghost",onPress:()=>{o(!1),c(s.user_id)},children:"Edit"}),e.jsx(ge,{trigger:"Delete",confirmLabel:"Delete user",isPending:a.isPending,message:e.jsxs(e.Fragment,{children:["Delete ",e.jsx("strong",{children:s.user_id}),"? This deactivates its API keys and hides the user; usage history is preserved."]}),onConfirm:()=>a.mutate(s.user_id)})]})}],[P,n.isPending,a.isPending,a.mutate,O]);return e.jsxs("div",{className:"flex flex-col gap-6",children:[e.jsx(Y,{title:"Users",description:"People and teams that own API keys. Set each one's budget and default model access here; issue their keys on the API keys page.",action:i?null:e.jsx(d,{variant:"primary",onPress:()=>{c(null),o(!0)},children:"Create user"})}),e.jsx(A,{error:t.error??n.error??a.error}),C?e.jsx(Z,{title:"No users yet",description:"A user owns API keys and carries the budget and default model access those keys inherit. Create a user here, then issue its keys on the API keys page.",actionLabel:"Create your first user",onAction:()=>{c(null),o(!0)}}):null,j>0?e.jsxs("label",{className:"flex w-fit items-center gap-2 text-xs text-[var(--otari-muted)]",children:[e.jsx("input",{type:"checkbox",checked:g,onChange:s=>p(s.target.checked)}),"Show auto-created (virtual) users (",j,")"]}):null,i?e.jsx(ce,{onClose:()=>o(!1)}):null,h?e.jsx(ue,{user:h,onClose:()=>c(null)},h.user_id):null,v.length>0?e.jsxs(ne,{selectedCount:v.length,allMatching:!1,matchingTotal:null,canSelectAllMatching:!1,onSelectAllMatching:()=>{},onClear:y.clear,children:[e.jsx(d,{size:"sm",variant:"primary",onPress:()=>N(!0),children:"Assign budget"}),e.jsx(d,{size:"sm",variant:"danger",onPress:()=>_(!0),children:"Delete"})]}):null,C?null:e.jsx(le,{ariaLabel:"Users",columns:J,rows:x,getRowKey:oe,isLoading:b,emptyContent:"No users yet. Create one, or create an API key to auto-create one.",selectionMode:"multiple",selectedKeys:y.selectedKeys,onSelectionChange:y.onSelectionChange}),e.jsx(re,{isOpen:q,onOpenChange:_,heading:"Delete users",body:`Delete ${v.length} ${v.length===1?"user":"users"}? This deactivates their API keys and hides them; usage history is preserved.`,confirmLabel:"Delete",isPending:T,error:F,onConfirm:()=>V(s=>a.mutateAsync(s),()=>_(!1))}),e.jsx(he,{isOpen:W,onOpenChange:N,budgets:l.data??[],count:v.length,isPending:T,error:F,onAssign:s=>V(k=>n.mutateAsync({id:k,body:{budget_id:s}}),()=>N(!1))})]})}export{Ae as UsersPage}; +import{j as e}from"./tanstack-query-1t81HyiD.js";import{r}from"./react-dgEcD0HR.js";import{u as Q,q as M,v as K,ar as X,P as Y,E as A,w as Z,as as ee,F as se}from"./index-Bi2hajrg.js";import{u as te,r as ae,B as ne}from"./tableSelection-9hV37uhu.js";import{C as re}from"./ConfirmDialog-ChuHp-Qm.js";import{D as le}from"./DataTable-Bmn_eYSV.js";import{F as B}from"./Field-Dwp6u3t8.js";import{a as ie,M as R}from"./ModelScopeControl-DNcVzk1f.js";import{f as I,B as d,d as S,A as f}from"./heroui-BI50yK5B.js";const de=new Intl.NumberFormat(void 0,{style:"currency",currency:"USD",maximumFractionDigits:4});function U(t){return de.format(t)}const oe=t=>t.user_id,D=t=>t.startsWith("apikey-");function H(t){return t.split("-")[0]}function E(t){return t.name??H(t.budget_id)}function $({value:t,onChange:l,budgets:n}){return e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx("label",{htmlFor:"user-budget",className:"text-sm font-medium text-[var(--otari-ink)]",children:"Budget"}),e.jsxs("select",{id:"user-budget",value:t??"",onChange:a=>l(a.target.value||null),className:"w-full rounded-lg border border-[var(--otari-line)] bg-[var(--otari-bg)] px-3 py-2 text-sm text-[var(--otari-ink)]",children:[e.jsx("option",{value:"",children:"No budget (unlimited)"}),n.map(a=>e.jsxs("option",{value:a.budget_id,children:[E(a),a.max_budget===null?" · no limit":` · ${U(a.max_budget)}`]},a.budget_id))]}),e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:"The spending limit this user is held to. Manage budgets on the Budgets page."})]})}function ce({onClose:t}){const l=ee(),n=M(),[a,i]=r.useState(""),[o,u]=r.useState(""),[c,g]=r.useState(null),[p,m]=r.useState(null),[b,j]=r.useState(!0),x=()=>{if(l.isPending||!b||a.trim()==="")return;const h={user_id:a.trim(),alias:o.trim()||null,budget_id:c,allowed_models:p};l.mutate(h,{onSuccess:t})};return e.jsx(S,{children:e.jsxs(S.Content,{className:"flex flex-col gap-4 p-5",children:[e.jsx("div",{className:"text-sm font-semibold text-[var(--otari-ink)]",children:"Create user"}),e.jsx(A,{error:l.error}),e.jsxs("div",{className:"grid gap-4 sm:grid-cols-2",children:[e.jsx(B,{label:"User ID",value:a,onChange:i,placeholder:"alice@example.com",isRequired:!0,autoFocus:!0,description:"The identifier callers send as the `user` field; spend and budgets track against it."}),e.jsx(B,{label:"Alias (optional)",value:o,onChange:u,placeholder:"Alice"})]}),e.jsx($,{value:c,onChange:g,budgets:n.data??[]}),e.jsx(R,{title:"Model access (default for this user's keys)",description:"The models this user's keys may list and call by default. A key can narrow this, but never exceed it.",initial:null,onChange:(h,C)=>{m(h),j(C)}}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(d,{variant:"primary",isDisabled:l.isPending||!b||a.trim()==="",onPress:x,children:l.isPending?"Creating…":"Create user"}),e.jsx(d,{variant:"ghost",onPress:t,children:"Cancel"})]})]})})}function ue({user:t,onClose:l}){const n=K(),a=M(),[i,o]=r.useState(t.alias??""),[u,c]=r.useState(t.budget_id),[g,p]=r.useState(t.allowed_models),[m,b]=r.useState(!0),j=()=>{if(n.isPending||!m)return;const x={alias:i.trim()||null,budget_id:u,allowed_models:g};n.mutate({id:t.user_id,body:x},{onSuccess:l})};return e.jsx(S,{children:e.jsxs(S.Content,{className:"flex flex-col gap-4 p-5",children:[e.jsxs("div",{className:"text-sm font-semibold text-[var(--otari-ink)]",children:["Edit ",e.jsx("code",{children:t.user_id})]}),e.jsx(A,{error:n.error}),e.jsx(B,{label:"Alias",value:i,onChange:o,placeholder:"Alice"}),e.jsx($,{value:u,onChange:c,budgets:a.data??[]}),e.jsx(R,{title:"Model access (default for this user's keys)",description:"The models this user's keys may list and call by default. A key can narrow this, but never exceed it.",initial:t.allowed_models,onChange:(x,h)=>{p(x),b(h)}}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(d,{variant:"primary",isDisabled:n.isPending||!m,onPress:j,children:n.isPending?"Saving…":"Save changes"}),e.jsx(d,{variant:"ghost",onPress:l,children:"Cancel"})]})]})})}function ge({trigger:t,message:l,confirmLabel:n,isPending:a,onConfirm:i}){const[o,u]=r.useState(!1);return o?e.jsxs("div",{className:"flex flex-col items-end gap-1.5 rounded-lg border border-amber-200 bg-amber-50 p-2 text-right",children:[e.jsx("span",{className:"max-w-xs text-xs text-amber-800",children:l}),e.jsxs("span",{className:"inline-flex gap-1",children:[e.jsx(d,{size:"sm",variant:"danger",isDisabled:a,onPress:i,children:n}),e.jsx(d,{size:"sm",variant:"ghost",isDisabled:a,onPress:()=>u(!1),children:"Cancel"})]})]}):e.jsx(d,{size:"sm",variant:"danger-soft",onPress:()=>u(!0),children:t})}function me({user:t}){return t.blocked?e.jsx(I,{size:"sm",color:"warning",children:"Blocked"}):e.jsx(I,{size:"sm",color:"accent",children:"Active"})}function xe({allowed:t}){const{text:l,tone:n}=ie(t),a=n==="danger"?"text-red-700 font-medium":n==="muted"?"text-[var(--otari-muted)]":"text-[var(--otari-brand-dark)] font-medium",i=t&&t.length>0?t.join(", "):void 0;return e.jsx("span",{className:`text-xs ${a}`,title:i,children:l})}function he({isOpen:t,onOpenChange:l,budgets:n,count:a,isPending:i,error:o,onAssign:u}){const[c,g]=r.useState("");return r.useEffect(()=>{t&&g("")},[t]),e.jsx(f,{isOpen:t,onOpenChange:l,children:t?e.jsx(f.Backdrop,{children:e.jsx(f.Container,{placement:"center",size:"md",children:e.jsxs(f.Dialog,{children:[e.jsx(f.Header,{children:e.jsx(f.Heading,{children:"Assign budget"})}),e.jsxs(f.Body,{className:"flex flex-col gap-4",children:[e.jsxs("p",{className:"text-sm text-[var(--otari-muted)]",children:["Assign a budget to ",a," selected ",a===1?"user":"users","."]}),e.jsx(se,{label:"Budget",value:c,onChange:g,options:[{value:"",label:"Select a budget…"},...n.map(p=>({value:p.budget_id,label:E(p)}))]}),e.jsx(A,{error:o})]}),e.jsxs(f.Footer,{children:[e.jsx(d,{variant:"ghost",isDisabled:i,onPress:()=>l(!1),children:"Cancel"}),e.jsx(d,{variant:"primary",isDisabled:!c,isPending:i,onPress:()=>u(c),children:"Assign"})]})]})})}):null})}function Ae(){const t=Q(),l=M(),n=K(),a=X(),[i,o]=r.useState(!1),[u,c]=r.useState(null),[g,p]=r.useState(!1),m=t.data??[],b=t.isLoading,j=m.filter(s=>D(s.user_id)).length,x=g?m:m.filter(s=>!D(s.user_id)),h=m.find(s=>s.user_id===u)??null,C=!b&&x.length===0&&!i,P=r.useMemo(()=>new Map((l.data??[]).map(s=>[s.budget_id,s])),[l.data]),y=te(),[q,_]=r.useState(!1),[W,N]=r.useState(!1),[F,z]=r.useState(void 0),[T,L]=r.useState(!1),G=x.map(s=>s.user_id),v=ae(y.selectedKeys,G),O=r.useCallback((s,k)=>n.mutate({id:s.user_id,body:{blocked:k}}),[n.mutate]),V=async(s,k)=>{L(!0),z(void 0);try{for(const w of v)await s(w);y.clear(),k()}catch(w){z(w)}finally{L(!1)}},J=r.useMemo(()=>[{id:"user",header:"User",isRowHeader:!0,cell:s=>e.jsxs("div",{className:"flex flex-col gap-0.5",children:[e.jsxs("span",{className:"inline-flex items-center gap-1.5",children:[e.jsx("code",{className:"text-xs font-medium text-[var(--otari-ink)]",children:s.user_id}),D(s.user_id)?e.jsx(I,{size:"sm",color:"default",children:"virtual"}):null]}),s.alias?e.jsx("span",{className:"text-xs text-[var(--otari-muted)]",children:s.alias}):null]})},{id:"status",header:"Status",cell:s=>e.jsx(me,{user:s})},{id:"budget",header:"Budget",cell:s=>s.budget_id?e.jsx("span",{className:"text-[var(--otari-muted)]",title:s.budget_id,children:P.get(s.budget_id)?E(P.get(s.budget_id)):H(s.budget_id)}):e.jsx("span",{className:"text-[var(--otari-muted)]",children:"—"})},{id:"spend",header:"Spend",cell:s=>e.jsxs("span",{className:"text-[var(--otari-muted)]",children:[U(s.spend),s.reserved>0?e.jsxs("span",{children:[" (+",U(s.reserved)," held)"]}):null]})},{id:"access",header:"Model access",cell:s=>e.jsx(xe,{allowed:s.allowed_models})},{id:"actions",header:"Actions",align:"end",cell:s=>e.jsxs("div",{className:"flex items-center justify-end gap-1.5",children:[e.jsx(d,{size:"sm",variant:"outline",isDisabled:n.isPending,onPress:()=>O(s,!s.blocked),children:s.blocked?"Unblock":"Block"}),e.jsx(d,{size:"sm",variant:"ghost",onPress:()=>{o(!1),c(s.user_id)},children:"Edit"}),e.jsx(ge,{trigger:"Delete",confirmLabel:"Delete user",isPending:a.isPending,message:e.jsxs(e.Fragment,{children:["Delete ",e.jsx("strong",{children:s.user_id}),"? This deactivates its API keys and hides the user; usage history is preserved."]}),onConfirm:()=>a.mutate(s.user_id)})]})}],[P,n.isPending,a.isPending,a.mutate,O]);return e.jsxs("div",{className:"flex flex-col gap-6",children:[e.jsx(Y,{title:"Users",description:"People and teams that own API keys. Set each one's budget and default model access here; issue their keys on the API keys page.",action:i?null:e.jsx(d,{variant:"primary",onPress:()=>{c(null),o(!0)},children:"Create user"})}),e.jsx(A,{error:t.error??n.error??a.error}),C?e.jsx(Z,{title:"No users yet",description:"A user owns API keys and carries the budget and default model access those keys inherit. Create a user here, then issue its keys on the API keys page.",actionLabel:"Create your first user",onAction:()=>{c(null),o(!0)}}):null,j>0?e.jsxs("label",{className:"flex w-fit items-center gap-2 text-xs text-[var(--otari-muted)]",children:[e.jsx("input",{type:"checkbox",checked:g,onChange:s=>p(s.target.checked)}),"Show auto-created (virtual) users (",j,")"]}):null,i?e.jsx(ce,{onClose:()=>o(!1)}):null,h?e.jsx(ue,{user:h,onClose:()=>c(null)},h.user_id):null,v.length>0?e.jsxs(ne,{selectedCount:v.length,allMatching:!1,matchingTotal:null,canSelectAllMatching:!1,onSelectAllMatching:()=>{},onClear:y.clear,children:[e.jsx(d,{size:"sm",variant:"primary",onPress:()=>N(!0),children:"Assign budget"}),e.jsx(d,{size:"sm",variant:"danger",onPress:()=>_(!0),children:"Delete"})]}):null,C?null:e.jsx(le,{ariaLabel:"Users",columns:J,rows:x,getRowKey:oe,isLoading:b,emptyContent:"No users yet. Create one, or create an API key to auto-create one.",selectionMode:"multiple",selectedKeys:y.selectedKeys,onSelectionChange:y.onSelectionChange}),e.jsx(re,{isOpen:q,onOpenChange:_,heading:"Delete users",body:`Delete ${v.length} ${v.length===1?"user":"users"}? This deactivates their API keys and hides them; usage history is preserved.`,confirmLabel:"Delete",isPending:T,error:F,onConfirm:()=>V(s=>a.mutateAsync(s),()=>_(!1))}),e.jsx(he,{isOpen:W,onOpenChange:N,budgets:l.data??[],count:v.length,isPending:T,error:F,onAssign:s=>V(k=>n.mutateAsync({id:k,body:{budget_id:s}}),()=>N(!1))})]})}export{Ae as UsersPage}; diff --git a/src/gateway/static/dashboard/assets/index-Bi2hajrg.js b/src/gateway/static/dashboard/assets/index-Bi2hajrg.js new file mode 100644 index 00000000..e491f16f --- /dev/null +++ b/src/gateway/static/dashboard/assets/index-Bi2hajrg.js @@ -0,0 +1,2 @@ +const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/ActivityPage-C5gSmqNJ.js","assets/tanstack-query-1t81HyiD.js","assets/react-dgEcD0HR.js","assets/FilterChips-Dqy1SR3R.js","assets/heroui-BI50yK5B.js","assets/recharts-C4kRDmvS.js","assets/tableSelection-9hV37uhu.js","assets/ConfirmDialog-ChuHp-Qm.js","assets/DataTable-Bmn_eYSV.js","assets/TablePagination-8CBn4us4.js","assets/AliasesPage-D7ZKXX3I.js","assets/Field-Dwp6u3t8.js","assets/UserComboBox-a9wxf8eF.js","assets/BudgetsPage-DanpEezo.js","assets/DocsPage-DkHyFdGF.js","assets/KeysPage-D4g9XrFY.js","assets/ModelScopeControl-DNcVzk1f.js","assets/ModelsPage-r0TNjwml.js","assets/OverviewPage-WmIAewmo.js","assets/charts-DIsd9m--.js","assets/ProvidersPage-BRQCYCYu.js","assets/SettingsPage-DjaTcy-f.js","assets/ToolsGuardrailsPage-B4MIR_ke.js","assets/UsagePage-CGU7s9AT.js","assets/UsersPage-CUF9BhT-.js"])))=>i.map(i=>d[i]); +var Ie=Object.defineProperty;var qe=(e,t,r)=>t in e?Ie(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r;var ce=(e,t,r)=>qe(e,typeof t!="symbol"?t+"":t,r);import{u as g,j as n,a as p,b as x,k as ne,Q as Re,c as Oe}from"./tanstack-query-1t81HyiD.js";import{d as Me,r as o,N as Z,L as Fe,O as Ue,H as Ke,e as Be,f as j,h as $e}from"./react-dgEcD0HR.js";import{B as C,C as U,L as xe,I as ye,a as ze,b as Qe,d as I,S as Ve,c as T,T as We,e as He}from"./heroui-BI50yK5B.js";(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const a of document.querySelectorAll('link[rel="modulepreload"]'))s(a);new MutationObserver(a=>{for(const i of a)if(i.type==="childList")for(const u of i.addedNodes)u.tagName==="LINK"&&u.rel==="modulepreload"&&s(u)}).observe(document,{childList:!0,subtree:!0});function r(a){const i={};return a.integrity&&(i.integrity=a.integrity),a.referrerPolicy&&(i.referrerPolicy=a.referrerPolicy),a.crossOrigin==="use-credentials"?i.credentials="include":a.crossOrigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function s(a){if(a.ep)return;a.ep=!0;const i=r(a);fetch(a.href,i)}})();var Ge=Me();const Je="modulepreload",Ye=function(e){return"/"+e},ue={},P=function(t,r,s){let a=Promise.resolve();if(r&&r.length>0){let u=function(y){return Promise.all(y.map(h=>Promise.resolve(h).then(b=>({status:"fulfilled",value:b}),b=>({status:"rejected",reason:b}))))};document.getElementsByTagName("link");const d=document.querySelector("meta[property=csp-nonce]"),f=(d==null?void 0:d.nonce)||(d==null?void 0:d.getAttribute("nonce"));a=u(r.map(y=>{if(y=Ye(y),y in ue)return;ue[y]=!0;const h=y.endsWith(".css"),b=h?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${y}"]${b}`))return;const m=document.createElement("link");if(m.rel=h?"stylesheet":Je,h||(m.as="script"),m.crossOrigin="",m.href=y,f&&m.setAttribute("nonce",f),document.head.appendChild(m),h)return new Promise((N,M)=>{m.addEventListener("load",N),m.addEventListener("error",()=>M(new Error(`Unable to preload CSS for ${y}`)))})}))}function i(u){const d=new Event("vite:preloadError",{cancelable:!0});if(d.payload=u,window.dispatchEvent(d),!d.defaultPrevented)throw u}return a.then(u=>{for(const d of u||[])d.status==="rejected"&&i(d.reason);return t().catch(i)})};class L extends Error{constructor(r,s){super(s);ce(this,"status");this.name="ApiError",this.status=r}}let K=null;function de(e){K=e}async function ee(e){try{const t=await e.json();if(typeof t.detail=="string")return t.detail;if(t.detail!=null)return JSON.stringify(t.detail)}catch{}return e.statusText||`Request failed (${e.status})`}async function Xe(e){let t;try{t=await fetch("/v1/auth/session",{method:"POST",headers:{Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify({master_key:e})})}catch{throw new L(0,"Network error: could not reach the gateway.")}if(t.status===401||t.status===403)return!1;if(!t.ok)throw new L(t.status,await ee(t));return!0}async function Ze(){try{await fetch("/v1/auth/session",{method:"DELETE"})}catch{}}async function c(e,t={}){const r=new Headers(t.headers);r.set("Accept","application/json"),t.body!=null&&!r.has("Content-Type")&&r.set("Content-Type","application/json");let s;try{s=await fetch(e,{...t,headers:r})}catch{throw new L(0,"Network error: could not reach the gateway.")}if(s.status===401||s.status===403)throw K==null||K(),new L(s.status,await ee(s));if(!s.ok)throw new L(s.status,await ee(s));if(s.status!==204)return await s.json()}const te="otari.dashboard.hasSession",ve=o.createContext(null);function et(){try{return window.localStorage.getItem(te)==="1"}catch{return!1}}function tt({children:e}){const t=g(),[r,s]=o.useState(et),a=o.useCallback(()=>{Ze(),s(!1),t.clear();try{window.localStorage.removeItem(te)}catch{}},[t]),i=o.useCallback(()=>{t.clear(),s(!0);try{window.localStorage.setItem(te,"1")}catch{}},[t]);o.useEffect(()=>(de(a),()=>de(null)),[a]);const u=o.useMemo(()=>({isAuthenticated:r,login:i,logout:a}),[r,i,a]);return n.jsx(ve.Provider,{value:u,children:e})}function re(){const e=o.useContext(ve);if(!e)throw new Error("useAuth must be used within an AuthProvider");return e}function nt(e){return e instanceof L&&e.status===0}function rt(){const e=g(),[t,r]=o.useState(!1);return o.useEffect(()=>{const s=e.getQueryCache(),a=()=>s.getAll().some(i=>i.state.status==="error"&&nt(i.state.error));return r(a()),s.subscribe(()=>r(a()))},[e]),t}function st(){return rt()?n.jsxs("div",{role:"alert","aria-live":"assertive",className:"fixed right-4 bottom-4 z-50 flex max-w-sm items-start gap-2.5 rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700 shadow-lg",children:[n.jsxs("svg",{viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2","aria-hidden":!0,className:"mt-0.5 h-5 w-5 shrink-0",children:[n.jsx("path",{d:"M12 9v4M12 17h.01",strokeLinecap:"round",strokeLinejoin:"round"}),n.jsx("path",{d:"M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z",strokeLinejoin:"round"})]}),n.jsxs("span",{children:[n.jsx("strong",{className:"font-semibold",children:"Can’t reach the gateway."})," The backend isn’t responding; data won’t load or save until the connection is restored."]})]}):null}const $=3600,_=86400,at=365*_,dn=[{key:"1h",label:"Last hour",seconds:$,bucket:"hour"},{key:"24h",label:"24h",seconds:_,bucket:"hour"},{key:"7d",label:"7d",seconds:7*_,bucket:"day"},{key:"30d",label:"30d",seconds:30*_,bucket:"day"},{key:"90d",label:"90d",seconds:90*_,bucket:"day"},{key:"12mo",label:"12mo",seconds:at,bucket:"day"}],mn="30d",fn=[{key:"1h",label:"1h",seconds:$,bucket:"hour"},{key:"24h",label:"24h",seconds:_,bucket:"hour"},{key:"7d",label:"7d",seconds:7*_,bucket:"day"},{key:"30d",label:"30d",seconds:30*_,bucket:"day"},{key:"all",label:"All",seconds:null,bucket:"day"}],hn="24h",xn="custom";function yn(e,t){return e.find(r=>r.key===t)}function it(e,t=Date.now()){return new Date(t-e*1e3).toISOString()}function ot(e){return(e==="hour"?$:_)*1e3}function vn(e,t,r=Date.now()){const s=new Date(e).getTime();return(t?new Date(t).getTime():r)-s<=_*1e3?"hour":"day"}function gn(e,t,r,s){if(e.length===0)return null;const a=Math.max(0,Math.min(t,r)),i=Math.min(e.length-1,Math.max(t,r)),u=new Date(e[a]).getTime(),d=new Date(e[i]).getTime()+ot(s);return{startIso:new Date(u).toISOString(),endIso:new Date(d).toISOString()}}function pn(e,t,r){const s=e.length;if(s===0)return{startIndex:0,endIndex:0};const a=e.map(d=>new Date(d).getTime());let i=0;if(t){const d=new Date(t).getTime();for(let f=0;fc("/v1/models"),staleTime:6e4})}function dt(){return p({queryKey:[ct],queryFn:()=>c("/dashboard-build.json"),refetchInterval:ut,refetchOnWindowFocus:!0,staleTime:0,retry:!1})}function jn(){return p({queryKey:[ae],queryFn:()=>c("/v1/models/discoverable"),staleTime:5*6e4})}function Sn(){return p({queryKey:[ie],queryFn:()=>c("/v1/providers"),staleTime:5*6e4})}function kn(){return p({queryKey:["provider-catalog"],queryFn:()=>c("/v1/providers/catalog"),staleTime:1/0})}function En(e){return p({queryKey:["provider-catalog",e],queryFn:()=>c(`/v1/providers/catalog/${encodeURIComponent(e)}`),enabled:e!=="",staleTime:1/0})}function Pn(){return p({queryKey:[oe],queryFn:()=>c("/v1/providers/health"),staleTime:me,refetchInterval:me})}function Nn(){const e=g();return x({mutationFn:()=>c("/v1/providers/health?refresh=true"),onSuccess:t=>e.setQueryData([oe],t)})}function Cn(){return p({queryKey:[be],queryFn:()=>c("/v1/provider-credentials"),staleTime:6e4})}function Q(e){e.invalidateQueries({queryKey:[be]}),e.invalidateQueries({queryKey:[ie]}),e.invalidateQueries({queryKey:[D]}),e.invalidateQueries({queryKey:[ae]}),e.invalidateQueries({queryKey:[oe]})}function Tn(){const e=g();return x({mutationFn:t=>c("/v1/provider-credentials",{method:"POST",body:JSON.stringify(t)}),onSuccess:()=>Q(e)})}function _n(){const e=g();return x({mutationFn:({instance:t,body:r})=>c(`/v1/provider-credentials/${encodeURIComponent(t)}`,{method:"PATCH",body:JSON.stringify(r)}),onSuccess:()=>Q(e)})}function Ln(){const e=g();return x({mutationFn:t=>c(`/v1/provider-credentials/${encodeURIComponent(t)}`,{method:"DELETE"}),onSuccess:()=>Q(e)})}function Dn(){const e=g();return x({mutationFn:()=>c("/v1/provider-credentials/reencrypt",{method:"POST"}),onSuccess:()=>Q(e)})}function An(){return x({mutationFn:e=>c(`/v1/provider-credentials/${encodeURIComponent(e)}/test`,{method:"POST"})})}function In(){return x({mutationFn:e=>c("/v1/provider-credentials/test",{method:"POST",body:JSON.stringify(e)})})}function qn(){return p({queryKey:[lt],queryFn:()=>c("/v1/models/metadata"),staleTime:10*6e4})}function Rn(){return p({queryKey:[se],queryFn:()=>c("/v1/aliases"),staleTime:6e4})}function On(){const e=g();return x({mutationFn:t=>c("/v1/aliases",{method:"POST",body:JSON.stringify(t)}),onSuccess:()=>{e.invalidateQueries({queryKey:[se]}),e.invalidateQueries({queryKey:[D]})}})}function Mn(){const e=g();return x({mutationFn:({name:t,userId:r})=>{const s=r==null?"":`?user_id=${encodeURIComponent(r)}`;return c(`/v1/aliases/${encodeURIComponent(t)}${s}`,{method:"DELETE"})},onSuccess:()=>{e.invalidateQueries({queryKey:[se]}),e.invalidateQueries({queryKey:[D]})}})}function mt(){return p({queryKey:[ge],queryFn:()=>c("/v1/settings"),staleTime:6e4})}function ft(){const e=g();return x({mutationFn:t=>c("/v1/settings",{method:"PATCH",body:JSON.stringify(t)}),onSuccess:t=>{e.setQueryData([ge],t),e.invalidateQueries({queryKey:[D]}),e.invalidateQueries({queryKey:[ae]})}})}function Fn(){return x({mutationFn:()=>c("/v1/settings/master-key/rotate",{method:"POST"})})}function Un(){return p({queryKey:[pe],queryFn:()=>c("/v1/tool-settings"),staleTime:6e4})}function Kn(){const e=g();return x({mutationFn:t=>c("/v1/tool-settings",{method:"PATCH",body:JSON.stringify(t)}),onSuccess:t=>{e.setQueryData([pe],t)}})}function Bn(){return x({mutationFn:({service:e,url:t})=>c(`/v1/tool-settings/${encodeURIComponent(e)}/test`,{method:"POST",body:JSON.stringify({url:t})})})}const H=1e3,ht=100;async function xt(){const e=[];for(let t=0;tc("/v1/pricing",{method:"POST",body:JSON.stringify(t)}),onSuccess:()=>{e.invalidateQueries({queryKey:[z]}),e.invalidateQueries({queryKey:[D]})}})}function Qn(){const e=g();return x({mutationFn:t=>c(`/v1/pricing/${encodeURIComponent(t)}`,{method:"DELETE"}),onSuccess:()=>{e.invalidateQueries({queryKey:[z]}),e.invalidateQueries({queryKey:[D]})}})}function Vn(){return x({mutationFn:()=>c("/v1/pricing/refresh",{method:"POST"})})}function Wn(){const e=g();return x({mutationFn:()=>c("/v1/pricing/refresh/confirm",{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:[z]}),e.invalidateQueries({queryKey:[D]}),e.invalidateQueries({queryKey:[ie]})}})}function Hn(){return x({mutationFn:()=>c("/v1/pricing/refresh/reject",{method:"POST"})})}const G=1e3,yt=100;async function vt(){const e=[];for(let t=0;tc("/v1/keys",{method:"POST",body:JSON.stringify(t)}),onSuccess:()=>void e.invalidateQueries({queryKey:[q]})})}function Yn(){const e=g();return x({mutationFn:({id:t,body:r})=>c(`/v1/keys/${encodeURIComponent(t)}`,{method:"PATCH",body:JSON.stringify(r)}),onSuccess:()=>void e.invalidateQueries({queryKey:[q]})})}function Xn(){const e=g();return x({mutationFn:t=>c(`/v1/keys/${encodeURIComponent(t)}/rotate`,{method:"POST"}),onSuccess:()=>void e.invalidateQueries({queryKey:[q]})})}function Zn(){const e=g();return x({mutationFn:t=>c(`/v1/keys/${encodeURIComponent(t)}`,{method:"DELETE"}),onSuccess:()=>void e.invalidateQueries({queryKey:[q]})})}const J=1e3,gt=100;async function pt(){const e=[];for(let t=0;tc(`/v1/budgets/${encodeURIComponent(e)}/reset-logs`),enabled:e!==null,staleTime:6e4})}function nr(){const e=g();return x({mutationFn:t=>c("/v1/budgets",{method:"POST",body:JSON.stringify(t)}),onSuccess:()=>void e.invalidateQueries({queryKey:[R]})})}function rr(){const e=g();return x({mutationFn:({id:t,body:r})=>c(`/v1/budgets/${encodeURIComponent(t)}`,{method:"PATCH",body:JSON.stringify(r)}),onSuccess:()=>void e.invalidateQueries({queryKey:[R]})})}function sr(){const e=g();return x({mutationFn:t=>c(`/v1/budgets/${encodeURIComponent(t)}`,{method:"DELETE"}),onSuccess:()=>void e.invalidateQueries({queryKey:[R]})})}const Y=1e3,bt=100;async function wt(){const e=[];for(let t=0;tc("/v1/users",{method:"POST",body:JSON.stringify(t)}),onSuccess:()=>le(e)})}function or(){const e=g();return x({mutationFn:({id:t,body:r})=>c(`/v1/users/${encodeURIComponent(t)}`,{method:"PATCH",body:JSON.stringify(r)}),onSuccess:()=>le(e)})}function lr(){const e=g();return x({mutationFn:t=>c(`/v1/users/${encodeURIComponent(t)}`,{method:"DELETE"}),onSuccess:()=>{le(e),e.invalidateQueries({queryKey:[q]})}})}function V(e){const t=new URLSearchParams;return e.start_date&&t.set("start_date",e.start_date),e.end_date&&t.set("end_date",e.end_date),e.status&&t.set("status",e.status),e.model&&t.set("model",e.model),e.endpoint&&t.set("endpoint",e.endpoint),e.user_id&&t.set("user_id",e.user_id),e.api_key_id&&t.set("api_key_id",e.api_key_id),e.source&&t.set("source",e.source),e.priced!==void 0&&t.set("priced",String(e.priced)),e.counts_toward_budget!==void 0&&t.set("counts_toward_budget",String(e.counts_toward_budget)),t}function cr(e,t,r){return p({queryKey:[O,"list",e,t,r],queryFn:()=>{const s=V(e);return s.set("skip",String(t*r)),s.set("limit",String(r)),c(`/v1/usage?${s.toString()}`)},placeholderData:ne,staleTime:1e4})}function ur(e,t=!0){return p({queryKey:[O,"count",e],queryFn:()=>c(`/v1/usage/count?${V(e).toString()}`),enabled:t,placeholderData:ne,staleTime:1e4})}const jt=6e4;function St(e,t=!0){return p({queryKey:[O,"count","failures",e],queryFn:()=>{const r={status:"error",source:"gateway",start_date:it(e)};return c(`/v1/usage/count?${V(r).toString()}`)},enabled:t,refetchInterval:jt,refetchOnWindowFocus:!0,staleTime:0,retry:!1})}function dr(){const e=g();return x({mutationFn:t=>c("/v1/usage",{method:"DELETE",body:JSON.stringify(t)}),onSuccess:()=>{e.invalidateQueries({queryKey:[O]})}})}function mr(){const e=g();return x({mutationFn:t=>c("/v1/usage/set-price",{method:"POST",body:JSON.stringify(t)}),onSuccess:()=>{e.invalidateQueries({queryKey:[O]})}})}function fr(e,t,r=!0){return p({queryKey:[O,"summary",e,t],queryFn:()=>{const s=V(e);return s.set("bucket",t),c(`/v1/usage/summary?${s.toString()}`)},enabled:r,placeholderData:ne,staleTime:3e4})}function hr(e){return e==null?"0":new Intl.NumberFormat("en-US").format(e)}function xr(e){if(e==null)return"$0.00";const t=e!==0&&Math.abs(e)<.01?4:2;return new Intl.NumberFormat("en-US",{style:"currency",currency:"USD",minimumFractionDigits:2,maximumFractionDigits:t}).format(e)}function yr(e){if(e==null)return"—";if(e>=1e6){const t=e/1e6;return`${Number.isInteger(t)?t:t.toFixed(1)}M`}if(e>=1e3){const t=Math.round(e/1e3);return t>=1e3?"1M":`${t}K`}return String(e)}const kt=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];function vr(e){if(!e)return"—";const t=/^(\d{4})-(\d{2})/.exec(e);if(!t)return e;const r=Number(t[2])-1;return r<0||r>11?t[1]:`${kt[r]} ${t[1]}`}const Et=new Intl.NumberFormat("en-US",{style:"currency",currency:"USD",maximumFractionDigits:2});function gr(e){return Et.format(e)}function pr(e){return e>=1e6?`${(e/1e6).toFixed(1)}M`:e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e)}function Pt(e){return`${(e*100).toFixed(1)}%`}function br(e,t){return t===void 0||t===0?null:(e-t)/t}function Nt(e,t=Date.now()){if(!e)return"never";const r=new Date(e);if(Number.isNaN(r.getTime()))return e;const s=Math.round((t-r.getTime())/1e3),a=s<0,i=Math.abs(s),u=[["second",60],["minute",60],["hour",24],["day",30],["month",12],["year",Number.POSITIVE_INFINITY]];let d=i,f="second";for(const[h,b]of u){if(f=h,d0?"▲":e<0?"▼":"•";return n.jsxs("span",{className:"text-[var(--otari-muted)]",children:[t," ",Pt(Math.abs(e))," vs prev"]})}function Ct(e){return e instanceof L||e instanceof Error?e.message:"Something went wrong."}function Tt({error:e}){return e?n.jsx("div",{role:"alert",className:"rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700",children:Ct(e)}):null}function _t({tone:e="info",children:t}){const r=e==="warning"?"border-amber-200 bg-amber-50 text-amber-800":"border-[var(--otari-brand)] bg-[var(--otari-brand-tint)] text-[var(--otari-brand-dark)]";return n.jsx("div",{className:`rounded-lg border px-4 py-3 text-sm ${r}`,children:t})}function Sr({title:e,description:t,action:r}){return n.jsxs("div",{className:"flex flex-col gap-3",children:[n.jsxs("div",{children:[n.jsx("h1",{className:"text-xl font-semibold text-[var(--otari-ink)]",children:e}),t?n.jsx("p",{className:"mt-1 text-sm text-[var(--otari-muted)]",children:t}):null]}),r?n.jsx("div",{className:"flex flex-wrap gap-2",children:r}):null]})}function Lt(e){const[t,r]=o.useState(()=>Date.now());return o.useEffect(()=>{let s;const a=()=>{s===void 0&&(s=setInterval(()=>r(Date.now()),e))},i=()=>{s!==void 0&&(clearInterval(s),s=void 0)},u=()=>{r(Date.now()),document.visibilityState==="visible"?a():i()};return u(),document.addEventListener("visibilitychange",u),()=>{i(),document.removeEventListener("visibilitychange",u)}},[e]),t}function kr({onRefresh:e,isFetching:t=!1,updatedAt:r,label:s="Refresh"}){const a=Lt(15e3),i=r?Nt(new Date(r).toISOString(),a):null;return n.jsxs("span",{className:"inline-flex items-center gap-2",children:[i?n.jsxs("span",{className:"text-xs text-[var(--otari-muted)]",children:["Updated ",i]}):null,n.jsx(C,{variant:"outline",size:"sm",isIconOnly:!0,isDisabled:t,onPress:e,"aria-label":s,children:n.jsxs("svg",{viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",className:`h-4 w-4 ${t?"animate-spin":""}`,"aria-hidden":"true",children:[n.jsx("path",{d:"M20 11a8 8 0 1 0-.5 4",strokeLinecap:"round",strokeLinejoin:"round"}),n.jsx("path",{d:"M20 4v5h-5",strokeLinecap:"round",strokeLinejoin:"round"})]})})]})}function Er({title:e,description:t,actionLabel:r,onAction:s,isActionDisabled:a,children:i}){return n.jsx(I,{children:n.jsxs(I.Content,{className:"flex flex-col gap-4 p-6",children:[n.jsxs("div",{children:[n.jsx("h2",{className:"text-lg font-semibold text-[var(--otari-ink)]",children:e}),t?n.jsx("p",{className:"mt-1 text-sm text-[var(--otari-muted)]",children:t}):null]}),i,r&&s?n.jsx("div",{children:n.jsx(C,{variant:"primary",isDisabled:a,onPress:s,children:r})}):null]})})}function Pr({label:e="Loading…"}){return n.jsxs("div",{role:"status",className:"flex items-center justify-center gap-2 px-4 py-10 text-sm text-[var(--otari-muted)]",children:[n.jsx(Ve,{size:"sm"}),n.jsx("span",{children:e})]})}function Nr({children:e,confirmLabel:t,onConfirm:r,isPending:s}){const[a,i]=o.useState(!1);return a?n.jsxs("span",{className:"inline-flex items-center gap-1",children:[n.jsx(C,{size:"sm",variant:"danger",isDisabled:s,onPress:r,children:t}),n.jsx(C,{size:"sm",variant:"ghost",isDisabled:s,onPress:()=>i(!1),children:"Cancel"})]}):n.jsx(C,{size:"sm",variant:"danger-soft",onPress:()=>i(!0),children:e})}const Dt="rounded-lg border border-[var(--otari-line)] bg-[var(--otari-bg)] px-3 py-2 text-sm text-[var(--otari-ink)] focus:border-[var(--otari-brand)] focus:outline-none";function Cr({id:e,label:t,ariaLabel:r,value:s,onChange:a,options:i,children:u,disabled:d}){const f=o.useId(),y=e??(t?f:void 0),h=n.jsx("select",{id:y,"aria-label":t?void 0:r,value:s,disabled:d,onChange:b=>a(b.target.value),className:Dt,children:i?i.map(b=>n.jsx("option",{value:b.value,children:b.label},b.value)):u});return t?n.jsxs("div",{className:"flex flex-col gap-1",children:[n.jsx("label",{htmlFor:y,className:"text-xs font-medium text-[var(--otari-muted)]",children:t}),h]}):h}function Tr({label:e,value:t,onChange:r,options:s,placeholder:a,maxVisible:i=50,allowsCustom:u=!1}){const d=m=>{var N;return((N=s.find(M=>M.value===m))==null?void 0:N.label)??m},[f,y]=o.useState(()=>d(t));o.useEffect(()=>{y(d(t))},[t]);const h=f.trim().toLowerCase(),b=s.filter(m=>!h||m.value.toLowerCase().includes(h)||m.label.toLowerCase().includes(h)).slice(0,i);return n.jsxs(U.Root,{allowsEmptyCollection:!0,allowsCustomValue:u,menuTrigger:"focus",inputValue:f,onInputChange:m=>{y(m),u?r(m.trim()):m.trim()===""&&r("")},onSelectionChange:m=>{m!=null&&r(String(m))},className:"flex flex-col gap-1",children:[n.jsx(xe,{className:"text-xs font-medium text-[var(--otari-muted)]",children:e}),n.jsxs(U.InputGroup,{children:[n.jsx(ye,{placeholder:a,autoComplete:"off",onFocus:m=>m.currentTarget.select()}),n.jsx(U.Trigger,{})]}),n.jsx(U.Popover,{children:n.jsx(ze,{items:b,className:"max-h-72 overflow-auto",children:m=>n.jsx(Qe,{id:m.value,textValue:m.label,children:m.label})})})]})}function At(){var f,y;const e=mt(),t=ft(),[r,s]=o.useState(!1),i=((f=e.data)==null?void 0:f.require_pricing)===!0&&e.data.default_pricing===!1&&!r,d=((y=St($,i).data)==null?void 0:y.total)??0;return i?n.jsx("div",{className:"shrink-0 px-6 pt-3",children:n.jsx(_t,{tone:"warning",children:n.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[n.jsxs("span",{children:["Requests are rejected until pricing is set (",n.jsx("code",{children:"require_pricing"})," is on). Enable default pricing to meter new models with public rates right away.",d>0?n.jsxs(n.Fragment,{children:[" ",n.jsxs("strong",{className:"font-semibold",children:[d.toLocaleString()," ",d===1?"request":"requests"," failed in the last hour."]})," ",n.jsx(Fe,{to:"/activity?status=error&range=1h&source=gateway",className:"underline underline-offset-2",children:"View failed requests"})]}):null]}),n.jsxs("span",{className:"flex items-center gap-2",children:[n.jsx(C,{size:"sm",variant:"primary",isDisabled:t.isPending,onPress:()=>t.mutate({default_pricing:!0}),children:t.isPending?"Enabling…":"Enable default pricing"}),n.jsx(C,{size:"sm",variant:"ghost",onPress:()=>s(!0),children:"Dismiss"})]})]})})}):null}function It(){const{data:e}=dt(),t=o.useRef(null);return e&&t.current===null&&(t.current=e.build),e!=null&&t.current!=null&&e.build!==t.current}function qt(){const e=It(),[t,r]=o.useState(!1);return!e||t?null:n.jsx("div",{className:"pointer-events-none absolute inset-x-0 top-0 z-50 flex justify-center",children:n.jsxs("div",{role:"status",className:"pointer-events-auto mt-1.5 flex items-center gap-3 rounded-full border border-[var(--otari-brand)] bg-[var(--otari-brand-tint)] py-1.5 pr-1.5 pl-4 text-sm text-[var(--otari-brand-dark)] shadow-md",children:[n.jsxs("span",{children:[n.jsx("strong",{className:"font-semibold",children:"An update is available."})," Reloading keeps you signed in."]}),n.jsx(C,{size:"sm",variant:"primary",onPress:()=>window.location.reload(),children:"Update now"}),n.jsx(C,{size:"sm",variant:"ghost",onPress:()=>r(!0),children:"Later"})]})})}const je=200,Se=480,X=240,Rt=60,ke="otari.dashboard.sidebarWidth",Ee="otari.dashboard.sidebarCollapsed",he=16,Pe="(max-width: 767px)",B=e=>Math.min(Se,Math.max(je,e));function Ot(){return typeof window>"u"||typeof window.matchMedia!="function"?!1:window.matchMedia(Pe).matches}const Mt='a[href], button:not([disabled]), [tabindex]:not([tabindex="-1"])';function Ft(e){return e?Array.from(e.querySelectorAll(Mt)).filter(t=>t.offsetParent!==null||t===document.activeElement):[]}function Ut(){if(typeof window>"u")return X;try{const e=window.localStorage.getItem(ke),t=e?Number.parseInt(e,10):Number.NaN;return Number.isNaN(t)?X:B(t)}catch{return X}}function Kt(){if(typeof window>"u")return!1;try{return window.localStorage.getItem(Ee)==="1"}catch{return!1}}const Bt=[{key:"home"},{key:"observability",label:"Observability"},{key:"catalog",label:"Catalog"},{key:"access",label:"Access"},{key:"system"}],$t=[{to:"/",section:"home",label:"Overview",end:!0,icon:n.jsxs("svg",{"aria-hidden":!0,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",className:"h-5 w-5 shrink-0",children:[n.jsx("rect",{x:"3.5",y:"3.5",width:"7",height:"7",rx:"1.5",strokeLinejoin:"round"}),n.jsx("rect",{x:"13.5",y:"3.5",width:"7",height:"7",rx:"1.5",strokeLinejoin:"round"}),n.jsx("rect",{x:"3.5",y:"13.5",width:"7",height:"7",rx:"1.5",strokeLinejoin:"round"}),n.jsx("rect",{x:"13.5",y:"13.5",width:"7",height:"7",rx:"1.5",strokeLinejoin:"round"})]})},{to:"/activity",section:"observability",label:"Activity",icon:n.jsx("svg",{"aria-hidden":!0,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",className:"h-5 w-5 shrink-0",children:n.jsx("path",{d:"M3 12h4l2.5-6 4 12 2.5-6H21",strokeLinecap:"round",strokeLinejoin:"round"})})},{to:"/usage",section:"observability",label:"Usage",icon:n.jsx("svg",{"aria-hidden":!0,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",className:"h-5 w-5 shrink-0",children:n.jsx("path",{d:"M4 20V10M10 20V4M16 20v-7M22 20H2",strokeLinecap:"round",strokeLinejoin:"round"})})},{to:"/providers",section:"catalog",label:"Providers",icon:n.jsxs("svg",{"aria-hidden":!0,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",className:"h-5 w-5 shrink-0",children:[n.jsx("rect",{x:"3.5",y:"4.5",width:"17",height:"6",rx:"1.5",strokeLinejoin:"round"}),n.jsx("rect",{x:"3.5",y:"13.5",width:"17",height:"6",rx:"1.5",strokeLinejoin:"round"}),n.jsx("path",{d:"M7 7.5h.01M7 16.5h.01",strokeLinecap:"round",strokeLinejoin:"round"})]})},{to:"/users",section:"access",label:"Users",icon:n.jsxs("svg",{"aria-hidden":!0,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",className:"h-5 w-5 shrink-0",children:[n.jsx("circle",{cx:"9",cy:"8",r:"3.2",strokeLinejoin:"round"}),n.jsx("path",{d:"M3.5 19a5.5 5.5 0 0 1 11 0",strokeLinecap:"round",strokeLinejoin:"round"}),n.jsx("path",{d:"M16 5.2a3.2 3.2 0 0 1 0 5.6M17.5 19a5.5 5.5 0 0 0-3-4.9",strokeLinecap:"round",strokeLinejoin:"round"})]})},{to:"/keys",section:"access",label:"API keys",icon:n.jsxs("svg",{"aria-hidden":!0,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",className:"h-5 w-5 shrink-0",children:[n.jsx("circle",{cx:"7.5",cy:"15.5",r:"3.5"}),n.jsx("path",{d:"M10 13l7-7M14 5l3 3M16.5 7.5l2-2",strokeLinecap:"round",strokeLinejoin:"round"})]})},{to:"/budgets",section:"access",label:"Budgets",icon:n.jsxs("svg",{"aria-hidden":!0,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",className:"h-5 w-5 shrink-0",children:[n.jsx("path",{d:"M3 7.5A1.5 1.5 0 0 1 4.5 6H18a1.5 1.5 0 0 1 1.5 1.5V9",strokeLinejoin:"round"}),n.jsx("rect",{x:"3",y:"7.5",width:"18",height:"12",rx:"1.5",strokeLinejoin:"round"}),n.jsx("path",{d:"M16 13.5h.01",strokeLinecap:"round",strokeLinejoin:"round"}),n.jsx("path",{d:"M21 12v3h-3.5a1.5 1.5 0 0 1 0-3H21z",strokeLinejoin:"round"})]})},{to:"/models",section:"catalog",label:"Models",icon:n.jsxs("svg",{"aria-hidden":!0,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",className:"h-5 w-5 shrink-0",children:[n.jsx("path",{d:"M12 3l8 4.5v9L12 21l-8-4.5v-9L12 3z",strokeLinejoin:"round"}),n.jsx("path",{d:"M12 12l8-4.5M12 12v9M12 12L4 7.5",strokeLinejoin:"round"})]})},{to:"/aliases",section:"catalog",label:"Aliases",icon:n.jsxs("svg",{"aria-hidden":!0,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",className:"h-5 w-5 shrink-0",children:[n.jsx("path",{d:"M20.6 13.4L13.4 20.6a2 2 0 0 1-2.8 0l-7-7A2 2 0 0 1 3 12.2V5a2 2 0 0 1 2-2h7.2a2 2 0 0 1 1.4.6l7 7a2 2 0 0 1 0 2.8z",strokeLinejoin:"round"}),n.jsx("circle",{cx:"7.5",cy:"7.5",r:"1.5"})]})},{to:"/tools",section:"system",label:"Tools & Guardrails",icon:n.jsxs("svg",{"aria-hidden":!0,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",className:"h-5 w-5 shrink-0",children:[n.jsx("path",{d:"M14.7 6.3a4 4 0 0 1 5 5l-8.4 8.4a2 2 0 0 1-2.8 0l-2.2-2.2a2 2 0 0 1 0-2.8z",strokeLinejoin:"round"}),n.jsx("path",{d:"M12 9 5 16",strokeLinecap:"round"})]})},{to:"/settings",section:"system",label:"Settings",icon:n.jsxs("svg",{"aria-hidden":!0,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",className:"h-5 w-5 shrink-0",children:[n.jsx("circle",{cx:"12",cy:"12",r:"3"}),n.jsx("path",{d:"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z",strokeLinejoin:"round"})]})}];function zt(){const{logout:e}=re(),t=o.useRef(null),r=o.useRef(null),s=o.useRef(null),[a,i]=o.useState(Ut),[u,d]=o.useState(Kt),[f,y]=o.useState(!1),[h,b]=o.useState(Ot),[m,N]=o.useState(!1);o.useEffect(()=>{if(typeof window>"u"||typeof window.matchMedia!="function")return;const l=window.matchMedia(Pe),v=w=>{b(w.matches),w.matches||N(!1)};return typeof l.addEventListener=="function"?(l.addEventListener("change",v),()=>l.removeEventListener("change",v)):(l.addListener(v),()=>l.removeListener(v))},[]),o.useEffect(()=>{if(!m)return;const l=v=>{v.key==="Escape"&&N(!1)};return window.addEventListener("keydown",l),()=>window.removeEventListener("keydown",l)},[m]),o.useEffect(()=>{var l,v,w;h&&(m?(l=t.current)==null||l.focus():(v=t.current)!=null&&v.contains(document.activeElement)&&((w=s.current)==null||w.focus()))},[h,m]);const M=o.useCallback(l=>{if(l.key!=="Tab")return;const v=Ft(t.current);if(v.length===0)return;const w=v[0],k=v[v.length-1],F=document.activeElement;l.shiftKey&&(F===w||F===t.current)?(l.preventDefault(),k.focus()):!l.shiftKey&&F===k&&(l.preventDefault(),w.focus())},[]);o.useEffect(()=>{const l=window.setTimeout(()=>{try{window.localStorage.setItem(ke,String(Math.round(a)))}catch{}},200);return()=>window.clearTimeout(l)},[a]),o.useEffect(()=>{try{window.localStorage.setItem(Ee,u?"1":"0")}catch{}},[u]);const Ce=o.useCallback(l=>{l.preventDefault(),l.currentTarget.setPointerCapture(l.pointerId),y(!0)},[]),Te=o.useCallback(l=>{var w;if(!l.currentTarget.hasPointerCapture(l.pointerId))return;const v=((w=t.current)==null?void 0:w.getBoundingClientRect().left)??0;i(B(l.clientX-v))},[]),_e=o.useCallback(l=>{l.currentTarget.hasPointerCapture(l.pointerId)&&l.currentTarget.releasePointerCapture(l.pointerId),y(!1)},[]),Le=o.useCallback(l=>{var v;l.preventDefault(),(v=r.current)==null||v.focus()},[]),De=o.useCallback(l=>{l.key==="ArrowLeft"?(l.preventDefault(),i(v=>B(v-he))):l.key==="ArrowRight"&&(l.preventDefault(),i(v=>B(v+he)))},[]),Ae=u?Rt:a,S=h?!1:u,W=h&&m?!0:void 0;return n.jsxs("div",{className:T("relative flex h-full flex-col overflow-hidden",f&&"cursor-col-resize select-none"),children:[n.jsx("button",{type:"button",inert:W,onClick:Le,className:"sr-only focus:not-sr-only focus:absolute focus:top-3 focus:left-3 focus:z-50 focus:rounded-lg focus:border focus:border-[var(--otari-brand)] focus:bg-[var(--otari-surface)] focus:px-4 focus:py-2 focus:text-sm focus:font-medium focus:text-[var(--otari-brand-dark)] focus:shadow-md focus:outline-none",children:"Skip to main content"}),n.jsxs("header",{inert:W,className:"flex shrink-0 items-center justify-between border-b border-[var(--otari-line)] bg-[var(--otari-surface)] px-5 py-3",children:[n.jsxs("div",{className:"flex items-center gap-2.5",children:[n.jsx("button",{type:"button",ref:s,onClick:()=>N(l=>!l),"aria-label":m?"Close navigation":"Open navigation","aria-expanded":m,"aria-controls":"app-sidebar",className:"-ml-1 flex h-8 w-8 items-center justify-center rounded-lg text-[var(--otari-muted)] transition-colors hover:bg-[var(--otari-bg)] hover:text-[var(--otari-ink)] md:hidden",children:n.jsx("svg",{"aria-hidden":!0,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",className:"h-5 w-5",children:n.jsx("path",{d:"M4 6h16M4 12h16M4 18h16",strokeLinecap:"round",strokeLinejoin:"round"})})}),n.jsx("img",{src:"/favicon.svg",alt:"",className:"h-7 w-7 shrink-0"}),n.jsx("span",{className:"text-base font-semibold text-[var(--otari-ink)]",children:"Otari"})]}),n.jsx(C,{size:"sm",variant:"outline",onPress:e,"aria-label":"Sign out",children:"Sign out"})]}),n.jsx(qt,{}),n.jsx(st,{}),n.jsx(At,{}),n.jsxs("div",{className:"flex min-h-0 flex-1",children:[h&&m?n.jsx("div",{"aria-hidden":"true",onClick:()=>N(!1),className:"fixed inset-0 z-30 bg-black/40 md:hidden"}):null,n.jsxs("aside",{ref:t,id:"app-sidebar",role:h?"dialog":void 0,"aria-modal":h&&m?!0:void 0,"aria-label":h?"Navigation":void 0,tabIndex:h?-1:void 0,inert:h&&!m?!0:void 0,onKeyDown:h&&m?M:void 0,style:h?void 0:{width:Ae},className:T("flex flex-col border-r border-[var(--otari-line)] bg-[var(--otari-surface)] focus:outline-none",h?T("fixed inset-y-0 left-0 z-40 w-[17rem] shadow-xl transition-transform duration-200",m?"translate-x-0":"-translate-x-full"):T("relative shrink-0",!f&&"transition-[width] duration-150")),children:[n.jsx("button",{type:"button",onClick:()=>d(l=>!l),"aria-label":u?"Expand sidebar":"Collapse sidebar","aria-pressed":u,title:u?"Expand sidebar":"Collapse sidebar",className:"absolute -right-3 top-4 z-30 hidden h-6 w-6 items-center justify-center rounded-full border border-[var(--otari-line)] bg-[var(--otari-surface)] text-[var(--otari-muted)] shadow-sm transition-colors hover:border-[var(--otari-brand)] hover:text-[var(--otari-brand-dark)] md:flex",children:n.jsx("svg",{"aria-hidden":!0,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2.5",className:T("h-3.5 w-3.5 transition-transform",u&&"rotate-180"),children:n.jsx("path",{d:"M15 6l-6 6 6 6",strokeLinecap:"round",strokeLinejoin:"round"})})}),n.jsx("nav",{className:T("flex flex-col py-4",S?"px-2":"px-3"),children:Bt.map((l,v)=>{const w=$t.filter(k=>k.section===l.key);return w.length===0?null:n.jsxs("div",{className:v>0?"mt-4":void 0,children:[!S&&l.label?n.jsx("div",{className:"px-3 pb-1 text-[11px] font-semibold tracking-wider text-[var(--otari-muted)] uppercase",children:l.label}):null,v>0&&(S||!l.label)?n.jsx("div",{className:"mx-1 mb-2 border-t border-[var(--otari-line)]"}):null,n.jsx("div",{className:"flex flex-col gap-1",children:w.map(k=>n.jsxs(Z,{to:k.to,end:k.end,onClick:()=>N(!1),"aria-label":S?k.label:void 0,title:S?k.label:void 0,className:({isActive:F})=>T("flex items-center rounded-lg py-2 text-sm font-medium transition-colors",S?"justify-center px-0":"gap-3 px-3",F?"bg-[var(--otari-brand-tint)] text-[var(--otari-brand-dark)]":"text-[var(--otari-muted)] hover:bg-[var(--otari-bg)] hover:text-[var(--otari-ink)]"),children:[k.icon,S?null:k.label]},k.to))})]},l.key)})}),n.jsxs("div",{className:"mt-auto flex flex-col gap-1 pb-3",children:[n.jsxs(Z,{to:"/docs",onClick:()=>N(!1),"aria-label":S?"User guide":void 0,title:S?"User guide":void 0,className:({isActive:l})=>T("flex items-center rounded-lg py-2 text-sm font-medium transition-colors",S?"mx-2 justify-center px-0":"mx-3 gap-3 px-3",l?"bg-[var(--otari-brand-tint)] text-[var(--otari-brand-dark)]":"text-[var(--otari-muted)] hover:bg-[var(--otari-bg)] hover:text-[var(--otari-ink)]"),children:[n.jsxs("svg",{"aria-hidden":"true",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",className:"h-5 w-5 shrink-0",children:[n.jsx("path",{d:"M12 6.5C10.5 5 8 4.5 4 4.5V18c4 0 6.5.5 8 2 1.5-1.5 4-2 8-2V4.5c-4 0-6.5.5-8 2z",strokeLinejoin:"round"}),n.jsx("path",{d:"M12 6.5V20",strokeLinecap:"round"})]}),S?null:"User guide"]}),n.jsxs("a",{href:"https://otari.ai",target:"_blank",rel:"noreferrer",title:"otari.ai: the hosted Otari gateway",className:T("flex items-center rounded-lg py-2 text-xs font-medium text-[var(--otari-muted)] transition-colors hover:bg-[var(--otari-bg)] hover:text-[var(--otari-brand-dark)]",S?"mx-2 justify-center px-0":"mx-3 gap-2 px-3"),children:[n.jsx("svg",{"aria-hidden":!0,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",className:"h-4 w-4 shrink-0",children:n.jsx("path",{d:"M18 10h-1.26A8 8 0 1 0 9 20h9a5 5 0 0 0 0-10z",strokeLinejoin:"round"})}),S?null:n.jsxs("span",{className:"flex-1",children:["otari.ai ",n.jsx("span",{"aria-hidden":!0,children:"↗"})]})]})]}),u||h?null:n.jsx("div",{role:"separator","aria-orientation":"vertical","aria-label":"Resize sidebar","aria-valuenow":Math.round(a),"aria-valuemin":je,"aria-valuemax":Se,tabIndex:0,onPointerDown:Ce,onPointerMove:Te,onPointerUp:_e,onKeyDown:De,className:T("absolute top-0 right-0 z-10 h-full w-1.5 cursor-col-resize touch-none transition-colors","hover:bg-[var(--otari-brand)] focus-visible:bg-[var(--otari-brand)] focus:outline-none",f?"bg-[var(--otari-brand)]":"bg-transparent")})]}),n.jsx("main",{ref:r,id:"main-content",tabIndex:-1,inert:W,className:"flex-1 overflow-y-auto focus:outline-none",children:n.jsx("div",{className:"mx-auto flex max-w-[1800px] flex-col gap-6 px-4 py-5 md:px-6 md:py-6",children:n.jsx(Ue,{})})})]})]})}function Qt(){const{login:e}=re(),[t,r]=o.useState(""),[s,a]=o.useState(null),[i,u]=o.useState(!1),d=async()=>{const f=t.trim();if(!(!f||i)){u(!0),a(null);try{await Xe(f)?e():a(new Error("Invalid master key."))}catch(y){a(y)}finally{u(!1)}}};return n.jsx("div",{className:"flex min-h-full items-center justify-center p-6",children:n.jsx(I,{className:"w-full max-w-md",children:n.jsxs(I.Content,{className:"flex flex-col gap-5 p-7",children:[n.jsxs("div",{className:"flex flex-col items-center gap-3 text-center",children:[n.jsx("img",{src:"/favicon.svg",alt:"Otari",className:"h-12 w-12"}),n.jsxs("div",{children:[n.jsx("h1",{className:"text-lg font-semibold text-[var(--otari-ink)]",children:"Otari Dashboard"}),n.jsx("p",{className:"mt-1 text-sm text-[var(--otari-muted)]",children:"Sign in with your master key to browse models, set pricing, and manage settings."})]})]}),n.jsxs("form",{className:"flex flex-col gap-4",onSubmit:f=>{f.preventDefault(),d()},children:[n.jsxs(We,{value:t,onChange:f=>{r(f),s&&a(null)},type:"password",isRequired:!0,className:"flex flex-col gap-1",children:[n.jsx(xe,{className:"text-sm font-medium text-[var(--otari-ink)]",children:"Master key"}),n.jsx(ye,{placeholder:"otari-mk-… or your master key",autoFocus:!0,autoComplete:"off"})]}),n.jsxs("details",{className:"text-xs text-[var(--otari-muted)]",children:[n.jsx("summary",{className:"cursor-pointer font-medium text-[var(--otari-brand-dark)]",children:"First run? Where to find your key"}),n.jsxs("p",{className:"mt-2 leading-relaxed",children:["If you did not set ",n.jsx("code",{children:"OTARI_MASTER_KEY"}),", Otari generated one and printed it to the server logs on startup. Look for the line ",n.jsx("code",{children:"Your master key:"})," (for example, run"," ",n.jsx("code",{children:"docker logs "}),") and paste it above."]})]}),n.jsx(Tt,{error:s}),n.jsx(C,{type:"submit",variant:"primary",fullWidth:!0,isDisabled:!t.trim()||i,children:i?"Signing in…":"Sign in"})]}),n.jsx("p",{className:"text-center text-xs text-[var(--otari-muted)]",children:"The key is sent once to this gateway and exchanged for a session cookie; it is never stored in the browser."}),n.jsx("div",{className:"border-t border-[var(--otari-line)] pt-4 text-center",children:n.jsx(He,{href:"/welcome",className:"text-sm font-medium text-[var(--otari-brand-dark)]",children:"New to Otari? Open the welcome guide"})})]})})})}const Vt=o.lazy(async()=>({default:(await P(async()=>{const{ActivityPage:e}=await import("./ActivityPage-C5gSmqNJ.js");return{ActivityPage:e}},__vite__mapDeps([0,1,2,3,4,5,6,7,8,9]))).ActivityPage})),Wt=o.lazy(async()=>({default:(await P(async()=>{const{AliasesPage:e}=await import("./AliasesPage-D7ZKXX3I.js");return{AliasesPage:e}},__vite__mapDeps([10,1,2,6,4,7,8,11,12]))).AliasesPage})),Ht=o.lazy(async()=>({default:(await P(async()=>{const{BudgetsPage:e}=await import("./BudgetsPage-DanpEezo.js");return{BudgetsPage:e}},__vite__mapDeps([13,1,2,6,4,7,8,11]))).BudgetsPage})),Gt=o.lazy(async()=>({default:(await P(async()=>{const{DocsPage:e}=await import("./DocsPage-DkHyFdGF.js");return{DocsPage:e}},__vite__mapDeps([14,1,2,4]))).DocsPage})),Jt=o.lazy(async()=>({default:(await P(async()=>{const{KeysPage:e}=await import("./KeysPage-D4g9XrFY.js");return{KeysPage:e}},__vite__mapDeps([15,1,2,6,4,7,8,11,16,12]))).KeysPage})),Yt=o.lazy(async()=>({default:(await P(async()=>{const{ModelsPage:e}=await import("./ModelsPage-r0TNjwml.js");return{ModelsPage:e}},__vite__mapDeps([17,1,2,6,4,8,9]))).ModelsPage})),Xt=o.lazy(async()=>({default:(await P(async()=>{const{OverviewIndex:e}=await import("./OverviewPage-WmIAewmo.js");return{OverviewIndex:e}},__vite__mapDeps([18,1,2,19,5,4,8]))).OverviewIndex})),Zt=o.lazy(async()=>({default:(await P(async()=>{const{ProvidersPage:e}=await import("./ProvidersPage-BRQCYCYu.js");return{ProvidersPage:e}},__vite__mapDeps([20,1,2,11,4,8]))).ProvidersPage})),en=o.lazy(async()=>({default:(await P(async()=>{const{SettingsPage:e}=await import("./SettingsPage-DjaTcy-f.js");return{SettingsPage:e}},__vite__mapDeps([21,1,2,4]))).SettingsPage})),tn=o.lazy(async()=>({default:(await P(async()=>{const{ToolsGuardrailsPage:e}=await import("./ToolsGuardrailsPage-B4MIR_ke.js");return{ToolsGuardrailsPage:e}},__vite__mapDeps([22,1,2,4]))).ToolsGuardrailsPage})),nn=o.lazy(async()=>({default:(await P(async()=>{const{UsagePage:e}=await import("./UsagePage-CGU7s9AT.js");return{UsagePage:e}},__vite__mapDeps([23,1,2,3,4,5,6,19,7,8,9]))).UsagePage})),rn=o.lazy(async()=>({default:(await P(async()=>{const{UsersPage:e}=await import("./UsersPage-CUF9BhT-.js");return{UsersPage:e}},__vite__mapDeps([24,1,2,6,4,7,8,11,16]))).UsersPage}));function E(e){return n.jsx(o.Suspense,{fallback:n.jsx("div",{role:"status",children:"Loading page…"}),children:e})}function sn(){const{isAuthenticated:e}=re();return e?n.jsx(Ke,{children:n.jsx(Be,{children:n.jsxs(j,{element:n.jsx(zt,{}),children:[n.jsx(j,{index:!0,element:E(n.jsx(Xt,{}))}),n.jsx(j,{path:"providers",element:E(n.jsx(Zt,{}))}),n.jsx(j,{path:"keys",element:E(n.jsx(Jt,{}))}),n.jsx(j,{path:"users",element:E(n.jsx(rn,{}))}),n.jsx(j,{path:"budgets",element:E(n.jsx(Ht,{}))}),n.jsx(j,{path:"activity",element:E(n.jsx(Vt,{}))}),n.jsx(j,{path:"usage",element:E(n.jsx(nn,{}))}),n.jsx(j,{path:"models",element:E(n.jsx(Yt,{}))}),n.jsx(j,{path:"aliases",element:E(n.jsx(Wt,{}))}),n.jsx(j,{path:"tools",element:E(n.jsx(tn,{}))}),n.jsx(j,{path:"settings",element:E(n.jsx(en,{}))}),n.jsx(j,{path:"docs",element:E(n.jsx(Gt,{}))}),n.jsx(j,{path:"*",element:n.jsx($e,{to:"/",replace:!0})})]})})}):n.jsx(Qt,{})}function an({children:e}){const[t]=o.useState(()=>new Re({defaultOptions:{queries:{refetchOnWindowFocus:!1,retry:(r,s)=>s instanceof L&&(s.status===401||s.status===403)?!1:r<2}}}));return n.jsx(Oe,{client:t,children:n.jsx(tt,{children:e})})}const Ne=document.getElementById("root");if(!Ne)throw new Error("Root element #root not found");Ge.createRoot(Ne).render(n.jsx(o.StrictMode,{children:n.jsx(an,{children:n.jsx(sn,{})})}));export{hr as $,hn as A,Zn as B,xn as C,Jn as D,Tt as E,Cr as F,wn as G,$n as H,_t as I,qn as J,zn as K,yr as L,Qn as M,Ct as N,vr as O,Sr as P,mt as Q,kr as R,xr as S,Sn as T,Pr as U,Pn as V,br as W,wr as X,at as Y,gr as Z,jr as _,Gn as a,Pt as a0,Nt as a1,Cn as a2,Ln as a3,An as a4,ft as a5,_n as a6,Nn as a7,Tn as a8,En as a9,kn as aa,In as ab,Vn as ac,Wn as ad,Hn as ae,Fn as af,Dn as ag,Un as ah,Kn as ai,Bn as aj,mn as ak,dn as al,pr as am,bn as an,ot as ao,pn as ap,gn as aq,lr as ar,ir as as,cr as b,ur as c,fr as d,vn as e,yn as f,dr as g,mr as h,fn as i,Tr as j,it as k,jn as l,Rn as m,Mn as n,Nr as o,On as p,er as q,nr as r,rr as s,sr as t,ar as u,or as v,Er as w,tr as x,Yn as y,Xn as z}; diff --git a/src/gateway/static/dashboard/assets/index-D4f8RVEq.js b/src/gateway/static/dashboard/assets/index-D4f8RVEq.js deleted file mode 100644 index 416673d6..00000000 --- a/src/gateway/static/dashboard/assets/index-D4f8RVEq.js +++ /dev/null @@ -1,2 +0,0 @@ -const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/ActivityPage-DsPiQv1J.js","assets/tanstack-query-1t81HyiD.js","assets/react-dgEcD0HR.js","assets/FilterChips-DtSH11eU.js","assets/heroui-BI50yK5B.js","assets/recharts-C4kRDmvS.js","assets/tableSelection-9hV37uhu.js","assets/ConfirmDialog-a8LQxZuS.js","assets/DataTable-Bmn_eYSV.js","assets/TablePagination-BTOqrUVz.js","assets/AliasesPage-BTmc50Jm.js","assets/Field-Dwp6u3t8.js","assets/UserComboBox-a9wxf8eF.js","assets/BudgetsPage-hf0SYw2U.js","assets/DocsPage-CUNhOocN.js","assets/KeysPage-Dnb7jGCb.js","assets/ModelScopeControl-CVWeyWke.js","assets/ModelsPage-BMeU3W4u.js","assets/OverviewPage-CW42wjoO.js","assets/charts-DIsd9m--.js","assets/ProvidersPage-D2tIyvqh.js","assets/SettingsPage-k4BcKpbT.js","assets/ToolsGuardrailsPage-Cl0epDLn.js","assets/UsagePage-B6Ow1D4j.js","assets/UsersPage-d3EPlBj3.js"])))=>i.map(i=>d[i]); -var Le=Object.defineProperty;var Ie=(e,r,n)=>r in e?Le(e,r,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[r]=n;var ie=(e,r,n)=>Ie(e,typeof r!="symbol"?r+"":r,n);import{u as y,j as t,a as g,b as h,k as X,Q as Ae,c as qe}from"./tanstack-query-1t81HyiD.js";import{d as Re,r as a,N as G,O as De,H as Oe,e as Me,f as w,h as Fe}from"./react-dgEcD0HR.js";import{B as C,C as M,L as me,I as fe,a as Ue,b as Ke,d as I,S as Be,c as _,T as $e,e as ze}from"./heroui-BI50yK5B.js";(function(){const r=document.createElement("link").relList;if(r&&r.supports&&r.supports("modulepreload"))return;for(const i of document.querySelectorAll('link[rel="modulepreload"]'))s(i);new MutationObserver(i=>{for(const o of i)if(o.type==="childList")for(const d of o.addedNodes)d.tagName==="LINK"&&d.rel==="modulepreload"&&s(d)}).observe(document,{childList:!0,subtree:!0});function n(i){const o={};return i.integrity&&(o.integrity=i.integrity),i.referrerPolicy&&(o.referrerPolicy=i.referrerPolicy),i.crossOrigin==="use-credentials"?o.credentials="include":i.crossOrigin==="anonymous"?o.credentials="omit":o.credentials="same-origin",o}function s(i){if(i.ep)return;i.ep=!0;const o=n(i);fetch(i.href,o)}})();var Qe=Re();const Ve="modulepreload",We=function(e){return"/"+e},oe={},P=function(r,n,s){let i=Promise.resolve();if(n&&n.length>0){let d=function(x){return Promise.all(x.map(f=>Promise.resolve(f).then(b=>({status:"fulfilled",value:b}),b=>({status:"rejected",reason:b}))))};document.getElementsByTagName("link");const m=document.querySelector("meta[property=csp-nonce]"),p=(m==null?void 0:m.nonce)||(m==null?void 0:m.getAttribute("nonce"));i=d(n.map(x=>{if(x=We(x),x in oe)return;oe[x]=!0;const f=x.endsWith(".css"),b=f?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${x}"]${b}`))return;const u=document.createElement("link");if(u.rel=f?"stylesheet":Ve,f||(u.as="script"),u.crossOrigin="",u.href=x,p&&u.setAttribute("nonce",p),document.head.appendChild(u),f)return new Promise((N,R)=>{u.addEventListener("load",N),u.addEventListener("error",()=>R(new Error(`Unable to preload CSS for ${x}`)))})}))}function o(d){const m=new Event("vite:preloadError",{cancelable:!0});if(m.payload=d,window.dispatchEvent(m),!m.defaultPrevented)throw d}return i.then(d=>{for(const m of d||[])m.status==="rejected"&&o(m.reason);return r().catch(o)})};class T extends Error{constructor(n,s){super(s);ie(this,"status");this.name="ApiError",this.status=n}}let F=null;function le(e){F=e}async function J(e){try{const r=await e.json();if(typeof r.detail=="string")return r.detail;if(r.detail!=null)return JSON.stringify(r.detail)}catch{}return e.statusText||`Request failed (${e.status})`}async function He(e){let r;try{r=await fetch("/v1/auth/session",{method:"POST",headers:{Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify({master_key:e})})}catch{throw new T(0,"Network error: could not reach the gateway.")}if(r.status===401||r.status===403)return!1;if(!r.ok)throw new T(r.status,await J(r));return!0}async function Ge(){try{await fetch("/v1/auth/session",{method:"DELETE"})}catch{}}async function c(e,r={}){const n=new Headers(r.headers);n.set("Accept","application/json"),r.body!=null&&!n.has("Content-Type")&&n.set("Content-Type","application/json");let s;try{s=await fetch(e,{...r,headers:n})}catch{throw new T(0,"Network error: could not reach the gateway.")}if(s.status===401||s.status===403)throw F==null||F(),new T(s.status,await J(s));if(!s.ok)throw new T(s.status,await J(s));if(s.status!==204)return await s.json()}const Y="otari.dashboard.hasSession",he=a.createContext(null);function Je(){try{return window.localStorage.getItem(Y)==="1"}catch{return!1}}function Ye({children:e}){const r=y(),[n,s]=a.useState(Je),i=a.useCallback(()=>{Ge(),s(!1),r.clear();try{window.localStorage.removeItem(Y)}catch{}},[r]),o=a.useCallback(()=>{r.clear(),s(!0);try{window.localStorage.setItem(Y,"1")}catch{}},[r]);a.useEffect(()=>(le(i),()=>le(null)),[i]);const d=a.useMemo(()=>({isAuthenticated:n,login:o,logout:i}),[n,o,i]);return t.jsx(he.Provider,{value:d,children:e})}function Z(){const e=a.useContext(he);if(!e)throw new Error("useAuth must be used within an AuthProvider");return e}function Xe(e){return e instanceof T&&e.status===0}function Ze(){const e=y(),[r,n]=a.useState(!1);return a.useEffect(()=>{const s=e.getQueryCache(),i=()=>s.getAll().some(o=>o.state.status==="error"&&Xe(o.state.error));return n(i()),s.subscribe(()=>n(i()))},[e]),r}function et(){return Ze()?t.jsxs("div",{role:"alert","aria-live":"assertive",className:"fixed right-4 bottom-4 z-50 flex max-w-sm items-start gap-2.5 rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700 shadow-lg",children:[t.jsxs("svg",{viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2","aria-hidden":!0,className:"mt-0.5 h-5 w-5 shrink-0",children:[t.jsx("path",{d:"M12 9v4M12 17h.01",strokeLinecap:"round",strokeLinejoin:"round"}),t.jsx("path",{d:"M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z",strokeLinejoin:"round"})]}),t.jsxs("span",{children:[t.jsx("strong",{className:"font-semibold",children:"Can’t reach the gateway."})," The backend isn’t responding; data won’t load or save until the connection is restored."]})]}):null}const L="models",K="pricing",xe="settings",ve="tool-settings",ee="aliases",te="discoverable",re="providers",ne="provider-health",ye="stored-providers",tt="model-metadata",rt="build",A="keys",q="budgets",pe="users",O="usage",nt=6e4,ce=60*6e4;function tr(){return g({queryKey:[L],queryFn:()=>c("/v1/models"),staleTime:6e4})}function st(){return g({queryKey:[rt],queryFn:()=>c("/dashboard-build.json"),refetchInterval:nt,refetchOnWindowFocus:!0,staleTime:0,retry:!1})}function rr(){return g({queryKey:[te],queryFn:()=>c("/v1/models/discoverable"),staleTime:5*6e4})}function nr(){return g({queryKey:[re],queryFn:()=>c("/v1/providers"),staleTime:5*6e4})}function sr(){return g({queryKey:["provider-catalog"],queryFn:()=>c("/v1/providers/catalog"),staleTime:1/0})}function ar(e){return g({queryKey:["provider-catalog",e],queryFn:()=>c(`/v1/providers/catalog/${encodeURIComponent(e)}`),enabled:e!=="",staleTime:1/0})}function ir(){return g({queryKey:[ne],queryFn:()=>c("/v1/providers/health"),staleTime:ce,refetchInterval:ce})}function or(){const e=y();return h({mutationFn:()=>c("/v1/providers/health?refresh=true"),onSuccess:r=>e.setQueryData([ne],r)})}function lr(){return g({queryKey:[ye],queryFn:()=>c("/v1/provider-credentials"),staleTime:6e4})}function B(e){e.invalidateQueries({queryKey:[ye]}),e.invalidateQueries({queryKey:[re]}),e.invalidateQueries({queryKey:[L]}),e.invalidateQueries({queryKey:[te]}),e.invalidateQueries({queryKey:[ne]})}function cr(){const e=y();return h({mutationFn:r=>c("/v1/provider-credentials",{method:"POST",body:JSON.stringify(r)}),onSuccess:()=>B(e)})}function ur(){const e=y();return h({mutationFn:({instance:r,body:n})=>c(`/v1/provider-credentials/${encodeURIComponent(r)}`,{method:"PATCH",body:JSON.stringify(n)}),onSuccess:()=>B(e)})}function dr(){const e=y();return h({mutationFn:r=>c(`/v1/provider-credentials/${encodeURIComponent(r)}`,{method:"DELETE"}),onSuccess:()=>B(e)})}function mr(){const e=y();return h({mutationFn:()=>c("/v1/provider-credentials/reencrypt",{method:"POST"}),onSuccess:()=>B(e)})}function fr(){return h({mutationFn:e=>c(`/v1/provider-credentials/${encodeURIComponent(e)}/test`,{method:"POST"})})}function hr(){return h({mutationFn:e=>c("/v1/provider-credentials/test",{method:"POST",body:JSON.stringify(e)})})}function xr(){return g({queryKey:[tt],queryFn:()=>c("/v1/models/metadata"),staleTime:10*6e4})}function vr(){return g({queryKey:[ee],queryFn:()=>c("/v1/aliases"),staleTime:6e4})}function yr(){const e=y();return h({mutationFn:r=>c("/v1/aliases",{method:"POST",body:JSON.stringify(r)}),onSuccess:()=>{e.invalidateQueries({queryKey:[ee]}),e.invalidateQueries({queryKey:[L]})}})}function pr(){const e=y();return h({mutationFn:({name:r,userId:n})=>{const s=n==null?"":`?user_id=${encodeURIComponent(n)}`;return c(`/v1/aliases/${encodeURIComponent(r)}${s}`,{method:"DELETE"})},onSuccess:()=>{e.invalidateQueries({queryKey:[ee]}),e.invalidateQueries({queryKey:[L]})}})}function at(){return g({queryKey:[xe],queryFn:()=>c("/v1/settings"),staleTime:6e4})}function it(){const e=y();return h({mutationFn:r=>c("/v1/settings",{method:"PATCH",body:JSON.stringify(r)}),onSuccess:r=>{e.setQueryData([xe],r),e.invalidateQueries({queryKey:[L]}),e.invalidateQueries({queryKey:[te]})}})}function gr(){return h({mutationFn:()=>c("/v1/settings/master-key/rotate",{method:"POST"})})}function br(){return g({queryKey:[ve],queryFn:()=>c("/v1/tool-settings"),staleTime:6e4})}function jr(){const e=y();return h({mutationFn:r=>c("/v1/tool-settings",{method:"PATCH",body:JSON.stringify(r)}),onSuccess:r=>{e.setQueryData([ve],r)}})}function wr(){return h({mutationFn:({service:e,url:r})=>c(`/v1/tool-settings/${encodeURIComponent(e)}/test`,{method:"POST",body:JSON.stringify({url:r})})})}const z=1e3,ot=100;async function lt(){const e=[];for(let r=0;rc("/v1/pricing",{method:"POST",body:JSON.stringify(r)}),onSuccess:()=>{e.invalidateQueries({queryKey:[K]}),e.invalidateQueries({queryKey:[L]})}})}function Er(){const e=y();return h({mutationFn:r=>c(`/v1/pricing/${encodeURIComponent(r)}`,{method:"DELETE"}),onSuccess:()=>{e.invalidateQueries({queryKey:[K]}),e.invalidateQueries({queryKey:[L]})}})}function Pr(){return h({mutationFn:()=>c("/v1/pricing/refresh",{method:"POST"})})}function Nr(){const e=y();return h({mutationFn:()=>c("/v1/pricing/refresh/confirm",{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:[K]}),e.invalidateQueries({queryKey:[L]}),e.invalidateQueries({queryKey:[re]})}})}function Cr(){return h({mutationFn:()=>c("/v1/pricing/refresh/reject",{method:"POST"})})}const Q=1e3,ct=100;async function ut(){const e=[];for(let r=0;rc("/v1/keys",{method:"POST",body:JSON.stringify(r)}),onSuccess:()=>void e.invalidateQueries({queryKey:[A]})})}function Lr(){const e=y();return h({mutationFn:({id:r,body:n})=>c(`/v1/keys/${encodeURIComponent(r)}`,{method:"PATCH",body:JSON.stringify(n)}),onSuccess:()=>void e.invalidateQueries({queryKey:[A]})})}function Ir(){const e=y();return h({mutationFn:r=>c(`/v1/keys/${encodeURIComponent(r)}/rotate`,{method:"POST"}),onSuccess:()=>void e.invalidateQueries({queryKey:[A]})})}function Ar(){const e=y();return h({mutationFn:r=>c(`/v1/keys/${encodeURIComponent(r)}`,{method:"DELETE"}),onSuccess:()=>void e.invalidateQueries({queryKey:[A]})})}const V=1e3,dt=100;async function mt(){const e=[];for(let r=0;rc(`/v1/budgets/${encodeURIComponent(e)}/reset-logs`),enabled:e!==null,staleTime:6e4})}function Dr(){const e=y();return h({mutationFn:r=>c("/v1/budgets",{method:"POST",body:JSON.stringify(r)}),onSuccess:()=>void e.invalidateQueries({queryKey:[q]})})}function Or(){const e=y();return h({mutationFn:({id:r,body:n})=>c(`/v1/budgets/${encodeURIComponent(r)}`,{method:"PATCH",body:JSON.stringify(n)}),onSuccess:()=>void e.invalidateQueries({queryKey:[q]})})}function Mr(){const e=y();return h({mutationFn:r=>c(`/v1/budgets/${encodeURIComponent(r)}`,{method:"DELETE"}),onSuccess:()=>void e.invalidateQueries({queryKey:[q]})})}const W=1e3,ft=100;async function ht(){const e=[];for(let r=0;rc("/v1/users",{method:"POST",body:JSON.stringify(r)}),onSuccess:()=>se(e)})}function Kr(){const e=y();return h({mutationFn:({id:r,body:n})=>c(`/v1/users/${encodeURIComponent(r)}`,{method:"PATCH",body:JSON.stringify(n)}),onSuccess:()=>se(e)})}function Br(){const e=y();return h({mutationFn:r=>c(`/v1/users/${encodeURIComponent(r)}`,{method:"DELETE"}),onSuccess:()=>{se(e),e.invalidateQueries({queryKey:[A]})}})}function ae(e){const r=new URLSearchParams;return e.start_date&&r.set("start_date",e.start_date),e.end_date&&r.set("end_date",e.end_date),e.status&&r.set("status",e.status),e.model&&r.set("model",e.model),e.endpoint&&r.set("endpoint",e.endpoint),e.user_id&&r.set("user_id",e.user_id),e.api_key_id&&r.set("api_key_id",e.api_key_id),e.source&&r.set("source",e.source),e.priced!==void 0&&r.set("priced",String(e.priced)),e.counts_toward_budget!==void 0&&r.set("counts_toward_budget",String(e.counts_toward_budget)),r}function $r(e,r,n){return g({queryKey:[O,"list",e,r,n],queryFn:()=>{const s=ae(e);return s.set("skip",String(r*n)),s.set("limit",String(n)),c(`/v1/usage?${s.toString()}`)},placeholderData:X,staleTime:1e4})}function zr(e,r=!0){return g({queryKey:[O,"count",e],queryFn:()=>c(`/v1/usage/count?${ae(e).toString()}`),enabled:r,placeholderData:X,staleTime:1e4})}function Qr(){const e=y();return h({mutationFn:r=>c("/v1/usage",{method:"DELETE",body:JSON.stringify(r)}),onSuccess:()=>{e.invalidateQueries({queryKey:[O]})}})}function Vr(){const e=y();return h({mutationFn:r=>c("/v1/usage/set-price",{method:"POST",body:JSON.stringify(r)}),onSuccess:()=>{e.invalidateQueries({queryKey:[O]})}})}function Wr(e,r,n=!0){return g({queryKey:[O,"summary",e,r],queryFn:()=>{const s=ae(e);return s.set("bucket",r),c(`/v1/usage/summary?${s.toString()}`)},enabled:n,placeholderData:X,staleTime:3e4})}function Hr(e){return e==null?"0":new Intl.NumberFormat("en-US").format(e)}function Gr(e){if(e==null)return"$0.00";const r=e!==0&&Math.abs(e)<.01?4:2;return new Intl.NumberFormat("en-US",{style:"currency",currency:"USD",minimumFractionDigits:2,maximumFractionDigits:r}).format(e)}function Jr(e){if(e==null)return"—";if(e>=1e6){const r=e/1e6;return`${Number.isInteger(r)?r:r.toFixed(1)}M`}if(e>=1e3){const r=Math.round(e/1e3);return r>=1e3?"1M":`${r}K`}return String(e)}const xt=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];function Yr(e){if(!e)return"—";const r=/^(\d{4})-(\d{2})/.exec(e);if(!r)return e;const n=Number(r[2])-1;return n<0||n>11?r[1]:`${xt[n]} ${r[1]}`}const vt=new Intl.NumberFormat("en-US",{style:"currency",currency:"USD",maximumFractionDigits:2});function Xr(e){return vt.format(e)}function Zr(e){return e>=1e6?`${(e/1e6).toFixed(1)}M`:e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e)}function yt(e){return`${(e*100).toFixed(1)}%`}function en(e,r){return r===void 0||r===0?null:(e-r)/r}function pt(e,r=Date.now()){if(!e)return"never";const n=new Date(e);if(Number.isNaN(n.getTime()))return e;const s=Math.round((r-n.getTime())/1e3),i=s<0,o=Math.abs(s),d=[["second",60],["minute",60],["hour",24],["day",30],["month",12],["year",Number.POSITIVE_INFINITY]];let m=o,p="second";for(const[f,b]of d){if(p=f,m0?"▲":e<0?"▼":"•";return t.jsxs("span",{className:"text-[var(--otari-muted)]",children:[r," ",yt(Math.abs(e))," vs prev"]})}function gt(e){return e instanceof T||e instanceof Error?e.message:"Something went wrong."}function bt({error:e}){return e?t.jsx("div",{role:"alert",className:"rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700",children:gt(e)}):null}function jt({tone:e="info",children:r}){const n=e==="warning"?"border-amber-200 bg-amber-50 text-amber-800":"border-[var(--otari-brand)] bg-[var(--otari-brand-tint)] text-[var(--otari-brand-dark)]";return t.jsx("div",{className:`rounded-lg border px-4 py-3 text-sm ${n}`,children:r})}function nn({title:e,description:r,action:n}){return t.jsxs("div",{className:"flex flex-col gap-3",children:[t.jsxs("div",{children:[t.jsx("h1",{className:"text-xl font-semibold text-[var(--otari-ink)]",children:e}),r?t.jsx("p",{className:"mt-1 text-sm text-[var(--otari-muted)]",children:r}):null]}),n?t.jsx("div",{className:"flex flex-wrap gap-2",children:n}):null]})}function wt(e){const[r,n]=a.useState(()=>Date.now());return a.useEffect(()=>{let s;const i=()=>{s===void 0&&(s=setInterval(()=>n(Date.now()),e))},o=()=>{s!==void 0&&(clearInterval(s),s=void 0)},d=()=>{n(Date.now()),document.visibilityState==="visible"?i():o()};return d(),document.addEventListener("visibilitychange",d),()=>{o(),document.removeEventListener("visibilitychange",d)}},[e]),r}function sn({onRefresh:e,isFetching:r=!1,updatedAt:n,label:s="Refresh"}){const i=wt(15e3),o=n?pt(new Date(n).toISOString(),i):null;return t.jsxs("span",{className:"inline-flex items-center gap-2",children:[o?t.jsxs("span",{className:"text-xs text-[var(--otari-muted)]",children:["Updated ",o]}):null,t.jsx(C,{variant:"outline",size:"sm",isIconOnly:!0,isDisabled:r,onPress:e,"aria-label":s,children:t.jsxs("svg",{viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",className:`h-4 w-4 ${r?"animate-spin":""}`,"aria-hidden":"true",children:[t.jsx("path",{d:"M20 11a8 8 0 1 0-.5 4",strokeLinecap:"round",strokeLinejoin:"round"}),t.jsx("path",{d:"M20 4v5h-5",strokeLinecap:"round",strokeLinejoin:"round"})]})})]})}function an({title:e,description:r,actionLabel:n,onAction:s,isActionDisabled:i,children:o}){return t.jsx(I,{children:t.jsxs(I.Content,{className:"flex flex-col gap-4 p-6",children:[t.jsxs("div",{children:[t.jsx("h2",{className:"text-lg font-semibold text-[var(--otari-ink)]",children:e}),r?t.jsx("p",{className:"mt-1 text-sm text-[var(--otari-muted)]",children:r}):null]}),o,n&&s?t.jsx("div",{children:t.jsx(C,{variant:"primary",isDisabled:i,onPress:s,children:n})}):null]})})}function on({label:e="Loading…"}){return t.jsxs("div",{role:"status",className:"flex items-center justify-center gap-2 px-4 py-10 text-sm text-[var(--otari-muted)]",children:[t.jsx(Be,{size:"sm"}),t.jsx("span",{children:e})]})}function ln({children:e,confirmLabel:r,onConfirm:n,isPending:s}){const[i,o]=a.useState(!1);return i?t.jsxs("span",{className:"inline-flex items-center gap-1",children:[t.jsx(C,{size:"sm",variant:"danger",isDisabled:s,onPress:n,children:r}),t.jsx(C,{size:"sm",variant:"ghost",isDisabled:s,onPress:()=>o(!1),children:"Cancel"})]}):t.jsx(C,{size:"sm",variant:"danger-soft",onPress:()=>o(!0),children:e})}const St="rounded-lg border border-[var(--otari-line)] bg-[var(--otari-bg)] px-3 py-2 text-sm text-[var(--otari-ink)] focus:border-[var(--otari-brand)] focus:outline-none";function cn({id:e,label:r,ariaLabel:n,value:s,onChange:i,options:o,children:d,disabled:m}){const p=a.useId(),x=e??(r?p:void 0),f=t.jsx("select",{id:x,"aria-label":r?void 0:n,value:s,disabled:m,onChange:b=>i(b.target.value),className:St,children:o?o.map(b=>t.jsx("option",{value:b.value,children:b.label},b.value)):d});return r?t.jsxs("div",{className:"flex flex-col gap-1",children:[t.jsx("label",{htmlFor:x,className:"text-xs font-medium text-[var(--otari-muted)]",children:r}),f]}):f}function un({label:e,value:r,onChange:n,options:s,placeholder:i,maxVisible:o=50,allowsCustom:d=!1}){const m=u=>{var N;return((N=s.find(R=>R.value===u))==null?void 0:N.label)??u},[p,x]=a.useState(()=>m(r));a.useEffect(()=>{x(m(r))},[r]);const f=p.trim().toLowerCase(),b=s.filter(u=>!f||u.value.toLowerCase().includes(f)||u.label.toLowerCase().includes(f)).slice(0,o);return t.jsxs(M.Root,{allowsEmptyCollection:!0,allowsCustomValue:d,menuTrigger:"focus",inputValue:p,onInputChange:u=>{x(u),d?n(u.trim()):u.trim()===""&&n("")},onSelectionChange:u=>{u!=null&&n(String(u))},className:"flex flex-col gap-1",children:[t.jsx(me,{className:"text-xs font-medium text-[var(--otari-muted)]",children:e}),t.jsxs(M.InputGroup,{children:[t.jsx(fe,{placeholder:i,autoComplete:"off",onFocus:u=>u.currentTarget.select()}),t.jsx(M.Trigger,{})]}),t.jsx(M.Popover,{children:t.jsx(Ue,{items:b,className:"max-h-72 overflow-auto",children:u=>t.jsx(Ke,{id:u.value,textValue:u.label,children:u.label})})})]})}function kt(){var o;const e=at(),r=it(),[n,s]=a.useState(!1);return!(((o=e.data)==null?void 0:o.require_pricing)===!0&&e.data.default_pricing===!1)||n?null:t.jsx("div",{className:"shrink-0 px-6 pt-3",children:t.jsx(jt,{tone:"warning",children:t.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[t.jsxs("span",{children:["Requests are rejected until pricing is set (",t.jsx("code",{children:"require_pricing"})," is on). Enable default pricing to meter new models with public rates right away."]}),t.jsxs("span",{className:"flex items-center gap-2",children:[t.jsx(C,{size:"sm",variant:"primary",isDisabled:r.isPending,onPress:()=>r.mutate({default_pricing:!0}),children:r.isPending?"Enabling…":"Enable default pricing"}),t.jsx(C,{size:"sm",variant:"ghost",onPress:()=>s(!0),children:"Dismiss"})]})]})})})}function Et(){const{data:e}=st(),r=a.useRef(null);return e&&r.current===null&&(r.current=e.build),e!=null&&r.current!=null&&e.build!==r.current}function Pt(){const e=Et(),[r,n]=a.useState(!1);return!e||r?null:t.jsx("div",{className:"pointer-events-none absolute inset-x-0 top-0 z-50 flex justify-center",children:t.jsxs("div",{role:"status",className:"pointer-events-auto mt-1.5 flex items-center gap-3 rounded-full border border-[var(--otari-brand)] bg-[var(--otari-brand-tint)] py-1.5 pr-1.5 pl-4 text-sm text-[var(--otari-brand-dark)] shadow-md",children:[t.jsxs("span",{children:[t.jsx("strong",{className:"font-semibold",children:"An update is available."})," Reloading keeps you signed in."]}),t.jsx(C,{size:"sm",variant:"primary",onPress:()=>window.location.reload(),children:"Update now"}),t.jsx(C,{size:"sm",variant:"ghost",onPress:()=>n(!0),children:"Later"})]})})}const ge=200,be=480,H=240,Nt=60,je="otari.dashboard.sidebarWidth",we="otari.dashboard.sidebarCollapsed",de=16,Se="(max-width: 767px)",U=e=>Math.min(be,Math.max(ge,e));function Ct(){return typeof window>"u"||typeof window.matchMedia!="function"?!1:window.matchMedia(Se).matches}const _t='a[href], button:not([disabled]), [tabindex]:not([tabindex="-1"])';function Tt(e){return e?Array.from(e.querySelectorAll(_t)).filter(r=>r.offsetParent!==null||r===document.activeElement):[]}function Lt(){if(typeof window>"u")return H;try{const e=window.localStorage.getItem(je),r=e?Number.parseInt(e,10):Number.NaN;return Number.isNaN(r)?H:U(r)}catch{return H}}function It(){if(typeof window>"u")return!1;try{return window.localStorage.getItem(we)==="1"}catch{return!1}}const At=[{key:"home"},{key:"observability",label:"Observability"},{key:"catalog",label:"Catalog"},{key:"access",label:"Access"},{key:"system"}],qt=[{to:"/",section:"home",label:"Overview",end:!0,icon:t.jsxs("svg",{"aria-hidden":!0,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",className:"h-5 w-5 shrink-0",children:[t.jsx("rect",{x:"3.5",y:"3.5",width:"7",height:"7",rx:"1.5",strokeLinejoin:"round"}),t.jsx("rect",{x:"13.5",y:"3.5",width:"7",height:"7",rx:"1.5",strokeLinejoin:"round"}),t.jsx("rect",{x:"3.5",y:"13.5",width:"7",height:"7",rx:"1.5",strokeLinejoin:"round"}),t.jsx("rect",{x:"13.5",y:"13.5",width:"7",height:"7",rx:"1.5",strokeLinejoin:"round"})]})},{to:"/activity",section:"observability",label:"Activity",icon:t.jsx("svg",{"aria-hidden":!0,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",className:"h-5 w-5 shrink-0",children:t.jsx("path",{d:"M3 12h4l2.5-6 4 12 2.5-6H21",strokeLinecap:"round",strokeLinejoin:"round"})})},{to:"/usage",section:"observability",label:"Usage",icon:t.jsx("svg",{"aria-hidden":!0,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",className:"h-5 w-5 shrink-0",children:t.jsx("path",{d:"M4 20V10M10 20V4M16 20v-7M22 20H2",strokeLinecap:"round",strokeLinejoin:"round"})})},{to:"/providers",section:"catalog",label:"Providers",icon:t.jsxs("svg",{"aria-hidden":!0,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",className:"h-5 w-5 shrink-0",children:[t.jsx("rect",{x:"3.5",y:"4.5",width:"17",height:"6",rx:"1.5",strokeLinejoin:"round"}),t.jsx("rect",{x:"3.5",y:"13.5",width:"17",height:"6",rx:"1.5",strokeLinejoin:"round"}),t.jsx("path",{d:"M7 7.5h.01M7 16.5h.01",strokeLinecap:"round",strokeLinejoin:"round"})]})},{to:"/users",section:"access",label:"Users",icon:t.jsxs("svg",{"aria-hidden":!0,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",className:"h-5 w-5 shrink-0",children:[t.jsx("circle",{cx:"9",cy:"8",r:"3.2",strokeLinejoin:"round"}),t.jsx("path",{d:"M3.5 19a5.5 5.5 0 0 1 11 0",strokeLinecap:"round",strokeLinejoin:"round"}),t.jsx("path",{d:"M16 5.2a3.2 3.2 0 0 1 0 5.6M17.5 19a5.5 5.5 0 0 0-3-4.9",strokeLinecap:"round",strokeLinejoin:"round"})]})},{to:"/keys",section:"access",label:"API keys",icon:t.jsxs("svg",{"aria-hidden":!0,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",className:"h-5 w-5 shrink-0",children:[t.jsx("circle",{cx:"7.5",cy:"15.5",r:"3.5"}),t.jsx("path",{d:"M10 13l7-7M14 5l3 3M16.5 7.5l2-2",strokeLinecap:"round",strokeLinejoin:"round"})]})},{to:"/budgets",section:"access",label:"Budgets",icon:t.jsxs("svg",{"aria-hidden":!0,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",className:"h-5 w-5 shrink-0",children:[t.jsx("path",{d:"M3 7.5A1.5 1.5 0 0 1 4.5 6H18a1.5 1.5 0 0 1 1.5 1.5V9",strokeLinejoin:"round"}),t.jsx("rect",{x:"3",y:"7.5",width:"18",height:"12",rx:"1.5",strokeLinejoin:"round"}),t.jsx("path",{d:"M16 13.5h.01",strokeLinecap:"round",strokeLinejoin:"round"}),t.jsx("path",{d:"M21 12v3h-3.5a1.5 1.5 0 0 1 0-3H21z",strokeLinejoin:"round"})]})},{to:"/models",section:"catalog",label:"Models",icon:t.jsxs("svg",{"aria-hidden":!0,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",className:"h-5 w-5 shrink-0",children:[t.jsx("path",{d:"M12 3l8 4.5v9L12 21l-8-4.5v-9L12 3z",strokeLinejoin:"round"}),t.jsx("path",{d:"M12 12l8-4.5M12 12v9M12 12L4 7.5",strokeLinejoin:"round"})]})},{to:"/aliases",section:"catalog",label:"Aliases",icon:t.jsxs("svg",{"aria-hidden":!0,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",className:"h-5 w-5 shrink-0",children:[t.jsx("path",{d:"M20.6 13.4L13.4 20.6a2 2 0 0 1-2.8 0l-7-7A2 2 0 0 1 3 12.2V5a2 2 0 0 1 2-2h7.2a2 2 0 0 1 1.4.6l7 7a2 2 0 0 1 0 2.8z",strokeLinejoin:"round"}),t.jsx("circle",{cx:"7.5",cy:"7.5",r:"1.5"})]})},{to:"/tools",section:"system",label:"Tools & Guardrails",icon:t.jsxs("svg",{"aria-hidden":!0,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",className:"h-5 w-5 shrink-0",children:[t.jsx("path",{d:"M14.7 6.3a4 4 0 0 1 5 5l-8.4 8.4a2 2 0 0 1-2.8 0l-2.2-2.2a2 2 0 0 1 0-2.8z",strokeLinejoin:"round"}),t.jsx("path",{d:"M12 9 5 16",strokeLinecap:"round"})]})},{to:"/settings",section:"system",label:"Settings",icon:t.jsxs("svg",{"aria-hidden":!0,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",className:"h-5 w-5 shrink-0",children:[t.jsx("circle",{cx:"12",cy:"12",r:"3"}),t.jsx("path",{d:"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z",strokeLinejoin:"round"})]})}];function Rt(){const{logout:e}=Z(),r=a.useRef(null),n=a.useRef(null),s=a.useRef(null),[i,o]=a.useState(Lt),[d,m]=a.useState(It),[p,x]=a.useState(!1),[f,b]=a.useState(Ct),[u,N]=a.useState(!1);a.useEffect(()=>{if(typeof window>"u"||typeof window.matchMedia!="function")return;const l=window.matchMedia(Se),v=j=>{b(j.matches),j.matches||N(!1)};return typeof l.addEventListener=="function"?(l.addEventListener("change",v),()=>l.removeEventListener("change",v)):(l.addListener(v),()=>l.removeListener(v))},[]),a.useEffect(()=>{if(!u)return;const l=v=>{v.key==="Escape"&&N(!1)};return window.addEventListener("keydown",l),()=>window.removeEventListener("keydown",l)},[u]),a.useEffect(()=>{var l,v,j;f&&(u?(l=r.current)==null||l.focus():(v=r.current)!=null&&v.contains(document.activeElement)&&((j=s.current)==null||j.focus()))},[f,u]);const R=a.useCallback(l=>{if(l.key!=="Tab")return;const v=Tt(r.current);if(v.length===0)return;const j=v[0],k=v[v.length-1],D=document.activeElement;l.shiftKey&&(D===j||D===r.current)?(l.preventDefault(),k.focus()):!l.shiftKey&&D===k&&(l.preventDefault(),j.focus())},[]);a.useEffect(()=>{const l=window.setTimeout(()=>{try{window.localStorage.setItem(je,String(Math.round(i)))}catch{}},200);return()=>window.clearTimeout(l)},[i]),a.useEffect(()=>{try{window.localStorage.setItem(we,d?"1":"0")}catch{}},[d]);const Ee=a.useCallback(l=>{l.preventDefault(),l.currentTarget.setPointerCapture(l.pointerId),x(!0)},[]),Pe=a.useCallback(l=>{var j;if(!l.currentTarget.hasPointerCapture(l.pointerId))return;const v=((j=r.current)==null?void 0:j.getBoundingClientRect().left)??0;o(U(l.clientX-v))},[]),Ne=a.useCallback(l=>{l.currentTarget.hasPointerCapture(l.pointerId)&&l.currentTarget.releasePointerCapture(l.pointerId),x(!1)},[]),Ce=a.useCallback(l=>{var v;l.preventDefault(),(v=n.current)==null||v.focus()},[]),_e=a.useCallback(l=>{l.key==="ArrowLeft"?(l.preventDefault(),o(v=>U(v-de))):l.key==="ArrowRight"&&(l.preventDefault(),o(v=>U(v+de)))},[]),Te=d?Nt:i,S=f?!1:d,$=f&&u?!0:void 0;return t.jsxs("div",{className:_("relative flex h-full flex-col overflow-hidden",p&&"cursor-col-resize select-none"),children:[t.jsx("button",{type:"button",inert:$,onClick:Ce,className:"sr-only focus:not-sr-only focus:absolute focus:top-3 focus:left-3 focus:z-50 focus:rounded-lg focus:border focus:border-[var(--otari-brand)] focus:bg-[var(--otari-surface)] focus:px-4 focus:py-2 focus:text-sm focus:font-medium focus:text-[var(--otari-brand-dark)] focus:shadow-md focus:outline-none",children:"Skip to main content"}),t.jsxs("header",{inert:$,className:"flex shrink-0 items-center justify-between border-b border-[var(--otari-line)] bg-[var(--otari-surface)] px-5 py-3",children:[t.jsxs("div",{className:"flex items-center gap-2.5",children:[t.jsx("button",{type:"button",ref:s,onClick:()=>N(l=>!l),"aria-label":u?"Close navigation":"Open navigation","aria-expanded":u,"aria-controls":"app-sidebar",className:"-ml-1 flex h-8 w-8 items-center justify-center rounded-lg text-[var(--otari-muted)] transition-colors hover:bg-[var(--otari-bg)] hover:text-[var(--otari-ink)] md:hidden",children:t.jsx("svg",{"aria-hidden":!0,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",className:"h-5 w-5",children:t.jsx("path",{d:"M4 6h16M4 12h16M4 18h16",strokeLinecap:"round",strokeLinejoin:"round"})})}),t.jsx("img",{src:"/favicon.svg",alt:"",className:"h-7 w-7 shrink-0"}),t.jsx("span",{className:"text-base font-semibold text-[var(--otari-ink)]",children:"Otari"})]}),t.jsx(C,{size:"sm",variant:"outline",onPress:e,"aria-label":"Sign out",children:"Sign out"})]}),t.jsx(Pt,{}),t.jsx(et,{}),t.jsx(kt,{}),t.jsxs("div",{className:"flex min-h-0 flex-1",children:[f&&u?t.jsx("div",{"aria-hidden":"true",onClick:()=>N(!1),className:"fixed inset-0 z-30 bg-black/40 md:hidden"}):null,t.jsxs("aside",{ref:r,id:"app-sidebar",role:f?"dialog":void 0,"aria-modal":f&&u?!0:void 0,"aria-label":f?"Navigation":void 0,tabIndex:f?-1:void 0,inert:f&&!u?!0:void 0,onKeyDown:f&&u?R:void 0,style:f?void 0:{width:Te},className:_("flex flex-col border-r border-[var(--otari-line)] bg-[var(--otari-surface)] focus:outline-none",f?_("fixed inset-y-0 left-0 z-40 w-[17rem] shadow-xl transition-transform duration-200",u?"translate-x-0":"-translate-x-full"):_("relative shrink-0",!p&&"transition-[width] duration-150")),children:[t.jsx("button",{type:"button",onClick:()=>m(l=>!l),"aria-label":d?"Expand sidebar":"Collapse sidebar","aria-pressed":d,title:d?"Expand sidebar":"Collapse sidebar",className:"absolute -right-3 top-4 z-30 hidden h-6 w-6 items-center justify-center rounded-full border border-[var(--otari-line)] bg-[var(--otari-surface)] text-[var(--otari-muted)] shadow-sm transition-colors hover:border-[var(--otari-brand)] hover:text-[var(--otari-brand-dark)] md:flex",children:t.jsx("svg",{"aria-hidden":!0,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2.5",className:_("h-3.5 w-3.5 transition-transform",d&&"rotate-180"),children:t.jsx("path",{d:"M15 6l-6 6 6 6",strokeLinecap:"round",strokeLinejoin:"round"})})}),t.jsx("nav",{className:_("flex flex-col py-4",S?"px-2":"px-3"),children:At.map((l,v)=>{const j=qt.filter(k=>k.section===l.key);return j.length===0?null:t.jsxs("div",{className:v>0?"mt-4":void 0,children:[!S&&l.label?t.jsx("div",{className:"px-3 pb-1 text-[11px] font-semibold tracking-wider text-[var(--otari-muted)] uppercase",children:l.label}):null,v>0&&(S||!l.label)?t.jsx("div",{className:"mx-1 mb-2 border-t border-[var(--otari-line)]"}):null,t.jsx("div",{className:"flex flex-col gap-1",children:j.map(k=>t.jsxs(G,{to:k.to,end:k.end,onClick:()=>N(!1),"aria-label":S?k.label:void 0,title:S?k.label:void 0,className:({isActive:D})=>_("flex items-center rounded-lg py-2 text-sm font-medium transition-colors",S?"justify-center px-0":"gap-3 px-3",D?"bg-[var(--otari-brand-tint)] text-[var(--otari-brand-dark)]":"text-[var(--otari-muted)] hover:bg-[var(--otari-bg)] hover:text-[var(--otari-ink)]"),children:[k.icon,S?null:k.label]},k.to))})]},l.key)})}),t.jsxs("div",{className:"mt-auto flex flex-col gap-1 pb-3",children:[t.jsxs(G,{to:"/docs",onClick:()=>N(!1),"aria-label":S?"User guide":void 0,title:S?"User guide":void 0,className:({isActive:l})=>_("flex items-center rounded-lg py-2 text-sm font-medium transition-colors",S?"mx-2 justify-center px-0":"mx-3 gap-3 px-3",l?"bg-[var(--otari-brand-tint)] text-[var(--otari-brand-dark)]":"text-[var(--otari-muted)] hover:bg-[var(--otari-bg)] hover:text-[var(--otari-ink)]"),children:[t.jsxs("svg",{"aria-hidden":"true",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",className:"h-5 w-5 shrink-0",children:[t.jsx("path",{d:"M12 6.5C10.5 5 8 4.5 4 4.5V18c4 0 6.5.5 8 2 1.5-1.5 4-2 8-2V4.5c-4 0-6.5.5-8 2z",strokeLinejoin:"round"}),t.jsx("path",{d:"M12 6.5V20",strokeLinecap:"round"})]}),S?null:"User guide"]}),t.jsxs("a",{href:"https://otari.ai",target:"_blank",rel:"noreferrer",title:"otari.ai: the hosted Otari gateway",className:_("flex items-center rounded-lg py-2 text-xs font-medium text-[var(--otari-muted)] transition-colors hover:bg-[var(--otari-bg)] hover:text-[var(--otari-brand-dark)]",S?"mx-2 justify-center px-0":"mx-3 gap-2 px-3"),children:[t.jsx("svg",{"aria-hidden":!0,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",className:"h-4 w-4 shrink-0",children:t.jsx("path",{d:"M18 10h-1.26A8 8 0 1 0 9 20h9a5 5 0 0 0 0-10z",strokeLinejoin:"round"})}),S?null:t.jsxs("span",{className:"flex-1",children:["otari.ai ",t.jsx("span",{"aria-hidden":!0,children:"↗"})]})]})]}),d||f?null:t.jsx("div",{role:"separator","aria-orientation":"vertical","aria-label":"Resize sidebar","aria-valuenow":Math.round(i),"aria-valuemin":ge,"aria-valuemax":be,tabIndex:0,onPointerDown:Ee,onPointerMove:Pe,onPointerUp:Ne,onKeyDown:_e,className:_("absolute top-0 right-0 z-10 h-full w-1.5 cursor-col-resize touch-none transition-colors","hover:bg-[var(--otari-brand)] focus-visible:bg-[var(--otari-brand)] focus:outline-none",p?"bg-[var(--otari-brand)]":"bg-transparent")})]}),t.jsx("main",{ref:n,id:"main-content",tabIndex:-1,inert:$,className:"flex-1 overflow-y-auto focus:outline-none",children:t.jsx("div",{className:"mx-auto flex max-w-[1800px] flex-col gap-6 px-4 py-5 md:px-6 md:py-6",children:t.jsx(De,{})})})]})]})}function Dt(){const{login:e}=Z(),[r,n]=a.useState(""),[s,i]=a.useState(null),[o,d]=a.useState(!1),m=async()=>{const p=r.trim();if(!(!p||o)){d(!0),i(null);try{await He(p)?e():i(new Error("Invalid master key."))}catch(x){i(x)}finally{d(!1)}}};return t.jsx("div",{className:"flex min-h-full items-center justify-center p-6",children:t.jsx(I,{className:"w-full max-w-md",children:t.jsxs(I.Content,{className:"flex flex-col gap-5 p-7",children:[t.jsxs("div",{className:"flex flex-col items-center gap-3 text-center",children:[t.jsx("img",{src:"/favicon.svg",alt:"Otari",className:"h-12 w-12"}),t.jsxs("div",{children:[t.jsx("h1",{className:"text-lg font-semibold text-[var(--otari-ink)]",children:"Otari Dashboard"}),t.jsx("p",{className:"mt-1 text-sm text-[var(--otari-muted)]",children:"Sign in with your master key to browse models, set pricing, and manage settings."})]})]}),t.jsxs("form",{className:"flex flex-col gap-4",onSubmit:p=>{p.preventDefault(),m()},children:[t.jsxs($e,{value:r,onChange:p=>{n(p),s&&i(null)},type:"password",isRequired:!0,className:"flex flex-col gap-1",children:[t.jsx(me,{className:"text-sm font-medium text-[var(--otari-ink)]",children:"Master key"}),t.jsx(fe,{placeholder:"otari-mk-… or your master key",autoFocus:!0,autoComplete:"off"})]}),t.jsxs("details",{className:"text-xs text-[var(--otari-muted)]",children:[t.jsx("summary",{className:"cursor-pointer font-medium text-[var(--otari-brand-dark)]",children:"First run? Where to find your key"}),t.jsxs("p",{className:"mt-2 leading-relaxed",children:["If you did not set ",t.jsx("code",{children:"OTARI_MASTER_KEY"}),", Otari generated one and printed it to the server logs on startup. Look for the line ",t.jsx("code",{children:"Your master key:"})," (for example, run"," ",t.jsx("code",{children:"docker logs "}),") and paste it above."]})]}),t.jsx(bt,{error:s}),t.jsx(C,{type:"submit",variant:"primary",fullWidth:!0,isDisabled:!r.trim()||o,children:o?"Signing in…":"Sign in"})]}),t.jsx("p",{className:"text-center text-xs text-[var(--otari-muted)]",children:"The key is sent once to this gateway and exchanged for a session cookie; it is never stored in the browser."}),t.jsx("div",{className:"border-t border-[var(--otari-line)] pt-4 text-center",children:t.jsx(ze,{href:"/welcome",className:"text-sm font-medium text-[var(--otari-brand-dark)]",children:"New to Otari? Open the welcome guide"})})]})})})}const Ot=a.lazy(async()=>({default:(await P(async()=>{const{ActivityPage:e}=await import("./ActivityPage-DsPiQv1J.js");return{ActivityPage:e}},__vite__mapDeps([0,1,2,3,4,5,6,7,8,9]))).ActivityPage})),Mt=a.lazy(async()=>({default:(await P(async()=>{const{AliasesPage:e}=await import("./AliasesPage-BTmc50Jm.js");return{AliasesPage:e}},__vite__mapDeps([10,1,2,6,4,7,8,11,12]))).AliasesPage})),Ft=a.lazy(async()=>({default:(await P(async()=>{const{BudgetsPage:e}=await import("./BudgetsPage-hf0SYw2U.js");return{BudgetsPage:e}},__vite__mapDeps([13,1,2,6,4,7,8,11]))).BudgetsPage})),Ut=a.lazy(async()=>({default:(await P(async()=>{const{DocsPage:e}=await import("./DocsPage-CUNhOocN.js");return{DocsPage:e}},__vite__mapDeps([14,1,2,4]))).DocsPage})),Kt=a.lazy(async()=>({default:(await P(async()=>{const{KeysPage:e}=await import("./KeysPage-Dnb7jGCb.js");return{KeysPage:e}},__vite__mapDeps([15,1,2,6,4,7,8,11,16,12]))).KeysPage})),Bt=a.lazy(async()=>({default:(await P(async()=>{const{ModelsPage:e}=await import("./ModelsPage-BMeU3W4u.js");return{ModelsPage:e}},__vite__mapDeps([17,1,2,6,4,8,9]))).ModelsPage})),$t=a.lazy(async()=>({default:(await P(async()=>{const{OverviewIndex:e}=await import("./OverviewPage-CW42wjoO.js");return{OverviewIndex:e}},__vite__mapDeps([18,1,2,19,5,4,8]))).OverviewIndex})),zt=a.lazy(async()=>({default:(await P(async()=>{const{ProvidersPage:e}=await import("./ProvidersPage-D2tIyvqh.js");return{ProvidersPage:e}},__vite__mapDeps([20,1,2,11,4,8]))).ProvidersPage})),Qt=a.lazy(async()=>({default:(await P(async()=>{const{SettingsPage:e}=await import("./SettingsPage-k4BcKpbT.js");return{SettingsPage:e}},__vite__mapDeps([21,1,2,4]))).SettingsPage})),Vt=a.lazy(async()=>({default:(await P(async()=>{const{ToolsGuardrailsPage:e}=await import("./ToolsGuardrailsPage-Cl0epDLn.js");return{ToolsGuardrailsPage:e}},__vite__mapDeps([22,1,2,4]))).ToolsGuardrailsPage})),Wt=a.lazy(async()=>({default:(await P(async()=>{const{UsagePage:e}=await import("./UsagePage-B6Ow1D4j.js");return{UsagePage:e}},__vite__mapDeps([23,1,2,3,4,5,6,19,7,8,9]))).UsagePage})),Ht=a.lazy(async()=>({default:(await P(async()=>{const{UsersPage:e}=await import("./UsersPage-d3EPlBj3.js");return{UsersPage:e}},__vite__mapDeps([24,1,2,6,4,7,8,11,16]))).UsersPage}));function E(e){return t.jsx(a.Suspense,{fallback:t.jsx("div",{role:"status",children:"Loading page…"}),children:e})}function Gt(){const{isAuthenticated:e}=Z();return e?t.jsx(Oe,{children:t.jsx(Me,{children:t.jsxs(w,{element:t.jsx(Rt,{}),children:[t.jsx(w,{index:!0,element:E(t.jsx($t,{}))}),t.jsx(w,{path:"providers",element:E(t.jsx(zt,{}))}),t.jsx(w,{path:"keys",element:E(t.jsx(Kt,{}))}),t.jsx(w,{path:"users",element:E(t.jsx(Ht,{}))}),t.jsx(w,{path:"budgets",element:E(t.jsx(Ft,{}))}),t.jsx(w,{path:"activity",element:E(t.jsx(Ot,{}))}),t.jsx(w,{path:"usage",element:E(t.jsx(Wt,{}))}),t.jsx(w,{path:"models",element:E(t.jsx(Bt,{}))}),t.jsx(w,{path:"aliases",element:E(t.jsx(Mt,{}))}),t.jsx(w,{path:"tools",element:E(t.jsx(Vt,{}))}),t.jsx(w,{path:"settings",element:E(t.jsx(Qt,{}))}),t.jsx(w,{path:"docs",element:E(t.jsx(Ut,{}))}),t.jsx(w,{path:"*",element:t.jsx(Fe,{to:"/",replace:!0})})]})})}):t.jsx(Dt,{})}function Jt({children:e}){const[r]=a.useState(()=>new Ae({defaultOptions:{queries:{refetchOnWindowFocus:!1,retry:(n,s)=>s instanceof T&&(s.status===401||s.status===403)?!1:n<2}}}));return t.jsx(qe,{client:r,children:t.jsx(Ye,{children:e})})}const ke=document.getElementById("root");if(!ke)throw new Error("Root element #root not found");Qe.createRoot(ke).render(t.jsx(a.StrictMode,{children:t.jsx(Jt,{children:t.jsx(Gt,{})})}));export{ur as $,kr as A,Jr as B,ln as C,Er as D,bt as E,cn as F,gt as G,Yr as H,jt as I,at as J,Gr as K,nr as L,on as M,ir as N,en as O,nn as P,Xr as Q,sn as R,tn as S,rn as T,Hr as U,yt as V,pt as W,lr as X,dr as Y,fr as Z,it as _,_r as a,or as a0,cr as a1,ar as a2,sr as a3,hr as a4,Pr as a5,Nr as a6,Cr as a7,gr as a8,mr as a9,br as aa,jr as ab,wr as ac,Zr as ad,Br as ae,Ur as af,$r as b,zr as c,Wr as d,Qr as e,Vr as f,un as g,rr as h,vr as i,pr as j,yr as k,qr as l,Dr as m,Or as n,Mr as o,Kr as p,an as q,Rr as r,Lr as s,Ir as t,Fr as u,Ar as v,Tr as w,tr as x,Sr as y,xr as z}; diff --git a/src/gateway/static/dashboard/index.html b/src/gateway/static/dashboard/index.html index 37412927..5db4e6b3 100644 --- a/src/gateway/static/dashboard/index.html +++ b/src/gateway/static/dashboard/index.html @@ -19,7 +19,7 @@ insets to sit out of the way. --> Otari Dashboard - + diff --git a/tests/integration/test_require_pricing.py b/tests/integration/test_require_pricing.py index 7db92fc6..53353453 100644 --- a/tests/integration/test_require_pricing.py +++ b/tests/integration/test_require_pricing.py @@ -9,6 +9,7 @@ import asyncio from collections.abc import AsyncGenerator, Generator +from typing import Any import pytest from fastapi.testclient import TestClient @@ -85,6 +86,113 @@ def test_unpriced_model_rejected_with_402(strict_pricing_client: TestClient) -> assert _chat(strict_pricing_client, model="openai:gpt-4o", user="priced-user") == 402 +def test_missing_pricing_rejection_is_recorded_in_the_usage_log(strict_pricing_client: TestClient) -> None: + """A 402 rejection is logged as an error row so an operator can see dropped traffic. + + Regression for #317: the gate refunded the reservation and raised without + writing anything, so requests dropped for missing pricing were invisible to + every admin view (the activity log, the error rate, the pricing alarm's + count). Cost stays null: nothing was spent. + """ + c = strict_pricing_client + c.post("/v1/users", json={"user_id": "priced-user"}, headers=_MASTER_HEADER) + assert _chat(c, model="openai:gpt-4o", user="priced-user") == 402 + + rows = c.get("/v1/usage", params={"status": "error"}, headers=_MASTER_HEADER).json() + assert len(rows) == 1 + assert rows[0]["model"] == "openai:gpt-4o" + assert rows[0]["endpoint"] == "/v1/chat/completions" + assert rows[0]["user_id"] == "priced-user" + assert rows[0]["status"] == "error" + assert rows[0]["cost"] is None + assert "pricing" in rows[0]["error_message"].lower() + # Always an enforced row, never an imported-looking one: the dashboard treats + # counts_toward_budget=False as imported and offers those to bulk delete and + # set-price, which must never reach a row the gateway wrote itself. + assert rows[0]["counts_toward_budget"] is True + + # The dashboard's live "N failed in the last hour" signal reads this count. + count = c.get("/v1/usage/count", params={"status": "error"}, headers=_MASTER_HEADER).json() + assert count["total"] == 1 + # And it reads it scoped to gateway traffic, which these rows must satisfy or + # the alarm would undercount its own rejections. + scoped = c.get( + "/v1/usage/count", params={"status": "error", "source": "gateway"}, headers=_MASTER_HEADER + ).json() + assert scoped["total"] == 1 + + +def test_passthrough_missing_pricing_rejection_is_recorded_too(strict_pricing_client: TestClient) -> None: + """The pass-through gate (embeddings, images, rerank) records its 402 as well, + so the failure count covers every rejected request, not only chat.""" + c = strict_pricing_client + c.post("/v1/users", json={"user_id": "priced-user"}, headers=_MASTER_HEADER) + resp = c.post( + "/v1/embeddings", + json={"model": "openai:text-embedding-3-small", "input": "hi", "user": "priced-user"}, + headers=_MASTER_HEADER, + ) + assert resp.status_code == 402 + + rows = c.get("/v1/usage", params={"status": "error"}, headers=_MASTER_HEADER).json() + assert len(rows) == 1 + assert rows[0]["endpoint"] == "/v1/embeddings" + assert rows[0]["cost"] is None + assert rows[0]["counts_toward_budget"] is True + # The pass-through routes log the bare model with the instance in `provider`, + # where the chat pipeline logs the full `instance:model` selector. Pinned + # because the two forms render differently in the Activity log's Model column + # and the model filter matches one or the other, so the split should change + # deliberately rather than drift. + assert rows[0]["model"] == "text-embedding-3-small" + assert rows[0]["provider"] == "openai" + + +def test_budget_exempt_key_writes_no_pricing_rejection_row(strict_pricing_client: TestClient) -> None: + """A budget-exempt key skips the gate, so no missing-pricing row is written. + + The gate is guarded by ``not budget_exempt``, which is what keeps every + pricing-rejection row at counts_toward_budget=True. If a refactor let the gate + fire for an exempt key, it would start writing counts_toward_budget=False + rows, which the dashboard classifies as imported and offers up to bulk delete + and set-price. Nothing else pins that, so pin it here. + + Structured as an A/B against an enforced key rather than as a bare "no row + appeared": this fixture configures no providers, so an exempt request fails + before any provider call and logs nothing either way. Without the control, the + negative would pass even if the gate had stopped writing rows entirely. + """ + c = strict_pricing_client + c.post("/v1/users", json={"user_id": "gate-user"}, headers=_MASTER_HEADER) + + def issue_key(name: str, *, exempt: bool) -> str: + body = {"key_name": name, "user_id": "gate-user", "exclude_from_budget": exempt} + return str(c.post("/v1/keys", json=body, headers=_MASTER_HEADER).json()["key"]) + + def chat(key: str) -> int: + resp = c.post( + "/v1/chat/completions", + json={"model": "openai:gpt-4o", "messages": _MESSAGES}, + headers={API_KEY_HEADER: f"Bearer {key}"}, + ) + return int(resp.status_code) + + def pricing_rejections() -> list[dict[str, Any]]: + rows = c.get("/v1/usage", params={"status": "error"}, headers=_MASTER_HEADER).json() + return [r for r in rows if "No pricing is configured" in (r["error_message"] or "")] + + # Control: an enforced key hits the gate and leaves exactly one row, carrying + # the enforced flag. This is what makes the negative below meaningful. + assert chat(issue_key("enforced", exempt=False)) == 402 + control = pricing_rejections() + assert len(control) == 1 + assert control[0]["counts_toward_budget"] is True + + # The exempt key skips the gate, so it adds no rejection row of its own. + assert chat(issue_key("exempt", exempt=True)) != 402 + assert len(pricing_rejections()) == 1 + + def test_priced_model_passes_the_gate(strict_pricing_client: TestClient) -> None: """A priced model clears the pricing gate (no 402); any later failure is a provider error.""" strict_pricing_client.post("/v1/users", json={"user_id": "priced-user"}, headers=_MASTER_HEADER) diff --git a/web/src/api/hooks.ts b/web/src/api/hooks.ts index 7abefce3..2beb49c3 100644 --- a/web/src/api/hooks.ts +++ b/web/src/api/hooks.ts @@ -1,6 +1,7 @@ import { keepPreviousData, useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { apiFetch } from "@/api/client"; +import { isoAgo } from "@/lib/timeRange"; import type { AliasResponse, ApiKey, @@ -690,6 +691,40 @@ export function useUsageCount(filters: UsageFilters, enabled = true) { }); } +// How often the rolling failure count re-reads. A dropped-traffic signal is only +// useful if it moves while the operator watches it. +const FAILURE_COUNT_POLL_MS = 60_000; + +// Requests that failed within the last `windowSeconds`, as a live count. The +// window is resolved inside the query function, not in the key, for two reasons: +// the key stays stable (a "now"-derived key would mint a new cache entry on every +// render), and every refetch re-anchors, so a tab left open keeps reporting the +// last hour rather than quietly widening to the last hour and a half. +// +// Scoped to `source: "gateway"`: imported usage can carry status=error too (the +// external-events API accepts it), and an imported session's failures are not this +// gateway dropping traffic. Counting them would make the signal cry wolf. +export function useFailureCount(windowSeconds: number, enabled = true) { + return useQuery({ + queryKey: [USAGE, "count", "failures", windowSeconds], + queryFn: () => { + const filters: UsageFilters = { + status: "error", + source: "gateway", + start_date: isoAgo(windowSeconds), + }; + return apiFetch(`/v1/usage/count?${usageParams(filters).toString()}`); + }, + enabled, + refetchInterval: FAILURE_COUNT_POLL_MS, + refetchOnWindowFocus: true, + staleTime: 0, + // A failed count is not worth surfacing: it sits beside its own alarm, and + // the next poll retries anyway. + retry: false, + }); +} + // Delete imported usage rows by selection (ids or by_filter). Only rows the // server treats as imported (counts_toward_budget = false) are removed; every // usage view is invalidated so the list, count, and analytics refresh. diff --git a/web/src/components/PricingWarning.test.tsx b/web/src/components/PricingWarning.test.tsx index deb7e1b4..356f85ba 100644 --- a/web/src/components/PricingWarning.test.tsx +++ b/web/src/components/PricingWarning.test.tsx @@ -2,6 +2,7 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { render, screen, waitFor } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import type { ReactElement } from "react"; +import { MemoryRouter } from "react-router-dom"; import { afterEach, describe, expect, it, vi } from "vitest"; import type { GatewaySettings } from "@/api/types"; @@ -22,7 +23,7 @@ function jsonResponse(body: unknown, status = 200): Response { return new Response(JSON.stringify(body), { status, headers: { "Content-Type": "application/json" } }); } -function mockSettings(settings: GatewaySettings) { +function mockSettings(settings: GatewaySettings, rejectedInLastHour = 0) { let current = { ...settings }; return vi.spyOn(globalThis, "fetch").mockImplementation(async (input, init) => { const url = String(input); @@ -31,13 +32,30 @@ function mockSettings(settings: GatewaySettings) { if (method === "PATCH") current = { ...current, ...JSON.parse(String(init?.body)) }; return jsonResponse(current); } + if (url.includes("/v1/usage/count")) { + return jsonResponse({ total: rejectedInLastHour }); + } return jsonResponse({}); }); } +type FetchMock = ReturnType; + +// The `start_date` each /v1/usage/count request asked for, in call order. +function countWindows(fetchMock: FetchMock): string[] { + return fetchMock.mock.calls + .map(([u]) => String(u)) + .filter((u) => u.includes("/v1/usage/count")) + .map((u) => String(new URLSearchParams(u.split("?")[1]).get("start_date"))); +} + function renderPage(ui: ReactElement) { const client = new QueryClient({ defaultOptions: { queries: { retry: false } } }); - return render({ui}); + return render( + + {ui} + , + ); } describe("PricingWarning", () => { @@ -69,6 +87,73 @@ describe("PricingWarning", () => { expect(screen.queryByText(/Requests are rejected/)).not.toBeInTheDocument(); }); + it("reports how many requests failed in the last hour and links to them", async () => { + const fetchMock = mockSettings({ ...BASE, require_pricing: true, default_pricing: false }, 12); + renderPage(); + + expect(await screen.findByText("12 requests failed in the last hour.")).toBeInTheDocument(); + // The link carries the same scope as the count, so the filtered view it lands + // on reports the same number the banner just claimed. + expect(screen.getByRole("link", { name: "View failed requests" })).toHaveAttribute( + "href", + "/activity?status=error&range=1h&source=gateway", + ); + + // Counted from the error rows of the last hour, not from all usage. + const countUrl = String(fetchMock.mock.calls.find(([u]) => String(u).includes("/v1/usage/count"))?.[0]); + expect(new URLSearchParams(countUrl.split("?")[1]).get("status")).toBe("error"); + // Imported usage can carry status=error too; an imported session's failures + // are not this gateway dropping traffic, so they must not raise the alarm. + expect(new URLSearchParams(countUrl.split("?")[1]).get("source")).toBe("gateway"); + const since = new Date(countWindows(fetchMock)[0]).getTime(); + expect(Date.now() - since).toBeGreaterThan(0); + expect(Date.now() - since).toBeLessThanOrEqual(3_600_000 + 5_000); + }); + + it("re-anchors the window as it polls, so a long-open tab still reports the last hour", async () => { + vi.useFakeTimers({ shouldAdvanceTime: true }); + try { + const fetchMock = mockSettings({ ...BASE, require_pricing: true, default_pricing: false }, 12); + renderPage(); + + await waitFor(() => expect(countWindows(fetchMock)).toHaveLength(1)); + await vi.advanceTimersByTimeAsync(60_000); + await waitFor(() => expect(countWindows(fetchMock).length).toBeGreaterThan(1)); + + // A frozen anchor would ask for the same start_date forever, turning "the + // last hour" into "everything since this tab was opened". + const [first, second] = countWindows(fetchMock); + expect(new Date(second).getTime() - new Date(first).getTime()).toBeGreaterThanOrEqual(59_000); + } finally { + vi.useRealTimers(); + } + }); + + it("stays a config note, with no count, while nothing is failing", async () => { + mockSettings({ ...BASE, require_pricing: true, default_pricing: false }, 0); + renderPage(); + + await screen.findByRole("button", { name: "Enable default pricing" }); + await waitFor(() => expect(globalThis.fetch).toHaveBeenCalledTimes(2)); + expect(screen.queryByText(/failed in the last hour/)).not.toBeInTheDocument(); + expect(screen.queryByRole("link", { name: "View failed requests" })).not.toBeInTheDocument(); + }); + + it("singularizes a lone failure", async () => { + mockSettings({ ...BASE, require_pricing: true, default_pricing: false }, 1); + renderPage(); + + expect(await screen.findByText("1 request failed in the last hour.")).toBeInTheDocument(); + }); + + it("does not count failures while the alarm is quiet", async () => { + const fetchMock = mockSettings({ ...BASE, require_pricing: true, default_pricing: true }, 12); + renderPage(); + + await waitFor(() => expect(globalThis.fetch).toHaveBeenCalled()); + expect(fetchMock.mock.calls.some(([u]) => String(u).includes("/v1/usage/count"))).toBe(false); + }); + it("can be dismissed", async () => { mockSettings({ ...BASE, require_pricing: true, default_pricing: false }); const user = userEvent.setup(); diff --git a/web/src/components/PricingWarning.tsx b/web/src/components/PricingWarning.tsx index fe8555b3..374b257f 100644 --- a/web/src/components/PricingWarning.tsx +++ b/web/src/components/PricingWarning.tsx @@ -1,8 +1,10 @@ import { Button } from "@heroui/react"; import { useState } from "react"; +import { Link } from "react-router-dom"; -import { useSettings, useUpdateSettings } from "@/api/hooks"; +import { useFailureCount, useSettings, useUpdateSettings } from "@/api/hooks"; import { InfoBanner } from "@/components/ui"; +import { HOUR_S } from "@/lib/timeRange"; // A gateway-wide alarm, shown on every management page: when `require_pricing` is // on but `default_pricing` is off, every request for an unpriced model is being @@ -10,13 +12,29 @@ import { InfoBanner } from "@/components/ui"; // operator sees it regardless of where they are, or how the state arose (e.g. // flipping require_pricing on via config long after onboarding). Dismissible per // tab; it reappears on reload while the condition holds. +// +// The banner also carries a live count of requests that failed in the last hour, +// so the reject state reads as an active incident (traffic is being dropped right +// now) rather than a static config note, and links into the activity log filtered +// to those failures. export function PricingWarning() { const settings = useSettings(); const updateSettings = useUpdateSettings(); const [dismissed, setDismissed] = useState(false); const needsPricing = settings.data?.require_pricing === true && settings.data.default_pricing === false; - if (!needsPricing || dismissed) { + const showing = needsPricing && !dismissed; + + // Every failure class the gateway served is counted (402 no pricing, 403 budget + // or model access, 502 provider), not only the pricing rejections: the operator's + // question in this state is "is traffic getting through", and over-reporting a + // failure is safer than a banner reading "0" while requests are being dropped. + // Imported usage is excluded, so the link's filtered view matches this count. + // Only polled while the alarm is up. + const failures = useFailureCount(HOUR_S, showing); + const failureCount = failures.data?.total ?? 0; + + if (!showing) { return null; } @@ -27,6 +45,17 @@ export function PricingWarning() { Requests are rejected until pricing is set (require_pricing is on). Enable default pricing to meter new models with public rates right away. + {failureCount > 0 ? ( + <> + {" "} + + {failureCount.toLocaleString()} {failureCount === 1 ? "request" : "requests"} failed in the last hour. + {" "} + + View failed requests + + + ) : null}