@hazeljs/inspector 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -8,6 +8,7 @@ Framework-aware runtime inspector for HazelJS. Explore metadata, routes, modules
|
|
|
8
8
|
- **Package-specific plugins** – Optional support for @hazeljs/cron, @hazeljs/queue, @hazeljs/websocket
|
|
9
9
|
- **DevTools UI** – Overview dashboard, search, filters, detail views, runtime stats
|
|
10
10
|
- **JSON API** – Consume inspector data programmatically
|
|
11
|
+
- **Agent OS timelines** – SSE live stream + JSON replay for agent execution steps
|
|
11
12
|
|
|
12
13
|
## Installation
|
|
13
14
|
|
|
@@ -48,6 +49,26 @@ Then run your app and open:
|
|
|
48
49
|
- **`http://localhost:3000/__hazel/websocket`** – WebSocket gateways (if @hazeljs/websocket is installed)
|
|
49
50
|
- **`http://localhost:3000/__hazel/stats`** – Runtime stats (memory, uptime)
|
|
50
51
|
|
|
52
|
+
### Agent OS timeline (with `@hazeljs/agent`)
|
|
53
|
+
|
|
54
|
+
When agents are registered, Inspector exposes live debugging endpoints:
|
|
55
|
+
|
|
56
|
+
| Endpoint | Description |
|
|
57
|
+
| ------------------------------------ | ------------------------------------------------- |
|
|
58
|
+
| `GET /__hazel/agents/:name/stream` | SSE stream of timeline steps while the agent runs |
|
|
59
|
+
| `GET /__hazel/agents/:name/timeline` | JSON replay of recorded timeline steps |
|
|
60
|
+
| `POST /__hazel/agents/:name/run` | Run the agent from the UI (optional input prompt) |
|
|
61
|
+
|
|
62
|
+
In the Agents panel, use **Run** (executes + streams) or **Timeline** (loads history and opens the live SSE feed).
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# Replay last timeline
|
|
66
|
+
curl http://localhost:3000/__hazel/agents/support-agent/timeline
|
|
67
|
+
|
|
68
|
+
# Live SSE (EventSource-compatible)
|
|
69
|
+
curl -N http://localhost:3000/__hazel/agents/support-agent/stream
|
|
70
|
+
```
|
|
71
|
+
|
|
51
72
|
## Configuration
|
|
52
73
|
|
|
53
74
|
| Option | Default | Description |
|
package/dist/inspector.module.js
CHANGED
|
@@ -321,6 +321,74 @@ function createInspectorHandler(service, config, app) {
|
|
|
321
321
|
}
|
|
322
322
|
return;
|
|
323
323
|
}
|
|
324
|
+
// Agent OS Visual Timeline — SSE live stream
|
|
325
|
+
const agentStreamMatch = pathSeg.match(/^\/agents\/([^/]+)\/stream\/?$/);
|
|
326
|
+
if (agentStreamMatch && req.method === 'GET') {
|
|
327
|
+
const agentName = decodeURIComponent(agentStreamMatch[1]);
|
|
328
|
+
try {
|
|
329
|
+
const { AgentService } = require('@hazeljs/agent');
|
|
330
|
+
const container = app.getContainer();
|
|
331
|
+
const svc = container.resolve(AgentService);
|
|
332
|
+
if (!svc?.getRuntime && !svc?.getTimeline) {
|
|
333
|
+
res.writeHead(503);
|
|
334
|
+
res.end(JSON.stringify({ error: 'AgentService not found' }));
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
res.writeHead(200, {
|
|
338
|
+
'Content-Type': 'text/event-stream',
|
|
339
|
+
'Cache-Control': 'no-cache',
|
|
340
|
+
Connection: 'keep-alive',
|
|
341
|
+
});
|
|
342
|
+
const recorder = svc.getRuntime?.()?.getTimelineRecorder?.();
|
|
343
|
+
const existing = recorder?.getTimeline({ agentName }) ?? svc.getTimeline?.({ agentName }) ?? [];
|
|
344
|
+
for (const step of existing) {
|
|
345
|
+
res.write(`data: ${JSON.stringify(step)}\n\n`);
|
|
346
|
+
}
|
|
347
|
+
const unsub = recorder?.subscribe((step) => {
|
|
348
|
+
const s = step;
|
|
349
|
+
if (!s.agentId || s.agentId === agentName) {
|
|
350
|
+
res.write(`data: ${JSON.stringify(step)}\n\n`);
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
const heartbeat = setInterval(() => {
|
|
354
|
+
res.write(`: heartbeat\n\n`);
|
|
355
|
+
}, 15000);
|
|
356
|
+
req.on('close', () => {
|
|
357
|
+
clearInterval(heartbeat);
|
|
358
|
+
unsub?.();
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
catch (err) {
|
|
362
|
+
res.writeHead(500);
|
|
363
|
+
res.end(JSON.stringify({ error: String(err) }));
|
|
364
|
+
}
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
// Replay timeline for agent or execution
|
|
368
|
+
const agentTimelineMatch = pathSeg.match(/^\/agents\/([^/]+)\/timeline\/?$/);
|
|
369
|
+
if (agentTimelineMatch && req.method === 'GET') {
|
|
370
|
+
const agentName = decodeURIComponent(agentTimelineMatch[1]);
|
|
371
|
+
const url = new URL(req.url ?? '/', 'http://localhost');
|
|
372
|
+
const executionId = url.searchParams.get('executionId') ?? undefined;
|
|
373
|
+
try {
|
|
374
|
+
const { AgentService } = require('@hazeljs/agent');
|
|
375
|
+
const container = app.getContainer();
|
|
376
|
+
const svc = container.resolve(AgentService);
|
|
377
|
+
if (!svc?.getTimeline) {
|
|
378
|
+
res.writeHead(503);
|
|
379
|
+
res.end(JSON.stringify({ error: 'AgentService.getTimeline not available' }));
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
const steps = svc.getTimeline(executionId ? { executionId } : { agentName });
|
|
383
|
+
res.writeHead(200);
|
|
384
|
+
res.end(JSON.stringify({ agentName, executionId, steps }));
|
|
385
|
+
}
|
|
386
|
+
catch (err) {
|
|
387
|
+
res.writeHead(500);
|
|
388
|
+
res.end(JSON.stringify({ error: String(err) }));
|
|
389
|
+
}
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
324
392
|
if (pathSeg === '/rag' || pathSeg === '/rag/') {
|
|
325
393
|
const rag = snapshot.entries.filter((e) => e.kind === 'rag');
|
|
326
394
|
res.writeHead(200);
|
|
@@ -486,6 +554,8 @@ function createInspectorHandler(service, config, app) {
|
|
|
486
554
|
'/queues',
|
|
487
555
|
'/websocket',
|
|
488
556
|
'/agents',
|
|
557
|
+
'/agents/:name/stream',
|
|
558
|
+
'/agents/:name/timeline',
|
|
489
559
|
'/rag',
|
|
490
560
|
'/prompts',
|
|
491
561
|
'/aifunctions',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hazeljs/inspector",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"description": "Framework-aware runtime inspector for HazelJS - metadata explorer and DevTools UI",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -22,22 +22,22 @@
|
|
|
22
22
|
"reflect-metadata": "^0.2.2"
|
|
23
23
|
},
|
|
24
24
|
"peerDependencies": {
|
|
25
|
-
"@hazeljs/agent": "^1.0.
|
|
26
|
-
"@hazeljs/ai": "^1.0.
|
|
27
|
-
"@hazeljs/core": "^1.0.
|
|
28
|
-
"@hazeljs/cron": "^1.0.
|
|
29
|
-
"@hazeljs/data": "^1.0.
|
|
30
|
-
"@hazeljs/event-emitter": "^1.0.
|
|
31
|
-
"@hazeljs/flow": "^1.0.
|
|
32
|
-
"@hazeljs/graphql": "^1.0.
|
|
33
|
-
"@hazeljs/grpc": "^1.0.
|
|
34
|
-
"@hazeljs/kafka": "^1.0.
|
|
35
|
-
"@hazeljs/ml": "^1.0.
|
|
36
|
-
"@hazeljs/prompts": "^1.0.
|
|
37
|
-
"@hazeljs/queue": "^1.0.
|
|
38
|
-
"@hazeljs/rag": "^1.0.
|
|
39
|
-
"@hazeljs/serverless": "^1.0.
|
|
40
|
-
"@hazeljs/websocket": "^1.0.
|
|
25
|
+
"@hazeljs/agent": "^1.0.6",
|
|
26
|
+
"@hazeljs/ai": "^1.0.6",
|
|
27
|
+
"@hazeljs/core": "^1.0.6",
|
|
28
|
+
"@hazeljs/cron": "^1.0.6",
|
|
29
|
+
"@hazeljs/data": "^1.0.6",
|
|
30
|
+
"@hazeljs/event-emitter": "^1.0.6",
|
|
31
|
+
"@hazeljs/flow": "^1.0.6",
|
|
32
|
+
"@hazeljs/graphql": "^1.0.6",
|
|
33
|
+
"@hazeljs/grpc": "^1.0.6",
|
|
34
|
+
"@hazeljs/kafka": "^1.0.6",
|
|
35
|
+
"@hazeljs/ml": "^1.0.6",
|
|
36
|
+
"@hazeljs/prompts": "^1.0.6",
|
|
37
|
+
"@hazeljs/queue": "^1.0.6",
|
|
38
|
+
"@hazeljs/rag": "^1.0.6",
|
|
39
|
+
"@hazeljs/serverless": "^1.0.6",
|
|
40
|
+
"@hazeljs/websocket": "^1.0.6"
|
|
41
41
|
},
|
|
42
42
|
"peerDependenciesMeta": {
|
|
43
43
|
"@hazeljs/cron": {
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
}
|
|
88
88
|
},
|
|
89
89
|
"devDependencies": {
|
|
90
|
-
"@hazeljs/core": "^1.0.
|
|
90
|
+
"@hazeljs/core": "^1.0.6",
|
|
91
91
|
"@types/jest": "^29.5.14",
|
|
92
92
|
"@types/node": "^20.19.39",
|
|
93
93
|
"@typescript-eslint/eslint-plugin": "^8.58.0",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
@import "https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&family=DM+Sans:wght@400;500;600;700&display=swap";:root{--hazel-primary:#1a365d;--hazel-primary-hover:#2c5282;--hazel-accent:#1a365d;--hazel-accent-hover:#2c5282;--hazel-primary-muted:#1a365d40;--hazel-accent-muted:#1a365d40;--bg-primary:#0c0e12;--bg-secondary:#14171d;--bg-tertiary:#1a1e26;--bg-elevated:#1f242b;--bg-hover:#252a33;--border:#2d333b;--border-subtle:#21262d;--text-primary:#e6edf3;--text-secondary:#8b949e;--text-muted:#6e7681;--accent:var(--hazel-accent);--accent-hover:var(--hazel-accent-hover);--accent-muted:var(--hazel-accent-muted);--success:#3fb950;--warning:#d29922;--error:#f85149;--radius-sm:6px;--radius-md:8px;--radius-lg:12px;--radius-xl:16px;--shadow-sm:0 1px 2px #0000004d;--shadow-md:0 4px 12px #0006;--shadow-lg:0 8px 24px #00000080;--shadow-glow:0 0 24px #1a365d33;--transition:.2s cubic-bezier(.4, 0, .2, 1)}*{box-sizing:border-box}body{background:var(--bg-primary);color:var(--text-primary);-webkit-font-smoothing:antialiased;margin:0;font-family:DM Sans,-apple-system,BlinkMacSystemFont,sans-serif;font-size:14px;line-height:1.5}#app{min-height:100vh;display:flex}.sidebar{background:var(--bg-secondary);border-right:1px solid var(--border-subtle);flex-direction:column;width:240px;min-width:240px;padding:0;display:flex}.logo{letter-spacing:.02em;color:var(--text-primary);border-bottom:1px solid var(--border-subtle);align-items:center;gap:.625rem;margin:0;padding:1.25rem 1.25rem 1rem;font-size:13px;font-weight:600;display:flex}.logo-img{object-fit:contain;flex-shrink:0;width:24px;height:24px}.logo-svg{width:24px;height:24px;color:var(--accent);flex-shrink:0}.logo-fallback{align-items:center;display:flex}.logo-text{color:var(--text-primary);font-weight:700}.sidebar nav{flex-direction:column;flex:1;gap:.25rem;min-height:0;padding:.75rem 0;display:flex;overflow-y:auto}.nav-section{flex-direction:column;gap:.125rem;display:flex}.nav-section-title{color:var(--text-muted);text-transform:uppercase;letter-spacing:.08em;border-top:1px solid var(--border-subtle);margin:.25rem .5rem 0 0;padding:.5rem 1.25rem .25rem;font-size:10px;font-weight:600}.sidebar nav a{color:var(--text-secondary);border-radius:var(--radius-sm);transition:color var(--transition), background var(--transition);align-items:center;gap:.625rem;margin:0 .5rem;padding:.5rem 1.25rem;font-weight:500;text-decoration:none;display:flex}.sidebar nav a:hover{color:var(--text-primary);background:var(--bg-hover)}.sidebar nav a.active{color:#60a5fa;background:#3b82f633}.sidebar nav a .nav-icon{background:var(--text-muted);border-radius:2px;flex-shrink:0;width:3px;height:14px}.sidebar nav a:hover .nav-icon{background:var(--text-secondary)}.sidebar nav a.active .nav-icon{background:#60a5fa}.sidebar-footer{border-top:1px solid var(--border-subtle);padding:1rem 1.25rem}.btn{background:var(--bg-tertiary);width:100%;color:var(--text-primary);border:1px solid var(--border);border-radius:var(--radius-sm);cursor:pointer;transition:background var(--transition), border-color var(--transition);padding:.5rem 1rem;font-family:inherit;font-size:13px;font-weight:500}.btn:hover{background:var(--bg-hover);border-color:var(--text-muted)}.btn-primary{background:var(--accent);border-color:var(--accent);color:#fff}.btn-primary:hover{background:var(--accent-hover);border-color:var(--accent-hover);color:#fff}.content{background:var(--bg-primary);isolation:isolate;flex:1;padding:1rem 1.5rem;position:relative;overflow:auto}.content:before{content:"";pointer-events:none;z-index:0;background:radial-gradient(80% 50% at 50% -20%,#1a365d59,#0000),radial-gradient(60% 40% at 100%,#1a365d14,#0000),radial-gradient(40% 30% at 0 80%,#1a365d26,#0000);position:absolute;inset:0}.content>*{z-index:1;position:relative}.toolbar{background:var(--bg-secondary);border:1px solid var(--border-subtle);border-radius:var(--radius-md);flex-wrap:wrap;align-items:center;gap:.75rem;margin-bottom:1rem;padding:.5rem .75rem;display:flex}.toolbar-actions{align-items:center;gap:.75rem;display:flex}.toolbar-toggle{color:var(--text-secondary);cursor:pointer;align-items:center;gap:.5rem;font-size:13px;display:flex}.toolbar-toggle input{accent-color:var(--accent)}.btn-sm{width:auto;padding:.4rem .75rem}.overview-status-bar{background:var(--bg-secondary);border:1px solid var(--border-subtle);border-radius:var(--radius-md);flex-wrap:wrap;justify-content:space-between;align-items:center;gap:.75rem;margin-bottom:1rem;padding:.75rem 1rem;display:flex}.status-bar-left{align-items:center;gap:.75rem;display:flex}.status-dot{background:var(--text-muted);border-radius:50%;width:8px;height:8px;animation:2s ease-in-out infinite pulse-dot}.status-dot.healthy{background:var(--success);box-shadow:0 0 8px #3fb95080}.status-dot.unhealthy{background:var(--error);box-shadow:0 0 8px #f8514980}.status-text{color:var(--text-primary);font-size:14px;font-weight:600}.status-uptime{font-family:JetBrains Mono,monospace;font-size:12px}.quick-stats{color:var(--text-secondary);align-items:center;gap:1.5rem;font-size:12px;display:flex}.quick-stat{align-items:center;gap:.375rem;display:flex}.quick-stat strong{color:var(--accent);font-weight:600}.quick-stat.muted{color:var(--text-muted)}@keyframes pulse-dot{0%,to{opacity:1}50%{opacity:.6}}.loading-overlay{-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);z-index:1000;color:var(--text-secondary);background:#0c0e12e6;flex-direction:column;justify-content:center;align-items:center;gap:1.25rem;display:flex;position:fixed;inset:0}.loading-spinner{border:3px solid var(--border-subtle);border-top-color:var(--accent);border-radius:50%;width:44px;height:44px;animation:.7s cubic-bezier(.5,0,.5,1) infinite spin}@keyframes spin{to{transform:rotate(360deg)}}.health-container{grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:1rem;margin-bottom:1.5rem;display:grid}.health-card{background:var(--bg-secondary);border:1px solid var(--border-subtle);border-radius:var(--radius-md);padding:1rem 1.25rem}.health-card.healthy{border-left:4px solid var(--success);background:linear-gradient(90deg,#3fb9500f 0%,#0000 100%)}.health-card.unhealthy{border-left:4px solid var(--error);background:linear-gradient(90deg,#f851490f 0%,#0000 100%)}.health-card.unknown{border-left:4px solid var(--warning);background:linear-gradient(90deg,#d299220f 0%,#0000 100%)}.health-card h3{margin:0 0 .5rem;font-size:14px}.health-card .status{font-weight:600}.health-card.healthy .status{color:var(--success)}.health-card.unhealthy .status{color:var(--error)}.health-card.unknown .status{color:var(--warning)}.health-card .endpoint{color:var(--text-muted);margin-top:.375rem;font-family:JetBrains Mono,monospace;font-size:10px}.overview-grid{grid-template-rows:repeat(2,minmax(0,1fr));grid-template-columns:repeat(3,minmax(0,1fr));align-items:stretch;gap:1rem;min-height:340px;margin-bottom:1.5rem;display:grid}@media (width<=900px){.overview-grid{grid-template-rows:repeat(3,minmax(0,1fr));grid-template-columns:repeat(2,minmax(0,1fr));min-height:510px}}@media (width<=600px){.overview-grid{grid-template-rows:repeat(6,minmax(0,1fr));grid-template-columns:1fr;min-height:720px}}.overview-block{background:var(--bg-secondary);border:1px solid var(--border-subtle);border-radius:var(--radius-md);min-width:0;min-height:0;transition:border-color var(--transition), box-shadow var(--transition);flex-direction:column;padding:1rem 1.25rem;display:flex;position:relative;overflow-y:auto}.overview-block:before{content:"";background:linear-gradient(90deg, var(--accent) 0%, transparent 70%);opacity:.5;height:2px;position:absolute;top:0;left:0;right:0}.overview-block:hover{border-color:var(--border);box-shadow:var(--shadow-sm)}.overview-block-title{color:var(--text-muted);text-transform:uppercase;letter-spacing:.1em;margin:0 0 .75rem;font-size:10px;font-weight:700}.overview-env .overview-block-title,.overview-health .overview-block-title,.overview-runtime .overview-block-title,.overview-gateway .overview-block-title,.overview-discovery .overview-block-title,.overview-resilience .overview-block-title{color:var(--text-secondary)}.env-info{grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:1rem;margin-bottom:1.5rem;display:grid}.env-info-compact{gap:.5rem;margin-bottom:0}.env-info .env-item{color:var(--text-secondary);border-bottom:1px solid var(--border-subtle);padding:.35rem 0;font-size:12px}.env-info .env-item:last-child{border-bottom:none}.env-info .env-item strong{color:var(--text-primary);margin-bottom:.125rem;font-weight:600;display:block}.health-cards-inline{flex-wrap:wrap;gap:.5rem;display:flex}.health-cards-inline .health-card{border-radius:var(--radius-sm);min-width:0;transition:box-shadow var(--transition);flex:1;padding:.75rem 1rem}.health-cards-inline .health-card:hover{box-shadow:var(--shadow-sm)}.health-cards-inline .health-card h3{color:var(--text-secondary);margin-bottom:.375rem;font-size:11px;font-weight:600}.health-cards-inline .health-card .status{font-size:13px;font-weight:700}.runtime-cards-inline{grid-template-columns:repeat(3,minmax(0,1fr));gap:.75rem;display:grid}.runtime-cards-inline .card{background:var(--bg-tertiary);border-radius:var(--radius-sm);border:1px solid var(--border-subtle);min-width:0;transition:border-color var(--transition), background var(--transition);padding:.75rem 1rem}.runtime-cards-inline .card:hover{background:var(--bg-elevated);border-color:var(--border)}.runtime-cards-inline .card .card-icon{width:22px;height:22px;color:var(--accent);margin-bottom:.35rem}.runtime-cards-inline .card .card-label{text-transform:uppercase;letter-spacing:.05em;color:var(--text-muted);margin-bottom:.2rem;font-size:9px;font-weight:600}.runtime-cards-inline .card .card-value{font-family:JetBrains Mono,monospace;font-size:1.1rem;font-weight:600}.runtime-cards-inline .card .card-value.highlight{color:var(--accent)}.chart-inline{height:120px;margin-bottom:1rem}.overview-gateway-stats,.overview-discovery-stats,.overview-resilience-stats{flex-wrap:wrap;gap:.75rem;margin-bottom:.75rem;display:flex}.overview-stat{background:var(--bg-tertiary);border-radius:var(--radius-sm);border:1px solid var(--border-subtle);flex-direction:column;gap:.125rem;min-width:0;padding:.4rem .6rem;display:flex}.overview-stat .stat-value{color:var(--accent);font-family:JetBrains Mono,monospace;font-size:1.1rem;font-weight:700}.overview-stat .stat-label{color:var(--text-muted);text-transform:uppercase;letter-spacing:.05em;font-size:9px;font-weight:600}.overview-gateway-routes,.overview-discovery-services,.overview-resilience-states{color:var(--text-secondary);overflow-wrap:break-word;word-break:break-word;min-width:0;font-size:11px;line-height:1.5}.overview-resilience-states{flex-wrap:wrap;gap:.375rem;display:flex}.overview-gateway-routes code,.overview-discovery-services code,.overview-resilience-states code{background:var(--bg-tertiary);border:1px solid var(--border-subtle);border-radius:4px;padding:.15rem .35rem;font-family:JetBrains Mono,monospace;font-size:10px}.discovery-service{margin-right:.5rem}.cb-state{border-radius:4px;padding:.15rem .4rem;font-size:11px;font-weight:600;display:inline-block}.cb-state.closed{color:var(--success);background:#3fb9501f}.cb-state.open{color:var(--error);background:#f851491f}.cb-state.half-open{color:var(--warning);background:#d299221f}.muted{color:var(--text-muted);font-size:11px}.detail-actions{gap:.5rem;display:flex}.modal{z-index:200;background:#0009;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.modal-content{background:var(--bg-secondary);border:1px solid var(--border);border-radius:var(--radius-lg);width:90%;max-width:480px;padding:1.5rem}.modal-content.modal-wide{max-width:720px}.playground-output{background:var(--bg-tertiary);border:1px solid var(--border);border-radius:var(--radius-sm);white-space:pre-wrap;word-break:break-word;max-height:200px;padding:1rem;font-size:12px;overflow:auto}.playground-meta{color:var(--text-muted);margin-top:.5rem;font-size:12px}.playground-actions{margin:.5rem 0}.diff-sources{grid-template-columns:1fr 1fr;gap:1rem;margin-bottom:1rem;display:grid}.diff-hint{color:var(--text-muted);margin:.25rem 0;font-size:12px}.diff-result{background:var(--bg-tertiary);border-radius:var(--radius-sm);max-height:300px;margin-top:1rem;padding:1rem;overflow:auto}.diff-result .added{color:var(--success)}.diff-result .removed{color:var(--error)}.diff-result .changed{color:var(--warning)}.module-graph-container{background:var(--bg-secondary);border:1px solid var(--border-subtle);border-radius:var(--radius-md);min-height:200px;margin-bottom:1rem;padding:1rem}.module-graph-svg{width:100%;height:300px}.rag-explorer{background:var(--bg-secondary);border:1px solid var(--border-subtle);border-radius:var(--radius-md);margin-bottom:1rem;padding:1rem}.rag-search-row{gap:.5rem;margin-top:.5rem;display:flex}.rag-search-row input{flex:1}.rag-results{max-height:300px;margin-top:1rem;overflow:auto}.rag-result-item{border-bottom:1px solid var(--border-subtle);padding:.75rem;font-size:12px}.rag-result-item .score{color:var(--accent);font-weight:600}.modal-content h3{margin:0 0 1rem;font-size:16px}.modal-body,.form-group{margin-bottom:1rem}.form-group label{color:var(--text-muted);margin-bottom:.5rem;font-size:12px;font-weight:600;display:block}.form-group input,.form-group select,.form-group textarea{border:1px solid var(--border);border-radius:var(--radius-sm);background:var(--bg-tertiary);width:100%;color:var(--text-primary);padding:.5rem;font-family:JetBrains Mono,monospace}.modal-footer{justify-content:flex-end;gap:.5rem;display:flex}.test-result{border-radius:var(--radius-sm);max-height:200px;margin-top:1rem;padding:1rem;font-family:JetBrains Mono,monospace;font-size:12px;overflow:auto}.test-result.success{color:var(--success);background:#3fb95026}.test-result.error{color:var(--error);background:#f8514926}.chart-container{background:var(--bg-secondary);border:1px solid var(--border-subtle);border-radius:var(--radius-md);height:200px;margin-bottom:1.5rem;padding:1rem}.flow-diagram{--flow-edge:var(--text-muted);background:var(--bg-secondary);border:1px solid var(--border-subtle);border-radius:var(--radius-md);flex-direction:column;gap:.5rem;margin-bottom:.5rem;padding:.5rem;display:flex}.flow-diagram-card{background:var(--bg-tertiary);border:1px solid var(--border-subtle);border-radius:var(--radius-sm);flex-direction:column;gap:.35rem;padding:.35rem .5rem;display:flex;overflow:hidden}.flow-diagram-badge{color:var(--text-secondary);text-transform:uppercase;letter-spacing:.04em;align-items:center;font-size:.65rem;font-weight:600;display:inline-flex}.flow-diagram-svg-wrap{border-radius:var(--radius-sm);background:var(--bg-primary);height:64px;overflow:hidden}.flow-diagram-svg{object-fit:contain;object-position:left center;width:100%;height:100%;display:block}.flow-runtime-hint{color:var(--text-muted);background:var(--bg-secondary);border:1px solid var(--border-subtle);border-radius:var(--radius-sm);flex-wrap:wrap;align-items:center;gap:.35rem .5rem;margin-bottom:.5rem;padding:.4rem .6rem;font-size:11px;display:flex}.flow-runtime-label{color:var(--text-secondary);font-weight:500}.flow-runtime-hint code{background:var(--bg-tertiary);border-radius:4px;padding:.1rem .3rem;font-family:JetBrains Mono,monospace;font-size:10px}.flow-runtime-sep{color:var(--border);font-weight:300}#flows .section-title{margin-bottom:.5rem}.flow-diagram-card .flow-node-group{cursor:default}.flow-diagram-card .flow-node-group:hover .flow-diagram-node{filter:brightness(1.08)}.flow-diagram-node{fill:var(--bg-elevated);stroke:var(--border-subtle);stroke-width:1px;transition:filter .15s}.flow-diagram-node.entry{fill:var(--accent-muted);stroke:var(--accent)}.flow-group{flex-wrap:wrap;align-items:center;gap:.5rem;display:flex}.flow-node{background:var(--bg-tertiary);border:1px solid var(--border);border-radius:var(--radius-sm);padding:.5rem 1rem;font-family:JetBrains Mono,monospace;font-size:12px}.flow-node.entry{border-color:var(--accent);background:var(--accent-muted)}.offline-banner{background:var(--error);color:#fff;border-radius:var(--radius-md);justify-content:space-between;align-items:center;gap:1rem;margin-bottom:1rem;padding:1rem 1.5rem;display:flex}.offline-banner button{border-radius:var(--radius-sm);color:#fff;cursor:pointer;background:#fff3;border:none;padding:.5rem 1rem;font-weight:600}.offline-banner button:hover{background:#ffffff4d}th.sortable{cursor:pointer;-webkit-user-select:none;user-select:none}th.sortable:hover{color:var(--accent)}th.sortable:after{content:" ▾";opacity:.5;font-size:10px}th.sortable.asc:after{content:" ▴";opacity:1}th.sortable.desc:after{content:" ▾";opacity:1}.search{border:1px solid var(--border);border-radius:var(--radius-md);background:var(--bg-secondary);max-width:360px;color:var(--text-primary);transition:border-color var(--transition), box-shadow var(--transition);flex:1;padding:.5rem 1rem .5rem 2.5rem;font-family:JetBrains Mono,monospace;font-size:13px}.search::placeholder{color:var(--text-muted)}.search:focus{border-color:var(--accent);box-shadow:0 0 0 2px var(--accent-muted);outline:none}.search-wrapper{position:relative}.search-wrapper:before{content:"⌕";color:var(--text-muted);pointer-events:none;font-size:14px;position:absolute;top:50%;left:.875rem;transform:translateY(-50%)}.search-wrapper .search{padding-left:2.25rem}.tab-panel{animation:.2s fadeIn;display:none}.tab-panel.active{display:block}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}#summary-cards{flex-direction:column;gap:2rem;margin-top:.5rem;display:flex}#summary-cards:before{content:"Application Summary";color:var(--text-muted);text-transform:uppercase;letter-spacing:.12em;border-bottom:1px solid var(--border-subtle);margin-bottom:1rem;padding-bottom:.75rem;font-size:10px;font-weight:700;display:block}.overview-section{flex-direction:column;gap:1rem;display:flex}.overview-section-title{color:var(--text-muted);text-transform:uppercase;letter-spacing:.08em;border-bottom:1px solid var(--border-subtle);margin:0;padding-bottom:.5rem;font-size:12px;font-weight:600}.overview-section-cards{grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:1rem;display:grid}.cards{grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:1rem;display:grid}.overview-section .card{cursor:pointer;transition:border-color var(--transition), box-shadow var(--transition), transform var(--transition), background var(--transition);background:#14171d99}.overview-section .card:hover{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent-muted);background:#1f242bcc;transform:translate(4px)}.overview-section .card .card-icon{color:var(--text-muted);transition:color var(--transition)}.overview-section .card:hover .card-icon{color:var(--accent)}.card{background:var(--bg-secondary);border:1px solid var(--border-subtle);border-radius:var(--radius-md);transition:border-color var(--transition), box-shadow var(--transition);cursor:default;flex-direction:column;gap:.5rem;padding:1.25rem;display:flex}.card:hover{border-color:var(--border);box-shadow:var(--shadow-sm)}.card .card-icon{background:var(--accent-muted);width:36px;height:36px;color:var(--accent);border-radius:var(--radius-sm);flex-shrink:0;justify-content:center;align-items:center;display:flex}.card .card-icon svg{flex-shrink:0}.card .card-label{color:var(--text-muted);text-transform:uppercase;letter-spacing:.06em;margin-bottom:0;font-size:11px;font-weight:600}.card .card-value{color:var(--text-primary);font-family:JetBrains Mono,monospace;font-size:1.75rem;font-weight:600}.card .card-value.highlight{color:var(--accent)}.table-container{border:1px solid var(--border-subtle);border-radius:var(--radius-md);background:var(--bg-secondary);overflow-x:auto}table{border-collapse:collapse;width:100%;font-size:13px}th,td{text-align:left;border-bottom:1px solid var(--border-subtle);padding:.75rem 1rem}th{background:var(--bg-tertiary);color:var(--text-muted);text-transform:uppercase;letter-spacing:.05em;font-size:11px;font-weight:600}tr{transition:background var(--transition)}tr:hover{background:var(--bg-hover)}tr:last-child td{border-bottom:none}tr[data-id]{cursor:pointer}td{font-family:JetBrains Mono,monospace;font-size:12px}.badge{text-transform:uppercase;border-radius:4px;padding:.2rem .5rem;font-size:10px;font-weight:600;display:inline-block}.badge-get{color:var(--success);background:#3fb95033}.badge-post{color:var(--warning);background:#d2992233}.badge-put{color:#389bfd;background:#388bfd33}.badge-patch{color:#a371f7;background:#a371f733}.badge-delete{color:var(--error);background:#f8514933}.badge-default{background:var(--bg-tertiary);color:var(--text-muted)}.detail-panel{background:var(--bg-secondary);border-left:1px solid var(--border);z-index:100;flex-direction:column;width:420px;max-width:90vw;height:100%;padding:0;animation:.2s slideIn;display:flex;position:fixed;top:0;right:0;overflow:hidden;box-shadow:-8px 0 24px #0006}.hidden{display:none!important}.info-card{background:var(--bg-secondary);border:1px solid var(--border);border-radius:var(--radius-md);margin-bottom:1rem;padding:1rem 1.25rem}.info-card-title{color:var(--text-primary);margin:0 0 .5rem;font-size:14px;font-weight:600}.info-card-text{color:var(--text-secondary);margin:.25rem 0;font-size:13px;line-height:1.5}.info-card code{background:var(--bg-tertiary);border-radius:4px;padding:.15rem .4rem;font-family:JetBrains Mono,monospace;font-size:12px}.overview-error{background:var(--bg-secondary);border:1px solid var(--error);border-radius:var(--radius-md);color:var(--text-secondary);padding:1.5rem}.overview-error a{color:var(--accent)}@keyframes slideIn{0%{transform:translate(100%)}to{transform:translate(0)}}.detail-header{border-bottom:1px solid var(--border-subtle);background:var(--bg-tertiary);justify-content:space-between;align-items:center;padding:1rem 1.25rem;display:flex}.detail-header h2{color:var(--text-primary);margin:0;font-size:14px;font-weight:600}#detail-content{white-space:pre-wrap;word-break:break-word;color:var(--text-secondary);flex:1;margin:0;padding:1.25rem;font-family:JetBrains Mono,monospace;font-size:12px;line-height:1.6;overflow:auto}#detail-content .json-key{color:#7ee787}#detail-content .json-string{color:#a5d6ff}#detail-content .json-number{color:#79c0ff}#detail-content .json-boolean{color:#ff7b72}#detail-content .json-null{color:var(--text-muted)}td.empty-state{text-align:center;color:var(--text-muted);padding:3rem 2rem!important}.empty-state p{margin:.5rem 0;font-size:14px}.content a{color:var(--accent);text-decoration:none}.content a:hover{text-decoration:underline}.section-title{color:var(--text-primary);margin:0 0 1rem;font-size:16px;font-weight:600}
|
|
1
|
+
@import "https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&family=DM+Sans:wght@400;500;600;700&display=swap";:root{--hazel-primary:#1a365d;--hazel-primary-hover:#2c5282;--hazel-accent:#1a365d;--hazel-accent-hover:#2c5282;--hazel-primary-muted:#1a365d40;--hazel-accent-muted:#1a365d40;--bg-primary:#0c0e12;--bg-secondary:#14171d;--bg-tertiary:#1a1e26;--bg-elevated:#1f242b;--bg-hover:#252a33;--border:#2d333b;--border-subtle:#21262d;--text-primary:#e6edf3;--text-secondary:#8b949e;--text-muted:#6e7681;--accent:var(--hazel-accent);--accent-hover:var(--hazel-accent-hover);--accent-muted:var(--hazel-accent-muted);--success:#3fb950;--warning:#d29922;--error:#f85149;--radius-sm:6px;--radius-md:8px;--radius-lg:12px;--radius-xl:16px;--shadow-sm:0 1px 2px #0000004d;--shadow-md:0 4px 12px #0006;--shadow-lg:0 8px 24px #00000080;--shadow-glow:0 0 24px #1a365d33;--transition:.2s cubic-bezier(.4, 0, .2, 1)}*{box-sizing:border-box}body{background:var(--bg-primary);color:var(--text-primary);-webkit-font-smoothing:antialiased;margin:0;font-family:DM Sans,-apple-system,BlinkMacSystemFont,sans-serif;font-size:14px;line-height:1.5}#app{min-height:100vh;display:flex}.sidebar{background:var(--bg-secondary);border-right:1px solid var(--border-subtle);flex-direction:column;width:240px;min-width:240px;padding:0;display:flex}.logo{letter-spacing:.02em;color:var(--text-primary);border-bottom:1px solid var(--border-subtle);align-items:center;gap:.625rem;margin:0;padding:1.25rem 1.25rem 1rem;font-size:13px;font-weight:600;display:flex}.logo-img{object-fit:contain;flex-shrink:0;width:24px;height:24px}.logo-svg{width:24px;height:24px;color:var(--accent);flex-shrink:0}.logo-fallback{align-items:center;display:flex}.logo-text{color:var(--text-primary);font-weight:700}.sidebar nav{flex-direction:column;flex:1;gap:.25rem;min-height:0;padding:.75rem 0;display:flex;overflow-y:auto}.nav-section{flex-direction:column;gap:.125rem;display:flex}.nav-section-title{color:var(--text-muted);text-transform:uppercase;letter-spacing:.08em;border-top:1px solid var(--border-subtle);margin:.25rem .5rem 0 0;padding:.5rem 1.25rem .25rem;font-size:10px;font-weight:600}.sidebar nav a{color:var(--text-secondary);border-radius:var(--radius-sm);transition:color var(--transition), background var(--transition);align-items:center;gap:.625rem;margin:0 .5rem;padding:.5rem 1.25rem;font-weight:500;text-decoration:none;display:flex}.sidebar nav a:hover{color:var(--text-primary);background:var(--bg-hover)}.sidebar nav a.active{color:#60a5fa;background:#3b82f633}.sidebar nav a .nav-icon{background:var(--text-muted);border-radius:2px;flex-shrink:0;width:3px;height:14px}.sidebar nav a:hover .nav-icon{background:var(--text-secondary)}.sidebar nav a.active .nav-icon{background:#60a5fa}.sidebar-footer{border-top:1px solid var(--border-subtle);padding:1rem 1.25rem}.btn{background:var(--bg-tertiary);width:100%;color:var(--text-primary);border:1px solid var(--border);border-radius:var(--radius-sm);cursor:pointer;transition:background var(--transition), border-color var(--transition);padding:.5rem 1rem;font-family:inherit;font-size:13px;font-weight:500}.btn:hover{background:var(--bg-hover);border-color:var(--text-muted)}.btn-primary{background:var(--accent);border-color:var(--accent);color:#fff}.btn-primary:hover{background:var(--accent-hover);border-color:var(--accent-hover);color:#fff}.content{background:var(--bg-primary);isolation:isolate;flex:1;padding:1rem 1.5rem;position:relative;overflow:auto}.content:before{content:"";pointer-events:none;z-index:0;background:radial-gradient(80% 50% at 50% -20%,#1a365d59,#0000),radial-gradient(60% 40% at 100%,#1a365d14,#0000),radial-gradient(40% 30% at 0 80%,#1a365d26,#0000);position:absolute;inset:0}.content>*{z-index:1;position:relative}.toolbar{background:var(--bg-secondary);border:1px solid var(--border-subtle);border-radius:var(--radius-md);flex-wrap:wrap;align-items:center;gap:.75rem;margin-bottom:1rem;padding:.5rem .75rem;display:flex}.toolbar-actions{align-items:center;gap:.75rem;display:flex}.toolbar-toggle{color:var(--text-secondary);cursor:pointer;align-items:center;gap:.5rem;font-size:13px;display:flex}.toolbar-toggle input{accent-color:var(--accent)}.btn-sm{width:auto;padding:.4rem .75rem}.overview-status-bar{background:var(--bg-secondary);border:1px solid var(--border-subtle);border-radius:var(--radius-md);flex-wrap:wrap;justify-content:space-between;align-items:center;gap:.75rem;margin-bottom:1rem;padding:.75rem 1rem;display:flex}.status-bar-left{align-items:center;gap:.75rem;display:flex}.status-dot{background:var(--text-muted);border-radius:50%;width:8px;height:8px;animation:2s ease-in-out infinite pulse-dot}.status-dot.healthy{background:var(--success);box-shadow:0 0 8px #3fb95080}.status-dot.unhealthy{background:var(--error);box-shadow:0 0 8px #f8514980}.status-text{color:var(--text-primary);font-size:14px;font-weight:600}.status-uptime{font-family:JetBrains Mono,monospace;font-size:12px}.quick-stats{color:var(--text-secondary);align-items:center;gap:1.5rem;font-size:12px;display:flex}.quick-stat{align-items:center;gap:.375rem;display:flex}.quick-stat strong{color:var(--accent);font-weight:600}.quick-stat.muted{color:var(--text-muted)}@keyframes pulse-dot{0%,to{opacity:1}50%{opacity:.6}}.loading-overlay{-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);z-index:1000;color:var(--text-secondary);background:#0c0e12e6;flex-direction:column;justify-content:center;align-items:center;gap:1.25rem;display:flex;position:fixed;inset:0}.loading-spinner{border:3px solid var(--border-subtle);border-top-color:var(--accent);border-radius:50%;width:44px;height:44px;animation:.7s cubic-bezier(.5,0,.5,1) infinite spin}@keyframes spin{to{transform:rotate(360deg)}}.health-container{grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:1rem;margin-bottom:1.5rem;display:grid}.health-card{background:var(--bg-secondary);border:1px solid var(--border-subtle);border-radius:var(--radius-md);padding:1rem 1.25rem}.health-card.healthy{border-left:4px solid var(--success);background:linear-gradient(90deg,#3fb9500f 0%,#0000 100%)}.health-card.unhealthy{border-left:4px solid var(--error);background:linear-gradient(90deg,#f851490f 0%,#0000 100%)}.health-card.unknown{border-left:4px solid var(--warning);background:linear-gradient(90deg,#d299220f 0%,#0000 100%)}.health-card h3{margin:0 0 .5rem;font-size:14px}.health-card .status{font-weight:600}.health-card.healthy .status{color:var(--success)}.health-card.unhealthy .status{color:var(--error)}.health-card.unknown .status{color:var(--warning)}.health-card .endpoint{color:var(--text-muted);margin-top:.375rem;font-family:JetBrains Mono,monospace;font-size:10px}.overview-grid{grid-template-rows:repeat(2,minmax(0,1fr));grid-template-columns:repeat(3,minmax(0,1fr));align-items:stretch;gap:1rem;min-height:340px;margin-bottom:1.5rem;display:grid}@media (width<=900px){.overview-grid{grid-template-rows:repeat(3,minmax(0,1fr));grid-template-columns:repeat(2,minmax(0,1fr));min-height:510px}}@media (width<=600px){.overview-grid{grid-template-rows:repeat(6,minmax(0,1fr));grid-template-columns:1fr;min-height:720px}}.overview-block{background:var(--bg-secondary);border:1px solid var(--border-subtle);border-radius:var(--radius-md);min-width:0;min-height:0;transition:border-color var(--transition), box-shadow var(--transition);flex-direction:column;padding:1rem 1.25rem;display:flex;position:relative;overflow-y:auto}.overview-block:before{content:"";background:linear-gradient(90deg, var(--accent) 0%, transparent 70%);opacity:.5;height:2px;position:absolute;top:0;left:0;right:0}.overview-block:hover{border-color:var(--border);box-shadow:var(--shadow-sm)}.overview-block-title{color:var(--text-muted);text-transform:uppercase;letter-spacing:.1em;margin:0 0 .75rem;font-size:10px;font-weight:700}.overview-env .overview-block-title,.overview-health .overview-block-title,.overview-runtime .overview-block-title,.overview-gateway .overview-block-title,.overview-discovery .overview-block-title,.overview-resilience .overview-block-title{color:var(--text-secondary)}.env-info{grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:1rem;margin-bottom:1.5rem;display:grid}.env-info-compact{gap:.5rem;margin-bottom:0}.env-info .env-item{color:var(--text-secondary);border-bottom:1px solid var(--border-subtle);padding:.35rem 0;font-size:12px}.env-info .env-item:last-child{border-bottom:none}.env-info .env-item strong{color:var(--text-primary);margin-bottom:.125rem;font-weight:600;display:block}.health-cards-inline{flex-wrap:wrap;gap:.5rem;display:flex}.health-cards-inline .health-card{border-radius:var(--radius-sm);min-width:0;transition:box-shadow var(--transition);flex:1;padding:.75rem 1rem}.health-cards-inline .health-card:hover{box-shadow:var(--shadow-sm)}.health-cards-inline .health-card h3{color:var(--text-secondary);margin-bottom:.375rem;font-size:11px;font-weight:600}.health-cards-inline .health-card .status{font-size:13px;font-weight:700}.runtime-cards-inline{grid-template-columns:repeat(3,minmax(0,1fr));gap:.75rem;display:grid}.runtime-cards-inline .card{background:var(--bg-tertiary);border-radius:var(--radius-sm);border:1px solid var(--border-subtle);min-width:0;transition:border-color var(--transition), background var(--transition);padding:.75rem 1rem}.runtime-cards-inline .card:hover{background:var(--bg-elevated);border-color:var(--border)}.runtime-cards-inline .card .card-icon{width:22px;height:22px;color:var(--accent);margin-bottom:.35rem}.runtime-cards-inline .card .card-label{text-transform:uppercase;letter-spacing:.05em;color:var(--text-muted);margin-bottom:.2rem;font-size:9px;font-weight:600}.runtime-cards-inline .card .card-value{font-family:JetBrains Mono,monospace;font-size:1.1rem;font-weight:600}.runtime-cards-inline .card .card-value.highlight{color:var(--accent)}.chart-inline{height:120px;margin-bottom:1rem}.overview-gateway-stats,.overview-discovery-stats,.overview-resilience-stats{flex-wrap:wrap;gap:.75rem;margin-bottom:.75rem;display:flex}.overview-stat{background:var(--bg-tertiary);border-radius:var(--radius-sm);border:1px solid var(--border-subtle);flex-direction:column;gap:.125rem;min-width:0;padding:.4rem .6rem;display:flex}.overview-stat .stat-value{color:var(--accent);font-family:JetBrains Mono,monospace;font-size:1.1rem;font-weight:700}.overview-stat .stat-label{color:var(--text-muted);text-transform:uppercase;letter-spacing:.05em;font-size:9px;font-weight:600}.overview-gateway-routes,.overview-discovery-services,.overview-resilience-states{color:var(--text-secondary);overflow-wrap:break-word;word-break:break-word;min-width:0;font-size:11px;line-height:1.5}.overview-resilience-states{flex-wrap:wrap;gap:.375rem;display:flex}.overview-gateway-routes code,.overview-discovery-services code,.overview-resilience-states code{background:var(--bg-tertiary);border:1px solid var(--border-subtle);border-radius:4px;padding:.15rem .35rem;font-family:JetBrains Mono,monospace;font-size:10px}.discovery-service{margin-right:.5rem}.cb-state{border-radius:4px;padding:.15rem .4rem;font-size:11px;font-weight:600;display:inline-block}.cb-state.closed{color:var(--success);background:#3fb9501f}.cb-state.open{color:var(--error);background:#f851491f}.cb-state.half-open{color:var(--warning);background:#d299221f}.muted{color:var(--text-muted);font-size:11px}.detail-actions{gap:.5rem;display:flex}.modal{z-index:200;background:#0009;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.modal-content{background:var(--bg-secondary);border:1px solid var(--border);border-radius:var(--radius-lg);width:90%;max-width:480px;padding:1.5rem}.modal-content.modal-wide{max-width:720px}.playground-output{background:var(--bg-tertiary);border:1px solid var(--border);border-radius:var(--radius-sm);white-space:pre-wrap;word-break:break-word;max-height:200px;padding:1rem;font-size:12px;overflow:auto}.playground-meta{color:var(--text-muted);margin-top:.5rem;font-size:12px}.playground-actions{margin:.5rem 0}.diff-sources{grid-template-columns:1fr 1fr;gap:1rem;margin-bottom:1rem;display:grid}.diff-hint{color:var(--text-muted);margin:.25rem 0;font-size:12px}.diff-result{background:var(--bg-tertiary);border-radius:var(--radius-sm);max-height:300px;margin-top:1rem;padding:1rem;overflow:auto}.diff-result .added{color:var(--success)}.diff-result .removed{color:var(--error)}.diff-result .changed{color:var(--warning)}.module-graph-container{background:var(--bg-secondary);border:1px solid var(--border-subtle);border-radius:var(--radius-md);min-height:200px;margin-bottom:1rem;padding:1rem}.module-graph-svg{width:100%;height:300px}.rag-explorer{background:var(--bg-secondary);border:1px solid var(--border-subtle);border-radius:var(--radius-md);margin-bottom:1rem;padding:1rem}.rag-search-row{gap:.5rem;margin-top:.5rem;display:flex}.rag-search-row input{flex:1}.rag-results{max-height:300px;margin-top:1rem;overflow:auto}.rag-result-item{border-bottom:1px solid var(--border-subtle);padding:.75rem;font-size:12px}.rag-result-item .score{color:var(--accent);font-weight:600}.modal-content h3{margin:0 0 1rem;font-size:16px}.modal-body,.form-group{margin-bottom:1rem}.form-group label{color:var(--text-muted);margin-bottom:.5rem;font-size:12px;font-weight:600;display:block}.form-group input,.form-group select,.form-group textarea{border:1px solid var(--border);border-radius:var(--radius-sm);background:var(--bg-tertiary);width:100%;color:var(--text-primary);padding:.5rem;font-family:JetBrains Mono,monospace}.modal-footer{justify-content:flex-end;gap:.5rem;display:flex}.test-result{border-radius:var(--radius-sm);max-height:200px;margin-top:1rem;padding:1rem;font-family:JetBrains Mono,monospace;font-size:12px;overflow:auto}.test-result.success{color:var(--success);background:#3fb95026}.test-result.error{color:var(--error);background:#f8514926}.chart-container{background:var(--bg-secondary);border:1px solid var(--border-subtle);border-radius:var(--radius-md);height:200px;margin-bottom:1.5rem;padding:1rem}.flow-diagram{--flow-edge:var(--text-muted);background:var(--bg-secondary);border:1px solid var(--border-subtle);border-radius:var(--radius-md);flex-direction:column;gap:.5rem;margin-bottom:.5rem;padding:.5rem;display:flex}.flow-diagram-card{background:var(--bg-tertiary);border:1px solid var(--border-subtle);border-radius:var(--radius-sm);flex-direction:column;gap:.35rem;padding:.35rem .5rem;display:flex;overflow:hidden}.flow-diagram-badge{color:var(--text-secondary);text-transform:uppercase;letter-spacing:.04em;align-items:center;font-size:.65rem;font-weight:600;display:inline-flex}.flow-diagram-svg-wrap{border-radius:var(--radius-sm);background:var(--bg-primary);height:64px;overflow:hidden}.flow-diagram-svg{object-fit:contain;object-position:left center;width:100%;height:100%;display:block}.flow-runtime-hint{color:var(--text-muted);background:var(--bg-secondary);border:1px solid var(--border-subtle);border-radius:var(--radius-sm);flex-wrap:wrap;align-items:center;gap:.35rem .5rem;margin-bottom:.5rem;padding:.4rem .6rem;font-size:11px;display:flex}.flow-runtime-label{color:var(--text-secondary);font-weight:500}.flow-runtime-hint code{background:var(--bg-tertiary);border-radius:4px;padding:.1rem .3rem;font-family:JetBrains Mono,monospace;font-size:10px}.flow-runtime-sep{color:var(--border);font-weight:300}#flows .section-title{margin-bottom:.5rem}.flow-diagram-card .flow-node-group{cursor:default}.flow-diagram-card .flow-node-group:hover .flow-diagram-node{filter:brightness(1.08)}.flow-diagram-node{fill:var(--bg-elevated);stroke:var(--border-subtle);stroke-width:1px;transition:filter .15s}.flow-diagram-node.entry{fill:var(--accent-muted);stroke:var(--accent)}.flow-group{flex-wrap:wrap;align-items:center;gap:.5rem;display:flex}.flow-node{background:var(--bg-tertiary);border:1px solid var(--border);border-radius:var(--radius-sm);padding:.5rem 1rem;font-family:JetBrains Mono,monospace;font-size:12px}.flow-node.entry{border-color:var(--accent);background:var(--accent-muted)}.offline-banner{background:var(--error);color:#fff;border-radius:var(--radius-md);justify-content:space-between;align-items:center;gap:1rem;margin-bottom:1rem;padding:1rem 1.5rem;display:flex}.offline-banner button{border-radius:var(--radius-sm);color:#fff;cursor:pointer;background:#fff3;border:none;padding:.5rem 1rem;font-weight:600}.offline-banner button:hover{background:#ffffff4d}th.sortable{cursor:pointer;-webkit-user-select:none;user-select:none}th.sortable:hover{color:var(--accent)}th.sortable:after{content:" ▾";opacity:.5;font-size:10px}th.sortable.asc:after{content:" ▴";opacity:1}th.sortable.desc:after{content:" ▾";opacity:1}.search{border:1px solid var(--border);border-radius:var(--radius-md);background:var(--bg-secondary);max-width:360px;color:var(--text-primary);transition:border-color var(--transition), box-shadow var(--transition);flex:1;padding:.5rem 1rem .5rem 2.5rem;font-family:JetBrains Mono,monospace;font-size:13px}.search::placeholder{color:var(--text-muted)}.search:focus{border-color:var(--accent);box-shadow:0 0 0 2px var(--accent-muted);outline:none}.search-wrapper{position:relative}.search-wrapper:before{content:"⌕";color:var(--text-muted);pointer-events:none;font-size:14px;position:absolute;top:50%;left:.875rem;transform:translateY(-50%)}.search-wrapper .search{padding-left:2.25rem}.tab-panel{animation:.2s fadeIn;display:none}.tab-panel.active{display:block}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}#summary-cards{flex-direction:column;gap:2rem;margin-top:.5rem;display:flex}#summary-cards:before{content:"Application Summary";color:var(--text-muted);text-transform:uppercase;letter-spacing:.12em;border-bottom:1px solid var(--border-subtle);margin-bottom:1rem;padding-bottom:.75rem;font-size:10px;font-weight:700;display:block}.overview-section{flex-direction:column;gap:1rem;display:flex}.overview-section-title{color:var(--text-muted);text-transform:uppercase;letter-spacing:.08em;border-bottom:1px solid var(--border-subtle);margin:0;padding-bottom:.5rem;font-size:12px;font-weight:600}.overview-section-cards{grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:1rem;display:grid}.cards{grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:1rem;display:grid}.overview-section .card{cursor:pointer;transition:border-color var(--transition), box-shadow var(--transition), transform var(--transition), background var(--transition);background:#14171d99}.overview-section .card:hover{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent-muted);background:#1f242bcc;transform:translate(4px)}.overview-section .card .card-icon{color:var(--text-muted);transition:color var(--transition)}.overview-section .card:hover .card-icon{color:var(--accent)}.card{background:var(--bg-secondary);border:1px solid var(--border-subtle);border-radius:var(--radius-md);transition:border-color var(--transition), box-shadow var(--transition);cursor:default;flex-direction:column;gap:.5rem;padding:1.25rem;display:flex}.card:hover{border-color:var(--border);box-shadow:var(--shadow-sm)}.card .card-icon{background:var(--accent-muted);width:36px;height:36px;color:var(--accent);border-radius:var(--radius-sm);flex-shrink:0;justify-content:center;align-items:center;display:flex}.card .card-icon svg{flex-shrink:0}.card .card-label{color:var(--text-muted);text-transform:uppercase;letter-spacing:.06em;margin-bottom:0;font-size:11px;font-weight:600}.card .card-value{color:var(--text-primary);font-family:JetBrains Mono,monospace;font-size:1.75rem;font-weight:600}.card .card-value.highlight{color:var(--accent)}.table-container{border:1px solid var(--border-subtle);border-radius:var(--radius-md);background:var(--bg-secondary);overflow-x:auto}table{border-collapse:collapse;width:100%;font-size:13px}th,td{text-align:left;border-bottom:1px solid var(--border-subtle);padding:.75rem 1rem}th{background:var(--bg-tertiary);color:var(--text-muted);text-transform:uppercase;letter-spacing:.05em;font-size:11px;font-weight:600}tr{transition:background var(--transition)}tr:hover{background:var(--bg-hover)}tr:last-child td{border-bottom:none}tr[data-id]{cursor:pointer}td{font-family:JetBrains Mono,monospace;font-size:12px}.badge{text-transform:uppercase;border-radius:4px;padding:.2rem .5rem;font-size:10px;font-weight:600;display:inline-block}.badge-get{color:var(--success);background:#3fb95033}.badge-post{color:var(--warning);background:#d2992233}.badge-put{color:#389bfd;background:#388bfd33}.badge-patch{color:#a371f7;background:#a371f733}.badge-delete{color:var(--error);background:#f8514933}.badge-default{background:var(--bg-tertiary);color:var(--text-muted)}.detail-panel{background:var(--bg-secondary);border-left:1px solid var(--border);z-index:100;flex-direction:column;width:420px;max-width:90vw;height:100%;padding:0;animation:.2s slideIn;display:flex;position:fixed;top:0;right:0;overflow:hidden;box-shadow:-8px 0 24px #0006}.hidden{display:none!important}.info-card{background:var(--bg-secondary);border:1px solid var(--border);border-radius:var(--radius-md);margin-bottom:1rem;padding:1rem 1.25rem}.info-card-title{color:var(--text-primary);margin:0 0 .5rem;font-size:14px;font-weight:600}.info-card-text{color:var(--text-secondary);margin:.25rem 0;font-size:13px;line-height:1.5}.info-card code{background:var(--bg-tertiary);border-radius:4px;padding:.15rem .4rem;font-family:JetBrains Mono,monospace;font-size:12px}.overview-error{background:var(--bg-secondary);border:1px solid var(--error);border-radius:var(--radius-md);color:var(--text-secondary);padding:1.5rem}.overview-error a{color:var(--accent)}@keyframes slideIn{0%{transform:translate(100%)}to{transform:translate(0)}}.detail-header{border-bottom:1px solid var(--border-subtle);background:var(--bg-tertiary);justify-content:space-between;align-items:center;padding:1rem 1.25rem;display:flex}.detail-header h2{color:var(--text-primary);margin:0;font-size:14px;font-weight:600}#detail-content{white-space:pre-wrap;word-break:break-word;color:var(--text-secondary);flex:1;margin:0;padding:1.25rem;font-family:JetBrains Mono,monospace;font-size:12px;line-height:1.6;overflow:auto}#detail-content .json-key{color:#7ee787}#detail-content .json-string{color:#a5d6ff}#detail-content .json-number{color:#79c0ff}#detail-content .json-boolean{color:#ff7b72}#detail-content .json-null{color:var(--text-muted)}td.empty-state{text-align:center;color:var(--text-muted);padding:3rem 2rem!important}.empty-state p{margin:.5rem 0;font-size:14px}.content a{color:var(--accent);text-decoration:none}.content a:hover{text-decoration:underline}.section-title{color:var(--text-primary);margin:0 0 1rem;font-size:16px;font-weight:600}.agent-timeline-panel{border-top:1px solid var(--border);margin-top:1.5rem;padding-top:1rem}.agent-timeline{flex-direction:column;gap:.5rem;max-height:420px;display:flex;overflow-y:auto}.timeline-step{border:1px solid var(--border);background:var(--bg-secondary);border-radius:6px;padding:.5rem .75rem}.timeline-step-head{flex-wrap:wrap;align-items:center;gap:.5rem;font-size:12px;display:flex}.timeline-prompt{white-space:pre-wrap;color:var(--text-muted);max-height:80px;margin:.4rem 0 0;font-size:11px;overflow:auto}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var e=(()=>{let e=window.location.pathname.match(/^\/[^/]+/);return e?e[0]:`/__hazel`})(),t=window.location.origin,n=null,r=!1,i=[],a=60;async function o(t=!1){let n=`${e}/inspect${t?`?refresh=1`:``}`,r=await fetch(n);if(!r.ok)throw Error(`Failed to fetch: ${r.status}`);return r.json()}async function s(){let t=await fetch(`${e}/stats`);return t.ok?t.json():{}}async function c(){let t=await fetch(`${e}/env`);return t.ok?t.json():{}}async function l(e){try{let n=await fetch(`${t}${e}`),r=n.ok,i;return i=n.headers.get(`content-type`)?.includes(`application/json`)?await n.json():await n.text(),{status:r?`up`:`down`,ok:r,data:i}}catch{return{status:`down`,ok:!1}}}function u(e){let t=document.getElementById(`loading-overlay`);t&&t.classList.toggle(`hidden`,!e)}function d(e,t){let n=document.getElementById(`status-dot`),r=document.getElementById(`status-text`),i=document.getElementById(`status-uptime`);if(!n||!r||!i)return;let a=e?.health?.ok&&e?.ready?.ok&&e?.startup?.ok,o=e?.health?.ok||e?.ready?.ok||e?.startup?.ok;n.className=`status-dot`+(a?` healthy`:o?``:` unhealthy`),r.textContent=a?`All systems operational`:o?`Degraded`:`Offline`,i.textContent=t.uptimeSeconds==null?``:`Uptime: ${m(t.uptimeSeconds)}`}function f(e){let t=document.getElementById(`quick-stats`);if(!t)return;let n=e&&typeof e==`object`?e:{},r=[];(n.route??0)>0&&r.push(`<span class="quick-stat"><strong>${n.route}</strong> routes</span>`),(n.module??0)>0&&r.push(`<span class="quick-stat"><strong>${n.module}</strong> modules</span>`),(n.provider??0)>0&&r.push(`<span class="quick-stat"><strong>${n.provider}</strong> providers</span>`),(n.cron??0)>0&&r.push(`<span class="quick-stat"><strong>${n.cron}</strong> jobs</span>`),t.innerHTML=r.join(``)||`<span class="quick-stat muted">No data</span>`}function p(e){let t=document.getElementById(`offline-banner`);e&&!t&&(t=document.createElement(`div`),t.id=`offline-banner`,t.className=`offline-banner`,t.innerHTML=`<span>App not running. Check that your server is started.</span><button id="retry-btn">Retry</button>`,document.querySelector(`.content`)?.insertBefore(t,document.querySelector(`.toolbar`)),t.querySelector(`#retry-btn`)?.addEventListener(`click`,()=>Y(!0))),t&&t.classList.toggle(`hidden`,!e)}function m(e){return e<60?`${Math.floor(e)}s`:e<3600?`${Math.floor(e/60)}m ${e%60}s`:`${Math.floor(e/3600)}h ${Math.floor(e%3600/60)}m`}function h(e){let t=String(e||``).toUpperCase();return`<span class="badge badge-${t===`GET`?`get`:t===`POST`?`post`:t===`PUT`?`put`:t===`PATCH`?`patch`:t===`DELETE`?`delete`:`default`}">${t||`?`}</span>`}function g(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,e=>{let t=`json-number`;return/^"/.test(e)?t=e.endsWith(`:`)?`json-key`:`json-string`:/true|false/.test(e)?t=`json-boolean`:/null/.test(e)&&(t=`json-null`),`<span class="${t}">${_(e)}</span>`})}function _(e){let t=document.createElement(`div`);return t.textContent=e,t.innerHTML}var v={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>`},y=[{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 b(e){let t=document.getElementById(`summary-cards`),n=e&&typeof e==`object`?e:{};t.innerHTML=y.map(e=>`
|
|
2
|
+
<section class="overview-section">
|
|
3
|
+
<h3 class="overview-section-title">${_(e.title)}</h3>
|
|
4
|
+
<div class="overview-section-cards">
|
|
5
|
+
${(Array.isArray(e.items)?e.items:[]).map(e=>`<div class="card" data-kind="${_(e.key)}">
|
|
6
|
+
<div class="card-icon">${v[e.key]??``}</div>
|
|
7
|
+
<div class="card-label">${_(e.label)}</div>
|
|
8
|
+
<div class="card-value">${n[e.key]??0}</div>
|
|
9
|
+
</div>`).join(``)}
|
|
10
|
+
</div>
|
|
11
|
+
</section>
|
|
12
|
+
`).join(``)}var x={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 S(e){let t=document.getElementById(`env-info`);t&&(t.innerHTML=`
|
|
13
|
+
<div class="env-item"><strong>Node</strong> ${_(e.nodeVersion??`—`)}</div>
|
|
14
|
+
<div class="env-item"><strong>NODE_ENV</strong> ${_(e.nodeEnv??`—`)}</div>
|
|
15
|
+
<div class="env-item"><strong>Inspector</strong> ${_(e.inspectorVersion??`—`)}</div>
|
|
16
|
+
<div class="env-item"><strong>Platform</strong> ${_(e.platform??`—`)}</div>
|
|
17
|
+
<div class="env-item"><strong>Arch</strong> ${_(e.arch??`—`)}</div>
|
|
18
|
+
`)}function C(e){let t=document.getElementById(`overview-gateway`);if(!t)return;let n=Array.isArray(e.routes)?e.routes:[],r=e.metrics;t.innerHTML=`
|
|
19
|
+
<h3 class="overview-block-title">Gateway</h3>
|
|
20
|
+
<div class="overview-gateway-stats">
|
|
21
|
+
<div class="overview-stat"><span class="stat-value">${n.length}</span><span class="stat-label">Routes</span></div>
|
|
22
|
+
${r?`
|
|
23
|
+
<div class="overview-stat"><span class="stat-value">${r.totalCalls}</span><span class="stat-label">Total Calls</span></div>
|
|
24
|
+
<div class="overview-stat"><span class="stat-value">${r.successCalls}</span><span class="stat-label">Success</span></div>
|
|
25
|
+
<div class="overview-stat"><span class="stat-value">${(r.failureRate??0).toFixed(1)}%</span><span class="stat-label">Failure Rate</span></div>
|
|
26
|
+
<div class="overview-stat"><span class="stat-value">${(r.averageResponseTime??0).toFixed(0)}ms</span><span class="stat-label">Avg Latency</span></div>
|
|
27
|
+
`:``}
|
|
28
|
+
</div>
|
|
29
|
+
${n.length?`<div class="overview-gateway-routes"><strong>Routes:</strong> ${n.slice(0,8).map(e=>`<code>${_(e)}</code>`).join(`, `)}${n.length>8?` <span class="muted">+${n.length-8} more</span>`:``}</div>`:``}
|
|
30
|
+
`,t.classList.remove(`hidden`)}function w(e){let t=document.getElementById(`overview-discovery`);if(!t)return;let n=Array.isArray(e.services)?e.services:[],r=e.instancesByService&&typeof e.instancesByService==`object`?e.instancesByService:{},i=n.slice(0,6).map(e=>`<span class="discovery-service"><code>${_(e)}</code>: ${r[e]??0} instance(s)</span>`).join(`, `);t.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
|
+
${n.length?`<div class="overview-discovery-services">${i}${n.length>6?` <span class="muted">+${n.length-6} more</span>`:``}</div>`:`<p class="muted">No services registered</p>`}
|
|
37
|
+
`,t.classList.remove(`hidden`)}function ee(e){let t=document.getElementById(`overview-resilience`);if(!t)return;let n=Array.isArray(e.circuitBreakerStates)?e.circuitBreakerStates:[],r=n.map(e=>`<span class="cb-state ${(e.state||``).toLowerCase()}"><code>${_(e.name)}</code>: ${_(e.state)}</span>`).join(`, `);t.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
|
+
${n.length?`<div class="overview-resilience-states">${r}</div>`:``}
|
|
43
|
+
`,t.classList.remove(`hidden`)}function te(e){let t=document.getElementById(`health-cards`);t&&(t.innerHTML=[{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}].map(e=>{let t=e.data??{status:`unknown`,ok:!1};return`
|
|
44
|
+
<div class="health-card ${t.ok?`healthy`:t.status===`unknown`?`unknown`:`unhealthy`}">
|
|
45
|
+
<h3>${_(e.label)}</h3>
|
|
46
|
+
<div class="status">${t.ok?`Up`:t.status===`unknown`?`Unknown`:`Down`}</div>
|
|
47
|
+
<div class="endpoint">${_(e.endpoint)}</div>
|
|
48
|
+
</div>
|
|
49
|
+
`}).join(``))}function ne(e){let t=document.getElementById(`runtime-cards`),n=e=>(e/1024/1024).toFixed(2);e.memory&&(i.push({heap:e.memory.heapUsed,rss:e.memory.rss,t:Date.now()}),i.length>a&&i.shift()),t.innerHTML=`
|
|
50
|
+
<div class="card">
|
|
51
|
+
<div class="card-icon">${x.heap}</div>
|
|
52
|
+
<div class="card-label">Heap Used</div>
|
|
53
|
+
<div class="card-value">${e.memory?.heapUsed?n(e.memory.heapUsed)+` MB`:`—`}</div>
|
|
54
|
+
</div>
|
|
55
|
+
<div class="card">
|
|
56
|
+
<div class="card-icon">${x.rss}</div>
|
|
57
|
+
<div class="card-label">RSS Memory</div>
|
|
58
|
+
<div class="card-value">${e.memory?.rss?n(e.memory.rss)+` MB`:`—`}</div>
|
|
59
|
+
</div>
|
|
60
|
+
<div class="card">
|
|
61
|
+
<div class="card-icon">${x.uptime}</div>
|
|
62
|
+
<div class="card-label">Uptime</div>
|
|
63
|
+
<div class="card-value highlight">${e.uptimeSeconds==null?`—`:m(e.uptimeSeconds)}</div>
|
|
64
|
+
</div>
|
|
65
|
+
`,T()}function T(){let e=document.getElementById(`memory-chart-container`);if(!e||i.length<2){e?.classList.add(`hidden`);return}e.classList.remove(`hidden`);let t=Math.max(...i.map(e=>e.heap)),n=Math.max(...i.map(e=>e.rss)),r=Math.max(t,n,1),a=e=>e/1024/1024/r*100;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="${i.map((e,t)=>`${t/(i.length-1)*100},${100-a(e.heap)}`).join(` `)}"/>
|
|
68
|
+
</svg>
|
|
69
|
+
<div style="font-size:11px;color:var(--text-muted);margin-top:0.5rem">Heap over time (last ${i.length} samples)</div>
|
|
70
|
+
`}var E={},D=50;function O(e){let t=new Map;for(let n of e){let e=String(n.flowId??``);t.has(e)||t.set(e,[]),t.get(e).push(n)}let n=new Map;for(let[e,r]of t){let t=r.find(e=>!!String(e.nodes??``).trim())??r[0],i=(t.nodes??``).split(/[,]/).map(e=>e.trim()).filter(Boolean);i.length===0&&(i=r.map(e=>e.nodeName).filter(e=>!!e));let a=(t.edges??``).toString().split(/[;,]/).map(e=>e.trim()).filter(Boolean).map(e=>{let t=e.indexOf(`→`);if(t<0)return null;let n=e.slice(0,t).trim(),r=e.slice(t+1).trim();return n&&r?{from:n,to:r}:null}).filter(e=>e!=null);for(let e of r){let t=(e.edges??``).toString().split(/[;,]/);for(let e of t){let t=e.indexOf(`→`);if(t>=0){let n=e.slice(0,t).trim(),r=e.slice(t+1).trim();n&&r&&!a.some(e=>e.from===n&&e.to===r)&&a.push({from:n,to:r})}}}let o=String(t.entryNode??i[0]??``);n.set(e,{nodes:[...new Set(i)],edges:a,entryNode:o})}return n}var k=48,re=24,A=6;function j(e){let t=new Map,n=new Map,r=e.entryNode||e.nodes[0];if(!r)return t;n.set(r,0);let i=[r],a=new Set([r]);for(;i.length>0;){let t=i.shift(),r=n.get(t)??0;for(let o of e.edges)if(o.from===t)if(!a.has(o.to))a.add(o.to),n.set(o.to,r+1),i.push(o.to);else{let e=n.get(o.to)??0;r+1>e&&n.set(o.to,r+1)}}let o=Math.max(0,...Array.from(n.values()));for(let t of e.nodes)n.has(t)||n.set(t,o+1);let s=new Map;for(let[e,t]of n)s.has(t)||s.set(t,[]),s.get(t).push(e);let c=[...s.keys()].sort((e,t)=>e-t);for(let e=0;e<c.length;e++){let n=c[e],r=s.get(n)??[];for(let n=0;n<r.length;n++){let i=r[n],a=A+e*54,o=A+n*28;t.set(i,{x:a,y:o})}}return t}function M(e){let t=document.getElementById(`flow-diagram`),n=Array.isArray(e)?e:[];if(!t||!n.length){t?.classList.add(`hidden`);return}let r=O(n);if(r.size===0){t?.classList.add(`hidden`);return}let i=k,a=re,o=``;for(let[e,t]of r){let n=j(t);if(n.size===0)continue;let r=Math.max(...Array.from(n.values()).map(e=>e.x))+i+A*2,s=Math.max(...Array.from(n.values()).map(e=>e.y))+a+A*2,c=`<svg class="flow-diagram-svg" viewBox="0 0 ${Math.max(240,r)} ${Math.max(48,s)}" xmlns="http://www.w3.org/2000/svg">`;for(let{from:e,to:r}of t.edges){let t=n.get(e),o=n.get(r);if(t&&o){let e=t.x+i,n=t.y+a/2,r=o.x,s=o.y+a/2,l=(e+r)/2;c+=`<path d="M ${e} ${n} C ${l} ${n} ${l} ${s} ${r} ${s}" fill="none" stroke="var(--flow-edge)" stroke-width="1" class="flow-edge"/>`;let u=r-4*Math.cos(Math.PI/6),d=s-4*Math.sin(Math.PI/6),f=r-4*Math.cos(-Math.PI/6),p=s-4*Math.sin(-Math.PI/6);c+=`<polygon points="${r},${s} ${u},${d} ${f},${p}" fill="var(--flow-edge)" class="flow-arrow"/>`}}for(let[e,r]of n){let n=e===t.entryNode?`flow-diagram-node entry`:`flow-diagram-node`,o=e.length>10?e.slice(0,8)+`…`:e;c+=`<g class="flow-node-group"><rect class="${n}" x="${r.x}" y="${r.y}" width="${i}" height="${a}" rx="4"/><text x="${r.x+i/2}" y="${r.y+a/2+3}" text-anchor="middle" font-size="9" fill="var(--text-primary)" class="flow-node-label">${_(o)}</text></g>`}c+=`</svg>`,o+=`<div class="flow-diagram-card"><span class="flow-diagram-badge" title="${_(e)}">${_(e)}</span><div class="flow-diagram-svg-wrap">${c}</div></div>`}t.innerHTML=o,t.classList.remove(`hidden`)}function N(e){let t=document.getElementById(`rag-explorer`),n=document.getElementById(`rag-pipeline-select`),r=document.getElementById(`rag-results`);if(!t||!n||!r)return;let i=Array.isArray(e)?e:[];if(!i.length){t.classList.add(`hidden`);return}t.classList.remove(`hidden`),n.innerHTML=i.map(e=>`<option value="${_(String(e.pipelineName??``))}">${_(String(e.pipelineName??``))}</option>`).join(``),r.innerHTML=``}async function P(){let t=document.getElementById(`rag-pipeline-select`),n=document.getElementById(`rag-search-input`),r=document.getElementById(`rag-results`);if(!t||!n||!r)return;let i=t.value,a=n.value.trim();if(a){r.innerHTML=`<p>Searching...</p>`;try{let t=await fetch(`${e}/rag/${encodeURIComponent(i)}/search?q=${encodeURIComponent(a)}`),n=await t.json();if(!t.ok){r.innerHTML=`<p class="error">${_(n.error??`Search failed`)}</p>`;return}let o=n.results??[];if(!o.length){r.innerHTML=`<p>No results found.</p>`;return}r.innerHTML=o.map(e=>`<div class="rag-result-item"><span class="score">${e.score==null?`—`:(e.score*100).toFixed(1)+`%`}</span> ${_(String(e.content??``).slice(0,200))}${String(e.content??``).length>200?`...`:``}</div>`).join(``)}catch(e){r.innerHTML=`<p class="error">${_(String(e))}</p>`}}}function F(e){let t=document.getElementById(`module-graph-container`),n=Array.isArray(e)?e:[];if(!t||!n.length){t?.classList.add(`hidden`);return}let r=new Map,i=[],a=n.map(e=>String(e.moduleName??``)).filter(Boolean),o=[...new Set(a)];o.forEach((e,t)=>{let n=Math.floor(t/4),i=t%4;r.set(e,{x:80+i*120,y:40+n*60})});for(let e of n){let t=String(e.moduleName??``),n=e.imports,a=Array.isArray(n)?n:typeof n==`string`?n.split(/[,;]/).map(e=>e.trim()):[];for(let e of a){let n=String(e).trim();n&&(o.includes(n)||r.has(n))&&(i.push({from:t,to:n}),r.has(n)||r.set(n,{x:80+r.size%4*120,y:40+Math.floor(r.size/4)*60}))}}let s=`<svg class="module-graph-svg" viewBox="0 0 500 ${Math.max(200,Math.ceil(o.length/4)*70)}" xmlns="http://www.w3.org/2000/svg">`;for(let{from:e,to:t}of i){let n=r.get(e),i=r.get(t);n&&i&&(s+=`<line x1="${n.x+50}" y1="${n.y+15}" x2="${i.x+50}" y2="${i.y+15}" stroke="var(--border)" stroke-width="1"/>`)}for(let[e,t]of r)s+=`<rect x="${t.x}" y="${t.y}" width="100" height="30" rx="4" fill="var(--bg-tertiary)" stroke="var(--border)"/>`,s+=`<text x="${t.x+50}" y="${t.y+20}" text-anchor="middle" font-size="11" fill="var(--text-primary)">${_(e.length>12?e.slice(0,10)+`..`:e)}</text>`;s+=`</svg>`,t.innerHTML=s,t.classList.remove(`hidden`)}function I(e,t,n,r,i,a){let o=document.getElementById(e),s=E[e]??{col:n[0],dir:`asc`},c=[...t];a?.sortable&&c.length>0&&c.sort((e,t)=>{let n=e[s.col],r=t[s.col],i=String(n??``).localeCompare(String(r??``),void 0,{numeric:!0});return s.dir===`asc`?i:-i});let l=c.length>D?c.slice(0,D):c,u=c.length>D;if(!t.length){o.innerHTML=`<thead></thead><tbody><tr><td colspan="${n.length+(a?.tryRoute||a?.runAgent?1:0)}" class="empty-state"><p>No entries found</p></td></tr></tbody>`;return}let d=i??{},f=n.map(e=>{let t=e.replace(/([A-Z])/g,` $1`).trim();return`<th class="${a?.sortable?` sortable ${s.col===e?s.dir:``}`:``}" data-col="${e}">${t}</th>`});if(a?.tryRoute&&f.push(`<th>Actions</th>`),a?.runAgent&&f.push(`<th>Actions</th>`),a?.previewPrompt&&f.push(`<th>Actions</th>`),o.innerHTML=`
|
|
71
|
+
<thead><tr>${f.join(``)}</tr></thead>
|
|
72
|
+
<tbody>
|
|
73
|
+
${l.map(e=>{let t=``;if(a?.tryRoute&&e.fullPath!=null){let n=String(e.fullPath);t=`<td><button class="btn btn-sm try-route" data-method="${String(e.httpMethod??`GET`).toUpperCase()}" data-path="${_(n)}">Try</button></td>`}else if(a?.runAgent&&e.agentName!=null){let n=_(String(e.agentName));t=`<td><button class="btn btn-sm run-agent" data-name="${n}">Run</button> <button class="btn btn-sm timeline-agent" data-name="${n}">Timeline</button></td>`}else a?.previewPrompt&&e.promptKey!=null?t=`<td><button class="btn btn-sm preview-prompt" data-key="${_(String(e.promptKey))}">Preview</button></td>`:(a?.tryRoute||a?.runAgent||a?.previewPrompt)&&(t=`<td></td>`);return`<tr data-id="${e.id??``}" data-json='${JSON.stringify(e).replace(/'/g,`\\'`)}'>
|
|
74
|
+
${n.map(t=>{let n=e[t],r=d[t];return`<td>${r?r(n,e):String(n??`—`)}</td>`}).join(``)}
|
|
75
|
+
${t}
|
|
76
|
+
</tr>`}).join(``)}
|
|
77
|
+
</tbody>
|
|
78
|
+
`,u){let e=document.createElement(`tr`);e.innerHTML=`<td colspan="${n.length+(a?.tryRoute||a?.runAgent?1:0)}" class="empty-state"><p>Showing ${D} of ${c.length}. Use search to filter.</p></td>`,o.querySelector(`tbody`).appendChild(e)}o.querySelectorAll(`tbody tr[data-json]`).forEach(e=>{e.addEventListener(`click`,t=>{if(t.target.closest(`button`))return;let n=e.dataset.json;n&&H(JSON.parse(n))})}),o.querySelectorAll(`th.sortable`).forEach(o=>{o.addEventListener(`click`,()=>{let c=o.dataset.col;E[e]={col:c,dir:s.col===c&&s.dir===`asc`?`desc`:`asc`},I(e,t,n,r,i,a)})}),o.querySelectorAll(`.try-route`).forEach(e=>{e.addEventListener(`click`,t=>{t.stopPropagation(),L(e.dataset.method??`GET`,e.dataset.path??`/`)})}),o.querySelectorAll(`.run-agent`).forEach(e=>{e.addEventListener(`click`,t=>{t.stopPropagation(),ie(e.dataset.name??``)})}),o.querySelectorAll(`.timeline-agent`).forEach(e=>{e.addEventListener(`click`,t=>{t.stopPropagation(),B(e.dataset.name??``)})}),o.querySelectorAll(`.preview-prompt`).forEach(e=>{e.addEventListener(`click`,t=>{t.stopPropagation(),se(e.dataset.key??``)})})}function L(e,n){let r=document.getElementById(`route-test-modal`),i=document.getElementById(`test-url`),a=document.getElementById(`test-method`),o=document.getElementById(`test-body-group`),s=document.getElementById(`test-result`);i.value=`${t}${n}`,a.value=e,o.classList.toggle(`hidden`,e===`GET`),s.classList.add(`hidden`),r.classList.remove(`hidden`)}var R=null;function z(e){let t=document.getElementById(`agent-timeline`);if(t){if(!e.length){t.innerHTML=`<p class="muted">No timeline events yet. Run an agent to stream steps.</p>`;return}t.innerHTML=e.map(e=>{let t=_(String(e.type??``)),n=e.state?`<span class="badge">${_(String(e.state))}</span>`:``,r=e.durationMs==null?``:`<span class="muted">${_(String(e.durationMs))}ms</span>`,i=e.confidence==null?``:`<span class="muted">confidence ${_(String(e.confidence))}</span>`,a=e.tokens==null?``:`<span class="muted">${_(String(e.tokens))} tok</span>`,o=e.cost==null?``:`<span class="muted">$${_(String(e.cost))}</span>`,s=e.prompt?`<pre class="timeline-prompt">${_(String(e.prompt).slice(0,400))}</pre>`:``;return`<div class="timeline-step" data-id="${_(String(e.id??``))}">
|
|
79
|
+
<div class="timeline-step-head"><strong>${t}</strong> ${n} ${r} ${i} ${a} ${o}</div>
|
|
80
|
+
${s}
|
|
81
|
+
</div>`}).join(``)}}async function B(t){let n=document.getElementById(`agent-timeline`);n&&(n.innerHTML=`<p class="muted">Loading timeline…</p>`);try{let r=await fetch(`${e}/agents/${encodeURIComponent(t)}/timeline`),i=await r.json();if(!r.ok){n&&(n.innerHTML=`<p class="muted">${_(i.error??`Failed`)}</p>`);return}z(i.steps??[])}catch(e){n&&(n.innerHTML=`<p class="muted">${_(String(e))}</p>`)}R&&=(R.close(),null);let r=[];R=new EventSource(`${e}/agents/${encodeURIComponent(t)}/stream`),R.onmessage=e=>{try{let t=JSON.parse(e.data);r.push(t),z(r.slice(-100))}catch{}}}async function ie(t){let n=prompt(`Enter input for agent (or leave empty for empty string):`)??``;B(t);try{let r=await fetch(`${e}/agents/${encodeURIComponent(t)}/run`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({input:n})}),i=await r.json();if(!r.ok){H({error:i.error??`Agent run failed`,status:r.status});return}H({agentName:t,result:i.result});let a=await fetch(`${e}/agents/${encodeURIComponent(t)}/timeline`);a.ok&&z((await a.json()).steps??[])}catch(e){H({error:String(e),agentName:t})}}function ae(e){let t=document.getElementById(`prompt-playground-modal`),n=document.getElementById(`playground-key`),r=document.getElementById(`playground-vars`),i=document.getElementById(`playground-output`),a=document.getElementById(`playground-tokens`);n.value=e,r.value=`{}`,i.textContent=``,a.textContent=`—`,t.classList.remove(`hidden`)}async function oe(t,n){let r=await fetch(`${e}/prompts/render`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({key:t,variables:n})});if(!r.ok){let e=await r.json().catch(()=>({error:r.statusText}));throw Error(e.error??`Failed to render`)}return r.json()}function se(e){ae(e)}var V=null;function H(e){V=e;let t=document.getElementById(`detail-panel`),n=document.getElementById(`detail-title`),r=document.getElementById(`detail-content`);n.textContent=String(e.kind??`Entry`),r.innerHTML=g(e),t.classList.remove(`hidden`)}function ce(){V=null,document.getElementById(`detail-panel`).classList.add(`hidden`)}function le(){if(!V)return;let e=JSON.stringify(V,null,2);navigator.clipboard.writeText(e).then(()=>{let e=document.getElementById(`detail-copy`);if(e){let t=e.textContent;e.textContent=`Copied!`,setTimeout(()=>{e.textContent=t},1500)}})}function ue(e,t){let n=Array.isArray(e)?e:[];if(!t.trim())return n;let r=t.toLowerCase();return n.filter(e=>JSON.stringify(e).toLowerCase().includes(r))}var U={httpMethod:e=>h(String(e??``))},W={enabled:e=>`<span class="badge ${e?`badge-get`:`badge-default`}">${e?`Enabled`:`Disabled`}</span>`,nextRuns:(e,t)=>{let n=Array.isArray(e)?e:[];return n.length?n.slice(0,3).map(e=>{try{return new Date(e).toLocaleString(void 0,{month:`short`,day:`numeric`,hour:`2-digit`,minute:`2-digit`})}catch{return e}}).join(`, `)+(n.length>3?`...`:``):`—`}},G={moduleName:e=>String(e??`—`),scope:e=>{let t=String(e??`singleton`);return`<span class="badge ${t===`singleton`?`badge-get`:t===`request`?`badge-post`:`badge-default`}">${t}</span>`}},K={tools:e=>Array.isArray(e)?e.join(`, `):String(e??`—`)},q={streaming:e=>`<span class="badge ${e?`badge-get`:`badge-default`}">${e?`Yes`:`No`}</span>`};function J(e,t){try{t()}catch(t){console.error(`[Inspector] ${e} failed:`,t)}}async function Y(e=!1){if(!r){r=!0,u(!0),p(!1);try{let t=await o(e),r=Array.isArray(t?.entries)?t.entries:[],i=t?.summary&&typeof t.summary==`object`?t.summary:{},a=t?.overview&&typeof t.overview==`object`?t.overview:{};n={entries:r,summary:i,overview:a},J(`overview`,()=>b(i)),a.gateway&&J(`gatewayOverview`,()=>C(a.gateway)),a.discovery&&J(`discoveryOverview`,()=>w(a.discovery)),a.resilience&&J(`resilienceOverview`,()=>ee(a.resilience)),[`overview-gateway`,`overview-discovery`,`overview-resilience`].forEach(e=>{let t=document.getElementById(e);t&&!a[e.replace(`overview-`,``)]&&t.classList.add(`hidden`)});let[u,p,m]=await Promise.all([c(),Promise.all([l(`/health`),l(`/ready`),l(`/startup`)]).then(([e,t,n])=>({health:e,ready:t,startup:n})),s()]);S(u),te(p),ne(m),d(p,m),f(i);let h=n.entries.filter(e=>e.kind===`route`),g=n.entries.filter(e=>e.kind===`module`),_=n.entries.filter(e=>e.kind===`provider`),v=n.entries.filter(e=>e.kind===`cron`),y=n.entries.filter(e=>e.kind===`queue`),x=n.entries.filter(e=>e.kind===`websocket`),T=n.entries.filter(e=>e.kind===`agent`),E=n.entries.filter(e=>e.kind===`rag`),D=n.entries.filter(e=>e.kind===`prompt`),O=n.entries.filter(e=>e.kind===`aifunction`),k=n.entries.filter(e=>e.kind===`event`),re=n.entries.filter(e=>e.kind===`graphql`),A=n.entries.filter(e=>e.kind===`grpc`),j=n.entries.filter(e=>e.kind===`kafka`),P=n.entries.filter(e=>e.kind===`flow`),L=n.entries.filter(e=>e.kind===`data`),R=n.entries.filter(e=>e.kind===`serverless`),z=n.entries.filter(e=>e.kind===`ml`);I(`routes-table`,h,[`httpMethod`,`fullPath`,`controllerPath`,`className`],`route`,U,{sortable:!0,tryRoute:!0}),J(`moduleGraph`,()=>F(g)),I(X.modules,g,[`moduleName`,`dynamicModule`,`imports`],`module`,void 0,{sortable:!0}),I(X.providers,_,[`providerName`,`moduleName`,`scope`],`provider`,G,{sortable:!0}),I(X.jobs,v,[`jobName`,`cronExpression`,`enabled`,`nextRuns`],`cron`,W),I(X.queues,y,[`queueName`,`consumerName`,`className`],`queue`),I(X.websocket,x,[`gatewayName`,`eventName`,`namespace`],`websocket`),I(X.agents,T,[`agentName`,`className`,`model`,`tools`],`agent`,K,{sortable:!0,runAgent:!0}),I(X.ai,O,[`className`,`methodName`,`provider`,`model`,`streaming`],`aifunction`,q),J(`ragExplorer`,()=>N(E)),I(X.rag,E,[`pipelineName`,`vectorStore`,`embeddingProvider`,`chunkingStrategy`],`rag`,void 0,{sortable:!0}),I(X.prompts,D,[`promptKey`,`scope`],`prompt`,void 0,{sortable:!0,previewPrompt:!0}),I(X.events,k,[`eventName`,`className`,`methodName`],`event`),I(X.graphql,re,[`operationType`,`operationName`,`resolverName`,`className`],`graphql`),I(X.grpc,A,[`serviceName`,`methodName`,`className`],`grpc`),I(X.kafka,j,[`consumerName`,`topic`,`groupId`,`methodName`],`kafka`);let B=document.getElementById(`flow-runtime-info`);B&&B.classList.toggle(`hidden`,P.length===0),J(`flowDiagram`,()=>M(P)),I(X.flows,P,[`flowId`,`version`,`sourceType`,`nodeName`,`entryNode`,`edges`,`className`],`flow`),I(X.data,L,[`pipelineName`,`className`],`data`),I(X.serverless,R,[`controllerName`,`runtime`,`memory`,`timeout`],`serverless`),I(X.ml,z,[`modelName`,`version`,`className`],`ml`)}catch(e){let t=String(e),n=t.includes(`Failed to fetch`)||t.includes(`NetworkError`)||t.includes(`Load failed`);p(n),d({health:{ok:!1},ready:{ok:!1},startup:{ok:!1}},{}),f({});let r=document.getElementById(`summary-cards`);if(r){let t=n?`Is the app running?`:`A rendering error occurred. Check the console for details.`;r.innerHTML=`<div class="overview-error"><p>Error: ${_(String(e))}</p><p>${_(t)} <button class="btn btn-sm btn-primary" id="retry-load">Retry</button></p></div>`,document.getElementById(`retry-load`)?.addEventListener(`click`,()=>Y(!0))}}finally{r=!1,u(!1)}}}var X={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`},de={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 Z(e){let t=document.querySelector(`.sidebar nav a[data-tab="${e}"]`);if(t){document.querySelectorAll(`.sidebar nav a`).forEach(e=>e.classList.remove(`active`)),document.querySelectorAll(`.tab-panel`).forEach(e=>e.classList.remove(`active`)),t.classList.add(`active`),document.getElementById(e)?.classList.add(`active`);let n=new URLSearchParams(window.location.search);n.set(`tab`,e),window.history.replaceState({},``,`${window.location.pathname}?${n}`)}}document.querySelectorAll(`.sidebar nav a`).forEach(e=>{e.addEventListener(`click`,t=>{t.preventDefault();let n=e.dataset.tab;Z(n)})}),document.getElementById(`summary-cards`)?.addEventListener(`click`,e=>{let t=e.target.closest(`.card[data-kind]`);if(t){let e=t.dataset.kind,n=e?de[e]:null;n&&Z(n)}});function Q(){Y(!0)}document.getElementById(`refresh`)?.addEventListener(`click`,Q),document.getElementById(`refresh-sidebar`)?.addEventListener(`click`,Q),document.getElementById(`detail-close`).addEventListener(`click`,ce),document.getElementById(`detail-copy`)?.addEventListener(`click`,le),document.getElementById(`export-btn`)?.addEventListener(`click`,()=>{if(!n)return;let e=new Blob([JSON.stringify(n,null,2)],{type:`application/json`}),t=document.createElement(`a`);t.href=URL.createObjectURL(e),t.download=`inspector-snapshot-${new Date().toISOString().slice(0,19).replace(/[T:]/g,`-`)}.json`,t.click(),URL.revokeObjectURL(t.href)});var fe=document.getElementById(`auto-refresh`),$=null;fe?.addEventListener(`change`,()=>{$&&clearInterval($),$=null,fe?.checked&&($=setInterval(()=>Y(!1),15e3))}),document.getElementById(`test-route-btn`)?.addEventListener(`click`,async()=>{let e=document.getElementById(`test-url`).value,t=document.getElementById(`test-method`).value,n=document.getElementById(`test-body`),r=document.getElementById(`test-result`);r.classList.remove(`hidden`),r.className=`test-result`,r.textContent=`Sending...`;try{let i={method:t};if(t!==`GET`&&n?.value)try{JSON.parse(n.value),i.body=n.value,i.headers={"Content-Type":`application/json`}}catch{r.className=`test-result error`,r.textContent=`Invalid JSON body`;return}let a=await fetch(e,i),o=await a.text();r.className=`test-result ${a.ok?`success`:`error`}`,r.textContent=`Status: ${a.status}\n\n${o.slice(0,500)}${o.length>500?`...`:``}`}catch(e){r.className=`test-result error`,r.textContent=String(e)}}),document.getElementById(`test-route-cancel`)?.addEventListener(`click`,()=>{document.getElementById(`route-test-modal`).classList.add(`hidden`)}),document.getElementById(`test-method`)?.addEventListener(`change`,e=>{let t=e.target.value;document.getElementById(`test-body-group`).classList.toggle(`hidden`,t===`GET`)}),document.getElementById(`playground-render`)?.addEventListener(`click`,async()=>{let e=document.getElementById(`playground-key`).value,t=document.getElementById(`playground-vars`).value,n=document.getElementById(`playground-output`),r=document.getElementById(`playground-tokens`),i={};try{i=t.trim()?JSON.parse(t):{}}catch{n.textContent=`Invalid JSON in variables`,r.textContent=`—`;return}try{let{rendered:t,tokenEstimate:a}=await oe(e,i);n.textContent=t,r.textContent=String(a)}catch(e){n.textContent=String(e),r.textContent=`—`}}),document.getElementById(`playground-close`)?.addEventListener(`click`,()=>{document.getElementById(`prompt-playground-modal`).classList.add(`hidden`)}),document.getElementById(`diff-btn`)?.addEventListener(`click`,()=>{document.getElementById(`diff-modal`).classList.remove(`hidden`)}),document.getElementById(`diff-close`)?.addEventListener(`click`,()=>{document.getElementById(`diff-modal`).classList.add(`hidden`)}),document.getElementById(`diff-load-file`)?.addEventListener(`click`,()=>{document.getElementById(`diff-file`).click()}),document.getElementById(`diff-file`)?.addEventListener(`change`,e=>{let t=e.target.files?.[0];if(!t)return;let n=new FileReader;n.onload=()=>{document.getElementById(`diff-snapshot-b`).value=String(n.result)},n.readAsText(t)}),document.getElementById(`rag-search-btn`)?.addEventListener(`click`,P),document.getElementById(`diff-compare-btn`)?.addEventListener(`click`,()=>{let e=document.getElementById(`diff-snapshot-b`).value.trim(),t=document.getElementById(`diff-result`);if(!n){t.innerHTML=`<p class="error">No current snapshot. Refresh first.</p>`,t.classList.remove(`hidden`);return}let r;try{r=e?JSON.parse(e):{entries:[],summary:{}}}catch{t.innerHTML=`<p class="error">Invalid JSON in Snapshot B.</p>`,t.classList.remove(`hidden`);return}let i=n.entries??[],a=r.entries??[],o=new Set(i.map(e=>e.id)),s=new Set(a.map(e=>e.id)),c=a.filter(e=>!o.has(e.id)),l=i.filter(e=>!s.has(e.id)),u=i.filter(e=>{let t=a.find(t=>t.id===e.id);return t&&JSON.stringify(e)!==JSON.stringify(t)}),d=``;c.length&&(d+=`<p class="added">+ ${c.length} added</p><ul>${c.map(e=>`<li>${_(String(e.kind))}: ${_(String(e.id??``))}</li>`).join(``)}</ul>`),l.length&&(d+=`<p class="removed">− ${l.length} removed</p><ul>${l.map(e=>`<li>${_(String(e.kind))}: ${_(String(e.id??``))}</li>`).join(``)}</ul>`),u.length&&(d+=`<p class="changed">~ ${u.length} changed</p><ul>${u.map(e=>`<li>${_(String(e.kind))}: ${_(String(e.id??``))}</li>`).join(``)}</ul>`),d||=`<p>No differences.</p>`,t.innerHTML=d,t.classList.remove(`hidden`)}),document.getElementById(`search`).addEventListener(`input`,e=>{let t=e.target.value;if(!n)return;let r=ue(n.entries,t),i=n.summary&&typeof n.summary==`object`?n.summary:{};b(Object.fromEntries(Object.entries(i).map(([e])=>[e,r.filter(t=>t.kind===e).length])));let a=r.filter(e=>e.kind===`route`),o=r.filter(e=>e.kind===`module`),s=r.filter(e=>e.kind===`provider`),c=r.filter(e=>e.kind===`cron`),l=r.filter(e=>e.kind===`queue`),u=r.filter(e=>e.kind===`websocket`),d=r.filter(e=>e.kind===`agent`),f=r.filter(e=>e.kind===`rag`),p=r.filter(e=>e.kind===`prompt`),m=r.filter(e=>e.kind===`aifunction`),h=r.filter(e=>e.kind===`event`),g=r.filter(e=>e.kind===`graphql`),_=r.filter(e=>e.kind===`grpc`),v=r.filter(e=>e.kind===`kafka`),y=r.filter(e=>e.kind===`flow`),x=r.filter(e=>e.kind===`data`),S=r.filter(e=>e.kind===`serverless`),C=r.filter(e=>e.kind===`ml`);I(`routes-table`,a,[`httpMethod`,`fullPath`,`controllerPath`,`className`],`route`,U,{sortable:!0,tryRoute:!0}),F(o),I(`modules-table`,o,[`moduleName`,`dynamicModule`,`imports`],`module`,void 0,{sortable:!0}),I(`providers-table`,s,[`providerName`,`moduleName`,`scope`],`provider`,G,{sortable:!0}),I(`jobs-table`,c,[`jobName`,`cronExpression`,`enabled`,`nextRuns`],`cron`,W),I(`queues-table`,l,[`queueName`,`consumerName`,`className`],`queue`),I(`websocket-table`,u,[`gatewayName`,`eventName`,`namespace`],`websocket`),I(`agents-table`,d,[`agentName`,`className`,`model`,`tools`],`agent`,K,{sortable:!0,runAgent:!0}),I(`ai-table`,m,[`className`,`methodName`,`provider`,`model`,`streaming`],`aifunction`,q),N(f),I(`rag-table`,f,[`pipelineName`,`vectorStore`,`embeddingProvider`,`chunkingStrategy`],`rag`,void 0,{sortable:!0}),I(`prompts-table`,p,[`promptKey`,`scope`],`prompt`,void 0,{sortable:!0,previewPrompt:!0}),I(`events-table`,h,[`eventName`,`className`,`methodName`],`event`),I(`graphql-table`,g,[`operationType`,`operationName`,`resolverName`,`className`],`graphql`),I(`grpc-table`,_,[`serviceName`,`methodName`,`className`],`grpc`),I(`kafka-table`,v,[`consumerName`,`topic`,`groupId`,`methodName`],`kafka`);let w=document.getElementById(`flow-runtime-info`);w&&w.classList.toggle(`hidden`,y.length===0),M(y),I(`flows-table`,y,[`flowId`,`version`,`sourceType`,`nodeName`,`entryNode`,`edges`,`className`],`flow`,void 0,{sortable:!0}),I(`data-table`,x,[`pipelineName`,`className`],`data`),I(`serverless-table`,S,[`controllerName`,`runtime`,`memory`,`timeout`],`serverless`),I(`ml-table`,C,[`modelName`,`version`,`className`],`ml`)}),Y().then(()=>{let e=new URLSearchParams(window.location.search).get(`tab`);e&&Z(e)});
|
package/ui-dist/index.html
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
6
|
<title>HazelJS Inspector</title>
|
|
7
|
-
<script type="module" crossorigin src="/__hazel/assets/index-
|
|
8
|
-
<link rel="stylesheet" crossorigin href="/__hazel/assets/index-
|
|
7
|
+
<script type="module" crossorigin src="/__hazel/assets/index-WT8tdMSx.js"></script>
|
|
8
|
+
<link rel="stylesheet" crossorigin href="/__hazel/assets/index-DsSZSL8P.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
11
11
|
<div id="app">
|
|
@@ -156,6 +156,13 @@
|
|
|
156
156
|
<div id="agents" class="tab-panel">
|
|
157
157
|
<h2 class="section-title">Agents</h2>
|
|
158
158
|
<div class="table-container"><table id="agents-table"></table></div>
|
|
159
|
+
<div class="agent-timeline-panel">
|
|
160
|
+
<h3 class="section-title">Execution Timeline</h3>
|
|
161
|
+
<p class="muted" style="font-size:12px;margin:0 0 8px">
|
|
162
|
+
Select an agent and click Timeline, or Run to stream live steps (Agent OS).
|
|
163
|
+
</p>
|
|
164
|
+
<div id="agent-timeline" class="agent-timeline"></div>
|
|
165
|
+
</div>
|
|
159
166
|
</div>
|
|
160
167
|
<div id="ai" class="tab-panel">
|
|
161
168
|
<h2 class="section-title">AI Functions</h2>
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var e=(()=>{let e=window.location.pathname.match(/^\/[^/]+/);return e?e[0]:`/__hazel`})(),t=window.location.origin,n=null,r=!1,i=[],a=60;async function o(t=!1){let n=`${e}/inspect${t?`?refresh=1`:``}`,r=await fetch(n);if(!r.ok)throw Error(`Failed to fetch: ${r.status}`);return r.json()}async function s(){let t=await fetch(`${e}/stats`);return t.ok?t.json():{}}async function c(){let t=await fetch(`${e}/env`);return t.ok?t.json():{}}async function l(e){try{let n=await fetch(`${t}${e}`),r=n.ok,i;return i=n.headers.get(`content-type`)?.includes(`application/json`)?await n.json():await n.text(),{status:r?`up`:`down`,ok:r,data:i}}catch{return{status:`down`,ok:!1}}}function u(e){let t=document.getElementById(`loading-overlay`);t&&t.classList.toggle(`hidden`,!e)}function d(e,t){let n=document.getElementById(`status-dot`),r=document.getElementById(`status-text`),i=document.getElementById(`status-uptime`);if(!n||!r||!i)return;let a=e?.health?.ok&&e?.ready?.ok&&e?.startup?.ok,o=e?.health?.ok||e?.ready?.ok||e?.startup?.ok;n.className=`status-dot`+(a?` healthy`:o?``:` unhealthy`),r.textContent=a?`All systems operational`:o?`Degraded`:`Offline`,i.textContent=t.uptimeSeconds==null?``:`Uptime: ${m(t.uptimeSeconds)}`}function f(e){let t=document.getElementById(`quick-stats`);if(!t)return;let n=e&&typeof e==`object`?e:{},r=[];(n.route??0)>0&&r.push(`<span class="quick-stat"><strong>${n.route}</strong> routes</span>`),(n.module??0)>0&&r.push(`<span class="quick-stat"><strong>${n.module}</strong> modules</span>`),(n.provider??0)>0&&r.push(`<span class="quick-stat"><strong>${n.provider}</strong> providers</span>`),(n.cron??0)>0&&r.push(`<span class="quick-stat"><strong>${n.cron}</strong> jobs</span>`),t.innerHTML=r.join(``)||`<span class="quick-stat muted">No data</span>`}function p(e){let t=document.getElementById(`offline-banner`);e&&!t&&(t=document.createElement(`div`),t.id=`offline-banner`,t.className=`offline-banner`,t.innerHTML=`<span>App not running. Check that your server is started.</span><button id="retry-btn">Retry</button>`,document.querySelector(`.content`)?.insertBefore(t,document.querySelector(`.toolbar`)),t.querySelector(`#retry-btn`)?.addEventListener(`click`,()=>Y(!0))),t&&t.classList.toggle(`hidden`,!e)}function m(e){return e<60?`${Math.floor(e)}s`:e<3600?`${Math.floor(e/60)}m ${e%60}s`:`${Math.floor(e/3600)}h ${Math.floor(e%3600/60)}m`}function h(e){let t=String(e||``).toUpperCase();return`<span class="badge badge-${t===`GET`?`get`:t===`POST`?`post`:t===`PUT`?`put`:t===`PATCH`?`patch`:t===`DELETE`?`delete`:`default`}">${t||`?`}</span>`}function g(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,e=>{let t=`json-number`;return/^"/.test(e)?t=e.endsWith(`:`)?`json-key`:`json-string`:/true|false/.test(e)?t=`json-boolean`:/null/.test(e)&&(t=`json-null`),`<span class="${t}">${_(e)}</span>`})}function _(e){let t=document.createElement(`div`);return t.textContent=e,t.innerHTML}var v={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>`},y=[{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 b(e){let t=document.getElementById(`summary-cards`),n=e&&typeof e==`object`?e:{};t.innerHTML=y.map(e=>`
|
|
2
|
-
<section class="overview-section">
|
|
3
|
-
<h3 class="overview-section-title">${_(e.title)}</h3>
|
|
4
|
-
<div class="overview-section-cards">
|
|
5
|
-
${(Array.isArray(e.items)?e.items:[]).map(e=>`<div class="card" data-kind="${_(e.key)}">
|
|
6
|
-
<div class="card-icon">${v[e.key]??``}</div>
|
|
7
|
-
<div class="card-label">${_(e.label)}</div>
|
|
8
|
-
<div class="card-value">${n[e.key]??0}</div>
|
|
9
|
-
</div>`).join(``)}
|
|
10
|
-
</div>
|
|
11
|
-
</section>
|
|
12
|
-
`).join(``)}var x={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 S(e){let t=document.getElementById(`env-info`);t&&(t.innerHTML=`
|
|
13
|
-
<div class="env-item"><strong>Node</strong> ${_(e.nodeVersion??`—`)}</div>
|
|
14
|
-
<div class="env-item"><strong>NODE_ENV</strong> ${_(e.nodeEnv??`—`)}</div>
|
|
15
|
-
<div class="env-item"><strong>Inspector</strong> ${_(e.inspectorVersion??`—`)}</div>
|
|
16
|
-
<div class="env-item"><strong>Platform</strong> ${_(e.platform??`—`)}</div>
|
|
17
|
-
<div class="env-item"><strong>Arch</strong> ${_(e.arch??`—`)}</div>
|
|
18
|
-
`)}function C(e){let t=document.getElementById(`overview-gateway`);if(!t)return;let n=Array.isArray(e.routes)?e.routes:[],r=e.metrics;t.innerHTML=`
|
|
19
|
-
<h3 class="overview-block-title">Gateway</h3>
|
|
20
|
-
<div class="overview-gateway-stats">
|
|
21
|
-
<div class="overview-stat"><span class="stat-value">${n.length}</span><span class="stat-label">Routes</span></div>
|
|
22
|
-
${r?`
|
|
23
|
-
<div class="overview-stat"><span class="stat-value">${r.totalCalls}</span><span class="stat-label">Total Calls</span></div>
|
|
24
|
-
<div class="overview-stat"><span class="stat-value">${r.successCalls}</span><span class="stat-label">Success</span></div>
|
|
25
|
-
<div class="overview-stat"><span class="stat-value">${(r.failureRate??0).toFixed(1)}%</span><span class="stat-label">Failure Rate</span></div>
|
|
26
|
-
<div class="overview-stat"><span class="stat-value">${(r.averageResponseTime??0).toFixed(0)}ms</span><span class="stat-label">Avg Latency</span></div>
|
|
27
|
-
`:``}
|
|
28
|
-
</div>
|
|
29
|
-
${n.length?`<div class="overview-gateway-routes"><strong>Routes:</strong> ${n.slice(0,8).map(e=>`<code>${_(e)}</code>`).join(`, `)}${n.length>8?` <span class="muted">+${n.length-8} more</span>`:``}</div>`:``}
|
|
30
|
-
`,t.classList.remove(`hidden`)}function w(e){let t=document.getElementById(`overview-discovery`);if(!t)return;let n=Array.isArray(e.services)?e.services:[],r=e.instancesByService&&typeof e.instancesByService==`object`?e.instancesByService:{},i=n.slice(0,6).map(e=>`<span class="discovery-service"><code>${_(e)}</code>: ${r[e]??0} instance(s)</span>`).join(`, `);t.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
|
-
${n.length?`<div class="overview-discovery-services">${i}${n.length>6?` <span class="muted">+${n.length-6} more</span>`:``}</div>`:`<p class="muted">No services registered</p>`}
|
|
37
|
-
`,t.classList.remove(`hidden`)}function ee(e){let t=document.getElementById(`overview-resilience`);if(!t)return;let n=Array.isArray(e.circuitBreakerStates)?e.circuitBreakerStates:[],r=n.map(e=>`<span class="cb-state ${(e.state||``).toLowerCase()}"><code>${_(e.name)}</code>: ${_(e.state)}</span>`).join(`, `);t.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
|
-
${n.length?`<div class="overview-resilience-states">${r}</div>`:``}
|
|
43
|
-
`,t.classList.remove(`hidden`)}function te(e){let t=document.getElementById(`health-cards`);t&&(t.innerHTML=[{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}].map(e=>{let t=e.data??{status:`unknown`,ok:!1};return`
|
|
44
|
-
<div class="health-card ${t.ok?`healthy`:t.status===`unknown`?`unknown`:`unhealthy`}">
|
|
45
|
-
<h3>${_(e.label)}</h3>
|
|
46
|
-
<div class="status">${t.ok?`Up`:t.status===`unknown`?`Unknown`:`Down`}</div>
|
|
47
|
-
<div class="endpoint">${_(e.endpoint)}</div>
|
|
48
|
-
</div>
|
|
49
|
-
`}).join(``))}function ne(e){let t=document.getElementById(`runtime-cards`),n=e=>(e/1024/1024).toFixed(2);e.memory&&(i.push({heap:e.memory.heapUsed,rss:e.memory.rss,t:Date.now()}),i.length>a&&i.shift()),t.innerHTML=`
|
|
50
|
-
<div class="card">
|
|
51
|
-
<div class="card-icon">${x.heap}</div>
|
|
52
|
-
<div class="card-label">Heap Used</div>
|
|
53
|
-
<div class="card-value">${e.memory?.heapUsed?n(e.memory.heapUsed)+` MB`:`—`}</div>
|
|
54
|
-
</div>
|
|
55
|
-
<div class="card">
|
|
56
|
-
<div class="card-icon">${x.rss}</div>
|
|
57
|
-
<div class="card-label">RSS Memory</div>
|
|
58
|
-
<div class="card-value">${e.memory?.rss?n(e.memory.rss)+` MB`:`—`}</div>
|
|
59
|
-
</div>
|
|
60
|
-
<div class="card">
|
|
61
|
-
<div class="card-icon">${x.uptime}</div>
|
|
62
|
-
<div class="card-label">Uptime</div>
|
|
63
|
-
<div class="card-value highlight">${e.uptimeSeconds==null?`—`:m(e.uptimeSeconds)}</div>
|
|
64
|
-
</div>
|
|
65
|
-
`,T()}function T(){let e=document.getElementById(`memory-chart-container`);if(!e||i.length<2){e?.classList.add(`hidden`);return}e.classList.remove(`hidden`);let t=Math.max(...i.map(e=>e.heap)),n=Math.max(...i.map(e=>e.rss)),r=Math.max(t,n,1),a=e=>e/1024/1024/r*100;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="${i.map((e,t)=>`${t/(i.length-1)*100},${100-a(e.heap)}`).join(` `)}"/>
|
|
68
|
-
</svg>
|
|
69
|
-
<div style="font-size:11px;color:var(--text-muted);margin-top:0.5rem">Heap over time (last ${i.length} samples)</div>
|
|
70
|
-
`}var E={},D=50;function O(e){let t=new Map;for(let n of e){let e=String(n.flowId??``);t.has(e)||t.set(e,[]),t.get(e).push(n)}let n=new Map;for(let[e,r]of t){let t=r.find(e=>!!String(e.nodes??``).trim())??r[0],i=(t.nodes??``).split(/[,]/).map(e=>e.trim()).filter(Boolean);i.length===0&&(i=r.map(e=>e.nodeName).filter(e=>!!e));let a=(t.edges??``).toString().split(/[;,]/).map(e=>e.trim()).filter(Boolean).map(e=>{let t=e.indexOf(`→`);if(t<0)return null;let n=e.slice(0,t).trim(),r=e.slice(t+1).trim();return n&&r?{from:n,to:r}:null}).filter(e=>e!=null);for(let e of r){let t=(e.edges??``).toString().split(/[;,]/);for(let e of t){let t=e.indexOf(`→`);if(t>=0){let n=e.slice(0,t).trim(),r=e.slice(t+1).trim();n&&r&&!a.some(e=>e.from===n&&e.to===r)&&a.push({from:n,to:r})}}}let o=String(t.entryNode??i[0]??``);n.set(e,{nodes:[...new Set(i)],edges:a,entryNode:o})}return n}var k=48,A=24,j=6;function M(e){let t=new Map,n=new Map,r=e.entryNode||e.nodes[0];if(!r)return t;n.set(r,0);let i=[r],a=new Set([r]);for(;i.length>0;){let t=i.shift(),r=n.get(t)??0;for(let o of e.edges)if(o.from===t)if(!a.has(o.to))a.add(o.to),n.set(o.to,r+1),i.push(o.to);else{let e=n.get(o.to)??0;r+1>e&&n.set(o.to,r+1)}}let o=Math.max(0,...Array.from(n.values()));for(let t of e.nodes)n.has(t)||n.set(t,o+1);let s=new Map;for(let[e,t]of n)s.has(t)||s.set(t,[]),s.get(t).push(e);let c=[...s.keys()].sort((e,t)=>e-t);for(let e=0;e<c.length;e++){let n=c[e],r=s.get(n)??[];for(let n=0;n<r.length;n++){let i=r[n],a=j+e*54,o=j+n*28;t.set(i,{x:a,y:o})}}return t}function re(e){let t=document.getElementById(`flow-diagram`),n=Array.isArray(e)?e:[];if(!t||!n.length){t?.classList.add(`hidden`);return}let r=O(n);if(r.size===0){t?.classList.add(`hidden`);return}let i=k,a=A,o=``;for(let[e,t]of r){let n=M(t);if(n.size===0)continue;let r=Math.max(...Array.from(n.values()).map(e=>e.x))+i+j*2,s=Math.max(...Array.from(n.values()).map(e=>e.y))+a+j*2,c=`<svg class="flow-diagram-svg" viewBox="0 0 ${Math.max(240,r)} ${Math.max(48,s)}" xmlns="http://www.w3.org/2000/svg">`;for(let{from:e,to:r}of t.edges){let t=n.get(e),o=n.get(r);if(t&&o){let e=t.x+i,n=t.y+a/2,r=o.x,s=o.y+a/2,l=(e+r)/2;c+=`<path d="M ${e} ${n} C ${l} ${n} ${l} ${s} ${r} ${s}" fill="none" stroke="var(--flow-edge)" stroke-width="1" class="flow-edge"/>`;let u=r-4*Math.cos(Math.PI/6),d=s-4*Math.sin(Math.PI/6),f=r-4*Math.cos(-Math.PI/6),p=s-4*Math.sin(-Math.PI/6);c+=`<polygon points="${r},${s} ${u},${d} ${f},${p}" fill="var(--flow-edge)" class="flow-arrow"/>`}}for(let[e,r]of n){let n=e===t.entryNode?`flow-diagram-node entry`:`flow-diagram-node`,o=e.length>10?e.slice(0,8)+`…`:e;c+=`<g class="flow-node-group"><rect class="${n}" x="${r.x}" y="${r.y}" width="${i}" height="${a}" rx="4"/><text x="${r.x+i/2}" y="${r.y+a/2+3}" text-anchor="middle" font-size="9" fill="var(--text-primary)" class="flow-node-label">${_(o)}</text></g>`}c+=`</svg>`,o+=`<div class="flow-diagram-card"><span class="flow-diagram-badge" title="${_(e)}">${_(e)}</span><div class="flow-diagram-svg-wrap">${c}</div></div>`}t.innerHTML=o,t.classList.remove(`hidden`)}function N(e){let t=document.getElementById(`rag-explorer`),n=document.getElementById(`rag-pipeline-select`),r=document.getElementById(`rag-results`);if(!t||!n||!r)return;let i=Array.isArray(e)?e:[];if(!i.length){t.classList.add(`hidden`);return}t.classList.remove(`hidden`),n.innerHTML=i.map(e=>`<option value="${_(String(e.pipelineName??``))}">${_(String(e.pipelineName??``))}</option>`).join(``),r.innerHTML=``}async function P(){let t=document.getElementById(`rag-pipeline-select`),n=document.getElementById(`rag-search-input`),r=document.getElementById(`rag-results`);if(!t||!n||!r)return;let i=t.value,a=n.value.trim();if(a){r.innerHTML=`<p>Searching...</p>`;try{let t=await fetch(`${e}/rag/${encodeURIComponent(i)}/search?q=${encodeURIComponent(a)}`),n=await t.json();if(!t.ok){r.innerHTML=`<p class="error">${_(n.error??`Search failed`)}</p>`;return}let o=n.results??[];if(!o.length){r.innerHTML=`<p>No results found.</p>`;return}r.innerHTML=o.map(e=>`<div class="rag-result-item"><span class="score">${e.score==null?`—`:(e.score*100).toFixed(1)+`%`}</span> ${_(String(e.content??``).slice(0,200))}${String(e.content??``).length>200?`...`:``}</div>`).join(``)}catch(e){r.innerHTML=`<p class="error">${_(String(e))}</p>`}}}function F(e){let t=document.getElementById(`module-graph-container`),n=Array.isArray(e)?e:[];if(!t||!n.length){t?.classList.add(`hidden`);return}let r=new Map,i=[],a=n.map(e=>String(e.moduleName??``)).filter(Boolean),o=[...new Set(a)];o.forEach((e,t)=>{let n=Math.floor(t/4),i=t%4;r.set(e,{x:80+i*120,y:40+n*60})});for(let e of n){let t=String(e.moduleName??``),n=e.imports,a=Array.isArray(n)?n:typeof n==`string`?n.split(/[,;]/).map(e=>e.trim()):[];for(let e of a){let n=String(e).trim();n&&(o.includes(n)||r.has(n))&&(i.push({from:t,to:n}),r.has(n)||r.set(n,{x:80+r.size%4*120,y:40+Math.floor(r.size/4)*60}))}}let s=`<svg class="module-graph-svg" viewBox="0 0 500 ${Math.max(200,Math.ceil(o.length/4)*70)}" xmlns="http://www.w3.org/2000/svg">`;for(let{from:e,to:t}of i){let n=r.get(e),i=r.get(t);n&&i&&(s+=`<line x1="${n.x+50}" y1="${n.y+15}" x2="${i.x+50}" y2="${i.y+15}" stroke="var(--border)" stroke-width="1"/>`)}for(let[e,t]of r)s+=`<rect x="${t.x}" y="${t.y}" width="100" height="30" rx="4" fill="var(--bg-tertiary)" stroke="var(--border)"/>`,s+=`<text x="${t.x+50}" y="${t.y+20}" text-anchor="middle" font-size="11" fill="var(--text-primary)">${_(e.length>12?e.slice(0,10)+`..`:e)}</text>`;s+=`</svg>`,t.innerHTML=s,t.classList.remove(`hidden`)}function I(e,t,n,r,i,a){let o=document.getElementById(e),s=E[e]??{col:n[0],dir:`asc`},c=[...t];a?.sortable&&c.length>0&&c.sort((e,t)=>{let n=e[s.col],r=t[s.col],i=String(n??``).localeCompare(String(r??``),void 0,{numeric:!0});return s.dir===`asc`?i:-i});let l=c.length>D?c.slice(0,D):c,u=c.length>D;if(!t.length){o.innerHTML=`<thead></thead><tbody><tr><td colspan="${n.length+(a?.tryRoute||a?.runAgent?1:0)}" class="empty-state"><p>No entries found</p></td></tr></tbody>`;return}let d=i??{},f=n.map(e=>{let t=e.replace(/([A-Z])/g,` $1`).trim();return`<th class="${a?.sortable?` sortable ${s.col===e?s.dir:``}`:``}" data-col="${e}">${t}</th>`});if(a?.tryRoute&&f.push(`<th>Actions</th>`),a?.runAgent&&f.push(`<th>Actions</th>`),a?.previewPrompt&&f.push(`<th>Actions</th>`),o.innerHTML=`
|
|
71
|
-
<thead><tr>${f.join(``)}</tr></thead>
|
|
72
|
-
<tbody>
|
|
73
|
-
${l.map(e=>{let t=``;if(a?.tryRoute&&e.fullPath!=null){let n=String(e.fullPath);t=`<td><button class="btn btn-sm try-route" data-method="${String(e.httpMethod??`GET`).toUpperCase()}" data-path="${_(n)}">Try</button></td>`}else a?.runAgent&&e.agentName!=null?t=`<td><button class="btn btn-sm run-agent" data-name="${_(String(e.agentName))}">Run</button></td>`:a?.previewPrompt&&e.promptKey!=null?t=`<td><button class="btn btn-sm preview-prompt" data-key="${_(String(e.promptKey))}">Preview</button></td>`:(a?.tryRoute||a?.runAgent||a?.previewPrompt)&&(t=`<td></td>`);return`<tr data-id="${e.id??``}" data-json='${JSON.stringify(e).replace(/'/g,`\\'`)}'>
|
|
74
|
-
${n.map(t=>{let n=e[t],r=d[t];return`<td>${r?r(n,e):String(n??`—`)}</td>`}).join(``)}
|
|
75
|
-
${t}
|
|
76
|
-
</tr>`}).join(``)}
|
|
77
|
-
</tbody>
|
|
78
|
-
`,u){let e=document.createElement(`tr`);e.innerHTML=`<td colspan="${n.length+(a?.tryRoute||a?.runAgent?1:0)}" class="empty-state"><p>Showing ${D} of ${c.length}. Use search to filter.</p></td>`,o.querySelector(`tbody`).appendChild(e)}o.querySelectorAll(`tbody tr[data-json]`).forEach(e=>{e.addEventListener(`click`,t=>{if(t.target.closest(`button`))return;let n=e.dataset.json;n&&H(JSON.parse(n))})}),o.querySelectorAll(`th.sortable`).forEach(o=>{o.addEventListener(`click`,()=>{let c=o.dataset.col;E[e]={col:c,dir:s.col===c&&s.dir===`asc`?`desc`:`asc`},I(e,t,n,r,i,a)})}),o.querySelectorAll(`.try-route`).forEach(e=>{e.addEventListener(`click`,t=>{t.stopPropagation(),L(e.dataset.method??`GET`,e.dataset.path??`/`)})}),o.querySelectorAll(`.run-agent`).forEach(e=>{e.addEventListener(`click`,t=>{t.stopPropagation(),R(e.dataset.name??``)})}),o.querySelectorAll(`.preview-prompt`).forEach(e=>{e.addEventListener(`click`,t=>{t.stopPropagation(),ie(e.dataset.key??``)})})}function L(e,n){let r=document.getElementById(`route-test-modal`),i=document.getElementById(`test-url`),a=document.getElementById(`test-method`),o=document.getElementById(`test-body-group`),s=document.getElementById(`test-result`);i.value=`${t}${n}`,a.value=e,o.classList.toggle(`hidden`,e===`GET`),s.classList.add(`hidden`),r.classList.remove(`hidden`)}async function R(t){let n=prompt(`Enter input for agent (or leave empty for empty string):`)??``;try{let r=await fetch(`${e}/agents/${encodeURIComponent(t)}/run`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({input:n})}),i=await r.json();if(!r.ok){H({error:i.error??`Agent run failed`,status:r.status});return}H({agentName:t,result:i.result})}catch(e){H({error:String(e),agentName:t})}}function z(e){let t=document.getElementById(`prompt-playground-modal`),n=document.getElementById(`playground-key`),r=document.getElementById(`playground-vars`),i=document.getElementById(`playground-output`),a=document.getElementById(`playground-tokens`);n.value=e,r.value=`{}`,i.textContent=``,a.textContent=`—`,t.classList.remove(`hidden`)}async function B(t,n){let r=await fetch(`${e}/prompts/render`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({key:t,variables:n})});if(!r.ok){let e=await r.json().catch(()=>({error:r.statusText}));throw Error(e.error??`Failed to render`)}return r.json()}function ie(e){z(e)}var V=null;function H(e){V=e;let t=document.getElementById(`detail-panel`),n=document.getElementById(`detail-title`),r=document.getElementById(`detail-content`);n.textContent=String(e.kind??`Entry`),r.innerHTML=g(e),t.classList.remove(`hidden`)}function ae(){V=null,document.getElementById(`detail-panel`).classList.add(`hidden`)}function oe(){if(!V)return;let e=JSON.stringify(V,null,2);navigator.clipboard.writeText(e).then(()=>{let e=document.getElementById(`detail-copy`);if(e){let t=e.textContent;e.textContent=`Copied!`,setTimeout(()=>{e.textContent=t},1500)}})}function se(e,t){let n=Array.isArray(e)?e:[];if(!t.trim())return n;let r=t.toLowerCase();return n.filter(e=>JSON.stringify(e).toLowerCase().includes(r))}var U={httpMethod:e=>h(String(e??``))},W={enabled:e=>`<span class="badge ${e?`badge-get`:`badge-default`}">${e?`Enabled`:`Disabled`}</span>`,nextRuns:(e,t)=>{let n=Array.isArray(e)?e:[];return n.length?n.slice(0,3).map(e=>{try{return new Date(e).toLocaleString(void 0,{month:`short`,day:`numeric`,hour:`2-digit`,minute:`2-digit`})}catch{return e}}).join(`, `)+(n.length>3?`...`:``):`—`}},G={moduleName:e=>String(e??`—`),scope:e=>{let t=String(e??`singleton`);return`<span class="badge ${t===`singleton`?`badge-get`:t===`request`?`badge-post`:`badge-default`}">${t}</span>`}},K={tools:e=>Array.isArray(e)?e.join(`, `):String(e??`—`)},q={streaming:e=>`<span class="badge ${e?`badge-get`:`badge-default`}">${e?`Yes`:`No`}</span>`};function J(e,t){try{t()}catch(t){console.error(`[Inspector] ${e} failed:`,t)}}async function Y(e=!1){if(!r){r=!0,u(!0),p(!1);try{let t=await o(e),r=Array.isArray(t?.entries)?t.entries:[],i=t?.summary&&typeof t.summary==`object`?t.summary:{},a=t?.overview&&typeof t.overview==`object`?t.overview:{};n={entries:r,summary:i,overview:a},J(`overview`,()=>b(i)),a.gateway&&J(`gatewayOverview`,()=>C(a.gateway)),a.discovery&&J(`discoveryOverview`,()=>w(a.discovery)),a.resilience&&J(`resilienceOverview`,()=>ee(a.resilience)),[`overview-gateway`,`overview-discovery`,`overview-resilience`].forEach(e=>{let t=document.getElementById(e);t&&!a[e.replace(`overview-`,``)]&&t.classList.add(`hidden`)});let[u,p,m]=await Promise.all([c(),Promise.all([l(`/health`),l(`/ready`),l(`/startup`)]).then(([e,t,n])=>({health:e,ready:t,startup:n})),s()]);S(u),te(p),ne(m),d(p,m),f(i);let h=n.entries.filter(e=>e.kind===`route`),g=n.entries.filter(e=>e.kind===`module`),_=n.entries.filter(e=>e.kind===`provider`),v=n.entries.filter(e=>e.kind===`cron`),y=n.entries.filter(e=>e.kind===`queue`),x=n.entries.filter(e=>e.kind===`websocket`),T=n.entries.filter(e=>e.kind===`agent`),E=n.entries.filter(e=>e.kind===`rag`),D=n.entries.filter(e=>e.kind===`prompt`),O=n.entries.filter(e=>e.kind===`aifunction`),k=n.entries.filter(e=>e.kind===`event`),A=n.entries.filter(e=>e.kind===`graphql`),j=n.entries.filter(e=>e.kind===`grpc`),M=n.entries.filter(e=>e.kind===`kafka`),P=n.entries.filter(e=>e.kind===`flow`),L=n.entries.filter(e=>e.kind===`data`),R=n.entries.filter(e=>e.kind===`serverless`),z=n.entries.filter(e=>e.kind===`ml`);I(`routes-table`,h,[`httpMethod`,`fullPath`,`controllerPath`,`className`],`route`,U,{sortable:!0,tryRoute:!0}),J(`moduleGraph`,()=>F(g)),I(X.modules,g,[`moduleName`,`dynamicModule`,`imports`],`module`,void 0,{sortable:!0}),I(X.providers,_,[`providerName`,`moduleName`,`scope`],`provider`,G,{sortable:!0}),I(X.jobs,v,[`jobName`,`cronExpression`,`enabled`,`nextRuns`],`cron`,W),I(X.queues,y,[`queueName`,`consumerName`,`className`],`queue`),I(X.websocket,x,[`gatewayName`,`eventName`,`namespace`],`websocket`),I(X.agents,T,[`agentName`,`className`,`model`,`tools`],`agent`,K,{sortable:!0,runAgent:!0}),I(X.ai,O,[`className`,`methodName`,`provider`,`model`,`streaming`],`aifunction`,q),J(`ragExplorer`,()=>N(E)),I(X.rag,E,[`pipelineName`,`vectorStore`,`embeddingProvider`,`chunkingStrategy`],`rag`,void 0,{sortable:!0}),I(X.prompts,D,[`promptKey`,`scope`],`prompt`,void 0,{sortable:!0,previewPrompt:!0}),I(X.events,k,[`eventName`,`className`,`methodName`],`event`),I(X.graphql,A,[`operationType`,`operationName`,`resolverName`,`className`],`graphql`),I(X.grpc,j,[`serviceName`,`methodName`,`className`],`grpc`),I(X.kafka,M,[`consumerName`,`topic`,`groupId`,`methodName`],`kafka`);let B=document.getElementById(`flow-runtime-info`);B&&B.classList.toggle(`hidden`,P.length===0),J(`flowDiagram`,()=>re(P)),I(X.flows,P,[`flowId`,`version`,`sourceType`,`nodeName`,`entryNode`,`edges`,`className`],`flow`),I(X.data,L,[`pipelineName`,`className`],`data`),I(X.serverless,R,[`controllerName`,`runtime`,`memory`,`timeout`],`serverless`),I(X.ml,z,[`modelName`,`version`,`className`],`ml`)}catch(e){let t=String(e),n=t.includes(`Failed to fetch`)||t.includes(`NetworkError`)||t.includes(`Load failed`);p(n),d({health:{ok:!1},ready:{ok:!1},startup:{ok:!1}},{}),f({});let r=document.getElementById(`summary-cards`);if(r){let t=n?`Is the app running?`:`A rendering error occurred. Check the console for details.`;r.innerHTML=`<div class="overview-error"><p>Error: ${_(String(e))}</p><p>${_(t)} <button class="btn btn-sm btn-primary" id="retry-load">Retry</button></p></div>`,document.getElementById(`retry-load`)?.addEventListener(`click`,()=>Y(!0))}}finally{r=!1,u(!1)}}}var X={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`},ce={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 Z(e){let t=document.querySelector(`.sidebar nav a[data-tab="${e}"]`);if(t){document.querySelectorAll(`.sidebar nav a`).forEach(e=>e.classList.remove(`active`)),document.querySelectorAll(`.tab-panel`).forEach(e=>e.classList.remove(`active`)),t.classList.add(`active`),document.getElementById(e)?.classList.add(`active`);let n=new URLSearchParams(window.location.search);n.set(`tab`,e),window.history.replaceState({},``,`${window.location.pathname}?${n}`)}}document.querySelectorAll(`.sidebar nav a`).forEach(e=>{e.addEventListener(`click`,t=>{t.preventDefault();let n=e.dataset.tab;Z(n)})}),document.getElementById(`summary-cards`)?.addEventListener(`click`,e=>{let t=e.target.closest(`.card[data-kind]`);if(t){let e=t.dataset.kind,n=e?ce[e]:null;n&&Z(n)}});function Q(){Y(!0)}document.getElementById(`refresh`)?.addEventListener(`click`,Q),document.getElementById(`refresh-sidebar`)?.addEventListener(`click`,Q),document.getElementById(`detail-close`).addEventListener(`click`,ae),document.getElementById(`detail-copy`)?.addEventListener(`click`,oe),document.getElementById(`export-btn`)?.addEventListener(`click`,()=>{if(!n)return;let e=new Blob([JSON.stringify(n,null,2)],{type:`application/json`}),t=document.createElement(`a`);t.href=URL.createObjectURL(e),t.download=`inspector-snapshot-${new Date().toISOString().slice(0,19).replace(/[T:]/g,`-`)}.json`,t.click(),URL.revokeObjectURL(t.href)});var le=document.getElementById(`auto-refresh`),$=null;le?.addEventListener(`change`,()=>{$&&clearInterval($),$=null,le?.checked&&($=setInterval(()=>Y(!1),15e3))}),document.getElementById(`test-route-btn`)?.addEventListener(`click`,async()=>{let e=document.getElementById(`test-url`).value,t=document.getElementById(`test-method`).value,n=document.getElementById(`test-body`),r=document.getElementById(`test-result`);r.classList.remove(`hidden`),r.className=`test-result`,r.textContent=`Sending...`;try{let i={method:t};if(t!==`GET`&&n?.value)try{JSON.parse(n.value),i.body=n.value,i.headers={"Content-Type":`application/json`}}catch{r.className=`test-result error`,r.textContent=`Invalid JSON body`;return}let a=await fetch(e,i),o=await a.text();r.className=`test-result ${a.ok?`success`:`error`}`,r.textContent=`Status: ${a.status}\n\n${o.slice(0,500)}${o.length>500?`...`:``}`}catch(e){r.className=`test-result error`,r.textContent=String(e)}}),document.getElementById(`test-route-cancel`)?.addEventListener(`click`,()=>{document.getElementById(`route-test-modal`).classList.add(`hidden`)}),document.getElementById(`test-method`)?.addEventListener(`change`,e=>{let t=e.target.value;document.getElementById(`test-body-group`).classList.toggle(`hidden`,t===`GET`)}),document.getElementById(`playground-render`)?.addEventListener(`click`,async()=>{let e=document.getElementById(`playground-key`).value,t=document.getElementById(`playground-vars`).value,n=document.getElementById(`playground-output`),r=document.getElementById(`playground-tokens`),i={};try{i=t.trim()?JSON.parse(t):{}}catch{n.textContent=`Invalid JSON in variables`,r.textContent=`—`;return}try{let{rendered:t,tokenEstimate:a}=await B(e,i);n.textContent=t,r.textContent=String(a)}catch(e){n.textContent=String(e),r.textContent=`—`}}),document.getElementById(`playground-close`)?.addEventListener(`click`,()=>{document.getElementById(`prompt-playground-modal`).classList.add(`hidden`)}),document.getElementById(`diff-btn`)?.addEventListener(`click`,()=>{document.getElementById(`diff-modal`).classList.remove(`hidden`)}),document.getElementById(`diff-close`)?.addEventListener(`click`,()=>{document.getElementById(`diff-modal`).classList.add(`hidden`)}),document.getElementById(`diff-load-file`)?.addEventListener(`click`,()=>{document.getElementById(`diff-file`).click()}),document.getElementById(`diff-file`)?.addEventListener(`change`,e=>{let t=e.target.files?.[0];if(!t)return;let n=new FileReader;n.onload=()=>{document.getElementById(`diff-snapshot-b`).value=String(n.result)},n.readAsText(t)}),document.getElementById(`rag-search-btn`)?.addEventListener(`click`,P),document.getElementById(`diff-compare-btn`)?.addEventListener(`click`,()=>{let e=document.getElementById(`diff-snapshot-b`).value.trim(),t=document.getElementById(`diff-result`);if(!n){t.innerHTML=`<p class="error">No current snapshot. Refresh first.</p>`,t.classList.remove(`hidden`);return}let r;try{r=e?JSON.parse(e):{entries:[],summary:{}}}catch{t.innerHTML=`<p class="error">Invalid JSON in Snapshot B.</p>`,t.classList.remove(`hidden`);return}let i=n.entries??[],a=r.entries??[],o=new Set(i.map(e=>e.id)),s=new Set(a.map(e=>e.id)),c=a.filter(e=>!o.has(e.id)),l=i.filter(e=>!s.has(e.id)),u=i.filter(e=>{let t=a.find(t=>t.id===e.id);return t&&JSON.stringify(e)!==JSON.stringify(t)}),d=``;c.length&&(d+=`<p class="added">+ ${c.length} added</p><ul>${c.map(e=>`<li>${_(String(e.kind))}: ${_(String(e.id??``))}</li>`).join(``)}</ul>`),l.length&&(d+=`<p class="removed">− ${l.length} removed</p><ul>${l.map(e=>`<li>${_(String(e.kind))}: ${_(String(e.id??``))}</li>`).join(``)}</ul>`),u.length&&(d+=`<p class="changed">~ ${u.length} changed</p><ul>${u.map(e=>`<li>${_(String(e.kind))}: ${_(String(e.id??``))}</li>`).join(``)}</ul>`),d||=`<p>No differences.</p>`,t.innerHTML=d,t.classList.remove(`hidden`)}),document.getElementById(`search`).addEventListener(`input`,e=>{let t=e.target.value;if(!n)return;let r=se(n.entries,t),i=n.summary&&typeof n.summary==`object`?n.summary:{};b(Object.fromEntries(Object.entries(i).map(([e])=>[e,r.filter(t=>t.kind===e).length])));let a=r.filter(e=>e.kind===`route`),o=r.filter(e=>e.kind===`module`),s=r.filter(e=>e.kind===`provider`),c=r.filter(e=>e.kind===`cron`),l=r.filter(e=>e.kind===`queue`),u=r.filter(e=>e.kind===`websocket`),d=r.filter(e=>e.kind===`agent`),f=r.filter(e=>e.kind===`rag`),p=r.filter(e=>e.kind===`prompt`),m=r.filter(e=>e.kind===`aifunction`),h=r.filter(e=>e.kind===`event`),g=r.filter(e=>e.kind===`graphql`),_=r.filter(e=>e.kind===`grpc`),v=r.filter(e=>e.kind===`kafka`),y=r.filter(e=>e.kind===`flow`),x=r.filter(e=>e.kind===`data`),S=r.filter(e=>e.kind===`serverless`),C=r.filter(e=>e.kind===`ml`);I(`routes-table`,a,[`httpMethod`,`fullPath`,`controllerPath`,`className`],`route`,U,{sortable:!0,tryRoute:!0}),F(o),I(`modules-table`,o,[`moduleName`,`dynamicModule`,`imports`],`module`,void 0,{sortable:!0}),I(`providers-table`,s,[`providerName`,`moduleName`,`scope`],`provider`,G,{sortable:!0}),I(`jobs-table`,c,[`jobName`,`cronExpression`,`enabled`,`nextRuns`],`cron`,W),I(`queues-table`,l,[`queueName`,`consumerName`,`className`],`queue`),I(`websocket-table`,u,[`gatewayName`,`eventName`,`namespace`],`websocket`),I(`agents-table`,d,[`agentName`,`className`,`model`,`tools`],`agent`,K,{sortable:!0,runAgent:!0}),I(`ai-table`,m,[`className`,`methodName`,`provider`,`model`,`streaming`],`aifunction`,q),N(f),I(`rag-table`,f,[`pipelineName`,`vectorStore`,`embeddingProvider`,`chunkingStrategy`],`rag`,void 0,{sortable:!0}),I(`prompts-table`,p,[`promptKey`,`scope`],`prompt`,void 0,{sortable:!0,previewPrompt:!0}),I(`events-table`,h,[`eventName`,`className`,`methodName`],`event`),I(`graphql-table`,g,[`operationType`,`operationName`,`resolverName`,`className`],`graphql`),I(`grpc-table`,_,[`serviceName`,`methodName`,`className`],`grpc`),I(`kafka-table`,v,[`consumerName`,`topic`,`groupId`,`methodName`],`kafka`);let w=document.getElementById(`flow-runtime-info`);w&&w.classList.toggle(`hidden`,y.length===0),re(y),I(`flows-table`,y,[`flowId`,`version`,`sourceType`,`nodeName`,`entryNode`,`edges`,`className`],`flow`,void 0,{sortable:!0}),I(`data-table`,x,[`pipelineName`,`className`],`data`),I(`serverless-table`,S,[`controllerName`,`runtime`,`memory`,`timeout`],`serverless`),I(`ml-table`,C,[`modelName`,`version`,`className`],`ml`)}),Y().then(()=>{let e=new URLSearchParams(window.location.search).get(`tab`);e&&Z(e)});
|