@tonyclaw/llm-inspector 1.9.0 → 1.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -14,4 +14,4 @@ Error generating stack: `+l.message+`
14
14
  `)}else{const p=o.indexOf(`
15
15
  `);if(p>=0){const v=o.slice(0,p).trim();o=o.slice(p+1),v.length>0&&(h=JSON.parse(v),f=!0)}}}return(async()=>{try{for(;;){const{value:y,done:m}=await r.read();y&&(o+=y);const p=o.lastIndexOf(`
16
16
  `);if(p>=0){const v=o.slice(0,p);o=o.slice(p+1);const S=v.split(`
17
- `).filter(Boolean);for(const _ of S)try{u(JSON.parse(_))}catch(R){i?.(`Invalid JSON line: ${_}`,R)}}if(m)break}}catch(y){i?.("Stream processing error:",y)}})(),u(h)}async function dR({jsonStream:a,onMessage:u,onError:i}){const r=a.getReader(),{value:o,done:f}=await r.read();if(f||!o)throw new Error("Stream ended before first object");const h=JSON.parse(o);return(async()=>{try{for(;;){const{value:y,done:m}=await r.read();if(m)break;if(y)try{u(JSON.parse(y))}catch(p){i?.(`Invalid JSON: ${y}`,p)}}}catch(y){i?.("Stream processing error:",y)}})(),u(h)}function hR(a){const u="/_serverFn/"+a;return Object.assign((...o)=>{const f=vg()?.serverFns?.fetch;return rR(u,o,f??fetch)},{url:u,serverFnMeta:{id:a},[Zo]:!0})}const mR={key:"$TSS/serverfn",test:a=>typeof a!="function"||!(Zo in a)?!1:!!a[Zo],toSerializable:({serverFnMeta:a})=>({functionId:a.id}),fromSerializable:({functionId:a})=>hR(a)};var lp=cg();const Eg=0,Rg=1,Tg=2,ip=3;var up=Object.prototype.hasOwnProperty;function Ko(a,u){var i,r;if(a===u)return!0;if(a&&u&&(i=a.constructor)===u.constructor){if(i===Date)return a.getTime()===u.getTime();if(i===RegExp)return a.toString()===u.toString();if(i===Array){if((r=a.length)===u.length)for(;r--&&Ko(a[r],u[r]););return r===-1}if(!i||typeof a=="object"){r=0;for(i in a)if(up.call(a,i)&&++r&&!up.call(u,i)||!(i in u)||!Ko(a[i],u[i]))return!1;return Object.keys(u).length===r}}return a!==a&&u!==u}const Bn=new WeakMap,Hn=()=>{},ge=Hn(),Xs=Object,_t=a=>a===ge,sn=a=>typeof a=="function",Gn=(a,u)=>({...a,...u}),Ag=a=>sn(a.then),No={},As={},pf="undefined",lu=typeof window!=pf,Jo=typeof document!=pf,yR=lu&&"Deno"in window,pR=()=>lu&&typeof window.requestAnimationFrame!=pf,Og=(a,u)=>{const i=Bn.get(a);return[()=>!_t(u)&&a.get(u)||No,r=>{if(!_t(u)){const o=a.get(u);u in As||(As[u]=o),i[5](u,Gn(o,r),o||No)}},i[6],()=>!_t(u)&&u in As?As[u]:!_t(u)&&a.get(u)||No]};let ko=!0;const gR=()=>ko,[Fo,Po]=lu&&window.addEventListener?[window.addEventListener.bind(window),window.removeEventListener.bind(window)]:[Hn,Hn],vR=()=>{const a=Jo&&document.visibilityState;return _t(a)||a!=="hidden"},SR=a=>(Jo&&document.addEventListener("visibilitychange",a),Fo("focus",a),()=>{Jo&&document.removeEventListener("visibilitychange",a),Po("focus",a)}),bR=a=>{const u=()=>{ko=!0,a()},i=()=>{ko=!1};return Fo("online",u),Fo("offline",i),()=>{Po("online",u),Po("offline",i)}},_R={isOnline:gR,isVisible:vR},ER={initFocus:SR,initReconnect:bR},sp=!qn.useId,Fl=!lu||yR,RR=a=>pR()?window.requestAnimationFrame(a):setTimeout(a,1),Ds=Fl?$.useEffect:$.useLayoutEffect,Uo=typeof navigator<"u"&&navigator.connection,rp=!Fl&&Uo&&(["slow-2g","2g"].includes(Uo.effectiveType)||Uo.saveData),Os=new WeakMap,TR=a=>Xs.prototype.toString.call(a),Bo=(a,u)=>a===`[object ${u}]`;let AR=0;const Wo=a=>{const u=typeof a,i=TR(a),r=Bo(i,"Date"),o=Bo(i,"RegExp"),f=Bo(i,"Object");let h,y;if(Xs(a)===a&&!r&&!o){if(h=Os.get(a),h)return h;if(h=++AR+"~",Os.set(a,h),Array.isArray(a)){for(h="@",y=0;y<a.length;y++)h+=Wo(a[y])+",";Os.set(a,h)}if(f){h="#";const m=Xs.keys(a).sort();for(;!_t(y=m.pop());)_t(a[y])||(h+=y+":"+Wo(a[y])+",");Os.set(a,h)}}else h=r?a.toJSON():u=="symbol"?a.toString():u=="string"?JSON.stringify(a):""+a;return h},gf=a=>{if(sn(a))try{a=a()}catch{a=""}const u=a;return a=typeof a=="string"?a:(Array.isArray(a)?a.length:a)?Wo(a):"",[a,u]};let OR=0;const $o=()=>++OR;async function wg(...a){const[u,i,r,o]=a,f=Gn({populateCache:!0,throwOnError:!0},typeof o=="boolean"?{revalidate:o}:o||{});let h=f.populateCache;const y=f.rollbackOnError;let m=f.optimisticData;const p=_=>typeof y=="function"?y(_):y!==!1,v=f.throwOnError;if(sn(i)){const _=i,R=[],z=u.keys();for(const A of z)!/^\$(inf|sub)\$/.test(A)&&_(u.get(A)._k)&&R.push(A);return Promise.all(R.map(S))}return S(i);async function S(_){const[R]=gf(_);if(!R)return;const[z,A]=Og(u,R),[x,Y,B,Z]=Bn.get(u),H=()=>{const it=x[R];return(sn(f.revalidate)?f.revalidate(z().data,_):f.revalidate!==!1)&&(delete B[R],delete Z[R],it&&it[0])?it[0](Tg).then(()=>z().data):z().data};if(a.length<3)return H();let k=r,I,Q=!1;const X=$o();Y[R]=[X,0];const K=!_t(m),rt=z(),nt=rt.data,lt=rt._c,ht=_t(lt)?nt:lt;if(K&&(m=sn(m)?m(ht,nt):m,A({data:m,_c:ht})),sn(k))try{k=k(ht)}catch(it){I=it,Q=!0}if(k&&Ag(k))if(k=await k.catch(it=>{I=it,Q=!0}),X!==Y[R][0]){if(Q)throw I;return k}else Q&&K&&p(I)&&(h=!0,A({data:ht,_c:ge}));if(h&&!Q)if(sn(h)){const it=h(k,ht);A({data:it,error:ge,_c:ge})}else A({data:k,error:ge,_c:ge});if(Y[R][1]=$o(),Promise.resolve(H()).then(()=>{A({_c:ge})}),Q){if(v)throw I;return}return k}}const cp=(a,u)=>{for(const i in a)a[i][0]&&a[i][0](u)},Mg=(a,u)=>{if(!Bn.has(a)){const i=Gn(ER,u),r=Object.create(null),o=wg.bind(ge,a);let f=Hn;const h=Object.create(null),y=(v,S)=>{const _=h[v]||[];return h[v]=_,_.push(S),()=>_.splice(_.indexOf(S),1)},m=(v,S,_)=>{a.set(v,S);const R=h[v];if(R)for(const z of R)z(S,_)},p=()=>{if(!Bn.has(a)&&(Bn.set(a,[r,Object.create(null),Object.create(null),Object.create(null),o,m,y]),!Fl)){const v=i.initFocus(setTimeout.bind(ge,cp.bind(ge,r,Eg))),S=i.initReconnect(setTimeout.bind(ge,cp.bind(ge,r,Rg)));f=()=>{v&&v(),S&&S(),Bn.delete(a)}}};return p(),[a,o,p,f]}return[a,Bn.get(a)[4]]},wR=(a,u,i,r,o)=>{const f=i.errorRetryCount,h=o.retryCount,y=~~((Math.random()+.5)*(1<<(h<8?h:8)))*i.errorRetryInterval;!_t(f)&&h>f||setTimeout(r,y,o)},MR=Ko,[vf,xR]=Mg(new Map),xg=Gn({onLoadingSlow:Hn,onSuccess:Hn,onError:Hn,onErrorRetry:wR,onDiscarded:Hn,revalidateOnFocus:!0,revalidateOnReconnect:!0,revalidateIfStale:!0,shouldRetryOnError:!0,errorRetryInterval:rp?1e4:5e3,focusThrottleInterval:5*1e3,dedupingInterval:2*1e3,loadingTimeout:rp?5e3:3e3,compare:MR,isPaused:()=>!1,cache:vf,mutate:xR,fallback:{}},_R),zg=(a,u)=>{const i=Gn(a,u);if(u){const{use:r,fallback:o}=a,{use:f,fallback:h}=u;r&&f&&(i.use=r.concat(f)),o&&h&&(i.fallback=Gn(o,h))}return i},Io=$.createContext({}),zR=a=>{const{value:u}=a,i=$.useContext(Io),r=sn(u),o=$.useMemo(()=>r?u(i):u,[r,i,u]),f=$.useMemo(()=>r?o:zg(i,o),[r,i,o]),h=o&&o.provider,y=$.useRef(ge);h&&!y.current&&(y.current=Mg(h(f.cache||vf),o));const m=y.current;return m&&(f.cache=m[0],f.mutate=m[1]),Ds(()=>{if(m)return m[2]&&m[2](),m[3]},[]),$.createElement(Io.Provider,Gn(a,{value:f}))},CR="$inf$",Cg=lu&&window.__SWR_DEVTOOLS_USE__,DR=Cg?window.__SWR_DEVTOOLS_USE__:[],LR=()=>{Cg&&(window.__SWR_DEVTOOLS_REACT__=qn)},NR=a=>sn(a[1])?[a[0],a[1],a[2]||{}]:[a[0],null,(a[1]===null?a[2]:a[1])||{}],UR=()=>{const a=$.useContext(Io);return $.useMemo(()=>Gn(xg,a),[a])},BR=a=>(u,i,r)=>a(u,i&&((...f)=>{const[h]=gf(u),[,,,y]=Bn.get(vf);if(h.startsWith(CR))return i(...f);const m=y[h];return _t(m)?i(...f):(delete y[h],m)}),r),jR=DR.concat(BR),HR=a=>function(...i){const r=UR(),[o,f,h]=NR(i),y=zg(r,h);let m=a;const{use:p}=y,v=(p||[]).concat(jR);for(let S=v.length;S--;)m=v[S](m);return m(o,f||y.fetcher||null,y)},qR=(a,u,i)=>{const r=u[a]||(u[a]=[]);return r.push(i),()=>{const o=r.indexOf(i);o>=0&&(r[o]=r[r.length-1],r.pop())}};LR();const jo=qn.use||(a=>{switch(a.status){case"pending":throw a;case"fulfilled":return a.value;case"rejected":throw a.reason;default:throw a.status="pending",a.then(u=>{a.status="fulfilled",a.value=u},u=>{a.status="rejected",a.reason=u}),a}}),Ho={dedupe:!0},op=Promise.resolve(ge),VR=()=>Hn,YR=(a,u,i)=>{const{cache:r,compare:o,suspense:f,fallbackData:h,revalidateOnMount:y,revalidateIfStale:m,refreshInterval:p,refreshWhenHidden:v,refreshWhenOffline:S,keepPreviousData:_,strictServerPrefetchWarning:R}=i,[z,A,x,Y]=Bn.get(r),[B,Z]=gf(a),H=$.useRef(!1),k=$.useRef(!1),I=$.useRef(B),Q=$.useRef(u),X=$.useRef(i),K=()=>X.current,rt=()=>K().isVisible()&&K().isOnline(),[nt,lt,ht,it]=Og(r,B),jt=$.useRef({}).current,N=_t(h)?_t(i.fallback)?ge:i.fallback[B]:h,F=(Et,Lt)=>{for(const At in jt){const qt=At;if(qt==="data"){if(!o(Et[qt],Lt[qt])&&(!_t(Et[qt])||!o(ot,Lt[qt])))return!1}else if(Lt[qt]!==Et[qt])return!1}return!0},ut=!H.current,Tt=$.useMemo(()=>{const Et=nt(),Lt=it(),At=Jt=>{const Vt=Gn(Jt);return delete Vt._k,(()=>{if(!B||!u||K().isPaused())return!1;if(ut&&!_t(y))return y;const xt=_t(N)?Vt.data:N;return _t(xt)||m})()?{isValidating:!0,isLoading:!0,...Vt}:Vt},qt=At(Et),ve=Et===Lt?qt:At(Lt);let oe=qt;return[()=>{const Jt=At(nt());return F(Jt,oe)?(oe.data=Jt.data,oe.isLoading=Jt.isLoading,oe.isValidating=Jt.isValidating,oe.error=Jt.error,oe):(oe=Jt,Jt)},()=>ve]},[r,B]),pt=lp.useSyncExternalStore($.useCallback(Et=>ht(B,(Lt,At)=>{F(At,Lt)||Et()}),[r,B]),Tt[0],Tt[1]),w=z[B]&&z[B].length>0,q=pt.data,J=_t(q)?N&&Ag(N)?jo(N):N:q,P=pt.error,ct=$.useRef(J),ot=_?_t(q)?_t(ct.current)?J:ct.current:q:J,ft=B&&_t(J),Xt=$.useRef(null);!Fl&&lp.useSyncExternalStore(VR,()=>(Xt.current=!1,Xt),()=>(Xt.current=!0,Xt));const Ht=Xt.current;R&&Ht&&!f&&ft&&console.warn(`Missing pre-initiated data for serialized key "${B}" during server-side rendering. Data fetching should be initiated on the server and provided to SWR via fallback data. You can set "strictServerPrefetchWarning: false" to disable this warning.`);const De=!B||!u||K().isPaused()||w&&!_t(P)?!1:ut&&!_t(y)?y:f?_t(J)?!1:m:_t(J)||m,Xe=ut&&De,Qn=_t(pt.isValidating)?Xe:pt.isValidating,Ta=_t(pt.isLoading)?Xe:pt.isLoading,_e=$.useCallback(async Et=>{const Lt=Q.current;if(!B||!Lt||k.current||K().isPaused())return!1;let At,qt,ve=!0;const oe=Et||{},Jt=!x[B]||!oe.dedupe,Vt=()=>sp?!k.current&&B===I.current&&H.current:B===I.current,yn={isValidating:!1,isLoading:!1},xt=()=>{lt(yn)},$t=()=>{const fe=x[B];fe&&fe[1]===qt&&delete x[B]},ae={isValidating:!0};_t(nt().data)&&(ae.isLoading=!0);try{if(Jt&&(lt(ae),i.loadingTimeout&&_t(nt().data)&&setTimeout(()=>{ve&&Vt()&&K().onLoadingSlow(B,i)},i.loadingTimeout),x[B]=[Lt(Z),$o()]),[At,qt]=x[B],At=await At,Jt&&setTimeout($t,i.dedupingInterval),!x[B]||x[B][1]!==qt)return Jt&&Vt()&&K().onDiscarded(B),!1;yn.error=ge;const fe=A[B];if(!_t(fe)&&(qt<=fe[0]||qt<=fe[1]||fe[1]===0))return xt(),Jt&&Vt()&&K().onDiscarded(B),!1;const Qe=nt().data;yn.data=o(Qe,At)?Qe:At,Jt&&Vt()&&K().onSuccess(At,B,i)}catch(fe){$t();const Qe=K(),{shouldRetryOnError:Wl}=Qe;Qe.isPaused()||(yn.error=fe,Jt&&Vt()&&(Qe.onError(fe,B,Qe),(Wl===!0||sn(Wl)&&Wl(fe))&&(!K().revalidateOnFocus||!K().revalidateOnReconnect||rt())&&Qe.onErrorRetry(fe,B,Qe,$s=>{const pn=z[B];pn&&pn[0]&&pn[0](ip,$s)},{retryCount:(oe.retryCount||0)+1,dedupe:!0})))}return ve=!1,xt(),!0},[B,r]),mn=$.useCallback((...Et)=>wg(r,I.current,...Et),[]);if(Ds(()=>{Q.current=u,X.current=i,_t(q)||(ct.current=q)}),Ds(()=>{if(!B)return;const Et=_e.bind(ge,Ho);let Lt=0;K().revalidateOnFocus&&(Lt=Date.now()+K().focusThrottleInterval);const qt=qR(B,z,(ve,oe={})=>{if(ve==Eg){const Jt=Date.now();K().revalidateOnFocus&&Jt>Lt&&rt()&&(Lt=Jt+K().focusThrottleInterval,Et())}else if(ve==Rg)K().revalidateOnReconnect&&rt()&&Et();else{if(ve==Tg)return _e();if(ve==ip)return _e(oe)}});return k.current=!1,I.current=B,H.current=!0,lt({_k:Z}),De&&(x[B]||(_t(J)||Fl?Et():RR(Et))),()=>{k.current=!0,qt()}},[B]),Ds(()=>{let Et;function Lt(){const qt=sn(p)?p(nt().data):p;qt&&Et!==-1&&(Et=setTimeout(At,qt))}function At(){!nt().error&&(v||K().isVisible())&&(S||K().isOnline())?_e(Ho).then(Lt):Lt()}return Lt(),()=>{Et&&(clearTimeout(Et),Et=-1)}},[p,v,S,B]),$.useDebugValue(ot),f){if(!sp&&Fl&&ft)throw new Error("Fallback data is required when using Suspense in SSR.");ft&&(Q.current=u,X.current=i,k.current=!1);const Et=Y[B],Lt=!_t(Et)&&ft?mn(Et):op;if(jo(Lt),!_t(P)&&ft)throw P;const At=ft?_e(Ho):op;!_t(ot)&&ft&&(At.status="fulfilled",At.value=!0),jo(At)}return{mutate:mn,get data(){return jt.data=!0,ot},get error(){return jt.error=!0,P},get isValidating(){return jt.isValidating=!0,Qn},get isLoading(){return jt.isLoading=!0,Ta}}},GR=Xs.defineProperty(zR,"defaultValue",{value:xg}),oT=HR(YR),XR="/assets/index-DdJSLfxK.css",Dg=DE({head:()=>({meta:[{charSet:"utf-8"},{name:"viewport",content:"width=device-width, initial-scale=1"},{title:"llm-inspector"}],links:[{rel:"stylesheet",href:XR}]}),component:QR});function QR(){return W.jsx(ZR,{children:W.jsx(yg,{})})}function ZR({children:a}){return W.jsxs("html",{lang:"en",className:"dark",children:[W.jsx("head",{children:W.jsx(kE,{})}),W.jsxs("body",{children:[W.jsx(GR,{value:{revalidateOnFocus:!1,revalidateIfStale:!1},children:a}),W.jsx(FE,{})]})]})}const KR="modulepreload",JR=function(a){return"/"+a},fp={},kR=function(u,i,r){let o=Promise.resolve();if(i&&i.length>0){let m=function(p){return Promise.all(p.map(v=>Promise.resolve(v).then(S=>({status:"fulfilled",value:S}),S=>({status:"rejected",reason:S}))))};document.getElementsByTagName("link");const h=document.querySelector("meta[property=csp-nonce]"),y=h?.nonce||h?.getAttribute("nonce");o=m(i.map(p=>{if(p=JR(p),p in fp)return;fp[p]=!0;const v=p.endsWith(".css"),S=v?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${p}"]${S}`))return;const _=document.createElement("link");if(_.rel=v?"stylesheet":KR,v||(_.as="script"),_.crossOrigin="",_.href=p,y&&_.setAttribute("nonce",y),document.head.appendChild(_),v)return new Promise((R,z)=>{_.addEventListener("load",R),_.addEventListener("error",()=>z(new Error(`Unable to preload CSS for ${p}`)))})}))}function f(h){const y=new Event("vite:preloadError",{cancelable:!0});if(y.payload=h,window.dispatchEvent(y),!y.defaultPrevented)throw h}return o.then(h=>{for(const y of h||[])y.status==="rejected"&&f(y.reason);return u().catch(f)})},FR=()=>kR(()=>import("./index-DyKLPMPn.js"),[]),PR=Qo("/")({component:LE(FR,"component")}),WR=PR.update({id:"/",path:"/",getParentRoute:()=>Dg}),$R={IndexRoute:WR},IR=Dg._addFileChildren($R);function tT(){return YE({routeTree:IR,scrollRestoration:!1})}async function eT(){const a=await tT();let u;return u=[],window.__TSS_START_OPTIONS__={serializationAdapters:u},u.push(mR),a.options.serializationAdapters&&u.push(...a.options.serializationAdapters),a.update({basepath:"",serializationAdapters:u}),a.state.matches.length||await WE(a),a}async function nT(){const a=await eT();return window.$_TSR?.h(),a}let qo;function aT(){return qo||(qo=nT()),W.jsx(rE,{promise:qo,children:a=>W.jsx(QE,{router:a})})}$.startTransition(()=>{iS.hydrateRoot(document,W.jsx($.StrictMode,{children:W.jsx(aT,{})}))});export{qn as R,fg as a,I0 as b,lT as c,rT as d,dp as g,W as j,$ as r,oT as u};
17
+ `).filter(Boolean);for(const _ of S)try{u(JSON.parse(_))}catch(R){i?.(`Invalid JSON line: ${_}`,R)}}if(m)break}}catch(y){i?.("Stream processing error:",y)}})(),u(h)}async function dR({jsonStream:a,onMessage:u,onError:i}){const r=a.getReader(),{value:o,done:f}=await r.read();if(f||!o)throw new Error("Stream ended before first object");const h=JSON.parse(o);return(async()=>{try{for(;;){const{value:y,done:m}=await r.read();if(m)break;if(y)try{u(JSON.parse(y))}catch(p){i?.(`Invalid JSON: ${y}`,p)}}}catch(y){i?.("Stream processing error:",y)}})(),u(h)}function hR(a){const u="/_serverFn/"+a;return Object.assign((...o)=>{const f=vg()?.serverFns?.fetch;return rR(u,o,f??fetch)},{url:u,serverFnMeta:{id:a},[Zo]:!0})}const mR={key:"$TSS/serverfn",test:a=>typeof a!="function"||!(Zo in a)?!1:!!a[Zo],toSerializable:({serverFnMeta:a})=>({functionId:a.id}),fromSerializable:({functionId:a})=>hR(a)};var lp=cg();const Eg=0,Rg=1,Tg=2,ip=3;var up=Object.prototype.hasOwnProperty;function Ko(a,u){var i,r;if(a===u)return!0;if(a&&u&&(i=a.constructor)===u.constructor){if(i===Date)return a.getTime()===u.getTime();if(i===RegExp)return a.toString()===u.toString();if(i===Array){if((r=a.length)===u.length)for(;r--&&Ko(a[r],u[r]););return r===-1}if(!i||typeof a=="object"){r=0;for(i in a)if(up.call(a,i)&&++r&&!up.call(u,i)||!(i in u)||!Ko(a[i],u[i]))return!1;return Object.keys(u).length===r}}return a!==a&&u!==u}const Bn=new WeakMap,Hn=()=>{},ge=Hn(),Xs=Object,_t=a=>a===ge,sn=a=>typeof a=="function",Gn=(a,u)=>({...a,...u}),Ag=a=>sn(a.then),No={},As={},pf="undefined",lu=typeof window!=pf,Jo=typeof document!=pf,yR=lu&&"Deno"in window,pR=()=>lu&&typeof window.requestAnimationFrame!=pf,Og=(a,u)=>{const i=Bn.get(a);return[()=>!_t(u)&&a.get(u)||No,r=>{if(!_t(u)){const o=a.get(u);u in As||(As[u]=o),i[5](u,Gn(o,r),o||No)}},i[6],()=>!_t(u)&&u in As?As[u]:!_t(u)&&a.get(u)||No]};let ko=!0;const gR=()=>ko,[Fo,Po]=lu&&window.addEventListener?[window.addEventListener.bind(window),window.removeEventListener.bind(window)]:[Hn,Hn],vR=()=>{const a=Jo&&document.visibilityState;return _t(a)||a!=="hidden"},SR=a=>(Jo&&document.addEventListener("visibilitychange",a),Fo("focus",a),()=>{Jo&&document.removeEventListener("visibilitychange",a),Po("focus",a)}),bR=a=>{const u=()=>{ko=!0,a()},i=()=>{ko=!1};return Fo("online",u),Fo("offline",i),()=>{Po("online",u),Po("offline",i)}},_R={isOnline:gR,isVisible:vR},ER={initFocus:SR,initReconnect:bR},sp=!qn.useId,Fl=!lu||yR,RR=a=>pR()?window.requestAnimationFrame(a):setTimeout(a,1),Ds=Fl?$.useEffect:$.useLayoutEffect,Uo=typeof navigator<"u"&&navigator.connection,rp=!Fl&&Uo&&(["slow-2g","2g"].includes(Uo.effectiveType)||Uo.saveData),Os=new WeakMap,TR=a=>Xs.prototype.toString.call(a),Bo=(a,u)=>a===`[object ${u}]`;let AR=0;const Wo=a=>{const u=typeof a,i=TR(a),r=Bo(i,"Date"),o=Bo(i,"RegExp"),f=Bo(i,"Object");let h,y;if(Xs(a)===a&&!r&&!o){if(h=Os.get(a),h)return h;if(h=++AR+"~",Os.set(a,h),Array.isArray(a)){for(h="@",y=0;y<a.length;y++)h+=Wo(a[y])+",";Os.set(a,h)}if(f){h="#";const m=Xs.keys(a).sort();for(;!_t(y=m.pop());)_t(a[y])||(h+=y+":"+Wo(a[y])+",");Os.set(a,h)}}else h=r?a.toJSON():u=="symbol"?a.toString():u=="string"?JSON.stringify(a):""+a;return h},gf=a=>{if(sn(a))try{a=a()}catch{a=""}const u=a;return a=typeof a=="string"?a:(Array.isArray(a)?a.length:a)?Wo(a):"",[a,u]};let OR=0;const $o=()=>++OR;async function wg(...a){const[u,i,r,o]=a,f=Gn({populateCache:!0,throwOnError:!0},typeof o=="boolean"?{revalidate:o}:o||{});let h=f.populateCache;const y=f.rollbackOnError;let m=f.optimisticData;const p=_=>typeof y=="function"?y(_):y!==!1,v=f.throwOnError;if(sn(i)){const _=i,R=[],z=u.keys();for(const A of z)!/^\$(inf|sub)\$/.test(A)&&_(u.get(A)._k)&&R.push(A);return Promise.all(R.map(S))}return S(i);async function S(_){const[R]=gf(_);if(!R)return;const[z,A]=Og(u,R),[x,Y,B,Z]=Bn.get(u),H=()=>{const it=x[R];return(sn(f.revalidate)?f.revalidate(z().data,_):f.revalidate!==!1)&&(delete B[R],delete Z[R],it&&it[0])?it[0](Tg).then(()=>z().data):z().data};if(a.length<3)return H();let k=r,I,Q=!1;const X=$o();Y[R]=[X,0];const K=!_t(m),rt=z(),nt=rt.data,lt=rt._c,ht=_t(lt)?nt:lt;if(K&&(m=sn(m)?m(ht,nt):m,A({data:m,_c:ht})),sn(k))try{k=k(ht)}catch(it){I=it,Q=!0}if(k&&Ag(k))if(k=await k.catch(it=>{I=it,Q=!0}),X!==Y[R][0]){if(Q)throw I;return k}else Q&&K&&p(I)&&(h=!0,A({data:ht,_c:ge}));if(h&&!Q)if(sn(h)){const it=h(k,ht);A({data:it,error:ge,_c:ge})}else A({data:k,error:ge,_c:ge});if(Y[R][1]=$o(),Promise.resolve(H()).then(()=>{A({_c:ge})}),Q){if(v)throw I;return}return k}}const cp=(a,u)=>{for(const i in a)a[i][0]&&a[i][0](u)},Mg=(a,u)=>{if(!Bn.has(a)){const i=Gn(ER,u),r=Object.create(null),o=wg.bind(ge,a);let f=Hn;const h=Object.create(null),y=(v,S)=>{const _=h[v]||[];return h[v]=_,_.push(S),()=>_.splice(_.indexOf(S),1)},m=(v,S,_)=>{a.set(v,S);const R=h[v];if(R)for(const z of R)z(S,_)},p=()=>{if(!Bn.has(a)&&(Bn.set(a,[r,Object.create(null),Object.create(null),Object.create(null),o,m,y]),!Fl)){const v=i.initFocus(setTimeout.bind(ge,cp.bind(ge,r,Eg))),S=i.initReconnect(setTimeout.bind(ge,cp.bind(ge,r,Rg)));f=()=>{v&&v(),S&&S(),Bn.delete(a)}}};return p(),[a,o,p,f]}return[a,Bn.get(a)[4]]},wR=(a,u,i,r,o)=>{const f=i.errorRetryCount,h=o.retryCount,y=~~((Math.random()+.5)*(1<<(h<8?h:8)))*i.errorRetryInterval;!_t(f)&&h>f||setTimeout(r,y,o)},MR=Ko,[vf,xR]=Mg(new Map),xg=Gn({onLoadingSlow:Hn,onSuccess:Hn,onError:Hn,onErrorRetry:wR,onDiscarded:Hn,revalidateOnFocus:!0,revalidateOnReconnect:!0,revalidateIfStale:!0,shouldRetryOnError:!0,errorRetryInterval:rp?1e4:5e3,focusThrottleInterval:5*1e3,dedupingInterval:2*1e3,loadingTimeout:rp?5e3:3e3,compare:MR,isPaused:()=>!1,cache:vf,mutate:xR,fallback:{}},_R),zg=(a,u)=>{const i=Gn(a,u);if(u){const{use:r,fallback:o}=a,{use:f,fallback:h}=u;r&&f&&(i.use=r.concat(f)),o&&h&&(i.fallback=Gn(o,h))}return i},Io=$.createContext({}),zR=a=>{const{value:u}=a,i=$.useContext(Io),r=sn(u),o=$.useMemo(()=>r?u(i):u,[r,i,u]),f=$.useMemo(()=>r?o:zg(i,o),[r,i,o]),h=o&&o.provider,y=$.useRef(ge);h&&!y.current&&(y.current=Mg(h(f.cache||vf),o));const m=y.current;return m&&(f.cache=m[0],f.mutate=m[1]),Ds(()=>{if(m)return m[2]&&m[2](),m[3]},[]),$.createElement(Io.Provider,Gn(a,{value:f}))},CR="$inf$",Cg=lu&&window.__SWR_DEVTOOLS_USE__,DR=Cg?window.__SWR_DEVTOOLS_USE__:[],LR=()=>{Cg&&(window.__SWR_DEVTOOLS_REACT__=qn)},NR=a=>sn(a[1])?[a[0],a[1],a[2]||{}]:[a[0],null,(a[1]===null?a[2]:a[1])||{}],UR=()=>{const a=$.useContext(Io);return $.useMemo(()=>Gn(xg,a),[a])},BR=a=>(u,i,r)=>a(u,i&&((...f)=>{const[h]=gf(u),[,,,y]=Bn.get(vf);if(h.startsWith(CR))return i(...f);const m=y[h];return _t(m)?i(...f):(delete y[h],m)}),r),jR=DR.concat(BR),HR=a=>function(...i){const r=UR(),[o,f,h]=NR(i),y=zg(r,h);let m=a;const{use:p}=y,v=(p||[]).concat(jR);for(let S=v.length;S--;)m=v[S](m);return m(o,f||y.fetcher||null,y)},qR=(a,u,i)=>{const r=u[a]||(u[a]=[]);return r.push(i),()=>{const o=r.indexOf(i);o>=0&&(r[o]=r[r.length-1],r.pop())}};LR();const jo=qn.use||(a=>{switch(a.status){case"pending":throw a;case"fulfilled":return a.value;case"rejected":throw a.reason;default:throw a.status="pending",a.then(u=>{a.status="fulfilled",a.value=u},u=>{a.status="rejected",a.reason=u}),a}}),Ho={dedupe:!0},op=Promise.resolve(ge),VR=()=>Hn,YR=(a,u,i)=>{const{cache:r,compare:o,suspense:f,fallbackData:h,revalidateOnMount:y,revalidateIfStale:m,refreshInterval:p,refreshWhenHidden:v,refreshWhenOffline:S,keepPreviousData:_,strictServerPrefetchWarning:R}=i,[z,A,x,Y]=Bn.get(r),[B,Z]=gf(a),H=$.useRef(!1),k=$.useRef(!1),I=$.useRef(B),Q=$.useRef(u),X=$.useRef(i),K=()=>X.current,rt=()=>K().isVisible()&&K().isOnline(),[nt,lt,ht,it]=Og(r,B),jt=$.useRef({}).current,N=_t(h)?_t(i.fallback)?ge:i.fallback[B]:h,F=(Et,Lt)=>{for(const At in jt){const qt=At;if(qt==="data"){if(!o(Et[qt],Lt[qt])&&(!_t(Et[qt])||!o(ot,Lt[qt])))return!1}else if(Lt[qt]!==Et[qt])return!1}return!0},ut=!H.current,Tt=$.useMemo(()=>{const Et=nt(),Lt=it(),At=Jt=>{const Vt=Gn(Jt);return delete Vt._k,(()=>{if(!B||!u||K().isPaused())return!1;if(ut&&!_t(y))return y;const xt=_t(N)?Vt.data:N;return _t(xt)||m})()?{isValidating:!0,isLoading:!0,...Vt}:Vt},qt=At(Et),ve=Et===Lt?qt:At(Lt);let oe=qt;return[()=>{const Jt=At(nt());return F(Jt,oe)?(oe.data=Jt.data,oe.isLoading=Jt.isLoading,oe.isValidating=Jt.isValidating,oe.error=Jt.error,oe):(oe=Jt,Jt)},()=>ve]},[r,B]),pt=lp.useSyncExternalStore($.useCallback(Et=>ht(B,(Lt,At)=>{F(At,Lt)||Et()}),[r,B]),Tt[0],Tt[1]),w=z[B]&&z[B].length>0,q=pt.data,J=_t(q)?N&&Ag(N)?jo(N):N:q,P=pt.error,ct=$.useRef(J),ot=_?_t(q)?_t(ct.current)?J:ct.current:q:J,ft=B&&_t(J),Xt=$.useRef(null);!Fl&&lp.useSyncExternalStore(VR,()=>(Xt.current=!1,Xt),()=>(Xt.current=!0,Xt));const Ht=Xt.current;R&&Ht&&!f&&ft&&console.warn(`Missing pre-initiated data for serialized key "${B}" during server-side rendering. Data fetching should be initiated on the server and provided to SWR via fallback data. You can set "strictServerPrefetchWarning: false" to disable this warning.`);const De=!B||!u||K().isPaused()||w&&!_t(P)?!1:ut&&!_t(y)?y:f?_t(J)?!1:m:_t(J)||m,Xe=ut&&De,Qn=_t(pt.isValidating)?Xe:pt.isValidating,Ta=_t(pt.isLoading)?Xe:pt.isLoading,_e=$.useCallback(async Et=>{const Lt=Q.current;if(!B||!Lt||k.current||K().isPaused())return!1;let At,qt,ve=!0;const oe=Et||{},Jt=!x[B]||!oe.dedupe,Vt=()=>sp?!k.current&&B===I.current&&H.current:B===I.current,yn={isValidating:!1,isLoading:!1},xt=()=>{lt(yn)},$t=()=>{const fe=x[B];fe&&fe[1]===qt&&delete x[B]},ae={isValidating:!0};_t(nt().data)&&(ae.isLoading=!0);try{if(Jt&&(lt(ae),i.loadingTimeout&&_t(nt().data)&&setTimeout(()=>{ve&&Vt()&&K().onLoadingSlow(B,i)},i.loadingTimeout),x[B]=[Lt(Z),$o()]),[At,qt]=x[B],At=await At,Jt&&setTimeout($t,i.dedupingInterval),!x[B]||x[B][1]!==qt)return Jt&&Vt()&&K().onDiscarded(B),!1;yn.error=ge;const fe=A[B];if(!_t(fe)&&(qt<=fe[0]||qt<=fe[1]||fe[1]===0))return xt(),Jt&&Vt()&&K().onDiscarded(B),!1;const Qe=nt().data;yn.data=o(Qe,At)?Qe:At,Jt&&Vt()&&K().onSuccess(At,B,i)}catch(fe){$t();const Qe=K(),{shouldRetryOnError:Wl}=Qe;Qe.isPaused()||(yn.error=fe,Jt&&Vt()&&(Qe.onError(fe,B,Qe),(Wl===!0||sn(Wl)&&Wl(fe))&&(!K().revalidateOnFocus||!K().revalidateOnReconnect||rt())&&Qe.onErrorRetry(fe,B,Qe,$s=>{const pn=z[B];pn&&pn[0]&&pn[0](ip,$s)},{retryCount:(oe.retryCount||0)+1,dedupe:!0})))}return ve=!1,xt(),!0},[B,r]),mn=$.useCallback((...Et)=>wg(r,I.current,...Et),[]);if(Ds(()=>{Q.current=u,X.current=i,_t(q)||(ct.current=q)}),Ds(()=>{if(!B)return;const Et=_e.bind(ge,Ho);let Lt=0;K().revalidateOnFocus&&(Lt=Date.now()+K().focusThrottleInterval);const qt=qR(B,z,(ve,oe={})=>{if(ve==Eg){const Jt=Date.now();K().revalidateOnFocus&&Jt>Lt&&rt()&&(Lt=Jt+K().focusThrottleInterval,Et())}else if(ve==Rg)K().revalidateOnReconnect&&rt()&&Et();else{if(ve==Tg)return _e();if(ve==ip)return _e(oe)}});return k.current=!1,I.current=B,H.current=!0,lt({_k:Z}),De&&(x[B]||(_t(J)||Fl?Et():RR(Et))),()=>{k.current=!0,qt()}},[B]),Ds(()=>{let Et;function Lt(){const qt=sn(p)?p(nt().data):p;qt&&Et!==-1&&(Et=setTimeout(At,qt))}function At(){!nt().error&&(v||K().isVisible())&&(S||K().isOnline())?_e(Ho).then(Lt):Lt()}return Lt(),()=>{Et&&(clearTimeout(Et),Et=-1)}},[p,v,S,B]),$.useDebugValue(ot),f){if(!sp&&Fl&&ft)throw new Error("Fallback data is required when using Suspense in SSR.");ft&&(Q.current=u,X.current=i,k.current=!1);const Et=Y[B],Lt=!_t(Et)&&ft?mn(Et):op;if(jo(Lt),!_t(P)&&ft)throw P;const At=ft?_e(Ho):op;!_t(ot)&&ft&&(At.status="fulfilled",At.value=!0),jo(At)}return{mutate:mn,get data(){return jt.data=!0,ot},get error(){return jt.error=!0,P},get isValidating(){return jt.isValidating=!0,Qn},get isLoading(){return jt.isLoading=!0,Ta}}},GR=Xs.defineProperty(zR,"defaultValue",{value:xg}),oT=HR(YR),XR="/assets/index-DdJSLfxK.css",Dg=DE({head:()=>({meta:[{charSet:"utf-8"},{name:"viewport",content:"width=device-width, initial-scale=1"},{title:"llm-inspector"}],links:[{rel:"stylesheet",href:XR}]}),component:QR});function QR(){return W.jsx(ZR,{children:W.jsx(yg,{})})}function ZR({children:a}){return W.jsxs("html",{lang:"en",className:"dark",children:[W.jsx("head",{children:W.jsx(kE,{})}),W.jsxs("body",{children:[W.jsx(GR,{value:{revalidateOnFocus:!1,revalidateIfStale:!1},children:a}),W.jsx(FE,{})]})]})}const KR="modulepreload",JR=function(a){return"/"+a},fp={},kR=function(u,i,r){let o=Promise.resolve();if(i&&i.length>0){let m=function(p){return Promise.all(p.map(v=>Promise.resolve(v).then(S=>({status:"fulfilled",value:S}),S=>({status:"rejected",reason:S}))))};document.getElementsByTagName("link");const h=document.querySelector("meta[property=csp-nonce]"),y=h?.nonce||h?.getAttribute("nonce");o=m(i.map(p=>{if(p=JR(p),p in fp)return;fp[p]=!0;const v=p.endsWith(".css"),S=v?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${p}"]${S}`))return;const _=document.createElement("link");if(_.rel=v?"stylesheet":KR,v||(_.as="script"),_.crossOrigin="",_.href=p,y&&_.setAttribute("nonce",y),document.head.appendChild(_),v)return new Promise((R,z)=>{_.addEventListener("load",R),_.addEventListener("error",()=>z(new Error(`Unable to preload CSS for ${p}`)))})}))}function f(h){const y=new Event("vite:preloadError",{cancelable:!0});if(y.payload=h,window.dispatchEvent(y),!y.defaultPrevented)throw h}return o.then(h=>{for(const y of h||[])y.status==="rejected"&&f(y.reason);return u().catch(f)})},FR=()=>kR(()=>import("./index-BmEH5jeO.js"),[]),PR=Qo("/")({component:LE(FR,"component")}),WR=PR.update({id:"/",path:"/",getParentRoute:()=>Dg}),$R={IndexRoute:WR},IR=Dg._addFileChildren($R);function tT(){return YE({routeTree:IR,scrollRestoration:!1})}async function eT(){const a=await tT();let u;return u=[],window.__TSS_START_OPTIONS__={serializationAdapters:u},u.push(mR),a.options.serializationAdapters&&u.push(...a.options.serializationAdapters),a.update({basepath:"",serializationAdapters:u}),a.state.matches.length||await WE(a),a}async function nT(){const a=await eT();return window.$_TSR?.h(),a}let qo;function aT(){return qo||(qo=nT()),W.jsx(rE,{promise:qo,children:a=>W.jsx(QE,{router:a})})}$.startTransition(()=>{iS.hydrateRoot(document,W.jsx($.StrictMode,{children:W.jsx(aT,{})}))});export{qn as R,fg as a,I0 as b,lT as c,rT as d,dp as g,W as j,$ as r,oT as u};
@@ -1,5 +1,5 @@
1
1
  import { r as reactExports, j as jsxRuntimeExports, a as React } from "../_libs/react.mjs";
