@hazeljs/inspector 0.2.0-rc.5

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 (75) hide show
  1. package/LICENSE +192 -0
  2. package/README.md +97 -0
  3. package/dist/config/inspector.config.d.ts +8 -0
  4. package/dist/config/inspector.config.d.ts.map +1 -0
  5. package/dist/config/inspector.config.js +38 -0
  6. package/dist/contracts/types.d.ts +253 -0
  7. package/dist/contracts/types.d.ts.map +1 -0
  8. package/dist/contracts/types.js +5 -0
  9. package/dist/index.d.ts +11 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +14 -0
  12. package/dist/inspector.module.d.ts +25 -0
  13. package/dist/inspector.module.d.ts.map +1 -0
  14. package/dist/inspector.module.js +489 -0
  15. package/dist/plugins/agent.inspector.d.ts +8 -0
  16. package/dist/plugins/agent.inspector.d.ts.map +1 -0
  17. package/dist/plugins/agent.inspector.js +51 -0
  18. package/dist/plugins/ai.inspector.d.ts +8 -0
  19. package/dist/plugins/ai.inspector.d.ts.map +1 -0
  20. package/dist/plugins/ai.inspector.js +87 -0
  21. package/dist/plugins/core.inspector.d.ts +8 -0
  22. package/dist/plugins/core.inspector.d.ts.map +1 -0
  23. package/dist/plugins/core.inspector.js +203 -0
  24. package/dist/plugins/cron.inspector.d.ts +8 -0
  25. package/dist/plugins/cron.inspector.d.ts.map +1 -0
  26. package/dist/plugins/cron.inspector.js +74 -0
  27. package/dist/plugins/data.inspector.d.ts +8 -0
  28. package/dist/plugins/data.inspector.d.ts.map +1 -0
  29. package/dist/plugins/data.inspector.js +50 -0
  30. package/dist/plugins/event-emitter.inspector.d.ts +8 -0
  31. package/dist/plugins/event-emitter.inspector.d.ts.map +1 -0
  32. package/dist/plugins/event-emitter.inspector.js +53 -0
  33. package/dist/plugins/flow.inspector.d.ts +8 -0
  34. package/dist/plugins/flow.inspector.d.ts.map +1 -0
  35. package/dist/plugins/flow.inspector.js +112 -0
  36. package/dist/plugins/graphql.inspector.d.ts +8 -0
  37. package/dist/plugins/graphql.inspector.d.ts.map +1 -0
  38. package/dist/plugins/graphql.inspector.js +75 -0
  39. package/dist/plugins/grpc.inspector.d.ts +8 -0
  40. package/dist/plugins/grpc.inspector.d.ts.map +1 -0
  41. package/dist/plugins/grpc.inspector.js +53 -0
  42. package/dist/plugins/kafka.inspector.d.ts +8 -0
  43. package/dist/plugins/kafka.inspector.d.ts.map +1 -0
  44. package/dist/plugins/kafka.inspector.js +59 -0
  45. package/dist/plugins/ml.inspector.d.ts +8 -0
  46. package/dist/plugins/ml.inspector.d.ts.map +1 -0
  47. package/dist/plugins/ml.inspector.js +78 -0
  48. package/dist/plugins/prompts.inspector.d.ts +7 -0
  49. package/dist/plugins/prompts.inspector.d.ts.map +1 -0
  50. package/dist/plugins/prompts.inspector.js +41 -0
  51. package/dist/plugins/queue.inspector.d.ts +8 -0
  52. package/dist/plugins/queue.inspector.d.ts.map +1 -0
  53. package/dist/plugins/queue.inspector.js +55 -0
  54. package/dist/plugins/rag.inspector.d.ts +8 -0
  55. package/dist/plugins/rag.inspector.d.ts.map +1 -0
  56. package/dist/plugins/rag.inspector.js +72 -0
  57. package/dist/plugins/serverless.inspector.d.ts +8 -0
  58. package/dist/plugins/serverless.inspector.d.ts.map +1 -0
  59. package/dist/plugins/serverless.inspector.js +53 -0
  60. package/dist/plugins/websocket.inspector.d.ts +8 -0
  61. package/dist/plugins/websocket.inspector.d.ts.map +1 -0
  62. package/dist/plugins/websocket.inspector.js +73 -0
  63. package/dist/registry/registry.d.ts +12 -0
  64. package/dist/registry/registry.d.ts.map +1 -0
  65. package/dist/registry/registry.js +43 -0
  66. package/dist/runtime/inspector-runtime.d.ts +66 -0
  67. package/dist/runtime/inspector-runtime.d.ts.map +1 -0
  68. package/dist/runtime/inspector-runtime.js +97 -0
  69. package/dist/service/inspector.service.d.ts +37 -0
  70. package/dist/service/inspector.service.d.ts.map +1 -0
  71. package/dist/service/inspector.service.js +146 -0
  72. package/package.json +124 -0
  73. package/ui-dist/assets/index-BN8Zr7QX.css +1 -0
  74. package/ui-dist/assets/index-DLS5TpZI.js +80 -0
  75. package/ui-dist/index.html +316 -0
