llmapi-tracker 1.0.7__tar.gz → 1.0.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/PKG-INFO +2 -2
  2. llmapi_tracker-1.0.8/backend/app/launcher.py +44 -0
  3. llmapi_tracker-1.0.7/backend/app/static/assets/index-jlcpybVb.js → llmapi_tracker-1.0.8/backend/app/static/assets/index-M74b_d8l.js +1 -1
  4. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/backend/app/static/index.html +1 -1
  5. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/llmapi_tracker.egg-info/PKG-INFO +2 -2
  6. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/llmapi_tracker.egg-info/SOURCES.txt +2 -1
  7. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/pyproject.toml +8 -6
  8. llmapi_tracker-1.0.8/tests/test_launcher.py +13 -0
  9. llmapi_tracker-1.0.7/backend/app/launcher.py +0 -21
  10. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/LICENSE +0 -0
  11. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/README.md +0 -0
  12. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/backend/__init__.py +0 -0
  13. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/backend/app/__init__.py +0 -0
  14. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/backend/app/database.py +0 -0
  15. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/backend/app/frontend.py +0 -0
  16. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/backend/app/main.py +0 -0
  17. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/backend/app/models.py +0 -0
  18. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/backend/app/paths.py +0 -0
  19. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/backend/app/routes/__init__.py +0 -0
  20. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/backend/app/routes/analytics.py +0 -0
  21. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/backend/app/routes/models.py +0 -0
  22. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/backend/app/routes/pricing.py +0 -0
  23. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/backend/app/routes/projects.py +0 -0
  24. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/backend/app/routes/providers.py +0 -0
  25. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/backend/app/routes/usage.py +0 -0
  26. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/backend/app/schemas.py +0 -0
  27. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/backend/app/services/__init__.py +0 -0
  28. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/backend/app/services/cost_service.py +0 -0
  29. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/backend/app/services/usage_service.py +0 -0
  30. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/backend/app/static/assets/index-3YVy8dav.css +0 -0
  31. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/llmapi_tracker.egg-info/dependency_links.txt +0 -0
  32. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/llmapi_tracker.egg-info/entry_points.txt +0 -0
  33. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/llmapi_tracker.egg-info/requires.txt +0 -0
  34. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/llmapi_tracker.egg-info/top_level.txt +0 -0
  35. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/sdk/api_tracker/__init__.py +0 -0
  36. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/sdk/api_tracker/client.py +0 -0
  37. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/sdk/api_tracker/models.py +0 -0
  38. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/sdk/api_tracker/pricing.py +0 -0
  39. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/sdk/api_tracker/providers/__init__.py +0 -0
  40. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/sdk/api_tracker/providers/gemini.py +0 -0
  41. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/sdk/api_tracker/providers/openai.py +0 -0
  42. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/sdk/api_tracker/py.typed +0 -0
  43. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/sdk/api_tracker/tracker.py +0 -0
  44. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/sdk/api_tracker/transport.py +0 -0
  45. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/setup.cfg +0 -0
  46. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/tests/test_analytics_routes.py +0 -0
  47. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/tests/test_cost_service.py +0 -0
  48. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/tests/test_paths.py +0 -0
  49. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/tests/test_provider_model_routes.py +0 -0
  50. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/tests/test_routes.py +0 -0
  51. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/tests/test_tracker.py +0 -0
  52. {llmapi_tracker-1.0.7 → llmapi_tracker-1.0.8}/tests/test_usage_service.py +0 -0
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: llmapi-tracker
3
- Version: 1.0.7
3
+ Version: 1.0.8
4
4
  Summary: Local-first API usage and cost tracking platform
5
5
  Author: API Tracker
6
- License: MIT
6
+ License-Expression: MIT
7
7
  Project-URL: Homepage, https://github.com/Lns9777/API-Usage-Tracker
8
8
  Project-URL: Repository, https://github.com/Lns9777/API-Usage-Tracker
9
9
  Project-URL: Issues, https://github.com/Lns9777/API-Usage-Tracker/issues
@@ -0,0 +1,44 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ import socket
5
+ import threading
6
+ import webbrowser
7
+
8
+ import uvicorn
9
+
10
+
11
+ def find_available_port(host: str, preferred_port: int = 8000) -> int:
12
+ """Prefer the standard port, then choose the first available port."""
13
+ candidates = (
14
+ [preferred_port]
15
+ if preferred_port == 0
16
+ else range(preferred_port, preferred_port + 100)
17
+ )
18
+ for port in candidates:
19
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as probe:
20
+ probe.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
21
+ try:
22
+ probe.bind((host, port))
23
+ except OSError:
24
+ continue
25
+ return probe.getsockname()[1]
26
+ raise RuntimeError(
27
+ f"No available port found between {preferred_port} and {preferred_port + 99}"
28
+ )
29
+
30
+
31
+ def launch_app(*_args: str) -> None:
32
+ host = os.getenv("API_TRACKER_HOST", "127.0.0.1")
33
+ requested_port = int(os.getenv("API_TRACKER_PORT", "8000"))
34
+ port = find_available_port(host, requested_port)
35
+ open_browser = os.getenv("API_TRACKER_OPEN_BROWSER", "true").lower() not in {
36
+ "0",
37
+ "false",
38
+ "no",
39
+ }
40
+ print(f"API Tracker dashboard: http://{host}:{port}")
41
+ if open_browser:
42
+ url = f"http://{host}:{port}"
43
+ threading.Timer(1.0, lambda: webbrowser.open(url)).start()
44
+ uvicorn.run("backend.app.main:app", host=host, port=port, reload=False)
@@ -72,4 +72,4 @@ Error generating stack: `+c.message+`
72
72
  `);return f===-1?"":u.stack.slice(f+1)})();try{if(!o.stack)o.stack=d;else if(d){const f=d.indexOf(`
73
73
  `),h=f===-1?-1:d.indexOf(`
74
74
  `,f+1),g=h===-1?"":d.slice(h+1);String(o.stack).endsWith(g)||(o.stack+=`