2
- import { C as CapturedLogSchema, a as parseRequest, p as parseOpenAIResponse, I as InspectorResponseSchema } from "./router-CwmgKXBJ.mjs";
2
+ import { C as CapturedLogSchema, a as parseRequest, p as parseOpenAIResponse, I as InspectorResponseSchema } from "./router-D9uLXa9A.mjs";
3
3
  import { u as useVirtualizer } from "../_libs/tanstack__react-virtual.mjs";
4
4
  import { J as JSZip } from "../_libs/jszip.mjs";
5
5
  import { c as clsx } from "../_libs/clsx.mjs";
@@ -199,7 +199,7 @@ async function exportLogsAsZip(logs) {
199
199
  document.body.removeChild(anchor);
200
200
  URL.revokeObjectURL(url);
201
201
  }
202
- const version = "1.9.0";
202
+ const version = "1.9.1";
203
203
  const packageJson = {
204
204
  version
205
205
  };
@@ -1726,6 +1726,7 @@ function StreamingChunkSequence({
1726
1726
  const [expandedIndices, setExpandedIndices] = reactExports.useState(/* @__PURE__ */ new Set());
1727
1727
  reactExports.useEffect(() => {
1728
1728
  if (!containerExpanded || chunkState.status !== "idle") return;
1729
+ let cancelled = false;
1729
1730
  setChunkState({ status: "loading" });
1730
1731
  fetch(`/api/logs/${logId}/chunks`).then((res) => {
1731
1732
  if (!res.ok) {
@@ -1733,11 +1734,18 @@ function StreamingChunkSequence({
1733
1734
  }
1734
1735
  return res.json();
1735
1736
  }).then((data) => {
1736
- setChunkState({ status: "success", chunks: data.chunks });
1737
+ if (!cancelled) {
1738
+ setChunkState({ status: "success", chunks: data.chunks });
1739
+ }
1737
1740
  }).catch(() => {
1738
- setChunkState({ status: "error", message: "Chunk data unavailable" });
1741
+ if (!cancelled) {
1742
+ setChunkState({ status: "error", message: "Chunk data unavailable" });
1743
+ }
1739
1744
  });
1740
- }, [containerExpanded, logId, chunkState.status]);
1745
+ return () => {
1746
+ cancelled = true;
1747
+ };
1748
+ }, [containerExpanded, logId]);
1741
1749
  const groups = reactExports.useMemo(() => {
1742
1750
  if (chunkState.status !== "success") return [];
1743
1751
  const map = /* @__PURE__ */ new Map();
@@ -197,7 +197,7 @@ function getResponse() {
197
197
  return event.res;
198
198
  }
199
199
  async function getStartManifest(matchedRoutes) {
200
- const { tsrStartManifest } = await import("../_tanstack-start-manifest_v-C7hQOzvX.mjs");
200
+ const { tsrStartManifest } = await import("../_tanstack-start-manifest_v-ByfnNZV_.mjs");
201
201
  const startManifest = tsrStartManifest();
202
202
  const rootRoute = startManifest.routes[rootRouteId] = startManifest.routes[rootRouteId] || {};
203
203
  rootRoute.assets = rootRoute.assets || [];
@@ -766,7 +766,7 @@ let entriesPromise;
766
766
  let baseManifestPromise;
767
767
  let cachedFinalManifestPromise;
768
768
  async function loadEntries() {
769
- const routerEntry = await import("./router-CwmgKXBJ.mjs").then((n) => n.r);
769
+ const routerEntry = await import("./router-D9uLXa9A.mjs").then((n) => n.r);
770
770
  const startEntry = await import("./start-HYkvq4Ni.mjs");
771
771
  return { startEntry, routerEntry };
772
772
  }
@@ -3,7 +3,7 @@ import { j as jsxRuntimeExports } from "../_libs/react.mjs";
3
3
  import { S as SWRConfig } from "../_libs/swr.mjs";
4
4
  import { mkdirSync, writeFileSync, renameSync, copyFileSync, unlinkSync, existsSync, readFileSync } from "node:fs";
5
5
  import path, { join, isAbsolute, dirname } from "node:path";
6
- import { mkdir, appendFile, readFile, writeFile } from "node:fs/promises";
6
+ import { mkdir, appendFile, readFile, writeFile, readdir, stat, unlink } from "node:fs/promises";
7
7
  import { C as Conf } from "../_libs/conf.mjs";
8
8
  import { randomUUID } from "crypto";
9
9
  import { exec } from "node:child_process";
@@ -68,12 +68,12 @@ function RootDocument({ children }) {
68
68
  ] })
69
69
  ] });