@@ -0,0 +1,80 @@
1
+ (function(){const n=document.createElement("link").relList;if(n&&n.supports&&n.supports("modulepreload"))return;for(const o of document.querySelectorAll('link[rel="modulepreload"]'))s(o);new MutationObserver(o=>{for(const r of o)if(r.type==="childList")for(const l of r.addedNodes)l.tagName==="LINK"&&l.rel==="modulepreload"&&s(l)}).observe(document,{childList:!0,subtree:!0});function t(o){const r={};return o.integrity&&(r.integrity=o.integrity),o.referrerPolicy&&(r.referrerPolicy=o.referrerPolicy),o.crossOrigin==="use-credentials"?r.credentials="include":o.crossOrigin==="anonymous"?r.credentials="omit":r.credentials="same-origin",r}function s(o){if(o.ep)return;o.ep=!0;const r=t(o);fetch(o.href,r)}})();const C=(()=>{const e=window.location.pathname.match(/^\/[^/]+/);return e?e[0]:"/__hazel"})(),ve=window.location.origin;let b=null,J=!1,B=[];const Me=60;async function Ae(e=!1){const n=`${C}/inspect${e?"?refresh=1":""}`,t=await fetch(n);if(!t.ok)throw new Error(`Failed to fetch: ${t.status}`);return t.json()}async function je(){const e=await fetch(`${C}/stats`);return e.ok?e.json():{}}async function Ce(){const e=await fetch(`${C}/env`);return e.ok?e.json():{}}async function z(e){try{const n=await fetch(`${ve}${e}`),t=n.ok;let s;const o=n.headers.get("content-type");return o!=null&&o.includes("application/json")?s=await n.json():s=await n.text(),{status:t?"up":"down",ok:t,data:s}}catch{return{status:"down",ok:!1}}}function V(e){const n=document.getElementById("loading-overlay");n&&n.classList.toggle("hidden",!e)}function K(e,n){var h,p,w,f,i,m;const t=document.getElementById("status-dot"),s=document.getElementById("status-text"),o=document.getElementById("status-uptime");if(!t||!s||!o)return;const r=((h=e==null?void 0:e.health)==null?void 0:h.ok)&&((p=e==null?void 0:e.ready)==null?void 0:p.ok)&&((w=e==null?void 0:e.startup)==null?void 0:w.ok),l=((f=e==null?void 0:e.health)==null?void 0:f.ok)||((i=e==null?void 0:e.ready)==null?void 0:i.ok)||((m=e==null?void 0:e.startup)==null?void 0:m.ok);t.className="status-dot"+(r?" healthy":l?"":" unhealthy"),s.textContent=r?"All systems operational":l?"Degraded":"Offline",o.textContent=n.uptimeSeconds!=null?`Uptime: ${he(n.uptimeSeconds)}`:""}function Y(e){const n=document.getElementById("quick-stats");if(!n)return;const t=e&&typeof e=="object"?e:{},s=[];(t.route??0)>0&&s.push(`<span class="quick-stat"><strong>${t.route}</strong> routes</span>`),(t.module??0)>0&&s.push(`<span class="quick-stat"><strong>${t.module}</strong> modules</span>`),(t.provider??0)>0&&s.push(`<span class="quick-stat"><strong>${t.provider}</strong> providers</span>`),(t.cron??0)>0&&s.push(`<span class="quick-stat"><strong>${t.cron}</strong> jobs</span>`),n.innerHTML=s.join("")||'<span class="quick-stat muted">No data</span>'}function X(e){var t,s;let n=document.getElementById("offline-banner");e&&!n&&(n=document.createElement("div"),n.id="offline-banner",n.className="offline-banner",n.innerHTML='<span>App not running. Check that your server is started.</span><button id="retry-btn">Retry</button>',(t=document.querySelector(".content"))==null||t.insertBefore(n,document.querySelector(".toolbar")),(s=n.querySelector("#retry-btn"))==null||s.addEventListener("click",()=>O(!0))),n&&n.classList.toggle("hidden",!e)}function he(e){if(e<60)return`${Math.floor(e)}s`;if(e<3600)return`${Math.floor(e/60)}m ${e%60}s`;const n=Math.floor(e/3600),t=Math.floor(e%3600/60);return`${n}h ${t}m`}function Te(e){const n=String(e||"").toUpperCase();return`<span class="badge badge-${n==="GET"?"get":n==="POST"?"post":n==="PUT"?"put":n==="PATCH"?"patch":n==="DELETE"?"delete":"default"}">${n||"?"}</span>`}function Oe(e){return JSON.stringify(e,null,2).replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?)/g,t=>{let s="json-number";return/^"/.test(t)?s=t.endsWith(":")?"json-key":"json-string":/true|false/.test(t)?s="json-boolean":/null/.test(t)&&(s="json-null"),`<span class="${s}">${y(t)}</span>`})}function y(e){const n=document.createElement("div");return n.textContent=e,n.innerHTML}const qe={route:'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>',module:'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/><polyline points="3.27 6.96 12 12.01 20.73 6.96"/><line x1="12" y1="22.08" x2="12" y2="12"/></svg>',provider:'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"/><path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"/></svg>',cron:'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>',queue:'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></svg>',websocket:'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>',agent:'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="10" rx="2"/><circle cx="12" cy="5" r="2"/><path d="M12 7v4"/></svg>',rag:'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/><path d="M8 7h8"/><path d="M8 11h8"/></svg>',prompt:'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>',aifunction:'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"/></svg>',event:'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 2v4"/><path d="M16 2v4"/><rect x="3" y="4" width="18" height="18" rx="2"/><path d="M3 10h18"/><path d="M8 14h.01"/><path d="M12 14h.01"/><path d="M16 14h.01"/></svg>',graphql:'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3v18"/><path d="M5 12h14"/><path d="M3 8l9-5 9 5"/><path d="M3 16l9 5 9-5"/></svg>',grpc:'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="M12 5l7 7-7 7"/></svg>',kafka:'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/><path d="M9 9h6"/><path d="M9 13h6"/><path d="M9 17h4"/></svg>',flow:'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>',data:'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/></svg>',serverless:'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 10h-1.26A8 8 0 1 0 9 20h9a5 5 0 0 0 0-10z"/></svg>',ml:'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2v4"/><path d="M12 18v4"/><path d="m4.93 4.93 2.83 2.83"/><path d="m16.24 16.24 2.83 2.83"/><path d="M2 12h4"/><path d="M18 12h4"/><path d="m4.93 19.07 2.83-2.83"/><path d="m16.24 7.76 2.83-2.83"/><circle cx="12" cy="12" r="4"/></svg>',decorator:'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z"/><line x1="7" y1="7" x2="7.01" y2="7"/></svg>'},Re=[{title:"Framework",items:[{key:"route",label:"Routes"},{key:"module",label:"Modules"},{key:"provider",label:"Providers"},{key:"decorator",label:"Decorators"}]},{title:"Scheduled & Async",items:[{key:"cron",label:"Cron Jobs"},{key:"queue",label:"Queues"}]},{title:"AI & Intelligence",items:[{key:"agent",label:"Agents"},{key:"aifunction",label:"AI Functions"},{key:"rag",label:"RAG"},{key:"prompt",label:"Prompts"},{key:"ml",label:"ML"}]},{title:"APIs & Messaging",items:[{key:"graphql",label:"GraphQL"},{key:"grpc",label:"gRPC"},{key:"kafka",label:"Kafka"},{key:"websocket",label:"WebSockets"},{key:"event",label:"Events"}]},{title:"Workflows & Data",items:[{key:"flow",label:"Flows"},{key:"data",label:"Data"},{key:"serverless",label:"Serverless"}]}];function fe(e){const n=document.getElementById("summary-cards"),t=e&&typeof e=="object"?e:{};n.innerHTML=Re.map(s=>`
2
+ <section class="overview-section">
3
+ <h3 class="overview-section-title">${y(s.title)}</h3>
4
+ <div class="overview-section-cards">
5
+ ${(Array.isArray(s.items)?s.items:[]).map(o=>`<div class="card" data-kind="${y(o.key)}">
6
+ <div class="card-icon">${qe[o.key]??""}</div>
7
+ <div class="card-label">${y(o.label)}</div>
8
+ <div class="card-value">${t[o.key]??0}</div>
9
+ </div>`).join("")}
10
+ </div>
11
+ </section>
12
+ `).join("")}const G={heap:'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2v4"/><path d="M12 18v4"/><path d="m4.93 4.93 2.83 2.83"/><path d="m16.24 16.24 2.83 2.83"/><path d="M2 12h4"/><path d="M18 12h4"/><path d="m4.93 19.07 2.83-2.83"/><path d="m16.24 7.76 2.83-2.83"/><circle cx="12" cy="12" r="4"/></svg>',rss:'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8"/><path d="M12 17v4"/></svg>',uptime:'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>'};function Pe(e){const n=document.getElementById("env-info");n&&(n.innerHTML=`
13
+ <div class="env-item"><strong>Node</strong> ${y(e.nodeVersion??"—")}</div>
14
+ <div class="env-item"><strong>NODE_ENV</strong> ${y(e.nodeEnv??"—")}</div>
15
+ <div class="env-item"><strong>Inspector</strong> ${y(e.inspectorVersion??"—")}</div>
16
+ <div class="env-item"><strong>Platform</strong> ${y(e.platform??"—")}</div>
17
+ <div class="env-item"><strong>Arch</strong> ${y(e.arch??"—")}</div>
18
+ `)}function He(e){const n=document.getElementById("overview-gateway");if(!n)return;const t=Array.isArray(e.routes)?e.routes:[],s=e.metrics;n.innerHTML=`
19
+ <h3 class="overview-block-title">Gateway</h3>
20
+ <div class="overview-gateway-stats">
21
+ <div class="overview-stat"><span class="stat-value">${t.length}</span><span class="stat-label">Routes</span></div>
22
+ ${s?`
23
+ <div class="overview-stat"><span class="stat-value">${s.totalCalls}</span><span class="stat-label">Total Calls</span></div>
24
+ <div class="overview-stat"><span class="stat-value">${s.successCalls}</span><span class="stat-label">Success</span></div>
25
+ <div class="overview-stat"><span class="stat-value">${(s.failureRate??0).toFixed(1)}%</span><span class="stat-label">Failure Rate</span></div>
26
+ <div class="overview-stat"><span class="stat-value">${(s.averageResponseTime??0).toFixed(0)}ms</span><span class="stat-label">Avg Latency</span></div>
27
+ `:""}
28
+ </div>
29
+ ${t.length?`<div class="overview-gateway-routes"><strong>Routes:</strong> ${t.slice(0,8).map(o=>`<code>${y(o)}</code>`).join(", ")}${t.length>8?` <span class="muted">+${t.length-8} more</span>`:""}</div>`:""}
30
+ `,n.classList.remove("hidden")}function Fe(e){const n=document.getElementById("overview-discovery");if(!n)return;const t=Array.isArray(e.services)?e.services:[],s=e.instancesByService&&typeof e.instancesByService=="object"?e.instancesByService:{},o=t.slice(0,6).map(r=>`<span class="discovery-service"><code>${y(r)}</code>: ${s[r]??0} instance(s)</span>`).join(", ");n.innerHTML=`
31
+ <h3 class="overview-block-title">Discovery</h3>
32
+ <div class="overview-discovery-stats">
33
+ <div class="overview-stat"><span class="stat-value">${e.totalServices??0}</span><span class="stat-label">Services</span></div>
34
+ <div class="overview-stat"><span class="stat-value">${e.totalInstances??0}</span><span class="stat-label">Connected Instances</span></div>
35
+ </div>
36
+ ${t.length?`<div class="overview-discovery-services">${o}${t.length>6?` <span class="muted">+${t.length-6} more</span>`:""}</div>`:'<p class="muted">No services registered</p>'}
37
+ `,n.classList.remove("hidden")}function De(e){const n=document.getElementById("overview-resilience");if(!n)return;const t=Array.isArray(e.circuitBreakerStates)?e.circuitBreakerStates:[],s=t.map(o=>`<span class="cb-state ${(o.state||"").toLowerCase()}"><code>${y(o.name)}</code>: ${y(o.state)}</span>`).join(", ");n.innerHTML=`
38
+ <h3 class="overview-block-title">Resilience</h3>
39
+ <div class="overview-resilience-stats">
40
+ <div class="overview-stat"><span class="stat-value">${e.circuitBreakers??0}</span><span class="stat-label">Circuit Breakers</span></div>
41
+ </div>
42
+ ${t.length?`<div class="overview-resilience-states">${s}</div>`:""}
43
+ `,n.classList.remove("hidden")}function Ue(e){const n=document.getElementById("health-cards");if(!n)return;const t=[{key:"health",endpoint:"/health",label:"Health",data:e.health},{key:"ready",endpoint:"/ready",label:"Ready",data:e.ready},{key:"startup",endpoint:"/startup",label:"Startup",data:e.startup}];n.innerHTML=t.map(s=>{const o=s.data??{status:"unknown",ok:!1};return`
44
+ <div class="health-card ${o.ok?"healthy":o.status==="unknown"?"unknown":"unhealthy"}">
45
+ <h3>${y(s.label)}</h3>
46
+ <div class="status">${o.ok?"Up":o.status==="unknown"?"Unknown":"Down"}</div>
47
+ <div class="endpoint">${y(s.endpoint)}</div>
48
+ </div>
49
+ `}).join("")}function _e(e){var s,o;const n=document.getElementById("runtime-cards"),t=r=>(r/1024/1024).toFixed(2);e.memory&&(B.push({heap:e.memory.heapUsed,rss:e.memory.rss,t:Date.now()}),B.length>Me&&B.shift()),n.innerHTML=`
50
+ <div class="card">
51
+ <div class="card-icon">${G.heap}</div>
52
+ <div class="card-label">Heap Used</div>
53
+ <div class="card-value">${(s=e.memory)!=null&&s.heapUsed?t(e.memory.heapUsed)+" MB":"—"}</div>
54
+ </div>
55
+ <div class="card">
56
+ <div class="card-icon">${G.rss}</div>
57
+ <div class="card-label">RSS Memory</div>
58
+ <div class="card-value">${(o=e.memory)!=null&&o.rss?t(e.memory.rss)+" MB":"—"}</div>
59
+ </div>
60
+ <div class="card">
61
+ <div class="card-icon">${G.uptime}</div>
62
+ <div class="card-label">Uptime</div>
63
+ <div class="card-value highlight">${e.uptimeSeconds!=null?he(e.uptimeSeconds):"—"}</div>
64
+ </div>
65
+ `,Je()}function Je(){const e=document.getElementById("memory-chart-container");if(!e||B.length<2){e==null||e.classList.add("hidden");return}e.classList.remove("hidden");const n=Math.max(...B.map(l=>l.heap)),t=Math.max(...B.map(l=>l.rss)),s=Math.max(n,t,1),o=l=>l/1024/1024/s*100,r=B.map((l,h)=>`${h/(B.length-1)*100},${100-o(l.heap)}`).join(" ");e.innerHTML=`
66
+ <svg width="100%" height="100%" viewBox="0 0 400 180" preserveAspectRatio="none">
67
+ <polyline fill="none" stroke="var(--accent)" stroke-width="2" points="${r}"/>
68
+ </svg>
69
+ <div style="font-size:11px;color:var(--text-muted);margin-top:0.5rem">Heap over time (last ${B.length} samples)</div>
70
+ `}const Q={},P=50;function ze(e){const n=new Map;for(const s of e){const o=String(s.flowId??"");n.has(o)||n.set(o,[]),n.get(o).push(s)}const t=new Map;for(const[s,o]of n){const l=o.find(a=>!!String(a.nodes??"").trim())??o[0];let p=(l.nodes??"").split(/[,]/).map(a=>a.trim()).filter(Boolean);p.length===0&&(p=o.map(a=>a.nodeName).filter(a=>!!a));const i=(l.edges??"").toString().split(/[;,]/).map(a=>a.trim()).filter(Boolean).map(a=>{const c=a.indexOf("→");if(c<0)return null;const d=a.slice(0,c).trim(),k=a.slice(c+1).trim();return d&&k?{from:d,to:k}:null}).filter(a=>a!=null);for(const a of o){const c=(a.edges??"").toString().split(/[;,]/);for(const d of c){const k=d.indexOf("→");if(k>=0){const x=d.slice(0,k).trim(),$=d.slice(k+1).trim();x&&$&&!i.some(S=>S.from===x&&S.to===$)&&i.push({from:x,to:$})}}}const m=String(l.entryNode??p[0]??"");t.set(s,{nodes:[...new Set(p)],edges:i,entryNode:m})}return t}const ye=48,we=24,Ge=6,We=4,D=6;function Ve(e){const n=new Map,t=new Map,s=e.entryNode||e.nodes[0];if(!s)return n;t.set(s,0);const o=[s],r=new Set([s]);for(;o.length>0;){const i=o.shift(),m=t.get(i)??0;for(const a of e.edges)if(a.from===i)if(!r.has(a.to))r.add(a.to),t.set(a.to,m+1),o.push(a.to);else{const c=t.get(a.to)??0;m+1>c&&t.set(a.to,m+1)}}const l=Math.max(0,...Array.from(t.values()));for(const i of e.nodes)t.has(i)||t.set(i,l+1);const h=new Map;for(const[i,m]of t)h.has(m)||h.set(m,[]),h.get(m).push(i);const p=ye+Ge,w=we+We,f=[...h.keys()].sort((i,m)=>i-m);for(let i=0;i<f.length;i++){const m=f[i],a=h.get(m)??[];for(let c=0;c<a.length;c++){const d=a[c],k=D+i*p,x=D+c*w;n.set(d,{x:k,y:x})}}return n}function ke(e){const n=document.getElementById("flow-diagram"),t=Array.isArray(e)?e:[];if(!n||!t.length){n==null||n.classList.add("hidden");return}const s=ze(t);if(s.size===0){n==null||n.classList.add("hidden");return}const o=ye,r=we;let l="";for(const[h,p]of s){const w=Ve(p);if(w.size===0)continue;const f=Math.max(...Array.from(w.values()).map(d=>d.x))+o+D*2,i=Math.max(...Array.from(w.values()).map(d=>d.y))+r+D*2,m=Math.max(240,f),a=Math.max(48,i);let c=`<svg class="flow-diagram-svg" viewBox="0 0 ${m} ${a}" xmlns="http://www.w3.org/2000/svg">`;for(const{from:d,to:k}of p.edges){const x=w.get(d),$=w.get(k);if(x&&$){const S=x.x+o,A=x.y+r/2,I=$.x,L=$.y+r/2,N=(S+I)/2;c+=`<path d="M ${S} ${A} C ${N} ${A} ${N} ${L} ${I} ${L}" fill="none" stroke="var(--flow-edge)" stroke-width="1" class="flow-edge"/>`;const u=4,T=I-u*Math.cos(Math.PI/6),_=L-u*Math.sin(Math.PI/6),q=I-u*Math.cos(-Math.PI/6),g=L-u*Math.sin(-Math.PI/6);c+=`<polygon points="${I},${L} ${T},${_} ${q},${g}" fill="var(--flow-edge)" class="flow-arrow"/>`}}for(const[d,k]of w){const $=d===p.entryNode?"flow-diagram-node entry":"flow-diagram-node",S=d.length>10?d.slice(0,8)+"…":d;c+=`<g class="flow-node-group"><rect class="${$}" x="${k.x}" y="${k.y}" width="${o}" height="${r}" rx="4"/><text x="${k.x+o/2}" y="${k.y+r/2+3}" text-anchor="middle" font-size="9" fill="var(--text-primary)" class="flow-node-label">${y(S)}</text></g>`}c+="</svg>",l+=`<div class="flow-diagram-card"><span class="flow-diagram-badge" title="${y(h)}">${y(h)}</span><div class="flow-diagram-svg-wrap">${c}</div></div>`}n.innerHTML=l,n.classList.remove("hidden")}function be(e){const n=document.getElementById("rag-explorer"),t=document.getElementById("rag-pipeline-select"),s=document.getElementById("rag-results");if(!n||!t||!s)return;const o=Array.isArray(e)?e:[];if(!o.length){n.classList.add("hidden");return}n.classList.remove("hidden"),t.innerHTML=o.map(r=>`<option value="${y(String(r.pipelineName??""))}">${y(String(r.pipelineName??""))}</option>`).join(""),s.innerHTML=""}async function Ke(){const e=document.getElementById("rag-pipeline-select"),n=document.getElementById("rag-search-input"),t=document.getElementById("rag-results");if(!e||!n||!t)return;const s=e.value,o=n.value.trim();if(o){t.innerHTML="<p>Searching...</p>";try{const r=await fetch(`${C}/rag/${encodeURIComponent(s)}/search?q=${encodeURIComponent(o)}`),l=await r.json();if(!r.ok){t.innerHTML=`<p class="error">${y(l.error??"Search failed")}</p>`;return}const h=l.results??[];if(!h.length){t.innerHTML="<p>No results found.</p>";return}t.innerHTML=h.map(p=>`<div class="rag-result-item"><span class="score">${p.score!=null?(p.score*100).toFixed(1)+"%":"—"}</span> ${y(String(p.content??"").slice(0,200))}${String(p.content??"").length>200?"...":""}</div>`).join("")}catch(r){t.innerHTML=`<p class="error">${y(String(r))}</p>`}}}function xe(e){const n=document.getElementById("module-graph-container"),t=Array.isArray(e)?e:[];if(!n||!t.length){n==null||n.classList.add("hidden");return}const s=new Map,o=[],r=t.map(f=>String(f.moduleName??"")).filter(Boolean),l=[...new Set(r)];l.forEach((f,i)=>{const m=Math.floor(i/4),a=i%4;s.set(f,{x:80+a*120,y:40+m*60})});for(const f of t){const i=String(f.moduleName??""),m=f.imports,a=Array.isArray(m)?m:typeof m=="string"?m.split(/[,;]/).map(c=>c.trim()):[];for(const c of a){const d=String(c).trim();d&&(l.includes(d)||s.has(d))&&(o.push({from:i,to:d}),s.has(d)||s.set(d,{x:80+s.size%4*120,y:40+Math.floor(s.size/4)*60}))}}const h=500,p=Math.max(200,Math.ceil(l.length/4)*70);let w=`<svg class="module-graph-svg" viewBox="0 0 ${h} ${p}" xmlns="http://www.w3.org/2000/svg">`;for(const{from:f,to:i}of o){const m=s.get(f),a=s.get(i);m&&a&&(w+=`<line x1="${m.x+50}" y1="${m.y+15}" x2="${a.x+50}" y2="${a.y+15}" stroke="var(--border)" stroke-width="1"/>`)}for(const[f,i]of s)w+=`<rect x="${i.x}" y="${i.y}" width="100" height="30" rx="4" fill="var(--bg-tertiary)" stroke="var(--border)"/>`,w+=`<text x="${i.x+50}" y="${i.y+20}" text-anchor="middle" font-size="11" fill="var(--text-primary)">${y(f.length>12?f.slice(0,10)+"..":f)}</text>`;w+="</svg>",n.innerHTML=w,n.classList.remove("hidden")}function v(e,n,t,s,o,r){const l=document.getElementById(e),h=Q[e]??{col:t[0],dir:"asc"};let p=[...n];r!=null&&r.sortable&&p.length>0&&p.sort((a,c)=>{const d=a[h.col],k=c[h.col],x=String(d??"").localeCompare(String(k??""),void 0,{numeric:!0});return h.dir==="asc"?x:-x});const w=p.length>P?p.slice(0,P):p,f=p.length>P;if(!n.length){l.innerHTML=`<thead></thead><tbody><tr><td colspan="${t.length+(r!=null&&r.tryRoute||r!=null&&r.runAgent?1:0)}" class="empty-state"><p>No entries found</p></td></tr></tbody>`;return}const i=o??{},m=t.map(a=>{const c=a.replace(/([A-Z])/g," $1").trim();return`<th class="${r!=null&&r.sortable?` sortable ${h.col===a?h.dir:""}`:""}" data-col="${a}">${c}</th>`});if(r!=null&&r.tryRoute&&m.push("<th>Actions</th>"),r!=null&&r.runAgent&&m.push("<th>Actions</th>"),r!=null&&r.previewPrompt&&m.push("<th>Actions</th>"),l.innerHTML=`
71
+ <thead><tr>${m.join("")}</tr></thead>
72
+ <tbody>
73
+ ${w.map(a=>{let c="";if(r!=null&&r.tryRoute&&a.fullPath!=null){const d=String(a.fullPath);c=`<td><button class="btn btn-sm try-route" data-method="${String(a.httpMethod??"GET").toUpperCase()}" data-path="${y(d)}">Try</button></td>`}else r!=null&&r.runAgent&&a.agentName!=null?c=`<td><button class="btn btn-sm run-agent" data-name="${y(String(a.agentName))}">Run</button></td>`:r!=null&&r.previewPrompt&&a.promptKey!=null?c=`<td><button class="btn btn-sm preview-prompt" data-key="${y(String(a.promptKey))}">Preview</button></td>`:(r!=null&&r.tryRoute||r!=null&&r.runAgent||r!=null&&r.previewPrompt)&&(c="<td></td>");return`<tr data-id="${a.id??""}" data-json='${JSON.stringify(a).replace(/'/g,"\\'")}'>
74
+ ${t.map(d=>{const k=a[d],x=i[d];return`<td>${x?x(k,a):String(k??"—")}</td>`}).join("")}
75
+ ${c}
76
+ </tr>`}).join("")}
77
+ </tbody>
78
+ `,f){const a=document.createElement("tr");a.innerHTML=`<td colspan="${t.length+(r!=null&&r.tryRoute||r!=null&&r.runAgent?1:0)}" class="empty-state"><p>Showing ${P} of ${p.length}. Use search to filter.</p></td>`,l.querySelector("tbody").appendChild(a)}l.querySelectorAll("tbody tr[data-json]").forEach(a=>{a.addEventListener("click",c=>{if(c.target.closest("button"))return;const d=a.dataset.json;d&&F(JSON.parse(d))})}),l.querySelectorAll("th.sortable").forEach(a=>{a.addEventListener("click",()=>{const c=a.dataset.col;Q[e]={col:c,dir:h.col===c&&h.dir==="asc"?"desc":"asc"},v(e,n,t,s,o,r)})}),l.querySelectorAll(".try-route").forEach(a=>{a.addEventListener("click",c=>{c.stopPropagation();const d=a.dataset.method??"GET",k=a.dataset.path??"/";Ye(d,k)})}),l.querySelectorAll(".run-agent").forEach(a=>{a.addEventListener("click",c=>{c.stopPropagation();const d=a.dataset.name??"";Xe(d)})}),l.querySelectorAll(".preview-prompt").forEach(a=>{a.addEventListener("click",c=>{c.stopPropagation();const d=a.dataset.key??"";et(d)})})}function Ye(e,n){const t=document.getElementById("route-test-modal"),s=document.getElementById("test-url"),o=document.getElementById("test-method"),r=document.getElementById("test-body-group"),l=document.getElementById("test-result");s.value=`${ve}${n}`,o.value=e,r.classList.toggle("hidden",e==="GET"),l.classList.add("hidden"),t.classList.remove("hidden")}async function Xe(e){const n=prompt("Enter input for agent (or leave empty for empty string):")??"";try{const t=await fetch(`${C}/agents/${encodeURIComponent(e)}/run`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({input:n})}),s=await t.json();if(!t.ok){F({error:s.error??"Agent run failed",status:t.status});return}F({agentName:e,result:s.result})}catch(t){F({error:String(t),agentName:e})}}function Qe(e){const n=document.getElementById("prompt-playground-modal"),t=document.getElementById("playground-key"),s=document.getElementById("playground-vars"),o=document.getElementById("playground-output"),r=document.getElementById("playground-tokens");t.value=e,s.value="{}",o.textContent="",r.textContent="—",n.classList.remove("hidden")}async function Ze(e,n){const t=await fetch(`${C}/prompts/render`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({key:e,variables:n})});if(!t.ok){const s=await t.json().catch(()=>({error:t.statusText}));throw new Error(s.error??"Failed to render")}return t.json()}function et(e){Qe(e)}let U=null;function F(e){U=e;const n=document.getElementById("detail-panel"),t=document.getElementById("detail-title"),s=document.getElementById("detail-content");t.textContent=String(e.kind??"Entry"),s.innerHTML=Oe(e),n.classList.remove("hidden")}function tt(){U=null,document.getElementById("detail-panel").classList.add("hidden")}function nt(){if(!U)return;const e=JSON.stringify(U,null,2);navigator.clipboard.writeText(e).then(()=>{const n=document.getElementById("detail-copy");if(n){const t=n.textContent;n.textContent="Copied!",setTimeout(()=>{n.textContent=t},1500)}})}function st(e,n){const t=Array.isArray(e)?e:[];if(!n.trim())return t;const s=n.toLowerCase();return t.filter(o=>JSON.stringify(o).toLowerCase().includes(s))}const Ee={httpMethod:e=>Te(String(e??""))},$e={enabled:e=>`<span class="badge ${e?"badge-get":"badge-default"}">${e?"Enabled":"Disabled"}</span>`,nextRuns:(e,n)=>{const t=Array.isArray(e)?e:[];if(!t.length)return"—";const s=o=>{try{return new Date(o).toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}catch{return o}};return t.slice(0,3).map(s).join(", ")+(t.length>3?"...":"")}},Se={moduleName:e=>String(e??"—"),scope:e=>{const n=String(e??"singleton");return`<span class="badge ${n==="singleton"?"badge-get":n==="request"?"badge-post":"badge-default"}">${n}</span>`}},Ie={tools:e=>Array.isArray(e)?e.join(", "):String(e??"—")},Le={streaming:e=>`<span class="badge ${e?"badge-get":"badge-default"}">${e?"Yes":"No"}</span>`};function M(e,n){try{n()}catch(t){console.error(`[Inspector] ${e} failed:`,t)}}async function O(e=!1){var n;if(!J){J=!0,V(!0),X(!1);try{const t=await Ae(e),s=Array.isArray(t==null?void 0:t.entries)?t.entries:[],o=t!=null&&t.summary&&typeof t.summary=="object"?t.summary:{},r=t!=null&&t.overview&&typeof t.overview=="object"?t.overview:{};b={entries:s,summary:o,overview:r},M("overview",()=>fe(o)),r.gateway&&M("gatewayOverview",()=>He(r.gateway)),r.discovery&&M("discoveryOverview",()=>Fe(r.discovery)),r.resilience&&M("resilienceOverview",()=>De(r.resilience)),["overview-gateway","overview-discovery","overview-resilience"].forEach(g=>{const R=document.getElementById(g);R&&!r[g.replace("overview-","")]&&R.classList.add("hidden")});const[l,h,p]=await Promise.all([Ce(),Promise.all([z("/health"),z("/ready"),z("/startup")]).then(([g,R,Be])=>({health:g,ready:R,startup:Be})),je()]);Pe(l),Ue(h),_e(p),K(h,p),Y(o);const w=b.entries.filter(g=>g.kind==="route"),f=b.entries.filter(g=>g.kind==="module"),i=b.entries.filter(g=>g.kind==="provider"),m=b.entries.filter(g=>g.kind==="cron"),a=b.entries.filter(g=>g.kind==="queue"),c=b.entries.filter(g=>g.kind==="websocket"),d=b.entries.filter(g=>g.kind==="agent"),k=b.entries.filter(g=>g.kind==="rag"),x=b.entries.filter(g=>g.kind==="prompt"),$=b.entries.filter(g=>g.kind==="aifunction"),S=b.entries.filter(g=>g.kind==="event"),A=b.entries.filter(g=>g.kind==="graphql"),I=b.entries.filter(g=>g.kind==="grpc"),L=b.entries.filter(g=>g.kind==="kafka"),N=b.entries.filter(g=>g.kind==="flow"),u=b.entries.filter(g=>g.kind==="data"),T=b.entries.filter(g=>g.kind==="serverless"),_=b.entries.filter(g=>g.kind==="ml");v("routes-table",w,["httpMethod","fullPath","controllerPath","className"],"route",Ee,{sortable:!0,tryRoute:!0}),M("moduleGraph",()=>xe(f)),v(E.modules,f,["moduleName","dynamicModule","imports"],"module",void 0,{sortable:!0}),v(E.providers,i,["providerName","moduleName","scope"],"provider",Se,{sortable:!0}),v(E.jobs,m,["jobName","cronExpression","enabled","nextRuns"],"cron",$e),v(E.queues,a,["queueName","consumerName","className"],"queue"),v(E.websocket,c,["gatewayName","eventName","namespace"],"websocket"),v(E.agents,d,["agentName","className","model","tools"],"agent",Ie,{sortable:!0,runAgent:!0}),v(E.ai,$,["className","methodName","provider","model","streaming"],"aifunction",Le),M("ragExplorer",()=>be(k)),v(E.rag,k,["pipelineName","vectorStore","embeddingProvider","chunkingStrategy"],"rag",void 0,{sortable:!0}),v(E.prompts,x,["promptKey","scope"],"prompt",void 0,{sortable:!0,previewPrompt:!0}),v(E.events,S,["eventName","className","methodName"],"event"),v(E.graphql,A,["operationType","operationName","resolverName","className"],"graphql"),v(E.grpc,I,["serviceName","methodName","className"],"grpc"),v(E.kafka,L,["consumerName","topic","groupId","methodName"],"kafka");const q=document.getElementById("flow-runtime-info");q&&q.classList.toggle("hidden",N.length===0),M("flowDiagram",()=>ke(N)),v(E.flows,N,["flowId","version","sourceType","nodeName","entryNode","edges","className"],"flow"),v(E.data,u,["pipelineName","className"],"data"),v(E.serverless,T,["controllerName","runtime","memory","timeout"],"serverless"),v(E.ml,_,["modelName","version","className"],"ml")}catch(t){const s=String(t),o=s.includes("Failed to fetch")||s.includes("NetworkError")||s.includes("Load failed");X(o),K({health:{ok:!1},ready:{ok:!1},startup:{ok:!1}},{}),Y({});const r=document.getElementById("summary-cards");if(r){const l=o?"Is the app running?":"A rendering error occurred. Check the console for details.";r.innerHTML=`<div class="overview-error"><p>Error: ${y(String(t))}</p><p>${y(l)} <button class="btn btn-sm btn-primary" id="retry-load">Retry</button></p></div>`,(n=document.getElementById("retry-load"))==null||n.addEventListener("click",()=>O(!0))}}finally{J=!1,V(!1)}}}const E={routes:"routes-table",modules:"modules-table",providers:"providers-table",jobs:"jobs-table",queues:"queues-table",websocket:"websocket-table",agents:"agents-table",ai:"ai-table",rag:"rag-table",prompts:"prompts-table",events:"events-table",graphql:"graphql-table",grpc:"grpc-table",kafka:"kafka-table",flows:"flows-table",data:"data-table",serverless:"serverless-table",ml:"ml-table"},rt={route:"routes",module:"modules",provider:"providers",cron:"jobs",queue:"queues",websocket:"websocket",agent:"agents",aifunction:"ai",rag:"rag",prompt:"prompts",event:"events",graphql:"graphql",grpc:"grpc",kafka:"kafka",flow:"flows",data:"data",serverless:"serverless",ml:"ml"};function W(e){var t;const n=document.querySelector(`.sidebar nav a[data-tab="${e}"]`);if(n){document.querySelectorAll(".sidebar nav a").forEach(o=>o.classList.remove("active")),document.querySelectorAll(".tab-panel").forEach(o=>o.classList.remove("active")),n.classList.add("active"),(t=document.getElementById(e))==null||t.classList.add("active");const s=new URLSearchParams(window.location.search);s.set("tab",e),window.history.replaceState({},"",`${window.location.pathname}?${s}`)}}document.querySelectorAll(".sidebar nav a").forEach(e=>{e.addEventListener("click",n=>{n.preventDefault();const t=e.dataset.tab;W(t)})});var Z;(Z=document.getElementById("summary-cards"))==null||Z.addEventListener("click",e=>{const n=e.target.closest(".card[data-kind]");if(n){const t=n.dataset.kind,s=t?rt[t]:null;s&&W(s)}});function Ne(){O(!0)}var ee;(ee=document.getElementById("refresh"))==null||ee.addEventListener("click",Ne);var te;(te=document.getElementById("refresh-sidebar"))==null||te.addEventListener("click",Ne);document.getElementById("detail-close").addEventListener("click",tt);var ne;(ne=document.getElementById("detail-copy"))==null||ne.addEventListener("click",nt);var se;(se=document.getElementById("export-btn"))==null||se.addEventListener("click",()=>{if(!b)return;const e=new Blob([JSON.stringify(b,null,2)],{type:"application/json"}),n=document.createElement("a");n.href=URL.createObjectURL(e),n.download=`inspector-snapshot-${new Date().toISOString().slice(0,19).replace(/[T:]/g,"-")}.json`,n.click(),URL.revokeObjectURL(n.href)});const j=document.getElementById("auto-refresh");let H=null;j==null||j.addEventListener("change",()=>{H&&clearInterval(H),H=null,j!=null&&j.checked&&(H=setInterval(()=>O(!1),15e3))});var re;(re=document.getElementById("test-route-btn"))==null||re.addEventListener("click",async()=>{const e=document.getElementById("test-url").value,n=document.getElementById("test-method").value,t=document.getElementById("test-body"),s=document.getElementById("test-result");s.classList.remove("hidden"),s.className="test-result",s.textContent="Sending...";try{const o={method:n};if(n!=="GET"&&(t!=null&&t.value))try{JSON.parse(t.value),o.body=t.value,o.headers={"Content-Type":"application/json"}}catch{s.className="test-result error",s.textContent="Invalid JSON body";return}const r=await fetch(e,o),l=await r.text();s.className=`test-result ${r.ok?"success":"error"}`,s.textContent=`Status: ${r.status}
79
+
80
+ ${l.slice(0,500)}${l.length>500?"...":""}`}catch(o){s.className="test-result error",s.textContent=String(o)}});var oe;(oe=document.getElementById("test-route-cancel"))==null||oe.addEventListener("click",()=>{document.getElementById("route-test-modal").classList.add("hidden")});var ae;(ae=document.getElementById("test-method"))==null||ae.addEventListener("change",e=>{const n=e.target.value;document.getElementById("test-body-group").classList.toggle("hidden",n==="GET")});var ie;(ie=document.getElementById("playground-render"))==null||ie.addEventListener("click",async()=>{const e=document.getElementById("playground-key").value,n=document.getElementById("playground-vars").value,t=document.getElementById("playground-output"),s=document.getElementById("playground-tokens");let o={};try{o=n.trim()?JSON.parse(n):{}}catch{t.textContent="Invalid JSON in variables",s.textContent="—";return}try{const{rendered:r,tokenEstimate:l}=await Ze(e,o);t.textContent=r,s.textContent=String(l)}catch(r){t.textContent=String(r),s.textContent="—"}});var le;(le=document.getElementById("playground-close"))==null||le.addEventListener("click",()=>{document.getElementById("prompt-playground-modal").classList.add("hidden")});var ce;(ce=document.getElementById("diff-btn"))==null||ce.addEventListener("click",()=>{document.getElementById("diff-modal").classList.remove("hidden")});var de;(de=document.getElementById("diff-close"))==null||de.addEventListener("click",()=>{document.getElementById("diff-modal").classList.add("hidden")});var ue;(ue=document.getElementById("diff-load-file"))==null||ue.addEventListener("click",()=>{document.getElementById("diff-file").click()});var me;(me=document.getElementById("diff-file"))==null||me.addEventListener("change",e=>{var s;const n=(s=e.target.files)==null?void 0:s[0];if(!n)return;const t=new FileReader;t.onload=()=>{document.getElementById("diff-snapshot-b").value=String(t.result)},t.readAsText(n)});var ge;(ge=document.getElementById("rag-search-btn"))==null||ge.addEventListener("click",Ke);var pe;(pe=document.getElementById("diff-compare-btn"))==null||pe.addEventListener("click",()=>{const e=document.getElementById("diff-snapshot-b").value.trim(),n=document.getElementById("diff-result");if(!b){n.innerHTML='<p class="error">No current snapshot. Refresh first.</p>',n.classList.remove("hidden");return}let t;try{t=e?JSON.parse(e):{entries:[],summary:{}}}catch{n.innerHTML='<p class="error">Invalid JSON in Snapshot B.</p>',n.classList.remove("hidden");return}const s=b.entries??[],o=t.entries??[],r=new Set(s.map(i=>i.id)),l=new Set(o.map(i=>i.id)),h=o.filter(i=>!r.has(i.id)),p=s.filter(i=>!l.has(i.id)),w=s.filter(i=>{const m=o.find(a=>a.id===i.id);return m&&JSON.stringify(i)!==JSON.stringify(m)});let f="";h.length&&(f+=`<p class="added">+ ${h.length} added</p><ul>${h.map(i=>`<li>${y(String(i.kind))}: ${y(String(i.id??""))}</li>`).join("")}</ul>`),p.length&&(f+=`<p class="removed">− ${p.length} removed</p><ul>${p.map(i=>`<li>${y(String(i.kind))}: ${y(String(i.id??""))}</li>`).join("")}</ul>`),w.length&&(f+=`<p class="changed">~ ${w.length} changed</p><ul>${w.map(i=>`<li>${y(String(i.kind))}: ${y(String(i.id??""))}</li>`).join("")}</ul>`),f||(f="<p>No differences.</p>"),n.innerHTML=f,n.classList.remove("hidden")});document.getElementById("search").addEventListener("input",e=>{const n=e.target.value;if(!b)return;const t=st(b.entries,n),s=b.summary&&typeof b.summary=="object"?b.summary:{},o=Object.fromEntries(Object.entries(s).map(([u])=>[u,t.filter(T=>T.kind===u).length]));fe(o);const r=t.filter(u=>u.kind==="route"),l=t.filter(u=>u.kind==="module"),h=t.filter(u=>u.kind==="provider"),p=t.filter(u=>u.kind==="cron"),w=t.filter(u=>u.kind==="queue"),f=t.filter(u=>u.kind==="websocket"),i=t.filter(u=>u.kind==="agent"),m=t.filter(u=>u.kind==="rag"),a=t.filter(u=>u.kind==="prompt"),c=t.filter(u=>u.kind==="aifunction"),d=t.filter(u=>u.kind==="event"),k=t.filter(u=>u.kind==="graphql"),x=t.filter(u=>u.kind==="grpc"),$=t.filter(u=>u.kind==="kafka"),S=t.filter(u=>u.kind==="flow"),A=t.filter(u=>u.kind==="data"),I=t.filter(u=>u.kind==="serverless"),L=t.filter(u=>u.kind==="ml");v("routes-table",r,["httpMethod","fullPath","controllerPath","className"],"route",Ee,{sortable:!0,tryRoute:!0}),xe(l),v("modules-table",l,["moduleName","dynamicModule","imports"],"module",void 0,{sortable:!0}),v("providers-table",h,["providerName","moduleName","scope"],"provider",Se,{sortable:!0}),v("jobs-table",p,["jobName","cronExpression","enabled","nextRuns"],"cron",$e),v("queues-table",w,["queueName","consumerName","className"],"queue"),v("websocket-table",f,["gatewayName","eventName","namespace"],"websocket"),v("agents-table",i,["agentName","className","model","tools"],"agent",Ie,{sortable:!0,runAgent:!0}),v("ai-table",c,["className","methodName","provider","model","streaming"],"aifunction",Le),be(m),v("rag-table",m,["pipelineName","vectorStore","embeddingProvider","chunkingStrategy"],"rag",void 0,{sortable:!0}),v("prompts-table",a,["promptKey","scope"],"prompt",void 0,{sortable:!0,previewPrompt:!0}),v("events-table",d,["eventName","className","methodName"],"event"),v("graphql-table",k,["operationType","operationName","resolverName","className"],"graphql"),v("grpc-table",x,["serviceName","methodName","className"],"grpc"),v("kafka-table",$,["consumerName","topic","groupId","methodName"],"kafka");const N=document.getElementById("flow-runtime-info");N&&N.classList.toggle("hidden",S.length===0),ke(S),v("flows-table",S,["flowId","version","sourceType","nodeName","entryNode","edges","className"],"flow",void 0,{sortable:!0}),v("data-table",A,["pipelineName","className"],"data"),v("serverless-table",I,["controllerName","runtime","memory","timeout"],"serverless"),v("ml-table",L,["modelName","version","className"],"ml")});O().then(()=>{const n=new URLSearchParams(window.location.search).get("tab");n&&W(n)});
@@ -0,0 +1,316 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>HazelJS Inspector</title>
7
+ <script type="module" crossorigin src="/__hazel/assets/index-DLS5TpZI.js"></script>
8
+ <link rel="stylesheet" crossorigin href="/__hazel/assets/index-BN8Zr7QX.css">
9
+ </head>
10
+ <body>
11
+ <div id="app">
12
+ <aside class="sidebar">
13
+ <div class="logo">
14
+ <svg class="logo-svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 96" width="24" height="24" aria-hidden="true">
15
+ <defs>
16
+ <radialGradient id="hazeljs-inspector-bg" cx="50%" cy="50%" r="60%" fx="50%" fy="50%">
17
+ <stop offset="0%" stop-color="#3b82f6" />
18
+ <stop offset="100%" stop-color="#2563eb" />
19
+ </radialGradient>
20
+ </defs>
21
+ <rect width="96" height="96" rx="20" fill="url(#hazeljs-inspector-bg)"/>
22
+ <!-- H left bar -->
23
+ <rect x="22" y="22" width="12" height="52" rx="6" fill="white"/>
24
+ <!-- H right bar -->
25
+ <rect x="62" y="22" width="12" height="52" rx="6" fill="white"/>
26
+ <!-- H crossbar with lightning bolt -->
27
+ <g>
28
+ <rect x="34" y="42" width="28" height="12" rx="6" fill="white"/>
29
+ <polygon points="48,44 54,44 50,52 56,52 44,68 48,56 42,56" fill="#facc15" stroke="#fbbf24" stroke-width="2"/>
30
+ </g>
31
+ <!-- JS badge -->
32
+ <g>
33
+ <rect x="66" y="66" width="18" height="18" rx="5" fill="#facc15" stroke="#fff" stroke-width="2"/>
34
+ <text x="75" y="80" font-family="Inter, system-ui, sans-serif" font-size="10" font-weight="bold" fill="#2563eb" text-anchor="middle" alignment-baseline="middle">JS</text>
35
+ </g>
36
+ </svg>
37
+ <span class="logo-text">HazelJS Inspector</span>
38
+ </div>
39
+ <nav>
40
+ <a href="#" data-tab="overview" class="active">
41
+ <span class="nav-icon"></span>
42
+ Overview
43
+ </a>
44
+ <div class="nav-section">
45
+ <span class="nav-section-title">Framework</span>
46
+ <a href="#" data-tab="routes"><span class="nav-icon"></span>Routes</a>
47
+ <a href="#" data-tab="modules"><span class="nav-icon"></span>Modules</a>
48
+ <a href="#" data-tab="providers"><span class="nav-icon"></span>Providers</a>
49
+ </div>
50
+ <div class="nav-section">
51
+ <span class="nav-section-title">Scheduled & Async</span>
52
+ <a href="#" data-tab="jobs"><span class="nav-icon"></span>Jobs</a>
53
+ <a href="#" data-tab="queues"><span class="nav-icon"></span>Queues</a>
54
+ </div>
55
+ <div class="nav-section">
56
+ <span class="nav-section-title">AI & Intelligence</span>
57
+ <a href="#" data-tab="agents"><span class="nav-icon"></span>Agents</a>
58
+ <a href="#" data-tab="ai"><span class="nav-icon"></span>AI</a>
59
+ <a href="#" data-tab="rag"><span class="nav-icon"></span>RAG</a>
60
+ <a href="#" data-tab="prompts"><span class="nav-icon"></span>Prompts</a>
61
+ <a href="#" data-tab="ml"><span class="nav-icon"></span>ML</a>
62
+ </div>
63
+ <div class="nav-section">
64
+ <span class="nav-section-title">APIs & Messaging</span>
65
+ <a href="#" data-tab="graphql"><span class="nav-icon"></span>GraphQL</a>
66
+ <a href="#" data-tab="grpc"><span class="nav-icon"></span>gRPC</a>
67
+ <a href="#" data-tab="kafka"><span class="nav-icon"></span>Kafka</a>
68
+ <a href="#" data-tab="websocket"><span class="nav-icon"></span>WebSocket</a>
69
+ <a href="#" data-tab="events"><span class="nav-icon"></span>Events</a>
70
+ </div>
71
+ <div class="nav-section">
72
+ <span class="nav-section-title">Workflows & Data</span>
73
+ <a href="#" data-tab="flows"><span class="nav-icon"></span>Flows</a>
74
+ <a href="#" data-tab="data"><span class="nav-icon"></span>Data</a>
75
+ <a href="#" data-tab="serverless"><span class="nav-icon"></span>Serverless</a>
76
+ </div>
77
+ </nav>
78
+ <div class="sidebar-footer">
79
+ <button id="refresh-sidebar" class="btn btn-primary">Refresh</button>
80
+ </div>
81
+ </aside>
82
+ <main class="content">
83
+ <header class="toolbar">
84
+ <div class="search-wrapper">
85
+ <input type="search" id="search" placeholder="Search routes, modules, providers..." class="search" />
86
+ </div>
87
+ <div class="toolbar-actions">
88
+ <label class="toolbar-toggle">
89
+ <input type="checkbox" id="auto-refresh" />
90
+ <span>Auto-refresh</span>
91
+ </label>
92
+ <button id="diff-btn" class="btn btn-sm" title="Compare snapshots">Diff</button>
93
+ <button id="export-btn" class="btn btn-sm" title="Export snapshot as JSON">Export</button>
94
+ <button id="refresh" class="btn btn-sm btn-primary">Refresh</button>
95
+ </div>
96
+ </header>
97
+ <div id="loading-overlay" class="loading-overlay hidden">
98
+ <div class="loading-spinner"></div>
99
+ <span>Loading...</span>
100
+ </div>
101
+ <div id="overview" class="tab-panel active">
102
+ <div id="overview-status-bar" class="overview-status-bar">
103
+ <div class="status-bar-left">
104
+ <span id="status-dot" class="status-dot" title="App status"></span>
105
+ <span id="status-text" class="status-text">Connecting...</span>
106
+ <span id="status-uptime" class="status-uptime muted"></span>
107
+ </div>
108
+ <div id="quick-stats" class="quick-stats"></div>
109
+ </div>
110
+ <h2 class="section-title">Overview</h2>
111
+ <div class="overview-grid">
112
+ <div class="overview-block overview-env">
113
+ <h3 class="overview-block-title">Environment</h3>
114
+ <div id="env-info" class="env-info env-info-compact"></div>
115
+ </div>
116
+ <div class="overview-block overview-health">
117
+ <h3 class="overview-block-title">Health</h3>
118
+ <div id="health-cards" class="health-cards-inline"></div>
119
+ </div>
120
+ <div class="overview-block overview-runtime">
121
+ <h3 class="overview-block-title">Runtime</h3>
122
+ <div id="memory-chart-container" class="chart-container chart-inline hidden"></div>
123
+ <div id="runtime-cards" class="runtime-cards-inline"></div>
124
+ </div>
125
+ <div id="overview-gateway" class="overview-block overview-gateway hidden"></div>
126
+ <div id="overview-discovery" class="overview-block overview-discovery hidden"></div>
127
+ <div id="overview-resilience" class="overview-block overview-resilience hidden"></div>
128
+ </div>
129
+ <div id="summary-cards" class="overview-container"></div>
130
+ </div>
131
+ <div id="routes" class="tab-panel">
132
+ <h2 class="section-title">Routes</h2>
133
+ <div class="table-container"><table id="routes-table"></table></div>
134
+ </div>
135
+ <div id="modules" class="tab-panel">
136
+ <h2 class="section-title">Modules</h2>
137
+ <div id="module-graph-container" class="module-graph-container hidden"></div>
138
+ <div class="table-container"><table id="modules-table"></table></div>
139
+ </div>
140
+ <div id="providers" class="tab-panel">
141
+ <h2 class="section-title">Providers</h2>
142
+ <div class="table-container"><table id="providers-table"></table></div>
143
+ </div>
144
+ <div id="jobs" class="tab-panel">
145
+ <h2 class="section-title">Cron Jobs</h2>
146
+ <div class="table-container"><table id="jobs-table"></table></div>
147
+ </div>
148
+ <div id="queues" class="tab-panel">
149
+ <h2 class="section-title">Queues</h2>
150
+ <div class="table-container"><table id="queues-table"></table></div>
151
+ </div>
152
+ <div id="websocket" class="tab-panel">
153
+ <h2 class="section-title">WebSocket Gateways</h2>
154
+ <div class="table-container"><table id="websocket-table"></table></div>
155
+ </div>
156
+ <div id="agents" class="tab-panel">
157
+ <h2 class="section-title">Agents</h2>
158
+ <div class="table-container"><table id="agents-table"></table></div>
159
+ </div>
160
+ <div id="ai" class="tab-panel">
161
+ <h2 class="section-title">AI Functions</h2>
162
+ <div class="table-container"><table id="ai-table"></table></div>
163
+ </div>
164
+ <div id="rag" class="tab-panel">
165
+ <h2 class="section-title">RAG Pipelines</h2>
166
+ <div id="rag-explorer" class="rag-explorer hidden">
167
+ <div class="form-group">
168
+ <label>Pipeline</label>
169
+ <select id="rag-pipeline-select"></select>
170
+ </div>
171
+ <div class="form-group">
172
+ <label>Semantic Search</label>
173
+ <div class="rag-search-row">
174
+ <input type="text" id="rag-search-input" placeholder="Search by text..." />
175
+ <button id="rag-search-btn" class="btn btn-sm btn-primary">Search</button>
176
+ </div>
177
+ </div>
178
+ <div id="rag-results" class="rag-results"></div>
179
+ </div>
180
+ <div class="table-container"><table id="rag-table"></table></div>
181
+ </div>
182
+ <div id="prompts" class="tab-panel">
183
+ <h2 class="section-title">Prompts</h2>
184
+ <div class="table-container"><table id="prompts-table"></table></div>
185
+ </div>
186
+ <div id="events" class="tab-panel">
187
+ <h2 class="section-title">Event Listeners</h2>
188
+ <div class="table-container"><table id="events-table"></table></div>
189
+ </div>
190
+ <div id="graphql" class="tab-panel">
191
+ <h2 class="section-title">GraphQL</h2>
192
+ <div class="table-container"><table id="graphql-table"></table></div>
193
+ </div>
194
+ <div id="grpc" class="tab-panel">
195
+ <h2 class="section-title">gRPC Methods</h2>
196
+ <div class="table-container"><table id="grpc-table"></table></div>
197
+ </div>
198
+ <div id="kafka" class="tab-panel">
199
+ <h2 class="section-title">Kafka Consumers</h2>
200
+ <div class="table-container"><table id="kafka-table"></table></div>
201
+ </div>
202
+ <div id="flows" class="tab-panel tab-panel-compact">
203
+ <h2 class="section-title">Flows</h2>
204
+ <div id="flow-diagram" class="flow-diagram hidden"></div>
205
+ <div id="flow-runtime-info" class="flow-runtime-hint hidden">
206
+ <span class="flow-runtime-label">Flow Runtime:</span>
207
+ <code>npx @hazeljs/flow-runtime</code>
208
+ <span class="flow-runtime-sep">·</span>
209
+ <code>POST /v1/runs/start</code>
210
+ <code>POST /v1/runs/:id/tick</code>
211
+ <code>GET /v1/flows</code>
212
+ </div>
213
+ <div class="table-container"><table id="flows-table"></table></div>
214
+ </div>
215
+ <div id="data" class="tab-panel">
216
+ <h2 class="section-title">Data Pipelines</h2>
217
+ <div class="table-container"><table id="data-table"></table></div>
218
+ </div>
219
+ <div id="serverless" class="tab-panel">
220
+ <h2 class="section-title">Serverless</h2>
221
+ <div class="table-container"><table id="serverless-table"></table></div>
222
+ </div>
223
+ <div id="ml" class="tab-panel">
224
+ <h2 class="section-title">ML Models</h2>
225
+ <div class="table-container"><table id="ml-table"></table></div>
226
+ </div>
227
+ <div id="detail-panel" class="detail-panel hidden">
228
+ <div class="detail-header">
229
+ <h2 id="detail-title"></h2>
230
+ <div class="detail-actions">
231
+ <button id="detail-copy" class="btn btn-sm" title="Copy to clipboard">Copy</button>
232
+ <button id="detail-close" class="btn btn-sm">Close</button>
233
+ </div>
234
+ </div>
235
+ <pre id="detail-content"></pre>
236
+ </div>
237
+ <div id="prompt-playground-modal" class="modal hidden">
238
+ <div class="modal-content modal-wide">
239
+ <h3>Prompt Playground</h3>
240
+ <div class="modal-body">
241
+ <div class="form-group">
242
+ <label>Prompt Key</label>
243
+ <input type="text" id="playground-key" readonly />
244
+ </div>
245
+ <div class="form-group">
246
+ <label>Variables (JSON)</label>
247
+ <textarea id="playground-vars" rows="4">{}</textarea>
248
+ </div>
249
+ <div class="playground-actions">
250
+ <button id="playground-render" class="btn btn-primary">Render</button>
251
+ </div>
252
+ <div class="form-group">
253
+ <label>Rendered Output</label>
254
+ <pre id="playground-output" class="playground-output"></pre>
255
+ </div>
256
+ <div class="playground-meta">
257
+ <span id="playground-tokens">—</span> tokens (estimate)
258
+ </div>
259
+ </div>
260
+ <div class="modal-footer">
261
+ <button id="playground-close" class="btn">Close</button>
262
+ </div>
263
+ </div>
264
+ </div>
265
+ <div id="route-test-modal" class="modal hidden">
266
+ <div class="modal-content">
267
+ <h3>Try Route</h3>
268
+ <div class="modal-body">
269
+ <div class="form-group">
270
+ <label>Method</label>
271
+ <select id="test-method"><option value="GET">GET</option><option value="POST">POST</option><option value="PUT">PUT</option><option value="PATCH">PATCH</option><option value="DELETE">DELETE</option></select>
272
+ </div>
273
+ <div class="form-group">
274
+ <label>URL</label>
275
+ <input type="text" id="test-url" readonly />
276
+ </div>
277
+ <div class="form-group hidden" id="test-body-group">
278
+ <label>Body (JSON)</label>
279
+ <textarea id="test-body" rows="4">{}</textarea>
280
+ </div>
281
+ </div>
282
+ <div class="modal-footer">
283
+ <button id="test-route-btn" class="btn btn-primary">Send</button>
284
+ <button id="test-route-cancel" class="btn">Cancel</button>
285
+ </div>
286
+ <div id="test-result" class="test-result hidden"></div>
287
+ </div>
288
+ </div>
289
+ <div id="diff-modal" class="modal hidden">
290
+ <div class="modal-content modal-wide">
291
+ <h3>Snapshot Diff</h3>
292
+ <div class="modal-body">
293
+ <div class="diff-sources">
294
+ <div class="form-group">
295
+ <label>Snapshot A (current)</label>
296
+ <p class="diff-hint">Use current snapshot</p>
297
+ </div>
298
+ <div class="form-group">
299
+ <label>Snapshot B (paste JSON or load file)</label>
300
+ <textarea id="diff-snapshot-b" rows="6" placeholder="Paste snapshot JSON or leave empty to load file..."></textarea>
301
+ <input type="file" id="diff-file" accept=".json" class="hidden" />
302
+ <button id="diff-load-file" class="btn btn-sm">Load file</button>
303
+ </div>
304
+ </div>
305
+ <button id="diff-compare-btn" class="btn btn-primary">Compare</button>
306
+ <div id="diff-result" class="diff-result hidden"></div>
307
+ </div>
308
+ <div class="modal-footer">
309
+ <button id="diff-close" class="btn">Close</button>
310
+ </div>
311
+ </div>
312
+ </div>
313
+ </main>
314
+ </div>
315
+ </body>
316
+ </html>