75
- `+d)}}catch{}}throw o}}_request(i,s){typeof i=="string"?(s=s||{},s.url=i):s=i||{},s=Mr(this.defaults,s);const{transitional:o,paramsSerializer:u,headers:d}=s;o!==void 0&&Kl.assertOptions(o,{silentJSONParsing:at.transitional(at.boolean),forcedJSONParsing:at.transitional(at.boolean),clarifyTimeoutError:at.transitional(at.boolean),legacyInterceptorReqResOrdering:at.transitional(at.boolean),advertiseZstdAcceptEncoding:at.transitional(at.boolean),validateStatusUndefinedResolves:at.transitional(at.boolean)},!1),u!=null&&(k.isFunction(u)?s.paramsSerializer={serialize:u}:Kl.assertOptions(u,{encode:at.function,serialize:at.function},!0)),s.allowAbsoluteUrls!==void 0||(this.defaults.allowAbsoluteUrls!==void 0?s.allowAbsoluteUrls=this.defaults.allowAbsoluteUrls:s.allowAbsoluteUrls=!0),Kl.assertOptions(s,{baseUrl:at.spelling("baseURL"),withXsrfToken:at.spelling("withXSRFToken")},!0),s.method=(s.method||this.defaults.method||"get").toLowerCase();let f=d&&k.merge(d.common,d[s.method]);d&&k.forEach(["delete","get","head","post","put","patch","query","common"],U=>{delete d[U]}),s.headers=ct.concat(f,d);const h=[];let g=!0;this.interceptors.request.forEach(function(F){if(typeof F.runWhen=="function"&&F.runWhen(s)===!1)return;g=g&&F.synchronous;const P=s.transitional||Ku;P&&P.legacyInterceptorReqResOrdering?h.unshift(F.fulfilled,F.rejected):h.push(F.fulfilled,F.rejected)});const w=[];this.interceptors.response.forEach(function(F){w.push(F.fulfilled,F.rejected)});let x,v=0,N;if(!g){const U=[du.bind(this),void 0];for(U.unshift(...h),U.push(...w),N=U.length,x=Promise.resolve(s);v<N;)x=x.then(U[v++],U[v++]);return x}N=h.length;let T=s;for(;v<N;){const U=h[v++],F=h[v++];try{T=U?U(T):T}catch(P){if(!F){x=Promise.reject(P);break}try{const C=F.call(this,P);k.isThenable(C)&&(x=Promise.resolve(C).then(()=>du.call(this,T)))}catch(C){x=Promise.reject(C)}break}}if(!x)try{x=du.call(this,T)}catch(U){x=Promise.reject(U)}for(v=0,N=w.length;v<N;)x=x.then(w[v++],w[v++]);return x}getUri(i){i=Mr(this.defaults,i);const s=$h(i.baseURL,i.url,i.allowAbsoluteUrls,i);return bh(s,i.params,i.paramsSerializer)}};k.forEach(["delete","get","head","options"],function(i){Lr.prototype[i]=function(s,o){return this.request(Mr(o||{},{method:i,url:s,data:o&&k.hasOwnProp(o,"data")?o.data:void 0}))}});k.forEach(["post","put","patch","query"],function(i){function s(o){return function(d,f,h){return this.request(Mr(h||{},{method:i,headers:o?{"Content-Type":"multipart/form-data"}:{},url:d,data:f}))}}Lr.prototype[i]=s(),i!=="query"&&(Lr.prototype[i+"Form"]=s(!0))});let uw=class Vh{constructor(i){if(typeof i!="function")throw new TypeError("executor must be a function.");let s;this.promise=new Promise(function(d){s=d});const o=this;this.promise.then(u=>{if(!o._listeners)return;let d=o._listeners.length;for(;d-- >0;)o._listeners[d](u);o._listeners=null}),this.promise.then=u=>{let d;const f=new Promise(h=>{o.subscribe(h),d=h}).then(u);return f.cancel=function(){o.unsubscribe(d)},f},i(function(d,f,h){o.reason||(o.reason=new Ls(d,f,h),s(o.reason))})}throwIfRequested(){if(this.reason)throw this.reason}subscribe(i){if(this.reason){i(this.reason);return}this._listeners?this._listeners.push(i):this._listeners=[i]}unsubscribe(i){if(!this._listeners)return;const s=this._listeners.indexOf(i);s!==-1&&this._listeners.splice(s,1)}toAbortSignal(){const i=new AbortController,s=o=>{i.abort(o)};return this.subscribe(s),i.signal.unsubscribe=()=>this.unsubscribe(s),i.signal}static source(){let i;return{token:new Vh(function(u){i=u}),cancel:i}}};function cw(r){return function(s){return r.apply(null,s)}}function dw(r){return k.isObject(r)&&r.isAxiosError===!0}const Du={Continue:100,SwitchingProtocols:101,Processing:102,EarlyHints:103,Ok:200,Created:201,Accepted:202,NonAuthoritativeInformation:203,NoContent:204,ResetContent:205,PartialContent:206,MultiStatus:207,AlreadyReported:208,ImUsed:226,MultipleChoices:300,MovedPermanently:301,Found:302,SeeOther:303,NotModified:304,UseProxy:305,Unused:306,TemporaryRedirect:307,PermanentRedirect:308,BadRequest:400,Unauthorized:401,PaymentRequired:402,Forbidden:403,NotFound:404,MethodNotAllowed:405,NotAcceptable:406,ProxyAuthenticationRequired:407,RequestTimeout:408,Conflict:409,Gone:410,LengthRequired:411,PreconditionFailed:412,PayloadTooLarge:413,UriTooLong:414,UnsupportedMediaType:415,RangeNotSatisfiable:416,ExpectationFailed:417,ImATeapot:418,MisdirectedRequest:421,UnprocessableEntity:422,Locked:423,FailedDependency:424,TooEarly:425,UpgradeRequired:426,PreconditionRequired:428,TooManyRequests:429,RequestHeaderFieldsTooLarge:431,UnavailableForLegalReasons:451,InternalServerError:500,NotImplemented:501,BadGateway:502,ServiceUnavailable:503,GatewayTimeout:504,HttpVersionNotSupported:505,VariantAlsoNegotiates:506,InsufficientStorage:507,LoopDetected:508,NotExtended:510,NetworkAuthenticationRequired:511,WebServerReturnsAnUnknownError:520,WebServerIsDown:521,ConnectionTimedOut:522,OriginIsUnreachable:523,TimeoutOccurred:524,SslHandshakeFailed:525,InvalidSslCertificate:526};Object.entries(Du).forEach(([r,i])=>{Du[i]=r});function Kh(r){const i=new Lr(r),s=Ch(Lr.prototype.request,i);return k.extend(s,Lr.prototype,i,{allOwnKeys:!0}),k.extend(s,i,null,{allOwnKeys:!0}),s.create=function(u){return Kh(Mr(r,u))},s}const ze=Kh(Ns);ze.Axios=Lr;ze.CanceledError=Ls;ze.CancelToken=uw;ze.isCancel=zh;ze.VERSION=Xu;ze.toFormData=lo;ze.AxiosError=Q;ze.Cancel=ze.CanceledError;ze.all=function(i){return Promise.all(i)};ze.spread=cw;ze.isAxiosError=dw;ze.mergeConfig=Mr;ze.AxiosHeaders=ct;ze.formToJSON=r=>Uh(k.isHTMLForm(r)?new FormData(r):r);ze.getAdapter=Wh.getAdapter;ze.HttpStatusCode=Du;ze.default=ze;const{Axios:qw,AxiosError:Ww,CanceledError:Vw,isCancel:Kw,CancelToken:Jw,VERSION:Xw,all:Gw,Cancel:Yw,isAxiosError:Zw,spread:eS,toFormData:tS,AxiosHeaders:nS,HttpStatusCode:rS,formToJSON:iS,getAdapter:sS,mergeConfig:lS,create:oS}=ze,kn=ze.create({baseURL:"http://localhost:8000"}),fw=async()=>(await kn.get("/analytics/overview")).data,Jh=()=>ji({queryKey:["overview"],queryFn:fw});function pw(r){const i=new Date,s=new Date(i);return s.setHours(0,0,0,0),r==="today"?s:r==="yesterday"?(s.setDate(s.getDate()-1),s):r==="7d"?(s.setDate(s.getDate()-6),s):r==="30d"?(s.setDate(s.getDate()-29),s):null}function Xh(r,i,s,o="all"){const u=i.trim().toLowerCase(),d=pw(o);return r.filter(f=>{const h=new Date(f.timestamp),g=!d||h>=d,w=!u||f.internal_request_id.toLowerCase().includes(u)||String(f.project_id).includes(u)||String(f.provider_id).includes(u)||String(f.model_id).includes(u),x=s==="all"||f.status===s;return g&&w&&x})}function Gh(r){return{requests:r.length,inputTokens:r.reduce((i,s)=>i+s.input_tokens,0),outputTokens:r.reduce((i,s)=>i+s.output_tokens,0),thinkingTokens:r.reduce((i,s)=>i+s.thinking_tokens,0),cachedTokens:r.reduce((i,s)=>i+s.cached_tokens,0),tokens:r.reduce((i,s)=>i+s.total_tokens,0),cost:r.reduce((i,s)=>i+s.total_cost,0),errors:r.filter(i=>i.status!=="success").length}}const hw=async()=>(await kn.get("/usage")).data,ao=()=>ji({queryKey:["usage"],queryFn:hw});function mw(){const{data:r,isLoading:i,isError:s}=Jh(),o=ao(),[u,d]=M.useState("all"),f=M.useMemo(()=>Xh(o.data??[],"","all",u),[o.data,u]),h=M.useMemo(()=>Gh(f),[f]);return i||o.isLoading?m.jsx(qe,{title:"Overview",description:"Loading dashboard metrics..."}):s||o.isError||!r||!o.data?m.jsx(qe,{title:"Overview",description:"Unable to load analytics."}):m.jsxs("div",{style:{display:"grid",gap:24},children:[m.jsxs("div",{className:"page",children:[m.jsx("h1",{children:"Overview"}),m.jsx("p",{children:"Real-time usage, cost, and reliability snapshot."})]}),m.jsxs("div",{className:"page",style:{display:"grid",gap:12},children:[m.jsx("h2",{children:"Date Range"}),m.jsxs("div",{style:{display:"grid",gap:12,gridTemplateColumns:"1fr 1fr"},children:[m.jsxs("select",{value:u,onChange:g=>d(g.target.value),style:{background:"#0f172a",color:"#e5eefb",border:"1px solid rgba(148,163,184,.18)",borderRadius:10,padding:12},children:[m.jsx("option",{value:"all",children:"All time"}),m.jsx("option",{value:"today",children:"Today"}),m.jsx("option",{value:"yesterday",children:"Yesterday"}),m.jsx("option",{value:"7d",children:"Last 7 days"}),m.jsx("option",{value:"30d",children:"Last 30 days"})]}),m.jsxs("div",{style:{color:"#8aa0c7",alignSelf:"center"},children:["Showing: ",u==="all"?"All time":u]})]})]}),m.jsxs("div",{style:{display:"grid",gridTemplateColumns:"repeat(5, minmax(0, 1fr))",gap:16},children:[m.jsx(ke,{label:"Total Requests",value:String(h.requests)}),m.jsx(ke,{label:"Total Tokens",value:h.tokens.toLocaleString()}),m.jsx(ke,{label:"Total Cost",value:`$${r.cost.toFixed(4)}`}),m.jsx(ke,{label:"Avg Latency",value:`${Math.round(r.average_latency_ms)} ms`}),m.jsx(ke,{label:"Error Rate",value:`${r.error_rate.toFixed(2)}%`})]}),m.jsxs("div",{className:"page",children:[m.jsx("h2",{children:"What to watch"}),m.jsxs("ul",{children:[m.jsx("li",{children:"Track pricing changes through versioned records only."}),m.jsx("li",{children:"Use the usage table to inspect provider and model mix."}),m.jsx("li",{children:"Keep prompts, responses, and secrets off the local store."})]})]})]})}function Ni({columns:r,data:i,emptyMessage:s="No rows found."}){return m.jsx("div",{style:{border:"1px solid rgba(148,163,184,.18)",borderRadius:16,overflow:"hidden",background:"rgba(15,23,42,.72)"},children:m.jsxs("table",{style:{width:"100%",borderCollapse:"collapse"},children:[m.jsx("thead",{children:m.jsx("tr",{children:r.map(o=>m.jsx("th",{style:{textAlign:"left",padding:14,color:"#8aa0c7",fontSize:13,borderBottom:"1px solid rgba(148,163,184,.12)"},children:o.header},o.header))})}),m.jsx("tbody",{children:i.length===0?m.jsx("tr",{children:m.jsx("td",{colSpan:r.length,style:{padding:18,color:"#8aa0c7"},children:s})}):i.map((o,u)=>m.jsx("tr",{children:r.map(d=>m.jsx("td",{style:{padding:14,borderBottom:"1px solid rgba(148,163,184,.08)"},children:d.cell(o)},d.header))},u))})]})})}const gw=async()=>(await kn.get("/projects")).data,yw=()=>ji({queryKey:["projects"],queryFn:gw});function vw(){const{data:r,isLoading:i,isError:s}=yw();return i?m.jsx(qe,{title:"Projects",description:"Loading projects..."}):s||!r?m.jsx(qe,{title:"Projects",description:"Unable to load projects."}):m.jsxs("div",{style:{display:"grid",gap:24},children:[m.jsxs("div",{className:"page",children:[m.jsx("h1",{children:"Projects"}),m.jsx("p",{children:"Project-level usage and cost breakdown."})]}),m.jsxs("div",{style:{display:"grid",gridTemplateColumns:"repeat(3, minmax(0, 1fr))",gap:16},children:[m.jsx(ke,{label:"Projects",value:String(r.length)}),m.jsx(ke,{label:"Production",value:String(r.filter(o=>o.environment==="production").length)}),m.jsx(ke,{label:"Development",value:String(r.filter(o=>o.environment!=="production").length)})]}),m.jsx(Ni,{data:r,columns:[{header:"Name",cell:o=>o.name},{header:"Environment",cell:o=>o.environment},{header:"Description",cell:o=>o.description||"-"},{header:"Created",cell:o=>new Date(o.created_at).toLocaleString()}]})]})}function ww(){const{data:r,isLoading:i,isError:s}=ao(),[o,u]=M.useState(""),[d,f]=M.useState("all"),[h,g]=M.useState("all"),[w,x]=M.useState(null),v=M.useMemo(()=>Xh(r??[],o,d,h),[r,o,d,h]),N=M.useMemo(()=>Gh(r??[]),[r]);return i?m.jsx(qe,{title:"Usage",description:"Loading API usage..."}):s||!r?m.jsx(qe,{title:"Usage",description:"Unable to load usage records."}):m.jsxs("div",{style:{display:"grid",gap:24},children:[m.jsxs("div",{className:"page",children:[m.jsx("h1",{children:"Usage"}),m.jsx("p",{children:"Recent tracked requests."})]}),m.jsxs("div",{style:{display:"grid",gridTemplateColumns:"repeat(4, minmax(0, 1fr))",gap:16},children:[m.jsx(ke,{label:"Requests",value:String(N.requests)}),m.jsx(ke,{label:"Input Tokens",value:N.inputTokens.toLocaleString()}),m.jsx(ke,{label:"Output Tokens",value:N.outputTokens.toLocaleString()}),m.jsx(ke,{label:"Total Tokens",value:N.tokens.toLocaleString()})]}),m.jsxs("div",{style:{display:"grid",gridTemplateColumns:"repeat(4, minmax(0, 1fr))",gap:16},children:[m.jsx(ke,{label:"Thinking Tokens",value:N.thinkingTokens.toLocaleString()}),m.jsx(ke,{label:"Cached Tokens",value:N.cachedTokens.toLocaleString()}),m.jsx(ke,{label:"Cost",value:`$${N.cost.toFixed(4)}`}),m.jsx(ke,{label:"Errors",value:String(N.errors)})]}),m.jsxs("div",{className:"page",style:{display:"grid",gap:12},children:[m.jsx("h2",{children:"Filters"}),m.jsxs("div",{style:{display:"grid",gap:12,gridTemplateColumns:"2fr 1fr 1fr"},children:[m.jsx("input",{value:o,onChange:T=>u(T.target.value),placeholder:"Search request id, project id, provider id, model id",style:{background:"#0f172a",color:"#e5eefb",border:"1px solid rgba(148,163,184,.18)",borderRadius:10,padding:12}}),m.jsxs("select",{value:d,onChange:T=>f(T.target.value),style:{background:"#0f172a",color:"#e5eefb",border:"1px solid rgba(148,163,184,.18)",borderRadius:10,padding:12},children:[m.jsx("option",{value:"all",children:"All statuses"}),m.jsx("option",{value:"success",children:"Success"}),m.jsx("option",{value:"error",children:"Error"})]}),m.jsxs("select",{value:h,onChange:T=>g(T.target.value),style:{background:"#0f172a",color:"#e5eefb",border:"1px solid rgba(148,163,184,.18)",borderRadius:10,padding:12},children:[m.jsx("option",{value:"all",children:"All time"}),m.jsx("option",{value:"today",children:"Today"}),m.jsx("option",{value:"yesterday",children:"Yesterday"}),m.jsx("option",{value:"7d",children:"Last 7 days"}),m.jsx("option",{value:"30d",children:"Last 30 days"})]})]})]}),m.jsx(Ni,{data:v,columns:[{header:"Timestamp",cell:T=>new Date(T.timestamp).toLocaleString()},{header:"Project",cell:T=>String(T.project_id)},{header:"Provider",cell:T=>String(T.provider_id)},{header:"Model",cell:T=>String(T.model_id)},{header:"Request ID",cell:T=>m.jsx("button",{onClick:()=>x(T),style:{background:"none",color:"#93c5fd",border:0,padding:0,cursor:"pointer"},children:T.internal_request_id})},{header:"Tokens",cell:T=>T.total_tokens.toLocaleString()},{header:"Cost",cell:T=>`$${T.total_cost.toFixed(4)}`},{header:"Latency",cell:T=>`${Math.round(T.latency_ms)} ms`},{header:"Status",cell:T=>T.status}]}),w?m.jsx("div",{onClick:()=>x(null),style:{position:"fixed",inset:0,background:"rgba(2,6,23,.72)",backdropFilter:"blur(6px)",display:"grid",placeItems:"center",padding:24,zIndex:50},children:m.jsxs("div",{onClick:T=>T.stopPropagation(),style:{width:"min(820px, 100%)",maxHeight:"90vh",overflow:"auto",background:"linear-gradient(180deg, #0f172a, #111827)",border:"1px solid rgba(148,163,184,.2)",borderRadius:18,padding:24,display:"grid",gap:14,boxShadow:"0 24px 80px rgba(0,0,0,.45)"},children:[m.jsxs("div",{style:{display:"flex",justifyContent:"space-between",gap:16},children:[m.jsxs("div",{children:[m.jsx("h2",{style:{margin:0},children:"Request Details"}),m.jsx("p",{style:{margin:"6px 0 0",color:"#8aa0c7"},children:w.internal_request_id})]}),m.jsx("button",{onClick:()=>x(null),style:{background:"#1f2937",color:"#e5eefb",border:0,borderRadius:10,padding:"8px 12px"},children:"Close"})]}),m.jsxs("div",{style:{display:"grid",gridTemplateColumns:"repeat(2, minmax(0, 1fr))",gap:12},children:[m.jsxs("div",{style:{background:"rgba(15,23,42,.7)",border:"1px solid rgba(148,163,184,.12)",borderRadius:12,padding:12},children:["Project ID: ",w.project_id]}),m.jsxs("div",{style:{background:"rgba(15,23,42,.7)",border:"1px solid rgba(148,163,184,.12)",borderRadius:12,padding:12},children:["Provider ID: ",w.provider_id]}),m.jsxs("div",{style:{background:"rgba(15,23,42,.7)",border:"1px solid rgba(148,163,184,.12)",borderRadius:12,padding:12},children:["Model ID: ",w.model_id]}),m.jsxs("div",{style:{background:"rgba(15,23,42,.7)",border:"1px solid rgba(148,163,184,.12)",borderRadius:12,padding:12},children:["Timestamp: ",new Date(w.timestamp).toLocaleString()]}),m.jsxs("div",{style:{background:"rgba(15,23,42,.7)",border:"1px solid rgba(148,163,184,.12)",borderRadius:12,padding:12},children:["Latency: ",Math.round(w.latency_ms)," ms"]}),m.jsxs("div",{style:{background:"rgba(15,23,42,.7)",border:"1px solid rgba(148,163,184,.12)",borderRadius:12,padding:12},children:["Status: ",w.status]}),m.jsxs("div",{style:{background:"rgba(15,23,42,.7)",border:"1px solid rgba(148,163,184,.12)",borderRadius:12,padding:12},children:["HTTP Status: ",w.http_status_code??"-"]}),m.jsxs("div",{style:{background:"rgba(15,23,42,.7)",border:"1px solid rgba(148,163,184,.12)",borderRadius:12,padding:12},children:["Capture Content: ",w.capture_content?"Enabled":"Disabled"]}),m.jsxs("div",{style:{background:"rgba(15,23,42,.7)",border:"1px solid rgba(148,163,184,.12)",borderRadius:12,padding:12},children:["Input Tokens: ",w.input_tokens]}),m.jsxs("div",{style:{background:"rgba(15,23,42,.7)",border:"1px solid rgba(148,163,184,.12)",borderRadius:12,padding:12},children:["Output Tokens: ",w.output_tokens]}),m.jsxs("div",{style:{background:"rgba(15,23,42,.7)",border:"1px solid rgba(148,163,184,.12)",borderRadius:12,padding:12},children:["Thinking Tokens: ",w.thinking_tokens]}),m.jsxs("div",{style:{background:"rgba(15,23,42,.7)",border:"1px solid rgba(148,163,184,.12)",borderRadius:12,padding:12},children:["Cached Tokens: ",w.cached_tokens]}),m.jsxs("div",{style:{background:"rgba(15,23,42,.7)",border:"1px solid rgba(148,163,184,.12)",borderRadius:12,padding:12},children:["Total Tokens: ",w.total_tokens]}),m.jsxs("div",{style:{background:"rgba(15,23,42,.7)",border:"1px solid rgba(148,163,184,.12)",borderRadius:12,padding:12},children:["Input Cost: $",w.input_cost.toFixed(4)]}),m.jsxs("div",{style:{background:"rgba(15,23,42,.7)",border:"1px solid rgba(148,163,184,.12)",borderRadius:12,padding:12},children:["Output Cost: $",w.output_cost.toFixed(4)]}),m.jsxs("div",{style:{background:"rgba(15,23,42,.7)",border:"1px solid rgba(148,163,184,.12)",borderRadius:12,padding:12},children:["Thinking Cost: $",w.thinking_cost.toFixed(4)]}),m.jsxs("div",{style:{background:"rgba(15,23,42,.7)",border:"1px solid rgba(148,163,184,.12)",borderRadius:12,padding:12},children:["Cached Cost: $",w.cached_cost.toFixed(4)]}),m.jsxs("div",{style:{background:"rgba(15,23,42,.7)",border:"1px solid rgba(148,163,184,.12)",borderRadius:12,padding:12},children:["Total Cost: $",w.total_cost.toFixed(4)]})]}),w.error_type?m.jsxs("div",{children:["Error Type: ",w.error_type]}):null,m.jsx("div",{style:{display:"flex",justifyContent:"flex-end"},children:m.jsx(ch,{to:`/usage/${w.id}`,children:"Open dedicated view"})})]})}):null]})}function Sw({label:r,value:i,max:s}){const o=s>0?Math.max(i/s*100,4):4;return m.jsxs("div",{style:{display:"grid",gap:8},children:[m.jsxs("div",{style:{display:"flex",justifyContent:"space-between",color:"#c7d2fe",fontSize:13},children:[m.jsx("span",{children:r}),m.jsx("span",{children:i.toLocaleString()})]}),m.jsx("div",{style:{height:10,borderRadius:999,background:"rgba(148,163,184,.14)",overflow:"hidden"},children:m.jsx("div",{style:{width:`${o}%`,height:"100%",background:"linear-gradient(90deg, #60a5fa, #34d399)"}})})]})}function xw(r){return r.reduce((i,s)=>(i[s.status]=(i[s.status]||0)+1,i),{})}function Ew(r){return Math.max(...Object.values(r),1)}function Cw(){const r=Jh(),i=ao();if(r.isLoading||i.isLoading)return m.jsx(qe,{title:"Analytics",description:"Loading analytics..."});if(r.isError||i.isError||!r.data||!i.data)return m.jsx(qe,{title:"Analytics",description:"Unable to load analytics."});const s=xw(i.data),o=Ew(s);return m.jsxs("div",{style:{display:"grid",gap:24},children:[m.jsxs("div",{className:"page",children:[m.jsx("h1",{children:"Analytics"}),m.jsx("p",{children:"Cost, usage, and reliability snapshots."})]}),m.jsxs("div",{style:{display:"grid",gridTemplateColumns:"repeat(4, minmax(0, 1fr))",gap:16},children:[m.jsx(ke,{label:"Requests",value:String(r.data.requests)}),m.jsx(ke,{label:"Tokens",value:r.data.tokens.toLocaleString()}),m.jsx(ke,{label:"Cost",value:`$${r.data.cost.toFixed(4)}`}),m.jsx(ke,{label:"Error Rate",value:`${r.data.error_rate.toFixed(2)}%`})]}),m.jsxs("div",{className:"page",children:[m.jsx("h2",{children:"Request Status"}),m.jsx("div",{style:{display:"grid",gap:14,marginTop:16},children:Object.entries(s).map(([u,d])=>m.jsx(Sw,{label:u,value:d,max:o},u))})]}),m.jsx(Ni,{data:Object.entries(s).map(([u,d])=>({status:u,count:d})),columns:[{header:"Status",cell:u=>u.status},{header:"Count",cell:u=>String(u.count)}],emptyMessage:"No usage yet."})]})}const kw=async()=>(await kn.get("/providers")).data,_w=async r=>(await kn.post("/providers",{name:r})).data,Yh=()=>ji({queryKey:["providers"],queryFn:kw});function Rw(){var N;const r=js(),{data:i,isLoading:s,isError:o}=Yh(),[u,d]=M.useState(""),[f,h]=M.useState(null),[g,w]=M.useState(null),x=Qu({mutationFn:_w,onSuccess:async()=>{await r.invalidateQueries({queryKey:["providers"]}),d(""),h("Provider added successfully."),w(null)},onError:()=>{h(null),w("Unable to add provider. Please try again.")}}),v=T=>{if(T.preventDefault(),h(null),w(null),!u.trim()){w("Provider name is required.");return}x.mutate(u.trim())};return s?m.jsx(qe,{title:"Providers",description:"Loading providers..."}):o||!i?m.jsx(qe,{title:"Providers",description:"Unable to load providers."}):m.jsxs("div",{style:{display:"grid",gap:24},children:[m.jsxs("div",{className:"page",children:[m.jsx("h1",{children:"Providers"}),m.jsx("p",{children:"Registered API providers in the local tracker."})]}),m.jsxs("div",{style:{border:"1px solid rgba(148,163,184,.18)",borderRadius:20,background:"linear-gradient(180deg, rgba(15,23,42,.92), rgba(15,23,42,.76))",padding:20,display:"grid",gap:16},children:[m.jsxs("div",{children:[m.jsx("h2",{style:{margin:0},children:"Add Provider"}),m.jsx("p",{style:{margin:"6px 0 0",color:"#8aa0c7"},children:"Create a local provider record for tracking usage and models."})]}),m.jsxs("form",{onSubmit:v,style:{display:"flex",gap:12,flexWrap:"wrap",alignItems:"center"},children:[m.jsx("input",{value:u,onChange:T=>d(T.target.value),placeholder:"Provider name",style:{minWidth:280,padding:12,borderRadius:12,border:"1px solid rgba(148,163,184,.18)",background:"#0f172a",color:"#e2e8f0"}}),m.jsx("button",{type:"submit",disabled:x.isPending,style:{padding:"12px 18px",borderRadius:12,border:"none",background:x.isPending?"#475569":"linear-gradient(135deg, #22c55e, #14b8a6)",color:"#fff",fontWeight:700,cursor:x.isPending?"wait":"pointer"},children:x.isPending?"Saving...":"Add Provider"}),f?m.jsx("span",{style:{color:"#86efac"},children:f}):null,g?m.jsx("span",{style:{color:"#fca5a5"},children:g}):null]})]}),m.jsxs("div",{style:{display:"grid",gridTemplateColumns:"repeat(3, minmax(0, 1fr))",gap:16},children:[m.jsx(ke,{label:"Providers",value:String(i.length)}),m.jsx(ke,{label:"Active Names",value:String(new Set(i.map(T=>T.name)).size)}),m.jsx(ke,{label:"Newest ID",value:String(((N=i[0])==null?void 0:N.id)??0)})]}),m.jsx(Ni,{data:i,columns:[{header:"ID",cell:T=>String(T.id)},{header:"Name",cell:T=>T.name},{header:"Created",cell:T=>new Date(T.created_at).toLocaleString()}]})]})}const Pw=async()=>(await kn.get("/models")).data,jw=async r=>(await kn.post("/models",r)).data,Zh=()=>ji({queryKey:["models"],queryFn:Pw});function Ow(){const r=js(),{data:i,isLoading:s,isError:o}=Zh(),{data:u=[]}=Yh(),[d,f]=M.useState(0),[h,g]=M.useState(""),[w,x]=M.useState("text"),[v,N]=M.useState(null),[T,U]=M.useState(null),F=M.useMemo(()=>u.map(D=>({id:D.id,label:`${D.name} (#${D.id})`})),[u]),P=Qu({mutationFn:jw,onSuccess:async()=>{await r.invalidateQueries({queryKey:["models"]}),f(0),g(""),x("text"),N("Model added successfully."),U(null)},onError:()=>{N(null),U("Unable to add model. Please check the form and try again.")}}),C=D=>{if(D.preventDefault(),N(null),U(null),!d){U("Provider is required.");return}if(!h.trim()){U("Model name is required.");return}P.mutate({provider_id:d,model_name:h.trim(),model_type:w})};return s?m.jsx(qe,{title:"Models",description:"Loading models..."}):o||!i?m.jsx(qe,{title:"Models",description:"Unable to load models."}):m.jsxs("div",{style:{display:"grid",gap:24},children:[m.jsxs("div",{className:"page",children:[m.jsx("h1",{children:"Models"}),m.jsx("p",{children:"Model registry and provider mappings."})]}),m.jsxs("div",{style:{border:"1px solid rgba(148,163,184,.18)",borderRadius:20,background:"linear-gradient(180deg, rgba(15,23,42,.92), rgba(15,23,42,.76))",padding:20,display:"grid",gap:16},children:[m.jsxs("div",{children:[m.jsx("h2",{style:{margin:0},children:"Add Model"}),m.jsx("p",{style:{margin:"6px 0 0",color:"#8aa0c7"},children:"Create a new local model mapping for a provider."})]}),m.jsxs("form",{onSubmit:C,style:{display:"grid",gap:16},children:[m.jsxs("div",{style:{display:"grid",gridTemplateColumns:"repeat(2, minmax(0, 1fr))",gap:16},children:[m.jsxs("label",{style:{display:"grid",gap:8},children:[m.jsx("span",{style:{color:"#8aa0c7",fontSize:13},children:"Provider"}),m.jsxs("select",{value:d,onChange:D=>f(Number(D.target.value)),style:{padding:12,borderRadius:12,border:"1px solid rgba(148,163,184,.18)",background:"#0f172a",color:"#e2e8f0"},children:[m.jsx("option",{value:0,children:"Select a provider"}),F.map(D=>m.jsx("option",{value:D.id,children:D.label},D.id))]})]}),m.jsxs("label",{style:{display:"grid",gap:8},children:[m.jsx("span",{style:{color:"#8aa0c7",fontSize:13},children:"Model Type"}),m.jsxs("select",{value:w,onChange:D=>x(D.target.value),style:{padding:12,borderRadius:12,border:"1px solid rgba(148,163,184,.18)",background:"#0f172a",color:"#e2e8f0"},children:[m.jsx("option",{value:"text",children:"text"}),m.jsx("option",{value:"vision",children:"vision"}),m.jsx("option",{value:"embedding",children:"embedding"}),m.jsx("option",{value:"audio",children:"audio"}),m.jsx("option",{value:"chat",children:"chat"})]})]})]}),m.jsxs("label",{style:{display:"grid",gap:8},children:[m.jsx("span",{style:{color:"#8aa0c7",fontSize:13},children:"Model Name"}),m.jsx("input",{value:h,onChange:D=>g(D.target.value),placeholder:"gemini-2.5-flash",style:{padding:12,borderRadius:12,border:"1px solid rgba(148,163,184,.18)",background:"#0f172a",color:"#e2e8f0"}})]}),m.jsxs("div",{style:{display:"flex",gap:12,alignItems:"center",flexWrap:"wrap"},children:[m.jsx("button",{type:"submit",disabled:P.isPending,style:{padding:"12px 18px",borderRadius:12,border:"none",background:P.isPending?"#475569":"linear-gradient(135deg, #22c55e, #14b8a6)",color:"#fff",fontWeight:700,cursor:P.isPending?"wait":"pointer"},children:P.isPending?"Saving...":"Add Model"}),v?m.jsx("span",{style:{color:"#86efac"},children:v}):null,T?m.jsx("span",{style:{color:"#fca5a5"},children:T}):null]})]})]}),m.jsxs("div",{style:{display:"grid",gridTemplateColumns:"repeat(3, minmax(0, 1fr))",gap:16},children:[m.jsx(ke,{label:"Models",value:String(i.length)}),m.jsx(ke,{label:"Text Models",value:String(i.filter(D=>D.model_type==="text").length)}),m.jsx(ke,{label:"Providers",value:String(new Set(i.map(D=>D.provider_id)).size)})]}),m.jsx(Ni,{data:i,columns:[{header:"ID",cell:D=>String(D.id)},{header:"Provider ID",cell:D=>String(D.provider_id)},{header:"Model Name",cell:D=>D.model_name},{header:"Type",cell:D=>D.model_type},{header:"Created",cell:D=>new Date(D.created_at).toLocaleString()}]})]})}const Tw=async()=>(await kn.get("/pricing")).data,Nw=async r=>(await kn.post("/pricing",r)).data,Lw=()=>ji({queryKey:["pricing"],queryFn:Tw}),Mp={model_id:0,input_price_per_1m:0,output_price_per_1m:0,thinking_price_per_1m:0,cached_input_price_per_1m:0,currency:"USD",effective_from:new Date().toISOString().slice(0,16),effective_to:null};function bp(r){return`${r}:00`}function Dw(){const r=js(),{data:i,isLoading:s,isError:o}=Lw(),{data:u=[]}=Zh(),[d,f]=M.useState(Mp),[h,g]=M.useState(null),[w,x]=M.useState(null),v=Qu({mutationFn:Nw,onSuccess:async()=>{await r.invalidateQueries({queryKey:["pricing"]}),g("Pricing row added locally and refreshed."),x(null),f(Mp)},onError:()=>{g(null),x("Unable to add pricing row. Check the form values and try again.")}}),N=M.useMemo(()=>u.map(C=>({id:C.id,label:`${C.model_name} (#${C.id})`})),[u]);if(s)return m.jsx(qe,{title:"Pricing",description:"Loading pricing versions..."});if(o||!i)return m.jsx(qe,{title:"Pricing",description:"Unable to load pricing."});const T=i.filter(C=>!C.effective_to).length,U=new Set(i.map(C=>C.model_id)).size,F=(C,D)=>{f(b=>({...b,[C]:D}))},P=C=>{if(C.preventDefault(),g(null),x(null),!d.model_id){x("Please select a model.");return}v.mutate({...d,effective_from:bp(d.effective_from),effective_to:d.effective_to?bp(d.effective_to):null})};return m.jsxs("div",{style:{display:"grid",gap:24},children:[m.jsxs("div",{className:"page",children:[m.jsx("h1",{children:"Pricing"}),m.jsx("p",{children:"Versioned pricing records drive historical cost calculation."})]}),m.jsxs("div",{style:{display:"grid",gridTemplateColumns:"repeat(3, minmax(0, 1fr))",gap:16},children:[m.jsx(ke,{label:"Pricing Rows",value:String(i.length)}),m.jsx(ke,{label:"Current",value:String(T)}),m.jsx(ke,{label:"Models Covered",value:String(U)})]}),m.jsxs("div",{style:{border:"1px solid rgba(148,163,184,.18)",borderRadius:20,background:"linear-gradient(180deg, rgba(15,23,42,.92), rgba(15,23,42,.76))",padding:20,display:"grid",gap:16},children:[m.jsxs("div",{children:[m.jsx("h2",{style:{margin:0},children:"Add Pricing"}),m.jsx("p",{style:{margin:"6px 0 0",color:"#8aa0c7"},children:"Create a new versioned pricing row. The new entry is stored locally in your backend database only."})]}),m.jsxs("form",{onSubmit:P,style:{display:"grid",gap:16},children:[m.jsxs("div",{style:{display:"grid",gridTemplateColumns:"repeat(2, minmax(0, 1fr))",gap:16},children:[m.jsxs("label",{style:{display:"grid",gap:8},children:[m.jsx("span",{style:{color:"#8aa0c7",fontSize:13},children:"Model"}),m.jsxs("select",{value:d.model_id,onChange:C=>F("model_id",Number(C.target.value)),style:{padding:12,borderRadius:12,border:"1px solid rgba(148,163,184,.18)",background:"#0f172a",color:"#e2e8f0"},children:[m.jsx("option",{value:0,children:"Select a model"}),N.map(C=>m.jsx("option",{value:C.id,children:C.label},C.id))]})]}),m.jsxs("label",{style:{display:"grid",gap:8},children:[m.jsx("span",{style:{color:"#8aa0c7",fontSize:13},children:"Currency"}),m.jsx("input",{value:d.currency,onChange:C=>F("currency",C.target.value.toUpperCase()),style:{padding:12,borderRadius:12,border:"1px solid rgba(148,163,184,.18)",background:"#0f172a",color:"#e2e8f0"}})]})]}),m.jsx("div",{style:{display:"grid",gridTemplateColumns:"repeat(2, minmax(0, 1fr))",gap:16},children:[["input_price_per_1m","Input / 1M"],["output_price_per_1m","Output / 1M"],["thinking_price_per_1m","Thinking / 1M"],["cached_input_price_per_1m","Cached / 1M"]].map(([C,D])=>m.jsxs("label",{style:{display:"grid",gap:8},children:[m.jsx("span",{style:{color:"#8aa0c7",fontSize:13},children:D}),m.jsx("input",{type:"number",step:"0.0001",min:"0",value:d[C],onChange:b=>F(C,Number(b.target.value)),style:{padding:12,borderRadius:12,border:"1px solid rgba(148,163,184,.18)",background:"#0f172a",color:"#e2e8f0"}})]},C))}),m.jsxs("div",{style:{display:"grid",gridTemplateColumns:"repeat(2, minmax(0, 1fr))",gap:16},children:[m.jsxs("label",{style:{display:"grid",gap:8},children:[m.jsx("span",{style:{color:"#8aa0c7",fontSize:13},children:"Effective From"}),m.jsx("input",{type:"datetime-local",value:d.effective_from,onChange:C=>F("effective_from",C.target.value),style:{padding:12,borderRadius:12,border:"1px solid rgba(148,163,184,.18)",background:"#0f172a",color:"#e2e8f0"}})]}),m.jsxs("label",{style:{display:"grid",gap:8},children:[m.jsx("span",{style:{color:"#8aa0c7",fontSize:13},children:"Effective To"}),m.jsx("input",{type:"datetime-local",value:d.effective_to??"",onChange:C=>F("effective_to",C.target.value||null),style:{padding:12,borderRadius:12,border:"1px solid rgba(148,163,184,.18)",background:"#0f172a",color:"#e2e8f0"}})]})]}),m.jsxs("div",{style:{display:"flex",gap:12,alignItems:"center",flexWrap:"wrap"},children:[m.jsx("button",{type:"submit",disabled:v.isPending,style:{padding:"12px 18px",borderRadius:12,border:"none",background:v.isPending?"#475569":"linear-gradient(135deg, #22c55e, #14b8a6)",color:"#fff",fontWeight:700,cursor:v.isPending?"wait":"pointer"},children:v.isPending?"Saving...":"Add Pricing"}),h?m.jsx("span",{style:{color:"#86efac"},children:h}):null,w?m.jsx("span",{style:{color:"#fca5a5"},children:w}):null]})]})]}),m.jsx(Ni,{data:i,columns:[{header:"Model ID",cell:C=>String(C.model_id)},{header:"Input / 1M",cell:C=>`$${C.input_price_per_1m.toFixed(4)}`},{header:"Output / 1M",cell:C=>`$${C.output_price_per_1m.toFixed(4)}`},{header:"Thinking / 1M",cell:C=>`$${C.thinking_price_per_1m.toFixed(4)}`},{header:"Cached / 1M",cell:C=>`$${C.cached_input_price_per_1m.toFixed(4)}`},{header:"Currency",cell:C=>C.currency},{header:"Effective From",cell:C=>new Date(C.effective_from).toLocaleString()},{header:"Effective To",cell:C=>C.effective_to?new Date(C.effective_to).toLocaleString():"Current"}]})]})}function Fw(){return m.jsx(qe,{title:"Project Details",description:"Project drilldowns will show cost, tokens, and requests over time."})}function Aw(){const{id:r}=by(),{data:i,isLoading:s,isError:o}=ao();if(s)return m.jsx(qe,{title:"Request Details",description:"Loading request details..."});if(o||!i)return m.jsx(qe,{title:"Request Details",description:"Unable to load request details."});const u=i.find(d=>String(d.id)===r);return u?m.jsxs("div",{style:{display:"grid",gap:24},children:[m.jsxs("div",{className:"page",children:[m.jsx("h1",{children:"Request Details"}),m.jsx("p",{children:u.internal_request_id})]}),m.jsxs("div",{className:"page",style:{display:"grid",gap:10},children:[m.jsxs("div",{children:["Project ID: ",u.project_id]}),m.jsxs("div",{children:["Provider ID: ",u.provider_id]}),m.jsxs("div",{children:["Model ID: ",u.model_id]}),m.jsxs("div",{children:["Timestamp: ",new Date(u.timestamp).toLocaleString()]}),m.jsxs("div",{children:["Latency: ",Math.round(u.latency_ms)," ms"]}),m.jsxs("div",{children:["Status: ",u.status]}),m.jsxs("div",{children:["HTTP Status: ",u.http_status_code??"-"]}),m.jsxs("div",{children:["Input Tokens: ",u.input_tokens]}),m.jsxs("div",{children:["Output Tokens: ",u.output_tokens]}),m.jsxs("div",{children:["Thinking Tokens: ",u.thinking_tokens]}),m.jsxs("div",{children:["Cached Tokens: ",u.cached_tokens]}),m.jsxs("div",{children:["Total Tokens: ",u.total_tokens]}),m.jsxs("div",{children:["Input Cost: $",u.input_cost.toFixed(4)]}),m.jsxs("div",{children:["Output Cost: $",u.output_cost.toFixed(4)]}),m.jsxs("div",{children:["Thinking Cost: $",u.thinking_cost.toFixed(4)]}),m.jsxs("div",{children:["Cached Cost: $",u.cached_cost.toFixed(4)]}),m.jsxs("div",{children:["Total Cost: $",u.total_cost.toFixed(4)]}),m.jsxs("div",{children:["Content Capture: ",u.capture_content?"Enabled":"Disabled"]})]})]}):m.jsx(qe,{title:"Request Details",description:"Request not found."})}function Mw(){return m.jsx(qe,{title:"Errors",description:"Error tracking and request failure trends will appear here."})}function bw(){return m.jsx(qe,{title:"Settings",description:"Workspace settings and notification preferences will appear here."})}const Iw=new Bv;function Uw(){return m.jsx($v,{client:Iw,children:m.jsx(tv,{children:m.jsxs(Et,{element:m.jsx(t0,{}),children:[m.jsx(Et,{path:"/",element:m.jsx(mw,{})}),m.jsx(Et,{path:"/projects",element:m.jsx(vw,{})}),m.jsx(Et,{path:"/usage",element:m.jsx(ww,{})}),m.jsx(Et,{path:"/analytics",element:m.jsx(Cw,{})}),m.jsx(Et,{path:"/providers",element:m.jsx(Rw,{})}),m.jsx(Et,{path:"/models",element:m.jsx(Ow,{})}),m.jsx(Et,{path:"/pricing",element:m.jsx(Dw,{})}),m.jsx(Et,{path:"/usage/:id",element:m.jsx(Aw,{})}),m.jsx(Et,{path:"/projects/:id",element:m.jsx(Fw,{})}),m.jsx(Et,{path:"/errors",element:m.jsx(Mw,{})}),m.jsx(Et,{path:"/settings",element:m.jsx(bw,{})}),m.jsx(Et,{path:"*",element:m.jsx(Yy,{to:"/",replace:!0})})]})})})}ly.createRoot(document.getElementById("root")).render(m.jsx(Xp.StrictMode,{children:m.jsx(uv,{children:m.jsx(Uw,{})})}));
75
+ `+d)}}catch{}}throw o}}_request(i,s){typeof i=="string"?(s=s||{},s.url=i):s=i||{},s=Mr(this.defaults,s);const{transitional:o,paramsSerializer:u,headers:d}=s;o!==void 0&&Kl.assertOptions(o,{silentJSONParsing:at.transitional(at.boolean),forcedJSONParsing:at.transitional(at.boolean),clarifyTimeoutError:at.transitional(at.boolean),legacyInterceptorReqResOrdering:at.transitional(at.boolean),advertiseZstdAcceptEncoding:at.transitional(at.boolean),validateStatusUndefinedResolves:at.transitional(at.boolean)},!1),u!=null&&(k.isFunction(u)?s.paramsSerializer={serialize:u}:Kl.assertOptions(u,{encode:at.function,serialize:at.function},!0)),s.allowAbsoluteUrls!==void 0||(this.defaults.allowAbsoluteUrls!==void 0?s.allowAbsoluteUrls=this.defaults.allowAbsoluteUrls:s.allowAbsoluteUrls=!0),Kl.assertOptions(s,{baseUrl:at.spelling("baseURL"),withXsrfToken:at.spelling("withXSRFToken")},!0),s.method=(s.method||this.defaults.method||"get").toLowerCase();let f=d&&k.merge(d.common,d[s.method]);d&&k.forEach(["delete","get","head","post","put","patch","query","common"],U=>{delete d[U]}),s.headers=ct.concat(f,d);const h=[];let g=!0;this.interceptors.request.forEach(function(F){if(typeof F.runWhen=="function"&&F.runWhen(s)===!1)return;g=g&&F.synchronous;const P=s.transitional||Ku;P&&P.legacyInterceptorReqResOrdering?h.unshift(F.fulfilled,F.rejected):h.push(F.fulfilled,F.rejected)});const w=[];this.interceptors.response.forEach(function(F){w.push(F.fulfilled,F.rejected)});let x,v=0,N;if(!g){const U=[du.bind(this),void 0];for(U.unshift(...h),U.push(...w),N=U.length,x=Promise.resolve(s);v<N;)x=x.then(U[v++],U[v++]);return x}N=h.length;let T=s;for(;v<N;){const U=h[v++],F=h[v++];try{T=U?U(T):T}catch(P){if(!F){x=Promise.reject(P);break}try{const C=F.call(this,P);k.isThenable(C)&&(x=Promise.resolve(C).then(()=>du.call(this,T)))}catch(C){x=Promise.reject(C)}break}}if(!x)try{x=du.call(this,T)}catch(U){x=Promise.reject(U)}for(v=0,N=w.length;v<N;)x=x.then(w[v++],w[v++]);return x}getUri(i){i=Mr(this.defaults,i);const s=$h(i.baseURL,i.url,i.allowAbsoluteUrls,i);return bh(s,i.params,i.paramsSerializer)}};k.forEach(["delete","get","head","options"],function(i){Lr.prototype[i]=function(s,o){return this.request(Mr(o||{},{method:i,url:s,data:o&&k.hasOwnProp(o,"data")?o.data:void 0}))}});k.forEach(["post","put","patch","query"],function(i){function s(o){return function(d,f,h){return this.request(Mr(h||{},{method:i,headers:o?{"Content-Type":"multipart/form-data"}:{},url:d,data:f}))}}Lr.prototype[i]=s(),i!=="query"&&(Lr.prototype[i+"Form"]=s(!0))});let uw=class Vh{constructor(i){if(typeof i!="function")throw new TypeError("executor must be a function.");let s;this.promise=new Promise(function(d){s=d});const o=this;this.promise.then(u=>{if(!o._listeners)return;let d=o._listeners.length;for(;d-- >0;)o._listeners[d](u);o._listeners=null}),this.promise.then=u=>{let d;const f=new Promise(h=>{o.subscribe(h),d=h}).then(u);return f.cancel=function(){o.unsubscribe(d)},f},i(function(d,f,h){o.reason||(o.reason=new Ls(d,f,h),s(o.reason))})}throwIfRequested(){if(this.reason)throw this.reason}subscribe(i){if(this.reason){i(this.reason);return}this._listeners?this._listeners.push(i):this._listeners=[i]}unsubscribe(i){if(!this._listeners)return;const s=this._listeners.indexOf(i);s!==-1&&this._listeners.splice(s,1)}toAbortSignal(){const i=new AbortController,s=o=>{i.abort(o)};return this.subscribe(s),i.signal.unsubscribe=()=>this.unsubscribe(s),i.signal}static source(){let i;return{token:new Vh(function(u){i=u}),cancel:i}}};function cw(r){return function(s){return r.apply(null,s)}}function dw(r){return k.isObject(r)&&r.isAxiosError===!0}const Du={Continue:100,SwitchingProtocols:101,Processing:102,EarlyHints:103,Ok:200,Created:201,Accepted:202,NonAuthoritativeInformation:203,NoContent:204,ResetContent:205,PartialContent:206,MultiStatus:207,AlreadyReported:208,ImUsed:226,MultipleChoices:300,MovedPermanently:301,Found:302,SeeOther:303,NotModified:304,UseProxy:305,Unused:306,TemporaryRedirect:307,PermanentRedirect:308,BadRequest:400,Unauthorized:401,PaymentRequired:402,Forbidden:403,NotFound:404,MethodNotAllowed:405,NotAcceptable:406,ProxyAuthenticationRequired:407,RequestTimeout:408,Conflict:409,Gone:410,LengthRequired:411,PreconditionFailed:412,PayloadTooLarge:413,UriTooLong:414,UnsupportedMediaType:415,RangeNotSatisfiable:416,ExpectationFailed:417,ImATeapot:418,MisdirectedRequest:421,UnprocessableEntity:422,Locked:423,FailedDependency:424,TooEarly:425,UpgradeRequired:426,PreconditionRequired:428,TooManyRequests:429,RequestHeaderFieldsTooLarge:431,UnavailableForLegalReasons:451,InternalServerError:500,NotImplemented:501,BadGateway:502,ServiceUnavailable:503,GatewayTimeout:504,HttpVersionNotSupported:505,VariantAlsoNegotiates:506,InsufficientStorage:507,LoopDetected:508,NotExtended:510,NetworkAuthenticationRequired:511,WebServerReturnsAnUnknownError:520,WebServerIsDown:521,ConnectionTimedOut:522,OriginIsUnreachable:523,TimeoutOccurred:524,SslHandshakeFailed:525,InvalidSslCertificate:526};Object.entries(Du).forEach(([r,i])=>{Du[i]=r});function Kh(r){const i=new Lr(r),s=Ch(Lr.prototype.request,i);return k.extend(s,Lr.prototype,i,{allOwnKeys:!0}),k.extend(s,i,null,{allOwnKeys:!0}),s.create=function(u){return Kh(Mr(r,u))},s}const ze=Kh(Ns);ze.Axios=Lr;ze.CanceledError=Ls;ze.CancelToken=uw;ze.isCancel=zh;ze.VERSION=Xu;ze.toFormData=lo;ze.AxiosError=Q;ze.Cancel=ze.CanceledError;ze.all=function(i){return Promise.all(i)};ze.spread=cw;ze.isAxiosError=dw;ze.mergeConfig=Mr;ze.AxiosHeaders=ct;ze.formToJSON=r=>Uh(k.isHTMLForm(r)?new FormData(r):r);ze.getAdapter=Wh.getAdapter;ze.HttpStatusCode=Du;ze.default=ze;const{Axios:qw,AxiosError:Ww,CanceledError:Vw,isCancel:Kw,CancelToken:Jw,VERSION:Xw,all:Gw,Cancel:Yw,isAxiosError:Zw,spread:eS,toFormData:tS,AxiosHeaders:nS,HttpStatusCode:rS,formToJSON:iS,getAdapter:sS,mergeConfig:lS,create:oS}=ze,kn=ze.create({baseURL:""}),fw=async()=>(await kn.get("/analytics/overview")).data,Jh=()=>ji({queryKey:["overview"],queryFn:fw});function pw(r){const i=new Date,s=new Date(i);return s.setHours(0,0,0,0),r==="today"?s:r==="yesterday"?(s.setDate(s.getDate()-1),s):r==="7d"?(s.setDate(s.getDate()-6),s):r==="30d"?(s.setDate(s.getDate()-29),s):null}function Xh(r,i,s,o="all"){const u=i.trim().toLowerCase(),d=pw(o);return r.filter(f=>{const h=new Date(f.timestamp),g=!d||h>=d,w=!u||f.internal_request_id.toLowerCase().includes(u)||String(f.project_id).includes(u)||String(f.provider_id).includes(u)||String(f.model_id).includes(u),x=s==="all"||f.status===s;return g&&w&&x})}function Gh(r){return{requests:r.length,inputTokens:r.reduce((i,s)=>i+s.input_tokens,0),outputTokens:r.reduce((i,s)=>i+s.output_tokens,0),thinkingTokens:r.reduce((i,s)=>i+s.thinking_tokens,0),cachedTokens:r.reduce((i,s)=>i+s.cached_tokens,0),tokens:r.reduce((i,s)=>i+s.total_tokens,0),cost:r.reduce((i,s)=>i+s.total_cost,0),errors:r.filter(i=>i.status!=="success").length}}const hw=async()=>(await kn.get("/usage")).data,ao=()=>ji({queryKey:["usage"],queryFn:hw});function mw(){const{data:r,isLoading:i,isError:s}=Jh(),o=ao(),[u,d]=M.useState("all"),f=M.useMemo(()=>Xh(o.data??[],"","all",u),[o.data,u]),h=M.useMemo(()=>Gh(f),[f]);return i||o.isLoading?m.jsx(qe,{title:"Overview",description:"Loading dashboard metrics..."}):s||o.isError||!r||!o.data?m.jsx(qe,{title:"Overview",description:"Unable to load analytics."}):m.jsxs("div",{style:{display:"grid",gap:24},children:[m.jsxs("div",{className:"page",children:[m.jsx("h1",{children:"Overview"}),m.jsx("p",{children:"Real-time usage, cost, and reliability snapshot."})]}),m.jsxs("div",{className:"page",style:{display:"grid",gap:12},children:[m.jsx("h2",{children:"Date Range"}),m.jsxs("div",{style:{display:"grid",gap:12,gridTemplateColumns:"1fr 1fr"},children:[m.jsxs("select",{value:u,onChange:g=>d(g.target.value),style:{background:"#0f172a",color:"#e5eefb",border:"1px solid rgba(148,163,184,.18)",borderRadius:10,padding:12},children:[m.jsx("option",{value:"all",children:"All time"}),m.jsx("option",{value:"today",children:"Today"}),m.jsx("option",{value:"yesterday",children:"Yesterday"}),m.jsx("option",{value:"7d",children:"Last 7 days"}),m.jsx("option",{value:"30d",children:"Last 30 days"})]}),m.jsxs("div",{style:{color:"#8aa0c7",alignSelf:"center"},children:["Showing: ",u==="all"?"All time":u]})]})]}),m.jsxs("div",{style:{display:"grid",gridTemplateColumns:"repeat(5, minmax(0, 1fr))",gap:16},children:[m.jsx(ke,{label:"Total Requests",value:String(h.requests)}),m.jsx(ke,{label:"Total Tokens",value:h.tokens.toLocaleString()}),m.jsx(ke,{label:"Total Cost",value:`$${r.cost.toFixed(4)}`}),m.jsx(ke,{label:"Avg Latency",value:`${Math.round(r.average_latency_ms)} ms`}),m.jsx(ke,{label:"Error Rate",value:`${r.error_rate.toFixed(2)}%`})]}),m.jsxs("div",{className:"page",children:[m.jsx("h2",{children:"What to watch"}),m.jsxs("ul",{children:[m.jsx("li",{children:"Track pricing changes through versioned records only."}),m.jsx("li",{children:"Use the usage table to inspect provider and model mix."}),m.jsx("li",{children:"Keep prompts, responses, and secrets off the local store."})]})]})]})}function Ni({columns:r,data:i,emptyMessage:s="No rows found."}){return m.jsx("div",{style:{border:"1px solid rgba(148,163,184,.18)",borderRadius:16,overflow:"hidden",background:"rgba(15,23,42,.72)"},children:m.jsxs("table",{style:{width:"100%",borderCollapse:"collapse"},children:[m.jsx("thead",{children:m.jsx("tr",{children:r.map(o=>m.jsx("th",{style:{textAlign:"left",padding:14,color:"#8aa0c7",fontSize:13,borderBottom:"1px solid rgba(148,163,184,.12)"},children:o.header},o.header))})}),m.jsx("tbody",{children:i.length===0?m.jsx("tr",{children:m.jsx("td",{colSpan:r.length,style:{padding:18,color:"#8aa0c7"},children:s})}):i.map((o,u)=>m.jsx("tr",{children:r.map(d=>m.jsx("td",{style:{padding:14,borderBottom:"1px solid rgba(148,163,184,.08)"},children:d.cell(o)},d.header))},u))})]})})}const gw=async()=>(await kn.get("/projects")).data,yw=()=>ji({queryKey:["projects"],queryFn:gw});function vw(){const{data:r,isLoading:i,isError:s}=yw();return i?m.jsx(qe,{title:"Projects",description:"Loading projects..."}):s||!r?m.jsx(qe,{title:"Projects",description:"Unable to load projects."}):m.jsxs("div",{style:{display:"grid",gap:24},children:[m.jsxs("div",{className:"page",children:[m.jsx("h1",{children:"Projects"}),m.jsx("p",{children:"Project-level usage and cost breakdown."})]}),m.jsxs("div",{style:{display:"grid",gridTemplateColumns:"repeat(3, minmax(0, 1fr))",gap:16},children:[m.jsx(ke,{label:"Projects",value:String(r.length)}),m.jsx(ke,{label:"Production",value:String(r.filter(o=>o.environment==="production").length)}),m.jsx(ke,{label:"Development",value:String(r.filter(o=>o.environment!=="production").length)})]}),m.jsx(Ni,{data:r,columns:[{header:"Name",cell:o=>o.name},{header:"Environment",cell:o=>o.environment},{header:"Description",cell:o=>o.description||"-"},{header:"Created",cell:o=>new Date(o.created_at).toLocaleString()}]})]})}function ww(){const{data:r,isLoading:i,isError:s}=ao(),[o,u]=M.useState(""),[d,f]=M.useState("all"),[h,g]=M.useState("all"),[w,x]=M.useState(null),v=M.useMemo(()=>Xh(r??[],o,d,h),[r,o,d,h]),N=M.useMemo(()=>Gh(r??[]),[r]);return i?m.jsx(qe,{title:"Usage",description:"Loading API usage..."}):s||!r?m.jsx(qe,{title:"Usage",description:"Unable to load usage records."}):m.jsxs("div",{style:{display:"grid",gap:24},children:[m.jsxs("div",{className:"page",children:[m.jsx("h1",{children:"Usage"}),m.jsx("p",{children:"Recent tracked requests."})]}),m.jsxs("div",{style:{display:"grid",gridTemplateColumns:"repeat(4, minmax(0, 1fr))",gap:16},children:[m.jsx(ke,{label:"Requests",value:String(N.requests)}),m.jsx(ke,{label:"Input Tokens",value:N.inputTokens.toLocaleString()}),m.jsx(ke,{label:"Output Tokens",value:N.outputTokens.toLocaleString()}),m.jsx(ke,{label:"Total Tokens",value:N.tokens.toLocaleString()})]}),m.jsxs("div",{style:{display:"grid",gridTemplateColumns:"repeat(4, minmax(0, 1fr))",gap:16},children:[m.jsx(ke,{label:"Thinking Tokens",value:N.thinkingTokens.toLocaleString()}),m.jsx(ke,{label:"Cached Tokens",value:N.cachedTokens.toLocaleString()}),m.jsx(ke,{label:"Cost",value:`$${N.cost.toFixed(4)}`}),m.jsx(ke,{label:"Errors",value:String(N.errors)})]}),m.jsxs("div",{className:"page",style:{display:"grid",gap:12},children:[m.jsx("h2",{children:"Filters"}),m.jsxs("div",{style:{display:"grid",gap:12,gridTemplateColumns:"2fr 1fr 1fr"},children:[m.jsx("input",{value:o,onChange:T=>u(T.target.value),placeholder:"Search request id, project id, provider id, model id",style:{background:"#0f172a",color:"#e5eefb",border:"1px solid rgba(148,163,184,.18)",borderRadius:10,padding:12}}),m.jsxs("select",{value:d,onChange:T=>f(T.target.value),style:{background:"#0f172a",color:"#e5eefb",border:"1px solid rgba(148,163,184,.18)",borderRadius:10,padding:12},children:[m.jsx("option",{value:"all",children:"All statuses"}),m.jsx("option",{value:"success",children:"Success"}),m.jsx("option",{value:"error",children:"Error"})]}),m.jsxs("select",{value:h,onChange:T=>g(T.target.value),style:{background:"#0f172a",color:"#e5eefb",border:"1px solid rgba(148,163,184,.18)",borderRadius:10,padding:12},children:[m.jsx("option",{value:"all",children:"All time"}),m.jsx("option",{value:"today",children:"Today"}),m.jsx("option",{value:"yesterday",children:"Yesterday"}),m.jsx("option",{value:"7d",children:"Last 7 days"}),m.jsx("option",{value:"30d",children:"Last 30 days"})]})]})]}),m.jsx(Ni,{data:v,columns:[{header:"Timestamp",cell:T=>new Date(T.timestamp).toLocaleString()},{header:"Project",cell:T=>String(T.project_id)},{header:"Provider",cell:T=>String(T.provider_id)},{header:"Model",cell:T=>String(T.model_id)},{header:"Request ID",cell:T=>m.jsx("button",{onClick:()=>x(T),style:{background:"none",color:"#93c5fd",border:0,padding:0,cursor:"pointer"},children:T.internal_request_id})},{header:"Tokens",cell:T=>T.total_tokens.toLocaleString()},{header:"Cost",cell:T=>`$${T.total_cost.toFixed(4)}`},{header:"Latency",cell:T=>`${Math.round(T.latency_ms)} ms`},{header:"Status",cell:T=>T.status}]}),w?m.jsx("div",{onClick:()=>x(null),style:{position:"fixed",inset:0,background:"rgba(2,6,23,.72)",backdropFilter:"blur(6px)",display:"grid",placeItems:"center",padding:24,zIndex:50},children:m.jsxs("div",{onClick:T=>T.stopPropagation(),style:{width:"min(820px, 100%)",maxHeight:"90vh",overflow:"auto",background:"linear-gradient(180deg, #0f172a, #111827)",border:"1px solid rgba(148,163,184,.2)",borderRadius:18,padding:24,display:"grid",gap:14,boxShadow:"0 24px 80px rgba(0,0,0,.45)"},children:[m.jsxs("div",{style:{display:"flex",justifyContent:"space-between",gap:16},children:[m.jsxs("div",{children:[m.jsx("h2",{style:{margin:0},children:"Request Details"}),m.jsx("p",{style:{margin:"6px 0 0",color:"#8aa0c7"},children:w.internal_request_id})]}),m.jsx("button",{onClick:()=>x(null),style:{background:"#1f2937",color:"#e5eefb",border:0,borderRadius:10,padding:"8px 12px"},children:"Close"})]}),m.jsxs("div",{style:{display:"grid",gridTemplateColumns:"repeat(2, minmax(0, 1fr))",gap:12},children:[m.jsxs("div",{style:{background:"rgba(15,23,42,.7)",border:"1px solid rgba(148,163,184,.12)",borderRadius:12,padding:12},children:["Project ID: ",w.project_id]}),m.jsxs("div",{style:{background:"rgba(15,23,42,.7)",border:"1px solid rgba(148,163,184,.12)",borderRadius:12,padding:12},children:["Provider ID: ",w.provider_id]}),m.jsxs("div",{style:{background:"rgba(15,23,42,.7)",border:"1px solid rgba(148,163,184,.12)",borderRadius:12,padding:12},children:["Model ID: ",w.model_id]}),m.jsxs("div",{style:{background:"rgba(15,23,42,.7)",border:"1px solid rgba(148,163,184,.12)",borderRadius:12,padding:12},children:["Timestamp: ",new Date(w.timestamp).toLocaleString()]}),m.jsxs("div",{style:{background:"rgba(15,23,42,.7)",border:"1px solid rgba(148,163,184,.12)",borderRadius:12,padding:12},children:["Latency: ",Math.round(w.latency_ms)," ms"]}),m.jsxs("div",{style:{background:"rgba(15,23,42,.7)",border:"1px solid rgba(148,163,184,.12)",borderRadius:12,padding:12},children:["Status: ",w.status]}),m.jsxs("div",{style:{background:"rgba(15,23,42,.7)",border:"1px solid rgba(148,163,184,.12)",borderRadius:12,padding:12},children:["HTTP Status: ",w.http_status_code??"-"]}),m.jsxs("div",{style:{background:"rgba(15,23,42,.7)",border:"1px solid rgba(148,163,184,.12)",borderRadius:12,padding:12},children:["Capture Content: ",w.capture_content?"Enabled":"Disabled"]}),m.jsxs("div",{style:{background:"rgba(15,23,42,.7)",border:"1px solid rgba(148,163,184,.12)",borderRadius:12,padding:12},children:["Input Tokens: ",w.input_tokens]}),m.jsxs("div",{style:{background:"rgba(15,23,42,.7)",border:"1px solid rgba(148,163,184,.12)",borderRadius:12,padding:12},children:["Output Tokens: ",w.output_tokens]}),m.jsxs("div",{style:{background:"rgba(15,23,42,.7)",border:"1px solid rgba(148,163,184,.12)",borderRadius:12,padding:12},children:["Thinking Tokens: ",w.thinking_tokens]}),m.jsxs("div",{style:{background:"rgba(15,23,42,.7)",border:"1px solid rgba(148,163,184,.12)",borderRadius:12,padding:12},children:["Cached Tokens: ",w.cached_tokens]}),m.jsxs("div",{style:{background:"rgba(15,23,42,.7)",border:"1px solid rgba(148,163,184,.12)",borderRadius:12,padding:12},children:["Total Tokens: ",w.total_tokens]}),m.jsxs("div",{style:{background:"rgba(15,23,42,.7)",border:"1px solid rgba(148,163,184,.12)",borderRadius:12,padding:12},children:["Input Cost: $",w.input_cost.toFixed(4)]}),m.jsxs("div",{style:{background:"rgba(15,23,42,.7)",border:"1px solid rgba(148,163,184,.12)",borderRadius:12,padding:12},children:["Output Cost: $",w.output_cost.toFixed(4)]}),m.jsxs("div",{style:{background:"rgba(15,23,42,.7)",border:"1px solid rgba(148,163,184,.12)",borderRadius:12,padding:12},children:["Thinking Cost: $",w.thinking_cost.toFixed(4)]}),m.jsxs("div",{style:{background:"rgba(15,23,42,.7)",border:"1px solid rgba(148,163,184,.12)",borderRadius:12,padding:12},children:["Cached Cost: $",w.cached_cost.toFixed(4)]}),m.jsxs("div",{style:{background:"rgba(15,23,42,.7)",border:"1px solid rgba(148,163,184,.12)",borderRadius:12,padding:12},children:["Total Cost: $",w.total_cost.toFixed(4)]})]}),w.error_type?m.jsxs("div",{children:["Error Type: ",w.error_type]}):null,m.jsx("div",{style:{display:"flex",justifyContent:"flex-end"},children:m.jsx(ch,{to:`/usage/${w.id}`,children:"Open dedicated view"})})]})}):null]})}function Sw({label:r,value:i,max:s}){const o=s>0?Math.max(i/s*100,4):4;return m.jsxs("div",{style:{display:"grid",gap:8},children:[m.jsxs("div",{style:{display:"flex",justifyContent:"space-between",color:"#c7d2fe",fontSize:13},children:[m.jsx("span",{children:r}),m.jsx("span",{children:i.toLocaleString()})]}),m.jsx("div",{style:{height:10,borderRadius:999,background:"rgba(148,163,184,.14)",overflow:"hidden"},children:m.jsx("div",{style:{width:`${o}%`,height:"100%",background:"linear-gradient(90deg, #60a5fa, #34d399)"}})})]})}function xw(r){return r.reduce((i,s)=>(i[s.status]=(i[s.status]||0)+1,i),{})}function Ew(r){return Math.max(...Object.values(r),1)}function Cw(){const r=Jh(),i=ao();if(r.isLoading||i.isLoading)return m.jsx(qe,{title:"Analytics",description:"Loading analytics..."});if(r.isError||i.isError||!r.data||!i.data)return m.jsx(qe,{title:"Analytics",description:"Unable to load analytics."});const s=xw(i.data),o=Ew(s);return m.jsxs("div",{style:{display:"grid",gap:24},children:[m.jsxs("div",{className:"page",children:[m.jsx("h1",{children:"Analytics"}),m.jsx("p",{children:"Cost, usage, and reliability snapshots."})]}),m.jsxs("div",{style:{display:"grid",gridTemplateColumns:"repeat(4, minmax(0, 1fr))",gap:16},children:[m.jsx(ke,{label:"Requests",value:String(r.data.requests)}),m.jsx(ke,{label:"Tokens",value:r.data.tokens.toLocaleString()}),m.jsx(ke,{label:"Cost",value:`$${r.data.cost.toFixed(4)}`}),m.jsx(ke,{label:"Error Rate",value:`${r.data.error_rate.toFixed(2)}%`})]}),m.jsxs("div",{className:"page",children:[m.jsx("h2",{children:"Request Status"}),m.jsx("div",{style:{display:"grid",gap:14,marginTop:16},children:Object.entries(s).map(([u,d])=>m.jsx(Sw,{label:u,value:d,max:o},u))})]}),m.jsx(Ni,{data:Object.entries(s).map(([u,d])=>({status:u,count:d})),columns:[{header:"Status",cell:u=>u.status},{header:"Count",cell:u=>String(u.count)}],emptyMessage:"No usage yet."})]})}const kw=async()=>(await kn.get("/providers")).data,_w=async r=>(await kn.post("/providers",{name:r})).data,Yh=()=>ji({queryKey:["providers"],queryFn:kw});function Rw(){var N;const r=js(),{data:i,isLoading:s,isError:o}=Yh(),[u,d]=M.useState(""),[f,h]=M.useState(null),[g,w]=M.useState(null),x=Qu({mutationFn:_w,onSuccess:async()=>{await r.invalidateQueries({queryKey:["providers"]}),d(""),h("Provider added successfully."),w(null)},onError:()=>{h(null),w("Unable to add provider. Please try again.")}}),v=T=>{if(T.preventDefault(),h(null),w(null),!u.trim()){w("Provider name is required.");return}x.mutate(u.trim())};return s?m.jsx(qe,{title:"Providers",description:"Loading providers..."}):o||!i?m.jsx(qe,{title:"Providers",description:"Unable to load providers."}):m.jsxs("div",{style:{display:"grid",gap:24},children:[m.jsxs("div",{className:"page",children:[m.jsx("h1",{children:"Providers"}),m.jsx("p",{children:"Registered API providers in the local tracker."})]}),m.jsxs("div",{style:{border:"1px solid rgba(148,163,184,.18)",borderRadius:20,background:"linear-gradient(180deg, rgba(15,23,42,.92), rgba(15,23,42,.76))",padding:20,display:"grid",gap:16},children:[m.jsxs("div",{children:[m.jsx("h2",{style:{margin:0},children:"Add Provider"}),m.jsx("p",{style:{margin:"6px 0 0",color:"#8aa0c7"},children:"Create a local provider record for tracking usage and models."})]}),m.jsxs("form",{onSubmit:v,style:{display:"flex",gap:12,flexWrap:"wrap",alignItems:"center"},children:[m.jsx("input",{value:u,onChange:T=>d(T.target.value),placeholder:"Provider name",style:{minWidth:280,padding:12,borderRadius:12,border:"1px solid rgba(148,163,184,.18)",background:"#0f172a",color:"#e2e8f0"}}),m.jsx("button",{type:"submit",disabled:x.isPending,style:{padding:"12px 18px",borderRadius:12,border:"none",background:x.isPending?"#475569":"linear-gradient(135deg, #22c55e, #14b8a6)",color:"#fff",fontWeight:700,cursor:x.isPending?"wait":"pointer"},children:x.isPending?"Saving...":"Add Provider"}),f?m.jsx("span",{style:{color:"#86efac"},children:f}):null,g?m.jsx("span",{style:{color:"#fca5a5"},children:g}):null]})]}),m.jsxs("div",{style:{display:"grid",gridTemplateColumns:"repeat(3, minmax(0, 1fr))",gap:16},children:[m.jsx(ke,{label:"Providers",value:String(i.length)}),m.jsx(ke,{label:"Active Names",value:String(new Set(i.map(T=>T.name)).size)}),m.jsx(ke,{label:"Newest ID",value:String(((N=i[0])==null?void 0:N.id)??0)})]}),m.jsx(Ni,{data:i,columns:[{header:"ID",cell:T=>String(T.id)},{header:"Name",cell:T=>T.name},{header:"Created",cell:T=>new Date(T.created_at).toLocaleString()}]})]})}const Pw=async()=>(await kn.get("/models")).data,jw=async r=>(await kn.post("/models",r)).data,Zh=()=>ji({queryKey:["models"],queryFn:Pw});function Ow(){const r=js(),{data:i,isLoading:s,isError:o}=Zh(),{data:u=[]}=Yh(),[d,f]=M.useState(0),[h,g]=M.useState(""),[w,x]=M.useState("text"),[v,N]=M.useState(null),[T,U]=M.useState(null),F=M.useMemo(()=>u.map(D=>({id:D.id,label:`${D.name} (#${D.id})`})),[u]),P=Qu({mutationFn:jw,onSuccess:async()=>{await r.invalidateQueries({queryKey:["models"]}),f(0),g(""),x("text"),N("Model added successfully."),U(null)},onError:()=>{N(null),U("Unable to add model. Please check the form and try again.")}}),C=D=>{if(D.preventDefault(),N(null),U(null),!d){U("Provider is required.");return}if(!h.trim()){U("Model name is required.");return}P.mutate({provider_id:d,model_name:h.trim(),model_type:w})};return s?m.jsx(qe,{title:"Models",description:"Loading models..."}):o||!i?m.jsx(qe,{title:"Models",description:"Unable to load models."}):m.jsxs("div",{style:{display:"grid",gap:24},children:[m.jsxs("div",{className:"page",children:[m.jsx("h1",{children:"Models"}),m.jsx("p",{children:"Model registry and provider mappings."})]}),m.jsxs("div",{style:{border:"1px solid rgba(148,163,184,.18)",borderRadius:20,background:"linear-gradient(180deg, rgba(15,23,42,.92), rgba(15,23,42,.76))",padding:20,display:"grid",gap:16},children:[m.jsxs("div",{children:[m.jsx("h2",{style:{margin:0},children:"Add Model"}),m.jsx("p",{style:{margin:"6px 0 0",color:"#8aa0c7"},children:"Create a new local model mapping for a provider."})]}),m.jsxs("form",{onSubmit:C,style:{display:"grid",gap:16},children:[m.jsxs("div",{style:{display:"grid",gridTemplateColumns:"repeat(2, minmax(0, 1fr))",gap:16},children:[m.jsxs("label",{style:{display:"grid",gap:8},children:[m.jsx("span",{style:{color:"#8aa0c7",fontSize:13},children:"Provider"}),m.jsxs("select",{value:d,onChange:D=>f(Number(D.target.value)),style:{padding:12,borderRadius:12,border:"1px solid rgba(148,163,184,.18)",background:"#0f172a",color:"#e2e8f0"},children:[m.jsx("option",{value:0,children:"Select a provider"}),F.map(D=>m.jsx("option",{value:D.id,children:D.label},D.id))]})]}),m.jsxs("label",{style:{display:"grid",gap:8},children:[m.jsx("span",{style:{color:"#8aa0c7",fontSize:13},children:"Model Type"}),m.jsxs("select",{value:w,onChange:D=>x(D.target.value),style:{padding:12,borderRadius:12,border:"1px solid rgba(148,163,184,.18)",background:"#0f172a",color:"#e2e8f0"},children:[m.jsx("option",{value:"text",children:"text"}),m.jsx("option",{value:"vision",children:"vision"}),m.jsx("option",{value:"embedding",children:"embedding"}),m.jsx("option",{value:"audio",children:"audio"}),m.jsx("option",{value:"chat",children:"chat"})]})]})]}),m.jsxs("label",{style:{display:"grid",gap:8},children:[m.jsx("span",{style:{color:"#8aa0c7",fontSize:13},children:"Model Name"}),m.jsx("input",{value:h,onChange:D=>g(D.target.value),placeholder:"gemini-2.5-flash",style:{padding:12,borderRadius:12,border:"1px solid rgba(148,163,184,.18)",background:"#0f172a",color:"#e2e8f0"}})]}),m.jsxs("div",{style:{display:"flex",gap:12,alignItems:"center",flexWrap:"wrap"},children:[m.jsx("button",{type:"submit",disabled:P.isPending,style:{padding:"12px 18px",borderRadius:12,border:"none",background:P.isPending?"#475569":"linear-gradient(135deg, #22c55e, #14b8a6)",color:"#fff",fontWeight:700,cursor:P.isPending?"wait":"pointer"},children:P.isPending?"Saving...":"Add Model"}),v?m.jsx("span",{style:{color:"#86efac"},children:v}):null,T?m.jsx("span",{style:{color:"#fca5a5"},children:T}):null]})]})]}),m.jsxs("div",{style:{display:"grid",gridTemplateColumns:"repeat(3, minmax(0, 1fr))",gap:16},children:[m.jsx(ke,{label:"Models",value:String(i.length)}),m.jsx(ke,{label:"Text Models",value:String(i.filter(D=>D.model_type==="text").length)}),m.jsx(ke,{label:"Providers",value:String(new Set(i.map(D=>D.provider_id)).size)})]}),m.jsx(Ni,{data:i,columns:[{header:"ID",cell:D=>String(D.id)},{header:"Provider ID",cell:D=>String(D.provider_id)},{header:"Model Name",cell:D=>D.model_name},{header:"Type",cell:D=>D.model_type},{header:"Created",cell:D=>new Date(D.created_at).toLocaleString()}]})]})}const Tw=async()=>(await kn.get("/pricing")).data,Nw=async r=>(await kn.post("/pricing",r)).data,Lw=()=>ji({queryKey:["pricing"],queryFn:Tw}),Mp={model_id:0,input_price_per_1m:0,output_price_per_1m:0,thinking_price_per_1m:0,cached_input_price_per_1m:0,currency:"USD",effective_from:new Date().toISOString().slice(0,16),effective_to:null};function bp(r){return`${r}:00`}function Dw(){const r=js(),{data:i,isLoading:s,isError:o}=Lw(),{data:u=[]}=Zh(),[d,f]=M.useState(Mp),[h,g]=M.useState(null),[w,x]=M.useState(null),v=Qu({mutationFn:Nw,onSuccess:async()=>{await r.invalidateQueries({queryKey:["pricing"]}),g("Pricing row added locally and refreshed."),x(null),f(Mp)},onError:()=>{g(null),x("Unable to add pricing row. Check the form values and try again.")}}),N=M.useMemo(()=>u.map(C=>({id:C.id,label:`${C.model_name} (#${C.id})`})),[u]);if(s)return m.jsx(qe,{title:"Pricing",description:"Loading pricing versions..."});if(o||!i)return m.jsx(qe,{title:"Pricing",description:"Unable to load pricing."});const T=i.filter(C=>!C.effective_to).length,U=new Set(i.map(C=>C.model_id)).size,F=(C,D)=>{f(b=>({...b,[C]:D}))},P=C=>{if(C.preventDefault(),g(null),x(null),!d.model_id){x("Please select a model.");return}v.mutate({...d,effective_from:bp(d.effective_from),effective_to:d.effective_to?bp(d.effective_to):null})};return m.jsxs("div",{style:{display:"grid",gap:24},children:[m.jsxs("div",{className:"page",children:[m.jsx("h1",{children:"Pricing"}),m.jsx("p",{children:"Versioned pricing records drive historical cost calculation."})]}),m.jsxs("div",{style:{display:"grid",gridTemplateColumns:"repeat(3, minmax(0, 1fr))",gap:16},children:[m.jsx(ke,{label:"Pricing Rows",value:String(i.length)}),m.jsx(ke,{label:"Current",value:String(T)}),m.jsx(ke,{label:"Models Covered",value:String(U)})]}),m.jsxs("div",{style:{border:"1px solid rgba(148,163,184,.18)",borderRadius:20,background:"linear-gradient(180deg, rgba(15,23,42,.92), rgba(15,23,42,.76))",padding:20,display:"grid",gap:16},children:[m.jsxs("div",{children:[m.jsx("h2",{style:{margin:0},children:"Add Pricing"}),m.jsx("p",{style:{margin:"6px 0 0",color:"#8aa0c7"},children:"Create a new versioned pricing row. The new entry is stored locally in your backend database only."})]}),m.jsxs("form",{onSubmit:P,style:{display:"grid",gap:16},children:[m.jsxs("div",{style:{display:"grid",gridTemplateColumns:"repeat(2, minmax(0, 1fr))",gap:16},children:[m.jsxs("label",{style:{display:"grid",gap:8},children:[m.jsx("span",{style:{color:"#8aa0c7",fontSize:13},children:"Model"}),m.jsxs("select",{value:d.model_id,onChange:C=>F("model_id",Number(C.target.value)),style:{padding:12,borderRadius:12,border:"1px solid rgba(148,163,184,.18)",background:"#0f172a",color:"#e2e8f0"},children:[m.jsx("option",{value:0,children:"Select a model"}),N.map(C=>m.jsx("option",{value:C.id,children:C.label},C.id))]})]}),m.jsxs("label",{style:{display:"grid",gap:8},children:[m.jsx("span",{style:{color:"#8aa0c7",fontSize:13},children:"Currency"}),m.jsx("input",{value:d.currency,onChange:C=>F("currency",C.target.value.toUpperCase()),style:{padding:12,borderRadius:12,border:"1px solid rgba(148,163,184,.18)",background:"#0f172a",color:"#e2e8f0"}})]})]}),m.jsx("div",{style:{display:"grid",gridTemplateColumns:"repeat(2, minmax(0, 1fr))",gap:16},children:[["input_price_per_1m","Input / 1M"],["output_price_per_1m","Output / 1M"],["thinking_price_per_1m","Thinking / 1M"],["cached_input_price_per_1m","Cached / 1M"]].map(([C,D])=>m.jsxs("label",{style:{display:"grid",gap:8},children:[m.jsx("span",{style:{color:"#8aa0c7",fontSize:13},children:D}),m.jsx("input",{type:"number",step:"0.0001",min:"0",value:d[C],onChange:b=>F(C,Number(b.target.value)),style:{padding:12,borderRadius:12,border:"1px solid rgba(148,163,184,.18)",background:"#0f172a",color:"#e2e8f0"}})]},C))}),m.jsxs("div",{style:{display:"grid",gridTemplateColumns:"repeat(2, minmax(0, 1fr))",gap:16},children:[m.jsxs("label",{style:{display:"grid",gap:8},children:[m.jsx("span",{style:{color:"#8aa0c7",fontSize:13},children:"Effective From"}),m.jsx("input",{type:"datetime-local",value:d.effective_from,onChange:C=>F("effective_from",C.target.value),style:{padding:12,borderRadius:12,border:"1px solid rgba(148,163,184,.18)",background:"#0f172a",color:"#e2e8f0"}})]}),m.jsxs("label",{style:{display:"grid",gap:8},children:[m.jsx("span",{style:{color:"#8aa0c7",fontSize:13},children:"Effective To"}),m.jsx("input",{type:"datetime-local",value:d.effective_to??"",onChange:C=>F("effective_to",C.target.value||null),style:{padding:12,borderRadius:12,border:"1px solid rgba(148,163,184,.18)",background:"#0f172a",color:"#e2e8f0"}})]})]}),m.jsxs("div",{style:{display:"flex",gap:12,alignItems:"center",flexWrap:"wrap"},children:[m.jsx("button",{type:"submit",disabled:v.isPending,style:{padding:"12px 18px",borderRadius:12,border:"none",background:v.isPending?"#475569":"linear-gradient(135deg, #22c55e, #14b8a6)",color:"#fff",fontWeight:700,cursor:v.isPending?"wait":"pointer"},children:v.isPending?"Saving...":"Add Pricing"}),h?m.jsx("span",{style:{color:"#86efac"},children:h}):null,w?m.jsx("span",{style:{color:"#fca5a5"},children:w}):null]})]})]}),m.jsx(Ni,{data:i,columns:[{header:"Model ID",cell:C=>String(C.model_id)},{header:"Input / 1M",cell:C=>`$${C.input_price_per_1m.toFixed(4)}`},{header:"Output / 1M",cell:C=>`$${C.output_price_per_1m.toFixed(4)}`},{header:"Thinking / 1M",cell:C=>`$${C.thinking_price_per_1m.toFixed(4)}`},{header:"Cached / 1M",cell:C=>`$${C.cached_input_price_per_1m.toFixed(4)}`},{header:"Currency",cell:C=>C.currency},{header:"Effective From",cell:C=>new Date(C.effective_from).toLocaleString()},{header:"Effective To",cell:C=>C.effective_to?new Date(C.effective_to).toLocaleString():"Current"}]})]})}function Fw(){return m.jsx(qe,{title:"Project Details",description:"Project drilldowns will show cost, tokens, and requests over time."})}function Aw(){const{id:r}=by(),{data:i,isLoading:s,isError:o}=ao();if(s)return m.jsx(qe,{title:"Request Details",description:"Loading request details..."});if(o||!i)return m.jsx(qe,{title:"Request Details",description:"Unable to load request details."});const u=i.find(d=>String(d.id)===r);return u?m.jsxs("div",{style:{display:"grid",gap:24},children:[m.jsxs("div",{className:"page",children:[m.jsx("h1",{children:"Request Details"}),m.jsx("p",{children:u.internal_request_id})]}),m.jsxs("div",{className:"page",style:{display:"grid",gap:10},children:[m.jsxs("div",{children:["Project ID: ",u.project_id]}),m.jsxs("div",{children:["Provider ID: ",u.provider_id]}),m.jsxs("div",{children:["Model ID: ",u.model_id]}),m.jsxs("div",{children:["Timestamp: ",new Date(u.timestamp).toLocaleString()]}),m.jsxs("div",{children:["Latency: ",Math.round(u.latency_ms)," ms"]}),m.jsxs("div",{children:["Status: ",u.status]}),m.jsxs("div",{children:["HTTP Status: ",u.http_status_code??"-"]}),m.jsxs("div",{children:["Input Tokens: ",u.input_tokens]}),m.jsxs("div",{children:["Output Tokens: ",u.output_tokens]}),m.jsxs("div",{children:["Thinking Tokens: ",u.thinking_tokens]}),m.jsxs("div",{children:["Cached Tokens: ",u.cached_tokens]}),m.jsxs("div",{children:["Total Tokens: ",u.total_tokens]}),m.jsxs("div",{children:["Input Cost: $",u.input_cost.toFixed(4)]}),m.jsxs("div",{children:["Output Cost: $",u.output_cost.toFixed(4)]}),m.jsxs("div",{children:["Thinking Cost: $",u.thinking_cost.toFixed(4)]}),m.jsxs("div",{children:["Cached Cost: $",u.cached_cost.toFixed(4)]}),m.jsxs("div",{children:["Total Cost: $",u.total_cost.toFixed(4)]}),m.jsxs("div",{children:["Content Capture: ",u.capture_content?"Enabled":"Disabled"]})]})]}):m.jsx(qe,{title:"Request Details",description:"Request not found."})}function Mw(){return m.jsx(qe,{title:"Errors",description:"Error tracking and request failure trends will appear here."})}function bw(){return m.jsx(qe,{title:"Settings",description:"Workspace settings and notification preferences will appear here."})}const Iw=new Bv;function Uw(){return m.jsx($v,{client:Iw,children:m.jsx(tv,{children:m.jsxs(Et,{element:m.jsx(t0,{}),children:[m.jsx(Et,{path:"/",element:m.jsx(mw,{})}),m.jsx(Et,{path:"/projects",element:m.jsx(vw,{})}),m.jsx(Et,{path:"/usage",element:m.jsx(ww,{})}),m.jsx(Et,{path:"/analytics",element:m.jsx(Cw,{})}),m.jsx(Et,{path:"/providers",element:m.jsx(Rw,{})}),m.jsx(Et,{path:"/models",element:m.jsx(Ow,{})}),m.jsx(Et,{path:"/pricing",element:m.jsx(Dw,{})}),m.jsx(Et,{path:"/usage/:id",element:m.jsx(Aw,{})}),m.jsx(Et,{path:"/projects/:id",element:m.jsx(Fw,{})}),m.jsx(Et,{path:"/errors",element:m.jsx(Mw,{})}),m.jsx(Et,{path:"/settings",element:m.jsx(bw,{})}),m.jsx(Et,{path:"*",element:m.jsx(Yy,{to:"/",replace:!0})})]})})})}ly.createRoot(document.getElementById("root")).render(m.jsx(Xp.StrictMode,{children:m.jsx(uv,{children:m.jsx(Uw,{})})}));
@@ -4,7 +4,7 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>API Tracker</title>
7
- <script type="module" crossorigin src="/assets/index-jlcpybVb.js"></script>
7
+ <script type="module" crossorigin src="/assets/index-M74b_d8l.js"></script>
8
8
  <link rel="stylesheet" crossorigin href="/assets/index-3YVy8dav.css">
9
9
  </head>
10
10
  <body>
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: llmapi-tracker
3
- Version: 1.0.7
3
+ Version: 1.0.8
4
4
  Summary: Local-first API usage and cost tracking platform
5
5
  Author: API Tracker
6
- License: MIT
6
+ License-Expression: MIT
7
7
  Project-URL: Homepage, https://github.com/Lns9777/API-Usage-Tracker
8
8
  Project-URL: Repository, https://github.com/Lns9777/API-Usage-Tracker
9
9
  Project-URL: Issues, https://github.com/Lns9777/API-Usage-Tracker/issues
@@ -22,7 +22,7 @@ backend/app/services/cost_service.py
22
22
  backend/app/services/usage_service.py
23
23
  backend/app/static/index.html
24
24
  backend/app/static/assets/index-3YVy8dav.css
25
- backend/app/static/assets/index-jlcpybVb.js
25
+ backend/app/static/assets/index-M74b_d8l.js
26
26
  llmapi_tracker.egg-info/PKG-INFO
27
27
  llmapi_tracker.egg-info/SOURCES.txt
28
28
  llmapi_tracker.egg-info/dependency_links.txt
@@ -41,6 +41,7 @@ sdk/api_tracker/providers/gemini.py
41
41
  sdk/api_tracker/providers/openai.py
42
42
  tests/test_analytics_routes.py
43
43
  tests/test_cost_service.py
44
+ tests/test_launcher.py
44
45
  tests/test_paths.py
45
46
  tests/test_provider_model_routes.py
46
47
  tests/test_routes.py
@@ -5,11 +5,11 @@ build-backend = "setuptools.build_meta"
5
5
 
6
6
  [project]
7
7
  name = "llmapi-tracker"
8
- version = "1.0.7"
8
+ version = "1.0.8"
9
9
  description = "Local-first API usage and cost tracking platform"
10
10
  readme = "README.md"
11
11
  requires-python = ">=3.10"
12
- license = { text = "MIT" }
12
+ license = "MIT"
13
13
  authors = [
14
14
  { name = "API Tracker" }
15
15
  ]
@@ -53,6 +53,8 @@ packages = [
53
53
  "backend.app",
54
54
  "backend.app.routes",
55
55
  "backend.app.services",
56
+ "backend.app.static",
57
+ "backend.app.static.assets",
56
58
  "api_tracker",
57
59
  "api_tracker.providers",
58
60
  ]
@@ -60,9 +62,9 @@ packages = [
60
62
 
61
63
  [tool.setuptools.package-data]
62
64
  api_tracker = ["py.typed"]
63
- backend = [
64
- "app/static/*",
65
- "app/static/assets/*",
65
+ "backend.app" = [
66
+ "static/*",
67
+ "static/assets/*",
66
68
  ]
67
69
 
68
70
 
@@ -83,4 +85,4 @@ select = [
83
85
  ]
84
86
  ignore = [
85
87
  "B008",
86
- ]
88
+ ]
@@ -0,0 +1,13 @@
1
+ import socket
2
+
3
+ from backend.app.launcher import find_available_port
4
+
5
+
6
+ def test_find_available_port_skips_busy_port():
7
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as busy_socket:
8
+ busy_socket.bind(("127.0.0.1", 0))
9
+ busy_port = busy_socket.getsockname()[1]
10
+
11
+ selected_port = find_available_port("127.0.0.1", busy_port)
12
+
13
+ assert selected_port != busy_port
@@ -1,21 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import os
4
- import threading
5
- import webbrowser
6
-
7
- import uvicorn
8
-
9
-
10
- def launch_app() -> None:
11
- host = os.getenv("API_TRACKER_HOST", "127.0.0.1")
12
- port = int(os.getenv("API_TRACKER_PORT", "8000"))
13
- open_browser = os.getenv("API_TRACKER_OPEN_BROWSER", "true").lower() not in {
14
- "0",
15
- "false",
16
- "no",
17
- }
18
- if open_browser:
19
- url = f"http://{host}:{port}"
20
- threading.Timer(1.0, lambda: webbrowser.open(url)).start()
21
- uvicorn.run("backend.app.main:app", host=host, port=port, reload=False)
File without changes
File without changes
File without changes