70
70
  }
71
- const $$splitComponentImporter = () => import("./index-COIATcfa.mjs");
71
+ const $$splitComponentImporter = () => import("./index-D0d6QxPt.mjs");
72
72
  const Route$f = createFileRoute("/")({
73
73
  component: lazyRouteComponent($$splitComponentImporter, "component")
74
74
  });
75
75
  const LOG_DIR_ENV = process.env["LOG_DIR"];
76
- Number(process.env["LOG_RETENTION_DAYS"] ?? "7");
76
+ const RETENTION_DAYS = Number(process.env["LOG_RETENTION_DAYS"] ?? "7");
77
77
  const LOG_FILE_ENV = process.env["LLM_INSPECTOR_LOG_FILE"];
78
78
  function getUserDataDir() {
79
79
  if (process.platform === "win32") {
@@ -106,6 +106,27 @@ function getInspectorLogPath() {
106
106
  const base = getUserDataDir();
107
107
  return path.join(base, ".llm-inspector", "logs", "inspector.log");
108
108
  }
109
+ async function initLogger() {
110
+ const dir = resolveLogDir();
111
+ const retentionMs = RETENTION_DAYS * 24 * 60 * 60 * 1e3;
112
+ const cutoff = Date.now() - retentionMs;
113
+ try {
114
+ const entries = await readdir(dir);
115
+ for (const entry of entries) {
116
+ if (!entry.endsWith(".jsonl")) continue;
117
+ const fullPath = path.join(dir, entry);
118
+ try {
119
+ const s = await stat(fullPath);
120
+ if (s.mtimeMs < cutoff) {
121
+ await unlink(fullPath);
122
+ }
123
+ } catch {
124
+ }
125
+ }
126
+ } catch (err) {
127
+ console.error("[logger] Failed to initialize log directory:", err);
128
+ }
129
+ }
109
130
  async function writeAppLog(message) {
110
131
  try {
111
132
  const logPath = getInspectorLogPath();
@@ -114,7 +135,8 @@ async function writeAppLog(message) {
114
135
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
115
136
  await appendFile(logPath, `[${timestamp}] ${message}
116
137
  `, "utf-8");
117
- } catch {
138
+ } catch (err) {
139
+ console.error(`[logger] Failed to write to ${getInspectorLogPath()}:`, err);
118
140
  }
119
141
  }
120
142
  const logger = {
@@ -149,7 +171,8 @@ async function flushWriteBuffer() {
149
171
  const filePath = getLogFilePath();
150
172
  await mkdir(path.dirname(filePath), { recursive: true });
151
173
  await appendFile(filePath, toWrite, "utf-8");
152
- } catch {
174
+ } catch (err) {
175
+ console.error("[logger] Failed to flush write buffer:", err);
153
176
  } finally {
154
177
  isFlushing = false;
155
178
  }
@@ -251,12 +274,30 @@ async function findInIndex(id) {
251
274
  const index = await loadIndex();
252
275
  return index.entries[id] ?? null;
253
276
  }
254
- let idGenerationLock = false;
255
- async function getNextLogId() {
256
- while (idGenerationLock) {
257
- await new Promise((resolve) => setTimeout(resolve, 0));
277
+ let idGenerationPromise = null;
278
+ let releaseLock = null;
279
+ async function acquireLock() {
280
+ if (releaseLock === null) {
281
+ idGenerationPromise = new Promise((resolve) => {
282
+ releaseLock = resolve;
283
+ });
284
+ } else {
285
+ await idGenerationPromise;
286
+ idGenerationPromise = new Promise((resolve) => {
287
+ releaseLock = resolve;
288
+ });
289
+ }
290
+ }
291
+ function releaseLockFn() {
292
+ if (releaseLock) {
293
+ const resolve = releaseLock;
294
+ releaseLock = null;
295
+ idGenerationPromise = null;
296
+ resolve();
258
297
  }
259
- idGenerationLock = true;
298
+ }
299
+ async function getNextLogId() {
300
+ await acquireLock();
260
301
  try {
261
302
  const index = await loadIndex();
262
303
  const nextId = index.maxId + 1;
@@ -264,7 +305,7 @@ async function getNextLogId() {
264
305
  cachedIndex = index;
265
306
  return nextId;
266
307
  } finally {
267
- idGenerationLock = false;
308
+ releaseLockFn();
268
309
  }
269
310
  }
270
311
  function getCurrentLogFile() {
@@ -877,8 +918,7 @@ async function getLogById(id) {
877
918
  return null;
878
919
  }
879
920
  function getFilteredLogs(sessionId, model) {
880
- const cachedLogs = Array.from(memoryCache.values());
881
- return cachedLogs.filter((l) => {
921
+ return [...memoryCache.values()].filter((l) => {
882
922
  if (sessionId !== void 0 && l.sessionId !== sessionId) return false;
883
923
  if (model !== void 0 && l.model !== model) return false;
884
924
  return true;
@@ -915,13 +955,17 @@ function onLogUpdate(handler) {
915
955
  };
916
956
  }
917
957
  function emitLogUpdate(log) {
958
+ const failedHandlers = [];
918
959
  for (const handler of sseHandlers) {
919
960
  try {
920
961
  handler(log);
921
962
  } catch {
922
- sseHandlers.delete(handler);
963
+ failedHandlers.push(handler);
923
964
  }
924
965
  }
966
+ for (const handler of failedHandlers) {
967
+ sseHandlers.delete(handler);
968
+ }
925
969
  }
926
970
  const DEFAULT_UPSTREAM$1 = "https://api.anthropic.com";
927
971
  const DEFAULT_OPENAI_UPSTREAM$1 = "https://api.openai.com/v1";
@@ -1858,6 +1902,11 @@ async function getClientInfo(request) {
1858
1902
  setCache(port, info);
1859
1903
  return info;
1860
1904
  }
1905
+ initLogger().then(() => {
1906
+ logger.info("Proxy handler initialized");
1907
+ }).catch((err) => {
1908
+ console.error("[handler] Logger initialization failed:", err);
1909
+ });
1861
1910
  function buildProxyHeaders(originalHeaders) {
1862
1911
  const rawHeaders = {};
1863
1912
  const headers = new Headers();
@@ -1,4 +1,4 @@
1
- const tsrStartManifest = () => ({ "routes": { "__root__": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/__root.tsx", "children": ["/", "/api/health", "/api/logs", "/api/models", "/api/providers", "/api/sessions", "/proxy/$", "/api/config/paths"], "preloads": ["/assets/main-Cu0oTDfX.js"], "assets": [] }, "/": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/index.tsx", "assets": [], "preloads": ["/assets/index-DyKLPMPn.js"] }, "/api/health": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/health.ts" }, "/api/logs": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.ts", "children": ["/api/logs/$id", "/api/logs/stream"] }, "/api/models": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/models.ts" }, "/api/providers": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.ts", "children": ["/api/providers/$providerId", "/api/providers/export", "/api/providers/import"] }, "/api/sessions": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/sessions.ts" }, "/proxy/$": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/proxy/$.ts" }, "/api/config/paths": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/config.paths.ts" }, "/api/logs/$id": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.$id.ts", "children": ["/api/logs/$id/chunks", "/api/logs/$id/replay"] }, "/api/logs/stream": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.stream.ts" }, "/api/providers/$providerId": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.$providerId.ts", "children": ["/api/providers/$providerId/test"] }, "/api/providers/export": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.export.ts" }, "/api/providers/import": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.import.ts" }, "/api/logs/$id/chunks": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.$id.chunks.ts" }, "/api/logs/$id/replay": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.$id.replay.ts" }, "/api/providers/$providerId/test": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.$providerId.test.ts" } }, "clientEntry": "/assets/main-Cu0oTDfX.js" });
1
+ const tsrStartManifest = () => ({ "routes": { "__root__": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/__root.tsx", "children": ["/", "/api/health", "/api/logs", "/api/models", "/api/providers", "/api/sessions", "/proxy/$", "/api/config/paths"], "preloads": ["/assets/main-GVpFMVGE.js"], "assets": [] }, "/": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/index.tsx", "assets": [], "preloads": ["/assets/index-BmEH5jeO.js"] }, "/api/health": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/health.ts" }, "/api/logs": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.ts", "children": ["/api/logs/$id", "/api/logs/stream"] }, "/api/models": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/models.ts" }, "/api/providers": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.ts", "children": ["/api/providers/$providerId", "/api/providers/export", "/api/providers/import"] }, "/api/sessions": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/sessions.ts" }, "/proxy/$": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/proxy/$.ts" }, "/api/config/paths": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/config.paths.ts" }, "/api/logs/$id": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.$id.ts", "children": ["/api/logs/$id/chunks", "/api/logs/$id/replay"] }, "/api/logs/stream": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.stream.ts" }, "/api/providers/$providerId": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.$providerId.ts", "children": ["/api/providers/$providerId/test"] }, "/api/providers/export": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.export.ts" }, "/api/providers/import": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.import.ts" }, "/api/logs/$id/chunks": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.$id.chunks.ts" }, "/api/logs/$id/replay": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.$id.replay.ts" }, "/api/providers/$providerId/test": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.$providerId.test.ts" } }, "clientEntry": "/assets/main-GVpFMVGE.js" });
2
2
  export {
3
3
  tsrStartManifest
4
4
  };
@@ -97,54 +97,54 @@ const headers = ((m) => function headersRouteRule(event) {
97
97
  }
98
98
  });
99
99
  const assets = {
100
+ "/assets/index-DdJSLfxK.css": {
101
+ "type": "text/css; charset=utf-8",
102
+ "etag": '"10da0-LYeZ5d/vwqh4bAnuP/9hr6Wka6g"',
103
+ "mtime": "2026-06-04T06:33:11.914Z",
104
+ "size": 69024,
105
+ "path": "../public/assets/index-DdJSLfxK.css"
106
+ },
100
107
  "/assets/alibaba-TTwafVwX.svg": {
101
108
  "type": "image/svg+xml",
102
109
  "etag": '"171b-6dyV5K8QjiaY35sN9qNprh9zDIs"',
103
- "mtime": "2026-06-04T03:52:13.283Z",
110
+ "mtime": "2026-06-04T06:33:11.914Z",
104
111
  "size": 5915,
105
112
  "path": "../public/assets/alibaba-TTwafVwX.svg"
106
113
  },
107
- "/assets/index-DdJSLfxK.css": {
108
- "type": "text/css; charset=utf-8",
109
- "etag": '"10da0-LYeZ5d/vwqh4bAnuP/9hr6Wka6g"',
110
- "mtime": "2026-06-04T03:52:13.283Z",
111
- "size": 69024,
112
- "path": "../public/assets/index-DdJSLfxK.css"
114
+ "/assets/qwen-CONDcHqt.png": {
115
+ "type": "image/png",
116
+ "etag": '"572c3-cdJAPaHdOvFCGzuaQjagdgOu6XE"',
117
+ "mtime": "2026-06-04T06:33:11.914Z",
118
+ "size": 357059,
119
+ "path": "../public/assets/qwen-CONDcHqt.png"
113
120
  },
114
121
  "/assets/minimax-BPMzvuL-.jpeg": {
115
122
  "type": "image/jpeg",
116
123
  "etag": '"1b06-IwivU89ko5UTMUM1/t7hn4sQK9A"',
117
- "mtime": "2026-06-04T03:52:13.278Z",
124
+ "mtime": "2026-06-04T06:33:11.914Z",
118
125
  "size": 6918,
119
126
  "path": "../public/assets/minimax-BPMzvuL-.jpeg"
120
127
  },
128
+ "/assets/main-GVpFMVGE.js": {
129
+ "type": "text/javascript; charset=utf-8",
130
+ "etag": '"50591-hoJGkyrSE5hjQqC3+NP6Sje9YUs"',
131
+ "mtime": "2026-06-04T06:33:11.914Z",
132
+ "size": 329105,
133
+ "path": "../public/assets/main-GVpFMVGE.js"
134
+ },
121
135
  "/assets/zhipuai-BPNAnxo-.svg": {
122
136
  "type": "image/svg+xml",
123
137
  "etag": '"2bf8-hNaLCTi89nOFCsIIfWpP/jrfo0s"',
124
- "mtime": "2026-06-04T03:52:13.283Z",
138
+ "mtime": "2026-06-04T06:33:11.914Z",
125
139
  "size": 11256,
126
140
  "path": "../public/assets/zhipuai-BPNAnxo-.svg"
127
141
  },
128
- "/assets/main-Cu0oTDfX.js": {
129
- "type": "text/javascript; charset=utf-8",
130
- "etag": '"50591-/K5L0AnXTcumA7dHm7kmA5HXlCE"',
131
- "mtime": "2026-06-04T03:52:13.283Z",
132
- "size": 329105,
133
- "path": "../public/assets/main-Cu0oTDfX.js"
134
- },
135
- "/assets/qwen-CONDcHqt.png": {
136
- "type": "image/png",
137
- "etag": '"572c3-cdJAPaHdOvFCGzuaQjagdgOu6XE"',
138
- "mtime": "2026-06-04T03:52:13.283Z",
139
- "size": 357059,
140
- "path": "../public/assets/qwen-CONDcHqt.png"
141
- },
142
- "/assets/index-DyKLPMPn.js": {
142
+ "/assets/index-BmEH5jeO.js": {
143
143
  "type": "text/javascript; charset=utf-8",
144
- "etag": '"84a31-iF3/oGIdY77bqBWoGeM9Ctiyids"',
145
- "mtime": "2026-06-04T03:52:13.284Z",
146
- "size": 543281,
147
- "path": "../public/assets/index-DyKLPMPn.js"
144
+ "etag": '"84a50-Thjv3JmUhqN6aR4NbGQypCxkmgY"',
145
+ "mtime": "2026-06-04T06:33:11.914Z",
146
+ "size": 543312,
147
+ "path": "../public/assets/index-BmEH5jeO.js"
148
148
  }
149
149
  };
150
150
  function readAsset(id) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tonyclaw/llm-inspector",
3
- "version": "1.9.0",
3
+ "version": "1.9.1",
4
4
  "type": "module",
5
5
  "description": "LLM API proxy inspector — captures and displays requests/responses from AI coding tools in a web UI",
6
6
  "license": "MIT",
@@ -31,6 +31,7 @@ export function StreamingChunkSequence({
31
31
  useEffect(() => {
32
32
  if (!containerExpanded || chunkState.status !== "idle") return;
33
33
 
34
+ let cancelled = false;
34
35
  setChunkState({ status: "loading" });
35
36
 
36
37
  fetch(`/api/logs/${logId}/chunks`)
@@ -41,12 +42,20 @@ export function StreamingChunkSequence({
41
42
  return res.json();
42
43
  })
43
44
  .then((data: { chunks: StreamingChunk[]; truncated?: boolean }) => {
44
- setChunkState({ status: "success", chunks: data.chunks });
45
+ if (!cancelled) {
46
+ setChunkState({ status: "success", chunks: data.chunks });
47
+ }
45
48
  })
46
49
  .catch(() => {
47
- setChunkState({ status: "error", message: "Chunk data unavailable" });
50
+ if (!cancelled) {
51
+ setChunkState({ status: "error", message: "Chunk data unavailable" });
52
+ }
48
53
  });
49
- }, [containerExpanded, logId, chunkState.status]);
54
+
55
+ return () => {
56
+ cancelled = true;
57
+ };
58
+ }, [containerExpanded, logId]);
50
59
 
51
60
  const groups = useMemo<ChunkGroup[]>(() => {
52
61
  if (chunkState.status !== "success") return [];
@@ -1,5 +1,5 @@
1
1
  import { createLog, emitLogUpdate, type CapturedLog } from "./store";
2
- import { appendLogEntry, logger } from "./logger";
2
+ import { appendLogEntry, initLogger, logger } from "./logger";
3
3
  import { writeChunks } from "./chunkStorage";
4
4
  import { extractModelFromBody, type RequestFormat } from "./schemas";
5
5
  import { registry } from "./formats";
@@ -28,6 +28,16 @@ import {
28
28
  STATUS_BAD_GATEWAY,
29
29
  } from "./constants";
30
30
 
31
+ // Initialize logger at startup
32
+ initLogger()
33
+ .then(() => {
34
+ logger.info("Proxy handler initialized");
35
+ })
36
+ .catch((err) => {
37
+ // eslint-disable-next-line no-console
38
+ console.error("[handler] Logger initialization failed:", err);
39
+ });
40
+
31
41
  /**
32
42
  * Strips all custom/non-standard headers from the request and replaces with
33
43
  * unified proxy identity. Only preserves standard HTTP headers needed for API calls.
@@ -201,16 +201,37 @@ export async function rebuildIndex(): Promise<LogIndex> {
201
201
  return newIndex;
202
202
  }
203
203
 
204
- // Mutex for atomic ID generation to prevent race conditions
205
- let idGenerationLock = false;
204
+ // Async mutex for atomic ID generation to prevent race conditions
205
+ // Uses a promise queue instead of busy-waiting
206
+ let idGenerationPromise: Promise<void> | null = null;
207
+ let releaseLock: (() => void) | null = null;
208
+
209
+ async function acquireLock(): Promise<void> {
210
+ if (releaseLock === null) {
211
+ idGenerationPromise = new Promise<void>((resolve) => {
212
+ releaseLock = resolve;
213
+ });
214
+ } else {
215
+ // Wait for the previous lock to be released
216
+ await idGenerationPromise;
217
+ // After waiting, we need to create a new promise for the next waiter
218
+ idGenerationPromise = new Promise<void>((resolve) => {
219
+ releaseLock = resolve;
220
+ });
221
+ }
222
+ }
206
223
 
207
- export async function getNextLogId(): Promise<number> {
208
- // Wait for any ongoing ID generation to complete
209
- while (idGenerationLock) {
210
- // Use setTimeout(0) to yield to event loop
211
- await new Promise((resolve) => setTimeout(resolve, 0));
224
+ function releaseLockFn(): void {
225
+ if (releaseLock) {
226
+ const resolve = releaseLock;
227
+ releaseLock = null;
228
+ idGenerationPromise = null;
229
+ resolve();
212
230
  }
213
- idGenerationLock = true;
231
+ }
232
+
233
+ export async function getNextLogId(): Promise<number> {
234
+ await acquireLock();
214
235
  try {
215
236
  const index = await loadIndex();
216
237
  const nextId = index.maxId + 1;
@@ -219,7 +240,7 @@ export async function getNextLogId(): Promise<number> {
219
240
  cachedIndex = index;
220
241
  return nextId;
221
242
  } finally {
222
- idGenerationLock = false;
243
+ releaseLockFn();
223
244
  }
224
245
  }
225
246
 
@@ -60,11 +60,13 @@ export async function initLogger(): Promise<void> {
60
60
  await unlink(fullPath);
61
61
  }
62
62
  } catch {
63
- // Skip files that can't be stat
63
+ // Skip files that can't be stat - not critical
64
64
  }
65
65
  }
66
- } catch {
67
- // Skip directory initialization errors
66
+ } catch (err) {
67
+ // Log directory initialization errors but don't fail startup
68
+ // eslint-disable-next-line no-console
69
+ console.error("[logger] Failed to initialize log directory:", err);
68
70
  }
69
71
  }
70
72
 
@@ -76,8 +78,10 @@ async function writeAppLog(message: string): Promise<void> {
76
78
  await mkdir(logDirPath, { recursive: true });
77
79
  const timestamp = new Date().toISOString();
78
80
  await appendFile(logPath, `[${timestamp}] ${message}\n`, "utf-8");
79
- } catch {
80
- // Silently fail if we can't write to log
81
+ } catch (err) {
82
+ // Log to stderr since file logging failed
83
+ // eslint-disable-next-line no-console
84
+ console.error(`[logger] Failed to write to ${getInspectorLogPath()}:`, err);
81
85
  }
82
86
  }
83
87
 
@@ -119,8 +123,10 @@ async function flushWriteBuffer(): Promise<void> {
119
123
  const filePath = getLogFilePath();
120
124
  await mkdir(path.dirname(filePath), { recursive: true });
121
125
  await appendFile(filePath, toWrite, "utf-8");
122
- } catch {
123
- // Silently fail write buffer errors
126
+ } catch (err) {
127
+ // Log write buffer errors but don't throw to prevent cascading failures
128
+ // eslint-disable-next-line no-console
129
+ console.error("[logger] Failed to flush write buffer:", err);
124
130
  } finally {
125
131
  isFlushing = false;
126
132
  }
@@ -266,9 +266,8 @@ export async function getLogById(id: number): Promise<CapturedLog | null> {
266
266
 
267
267
  export function getFilteredLogs(sessionId?: string, model?: string): CapturedLog[] {
268
268
  // Cache maintains insertion order (sorted by ID since logs are added in ID order)
269
- const cachedLogs = Array.from(memoryCache.values());
270
-
271
- return cachedLogs.filter((l) => {
269
+ // Use spread instead of Array.from for slightly better performance
270
+ return [...memoryCache.values()].filter((l) => {
272
271
  if (sessionId !== undefined && l.sessionId !== sessionId) return false;
273
272
  if (model !== undefined && l.model !== model) return false;
274
273
  return true;
@@ -385,12 +384,17 @@ export function onLogUpdate(handler: LogUpdateHandler): () => void {
385
384
  }
386
385
 
387
386
  export function emitLogUpdate(log: CapturedLog): void {
387
+ const failedHandlers: LogUpdateHandler[] = [];
388
388
  for (const handler of sseHandlers) {
389
389
  try {
390
390
  handler(log);
391
391
  } catch {
392
- // Remove handler that threw
393
- sseHandlers.delete(handler);
392
+ // Collect failed handlers to remove after iteration
393
+ failedHandlers.push(handler);
394
394
  }
395
395
  }
396
+ // Remove failed handlers after iteration to avoid Set mutation during for...of
397
+ for (const handler of failedHandlers) {
398
+ sseHandlers.delete(handler);
399
+ }
396
400
  }