@forinda/kickjs-devtools 5.0.1 → 5.1.0
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/dist/index.mjs +22 -6
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/public/spa/assets/index.js +1 -1
- package/public/spa/assets/style.css +1 -1
- package/public/spa/index.html +25 -1
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @forinda/kickjs-devtools v5.0
|
|
2
|
+
* @forinda/kickjs-devtools v5.1.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Felix Orinda
|
|
5
5
|
*
|
|
@@ -90,14 +90,30 @@ function collectTokens(container) {
|
|
|
90
90
|
}));
|
|
91
91
|
}
|
|
92
92
|
/**
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
* contributors
|
|
97
|
-
*
|
|
93
|
+
* Contributor enumeration. Prefers `app.getContributors()` (the
|
|
94
|
+
* Application-level walk that preserves adapter / plugin / global
|
|
95
|
+
* source labels) when present; falls back to walking
|
|
96
|
+
* `adapter.contributors()` + `plugin.contributors()` directly for
|
|
97
|
+
* older Application implementations that don't expose the helper.
|
|
98
|
+
*
|
|
99
|
+
* Module-level contributors are still not surfaced here — module
|
|
100
|
+
* instances aren't retained post-bootstrap. Per-route enumeration
|
|
101
|
+
* lands in a later iteration alongside the route detail panel.
|
|
98
102
|
*/
|
|
99
103
|
function collectContributors(app) {
|
|
100
104
|
const seen = /* @__PURE__ */ new Map();
|
|
105
|
+
if (typeof app.getContributors === "function") {
|
|
106
|
+
for (const c of app.getContributors()) {
|
|
107
|
+
if (seen.has(c.key)) continue;
|
|
108
|
+
const mapped = c.source === "module" ? "module" : "adapter";
|
|
109
|
+
seen.set(c.key, {
|
|
110
|
+
key: c.key,
|
|
111
|
+
source: mapped,
|
|
112
|
+
dependsOn: c.dependsOn
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
return [...seen.values()];
|
|
116
|
+
}
|
|
101
117
|
const ingest = (list, source) => {
|
|
102
118
|
if (!list) return;
|
|
103
119
|
for (const reg of list) {
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["serveStatic"],"sources":["../src/topology.ts","../src/devtools-tabs.ts","../src/adapter.ts"],"sourcesContent":["/**\n * Topology aggregator — walks the running KickJS application + DI\n * container and produces a JSON-serialisable {@link TopologySnapshot}.\n *\n * Calls `introspect()` on every plugin and adapter that implements it\n * (architecture.md §23.3); falls back to a minimal `{ protocolVersion,\n * name, kind }` stub for primitives that don't. Per-primitive\n * introspection failures are caught + collected into the snapshot's\n * `errors` field rather than failing the entire endpoint.\n *\n * @module @forinda/kickjs-devtools/topology\n */\n\nimport type { AppAdapter, Container, KickPlugin } from '@forinda/kickjs'\nimport {\n PROTOCOL_VERSION,\n type IntrospectionSnapshot,\n type TopologyContributorEntry,\n type TopologyError,\n type TopologySnapshot,\n type TopologyTokenEntry,\n} from '@forinda/kickjs-devtools-kit'\n\n/** Minimal Application surface the aggregator needs — keeps coupling thin. */\nexport interface TopologyApplicationLike {\n getAdapters(): AppAdapter[]\n getPlugins(): readonly KickPlugin[]\n}\n\n/** Inputs to {@link collectTopologySnapshot}. */\nexport interface CollectTopologyOptions {\n /** The running KickJS application (or anything that exposes its surface). */\n app: TopologyApplicationLike\n /** The DI container — used to enumerate registered tokens. */\n container: Container\n /**\n * Optional per-call introspect timeout in milliseconds. An adapter\n * whose `introspect()` doesn't settle within the budget gets a stub\n * snapshot + an entry in `errors`. Default: 100ms — keeps the\n * topology endpoint snappy even if one adapter misbehaves.\n */\n introspectTimeoutMs?: number\n}\n\nconst DEFAULT_INTROSPECT_TIMEOUT_MS = 100\n\n/**\n * Collect a {@link TopologySnapshot} for the given application.\n *\n * Async because plugin/adapter `introspect()` may be async; the work\n * is parallelised across all primitives so wall-clock time scales\n * with the slowest introspector, not their sum.\n */\nexport async function collectTopologySnapshot(\n opts: CollectTopologyOptions,\n): Promise<TopologySnapshot> {\n const { app, container, introspectTimeoutMs = DEFAULT_INTROSPECT_TIMEOUT_MS } = opts\n const errors: TopologyError[] = []\n\n const plugins = await Promise.all(\n app.getPlugins().map((p) => snapshotFor(p, 'plugin', introspectTimeoutMs, errors)),\n )\n const adapters = await Promise.all(\n app.getAdapters().map((a) => snapshotFor(a, 'adapter', introspectTimeoutMs, errors)),\n )\n\n return {\n protocolVersion: PROTOCOL_VERSION,\n timestamp: Date.now(),\n plugins,\n adapters,\n contributors: collectContributors(app),\n diTokens: collectTokens(container),\n errors,\n }\n}\n\n/**\n * Coerce one primitive into an {@link IntrospectionSnapshot}. Tries\n * the primitive's own `introspect()` first; falls back to a stub on\n * any of: missing implementation, throw, timeout, or non-object return.\n */\nasync function snapshotFor(\n primitive: AppAdapter | KickPlugin,\n kind: 'plugin' | 'adapter',\n timeoutMs: number,\n errors: TopologyError[],\n): Promise<IntrospectionSnapshot> {\n const name = primitive.name ?? '(unnamed)'\n const stub: IntrospectionSnapshot = {\n protocolVersion: PROTOCOL_VERSION,\n name,\n kind,\n }\n if (typeof primitive.introspect !== 'function') return stub\n\n try {\n const result = await Promise.race([\n Promise.resolve(primitive.introspect()),\n new Promise<never>((_, reject) =>\n setTimeout(\n () => reject(new Error(`introspect() timed out after ${timeoutMs}ms`)),\n timeoutMs,\n ),\n ),\n ])\n if (result && typeof result === 'object') {\n // Accept whatever the primitive returned; the kit's\n // IntrospectionSnapshot is opt-in typed via the kit, not enforced\n // at this layer (see plugin.ts / adapter.ts comment about avoiding\n // a runtime dep on the kit).\n const snap = result as Partial<IntrospectionSnapshot>\n return {\n protocolVersion: PROTOCOL_VERSION,\n name: snap.name ?? name,\n kind: snap.kind ?? kind,\n version: snap.version,\n state: snap.state,\n tokens: snap.tokens,\n metrics: snap.metrics,\n memoryBytes: snap.memoryBytes,\n }\n }\n return stub\n } catch (err) {\n errors.push({\n name,\n kind,\n message: err instanceof Error ? err.message : String(err),\n })\n return stub\n }\n}\n\n/** Read DI registrations into the topology shape — drops noisy HMR tokens. */\nfunction collectTokens(container: Container): TopologyTokenEntry[] {\n return container\n .getRegistrations()\n .filter((r) => !r.token.startsWith('__hmr__'))\n .map((r) => ({\n token: r.token,\n scope: r.scope,\n kind: r.kind,\n instantiated: r.instantiated,\n }))\n}\n\n/**\n * Best-effort contributor enumeration. Plugins + adapters can both\n * return contributor registrations via `contributors()` — we walk both\n * lists, normalise the entries, and dedupe by `key`. Module-level\n * contributors (the most common case) are not enumerable from this\n * surface; the panel will surface them per-route in a later iteration.\n */\nfunction collectContributors(app: TopologyApplicationLike): TopologyContributorEntry[] {\n const seen = new Map<string, TopologyContributorEntry>()\n\n const ingest = (\n list: ReadonlyArray<unknown> | null | undefined,\n source: TopologyContributorEntry['source'],\n ): void => {\n if (!list) return\n for (const reg of list) {\n const r = reg as { key?: string; dependsOn?: readonly string[] }\n const key = typeof r.key === 'string' ? r.key : null\n if (!key || seen.has(key)) continue\n seen.set(key, {\n key,\n source,\n dependsOn: Array.isArray(r.dependsOn) ? r.dependsOn : [],\n })\n }\n }\n\n for (const plugin of app.getPlugins()) {\n ingest(plugin.contributors?.(), 'adapter')\n }\n for (const adapter of app.getAdapters()) {\n ingest(adapter.contributors?.(), 'adapter')\n }\n\n return [...seen.values()]\n}\n","/**\n * Custom-tab aggregator — collects every plugin/adapter's\n * `devtoolsTabs()` contribution into a single deduped list for the\n * panel's `/_debug/tabs` endpoint.\n *\n * Validation is permissive: anything that doesn't look like a\n * {@link DevtoolsTabDescriptor} is dropped with a console warning\n * rather than throwing — a misconfigured adapter shouldn't break the\n * whole DevTools panel.\n *\n * @module @forinda/kickjs-devtools/devtools-tabs\n */\n\nimport type { DevtoolsTabDescriptor } from '@forinda/kickjs-devtools-kit'\nimport type { TopologyApplicationLike } from './topology'\n\n/** Result of {@link collectDevtoolsTabs}. */\nexport interface DevtoolsTabsResult {\n /** Deduped, validated tabs in registration order. */\n tabs: DevtoolsTabDescriptor[]\n /** Per-source collection errors (drop reason, source name). */\n errors: ReadonlyArray<{ source: string; reason: string }>\n}\n\nconst VALID_VIEW_TYPES = new Set(['iframe', 'launch', 'html'])\n\n/**\n * Walk every plugin + adapter, call `devtoolsTabs?()`, validate each\n * entry, and dedupe by `id`. Last-source-wins on collision is too\n * surprising — first-source-wins + a warning entry instead.\n */\nexport function collectDevtoolsTabs(app: TopologyApplicationLike): DevtoolsTabsResult {\n const tabs: DevtoolsTabDescriptor[] = []\n const seen = new Map<string, string>() // id → source name (for collision warnings)\n const errors: Array<{ source: string; reason: string }> = []\n\n const ingest = (sourceName: string, raw: unknown): void => {\n if (!Array.isArray(raw)) {\n errors.push({ source: sourceName, reason: 'devtoolsTabs() did not return an array' })\n return\n }\n for (const entry of raw) {\n const validation = validateTab(entry)\n if (!validation.ok) {\n errors.push({ source: sourceName, reason: validation.reason })\n continue\n }\n const tab = validation.tab\n const owner = seen.get(tab.id)\n if (owner) {\n errors.push({\n source: sourceName,\n reason: `tab id '${tab.id}' already registered by ${owner} — first-source wins`,\n })\n continue\n }\n seen.set(tab.id, sourceName)\n tabs.push(tab)\n }\n }\n\n for (const plugin of app.getPlugins()) {\n if (typeof plugin.devtoolsTabs !== 'function') continue\n try {\n ingest(plugin.name ?? '(unnamed plugin)', plugin.devtoolsTabs())\n } catch (err) {\n errors.push({\n source: plugin.name ?? '(unnamed plugin)',\n reason: err instanceof Error ? err.message : String(err),\n })\n }\n }\n for (const adapter of app.getAdapters()) {\n if (typeof adapter.devtoolsTabs !== 'function') continue\n try {\n ingest(adapter.name ?? '(unnamed adapter)', adapter.devtoolsTabs())\n } catch (err) {\n errors.push({\n source: adapter.name ?? '(unnamed adapter)',\n reason: err instanceof Error ? err.message : String(err),\n })\n }\n }\n\n return { tabs, errors }\n}\n\ninterface ValidationOk {\n ok: true\n tab: DevtoolsTabDescriptor\n}\n\ninterface ValidationFail {\n ok: false\n reason: string\n}\n\n/**\n * Coerce + validate a tab descriptor. Returns the typed object on\n * success; a structured reason on failure. Uses a permissive checker\n * so a partially-correct entry from a third-party adapter doesn't\n * break the whole panel.\n */\nfunction validateTab(raw: unknown): ValidationOk | ValidationFail {\n if (!raw || typeof raw !== 'object') {\n return { ok: false, reason: 'tab entry is not an object' }\n }\n const obj = raw as Record<string, unknown>\n if (typeof obj.id !== 'string' || obj.id.length === 0) {\n return { ok: false, reason: 'tab.id must be a non-empty string' }\n }\n if (typeof obj.title !== 'string' || obj.title.length === 0) {\n return { ok: false, reason: `tab '${obj.id}': title must be a non-empty string` }\n }\n const view = obj.view as Record<string, unknown> | undefined\n if (!view || typeof view !== 'object') {\n return { ok: false, reason: `tab '${obj.id}': view object is required` }\n }\n if (typeof view.type !== 'string' || !VALID_VIEW_TYPES.has(view.type)) {\n return {\n ok: false,\n reason: `tab '${obj.id}': view.type must be one of iframe / launch / html`,\n }\n }\n switch (view.type) {\n case 'iframe':\n if (typeof view.src !== 'string' || view.src.length === 0) {\n return { ok: false, reason: `tab '${obj.id}': iframe view requires a non-empty src` }\n }\n break\n case 'html':\n if (typeof view.html !== 'string') {\n return { ok: false, reason: `tab '${obj.id}': html view requires html string` }\n }\n break\n case 'launch':\n if (!Array.isArray(view.actions)) {\n return { ok: false, reason: `tab '${obj.id}': launch view requires actions array` }\n }\n break\n }\n return { ok: true, tab: obj as unknown as DevtoolsTabDescriptor }\n}\n","import type { Request, Response, NextFunction } from 'express'\nimport { Router, static as serveStatic } from 'express'\nimport { dirname, join } from 'node:path'\nimport { tmpdir } from 'node:os'\nimport { fileURLToPath } from 'node:url'\nimport { createReadStream, existsSync, readFileSync, statSync, unlink } from 'node:fs'\nimport { randomBytes } from 'node:crypto'\nimport { writeHeapSnapshot } from 'node:v8'\nimport {\n type AdapterMiddleware,\n type Container,\n METADATA,\n defineAdapter,\n ref,\n computed,\n reactive,\n watch,\n createLogger,\n type Ref,\n type ComputedRef,\n getClassMeta,\n getMethodMeta,\n} from '@forinda/kickjs'\nimport {\n MemoryAnalyzer,\n PROTOCOL_VERSION,\n RuntimeSampler,\n type IntrospectionSnapshot,\n} from '@forinda/kickjs-devtools-kit'\nimport { collectTopologySnapshot, type TopologyApplicationLike } from './topology'\nimport { collectDevtoolsTabs } from './devtools-tabs'\n\nconst log = createLogger('DevTools')\n\n/** Route metadata collected during mount */\ninterface RouteInfo {\n method: string\n path: string\n controller: string\n handler: string\n middleware: string[]\n}\n\n/** Per-route latency stats with percentile tracking */\ninterface RouteStats {\n count: number\n totalMs: number\n minMs: number\n maxMs: number\n /** Ring buffer of last N samples for percentile computation */\n samples: number[]\n}\n\nconst MAX_SAMPLES = 1000\n\n/** Compute a percentile from a sorted array of numbers */\nfunction percentile(sorted: number[], p: number): number {\n if (sorted.length === 0) return 0\n const idx = Math.ceil(p * sorted.length) - 1\n return sorted[Math.max(0, idx)]\n}\n\n/** Compute p50, p95, p99 from a RouteStats samples buffer */\nfunction computePercentiles(stats: RouteStats): { p50: number; p95: number; p99: number } {\n const sorted = [...stats.samples].sort((a, b) => a - b)\n return {\n p50: percentile(sorted, 0.5),\n p95: percentile(sorted, 0.95),\n p99: percentile(sorted, 0.99),\n }\n}\n\n/**\n * Open an SSE response — sets the headers, flushes them, and disables\n * any compression middleware that may have been registered upstream\n * (compression buffers SSE chunks indefinitely; we need flush-on-write).\n */\nfunction openSseStream(req: Request, res: Response): void {\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache, no-transform',\n Connection: 'keep-alive',\n 'X-Accel-Buffering': 'no',\n })\n res.flushHeaders?.()\n // Defensive: the compression middleware checks this header. Some\n // setups also wrap res.write — calling res.flush after each write\n // is safe even when no compression is in play.\n void req\n}\n\n/** Write a single SSE `data:` event with a JSON payload + double newline. */\nfunction writeSseEvent(res: Response, payload: unknown): void {\n res.write(`data: ${JSON.stringify(payload)}\\n\\n`)\n}\n\n/**\n * Module-scoped guard for `POST /_debug/memory/snapshot`. `writeHeapSnapshot()`\n * blocks the event loop for the duration of the capture (multi-second\n * for large heaps); two concurrent captures would compound the pause.\n * The endpoint returns 503 + a hint message when this flag is set so\n * the SPA can surface a \"snapshot already running\" warning rather than\n * silently queueing.\n *\n * Module-scoped (not per-adapter-instance) because writeHeapSnapshot\n * acts on the V8 process — multiple DevToolsAdapter instances would\n * still race at the v8 layer.\n */\nlet snapshotInProgress = false\n\nexport interface DevToolsOptions {\n /** Base path for debug endpoints (default: '/_debug') */\n basePath?: string\n /** Only enable when this is true (default: process.env.NODE_ENV !== 'production') */\n enabled?: boolean\n /** Include environment variables (sanitized) at /_debug/config (default: false) */\n exposeConfig?: boolean\n /** Env var prefixes to expose (default: ['APP_', 'NODE_ENV']). Others are redacted. */\n configPrefixes?: string[]\n /** Callback when error rate exceeds threshold */\n onErrorRateExceeded?: (rate: number) => void\n /** Error rate threshold (default: 0.5 = 50%) */\n errorRateThreshold?: number\n /** Other adapters to discover stats from (e.g., WsAdapter) */\n adapters?: any[]\n\n /**\n * Secret token to guard DevTools access. When set, all requests must\n * include this token as `x-devtools-token` header or `?token=` query param.\n *\n * Auto-generated on startup if not provided. The token is logged to the console.\n * Set to `false` to disable the guard entirely (not recommended).\n *\n * @example\n * ```ts\n * DevToolsAdapter({ secret: getEnv('DEVTOOLS_SECRET') })\n * ```\n */\n secret?: string | false\n\n /**\n * Tuning for the runtime sampler that powers `/_debug/runtime` and\n * the upcoming Memory tab (architecture.md §23). Defaults to\n * 1-second polling with a 60-sample (~1 minute) ring buffer.\n *\n * Set `runtime.enabled = false` to skip starting the sampler — the\n * `/_debug/runtime` endpoint then returns 404 instead of an empty\n * snapshot, signalling deliberate opt-out rather than a startup race.\n */\n runtime?: {\n /** Whether to start the runtime sampler at all. Default: true. */\n enabled?: boolean\n /** Polling interval in milliseconds. Default: 1000. */\n intervalMs?: number\n /** Ring-buffer size — number of past samples retained. Default: 60. */\n bufferSize?: number\n }\n}\n\n/**\n * Public reactive surface exposed by a DevToolsAdapter instance —\n * counters, computed metrics, and the route latency map. Tests and\n * peer adapters consume these directly to drive their own behavior.\n */\nexport interface DevToolsAdapterExtensions {\n /** Total requests received. */\n readonly requestCount: Ref<number>\n /** Total responses with status >= 500. */\n readonly errorCount: Ref<number>\n /** Total responses with status >= 400 and < 500. */\n readonly clientErrorCount: Ref<number>\n /** Server start time. */\n readonly startedAt: Ref<number>\n /** Computed error rate (server errors / total requests). */\n readonly errorRate: ComputedRef<number>\n /** Computed uptime in seconds. */\n readonly uptimeSeconds: ComputedRef<number>\n /** Per-route latency tracking. */\n readonly routeLatency: Record<string, RouteStats>\n /**\n * Tier-1 runtime sampler from `@forinda/kickjs-devtools-kit`. `null`\n * when `runtime.enabled` is `false`. Tests can `latest()` and\n * `history()` directly without going through the HTTP endpoint.\n */\n readonly runtimeSampler: RuntimeSampler | null\n /**\n * Memory analyzer fed by the runtime sampler. `null` when the\n * sampler is disabled. Use `analyzer.health(sampler.history())` to\n * compose a composite memory-health snapshot.\n */\n readonly memoryAnalyzer: MemoryAnalyzer | null\n}\n\n/**\n * DevToolsAdapter — Vue-style reactive introspection for KickJS applications.\n *\n * Exposes debug endpoints powered by reactive state (ref, computed, watch):\n * - `GET /_debug/routes` — all registered routes with middleware\n * - `GET /_debug/container` — DI registry with scopes and instantiation status\n * - `GET /_debug/metrics` — live request/error counts, error rate, uptime\n * - `GET /_debug/health` — deep health check with adapter status\n * - `GET /_debug/config` — sanitized environment variables (opt-in)\n * - `GET /_debug/state` — full reactive state snapshot\n *\n * @example\n * ```ts\n * import { DevToolsAdapter } from '@forinda/kickjs-devtools'\n *\n * bootstrap({\n * modules: [UserModule],\n * adapters: [\n * DevToolsAdapter({\n * enabled: process.env.NODE_ENV !== 'production',\n * exposeConfig: true,\n * configPrefixes: ['APP_', 'DATABASE_'],\n * }),\n * ],\n * })\n * ```\n */\nexport const DevToolsAdapter = defineAdapter<DevToolsOptions, DevToolsAdapterExtensions>({\n name: 'DevToolsAdapter',\n defaults: {\n basePath: '/_debug',\n errorRateThreshold: 0.5,\n exposeConfig: false,\n configPrefixes: ['APP_', 'NODE_ENV'],\n },\n build: (options) => {\n const basePath = options.basePath!\n const enabled = options.enabled ?? process.env.NODE_ENV !== 'production'\n const exposeConfig = options.exposeConfig!\n const configPrefixes = options.configPrefixes!\n const errorRateThreshold = options.errorRateThreshold!\n const peerAdapters = options.adapters ?? []\n\n // Secret token guard\n let secret: string | false\n if (options.secret === false) {\n secret = false\n } else if (options.secret) {\n secret = options.secret\n } else {\n secret = randomBytes(16).toString('hex')\n }\n\n // ── Runtime sampler + memory analyzer (kit) ────────────────────\n // Lazily instantiated so an adopter that disables runtime monitoring\n // doesn't pay the perf_hooks histogram cost. Lifecycle: start in\n // `beforeMount`, stop in `shutdown`.\n const runtimeEnabled = options.runtime?.enabled ?? true\n const runtimeSampler = runtimeEnabled\n ? new RuntimeSampler({\n intervalMs: options.runtime?.intervalMs ?? 1000,\n bufferSize: options.runtime?.bufferSize ?? 60,\n })\n : null\n const memoryAnalyzer = runtimeEnabled ? new MemoryAnalyzer() : null\n\n // ── Reactive state ─────────────────────────────────────────────\n const requestCount = ref(0)\n const errorCount = ref(0)\n const clientErrorCount = ref(0)\n const startedAt = ref(Date.now())\n const routeLatency = reactive<Record<string, RouteStats>>({})\n\n const errorRate = computed(() =>\n requestCount.value > 0 ? errorCount.value / requestCount.value : 0,\n )\n\n const uptimeSeconds = computed(() => Math.floor((Date.now() - startedAt.value) / 1000))\n\n // ── Internal mutable state ─────────────────────────────────────\n let routes: RouteInfo[] = []\n let container: Container | null = null\n let appRef: any = null\n const adapterStatuses: Record<string, string> = {}\n let stopErrorWatch: (() => void) | null = null\n\n // Watch error rate — log warnings when elevated\n if (options.onErrorRateExceeded) {\n const callback = options.onErrorRateExceeded\n stopErrorWatch = watch(errorRate, (rate) => {\n if (rate > errorRateThreshold) {\n callback(rate)\n }\n })\n } else {\n stopErrorWatch = watch(errorRate, (rate) => {\n if (rate > errorRateThreshold) {\n log.warn(`Error rate elevated: ${(rate * 100).toFixed(1)}%`)\n }\n })\n }\n\n /**\n * Find the dashboard's public directory. Prefers the new Solid SPA\n * (public/spa/, shipped from PR 4 of §23); falls back to the legacy\n * Vue+Tailwind dashboard (public/devtools/) for environments that\n * haven't run `pnpm --filter @forinda/kickjs-devtools build:spa`.\n */\n const resolvePublicDir = (): string | null => {\n const thisDir = dirname(fileURLToPath(import.meta.url))\n const candidates = [\n join(thisDir, '..', 'public', 'spa'), // dist/ -> public/spa\n join(thisDir, '..', '..', 'public', 'spa'), // src/ -> public/spa\n join(thisDir, '..', 'public', 'devtools'), // legacy Vue dashboard\n join(thisDir, '..', '..', 'public', 'devtools'), // legacy from src/\n ]\n for (const dir of candidates) {\n if (existsSync(join(dir, 'index.html'))) return dir\n }\n return null\n }\n\n /**\n * Resolve peer adapters at request time. Prefers live adapters from the\n * Application registry (survives HMR rebuild) and falls back to the\n * constructor-provided refs.\n */\n const getPeerAdapters = (): any[] => {\n const kickApp = appRef?.__kickApp\n if (kickApp && typeof kickApp.getAdapters === 'function') {\n return kickApp.getAdapters()\n }\n return peerAdapters\n }\n\n return {\n // ── Extensions (TExtra) ───────────────────────────────────────\n requestCount,\n errorCount,\n clientErrorCount,\n startedAt,\n errorRate,\n uptimeSeconds,\n routeLatency,\n runtimeSampler,\n memoryAnalyzer,\n\n // ── DevTools introspection (architecture.md §23) ─────────────\n // Cheap snapshot — counters + flags only. Anything that requires\n // a container walk or DB hit belongs in the per-endpoint RPCs\n // (`/_debug/container`, `/_debug/graph`), not here.\n introspect(): IntrospectionSnapshot {\n return {\n protocolVersion: PROTOCOL_VERSION,\n name: 'DevToolsAdapter',\n kind: 'adapter',\n state: {\n basePath,\n enabled,\n runtimeEnabled,\n secret: secret === false ? false : 'present',\n },\n metrics: {\n requestCount: requestCount.value,\n serverErrors: errorCount.value,\n clientErrors: clientErrorCount.value,\n uptimeSeconds: uptimeSeconds.value,\n routesTracked: routes.length,\n },\n }\n },\n\n // ── Lifecycle ─────────────────────────────────────────────────\n\n beforeMount({ app, container: containerArg }) {\n if (!enabled) return\n\n appRef = app\n container = containerArg\n startedAt.value = Date.now()\n // Clear routes on rebuild/restart to prevent HMR duplication\n routes = []\n adapterStatuses['DevToolsAdapter'] = 'running'\n\n // Start the runtime sampler + memory analyzer here (rather than\n // at construction) so test harnesses that build the adapter but\n // never mount it don't leak interval timers.\n runtimeSampler?.start()\n memoryAnalyzer?.start()\n\n const router = Router()\n\n // ── Access guard — require secret token ──────────────────\n if (secret !== false) {\n const token = secret\n router.use((req: Request, res: Response, next: NextFunction) => {\n const provided = req.headers['x-devtools-token'] ?? req.query?.token\n if (provided === token) return next()\n // Allow the dashboard HTML itself (it will include the token in API calls)\n if (req.path === '/' && req.method === 'GET' && !req.query?.token) {\n return next() // serve dashboard, it handles auth via token\n }\n // Serve static assets for the dashboard (js files)\n if (req.path.endsWith('.js') || req.path.endsWith('.css')) {\n return next()\n }\n res.status(403).json({ error: 'Forbidden — invalid or missing devtools token' })\n })\n }\n\n router.get('/routes', (_req: Request, res: Response) => {\n res.json({ routes })\n })\n\n router.get('/container', (_req: Request, res: Response) => {\n const registrations = container?.getRegistrations() ?? []\n res.json({ registrations, count: registrations.length })\n })\n\n router.get('/metrics', (_req: Request, res: Response) => {\n // Build latency with percentiles, omitting raw samples from response\n const latency: Record<string, any> = {}\n for (const [key, stats] of Object.entries(routeLatency)) {\n const { samples: _, ...rest } = stats\n latency[key] = { ...rest, ...computePercentiles(stats) }\n }\n res.json({\n requests: requestCount.value,\n serverErrors: errorCount.value,\n clientErrors: clientErrorCount.value,\n errorRate: errorRate.value,\n uptimeSeconds: uptimeSeconds.value,\n startedAt: new Date(startedAt.value).toISOString(),\n routeLatency: latency,\n })\n })\n\n router.get('/health', (_req: Request, res: Response) => {\n const healthy = errorRate.value < errorRateThreshold\n const status = healthy ? 'healthy' : 'degraded'\n\n res.status(healthy ? 200 : 503).json({\n status,\n errorRate: errorRate.value,\n uptime: uptimeSeconds.value,\n adapters: adapterStatuses,\n })\n })\n\n router.get('/state', (_req: Request, res: Response) => {\n const wsAdapter = getPeerAdapters().find(\n (a) => a.name === 'WsAdapter' && typeof a.getStats === 'function',\n )\n res.json({\n reactive: {\n requestCount: requestCount.value,\n errorCount: errorCount.value,\n clientErrorCount: clientErrorCount.value,\n errorRate: errorRate.value,\n uptimeSeconds: uptimeSeconds.value,\n startedAt: new Date(startedAt.value).toISOString(),\n },\n routes: routes.length,\n container: container?.getRegistrations().length ?? 0,\n routeLatency,\n ...(wsAdapter ? { ws: wsAdapter.getStats() } : {}),\n })\n })\n\n // ── Tier-1 runtime monitoring (architecture.md §23) ─────────\n // Returns the latest RuntimeSnapshot + a composite MemoryHealth\n // computed from the sampler's ring buffer. Returns 404 when the\n // sampler is disabled so adopters can distinguish \"off\" from\n // \"starting up\".\n router.get('/runtime', (_req: Request, res: Response) => {\n if (!runtimeSampler || !memoryAnalyzer) {\n res.status(404).json({ error: 'runtime sampler disabled — set runtime.enabled = true' })\n return\n }\n const latest = runtimeSampler.latest()\n const history = runtimeSampler.history()\n const health = memoryAnalyzer.health(history)\n res.json({\n protocolVersion: PROTOCOL_VERSION,\n latest,\n history,\n health,\n })\n })\n\n // ── SSE: live runtime snapshots (architecture.md §23) ───────\n // Pushes the latest RuntimeSnapshot every `intervalMs`. SSE\n // (not WebSocket) avoids the http.Server `upgrade`-event\n // coordination cost — see devtools-flows.md §3 for rationale.\n router.get('/runtime/stream', (req: Request, res: Response) => {\n if (!runtimeSampler) {\n res.status(404).json({ error: 'runtime sampler disabled' })\n return\n }\n openSseStream(req, res)\n const intervalMs = options.runtime?.intervalMs ?? 1000\n const tick = (): void => {\n const snap = runtimeSampler.latest()\n if (snap) writeSseEvent(res, snap)\n }\n tick()\n const interval = setInterval(tick, intervalMs)\n const heartbeat = setInterval(() => res.write(': heartbeat\\n\\n'), 30_000)\n req.on('close', () => {\n clearInterval(interval)\n clearInterval(heartbeat)\n })\n })\n\n // ── SSE: memory health composite (architecture.md §23) ──────\n router.get('/memory/stream', (req: Request, res: Response) => {\n if (!runtimeSampler || !memoryAnalyzer) {\n res.status(404).json({ error: 'runtime sampler disabled' })\n return\n }\n openSseStream(req, res)\n const intervalMs = options.runtime?.intervalMs ?? 1000\n const tick = (): void => {\n const snap = runtimeSampler.latest()\n if (!snap) return\n const health = memoryAnalyzer.health(runtimeSampler.history())\n writeSseEvent(res, { snapshot: snap, health })\n }\n tick()\n const interval = setInterval(tick, intervalMs)\n const heartbeat = setInterval(() => res.write(': heartbeat\\n\\n'), 30_000)\n req.on('close', () => {\n clearInterval(interval)\n clearInterval(heartbeat)\n })\n })\n\n // ── Heap snapshot — Tier 3 monitoring (architecture.md §23) ─\n // POST /_debug/memory/snapshot — captures a V8 heap snapshot\n // and streams the resulting .heapsnapshot file back as\n // application/json with Content-Disposition. Snapshot capture\n // blocks the event loop while writing (multi-second pause for\n // large heaps), so the endpoint enforces single-flight via a\n // module-scoped flag — concurrent calls return 503.\n //\n // The temp file is deleted as soon as the response stream\n // completes (success or error). Worst case if the process\n // dies mid-snapshot is a stranded file in `os.tmpdir()`,\n // which the OS cleans up on next boot.\n router.post('/memory/snapshot', (_req: Request, res: Response) => {\n if (snapshotInProgress) {\n res\n .status(503)\n .json({ error: 'heap snapshot already in progress — wait for it to complete' })\n return\n }\n snapshotInProgress = true\n const startedAt = Date.now()\n const filename = `kickjs-heap-${new Date().toISOString().replace(/[:.]/g, '-')}.heapsnapshot`\n const targetPath = join(tmpdir(), filename)\n\n let written: string\n try {\n // writeHeapSnapshot is synchronous — the event loop is\n // blocked for the duration. There's no async variant in\n // the v8 module today; if one ships, swap here.\n written = writeHeapSnapshot(targetPath)\n } catch (err) {\n snapshotInProgress = false\n log.error({ err }, 'heap snapshot capture failed')\n res\n .status(500)\n .json({ error: 'snapshot capture failed', message: (err as Error).message })\n return\n }\n\n let size = 0\n try {\n size = statSync(written).size\n } catch {\n /* size header is best-effort */\n }\n const elapsedMs = Date.now() - startedAt\n log.info(\n `Heap snapshot captured: ${written} (${(size / 1024 / 1024).toFixed(1)} MiB in ${elapsedMs}ms)`,\n )\n\n res.setHeader('Content-Type', 'application/json')\n res.setHeader('Content-Disposition', `attachment; filename=\"${filename}\"`)\n if (size > 0) res.setHeader('Content-Length', String(size))\n res.setHeader('X-Snapshot-Capture-Ms', String(elapsedMs))\n\n const cleanup = (): void => {\n unlink(written, (err) => {\n if (err) log.warn(`Failed to delete heap snapshot ${written}: ${err.message}`)\n snapshotInProgress = false\n })\n }\n const stream = createReadStream(written)\n stream.on('end', cleanup)\n stream.on('error', (err) => {\n log.error({ err }, 'heap snapshot stream failed')\n if (!res.headersSent) res.status(500).end()\n cleanup()\n })\n // Defensive: if the client disconnects mid-download, abort\n // the stream + run cleanup so the temp file doesn't linger.\n res.on('close', () => {\n stream.destroy()\n // If the stream already fired 'end', cleanup already ran\n // — the unlink is idempotent enough that running twice\n // just yields ENOENT which we ignore in cleanup.\n })\n stream.pipe(res)\n })\n\n // ── Force GC — Tier 3 monitoring (architecture.md §23) ──────\n // POST /_debug/memory/gc — calls `global.gc()` if Node was\n // started with --expose-gc, returning before/after heap size\n // so the panel can show how much was reclaimed. Useful for\n // confirming \"is this growth real or just delayed GC?\".\n //\n // Returns 412 Precondition Failed (with hint) when the flag\n // wasn't set, so the SPA can show \"Run with --expose-gc to\n // enable this button\" instead of a generic 5xx.\n router.post('/memory/gc', (_req: Request, res: Response) => {\n const gc = (globalThis as { gc?: () => void }).gc\n if (typeof gc !== 'function') {\n res.status(412).json({\n error: 'global.gc unavailable — start Node with --expose-gc to enable this endpoint',\n })\n return\n }\n const before = process.memoryUsage().heapUsed\n const startedAt = Date.now()\n try {\n gc()\n } catch (err) {\n res.status(500).json({\n error: 'forced GC failed',\n message: err instanceof Error ? err.message : String(err),\n })\n return\n }\n const after = process.memoryUsage().heapUsed\n const reclaimedBytes = Math.max(0, before - after)\n const elapsedMs = Date.now() - startedAt\n log.info(\n `Forced GC reclaimed ${(reclaimedBytes / 1024 / 1024).toFixed(2)} MiB in ${elapsedMs}ms`,\n )\n res.json({ before, after, reclaimedBytes, elapsedMs })\n })\n\n // ── Custom-tab discovery (architecture.md §23) ──────────────\n // Walks every plugin/adapter `devtoolsTabs?()` contribution\n // and serves the deduped + validated list. The SPA fetches\n // this once at boot to render dynamic tabs after the four\n // built-ins.\n router.get('/tabs', (_req: Request, res: Response) => {\n const kickApp = appRef?.__kickApp as TopologyApplicationLike | undefined\n if (!kickApp) {\n res.status(503).json({ error: 'tabs unavailable — application surface not exposed' })\n return\n }\n res.json(collectDevtoolsTabs(kickApp))\n })\n\n // ── Topology RPC (architecture.md §23) ──────────────────────\n // Aggregates plugins + adapters + contributors + DI tokens\n // into one snapshot; calls each primitive's introspect() in\n // parallel with a per-call timeout so a misbehaving adapter\n // can't block the endpoint. Errors are collected, not thrown.\n router.get('/topology', async (_req: Request, res: Response) => {\n if (!container) {\n res.status(503).json({ error: 'topology unavailable — container not bound yet' })\n return\n }\n const kickApp = appRef?.__kickApp as TopologyApplicationLike | undefined\n if (!kickApp) {\n res\n .status(503)\n .json({ error: 'topology unavailable — application surface not exposed' })\n return\n }\n try {\n const snapshot = await collectTopologySnapshot({ app: kickApp, container })\n res.json(snapshot)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n res.status(500).json({ error: 'topology collection failed', message })\n }\n })\n\n router.get('/ws', (_req: Request, res: Response) => {\n const wsAdapter = getPeerAdapters().find(\n (a) => a.name === 'WsAdapter' && typeof a.getStats === 'function',\n )\n if (!wsAdapter) {\n res.json({ enabled: false, message: 'WsAdapter not found' })\n return\n }\n res.json({ enabled: true, ...wsAdapter.getStats() })\n })\n\n router.get('/queues', async (_req: Request, res: Response) => {\n const queueAdapter = getPeerAdapters().find(\n (a) => a.name === 'QueueAdapter' && typeof a.getQueueNames === 'function',\n )\n if (!queueAdapter) {\n res.json({ enabled: false, message: 'QueueAdapter not found' })\n return\n }\n try {\n const names: string[] = queueAdapter.getQueueNames?.() ?? []\n const queues: any[] = []\n for (const name of names) {\n const stats = await queueAdapter.getQueueStats?.(name)\n queues.push({ name, ...stats })\n }\n res.json({ enabled: true, queues })\n } catch {\n res.json({ enabled: true, queues: [], error: 'Failed to fetch queue stats' })\n }\n })\n\n // ── Dependency graph ────────────────────────────────────────\n router.get('/graph', (_req: Request, res: Response) => {\n const registrations = container?.getRegistrations() ?? []\n const nodes = registrations\n .filter((r) => !r.token.startsWith('__hmr__'))\n .map((r) => ({\n id: r.token,\n kind: r.kind,\n scope: r.scope,\n resolveCount: r.resolveCount,\n }))\n const nodeIds = new Set(nodes.map((n) => n.id))\n const edges: Array<{ from: string; to: string }> = []\n for (const r of registrations) {\n if (r.token.startsWith('__hmr__')) continue\n for (const dep of r.dependencies) {\n if (nodeIds.has(dep)) {\n edges.push({ from: r.token, to: dep })\n }\n }\n }\n res.json({ nodes, edges })\n })\n\n // ── SSE stream for real-time updates ────────────────────────\n router.get('/stream', (req: Request, res: Response) => {\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n })\n\n const sendMetrics = () => {\n const data = {\n type: 'metrics',\n requestCount: requestCount.value,\n errorCount: errorCount.value,\n clientErrorCount: clientErrorCount.value,\n errorRate: errorRate.value,\n uptimeSeconds: uptimeSeconds.value,\n }\n res.write(`data: ${JSON.stringify(data)}\\n\\n`)\n }\n sendMetrics()\n\n const unsubContainer = container?.onChange?.((changes) => {\n res.write(\n `data: ${JSON.stringify({ type: 'container', changes, timestamp: Date.now() })}\\n\\n`,\n )\n sendMetrics()\n })\n\n const stopRequestWatch = watch(requestCount, () => sendMetrics())\n const stopErrWatch = watch(errorCount, () => sendMetrics())\n\n const heartbeat = setInterval(() => {\n res.write(`: heartbeat\\n\\n`)\n }, 30000)\n\n req.on('close', () => {\n unsubContainer?.()\n stopRequestWatch()\n stopErrWatch()\n clearInterval(heartbeat)\n })\n })\n\n if (exposeConfig) {\n router.get('/config', (_req: Request, res: Response) => {\n const config: Record<string, string> = {}\n for (const [key, value] of Object.entries(process.env)) {\n if (value === undefined) continue\n const allowed = configPrefixes.some((prefix) => key.startsWith(prefix))\n config[key] = allowed ? value : '[REDACTED]'\n }\n res.json({ config })\n })\n }\n\n // Dashboard UI — Vue + Tailwind from public/devtools directory\n const publicDir = resolvePublicDir()\n if (publicDir) {\n router.use(serveStatic(publicDir))\n\n const indexHtml = readFileSync(join(publicDir, 'index.html'), 'utf-8')\n router.get('/', (_req: Request, res: Response) => {\n const html = indexHtml.replace('<body', `<body data-base=\"${basePath}\"`)\n res.type('html').send(html)\n })\n } else {\n router.get('/', (_req: Request, res: Response) => {\n res.type('html').send('<h1>DevTools: public directory not found</h1>')\n })\n }\n\n app.use(basePath, router)\n\n if (secret) {\n log.info(`DevTools mounted at ${basePath} [token: ${secret}]`)\n log.info(`Access: ${basePath}?token=${secret}`)\n } else {\n log.info(`DevTools mounted at ${basePath} [no guard]`)\n }\n },\n\n middleware(): AdapterMiddleware[] {\n if (!enabled) return []\n\n return [\n {\n handler: (req: Request, res: Response, next: NextFunction) => {\n const start = Date.now()\n requestCount.value++\n\n res.on('finish', () => {\n if (res.statusCode >= 500) errorCount.value++\n else if (res.statusCode >= 400) clientErrorCount.value++\n\n const routeKey = `${req.method} ${req.route?.path ?? req.path}`\n const elapsed = Date.now() - start\n\n if (!routeLatency[routeKey]) {\n routeLatency[routeKey] = {\n count: 0,\n totalMs: 0,\n minMs: Infinity,\n maxMs: 0,\n samples: [],\n }\n }\n const stats = routeLatency[routeKey]\n stats.count++\n stats.totalMs += elapsed\n stats.minMs = Math.min(stats.minMs, elapsed)\n stats.maxMs = Math.max(stats.maxMs, elapsed)\n stats.samples.push(elapsed)\n if (stats.samples.length > MAX_SAMPLES) stats.samples.shift()\n })\n\n next()\n },\n phase: 'beforeGlobal',\n },\n ]\n },\n\n onRouteMount(controllerClass, mountPath) {\n if (!enabled) return\n\n const collectedRoutes = getClassMeta<\n Array<{ method: string; path: string; handlerName: string }>\n >(METADATA.ROUTES, controllerClass, [])\n\n const classMiddleware = getClassMeta<any[]>(METADATA.CLASS_MIDDLEWARES, controllerClass, [])\n\n for (const route of collectedRoutes) {\n const methodMiddleware = getMethodMeta<any[]>(\n METADATA.METHOD_MIDDLEWARES,\n controllerClass.prototype,\n route.handlerName,\n [],\n )\n\n routes.push({\n method: route.method.toUpperCase(),\n path: `${mountPath}${route.path === '/' ? '' : route.path}`,\n controller: controllerClass.name,\n handler: route.handlerName,\n middleware: [\n ...classMiddleware.map((m: any) => m.name || 'anonymous'),\n ...methodMiddleware.map((m: any) => m.name || 'anonymous'),\n ],\n })\n }\n },\n\n afterStart() {\n if (!enabled) return\n log.info(\n `DevTools ready — ${routes.length} routes tracked, ` +\n `${container?.getRegistrations().length ?? 0} DI bindings`,\n )\n },\n\n shutdown() {\n stopErrorWatch?.()\n runtimeSampler?.stop()\n memoryAnalyzer?.stop()\n adapterStatuses['DevToolsAdapter'] = 'stopped'\n },\n }\n },\n})\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["serveStatic"],"sources":["../src/topology.ts","../src/devtools-tabs.ts","../src/adapter.ts"],"sourcesContent":["/**\n * Topology aggregator — walks the running KickJS application + DI\n * container and produces a JSON-serialisable {@link TopologySnapshot}.\n *\n * Calls `introspect()` on every plugin and adapter that implements it\n * (architecture.md §23.3); falls back to a minimal `{ protocolVersion,\n * name, kind }` stub for primitives that don't. Per-primitive\n * introspection failures are caught + collected into the snapshot's\n * `errors` field rather than failing the entire endpoint.\n *\n * @module @forinda/kickjs-devtools/topology\n */\n\nimport type { AppAdapter, Container, KickPlugin } from '@forinda/kickjs'\nimport {\n PROTOCOL_VERSION,\n type IntrospectionSnapshot,\n type TopologyContributorEntry,\n type TopologyError,\n type TopologySnapshot,\n type TopologyTokenEntry,\n} from '@forinda/kickjs-devtools-kit'\n\n/** Minimal Application surface the aggregator needs — keeps coupling thin. */\nexport interface TopologyApplicationLike {\n getAdapters(): AppAdapter[]\n getPlugins(): readonly KickPlugin[]\n /**\n * Optional in older Application implementations — when present, returns\n * the union of contributors across adapters/plugins/global with proper\n * source labels. The topology aggregator prefers this over walking\n * `adapter.contributors()` + `plugin.contributors()` directly because\n * the application-level walk preserves source provenance.\n */\n getContributors?(): ReadonlyArray<{\n key: string\n source: 'adapter' | 'plugin' | 'module' | 'global'\n label: string\n dependsOn: readonly string[]\n }>\n}\n\n/** Inputs to {@link collectTopologySnapshot}. */\nexport interface CollectTopologyOptions {\n /** The running KickJS application (or anything that exposes its surface). */\n app: TopologyApplicationLike\n /** The DI container — used to enumerate registered tokens. */\n container: Container\n /**\n * Optional per-call introspect timeout in milliseconds. An adapter\n * whose `introspect()` doesn't settle within the budget gets a stub\n * snapshot + an entry in `errors`. Default: 100ms — keeps the\n * topology endpoint snappy even if one adapter misbehaves.\n */\n introspectTimeoutMs?: number\n}\n\nconst DEFAULT_INTROSPECT_TIMEOUT_MS = 100\n\n/**\n * Collect a {@link TopologySnapshot} for the given application.\n *\n * Async because plugin/adapter `introspect()` may be async; the work\n * is parallelised across all primitives so wall-clock time scales\n * with the slowest introspector, not their sum.\n */\nexport async function collectTopologySnapshot(\n opts: CollectTopologyOptions,\n): Promise<TopologySnapshot> {\n const { app, container, introspectTimeoutMs = DEFAULT_INTROSPECT_TIMEOUT_MS } = opts\n const errors: TopologyError[] = []\n\n const plugins = await Promise.all(\n app.getPlugins().map((p) => snapshotFor(p, 'plugin', introspectTimeoutMs, errors)),\n )\n const adapters = await Promise.all(\n app.getAdapters().map((a) => snapshotFor(a, 'adapter', introspectTimeoutMs, errors)),\n )\n\n return {\n protocolVersion: PROTOCOL_VERSION,\n timestamp: Date.now(),\n plugins,\n adapters,\n contributors: collectContributors(app),\n diTokens: collectTokens(container),\n errors,\n }\n}\n\n/**\n * Coerce one primitive into an {@link IntrospectionSnapshot}. Tries\n * the primitive's own `introspect()` first; falls back to a stub on\n * any of: missing implementation, throw, timeout, or non-object return.\n */\nasync function snapshotFor(\n primitive: AppAdapter | KickPlugin,\n kind: 'plugin' | 'adapter',\n timeoutMs: number,\n errors: TopologyError[],\n): Promise<IntrospectionSnapshot> {\n const name = primitive.name ?? '(unnamed)'\n const stub: IntrospectionSnapshot = {\n protocolVersion: PROTOCOL_VERSION,\n name,\n kind,\n }\n if (typeof primitive.introspect !== 'function') return stub\n\n try {\n const result = await Promise.race([\n Promise.resolve(primitive.introspect()),\n new Promise<never>((_, reject) =>\n setTimeout(\n () => reject(new Error(`introspect() timed out after ${timeoutMs}ms`)),\n timeoutMs,\n ),\n ),\n ])\n if (result && typeof result === 'object') {\n // Accept whatever the primitive returned; the kit's\n // IntrospectionSnapshot is opt-in typed via the kit, not enforced\n // at this layer (see plugin.ts / adapter.ts comment about avoiding\n // a runtime dep on the kit).\n const snap = result as Partial<IntrospectionSnapshot>\n return {\n protocolVersion: PROTOCOL_VERSION,\n name: snap.name ?? name,\n kind: snap.kind ?? kind,\n version: snap.version,\n state: snap.state,\n tokens: snap.tokens,\n metrics: snap.metrics,\n memoryBytes: snap.memoryBytes,\n }\n }\n return stub\n } catch (err) {\n errors.push({\n name,\n kind,\n message: err instanceof Error ? err.message : String(err),\n })\n return stub\n }\n}\n\n/** Read DI registrations into the topology shape — drops noisy HMR tokens. */\nfunction collectTokens(container: Container): TopologyTokenEntry[] {\n return container\n .getRegistrations()\n .filter((r) => !r.token.startsWith('__hmr__'))\n .map((r) => ({\n token: r.token,\n scope: r.scope,\n kind: r.kind,\n instantiated: r.instantiated,\n }))\n}\n\n/**\n * Contributor enumeration. Prefers `app.getContributors()` (the\n * Application-level walk that preserves adapter / plugin / global\n * source labels) when present; falls back to walking\n * `adapter.contributors()` + `plugin.contributors()` directly for\n * older Application implementations that don't expose the helper.\n *\n * Module-level contributors are still not surfaced here — module\n * instances aren't retained post-bootstrap. Per-route enumeration\n * lands in a later iteration alongside the route detail panel.\n */\nfunction collectContributors(app: TopologyApplicationLike): TopologyContributorEntry[] {\n const seen = new Map<string, TopologyContributorEntry>()\n\n if (typeof app.getContributors === 'function') {\n for (const c of app.getContributors()) {\n if (seen.has(c.key)) continue\n // The kit's source enum currently only allows 'adapter' | 'module';\n // 'plugin' + 'global' both map to 'adapter' provenance for now —\n // the Topology UI labels them by `label` so the source field is\n // mainly a coarse category. Future kit version can widen.\n const mapped: TopologyContributorEntry['source'] =\n c.source === 'module' ? 'module' : 'adapter'\n seen.set(c.key, {\n key: c.key,\n source: mapped,\n dependsOn: c.dependsOn as string[],\n })\n }\n return [...seen.values()]\n }\n\n // Legacy path — direct walk.\n const ingest = (\n list: ReadonlyArray<unknown> | null | undefined,\n source: TopologyContributorEntry['source'],\n ): void => {\n if (!list) return\n for (const reg of list) {\n const r = reg as { key?: string; dependsOn?: readonly string[] }\n const key = typeof r.key === 'string' ? r.key : null\n if (!key || seen.has(key)) continue\n seen.set(key, {\n key,\n source,\n dependsOn: Array.isArray(r.dependsOn) ? r.dependsOn : [],\n })\n }\n }\n\n for (const plugin of app.getPlugins()) {\n ingest(plugin.contributors?.(), 'adapter')\n }\n for (const adapter of app.getAdapters()) {\n ingest(adapter.contributors?.(), 'adapter')\n }\n\n return [...seen.values()]\n}\n","/**\n * Custom-tab aggregator — collects every plugin/adapter's\n * `devtoolsTabs()` contribution into a single deduped list for the\n * panel's `/_debug/tabs` endpoint.\n *\n * Validation is permissive: anything that doesn't look like a\n * {@link DevtoolsTabDescriptor} is dropped with a console warning\n * rather than throwing — a misconfigured adapter shouldn't break the\n * whole DevTools panel.\n *\n * @module @forinda/kickjs-devtools/devtools-tabs\n */\n\nimport type { DevtoolsTabDescriptor } from '@forinda/kickjs-devtools-kit'\nimport type { TopologyApplicationLike } from './topology'\n\n/** Result of {@link collectDevtoolsTabs}. */\nexport interface DevtoolsTabsResult {\n /** Deduped, validated tabs in registration order. */\n tabs: DevtoolsTabDescriptor[]\n /** Per-source collection errors (drop reason, source name). */\n errors: ReadonlyArray<{ source: string; reason: string }>\n}\n\nconst VALID_VIEW_TYPES = new Set(['iframe', 'launch', 'html'])\n\n/**\n * Walk every plugin + adapter, call `devtoolsTabs?()`, validate each\n * entry, and dedupe by `id`. Last-source-wins on collision is too\n * surprising — first-source-wins + a warning entry instead.\n */\nexport function collectDevtoolsTabs(app: TopologyApplicationLike): DevtoolsTabsResult {\n const tabs: DevtoolsTabDescriptor[] = []\n const seen = new Map<string, string>() // id → source name (for collision warnings)\n const errors: Array<{ source: string; reason: string }> = []\n\n const ingest = (sourceName: string, raw: unknown): void => {\n if (!Array.isArray(raw)) {\n errors.push({ source: sourceName, reason: 'devtoolsTabs() did not return an array' })\n return\n }\n for (const entry of raw) {\n const validation = validateTab(entry)\n if (!validation.ok) {\n errors.push({ source: sourceName, reason: validation.reason })\n continue\n }\n const tab = validation.tab\n const owner = seen.get(tab.id)\n if (owner) {\n errors.push({\n source: sourceName,\n reason: `tab id '${tab.id}' already registered by ${owner} — first-source wins`,\n })\n continue\n }\n seen.set(tab.id, sourceName)\n tabs.push(tab)\n }\n }\n\n for (const plugin of app.getPlugins()) {\n if (typeof plugin.devtoolsTabs !== 'function') continue\n try {\n ingest(plugin.name ?? '(unnamed plugin)', plugin.devtoolsTabs())\n } catch (err) {\n errors.push({\n source: plugin.name ?? '(unnamed plugin)',\n reason: err instanceof Error ? err.message : String(err),\n })\n }\n }\n for (const adapter of app.getAdapters()) {\n if (typeof adapter.devtoolsTabs !== 'function') continue\n try {\n ingest(adapter.name ?? '(unnamed adapter)', adapter.devtoolsTabs())\n } catch (err) {\n errors.push({\n source: adapter.name ?? '(unnamed adapter)',\n reason: err instanceof Error ? err.message : String(err),\n })\n }\n }\n\n return { tabs, errors }\n}\n\ninterface ValidationOk {\n ok: true\n tab: DevtoolsTabDescriptor\n}\n\ninterface ValidationFail {\n ok: false\n reason: string\n}\n\n/**\n * Coerce + validate a tab descriptor. Returns the typed object on\n * success; a structured reason on failure. Uses a permissive checker\n * so a partially-correct entry from a third-party adapter doesn't\n * break the whole panel.\n */\nfunction validateTab(raw: unknown): ValidationOk | ValidationFail {\n if (!raw || typeof raw !== 'object') {\n return { ok: false, reason: 'tab entry is not an object' }\n }\n const obj = raw as Record<string, unknown>\n if (typeof obj.id !== 'string' || obj.id.length === 0) {\n return { ok: false, reason: 'tab.id must be a non-empty string' }\n }\n if (typeof obj.title !== 'string' || obj.title.length === 0) {\n return { ok: false, reason: `tab '${obj.id}': title must be a non-empty string` }\n }\n const view = obj.view as Record<string, unknown> | undefined\n if (!view || typeof view !== 'object') {\n return { ok: false, reason: `tab '${obj.id}': view object is required` }\n }\n if (typeof view.type !== 'string' || !VALID_VIEW_TYPES.has(view.type)) {\n return {\n ok: false,\n reason: `tab '${obj.id}': view.type must be one of iframe / launch / html`,\n }\n }\n switch (view.type) {\n case 'iframe':\n if (typeof view.src !== 'string' || view.src.length === 0) {\n return { ok: false, reason: `tab '${obj.id}': iframe view requires a non-empty src` }\n }\n break\n case 'html':\n if (typeof view.html !== 'string') {\n return { ok: false, reason: `tab '${obj.id}': html view requires html string` }\n }\n break\n case 'launch':\n if (!Array.isArray(view.actions)) {\n return { ok: false, reason: `tab '${obj.id}': launch view requires actions array` }\n }\n break\n }\n return { ok: true, tab: obj as unknown as DevtoolsTabDescriptor }\n}\n","import type { Request, Response, NextFunction } from 'express'\nimport { Router, static as serveStatic } from 'express'\nimport { dirname, join } from 'node:path'\nimport { tmpdir } from 'node:os'\nimport { fileURLToPath } from 'node:url'\nimport { createReadStream, existsSync, readFileSync, statSync, unlink } from 'node:fs'\nimport { randomBytes } from 'node:crypto'\nimport { writeHeapSnapshot } from 'node:v8'\nimport {\n type AdapterMiddleware,\n type Container,\n METADATA,\n defineAdapter,\n ref,\n computed,\n reactive,\n watch,\n createLogger,\n type Ref,\n type ComputedRef,\n getClassMeta,\n getMethodMeta,\n} from '@forinda/kickjs'\nimport {\n MemoryAnalyzer,\n PROTOCOL_VERSION,\n RuntimeSampler,\n type IntrospectionSnapshot,\n} from '@forinda/kickjs-devtools-kit'\nimport { collectTopologySnapshot, type TopologyApplicationLike } from './topology'\nimport { collectDevtoolsTabs } from './devtools-tabs'\n\nconst log = createLogger('DevTools')\n\n/** Route metadata collected during mount */\ninterface RouteInfo {\n method: string\n path: string\n controller: string\n handler: string\n middleware: string[]\n}\n\n/** Per-route latency stats with percentile tracking */\ninterface RouteStats {\n count: number\n totalMs: number\n minMs: number\n maxMs: number\n /** Ring buffer of last N samples for percentile computation */\n samples: number[]\n}\n\nconst MAX_SAMPLES = 1000\n\n/** Compute a percentile from a sorted array of numbers */\nfunction percentile(sorted: number[], p: number): number {\n if (sorted.length === 0) return 0\n const idx = Math.ceil(p * sorted.length) - 1\n return sorted[Math.max(0, idx)]\n}\n\n/** Compute p50, p95, p99 from a RouteStats samples buffer */\nfunction computePercentiles(stats: RouteStats): { p50: number; p95: number; p99: number } {\n const sorted = [...stats.samples].sort((a, b) => a - b)\n return {\n p50: percentile(sorted, 0.5),\n p95: percentile(sorted, 0.95),\n p99: percentile(sorted, 0.99),\n }\n}\n\n/**\n * Open an SSE response — sets the headers, flushes them, and disables\n * any compression middleware that may have been registered upstream\n * (compression buffers SSE chunks indefinitely; we need flush-on-write).\n */\nfunction openSseStream(req: Request, res: Response): void {\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache, no-transform',\n Connection: 'keep-alive',\n 'X-Accel-Buffering': 'no',\n })\n res.flushHeaders?.()\n // Defensive: the compression middleware checks this header. Some\n // setups also wrap res.write — calling res.flush after each write\n // is safe even when no compression is in play.\n void req\n}\n\n/** Write a single SSE `data:` event with a JSON payload + double newline. */\nfunction writeSseEvent(res: Response, payload: unknown): void {\n res.write(`data: ${JSON.stringify(payload)}\\n\\n`)\n}\n\n/**\n * Module-scoped guard for `POST /_debug/memory/snapshot`. `writeHeapSnapshot()`\n * blocks the event loop for the duration of the capture (multi-second\n * for large heaps); two concurrent captures would compound the pause.\n * The endpoint returns 503 + a hint message when this flag is set so\n * the SPA can surface a \"snapshot already running\" warning rather than\n * silently queueing.\n *\n * Module-scoped (not per-adapter-instance) because writeHeapSnapshot\n * acts on the V8 process — multiple DevToolsAdapter instances would\n * still race at the v8 layer.\n */\nlet snapshotInProgress = false\n\nexport interface DevToolsOptions {\n /** Base path for debug endpoints (default: '/_debug') */\n basePath?: string\n /** Only enable when this is true (default: process.env.NODE_ENV !== 'production') */\n enabled?: boolean\n /** Include environment variables (sanitized) at /_debug/config (default: false) */\n exposeConfig?: boolean\n /** Env var prefixes to expose (default: ['APP_', 'NODE_ENV']). Others are redacted. */\n configPrefixes?: string[]\n /** Callback when error rate exceeds threshold */\n onErrorRateExceeded?: (rate: number) => void\n /** Error rate threshold (default: 0.5 = 50%) */\n errorRateThreshold?: number\n /** Other adapters to discover stats from (e.g., WsAdapter) */\n adapters?: any[]\n\n /**\n * Secret token to guard DevTools access. When set, all requests must\n * include this token as `x-devtools-token` header or `?token=` query param.\n *\n * Auto-generated on startup if not provided. The token is logged to the console.\n * Set to `false` to disable the guard entirely (not recommended).\n *\n * @example\n * ```ts\n * DevToolsAdapter({ secret: getEnv('DEVTOOLS_SECRET') })\n * ```\n */\n secret?: string | false\n\n /**\n * Tuning for the runtime sampler that powers `/_debug/runtime` and\n * the upcoming Memory tab (architecture.md §23). Defaults to\n * 1-second polling with a 60-sample (~1 minute) ring buffer.\n *\n * Set `runtime.enabled = false` to skip starting the sampler — the\n * `/_debug/runtime` endpoint then returns 404 instead of an empty\n * snapshot, signalling deliberate opt-out rather than a startup race.\n */\n runtime?: {\n /** Whether to start the runtime sampler at all. Default: true. */\n enabled?: boolean\n /** Polling interval in milliseconds. Default: 1000. */\n intervalMs?: number\n /** Ring-buffer size — number of past samples retained. Default: 60. */\n bufferSize?: number\n }\n}\n\n/**\n * Public reactive surface exposed by a DevToolsAdapter instance —\n * counters, computed metrics, and the route latency map. Tests and\n * peer adapters consume these directly to drive their own behavior.\n */\nexport interface DevToolsAdapterExtensions {\n /** Total requests received. */\n readonly requestCount: Ref<number>\n /** Total responses with status >= 500. */\n readonly errorCount: Ref<number>\n /** Total responses with status >= 400 and < 500. */\n readonly clientErrorCount: Ref<number>\n /** Server start time. */\n readonly startedAt: Ref<number>\n /** Computed error rate (server errors / total requests). */\n readonly errorRate: ComputedRef<number>\n /** Computed uptime in seconds. */\n readonly uptimeSeconds: ComputedRef<number>\n /** Per-route latency tracking. */\n readonly routeLatency: Record<string, RouteStats>\n /**\n * Tier-1 runtime sampler from `@forinda/kickjs-devtools-kit`. `null`\n * when `runtime.enabled` is `false`. Tests can `latest()` and\n * `history()` directly without going through the HTTP endpoint.\n */\n readonly runtimeSampler: RuntimeSampler | null\n /**\n * Memory analyzer fed by the runtime sampler. `null` when the\n * sampler is disabled. Use `analyzer.health(sampler.history())` to\n * compose a composite memory-health snapshot.\n */\n readonly memoryAnalyzer: MemoryAnalyzer | null\n}\n\n/**\n * DevToolsAdapter — Vue-style reactive introspection for KickJS applications.\n *\n * Exposes debug endpoints powered by reactive state (ref, computed, watch):\n * - `GET /_debug/routes` — all registered routes with middleware\n * - `GET /_debug/container` — DI registry with scopes and instantiation status\n * - `GET /_debug/metrics` — live request/error counts, error rate, uptime\n * - `GET /_debug/health` — deep health check with adapter status\n * - `GET /_debug/config` — sanitized environment variables (opt-in)\n * - `GET /_debug/state` — full reactive state snapshot\n *\n * @example\n * ```ts\n * import { DevToolsAdapter } from '@forinda/kickjs-devtools'\n *\n * bootstrap({\n * modules: [UserModule],\n * adapters: [\n * DevToolsAdapter({\n * enabled: process.env.NODE_ENV !== 'production',\n * exposeConfig: true,\n * configPrefixes: ['APP_', 'DATABASE_'],\n * }),\n * ],\n * })\n * ```\n */\nexport const DevToolsAdapter = defineAdapter<DevToolsOptions, DevToolsAdapterExtensions>({\n name: 'DevToolsAdapter',\n defaults: {\n basePath: '/_debug',\n errorRateThreshold: 0.5,\n exposeConfig: false,\n configPrefixes: ['APP_', 'NODE_ENV'],\n },\n build: (options) => {\n const basePath = options.basePath!\n const enabled = options.enabled ?? process.env.NODE_ENV !== 'production'\n const exposeConfig = options.exposeConfig!\n const configPrefixes = options.configPrefixes!\n const errorRateThreshold = options.errorRateThreshold!\n const peerAdapters = options.adapters ?? []\n\n // Secret token guard\n let secret: string | false\n if (options.secret === false) {\n secret = false\n } else if (options.secret) {\n secret = options.secret\n } else {\n secret = randomBytes(16).toString('hex')\n }\n\n // ── Runtime sampler + memory analyzer (kit) ────────────────────\n // Lazily instantiated so an adopter that disables runtime monitoring\n // doesn't pay the perf_hooks histogram cost. Lifecycle: start in\n // `beforeMount`, stop in `shutdown`.\n const runtimeEnabled = options.runtime?.enabled ?? true\n const runtimeSampler = runtimeEnabled\n ? new RuntimeSampler({\n intervalMs: options.runtime?.intervalMs ?? 1000,\n bufferSize: options.runtime?.bufferSize ?? 60,\n })\n : null\n const memoryAnalyzer = runtimeEnabled ? new MemoryAnalyzer() : null\n\n // ── Reactive state ─────────────────────────────────────────────\n const requestCount = ref(0)\n const errorCount = ref(0)\n const clientErrorCount = ref(0)\n const startedAt = ref(Date.now())\n const routeLatency = reactive<Record<string, RouteStats>>({})\n\n const errorRate = computed(() =>\n requestCount.value > 0 ? errorCount.value / requestCount.value : 0,\n )\n\n const uptimeSeconds = computed(() => Math.floor((Date.now() - startedAt.value) / 1000))\n\n // ── Internal mutable state ─────────────────────────────────────\n let routes: RouteInfo[] = []\n let container: Container | null = null\n let appRef: any = null\n const adapterStatuses: Record<string, string> = {}\n let stopErrorWatch: (() => void) | null = null\n\n // Watch error rate — log warnings when elevated\n if (options.onErrorRateExceeded) {\n const callback = options.onErrorRateExceeded\n stopErrorWatch = watch(errorRate, (rate) => {\n if (rate > errorRateThreshold) {\n callback(rate)\n }\n })\n } else {\n stopErrorWatch = watch(errorRate, (rate) => {\n if (rate > errorRateThreshold) {\n log.warn(`Error rate elevated: ${(rate * 100).toFixed(1)}%`)\n }\n })\n }\n\n /**\n * Find the dashboard's public directory. Prefers the new Solid SPA\n * (public/spa/, shipped from PR 4 of §23); falls back to the legacy\n * Vue+Tailwind dashboard (public/devtools/) for environments that\n * haven't run `pnpm --filter @forinda/kickjs-devtools build:spa`.\n */\n const resolvePublicDir = (): string | null => {\n const thisDir = dirname(fileURLToPath(import.meta.url))\n const candidates = [\n join(thisDir, '..', 'public', 'spa'), // dist/ -> public/spa\n join(thisDir, '..', '..', 'public', 'spa'), // src/ -> public/spa\n join(thisDir, '..', 'public', 'devtools'), // legacy Vue dashboard\n join(thisDir, '..', '..', 'public', 'devtools'), // legacy from src/\n ]\n for (const dir of candidates) {\n if (existsSync(join(dir, 'index.html'))) return dir\n }\n return null\n }\n\n /**\n * Resolve peer adapters at request time. Prefers live adapters from the\n * Application registry (survives HMR rebuild) and falls back to the\n * constructor-provided refs.\n */\n const getPeerAdapters = (): any[] => {\n const kickApp = appRef?.__kickApp\n if (kickApp && typeof kickApp.getAdapters === 'function') {\n return kickApp.getAdapters()\n }\n return peerAdapters\n }\n\n return {\n // ── Extensions (TExtra) ───────────────────────────────────────\n requestCount,\n errorCount,\n clientErrorCount,\n startedAt,\n errorRate,\n uptimeSeconds,\n routeLatency,\n runtimeSampler,\n memoryAnalyzer,\n\n // ── DevTools introspection (architecture.md §23) ─────────────\n // Cheap snapshot — counters + flags only. Anything that requires\n // a container walk or DB hit belongs in the per-endpoint RPCs\n // (`/_debug/container`, `/_debug/graph`), not here.\n introspect(): IntrospectionSnapshot {\n return {\n protocolVersion: PROTOCOL_VERSION,\n name: 'DevToolsAdapter',\n kind: 'adapter',\n state: {\n basePath,\n enabled,\n runtimeEnabled,\n secret: secret === false ? false : 'present',\n },\n metrics: {\n requestCount: requestCount.value,\n serverErrors: errorCount.value,\n clientErrors: clientErrorCount.value,\n uptimeSeconds: uptimeSeconds.value,\n routesTracked: routes.length,\n },\n }\n },\n\n // ── Lifecycle ─────────────────────────────────────────────────\n\n beforeMount({ app, container: containerArg }) {\n if (!enabled) return\n\n appRef = app\n container = containerArg\n startedAt.value = Date.now()\n // Clear routes on rebuild/restart to prevent HMR duplication\n routes = []\n adapterStatuses['DevToolsAdapter'] = 'running'\n\n // Start the runtime sampler + memory analyzer here (rather than\n // at construction) so test harnesses that build the adapter but\n // never mount it don't leak interval timers.\n runtimeSampler?.start()\n memoryAnalyzer?.start()\n\n const router = Router()\n\n // ── Access guard — require secret token ──────────────────\n if (secret !== false) {\n const token = secret\n router.use((req: Request, res: Response, next: NextFunction) => {\n const provided = req.headers['x-devtools-token'] ?? req.query?.token\n if (provided === token) return next()\n // Allow the dashboard HTML itself (it will include the token in API calls)\n if (req.path === '/' && req.method === 'GET' && !req.query?.token) {\n return next() // serve dashboard, it handles auth via token\n }\n // Serve static assets for the dashboard (js files)\n if (req.path.endsWith('.js') || req.path.endsWith('.css')) {\n return next()\n }\n res.status(403).json({ error: 'Forbidden — invalid or missing devtools token' })\n })\n }\n\n router.get('/routes', (_req: Request, res: Response) => {\n res.json({ routes })\n })\n\n router.get('/container', (_req: Request, res: Response) => {\n const registrations = container?.getRegistrations() ?? []\n res.json({ registrations, count: registrations.length })\n })\n\n router.get('/metrics', (_req: Request, res: Response) => {\n // Build latency with percentiles, omitting raw samples from response\n const latency: Record<string, any> = {}\n for (const [key, stats] of Object.entries(routeLatency)) {\n const { samples: _, ...rest } = stats\n latency[key] = { ...rest, ...computePercentiles(stats) }\n }\n res.json({\n requests: requestCount.value,\n serverErrors: errorCount.value,\n clientErrors: clientErrorCount.value,\n errorRate: errorRate.value,\n uptimeSeconds: uptimeSeconds.value,\n startedAt: new Date(startedAt.value).toISOString(),\n routeLatency: latency,\n })\n })\n\n router.get('/health', (_req: Request, res: Response) => {\n const healthy = errorRate.value < errorRateThreshold\n const status = healthy ? 'healthy' : 'degraded'\n\n res.status(healthy ? 200 : 503).json({\n status,\n errorRate: errorRate.value,\n uptime: uptimeSeconds.value,\n adapters: adapterStatuses,\n })\n })\n\n router.get('/state', (_req: Request, res: Response) => {\n const wsAdapter = getPeerAdapters().find(\n (a) => a.name === 'WsAdapter' && typeof a.getStats === 'function',\n )\n res.json({\n reactive: {\n requestCount: requestCount.value,\n errorCount: errorCount.value,\n clientErrorCount: clientErrorCount.value,\n errorRate: errorRate.value,\n uptimeSeconds: uptimeSeconds.value,\n startedAt: new Date(startedAt.value).toISOString(),\n },\n routes: routes.length,\n container: container?.getRegistrations().length ?? 0,\n routeLatency,\n ...(wsAdapter ? { ws: wsAdapter.getStats() } : {}),\n })\n })\n\n // ── Tier-1 runtime monitoring (architecture.md §23) ─────────\n // Returns the latest RuntimeSnapshot + a composite MemoryHealth\n // computed from the sampler's ring buffer. Returns 404 when the\n // sampler is disabled so adopters can distinguish \"off\" from\n // \"starting up\".\n router.get('/runtime', (_req: Request, res: Response) => {\n if (!runtimeSampler || !memoryAnalyzer) {\n res.status(404).json({ error: 'runtime sampler disabled — set runtime.enabled = true' })\n return\n }\n const latest = runtimeSampler.latest()\n const history = runtimeSampler.history()\n const health = memoryAnalyzer.health(history)\n res.json({\n protocolVersion: PROTOCOL_VERSION,\n latest,\n history,\n health,\n })\n })\n\n // ── SSE: live runtime snapshots (architecture.md §23) ───────\n // Pushes the latest RuntimeSnapshot every `intervalMs`. SSE\n // (not WebSocket) avoids the http.Server `upgrade`-event\n // coordination cost — see devtools-flows.md §3 for rationale.\n router.get('/runtime/stream', (req: Request, res: Response) => {\n if (!runtimeSampler) {\n res.status(404).json({ error: 'runtime sampler disabled' })\n return\n }\n openSseStream(req, res)\n const intervalMs = options.runtime?.intervalMs ?? 1000\n const tick = (): void => {\n const snap = runtimeSampler.latest()\n if (snap) writeSseEvent(res, snap)\n }\n tick()\n const interval = setInterval(tick, intervalMs)\n const heartbeat = setInterval(() => res.write(': heartbeat\\n\\n'), 30_000)\n req.on('close', () => {\n clearInterval(interval)\n clearInterval(heartbeat)\n })\n })\n\n // ── SSE: memory health composite (architecture.md §23) ──────\n router.get('/memory/stream', (req: Request, res: Response) => {\n if (!runtimeSampler || !memoryAnalyzer) {\n res.status(404).json({ error: 'runtime sampler disabled' })\n return\n }\n openSseStream(req, res)\n const intervalMs = options.runtime?.intervalMs ?? 1000\n const tick = (): void => {\n const snap = runtimeSampler.latest()\n if (!snap) return\n const health = memoryAnalyzer.health(runtimeSampler.history())\n writeSseEvent(res, { snapshot: snap, health })\n }\n tick()\n const interval = setInterval(tick, intervalMs)\n const heartbeat = setInterval(() => res.write(': heartbeat\\n\\n'), 30_000)\n req.on('close', () => {\n clearInterval(interval)\n clearInterval(heartbeat)\n })\n })\n\n // ── Heap snapshot — Tier 3 monitoring (architecture.md §23) ─\n // POST /_debug/memory/snapshot — captures a V8 heap snapshot\n // and streams the resulting .heapsnapshot file back as\n // application/json with Content-Disposition. Snapshot capture\n // blocks the event loop while writing (multi-second pause for\n // large heaps), so the endpoint enforces single-flight via a\n // module-scoped flag — concurrent calls return 503.\n //\n // The temp file is deleted as soon as the response stream\n // completes (success or error). Worst case if the process\n // dies mid-snapshot is a stranded file in `os.tmpdir()`,\n // which the OS cleans up on next boot.\n router.post('/memory/snapshot', (_req: Request, res: Response) => {\n if (snapshotInProgress) {\n res\n .status(503)\n .json({ error: 'heap snapshot already in progress — wait for it to complete' })\n return\n }\n snapshotInProgress = true\n const startedAt = Date.now()\n const filename = `kickjs-heap-${new Date().toISOString().replace(/[:.]/g, '-')}.heapsnapshot`\n const targetPath = join(tmpdir(), filename)\n\n let written: string\n try {\n // writeHeapSnapshot is synchronous — the event loop is\n // blocked for the duration. There's no async variant in\n // the v8 module today; if one ships, swap here.\n written = writeHeapSnapshot(targetPath)\n } catch (err) {\n snapshotInProgress = false\n log.error({ err }, 'heap snapshot capture failed')\n res\n .status(500)\n .json({ error: 'snapshot capture failed', message: (err as Error).message })\n return\n }\n\n let size = 0\n try {\n size = statSync(written).size\n } catch {\n /* size header is best-effort */\n }\n const elapsedMs = Date.now() - startedAt\n log.info(\n `Heap snapshot captured: ${written} (${(size / 1024 / 1024).toFixed(1)} MiB in ${elapsedMs}ms)`,\n )\n\n res.setHeader('Content-Type', 'application/json')\n res.setHeader('Content-Disposition', `attachment; filename=\"${filename}\"`)\n if (size > 0) res.setHeader('Content-Length', String(size))\n res.setHeader('X-Snapshot-Capture-Ms', String(elapsedMs))\n\n const cleanup = (): void => {\n unlink(written, (err) => {\n if (err) log.warn(`Failed to delete heap snapshot ${written}: ${err.message}`)\n snapshotInProgress = false\n })\n }\n const stream = createReadStream(written)\n stream.on('end', cleanup)\n stream.on('error', (err) => {\n log.error({ err }, 'heap snapshot stream failed')\n if (!res.headersSent) res.status(500).end()\n cleanup()\n })\n // Defensive: if the client disconnects mid-download, abort\n // the stream + run cleanup so the temp file doesn't linger.\n res.on('close', () => {\n stream.destroy()\n // If the stream already fired 'end', cleanup already ran\n // — the unlink is idempotent enough that running twice\n // just yields ENOENT which we ignore in cleanup.\n })\n stream.pipe(res)\n })\n\n // ── Force GC — Tier 3 monitoring (architecture.md §23) ──────\n // POST /_debug/memory/gc — calls `global.gc()` if Node was\n // started with --expose-gc, returning before/after heap size\n // so the panel can show how much was reclaimed. Useful for\n // confirming \"is this growth real or just delayed GC?\".\n //\n // Returns 412 Precondition Failed (with hint) when the flag\n // wasn't set, so the SPA can show \"Run with --expose-gc to\n // enable this button\" instead of a generic 5xx.\n router.post('/memory/gc', (_req: Request, res: Response) => {\n const gc = (globalThis as { gc?: () => void }).gc\n if (typeof gc !== 'function') {\n res.status(412).json({\n error: 'global.gc unavailable — start Node with --expose-gc to enable this endpoint',\n })\n return\n }\n const before = process.memoryUsage().heapUsed\n const startedAt = Date.now()\n try {\n gc()\n } catch (err) {\n res.status(500).json({\n error: 'forced GC failed',\n message: err instanceof Error ? err.message : String(err),\n })\n return\n }\n const after = process.memoryUsage().heapUsed\n const reclaimedBytes = Math.max(0, before - after)\n const elapsedMs = Date.now() - startedAt\n log.info(\n `Forced GC reclaimed ${(reclaimedBytes / 1024 / 1024).toFixed(2)} MiB in ${elapsedMs}ms`,\n )\n res.json({ before, after, reclaimedBytes, elapsedMs })\n })\n\n // ── Custom-tab discovery (architecture.md §23) ──────────────\n // Walks every plugin/adapter `devtoolsTabs?()` contribution\n // and serves the deduped + validated list. The SPA fetches\n // this once at boot to render dynamic tabs after the four\n // built-ins.\n router.get('/tabs', (_req: Request, res: Response) => {\n const kickApp = appRef?.__kickApp as TopologyApplicationLike | undefined\n if (!kickApp) {\n res.status(503).json({ error: 'tabs unavailable — application surface not exposed' })\n return\n }\n res.json(collectDevtoolsTabs(kickApp))\n })\n\n // ── Topology RPC (architecture.md §23) ──────────────────────\n // Aggregates plugins + adapters + contributors + DI tokens\n // into one snapshot; calls each primitive's introspect() in\n // parallel with a per-call timeout so a misbehaving adapter\n // can't block the endpoint. Errors are collected, not thrown.\n router.get('/topology', async (_req: Request, res: Response) => {\n if (!container) {\n res.status(503).json({ error: 'topology unavailable — container not bound yet' })\n return\n }\n const kickApp = appRef?.__kickApp as TopologyApplicationLike | undefined\n if (!kickApp) {\n res\n .status(503)\n .json({ error: 'topology unavailable — application surface not exposed' })\n return\n }\n try {\n const snapshot = await collectTopologySnapshot({ app: kickApp, container })\n res.json(snapshot)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n res.status(500).json({ error: 'topology collection failed', message })\n }\n })\n\n router.get('/ws', (_req: Request, res: Response) => {\n const wsAdapter = getPeerAdapters().find(\n (a) => a.name === 'WsAdapter' && typeof a.getStats === 'function',\n )\n if (!wsAdapter) {\n res.json({ enabled: false, message: 'WsAdapter not found' })\n return\n }\n res.json({ enabled: true, ...wsAdapter.getStats() })\n })\n\n router.get('/queues', async (_req: Request, res: Response) => {\n const queueAdapter = getPeerAdapters().find(\n (a) => a.name === 'QueueAdapter' && typeof a.getQueueNames === 'function',\n )\n if (!queueAdapter) {\n res.json({ enabled: false, message: 'QueueAdapter not found' })\n return\n }\n try {\n const names: string[] = queueAdapter.getQueueNames?.() ?? []\n const queues: any[] = []\n for (const name of names) {\n const stats = await queueAdapter.getQueueStats?.(name)\n queues.push({ name, ...stats })\n }\n res.json({ enabled: true, queues })\n } catch {\n res.json({ enabled: true, queues: [], error: 'Failed to fetch queue stats' })\n }\n })\n\n // ── Dependency graph ────────────────────────────────────────\n router.get('/graph', (_req: Request, res: Response) => {\n const registrations = container?.getRegistrations() ?? []\n const nodes = registrations\n .filter((r) => !r.token.startsWith('__hmr__'))\n .map((r) => ({\n id: r.token,\n kind: r.kind,\n scope: r.scope,\n resolveCount: r.resolveCount,\n }))\n const nodeIds = new Set(nodes.map((n) => n.id))\n const edges: Array<{ from: string; to: string }> = []\n for (const r of registrations) {\n if (r.token.startsWith('__hmr__')) continue\n for (const dep of r.dependencies) {\n if (nodeIds.has(dep)) {\n edges.push({ from: r.token, to: dep })\n }\n }\n }\n res.json({ nodes, edges })\n })\n\n // ── SSE stream for real-time updates ────────────────────────\n router.get('/stream', (req: Request, res: Response) => {\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n })\n\n const sendMetrics = () => {\n const data = {\n type: 'metrics',\n requestCount: requestCount.value,\n errorCount: errorCount.value,\n clientErrorCount: clientErrorCount.value,\n errorRate: errorRate.value,\n uptimeSeconds: uptimeSeconds.value,\n }\n res.write(`data: ${JSON.stringify(data)}\\n\\n`)\n }\n sendMetrics()\n\n const unsubContainer = container?.onChange?.((changes) => {\n res.write(\n `data: ${JSON.stringify({ type: 'container', changes, timestamp: Date.now() })}\\n\\n`,\n )\n sendMetrics()\n })\n\n const stopRequestWatch = watch(requestCount, () => sendMetrics())\n const stopErrWatch = watch(errorCount, () => sendMetrics())\n\n const heartbeat = setInterval(() => {\n res.write(`: heartbeat\\n\\n`)\n }, 30000)\n\n req.on('close', () => {\n unsubContainer?.()\n stopRequestWatch()\n stopErrWatch()\n clearInterval(heartbeat)\n })\n })\n\n if (exposeConfig) {\n router.get('/config', (_req: Request, res: Response) => {\n const config: Record<string, string> = {}\n for (const [key, value] of Object.entries(process.env)) {\n if (value === undefined) continue\n const allowed = configPrefixes.some((prefix) => key.startsWith(prefix))\n config[key] = allowed ? value : '[REDACTED]'\n }\n res.json({ config })\n })\n }\n\n // Dashboard UI — Vue + Tailwind from public/devtools directory\n const publicDir = resolvePublicDir()\n if (publicDir) {\n router.use(serveStatic(publicDir))\n\n const indexHtml = readFileSync(join(publicDir, 'index.html'), 'utf-8')\n router.get('/', (_req: Request, res: Response) => {\n const html = indexHtml.replace('<body', `<body data-base=\"${basePath}\"`)\n res.type('html').send(html)\n })\n } else {\n router.get('/', (_req: Request, res: Response) => {\n res.type('html').send('<h1>DevTools: public directory not found</h1>')\n })\n }\n\n app.use(basePath, router)\n\n if (secret) {\n log.info(`DevTools mounted at ${basePath} [token: ${secret}]`)\n log.info(`Access: ${basePath}?token=${secret}`)\n } else {\n log.info(`DevTools mounted at ${basePath} [no guard]`)\n }\n },\n\n middleware(): AdapterMiddleware[] {\n if (!enabled) return []\n\n return [\n {\n handler: (req: Request, res: Response, next: NextFunction) => {\n const start = Date.now()\n requestCount.value++\n\n res.on('finish', () => {\n if (res.statusCode >= 500) errorCount.value++\n else if (res.statusCode >= 400) clientErrorCount.value++\n\n const routeKey = `${req.method} ${req.route?.path ?? req.path}`\n const elapsed = Date.now() - start\n\n if (!routeLatency[routeKey]) {\n routeLatency[routeKey] = {\n count: 0,\n totalMs: 0,\n minMs: Infinity,\n maxMs: 0,\n samples: [],\n }\n }\n const stats = routeLatency[routeKey]\n stats.count++\n stats.totalMs += elapsed\n stats.minMs = Math.min(stats.minMs, elapsed)\n stats.maxMs = Math.max(stats.maxMs, elapsed)\n stats.samples.push(elapsed)\n if (stats.samples.length > MAX_SAMPLES) stats.samples.shift()\n })\n\n next()\n },\n phase: 'beforeGlobal',\n },\n ]\n },\n\n onRouteMount(controllerClass, mountPath) {\n if (!enabled) return\n\n const collectedRoutes = getClassMeta<\n Array<{ method: string; path: string; handlerName: string }>\n >(METADATA.ROUTES, controllerClass, [])\n\n const classMiddleware = getClassMeta<any[]>(METADATA.CLASS_MIDDLEWARES, controllerClass, [])\n\n for (const route of collectedRoutes) {\n const methodMiddleware = getMethodMeta<any[]>(\n METADATA.METHOD_MIDDLEWARES,\n controllerClass.prototype,\n route.handlerName,\n [],\n )\n\n routes.push({\n method: route.method.toUpperCase(),\n path: `${mountPath}${route.path === '/' ? '' : route.path}`,\n controller: controllerClass.name,\n handler: route.handlerName,\n middleware: [\n ...classMiddleware.map((m: any) => m.name || 'anonymous'),\n ...methodMiddleware.map((m: any) => m.name || 'anonymous'),\n ],\n })\n }\n },\n\n afterStart() {\n if (!enabled) return\n log.info(\n `DevTools ready — ${routes.length} routes tracked, ` +\n `${container?.getRegistrations().length ?? 0} DI bindings`,\n )\n },\n\n shutdown() {\n stopErrorWatch?.()\n runtimeSampler?.stop()\n memoryAnalyzer?.stop()\n adapterStatuses['DevToolsAdapter'] = 'stopped'\n },\n }\n },\n})\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAyDA,MAAM,gCAAgC;;;;;;;;AAStC,eAAsB,wBACpB,MAC2B;CAC3B,MAAM,EAAE,KAAK,WAAW,sBAAsB,kCAAkC;CAChF,MAAM,SAA0B,EAAE;CAElC,MAAM,UAAU,MAAM,QAAQ,IAC5B,IAAI,YAAY,CAAC,KAAK,MAAM,YAAY,GAAG,UAAU,qBAAqB,OAAO,CAAC,CACnF;CACD,MAAM,WAAW,MAAM,QAAQ,IAC7B,IAAI,aAAa,CAAC,KAAK,MAAM,YAAY,GAAG,WAAW,qBAAqB,OAAO,CAAC,CACrF;AAED,QAAO;EACL,iBAAiB;EACjB,WAAW,KAAK,KAAK;EACrB;EACA;EACA,cAAc,oBAAoB,IAAI;EACtC,UAAU,cAAc,UAAU;EAClC;EACD;;;;;;;AAQH,eAAe,YACb,WACA,MACA,WACA,QACgC;CAChC,MAAM,OAAO,UAAU,QAAQ;CAC/B,MAAM,OAA8B;EAClC,iBAAiB;EACjB;EACA;EACD;AACD,KAAI,OAAO,UAAU,eAAe,WAAY,QAAO;AAEvD,KAAI;EACF,MAAM,SAAS,MAAM,QAAQ,KAAK,CAChC,QAAQ,QAAQ,UAAU,YAAY,CAAC,EACvC,IAAI,SAAgB,GAAG,WACrB,iBACQ,uBAAO,IAAI,MAAM,gCAAgC,UAAU,IAAI,CAAC,EACtE,UACD,CACF,CACF,CAAC;AACF,MAAI,UAAU,OAAO,WAAW,UAAU;GAKxC,MAAM,OAAO;AACb,UAAO;IACL,iBAAiB;IACjB,MAAM,KAAK,QAAQ;IACnB,MAAM,KAAK,QAAQ;IACnB,SAAS,KAAK;IACd,OAAO,KAAK;IACZ,QAAQ,KAAK;IACb,SAAS,KAAK;IACd,aAAa,KAAK;IACnB;;AAEH,SAAO;UACA,KAAK;AACZ,SAAO,KAAK;GACV;GACA;GACA,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;GAC1D,CAAC;AACF,SAAO;;;;AAKX,SAAS,cAAc,WAA4C;AACjE,QAAO,UACJ,kBAAkB,CAClB,QAAQ,MAAM,CAAC,EAAE,MAAM,WAAW,UAAU,CAAC,CAC7C,KAAK,OAAO;EACX,OAAO,EAAE;EACT,OAAO,EAAE;EACT,MAAM,EAAE;EACR,cAAc,EAAE;EACjB,EAAE;;;;;;;;;;;;;AAcP,SAAS,oBAAoB,KAA0D;CACrF,MAAM,uBAAO,IAAI,KAAuC;AAExD,KAAI,OAAO,IAAI,oBAAoB,YAAY;AAC7C,OAAK,MAAM,KAAK,IAAI,iBAAiB,EAAE;AACrC,OAAI,KAAK,IAAI,EAAE,IAAI,CAAE;GAKrB,MAAM,SACJ,EAAE,WAAW,WAAW,WAAW;AACrC,QAAK,IAAI,EAAE,KAAK;IACd,KAAK,EAAE;IACP,QAAQ;IACR,WAAW,EAAE;IACd,CAAC;;AAEJ,SAAO,CAAC,GAAG,KAAK,QAAQ,CAAC;;CAI3B,MAAM,UACJ,MACA,WACS;AACT,MAAI,CAAC,KAAM;AACX,OAAK,MAAM,OAAO,MAAM;GACtB,MAAM,IAAI;GACV,MAAM,MAAM,OAAO,EAAE,QAAQ,WAAW,EAAE,MAAM;AAChD,OAAI,CAAC,OAAO,KAAK,IAAI,IAAI,CAAE;AAC3B,QAAK,IAAI,KAAK;IACZ;IACA;IACA,WAAW,MAAM,QAAQ,EAAE,UAAU,GAAG,EAAE,YAAY,EAAE;IACzD,CAAC;;;AAIN,MAAK,MAAM,UAAU,IAAI,YAAY,CACnC,QAAO,OAAO,gBAAgB,EAAE,UAAU;AAE5C,MAAK,MAAM,WAAW,IAAI,aAAa,CACrC,QAAO,QAAQ,gBAAgB,EAAE,UAAU;AAG7C,QAAO,CAAC,GAAG,KAAK,QAAQ,CAAC;;;;ACjM3B,MAAM,mBAAmB,IAAI,IAAI;CAAC;CAAU;CAAU;CAAO,CAAC;;;;;;AAO9D,SAAgB,oBAAoB,KAAkD;CACpF,MAAM,OAAgC,EAAE;CACxC,MAAM,uBAAO,IAAI,KAAqB;CACtC,MAAM,SAAoD,EAAE;CAE5D,MAAM,UAAU,YAAoB,QAAuB;AACzD,MAAI,CAAC,MAAM,QAAQ,IAAI,EAAE;AACvB,UAAO,KAAK;IAAE,QAAQ;IAAY,QAAQ;IAA0C,CAAC;AACrF;;AAEF,OAAK,MAAM,SAAS,KAAK;GACvB,MAAM,aAAa,YAAY,MAAM;AACrC,OAAI,CAAC,WAAW,IAAI;AAClB,WAAO,KAAK;KAAE,QAAQ;KAAY,QAAQ,WAAW;KAAQ,CAAC;AAC9D;;GAEF,MAAM,MAAM,WAAW;GACvB,MAAM,QAAQ,KAAK,IAAI,IAAI,GAAG;AAC9B,OAAI,OAAO;AACT,WAAO,KAAK;KACV,QAAQ;KACR,QAAQ,WAAW,IAAI,GAAG,0BAA0B,MAAM;KAC3D,CAAC;AACF;;AAEF,QAAK,IAAI,IAAI,IAAI,WAAW;AAC5B,QAAK,KAAK,IAAI;;;AAIlB,MAAK,MAAM,UAAU,IAAI,YAAY,EAAE;AACrC,MAAI,OAAO,OAAO,iBAAiB,WAAY;AAC/C,MAAI;AACF,UAAO,OAAO,QAAQ,oBAAoB,OAAO,cAAc,CAAC;WACzD,KAAK;AACZ,UAAO,KAAK;IACV,QAAQ,OAAO,QAAQ;IACvB,QAAQ,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;IACzD,CAAC;;;AAGN,MAAK,MAAM,WAAW,IAAI,aAAa,EAAE;AACvC,MAAI,OAAO,QAAQ,iBAAiB,WAAY;AAChD,MAAI;AACF,UAAO,QAAQ,QAAQ,qBAAqB,QAAQ,cAAc,CAAC;WAC5D,KAAK;AACZ,UAAO,KAAK;IACV,QAAQ,QAAQ,QAAQ;IACxB,QAAQ,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;IACzD,CAAC;;;AAIN,QAAO;EAAE;EAAM;EAAQ;;;;;;;;AAmBzB,SAAS,YAAY,KAA6C;AAChE,KAAI,CAAC,OAAO,OAAO,QAAQ,SACzB,QAAO;EAAE,IAAI;EAAO,QAAQ;EAA8B;CAE5D,MAAM,MAAM;AACZ,KAAI,OAAO,IAAI,OAAO,YAAY,IAAI,GAAG,WAAW,EAClD,QAAO;EAAE,IAAI;EAAO,QAAQ;EAAqC;AAEnE,KAAI,OAAO,IAAI,UAAU,YAAY,IAAI,MAAM,WAAW,EACxD,QAAO;EAAE,IAAI;EAAO,QAAQ,QAAQ,IAAI,GAAG;EAAsC;CAEnF,MAAM,OAAO,IAAI;AACjB,KAAI,CAAC,QAAQ,OAAO,SAAS,SAC3B,QAAO;EAAE,IAAI;EAAO,QAAQ,QAAQ,IAAI,GAAG;EAA6B;AAE1E,KAAI,OAAO,KAAK,SAAS,YAAY,CAAC,iBAAiB,IAAI,KAAK,KAAK,CACnE,QAAO;EACL,IAAI;EACJ,QAAQ,QAAQ,IAAI,GAAG;EACxB;AAEH,SAAQ,KAAK,MAAb;EACE,KAAK;AACH,OAAI,OAAO,KAAK,QAAQ,YAAY,KAAK,IAAI,WAAW,EACtD,QAAO;IAAE,IAAI;IAAO,QAAQ,QAAQ,IAAI,GAAG;IAA0C;AAEvF;EACF,KAAK;AACH,OAAI,OAAO,KAAK,SAAS,SACvB,QAAO;IAAE,IAAI;IAAO,QAAQ,QAAQ,IAAI,GAAG;IAAoC;AAEjF;EACF,KAAK;AACH,OAAI,CAAC,MAAM,QAAQ,KAAK,QAAQ,CAC9B,QAAO;IAAE,IAAI;IAAO,QAAQ,QAAQ,IAAI,GAAG;IAAwC;AAErF;;AAEJ,QAAO;EAAE,IAAI;EAAM,KAAK;EAAyC;;;;AC7GnE,MAAM,MAAM,aAAa,WAAW;AAqBpC,MAAM,cAAc;;AAGpB,SAAS,WAAW,QAAkB,GAAmB;AACvD,KAAI,OAAO,WAAW,EAAG,QAAO;CAChC,MAAM,MAAM,KAAK,KAAK,IAAI,OAAO,OAAO,GAAG;AAC3C,QAAO,OAAO,KAAK,IAAI,GAAG,IAAI;;;AAIhC,SAAS,mBAAmB,OAA8D;CACxF,MAAM,SAAS,CAAC,GAAG,MAAM,QAAQ,CAAC,MAAM,GAAG,MAAM,IAAI,EAAE;AACvD,QAAO;EACL,KAAK,WAAW,QAAQ,GAAI;EAC5B,KAAK,WAAW,QAAQ,IAAK;EAC7B,KAAK,WAAW,QAAQ,IAAK;EAC9B;;;;;;;AAQH,SAAS,cAAc,KAAc,KAAqB;AACxD,KAAI,UAAU,KAAK;EACjB,gBAAgB;EAChB,iBAAiB;EACjB,YAAY;EACZ,qBAAqB;EACtB,CAAC;AACF,KAAI,gBAAgB;;;AAQtB,SAAS,cAAc,KAAe,SAAwB;AAC5D,KAAI,MAAM,SAAS,KAAK,UAAU,QAAQ,CAAC,MAAM;;;;;;;;;;;;;;AAenD,IAAI,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgHzB,MAAa,kBAAkB,cAA0D;CACvF,MAAM;CACN,UAAU;EACR,UAAU;EACV,oBAAoB;EACpB,cAAc;EACd,gBAAgB,CAAC,QAAQ,WAAW;EACrC;CACD,QAAQ,YAAY;EAClB,MAAM,WAAW,QAAQ;EACzB,MAAM,UAAU,QAAQ,WAAW,QAAQ,IAAI,aAAa;EAC5D,MAAM,eAAe,QAAQ;EAC7B,MAAM,iBAAiB,QAAQ;EAC/B,MAAM,qBAAqB,QAAQ;EACnC,MAAM,eAAe,QAAQ,YAAY,EAAE;EAG3C,IAAI;AACJ,MAAI,QAAQ,WAAW,MACrB,UAAS;WACA,QAAQ,OACjB,UAAS,QAAQ;MAEjB,UAAS,YAAY,GAAG,CAAC,SAAS,MAAM;EAO1C,MAAM,iBAAiB,QAAQ,SAAS,WAAW;EACnD,MAAM,iBAAiB,iBACnB,IAAI,eAAe;GACjB,YAAY,QAAQ,SAAS,cAAc;GAC3C,YAAY,QAAQ,SAAS,cAAc;GAC5C,CAAC,GACF;EACJ,MAAM,iBAAiB,iBAAiB,IAAI,gBAAgB,GAAG;EAG/D,MAAM,eAAe,IAAI,EAAE;EAC3B,MAAM,aAAa,IAAI,EAAE;EACzB,MAAM,mBAAmB,IAAI,EAAE;EAC/B,MAAM,YAAY,IAAI,KAAK,KAAK,CAAC;EACjC,MAAM,eAAe,SAAqC,EAAE,CAAC;EAE7D,MAAM,YAAY,eAChB,aAAa,QAAQ,IAAI,WAAW,QAAQ,aAAa,QAAQ,EAClE;EAED,MAAM,gBAAgB,eAAe,KAAK,OAAO,KAAK,KAAK,GAAG,UAAU,SAAS,IAAK,CAAC;EAGvF,IAAI,SAAsB,EAAE;EAC5B,IAAI,YAA8B;EAClC,IAAI,SAAc;EAClB,MAAM,kBAA0C,EAAE;EAClD,IAAI,iBAAsC;AAG1C,MAAI,QAAQ,qBAAqB;GAC/B,MAAM,WAAW,QAAQ;AACzB,oBAAiB,MAAM,YAAY,SAAS;AAC1C,QAAI,OAAO,mBACT,UAAS,KAAK;KAEhB;QAEF,kBAAiB,MAAM,YAAY,SAAS;AAC1C,OAAI,OAAO,mBACT,KAAI,KAAK,yBAAyB,OAAO,KAAK,QAAQ,EAAE,CAAC,GAAG;IAE9D;;;;;;;EASJ,MAAM,yBAAwC;GAC5C,MAAM,UAAU,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC;GACvD,MAAM,aAAa;IACjB,KAAK,SAAS,MAAM,UAAU,MAAM;IACpC,KAAK,SAAS,MAAM,MAAM,UAAU,MAAM;IAC1C,KAAK,SAAS,MAAM,UAAU,WAAW;IACzC,KAAK,SAAS,MAAM,MAAM,UAAU,WAAW;IAChD;AACD,QAAK,MAAM,OAAO,WAChB,KAAI,WAAW,KAAK,KAAK,aAAa,CAAC,CAAE,QAAO;AAElD,UAAO;;;;;;;EAQT,MAAM,wBAA+B;GACnC,MAAM,UAAU,QAAQ;AACxB,OAAI,WAAW,OAAO,QAAQ,gBAAgB,WAC5C,QAAO,QAAQ,aAAa;AAE9B,UAAO;;AAGT,SAAO;GAEL;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GAMA,aAAoC;AAClC,WAAO;KACL,iBAAiB;KACjB,MAAM;KACN,MAAM;KACN,OAAO;MACL;MACA;MACA;MACA,QAAQ,WAAW,QAAQ,QAAQ;MACpC;KACD,SAAS;MACP,cAAc,aAAa;MAC3B,cAAc,WAAW;MACzB,cAAc,iBAAiB;MAC/B,eAAe,cAAc;MAC7B,eAAe,OAAO;MACvB;KACF;;GAKH,YAAY,EAAE,KAAK,WAAW,gBAAgB;AAC5C,QAAI,CAAC,QAAS;AAEd,aAAS;AACT,gBAAY;AACZ,cAAU,QAAQ,KAAK,KAAK;AAE5B,aAAS,EAAE;AACX,oBAAgB,qBAAqB;AAKrC,oBAAgB,OAAO;AACvB,oBAAgB,OAAO;IAEvB,MAAM,SAAS,QAAQ;AAGvB,QAAI,WAAW,OAAO;KACpB,MAAM,QAAQ;AACd,YAAO,KAAK,KAAc,KAAe,SAAuB;AAE9D,WADiB,IAAI,QAAQ,uBAAuB,IAAI,OAAO,WAC9C,MAAO,QAAO,MAAM;AAErC,UAAI,IAAI,SAAS,OAAO,IAAI,WAAW,SAAS,CAAC,IAAI,OAAO,MAC1D,QAAO,MAAM;AAGf,UAAI,IAAI,KAAK,SAAS,MAAM,IAAI,IAAI,KAAK,SAAS,OAAO,CACvD,QAAO,MAAM;AAEf,UAAI,OAAO,IAAI,CAAC,KAAK,EAAE,OAAO,iDAAiD,CAAC;OAChF;;AAGJ,WAAO,IAAI,YAAY,MAAe,QAAkB;AACtD,SAAI,KAAK,EAAE,QAAQ,CAAC;MACpB;AAEF,WAAO,IAAI,eAAe,MAAe,QAAkB;KACzD,MAAM,gBAAgB,WAAW,kBAAkB,IAAI,EAAE;AACzD,SAAI,KAAK;MAAE;MAAe,OAAO,cAAc;MAAQ,CAAC;MACxD;AAEF,WAAO,IAAI,aAAa,MAAe,QAAkB;KAEvD,MAAM,UAA+B,EAAE;AACvC,UAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,aAAa,EAAE;MACvD,MAAM,EAAE,SAAS,GAAG,GAAG,SAAS;AAChC,cAAQ,OAAO;OAAE,GAAG;OAAM,GAAG,mBAAmB,MAAM;OAAE;;AAE1D,SAAI,KAAK;MACP,UAAU,aAAa;MACvB,cAAc,WAAW;MACzB,cAAc,iBAAiB;MAC/B,WAAW,UAAU;MACrB,eAAe,cAAc;MAC7B,WAAW,IAAI,KAAK,UAAU,MAAM,CAAC,aAAa;MAClD,cAAc;MACf,CAAC;MACF;AAEF,WAAO,IAAI,YAAY,MAAe,QAAkB;KACtD,MAAM,UAAU,UAAU,QAAQ;KAClC,MAAM,SAAS,UAAU,YAAY;AAErC,SAAI,OAAO,UAAU,MAAM,IAAI,CAAC,KAAK;MACnC;MACA,WAAW,UAAU;MACrB,QAAQ,cAAc;MACtB,UAAU;MACX,CAAC;MACF;AAEF,WAAO,IAAI,WAAW,MAAe,QAAkB;KACrD,MAAM,YAAY,iBAAiB,CAAC,MACjC,MAAM,EAAE,SAAS,eAAe,OAAO,EAAE,aAAa,WACxD;AACD,SAAI,KAAK;MACP,UAAU;OACR,cAAc,aAAa;OAC3B,YAAY,WAAW;OACvB,kBAAkB,iBAAiB;OACnC,WAAW,UAAU;OACrB,eAAe,cAAc;OAC7B,WAAW,IAAI,KAAK,UAAU,MAAM,CAAC,aAAa;OACnD;MACD,QAAQ,OAAO;MACf,WAAW,WAAW,kBAAkB,CAAC,UAAU;MACnD;MACA,GAAI,YAAY,EAAE,IAAI,UAAU,UAAU,EAAE,GAAG,EAAE;MAClD,CAAC;MACF;AAOF,WAAO,IAAI,aAAa,MAAe,QAAkB;AACvD,SAAI,CAAC,kBAAkB,CAAC,gBAAgB;AACtC,UAAI,OAAO,IAAI,CAAC,KAAK,EAAE,OAAO,yDAAyD,CAAC;AACxF;;KAEF,MAAM,SAAS,eAAe,QAAQ;KACtC,MAAM,UAAU,eAAe,SAAS;KACxC,MAAM,SAAS,eAAe,OAAO,QAAQ;AAC7C,SAAI,KAAK;MACP,iBAAiB;MACjB;MACA;MACA;MACD,CAAC;MACF;AAMF,WAAO,IAAI,oBAAoB,KAAc,QAAkB;AAC7D,SAAI,CAAC,gBAAgB;AACnB,UAAI,OAAO,IAAI,CAAC,KAAK,EAAE,OAAO,4BAA4B,CAAC;AAC3D;;AAEF,mBAAc,KAAK,IAAI;KACvB,MAAM,aAAa,QAAQ,SAAS,cAAc;KAClD,MAAM,aAAmB;MACvB,MAAM,OAAO,eAAe,QAAQ;AACpC,UAAI,KAAM,eAAc,KAAK,KAAK;;AAEpC,WAAM;KACN,MAAM,WAAW,YAAY,MAAM,WAAW;KAC9C,MAAM,YAAY,kBAAkB,IAAI,MAAM,kBAAkB,EAAE,IAAO;AACzE,SAAI,GAAG,eAAe;AACpB,oBAAc,SAAS;AACvB,oBAAc,UAAU;OACxB;MACF;AAGF,WAAO,IAAI,mBAAmB,KAAc,QAAkB;AAC5D,SAAI,CAAC,kBAAkB,CAAC,gBAAgB;AACtC,UAAI,OAAO,IAAI,CAAC,KAAK,EAAE,OAAO,4BAA4B,CAAC;AAC3D;;AAEF,mBAAc,KAAK,IAAI;KACvB,MAAM,aAAa,QAAQ,SAAS,cAAc;KAClD,MAAM,aAAmB;MACvB,MAAM,OAAO,eAAe,QAAQ;AACpC,UAAI,CAAC,KAAM;AAEX,oBAAc,KAAK;OAAE,UAAU;OAAM,QADtB,eAAe,OAAO,eAAe,SAAS,CAAC;OACjB,CAAC;;AAEhD,WAAM;KACN,MAAM,WAAW,YAAY,MAAM,WAAW;KAC9C,MAAM,YAAY,kBAAkB,IAAI,MAAM,kBAAkB,EAAE,IAAO;AACzE,SAAI,GAAG,eAAe;AACpB,oBAAc,SAAS;AACvB,oBAAc,UAAU;OACxB;MACF;AAcF,WAAO,KAAK,qBAAqB,MAAe,QAAkB;AAChE,SAAI,oBAAoB;AACtB,UACG,OAAO,IAAI,CACX,KAAK,EAAE,OAAO,+DAA+D,CAAC;AACjF;;AAEF,0BAAqB;KACrB,MAAM,YAAY,KAAK,KAAK;KAC5B,MAAM,WAAW,gCAAe,IAAI,MAAM,EAAC,aAAa,CAAC,QAAQ,SAAS,IAAI,CAAC;KAC/E,MAAM,aAAa,KAAK,QAAQ,EAAE,SAAS;KAE3C,IAAI;AACJ,SAAI;AAIF,gBAAU,kBAAkB,WAAW;cAChC,KAAK;AACZ,2BAAqB;AACrB,UAAI,MAAM,EAAE,KAAK,EAAE,+BAA+B;AAClD,UACG,OAAO,IAAI,CACX,KAAK;OAAE,OAAO;OAA2B,SAAU,IAAc;OAAS,CAAC;AAC9E;;KAGF,IAAI,OAAO;AACX,SAAI;AACF,aAAO,SAAS,QAAQ,CAAC;aACnB;KAGR,MAAM,YAAY,KAAK,KAAK,GAAG;AAC/B,SAAI,KACF,2BAA2B,QAAQ,KAAK,OAAO,OAAO,MAAM,QAAQ,EAAE,CAAC,UAAU,UAAU,KAC5F;AAED,SAAI,UAAU,gBAAgB,mBAAmB;AACjD,SAAI,UAAU,uBAAuB,yBAAyB,SAAS,GAAG;AAC1E,SAAI,OAAO,EAAG,KAAI,UAAU,kBAAkB,OAAO,KAAK,CAAC;AAC3D,SAAI,UAAU,yBAAyB,OAAO,UAAU,CAAC;KAEzD,MAAM,gBAAsB;AAC1B,aAAO,UAAU,QAAQ;AACvB,WAAI,IAAK,KAAI,KAAK,kCAAkC,QAAQ,IAAI,IAAI,UAAU;AAC9E,4BAAqB;QACrB;;KAEJ,MAAM,SAAS,iBAAiB,QAAQ;AACxC,YAAO,GAAG,OAAO,QAAQ;AACzB,YAAO,GAAG,UAAU,QAAQ;AAC1B,UAAI,MAAM,EAAE,KAAK,EAAE,8BAA8B;AACjD,UAAI,CAAC,IAAI,YAAa,KAAI,OAAO,IAAI,CAAC,KAAK;AAC3C,eAAS;OACT;AAGF,SAAI,GAAG,eAAe;AACpB,aAAO,SAAS;OAIhB;AACF,YAAO,KAAK,IAAI;MAChB;AAWF,WAAO,KAAK,eAAe,MAAe,QAAkB;KAC1D,MAAM,KAAM,WAAmC;AAC/C,SAAI,OAAO,OAAO,YAAY;AAC5B,UAAI,OAAO,IAAI,CAAC,KAAK,EACnB,OAAO,+EACR,CAAC;AACF;;KAEF,MAAM,SAAS,QAAQ,aAAa,CAAC;KACrC,MAAM,YAAY,KAAK,KAAK;AAC5B,SAAI;AACF,UAAI;cACG,KAAK;AACZ,UAAI,OAAO,IAAI,CAAC,KAAK;OACnB,OAAO;OACP,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;OAC1D,CAAC;AACF;;KAEF,MAAM,QAAQ,QAAQ,aAAa,CAAC;KACpC,MAAM,iBAAiB,KAAK,IAAI,GAAG,SAAS,MAAM;KAClD,MAAM,YAAY,KAAK,KAAK,GAAG;AAC/B,SAAI,KACF,wBAAwB,iBAAiB,OAAO,MAAM,QAAQ,EAAE,CAAC,UAAU,UAAU,IACtF;AACD,SAAI,KAAK;MAAE;MAAQ;MAAO;MAAgB;MAAW,CAAC;MACtD;AAOF,WAAO,IAAI,UAAU,MAAe,QAAkB;KACpD,MAAM,UAAU,QAAQ;AACxB,SAAI,CAAC,SAAS;AACZ,UAAI,OAAO,IAAI,CAAC,KAAK,EAAE,OAAO,sDAAsD,CAAC;AACrF;;AAEF,SAAI,KAAK,oBAAoB,QAAQ,CAAC;MACtC;AAOF,WAAO,IAAI,aAAa,OAAO,MAAe,QAAkB;AAC9D,SAAI,CAAC,WAAW;AACd,UAAI,OAAO,IAAI,CAAC,KAAK,EAAE,OAAO,kDAAkD,CAAC;AACjF;;KAEF,MAAM,UAAU,QAAQ;AACxB,SAAI,CAAC,SAAS;AACZ,UACG,OAAO,IAAI,CACX,KAAK,EAAE,OAAO,0DAA0D,CAAC;AAC5E;;AAEF,SAAI;MACF,MAAM,WAAW,MAAM,wBAAwB;OAAE,KAAK;OAAS;OAAW,CAAC;AAC3E,UAAI,KAAK,SAAS;cACX,KAAK;MACZ,MAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;AAChE,UAAI,OAAO,IAAI,CAAC,KAAK;OAAE,OAAO;OAA8B;OAAS,CAAC;;MAExE;AAEF,WAAO,IAAI,QAAQ,MAAe,QAAkB;KAClD,MAAM,YAAY,iBAAiB,CAAC,MACjC,MAAM,EAAE,SAAS,eAAe,OAAO,EAAE,aAAa,WACxD;AACD,SAAI,CAAC,WAAW;AACd,UAAI,KAAK;OAAE,SAAS;OAAO,SAAS;OAAuB,CAAC;AAC5D;;AAEF,SAAI,KAAK;MAAE,SAAS;MAAM,GAAG,UAAU,UAAU;MAAE,CAAC;MACpD;AAEF,WAAO,IAAI,WAAW,OAAO,MAAe,QAAkB;KAC5D,MAAM,eAAe,iBAAiB,CAAC,MACpC,MAAM,EAAE,SAAS,kBAAkB,OAAO,EAAE,kBAAkB,WAChE;AACD,SAAI,CAAC,cAAc;AACjB,UAAI,KAAK;OAAE,SAAS;OAAO,SAAS;OAA0B,CAAC;AAC/D;;AAEF,SAAI;MACF,MAAM,QAAkB,aAAa,iBAAiB,IAAI,EAAE;MAC5D,MAAM,SAAgB,EAAE;AACxB,WAAK,MAAM,QAAQ,OAAO;OACxB,MAAM,QAAQ,MAAM,aAAa,gBAAgB,KAAK;AACtD,cAAO,KAAK;QAAE;QAAM,GAAG;QAAO,CAAC;;AAEjC,UAAI,KAAK;OAAE,SAAS;OAAM;OAAQ,CAAC;aAC7B;AACN,UAAI,KAAK;OAAE,SAAS;OAAM,QAAQ,EAAE;OAAE,OAAO;OAA+B,CAAC;;MAE/E;AAGF,WAAO,IAAI,WAAW,MAAe,QAAkB;KACrD,MAAM,gBAAgB,WAAW,kBAAkB,IAAI,EAAE;KACzD,MAAM,QAAQ,cACX,QAAQ,MAAM,CAAC,EAAE,MAAM,WAAW,UAAU,CAAC,CAC7C,KAAK,OAAO;MACX,IAAI,EAAE;MACN,MAAM,EAAE;MACR,OAAO,EAAE;MACT,cAAc,EAAE;MACjB,EAAE;KACL,MAAM,UAAU,IAAI,IAAI,MAAM,KAAK,MAAM,EAAE,GAAG,CAAC;KAC/C,MAAM,QAA6C,EAAE;AACrD,UAAK,MAAM,KAAK,eAAe;AAC7B,UAAI,EAAE,MAAM,WAAW,UAAU,CAAE;AACnC,WAAK,MAAM,OAAO,EAAE,aAClB,KAAI,QAAQ,IAAI,IAAI,CAClB,OAAM,KAAK;OAAE,MAAM,EAAE;OAAO,IAAI;OAAK,CAAC;;AAI5C,SAAI,KAAK;MAAE;MAAO;MAAO,CAAC;MAC1B;AAGF,WAAO,IAAI,YAAY,KAAc,QAAkB;AACrD,SAAI,UAAU,KAAK;MACjB,gBAAgB;MAChB,iBAAiB;MACjB,YAAY;MACb,CAAC;KAEF,MAAM,oBAAoB;MACxB,MAAM,OAAO;OACX,MAAM;OACN,cAAc,aAAa;OAC3B,YAAY,WAAW;OACvB,kBAAkB,iBAAiB;OACnC,WAAW,UAAU;OACrB,eAAe,cAAc;OAC9B;AACD,UAAI,MAAM,SAAS,KAAK,UAAU,KAAK,CAAC,MAAM;;AAEhD,kBAAa;KAEb,MAAM,iBAAiB,WAAW,YAAY,YAAY;AACxD,UAAI,MACF,SAAS,KAAK,UAAU;OAAE,MAAM;OAAa;OAAS,WAAW,KAAK,KAAK;OAAE,CAAC,CAAC,MAChF;AACD,mBAAa;OACb;KAEF,MAAM,mBAAmB,MAAM,oBAAoB,aAAa,CAAC;KACjE,MAAM,eAAe,MAAM,kBAAkB,aAAa,CAAC;KAE3D,MAAM,YAAY,kBAAkB;AAClC,UAAI,MAAM,kBAAkB;QAC3B,IAAM;AAET,SAAI,GAAG,eAAe;AACpB,wBAAkB;AAClB,wBAAkB;AAClB,oBAAc;AACd,oBAAc,UAAU;OACxB;MACF;AAEF,QAAI,aACF,QAAO,IAAI,YAAY,MAAe,QAAkB;KACtD,MAAM,SAAiC,EAAE;AACzC,UAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,IAAI,EAAE;AACtD,UAAI,UAAU,KAAA,EAAW;AAEzB,aAAO,OADS,eAAe,MAAM,WAAW,IAAI,WAAW,OAAO,CAAC,GAC/C,QAAQ;;AAElC,SAAI,KAAK,EAAE,QAAQ,CAAC;MACpB;IAIJ,MAAM,YAAY,kBAAkB;AACpC,QAAI,WAAW;AACb,YAAO,IAAIA,SAAY,UAAU,CAAC;KAElC,MAAM,YAAY,aAAa,KAAK,WAAW,aAAa,EAAE,QAAQ;AACtE,YAAO,IAAI,MAAM,MAAe,QAAkB;MAChD,MAAM,OAAO,UAAU,QAAQ,SAAS,oBAAoB,SAAS,GAAG;AACxE,UAAI,KAAK,OAAO,CAAC,KAAK,KAAK;OAC3B;UAEF,QAAO,IAAI,MAAM,MAAe,QAAkB;AAChD,SAAI,KAAK,OAAO,CAAC,KAAK,gDAAgD;MACtE;AAGJ,QAAI,IAAI,UAAU,OAAO;AAEzB,QAAI,QAAQ;AACV,SAAI,KAAK,uBAAuB,SAAS,WAAW,OAAO,GAAG;AAC9D,SAAI,KAAK,WAAW,SAAS,SAAS,SAAS;UAE/C,KAAI,KAAK,uBAAuB,SAAS,aAAa;;GAI1D,aAAkC;AAChC,QAAI,CAAC,QAAS,QAAO,EAAE;AAEvB,WAAO,CACL;KACE,UAAU,KAAc,KAAe,SAAuB;MAC5D,MAAM,QAAQ,KAAK,KAAK;AACxB,mBAAa;AAEb,UAAI,GAAG,gBAAgB;AACrB,WAAI,IAAI,cAAc,IAAK,YAAW;gBAC7B,IAAI,cAAc,IAAK,kBAAiB;OAEjD,MAAM,WAAW,GAAG,IAAI,OAAO,GAAG,IAAI,OAAO,QAAQ,IAAI;OACzD,MAAM,UAAU,KAAK,KAAK,GAAG;AAE7B,WAAI,CAAC,aAAa,UAChB,cAAa,YAAY;QACvB,OAAO;QACP,SAAS;QACT,OAAO;QACP,OAAO;QACP,SAAS,EAAE;QACZ;OAEH,MAAM,QAAQ,aAAa;AAC3B,aAAM;AACN,aAAM,WAAW;AACjB,aAAM,QAAQ,KAAK,IAAI,MAAM,OAAO,QAAQ;AAC5C,aAAM,QAAQ,KAAK,IAAI,MAAM,OAAO,QAAQ;AAC5C,aAAM,QAAQ,KAAK,QAAQ;AAC3B,WAAI,MAAM,QAAQ,SAAS,YAAa,OAAM,QAAQ,OAAO;QAC7D;AAEF,YAAM;;KAER,OAAO;KACR,CACF;;GAGH,aAAa,iBAAiB,WAAW;AACvC,QAAI,CAAC,QAAS;IAEd,MAAM,kBAAkB,aAEtB,SAAS,QAAQ,iBAAiB,EAAE,CAAC;IAEvC,MAAM,kBAAkB,aAAoB,SAAS,mBAAmB,iBAAiB,EAAE,CAAC;AAE5F,SAAK,MAAM,SAAS,iBAAiB;KACnC,MAAM,mBAAmB,cACvB,SAAS,oBACT,gBAAgB,WAChB,MAAM,aACN,EAAE,CACH;AAED,YAAO,KAAK;MACV,QAAQ,MAAM,OAAO,aAAa;MAClC,MAAM,GAAG,YAAY,MAAM,SAAS,MAAM,KAAK,MAAM;MACrD,YAAY,gBAAgB;MAC5B,SAAS,MAAM;MACf,YAAY,CACV,GAAG,gBAAgB,KAAK,MAAW,EAAE,QAAQ,YAAY,EACzD,GAAG,iBAAiB,KAAK,MAAW,EAAE,QAAQ,YAAY,CAC3D;MACF,CAAC;;;GAIN,aAAa;AACX,QAAI,CAAC,QAAS;AACd,QAAI,KACF,oBAAoB,OAAO,OAAO,mBAC7B,WAAW,kBAAkB,CAAC,UAAU,EAAE,cAChD;;GAGH,WAAW;AACT,sBAAkB;AAClB,oBAAgB,MAAM;AACtB,oBAAgB,MAAM;AACtB,oBAAgB,qBAAqB;;GAExC;;CAEJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forinda/kickjs-devtools",
|
|
3
|
-
"version": "5.0
|
|
3
|
+
"version": "5.1.0",
|
|
4
4
|
"description": "Development introspection dashboard for KickJS — routes, DI container, metrics, health",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"kickjs",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
},
|
|
63
63
|
"dependencies": {
|
|
64
64
|
"reflect-metadata": "^0.2.2",
|
|
65
|
-
"@forinda/kickjs-devtools-kit": "5.0
|
|
65
|
+
"@forinda/kickjs-devtools-kit": "5.1.0"
|
|
66
66
|
},
|
|
67
67
|
"peerDependencies": {
|
|
68
68
|
"express": "^5.1.0",
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
"vite": "^8.0.9",
|
|
78
78
|
"vite-plugin-solid": "^2.11.12",
|
|
79
79
|
"vitest": "^4.1.5",
|
|
80
|
-
"@forinda/kickjs": "5.0
|
|
80
|
+
"@forinda/kickjs": "5.1.0"
|
|
81
81
|
},
|
|
82
82
|
"publishConfig": {
|
|
83
83
|
"access": "public"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const s of document.querySelectorAll('link[rel="modulepreload"]'))n(s);new MutationObserver(s=>{for(const i of s)if(i.type==="childList")for(const c of i.addedNodes)c.tagName==="LINK"&&c.rel==="modulepreload"&&n(c)}).observe(document,{childList:!0,subtree:!0});function r(s){const i={};return s.integrity&&(i.integrity=s.integrity),s.referrerPolicy&&(i.referrerPolicy=s.referrerPolicy),s.crossOrigin==="use-credentials"?i.credentials="include":s.crossOrigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function n(s){if(s.ep)return;s.ep=!0;const i=r(s);fetch(s.href,i)}})();var L={context:void 0,registry:void 0,effects:void 0,done:!1,getContextId(){return rt(this.context.count)},getNextContextId(){return rt(this.context.count++)}};function rt(e){const t=String(e),r=t.length-1;return L.context.id+(r?String.fromCharCode(96+r):"")+t}function qe(e){L.context=e}function zt(){return{...L.context,id:L.getNextContextId(),count:0}}var Ht=(e,t)=>e===t,Ft=Symbol("solid-track"),Se={equals:Ht},nt=null,_t=kt,F=1,oe=2,yt={owned:null,cleanups:null,context:null,owner:null},T=null,b=null,de=null,re=null,R=null,P=null,N=null,Ae=0;function _e(e,t){const r=R,n=T,s=e.length===0,i=t===void 0?n:t,c=s?yt:{owned:null,cleanups:null,context:i?i.context:null,owner:i},a=s?e:()=>e(()=>Q(()=>Y(c)));T=c,R=null;try{return W(a,!0)}finally{R=r,T=n}}function y(e,t){t=t?Object.assign({},Se,t):Se;const r={value:e,observers:null,observerSlots:null,comparator:t.equals||void 0},n=s=>(typeof s=="function"&&(b&&b.running&&b.sources.has(r)?s=s(r.tValue):s=s(r.value)),St(r,s));return[wt.bind(r),n]}function S(e,t,r){const n=Ie(e,t,!1,F);de&&b&&b.running?P.push(n):ge(n)}function Gt(e,t,r){_t=Jt;const n=Ie(e,t,!1,F),s=je&&Kt(je);s&&(n.suspense=s),(!r||!r.render)&&(n.user=!0),N?N.push(n):ge(n)}function O(e,t,r){r=r?Object.assign({},Se,r):Se;const n=Ie(e,t,!0,0);return n.observers=null,n.observerSlots=null,n.comparator=r.equals||void 0,de&&b&&b.running?(n.tState=F,P.push(n)):ge(n),wt.bind(n)}function Q(e){if(!re&&R===null)return e();const t=R;R=null;try{return re?re.untrack(e):e()}finally{R=t}}function he(e){Gt(()=>Q(e))}function fe(e){return T===null||(T.cleanups===null?T.cleanups=[e]:T.cleanups.push(e)),e}function Vt(e){if(b&&b.running)return e(),b.done;const t=R,r=T;return Promise.resolve().then(()=>{R=t,T=r;let n;return(de||je)&&(n=b||(b={sources:new Set,effects:[],promises:new Set,disposed:new Set,queue:new Set,running:!0}),n.done||(n.done=new Promise(s=>n.resolve=s)),n.running=!0),W(e,!1),R=T=null,n?n.done:void 0})}var[Ys,lt]=y(!1);function Kt(e){let t;return T&&T.context&&(t=T.context[e.id])!==void 0?t:e.defaultValue}var je;function wt(){const e=b&&b.running;if(this.sources&&(e?this.tState:this.state))if((e?this.tState:this.state)===F)ge(this);else{const t=P;P=null,W(()=>ke(this),!1),P=t}if(R){const t=this.observers?this.observers.length:0;R.sources?(R.sources.push(this),R.sourceSlots.push(t)):(R.sources=[this],R.sourceSlots=[t]),this.observers?(this.observers.push(R),this.observerSlots.push(R.sources.length-1)):(this.observers=[R],this.observerSlots=[R.sources.length-1])}return e&&b.sources.has(this)?this.tValue:this.value}function St(e,t,r){let n=b&&b.running&&b.sources.has(e)?e.tValue:e.value;if(!e.comparator||!e.comparator(n,t)){if(b){const s=b.running;(s||!r&&b.sources.has(e))&&(b.sources.add(e),e.tValue=t),s||(e.value=t)}else e.value=t;e.observers&&e.observers.length&&W(()=>{for(let s=0;s<e.observers.length;s+=1){const i=e.observers[s],c=b&&b.running;c&&b.disposed.has(i)||((c?!i.tState:!i.state)&&(i.pure?P.push(i):N.push(i),i.observers&&Ct(i)),c?i.tState=F:i.state=F)}if(P.length>1e6)throw P=[],new Error},!1)}return t}function ge(e){if(!e.fn)return;Y(e);const t=Ae;st(e,b&&b.running&&b.sources.has(e)?e.tValue:e.value,t),b&&!b.running&&b.sources.has(e)&&queueMicrotask(()=>{W(()=>{b&&(b.running=!0),R=T=e,st(e,e.tValue,t),R=T=null},!1)})}function st(e,t,r){let n;const s=T,i=R;R=T=e;try{n=e.fn(t)}catch(c){return e.pure&&(b&&b.running?(e.tState=F,e.tOwned&&e.tOwned.forEach(Y),e.tOwned=void 0):(e.state=F,e.owned&&e.owned.forEach(Y),e.owned=null)),e.updatedAt=r+1,De(c)}finally{R=i,T=s}(!e.updatedAt||e.updatedAt<=r)&&(e.updatedAt!=null&&"observers"in e?St(e,n,!0):b&&b.running&&e.pure?(b.sources.has(e)||(e.value=n),b.sources.add(e),e.tValue=n):e.value=n,e.updatedAt=r)}function Ie(e,t,r,n=F,s){const i={fn:e,state:n,updatedAt:null,owned:null,sources:null,sourceSlots:null,cleanups:null,value:t,owner:T,context:T?T.context:null,pure:r};if(b&&b.running&&(i.state=0,i.tState=n),T===null||T!==yt&&(b&&b.running&&T.pure?T.tOwned?T.tOwned.push(i):T.tOwned=[i]:T.owned?T.owned.push(i):T.owned=[i]),re&&i.fn){const c=i.fn,[a,o]=y(void 0,{equals:!1}),h=re.factory(c,o);fe(()=>h.dispose());let f;const d=()=>Vt(o).then(()=>{f&&(f.dispose(),f=void 0)});i.fn=g=>(a(),b&&b.running?(f||(f=re.factory(c,d)),f.track(g)):h.track(g))}return i}function ce(e){const t=b&&b.running;if((t?e.tState:e.state)===0)return;if((t?e.tState:e.state)===oe)return ke(e);if(e.suspense&&Q(e.suspense.inFallback))return e.suspense.effects.push(e);const r=[e];for(;(e=e.owner)&&(!e.updatedAt||e.updatedAt<Ae);){if(t&&b.disposed.has(e))return;(t?e.tState:e.state)&&r.push(e)}for(let n=r.length-1;n>=0;n--){if(e=r[n],t){let s=e,i=r[n+1];for(;(s=s.owner)&&s!==i;)if(b.disposed.has(s))return}if((t?e.tState:e.state)===F)ge(e);else if((t?e.tState:e.state)===oe){const s=P;P=null,W(()=>ke(e,r[0]),!1),P=s}}}function W(e,t){if(P)return e();let r=!1;t||(P=[]),N?r=!0:N=[],Ae++;try{const n=e();return Qt(r),n}catch(n){r||(N=null),P=null,De(n)}}function Qt(e){if(P&&(de&&b&&b.running?Wt(P):kt(P),P=null),e)return;let t;if(b){if(!b.promises.size&&!b.queue.size){const n=b.sources,s=b.disposed;N.push.apply(N,b.effects),t=b.resolve;for(const i of N)"tState"in i&&(i.state=i.tState),delete i.tState;b=null,W(()=>{for(const i of s)Y(i);for(const i of n){if(i.value=i.tValue,i.owned)for(let c=0,a=i.owned.length;c<a;c++)Y(i.owned[c]);i.tOwned&&(i.owned=i.tOwned),delete i.tValue,delete i.tOwned,i.tState=0}lt(!1)},!1)}else if(b.running){b.running=!1,b.effects.push.apply(b.effects,N),N=null,lt(!0);return}}const r=N;N=null,r.length&&W(()=>_t(r),!1),t&&t()}function kt(e){for(let t=0;t<e.length;t++)ce(e[t])}function Wt(e){for(let t=0;t<e.length;t++){const r=e[t],n=b.queue;n.has(r)||(n.add(r),de(()=>{n.delete(r),W(()=>{b.running=!0,ce(r)},!1),b&&(b.running=!1)}))}}function Jt(e){let t,r=0;for(t=0;t<e.length;t++){const n=e[t];n.user?e[r++]=n:ce(n)}if(L.context){if(L.count){L.effects||(L.effects=[]),L.effects.push(...e.slice(0,r));return}qe()}for(L.effects&&(L.done||!L.count)&&(e=[...L.effects,...e],r+=L.effects.length,delete L.effects),t=0;t<r;t++)ce(e[t])}function ke(e,t){const r=b&&b.running;r?e.tState=0:e.state=0;for(let n=0;n<e.sources.length;n+=1){const s=e.sources[n];if(s.sources){const i=r?s.tState:s.state;i===F?s!==t&&(!s.updatedAt||s.updatedAt<Ae)&&ce(s):i===oe&&ke(s,t)}}}function Ct(e){const t=b&&b.running;for(let r=0;r<e.observers.length;r+=1){const n=e.observers[r];(t?!n.tState:!n.state)&&(t?n.tState=oe:n.state=oe,n.pure?P.push(n):N.push(n),n.observers&&Ct(n))}}function Y(e){let t;if(e.sources)for(;e.sources.length;){const r=e.sources.pop(),n=e.sourceSlots.pop(),s=r.observers;if(s&&s.length){const i=s.pop(),c=r.observerSlots.pop();n<s.length&&(i.sourceSlots[c]=n,s[n]=i,r.observerSlots[n]=c)}}if(e.tOwned){for(t=e.tOwned.length-1;t>=0;t--)Y(e.tOwned[t]);delete e.tOwned}if(b&&b.running&&e.pure)Tt(e,!0);else if(e.owned){for(t=e.owned.length-1;t>=0;t--)Y(e.owned[t]);e.owned=null}if(e.cleanups){for(t=e.cleanups.length-1;t>=0;t--)e.cleanups[t]();e.cleanups=null}b&&b.running?e.tState=0:e.state=0}function Tt(e,t){if(t||(e.tState=0,b.disposed.add(e)),e.owned)for(let r=0;r<e.owned.length;r++)Tt(e.owned[r])}function Yt(e){return e instanceof Error?e:new Error(typeof e=="string"?e:"Unknown error",{cause:e})}function it(e,t,r){try{for(const n of t)n(e)}catch(n){De(n,r&&r.owner||null)}}function De(e,t=T){const r=nt&&t&&t.context&&t.context[nt],n=Yt(e);if(!r)throw n;N?N.push({fn(){it(n,r,t)},state:F}):it(n,r,t)}var Xt=Symbol("fallback");function at(e){for(let t=0;t<e.length;t++)e[t]()}function Zt(e,t,r={}){let n=[],s=[],i=[],c=0,a=t.length>1?[]:null;return fe(()=>at(i)),()=>{let o=e()||[],h=o.length,f,d;return o[Ft],Q(()=>{let v,m,x,_,w,k,E,M,B;if(h===0)c!==0&&(at(i),i=[],n=[],s=[],c=0,a&&(a=[])),r.fallback&&(n=[Xt],s[0]=_e(K=>(i[0]=K,r.fallback())),c=1);else if(c===0){for(s=new Array(h),d=0;d<h;d++)n[d]=o[d],s[d]=_e(g);c=h}else{for(x=new Array(h),_=new Array(h),a&&(w=new Array(h)),k=0,E=Math.min(c,h);k<E&&n[k]===o[k];k++);for(E=c-1,M=h-1;E>=k&&M>=k&&n[E]===o[M];E--,M--)x[M]=s[E],_[M]=i[E],a&&(w[M]=a[E]);for(v=new Map,m=new Array(M+1),d=M;d>=k;d--)B=o[d],f=v.get(B),m[d]=f===void 0?-1:f,v.set(B,d);for(f=k;f<=E;f++)B=n[f],d=v.get(B),d!==void 0&&d!==-1?(x[d]=s[f],_[d]=i[f],a&&(w[d]=a[f]),d=m[d],v.set(B,d)):i[f]();for(d=k;d<h;d++)d in x?(s[d]=x[d],i[d]=_[d],a&&(a[d]=w[d],a[d](d))):s[d]=_e(g);s=s.slice(0,c=h),n=o.slice(0)}return s});function g(v){if(i[d]=v,a){const[m,x]=y(d);return a[d]=x,t(o[d],m)}return t(o[d])}}}var er=!1;function u(e,t){if(er&&L.context){const r=L.context;qe(zt());const n=Q(()=>e(t||{}));return qe(r),n}return Q(()=>e(t||{}))}var tr=e=>`Stale read from <${e}>.`;function A(e){const t="fallback"in e&&{fallback:()=>e.fallback};return O(Zt(()=>e.each,e.children,t||void 0))}function $(e){const t=e.keyed,r=O(()=>e.when,void 0,void 0),n=t?r:O(r,void 0,{equals:(s,i)=>!s==!i});return O(()=>{const s=n();if(s){const i=e.children;return typeof i=="function"&&i.length>0?Q(()=>i(t?s:()=>{if(!Q(n))throw tr("Show");return r()})):i}return e.fallback},void 0,void 0)}var Ue=e=>O(()=>e());function rr(e,t,r){let n=r.length,s=t.length,i=n,c=0,a=0,o=t[s-1].nextSibling,h=null;for(;c<s||a<i;){if(t[c]===r[a]){c++,a++;continue}for(;t[s-1]===r[i-1];)s--,i--;if(s===c){const f=i<n?a?r[a-1].nextSibling:r[i-a]:o;for(;a<i;)e.insertBefore(r[a++],f)}else if(i===a)for(;c<s;)(!h||!h.has(t[c]))&&t[c].remove(),c++;else if(t[c]===r[i-1]&&r[a]===t[s-1]){const f=t[--s].nextSibling;e.insertBefore(r[a++],t[c++].nextSibling),e.insertBefore(r[--i],f),t[s]=r[i]}else{if(!h){h=new Map;let d=a;for(;d<i;)h.set(r[d],d++)}const f=h.get(t[c]);if(f!=null)if(a<f&&f<i){let d=c,g=1,v;for(;++d<s&&d<i&&!((v=h.get(t[d]))==null||v!==f+g);)g++;if(g>f-a){const m=t[c];for(;a<f;)e.insertBefore(r[a++],m)}else e.replaceChild(r[a++],t[c++])}else c++;else t[c++].remove()}}}var ot="_$DX_DELEGATE";function nr(e,t,r,n={}){let s;return _e(i=>{s=i,t===document?e():l(t,e(),t.firstChild?null:void 0,r)},n.owner),()=>{s(),t.textContent=""}}function p(e,t,r,n){let s;const i=()=>{const a=n?document.createElementNS("http://www.w3.org/1998/Math/MathML","template"):document.createElement("template");return a.innerHTML=e,r?a.content.firstChild.firstChild:n?a.firstChild:a.content.firstChild},c=t?()=>Q(()=>document.importNode(s||(s=i()),!0)):()=>(s||(s=i())).cloneNode(!0);return c.cloneNode=c,c}function z(e,t=window.document){const r=t[ot]||(t[ot]=new Set);for(let n=0,s=e.length;n<s;n++){const i=e[n];r.has(i)||(r.add(i),t.addEventListener(i,lr))}}function I(e,t,r){ze(e)||(r==null?e.removeAttribute(t):e.setAttribute(t,r))}function q(e,t){ze(e)||(t==null?e.removeAttribute("class"):e.className=t)}function l(e,t,r,n){if(r!==void 0&&!n&&(n=[]),typeof t!="function")return Ce(e,t,n,r);S(s=>Ce(e,t(),s,r),n)}function ze(e){return!!L.context&&!L.done&&(!e||e.isConnected)}function lr(e){if(L.registry&&L.events&&L.events.find(([o,h])=>h===e))return;let t=e.target;const r=`$$${e.type}`,n=e.target,s=e.currentTarget,i=o=>Object.defineProperty(e,"target",{configurable:!0,value:o}),c=()=>{const o=t[r];if(o&&!t.disabled){const h=t[`${r}Data`];if(h!==void 0?o.call(t,h,e):o.call(t,e),e.cancelBubble)return}return t.host&&typeof t.host!="string"&&!t.host._$host&&t.contains(e.target)&&i(t.host),!0},a=()=>{for(;c()&&(t=t._$host||t.parentNode||t.host););};if(Object.defineProperty(e,"currentTarget",{configurable:!0,get(){return t||document}}),L.registry&&!L.done&&(L.done=_$HY.done=!0),e.composedPath){const o=e.composedPath();i(o[0]);for(let h=0;h<o.length-2&&(t=o[h],!!c());h++){if(t._$host){t=t._$host,a();break}if(t.parentNode===s)break}}else a();i(n)}function Ce(e,t,r,n,s){const i=ze(e);if(i){!r&&(r=[...e.childNodes]);let o=[];for(let h=0;h<r.length;h++){const f=r[h];f.nodeType===8&&f.data.slice(0,2)==="!$"?f.remove():o.push(f)}r=o}for(;typeof r=="function";)r=r();if(t===r)return r;const c=typeof t,a=n!==void 0;if(e=a&&r[0]&&r[0].parentNode||e,c==="string"||c==="number"){if(i||c==="number"&&(t=t.toString(),t===r))return r;if(a){let o=r[0];o&&o.nodeType===3?o.data!==t&&(o.data=t):o=document.createTextNode(t),r=ee(e,r,n,o)}else r!==""&&typeof r=="string"?r=e.firstChild.data=t:r=e.textContent=t}else if(t==null||c==="boolean"){if(i)return r;r=ee(e,r,n)}else{if(c==="function")return S(()=>{let o=t();for(;typeof o=="function";)o=o();r=Ce(e,o,r,n)}),()=>r;if(Array.isArray(t)){const o=[],h=r&&Array.isArray(r);if(Oe(o,t,r,s))return S(()=>r=Ce(e,o,r,n,!0)),()=>r;if(i){if(!o.length)return r;if(n===void 0)return r=[...e.childNodes];let f=o[0];if(f.parentNode!==e)return r;const d=[f];for(;(f=f.nextSibling)!==n;)d.push(f);return r=d}if(o.length===0){if(r=ee(e,r,n),a)return r}else h?r.length===0?ct(e,o,n):rr(e,r,o):(r&&ee(e),ct(e,o));r=o}else if(t.nodeType){if(i&&t.parentNode)return r=a?[t]:t;if(Array.isArray(r)){if(a)return r=ee(e,r,n,t);ee(e,r,null,t)}else r==null||r===""||!e.firstChild?e.appendChild(t):e.replaceChild(t,e.firstChild);r=t}}return r}function Oe(e,t,r,n){let s=!1;for(let i=0,c=t.length;i<c;i++){let a=t[i],o=r&&r[e.length],h;if(!(a==null||a===!0||a===!1))if((h=typeof a)=="object"&&a.nodeType)e.push(a);else if(Array.isArray(a))s=Oe(e,a,o)||s;else if(h==="function")if(n){for(;typeof a=="function";)a=a();s=Oe(e,Array.isArray(a)?a:[a],Array.isArray(o)?o:[o])||s}else e.push(a),s=!0;else{const f=String(a);o&&o.nodeType===3&&o.data===f?e.push(o):e.push(document.createTextNode(f))}}return s}function ct(e,t,r=null){for(let n=0,s=t.length;n<s;n++)e.insertBefore(t[n],r)}function ee(e,t,r,n){if(r===void 0)return e.textContent="";const s=n||document.createTextNode("");if(t.length){let i=!1;for(let c=t.length-1;c>=0;c--){const a=t[c];if(s!==a){const o=a.parentNode===e;!i&&!c?o?e.replaceChild(s,a):e.insertBefore(s,r):o&&a.remove()}else i=!0}}else e.insertBefore(s,r);return[s]}var[sr,ir]=y("connecting"),[ar,ut]=y(null),[or,cr]=y(!1),[ur,dr]=y(null),[hr,fr]=y(null),[gr,pr]=y(null),[vr,mr]=y([]),[br,$r]=y([]),[xr,_r]=y({enabled:!1,queues:[]}),[yr,wr]=y({enabled:!1}),C={connectionStatus:sr,lastUpdate:ar,authRequired:or,authError:ur,health:hr,metrics:gr,routes:vr,container:br,queues:xr,ws:yr},j={setConnectionStatus:ir,setLastUpdate:ut,setAuthRequired:cr,setAuthError:dr,setHealth:fr,setMetrics:pr,setRoutes:mr,setContainer:$r,setQueues:_r,setWs:wr,touch(){ut(new Date)}};function D(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KiB`:e<1024*1024*1024?`${(e/1024/1024).toFixed(1)} MiB`:`${(e/1024/1024/1024).toFixed(2)} GiB`}function Sr(e){if(e===0)return"0";const t=e*60;return Math.abs(t)<1024*1024?`${(t/1024).toFixed(1)} KiB/min`:`${(t/1024/1024).toFixed(1)} MiB/min`}function Z(e){return e<1?`${e.toFixed(2)} ms`:e<100?`${e.toFixed(1)} ms`:`${Math.round(e)} ms`}function He(e){const t=Math.floor(e);return t<60?`${t}s`:t<3600?`${Math.floor(t/60)}m ${t%60}s`:`${Math.floor(t/3600)}h ${Math.floor(t%3600/60)}m ${t%60}s`}function Te(e){return`${Math.round(e*100)}%`}var kr=p('<span class=dt-tip tabindex=0><svg class=dt-tip-icon viewBox="0 0 24 24"aria-hidden=true><circle cx=12 cy=12 r=9 fill=none stroke=currentColor stroke-width=1.5></circle><path d="M12 8h.01M12 11v6"stroke=currentColor stroke-width=2 stroke-linecap=round fill=none></path></svg><span role=tooltip>'),Cr=p('<button type=button class="dt-tip dt-tip-clickable"><svg class=dt-tip-icon viewBox="0 0 24 24"aria-hidden=true><circle cx=12 cy=12 r=9 fill=none stroke=currentColor stroke-width=1.5></circle><path d="M12 8h.01M12 11v6"stroke=currentColor stroke-width=2 stroke-linecap=round fill=none>'),Tr=p('<div class="fixed inset-0 z-50 bg-slate-950/80 flex items-center justify-center p-4"><div class="bg-slate-900 border border-slate-700 rounded-2xl p-6 max-w-lg w-full shadow-2xl max-h-[90vh] overflow-y-auto"><div class="flex items-start justify-between mb-4"><h2 class="text-lg font-semibold text-slate-200"></h2><button type=button class="text-slate-500 hover:text-slate-300 p-1"aria-label=Close><svg class="w-5 h-5"fill=none stroke=currentColor viewBox="0 0 24 24"><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M6 18L18 6M6 6l12 12"></path></svg></button></div><div class="text-sm text-slate-300 space-y-3">'),Pe={"heap.used":{short:"V8-allocated memory currently used by JavaScript objects.",detail:"Grows as your code allocates objects, shrinks after GC frees them. A consistently rising heap-used line on the sparkline is the textbook leak signature."},"heap.total":{short:"V8-allocated memory the JS heap is currently sized to use.",detail:"Larger than heap-used; V8 reserves headroom so allocations don't pause to grow the heap. Bumps up in 1-8 MiB jumps as the heap expands."},rss:{short:"Total memory resident in physical RAM for this Node process.",detail:'Includes the JS heap, native buffers, V8 internal structures, and code. Always larger than heap-used; the gap is "everything the OS sees" minus "JS objects".'},external:{short:"Memory used by C++ objects bound to JS (Buffers, native bindings)."},"array-buffers":{short:"Memory used by ArrayBuffer / SharedArrayBuffer instances."},"event-loop.p99":{short:"99% of event-loop ticks completed within this time.",detail:"Sustained values above ~50ms mean some synchronous operation is blocking the loop. Common culprits: large JSON.parse, sync crypto, blocking DB drivers."},gc:{short:"Garbage-collector activity since process start.",detail:"Total run count and cumulative pause time. Frequent GC with low reclaim ratio = leak; rare GC with healthy reclaim = good citizen."},"leak.risk":{short:"Heap-growth slope over the recent window — stable / warn / critical.",detail:"Bucketed from heap-growth in MB/min: <5 = ok, <20 = warn, ≥20 = critical. Critical sustained for >5 minutes is the moment to capture a heap snapshot."},"gc.reclaim":{short:"Average ratio of memory freed by each GC pass.",detail:"Trending toward zero means GC can't free anything — strong leak indicator. Healthy apps reclaim 20-60% on each major GC."},"heap.utilization":{short:"Fraction of V8's hard heap-size limit currently in use.",detail:"Approaching 1 means the process is close to OOM. Use --max-old-space-size to raise the limit if your workload is memory-bound."},requests:{short:"Total HTTP requests handled since process start."},"server-errors":{short:"5xx responses — server-side failures."},"client-errors":{short:"4xx responses — bad client input, missing routes, auth denials."},"error-rate":{short:"Server errors as a percentage of total requests.",detail:"Computed across the lifetime of the process. Spikes typically signal upstream dependency failures; sustained elevation = code bug."},uptime:{short:"How long this Node process has been running."},"latency.avg":{short:"Mean response time per route (sum of all calls / call count)."},"latency.p50":{short:"Median — half the requests complete faster than this."},"latency.p95":{short:"95% of requests complete within this time."},"latency.p99":{short:"99% of requests complete within this time. Outlier-sensitive."},"latency.max":{short:"Slowest single response observed since process start."},"resolve.count":{short:"Number of times this token was resolved from the DI container."},"resolve.duration":{short:"How long the container took to resolve this token (ms)."},"post-construct":{short:"@PostConstruct lifecycle status: done / failed / none.",detail:'A failed PostConstruct means the service registered but its async init threw. The token is left in a "registered" state; resolve() will throw the original error.'}},U=e=>{const t=()=>e.text??Pe[e.metric??""]?.short??"",r=e.placement??"top";return(()=>{var n=kr(),s=n.firstChild.nextSibling;return q(s,`dt-tip-pop dt-tip-pop-${r}`),l(s,t),S(()=>I(n,"aria-label",t())),n})()},Er=e=>{const[t,r]=y(!1);return[(()=>{var n=Cr();return n.$$click=()=>r(!0),S(()=>I(n,"aria-label",`More info: ${e.title}`)),n})(),u($,{get when(){return t()},get children(){return u(Mr,{get title(){return e.title},onClose:()=>r(!1),get children(){return e.children}})}})]},Mr=e=>(()=>{var t=Tr(),r=t.firstChild.firstChild,n=r.firstChild,s=n.nextSibling,i=r.nextSibling;return t.$$click=c=>{c.target===c.currentTarget&&e.onClose()},l(n,()=>e.title),s.$$click=()=>e.onClose(),l(i,()=>e.children),t})();z(["click"]);var Ar=p('<div class="grid grid-cols-1 md:grid-cols-3 gap-4">'),Lr=p('<div class="bg-slate-900 rounded-xl border border-slate-800 p-5"><h2 class="text-xs font-semibold uppercase tracking-wider text-slate-500 mb-3">Health'),Et=p('<p class="text-slate-600 italic">Loading…'),Rr=p("<span>"),ne=p('<span class="font-semibold tabular-nums">'),Mt=p("<div class=mt-1>"),qr=p('<div class="border-t border-slate-800 mt-2 pt-2"><button type=button class="text-xs text-slate-500 hover:text-slate-300 flex items-center gap-1"><svg fill=none stroke=currentColor viewBox="0 0 24 24"aria-hidden=true><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M9 5l7 7-7 7"></path></svg>Adapters (<!>)'),jr=p('<div class="flex items-center justify-between py-1"><span class="text-slate-400 text-sm"></span><span>'),Or=p('<div class="bg-slate-900 rounded-xl border border-slate-800 p-5"><h2 class="text-xs font-semibold uppercase tracking-wider text-slate-500 mb-3">Metrics'),Pr=p('<span class="font-semibold tabular-nums text-red-400">'),Br=p('<span class="font-semibold tabular-nums text-amber-400">'),Nr=p('<span class="font-semibold text-sm">'),Ir=p('<span class="font-semibold tabular-nums text-emerald-400">'),Dr=p('<div class="border-t border-slate-800 mt-2 pt-2"><button type=button class="text-xs text-slate-500 hover:text-slate-300 flex items-center gap-1"><svg fill=none stroke=currentColor viewBox="0 0 24 24"aria-hidden=true><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M9 5l7 7-7 7"></path></svg>Namespaces (<!>)'),Ur=p('<div class="bg-slate-900 rounded-xl border border-slate-800 p-5"><h2 class="text-xs font-semibold uppercase tracking-wider text-slate-500 mb-3">WebSocket'),zr=p('<p class="text-slate-600 italic">No WsAdapter detected'),Hr=p('<div class="flex items-center justify-between py-1"><span class="text-slate-400 text-sm font-mono"></span><span class=text-sm> conn / <!> handlers'),Fr=p('<div class="flex items-center justify-between mb-2"><span class=text-slate-400>'),Gr=()=>(()=>{var e=Ar();return l(e,u(Vr,{}),null),l(e,u(Kr,{}),null),l(e,u(Qr,{}),null),e})(),Vr=()=>{const[e,t]=y(!1);return(()=>{var r=Lr();return r.firstChild,l(r,u($,{get when(){return C.health()},get fallback(){return Et()},children:n=>[u(G,{label:"Status",get children(){var s=Rr();return l(s,()=>n().status),S(()=>q(s,`badge ${Wr(n().status)}`)),s}}),u(G,{label:"Uptime",get children(){var s=ne();return l(s,()=>He(n().uptime)),s}}),u(G,{label:"Error rate",get children(){var s=ne();return l(s,()=>Te(n().errorRate),null),l(s,u(U,{metric:"error-rate"}),null),s}}),u($,{get when(){return Object.keys(n().adapters).length>0},get children(){var s=qr(),i=s.firstChild,c=i.firstChild,a=c.nextSibling.nextSibling;return a.nextSibling,i.$$click=()=>t(o=>!o),l(i,()=>Object.keys(n().adapters).length,a),l(s,u($,{get when(){return e()},get children(){var o=Mt();return l(o,u(A,{get each(){return Object.entries(n().adapters)},children:([h,f])=>(()=>{var d=jr(),g=d.firstChild,v=g.nextSibling;return l(g,h),q(v,`badge ${f==="running"?"badge-ok":"badge-warn"}`),l(v,f),d})()})),o}}),null),S(()=>I(c,"class",`w-3 h-3 transition-transform ${e()?"rotate-90":""}`)),s}})]}),null),r})()},Kr=()=>(()=>{var e=Or();return e.firstChild,l(e,u($,{get when(){return C.metrics()},get fallback(){return Et()},children:t=>[u(G,{label:"Total requests",get children(){var r=ne();return l(r,()=>t().requests.toLocaleString()),r}}),u(G,{label:"5xx errors",get children(){var r=Pr();return l(r,()=>t().serverErrors),r}}),u(G,{label:"4xx errors",get children(){var r=Br();return l(r,()=>t().clientErrors),r}}),u(G,{label:"Started",get children(){var r=Nr();return l(r,()=>new Date(t().startedAt).toLocaleTimeString()),r}})]}),null),e})(),Qr=()=>{const[e,t]=y(!1);return(()=>{var r=Ur();return r.firstChild,l(r,u($,{get when(){return C.ws().enabled},get fallback(){return zr()},get children(){return[u(G,{label:"Active",get children(){var n=Ir();return l(n,()=>C.ws().activeConnections??0),n}}),u(G,{label:"Total",get children(){var n=ne();return l(n,()=>C.ws().totalConnections??0),n}}),u(G,{label:"Messages in",get children(){var n=ne();return l(n,()=>C.ws().messagesReceived??0),n}}),u(G,{label:"Messages out",get children(){var n=ne();return l(n,()=>C.ws().messagesSent??0),n}}),u($,{get when(){return Ue(()=>!!C.ws().namespaces)()&&Object.keys(C.ws().namespaces??{}).length>0},get children(){var n=Dr(),s=n.firstChild,i=s.firstChild,c=i.nextSibling.nextSibling;return c.nextSibling,s.$$click=()=>t(a=>!a),l(s,()=>Object.keys(C.ws().namespaces??{}).length,c),l(n,u($,{get when(){return e()},get children(){var a=Mt();return l(a,u(A,{get each(){return Object.entries(C.ws().namespaces??{})},children:([o,h])=>(()=>{var f=Hr(),d=f.firstChild,g=d.nextSibling,v=g.firstChild,m=v.nextSibling;return m.nextSibling,l(d,o),l(g,()=>h.connections,v),l(g,()=>h.handlers,m),f})()})),a}}),null),S(()=>I(i,"class",`w-3 h-3 transition-transform ${e()?"rotate-90":""}`)),n}})]}}),null),r})()},G=e=>(()=>{var t=Fr(),r=t.firstChild;return l(r,()=>e.label),l(t,()=>e.children,null),t})();function Wr(e){return e==="healthy"?"badge-ok":e==="degraded"?"badge-warn":"badge-critical"}z(["click"]);var Jr=p("<svg class=sparkline preserveAspectRatio=none aria-hidden=true><path>"),ye=e=>{const t=()=>e.width??200,n=O(()=>{const s=e.values;if(s.length<2)return"";const i=Math.min(...s),c=Math.max(...s)-i||1,a=t()/(s.length-1),o=f=>40-(f-i)/c*36-2;let h=`M0 ${o(s[0]).toFixed(2)}`;for(let f=1;f<s.length;f++)h+=` L${(f*a).toFixed(2)} ${o(s[f]).toFixed(2)}`;return h});return(()=>{var s=Jr(),i=s.firstChild;return S(c=>{var a=`0 0 ${t()} 40`,o=n(),h=e.stroke;return a!==c.e&&I(s,"viewBox",c.e=a),o!==c.t&&I(i,"d",c.t=o),h!==c.a&&I(i,"stroke",c.a=h),c},{e:void 0,t:void 0,a:void 0}),s})()};function pe(){return document.body.dataset.base??"/_debug"}var At="kickjs_devtools_token",Yr=30,ie=null;function le(){if(ie)return ie;const e=new URLSearchParams(location.search).get("token");if(e){Lt(e);const r=new URL(location.href);return r.searchParams.delete("token"),history.replaceState({},"",r.toString()),e}const t=document.cookie.match(new RegExp(`${At}=([^;]+)`));return t?(ie=decodeURIComponent(t[1]),ie):null}function Lt(e){ie=e,document.cookie=`${At}=${encodeURIComponent(e)}; path=/; max-age=${3600*24*Yr}; SameSite=Lax`}function Rt(e){const t=le();return t?`${e}${e.includes("?")?"&":"?"}token=${encodeURIComponent(t)}`:e}var qt=class extends Error{constructor(){super("AUTH_REQUIRED"),this.name="AuthRequiredError"}};async function V(e){const t=Rt(`${pe()}${e}`),r=await fetch(t,{headers:Xr()});if(r.status===401||r.status===403)throw new qt;if(!r.ok)throw new Error(`GET ${e} failed: ${r.status} ${r.statusText}`);return await r.json()}function Xr(){const e=le();return e?{"x-devtools-token":e}:{}}var H={runtime:()=>V("/runtime"),topology:()=>V("/topology"),metrics:()=>V("/metrics"),routes:()=>V("/metrics"),routeRegistry:()=>V("/routes"),container:()=>V("/container"),health:()=>V("/health"),queues:()=>V("/queues"),ws:()=>V("/ws"),tabs:()=>V("/tabs")};function Fe(e,t,r){const n=Rt(`${pe()}${e}`),s=new EventSource(n);return s.onmessage=i=>{try{t(JSON.parse(i.data))}catch(c){console.warn("SSE parse failed",c)}},r&&(s.onerror=r),()=>s.close()}var Zr=p("<div class=status><span><span></span></span><span> samples"),en=p("<div class=empty>Loading runtime metrics…"),tn=p("<div class=empty style=padding:0;text-align:left;font-size:11px>GC: <!> runs, <!> total"),dt=p("<div class=grid>"),rn=p("<div class=card><div class=card-header><div class=card-title></div><div class=card-value>"),Re=60,nn=()=>{const[e,t]=y(null),[r,n]=y([]),[s,i]=y([]),[c,a]=y([]),[o,h]=y(!1),f=d=>{t(d),n(g=>[...g,d.memory.heapUsed].slice(-Re)),i(g=>[...g,d.memory.rss].slice(-Re)),a(g=>[...g,d.eventLoop.p99].slice(-Re))};return he(()=>{H.runtime().then(d=>{for(const g of d.history)f(g);h(!0)}).catch(()=>h(!1)),fe(Fe("/runtime/stream",d=>{h(!0),f(d)},()=>h(!1)))}),[u($,{get when(){return e()},get fallback(){return en()},children:d=>[(()=>{var g=dt();return l(g,u(J,{title:"Heap used",metric:"heap.used",get value(){return D(d().memory.heapUsed)},get children(){return u(ye,{get values(){return r()}})}}),null),l(g,u(J,{title:"RSS",metric:"rss",get value(){return D(d().memory.rss)},get children(){return u(ye,{get values(){return s()}})}}),null),l(g,u(J,{title:"Event loop p99",metric:"event-loop.p99",get value(){return Z(d().eventLoop.p99)},get children(){return u(ye,{get values(){return c()}})}}),null),l(g,u(J,{title:"Uptime",metric:"uptime",get value(){return He(d().uptimeSec)},get children(){var v=tn(),m=v.firstChild.nextSibling,x=m.nextSibling.nextSibling;return x.nextSibling,l(v,()=>d().gc.count,m),l(v,()=>Z(d().gc.totalPauseMs),x),v}}),null),g})(),(()=>{var g=dt();return l(g,u(J,{title:"External",metric:"external",get value(){return D(d().memory.external)}}),null),l(g,u(J,{title:"Array buffers",metric:"array-buffers",get value(){return D(d().memory.arrayBuffers)}}),null),l(g,u(J,{title:"Heap total",metric:"heap.total",get value(){return D(d().memory.heapTotal)}}),null),l(g,u(J,{title:"CPU (last sample)",get value(){return`${(d().cpu.userMicros/1e3).toFixed(1)} ms u / ${(d().cpu.systemMicros/1e3).toFixed(1)} ms s`}}),null),g})()]}),(()=>{var d=Zr(),g=d.firstChild,v=g.firstChild,m=g.nextSibling,x=m.firstChild;return l(g,()=>o()?"streaming":"reconnecting…",null),l(m,()=>r().length,x),S(()=>q(v,`status-dot ${o()?"connected":"disconnected"}`)),d})()]},J=e=>(()=>{var t=rn(),r=t.firstChild.firstChild,n=r.nextSibling;return l(r,()=>e.title,null),l(r,u($,{get when(){return e.metric},children:s=>u(U,{get metric(){return s()}})}),null),l(n,()=>e.value),l(t,()=>e.children,null),t})(),ln=p("<div class=status><span><span></span></span><span> samples"),sn=p("<div class=empty>Loading memory metrics…"),ht=p("<p>"),an=p("<p><strong>Severity buckets</strong> (heap-growth in MB/min):"),on=p('<ul class="list-disc pl-5 space-y-1"><li><span class="badge badge-ok">ok</span> < 5 MB/min — typical operation.</li><li><span class="badge badge-warn">warn</span> < 20 MB/min — investigate if sustained > 5 minutes.</li><li><span class="badge badge-critical">critical</span> ≥ 20 MB/min — capture a heap snapshot now.'),cn=p("<div class=card><div class=card-header><div class=card-title>Leak risk</div><span></span></div><div style=display:flex;justify-content:space-between;align-items:baseline><div class=card-value> growth</div><div class=card-value style=font-size:13px;color:var(--text-dim)>GC reclaim<!> <!> • heap util<!> "),un=p("<div class=grid>"),dn=p("<table><thead><tr><th>Type</th><th style=text-align:right>Count</th></tr></thead><tbody>"),hn=p("<div class=card><div class=card-header><div class=card-title>Active handles</div><div class=card-value>"),fn=p("<div class=empty>No handle inventory available on this runtime."),gn=p("<tr><td></td><td style=text-align:right>"),pn=p("<div class=card><div class=card-header><div class=card-title></div><div class=card-value>"),vn=p('<div class=card><div class=card-header><div class=card-title>Heap snapshot</div><div class=card-value style=font-size:13px;color:var(--text-dim)>~<!> estimate</div></div><p style="margin:0 0 12px;color:var(--text-dim);font-size:12px">Captures a V8 heap snapshot for retained-size analysis in Chrome DevTools (Memory tab, Load profile). Capture blocks the event loop for several seconds — avoid in production.</p><div style=display:flex;align-items:center;gap:12px><button type=button class=tab style="border:1px solid var(--accent);border-radius:4px;padding:6px 14px;border-bottom-color:var(--accent);color:var(--accent)">'),mn=p("<span style=color:var(--text-dim);font-size:12px;font-family:var(--font-mono)>Last: <!> (<!>)"),jt=p('<p style="margin:8px 0 0;color:var(--critical);font-size:12px;font-family:var(--font-mono)">'),bn=p('<div class=card><div class=card-header><div class=card-title>Force GC</div></div><p style="margin:0 0 12px;color:var(--text-dim);font-size:12px">Triggers a synchronous V8 GC pass to confirm whether heap growth is real retention or just uncollected garbage. Requires <code>node --expose-gc</code>.</p><div style=display:flex;align-items:center;gap:12px;flex-wrap:wrap><button type=button class=tab style="border:1px solid var(--accent);border-radius:4px;padding:6px 14px;border-bottom-color:var(--accent);color:var(--accent)">'),$n=p("<span style=color:var(--text-dim);font-size:12px;font-family:var(--font-mono)>Reclaimed <!> (<!> → <!>) in <!>ms"),ft=60,xn=()=>{const[e,t]=y(null),[r,n]=y([]),[s,i]=y(!1),c=o=>{t(o),n(h=>[...h,o.snapshot.memory.heapUsed].slice(-ft))};he(()=>{H.runtime().then(o=>{o.latest&&(c({snapshot:o.latest,health:o.health}),n(o.history.map(h=>h.memory.heapUsed).slice(-ft))),i(!0)}).catch(()=>i(!1)),fe(Fe("/memory/stream",o=>{i(!0),c(o)},()=>i(!1)))});const a=O(()=>{const o=e();return o?Object.entries(o.health.handlesByType).sort((h,f)=>f[1]-h[1]):[]});return[u($,{get when(){return e()},get fallback(){return sn()},children:o=>[(()=>{var h=cn(),f=h.firstChild,d=f.firstChild;d.firstChild;var g=d.nextSibling,v=f.nextSibling.firstChild,m=v.firstChild,x=v.nextSibling,_=x.firstChild.nextSibling,w=_.nextSibling.nextSibling,k=w.nextSibling.nextSibling;return k.nextSibling,l(d,u(Er,{title:"What is leak risk?",get children(){return[(()=>{var E=ht();return l(E,()=>Pe["leak.risk"].short),E})(),(()=>{var E=ht();return l(E,()=>Pe["leak.risk"].detail),E})(),an(),on()]}}),null),l(g,()=>o().health.heapGrowthSeverity),l(v,()=>Sr(o().health.heapGrowthBytesPerSec),m),l(x,u(U,{metric:"gc.reclaim"}),_),l(x,()=>Te(o().health.gcReclaimRatio),w),l(x,u(U,{metric:"heap.utilization"}),k),l(x,()=>Te(o().health.heapUtilization),null),l(h,u(ye,{get values(){return r()}}),null),S(()=>q(g,`badge badge-${o().health.heapGrowthSeverity}`)),h})(),(()=>{var h=un();return l(h,u(be,{title:"Heap used",metric:"heap.used",get value(){return D(o().snapshot.memory.heapUsed)}}),null),l(h,u(be,{title:"Heap total",metric:"heap.total",get value(){return D(o().snapshot.memory.heapTotal)}}),null),l(h,u(be,{title:"RSS",metric:"rss",get value(){return D(o().snapshot.memory.rss)}}),null),l(h,u(be,{title:"External",metric:"external",get value(){return D(o().snapshot.memory.external)}}),null),h})(),(()=>{var h=hn(),f=h.firstChild.firstChild.nextSibling;return l(f,()=>o().health.activeHandles),l(h,u($,{get when(){return a().length>0},get fallback(){return fn()},get children(){var d=dn(),g=d.firstChild.nextSibling;return l(g,u(A,{get each(){return a()},children:([v,m])=>(()=>{var x=gn(),_=x.firstChild,w=_.nextSibling;return l(_,v),l(w,m),x})()})),d}}),null),h})(),u(_n,{get heapTotal(){return o().snapshot.memory.heapTotal}}),u(Sn,{})]}),(()=>{var o=ln(),h=o.firstChild,f=h.firstChild,d=h.nextSibling,g=d.firstChild;return l(h,()=>s()?"streaming":"reconnecting…",null),l(d,()=>r().length,g),S(()=>q(f,`status-dot ${s()?"connected":"disconnected"}`)),o})()]},be=e=>(()=>{var t=pn(),r=t.firstChild.firstChild,n=r.nextSibling;return l(r,()=>e.title,null),l(r,u($,{get when(){return e.metric},children:s=>u(U,{get metric(){return s()}})}),null),l(n,()=>e.value),t})(),_n=e=>{const[t,r]=y(!1),[n,s]=y(null),[i,c]=y(null),a=async()=>{r(!0),s(null);try{const o=le(),h=`${pe()}/memory/snapshot${o?`?token=${encodeURIComponent(o)}`:""}`,f=await fetch(h,{method:"POST",headers:o?{"x-devtools-token":o}:void 0});if(!f.ok){let v=`${f.status} ${f.statusText}`;try{const m=await f.json();m.error&&(v=m.error)}catch{}throw new Error(v)}const d=await f.blob(),g=yn(f.headers.get("content-disposition"))??`kickjs-heap-${Date.now()}.heapsnapshot`;wn(d,g),c({name:g,sizeBytes:d.size})}catch(o){s(o instanceof Error?o.message:String(o))}finally{r(!1)}};return(()=>{var o=vn(),h=o.firstChild,f=h.firstChild.nextSibling,d=f.firstChild.nextSibling;d.nextSibling;var g=h.nextSibling.nextSibling,v=g.firstChild;return l(f,()=>D(e.heapTotal),d),v.$$click=()=>{a()},l(v,()=>t()?"Capturing…":"Take snapshot"),l(g,u($,{get when(){return i()},children:m=>(()=>{var x=mn(),_=x.firstChild.nextSibling,w=_.nextSibling.nextSibling;return w.nextSibling,l(x,()=>m().name,_),l(x,()=>D(m().sizeBytes),w),x})()}),null),l(o,u($,{get when(){return n()},children:m=>(()=>{var x=jt();return l(x,m),x})()}),null),S(()=>v.disabled=t()),o})()};function yn(e){if(!e)return null;const t=/filename="?([^";]+)"?/.exec(e);return t?t[1]:null}function wn(e,t){const r=URL.createObjectURL(e),n=document.createElement("a");n.href=r,n.download=t,document.body.appendChild(n),n.click(),document.body.removeChild(n),URL.revokeObjectURL(r)}var Sn=()=>{const[e,t]=y(!1),[r,n]=y(null),[s,i]=y(null),c=async()=>{t(!0),i(null);try{const a=le(),o=`${pe()}/memory/gc${a?`?token=${encodeURIComponent(a)}`:""}`,h=await fetch(o,{method:"POST",headers:a?{"x-devtools-token":a}:void 0});if(!h.ok){let f=`${h.status} ${h.statusText}`;try{const d=await h.json();d.error&&(f=d.error)}catch{}throw new Error(f)}n(await h.json())}catch(a){i(a instanceof Error?a.message:String(a))}finally{t(!1)}};return(()=>{var a=bn(),o=a.firstChild.nextSibling.nextSibling,h=o.firstChild;return h.$$click=()=>{c()},l(h,()=>e()?"Collecting…":"Run GC"),l(o,u($,{get when(){return r()},children:f=>(()=>{var d=$n(),g=d.firstChild.nextSibling,v=g.nextSibling.nextSibling,m=v.nextSibling.nextSibling,x=m.nextSibling.nextSibling;return x.nextSibling,l(d,()=>D(f().reclaimedBytes),g),l(d,()=>D(f().before),v),l(d,()=>D(f().after),m),l(d,()=>f().elapsedMs,x),d})()}),null),l(a,u($,{get when(){return s()},children:f=>(()=>{var d=jt();return l(d,f),d})()}),null),S(()=>h.disabled=e()),a})()};z(["click"]);var kn=p('<div style=display:flex;justify-content:space-between;align-items:center;margin-bottom:12px><h2 style=margin:0;font-size:16px>Topology</h2><button type=button class=tab style="border:1px solid var(--border);border-radius:4px;padding:4px 12px;border-bottom-color:var(--border)">'),Cn=p("<div class=card style=border-color:var(--critical)><div class=card-title style=color:var(--critical)>Topology error</div><code>"),Tn=p("<div class=empty>Loading topology…"),En=p('<div class=card style=border-color:var(--warn)><div class=card-title style=color:var(--warn)> introspect failure(s)</div><ul style="margin:8px 0 0;padding-left:20px;font-family:var(--font-mono);font-size:12px">'),Mn=p("<table><thead><tr><th>Key</th><th>Source</th><th>Depends on</th></tr></thead><tbody>"),An=p("<div class=card><div class=card-header><div class=card-title>Contributors (<!>)"),Ln=p("<table><thead><tr><th>Token</th><th>Scope</th><th>Kind</th><th>Resolved</th></tr></thead><tbody>"),Rn=p("<div class=card><div class=card-header><div class=card-title>DI tokens (<!>)"),qn=p("<li>/<!>: "),jn=p("<div class=empty>No contributors registered"),On=p("<tr><td><span class=tree-key></span></td><td></td><td>"),Pn=p("<div class=empty>No DI tokens registered"),Bn=p("<tr><td><span class=tree-key></span></td><td></td><td></td><td>"),Nn=p("<div class=card><div class=card-header><div class=card-title>"),In=p("<div class=empty>"),Dn=p("<span class=tree-meta>v"),Un=p("<div class=tree-meta>provides: "),zn=p("<div class=tree-node><span class=tree-key>"),Hn=p("<div class=tree-meta>"),Fn=p("<span style=margin-right:12px>: <strong style=color:var(--text)>"),Gn=()=>{const[e,t]=y(null),[r,n]=y(null),[s,i]=y(!1),c=async()=>{i(!0),n(null);try{t(await H.topology())}catch(a){n(a instanceof Error?a.message:String(a))}finally{i(!1)}};return he(()=>{c()}),[(()=>{var a=kn(),o=a.firstChild.nextSibling;return o.$$click=()=>{c()},l(o,()=>s()?"Refreshing…":"Refresh"),S(()=>o.disabled=s()),a})(),u($,{get when(){return r()},children:a=>(()=>{var o=Cn(),h=o.firstChild.nextSibling;return l(h,a),o})()}),u($,{get when(){return e()},get fallback(){return Tn()},children:a=>[u($,{get when(){return a().errors.length>0},get children(){var o=En(),h=o.firstChild,f=h.firstChild,d=h.nextSibling;return l(h,()=>a().errors.length,f),l(d,u(A,{get each(){return a().errors},children:g=>(()=>{var v=qn(),m=v.firstChild,x=m.nextSibling;return x.nextSibling,l(v,()=>g.kind,m),l(v,()=>g.name,x),l(v,()=>g.message,null),v})()})),o}}),u(gt,{get title(){return`Plugins (${a().plugins.length})`},get items(){return a().plugins},empty:"No plugins registered"}),u(gt,{get title(){return`Adapters (${a().adapters.length})`},get items(){return a().adapters},empty:"No adapters registered"}),(()=>{var o=An(),h=o.firstChild.firstChild,f=h.firstChild.nextSibling;return f.nextSibling,l(h,()=>a().contributors.length,f),l(o,u($,{get when(){return a().contributors.length>0},get fallback(){return jn()},get children(){var d=Mn(),g=d.firstChild.nextSibling;return l(g,u(A,{get each(){return a().contributors},children:v=>(()=>{var m=On(),x=m.firstChild,_=x.firstChild,w=x.nextSibling,k=w.nextSibling;return l(_,()=>v.key),l(w,()=>v.source),l(k,()=>v.dependsOn.join(", ")||"—"),m})()})),d}}),null),o})(),(()=>{var o=Rn(),h=o.firstChild.firstChild,f=h.firstChild.nextSibling;return f.nextSibling,l(h,()=>a().diTokens.length,f),l(o,u($,{get when(){return a().diTokens.length>0},get fallback(){return Pn()},get children(){var d=Ln(),g=d.firstChild.nextSibling;return l(g,u(A,{get each(){return a().diTokens},children:v=>(()=>{var m=Bn(),x=m.firstChild,_=x.firstChild,w=x.nextSibling,k=w.nextSibling,E=k.nextSibling;return l(_,()=>v.token),l(w,()=>v.scope),l(k,()=>v.kind),l(E,()=>v.instantiated?"yes":"no"),m})()})),d}}),null),o})()]})]},gt=e=>(()=>{var t=Nn(),r=t.firstChild.firstChild;return l(r,()=>e.title),l(t,u($,{get when(){return e.items.length>0},get fallback(){return(()=>{var n=In();return l(n,()=>e.empty),n})()},get children(){return u(A,{get each(){return e.items},children:n=>u(Vn,{item:n})})}}),null),t})(),Vn=e=>(()=>{var t=zn(),r=t.firstChild;return l(r,()=>e.item.name),l(t,u($,{get when(){return e.item.version},get children(){var n=Dn();return n.firstChild,l(n,()=>e.item.version,null),n}}),null),l(t,u($,{get when(){return e.item.tokens?.provides.length},get children(){var n=Un();return n.firstChild,l(n,()=>e.item.tokens?.provides.join(", "),null),n}}),null),l(t,u($,{get when(){return e.item.metrics},children:n=>(()=>{var s=Hn();return l(s,u(A,{get each(){return Object.entries(n())},children:([i,c])=>(()=>{var a=Fn(),o=a.firstChild,h=o.nextSibling;return l(a,i,o),l(h,c),a})()})),s})()}),null),t})();z(["click"]);var Kn=p('<div class="flex items-center justify-between mt-4 pt-3 border-t border-slate-800 text-xs text-slate-500"><div class="flex items-center gap-3"><span>Showing <!>–<!> of </span><label class="flex items-center gap-1"><span class=text-slate-600>Per page</span><select class="bg-slate-800 border border-slate-700 rounded px-1.5 py-0.5 text-slate-200"></select></label></div><div class="flex items-center gap-1"><button type=button class="px-2.5 py-1 rounded border border-slate-700 bg-slate-800 hover:bg-slate-700 disabled:opacity-30">Prev</button><button type=button class="px-2.5 py-1 rounded border border-slate-700 bg-slate-800 hover:bg-slate-700 disabled:opacity-30">Next'),Qn=p("<option>"),Wn=p('<span class="px-1 text-slate-600">…'),Jn=p("<button type=button>"),Yn=[10,20,50,100];function Ge(e,t={}){const r=t.pageSizeChoices??Yn,[n,s]=y(t.pageSize??r[1]??20),[i,c]=y(1),a=O(()=>Math.max(1,Math.ceil(e().length/n()))),o=O(()=>Math.min(i(),a()));return{source:e,page:O(()=>{const h=(o()-1)*n();return e().slice(h,h+n())}),current:o,total:a,pageSize:n,pageSizeChoices:r,range:O(()=>{const h=e().length;return h===0?{start:0,end:0,total:0}:{start:(o()-1)*n()+1,end:Math.min(o()*n(),h),total:h}}),goto(h){c(Math.max(1,Math.min(h,a())))},next(){c(h=>Math.min(h+1,a()))},prev(){c(h=>Math.max(h-1,1))},setPageSize(h){s(h);const f=(o()-1)*n();c(Math.max(1,Math.floor(f/h)+1))}}}var Ve=e=>{const t=O(()=>{const r=e.pager.total(),n=e.pager.current();if(r<=7)return Array.from({length:r},(a,o)=>o+1);const s=[1],i=Math.max(2,n-1),c=Math.min(r-1,n+1);i>2&&s.push("gap");for(let a=i;a<=c;a++)s.push(a);return c<r-1&&s.push("gap"),s.push(r),s});return u($,{get when(){return e.pager.total()>1||e.pager.source().length>e.pager.pageSize()},get children(){var r=Kn(),n=r.firstChild,s=n.firstChild,i=s.firstChild.nextSibling,c=i.nextSibling.nextSibling;c.nextSibling;var a=s.nextSibling.firstChild.nextSibling,o=n.nextSibling,h=o.firstChild,f=h.nextSibling;return l(s,()=>e.pager.range().start,i),l(s,()=>e.pager.range().end,c),l(s,()=>e.pager.range().total,null),a.addEventListener("change",d=>e.pager.setPageSize(Number(d.currentTarget.value))),l(a,u(A,{get each(){return e.pager.pageSizeChoices},children:d=>(()=>{var g=Qn();return g.value=d,l(g,d),g})()})),h.$$click=()=>e.pager.prev(),l(o,u(A,{get each(){return t()},children:d=>u($,{when:d==="gap",get fallback(){return(()=>{var g=Jn();return g.$$click=()=>e.pager.goto(d),l(g,d),S(()=>q(g,`px-2.5 py-1 rounded border ${d===e.pager.current()?"border-kick-500/30 bg-kick-500/20 text-kick-500":"border-slate-700 bg-slate-800 hover:bg-slate-700"}`)),g})()},get children(){return Wn()}})}),f),f.$$click=()=>e.pager.next(),S(d=>{var g=e.pager.current()===1,v=e.pager.current()===e.pager.total();return g!==d.e&&(h.disabled=d.e=g),v!==d.t&&(f.disabled=d.t=v),d},{e:void 0,t:void 0}),S(()=>a.value=e.pager.pageSize()),r}})};z(["click"]);var Xn=p("<div class=overflow-x-auto><table><thead><tr><th>Method</th><th>Path</th><th>Controller</th><th>Handler</th><th>Middleware</th></tr></thead><tbody>"),Zn=p('<div class="bg-slate-900 rounded-xl border border-slate-800 p-5"><div class="flex flex-col sm:flex-row gap-3 mb-4"><div class="relative flex-1"><svg class="absolute left-3 top-2.5 w-4 h-4 text-slate-500"fill=none stroke=currentColor viewBox="0 0 24 24"aria-hidden=true><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path></svg><input type=text placeholder="Search routes (path, controller, handler)…"class="w-full bg-slate-800 border border-slate-700 rounded-lg pl-10 pr-4 py-2 text-sm text-slate-200 placeholder-slate-500 focus:outline-none focus:border-kick-500"></div><div class="flex gap-1">'),el=p("<button type=button>"),tl=p("<div class=empty>"),rl=p('<tr><td><span></span></td><td class="font-mono text-sm"></td><td></td><td class=text-slate-400></td><td class="text-slate-500 text-xs">'),nl=["ALL","GET","POST","PUT","DELETE","PATCH"],ll=()=>{const[e,t]=y(""),[r,n]=y("ALL"),s=O(()=>{let c=C.routes();r()!=="ALL"&&(c=c.filter(o=>o.method.toUpperCase()===r()));const a=e().trim().toLowerCase();return a&&(c=c.filter(o=>o.path.toLowerCase().includes(a)||o.controller.toLowerCase().includes(a)||o.handler.toLowerCase().includes(a))),c}),i=Ge(()=>s(),{pageSize:20});return(()=>{var c=Zn(),a=c.firstChild.firstChild,o=a.firstChild.nextSibling,h=a.nextSibling;return o.$$input=f=>t(f.currentTarget.value),l(h,u(A,{each:nl,children:f=>(()=>{var d=el();return d.$$click=()=>n(f),l(d,f),S(()=>q(d,`px-3 py-1.5 text-xs font-semibold rounded-lg transition-colors border ${r()===f?"bg-kick-500/20 text-kick-500 border-kick-500/30":"bg-slate-800 text-slate-400 border-slate-700 hover:text-slate-200"}`)),d})()})),l(c,u($,{get when(){return i.page().length>0},get fallback(){return(()=>{var f=tl();return l(f,()=>e()||r()!=="ALL"?"No routes match the current filter":"No routes registered"),f})()},get children(){return[(()=>{var f=Xn(),d=f.firstChild.firstChild.nextSibling;return l(d,u(A,{get each(){return i.page()},children:g=>(()=>{var v=rl(),m=v.firstChild,x=m.firstChild,_=m.nextSibling,w=_.nextSibling,k=w.nextSibling,E=k.nextSibling;return l(x,()=>g.method),l(_,()=>g.path),l(w,()=>g.controller),l(k,()=>g.handler),l(E,(()=>{var M=Ue(()=>!!g.middleware.length);return()=>M()?g.middleware.join(", "):"—"})()),S(()=>q(x,`text-xs font-bold ${sl(g.method)}`)),v})()})),f})(),u(Ve,{pager:i})]}}),null),S(()=>o.value=e()),c})()};function sl(e){const t=e.toUpperCase();return t==="GET"?"text-emerald-400":t==="POST"?"text-cyan-400":t==="PUT"||t==="PATCH"?"text-amber-400":t==="DELETE"?"text-red-400":"text-slate-400"}z(["input","click"]);var il=p("<div class=card style=border-color:var(--critical)><div class=card-title style=color:var(--critical)>Failed to load metrics</div><code>"),al=p("<div class=empty>Loading route metrics…"),ol=p("<div class=grid>"),cl=p("<table><thead><tr><th>Route</th><th style=text-align:right>Calls</th><th style=text-align:right>Avg</th><th style=text-align:right>p50</th><th style=text-align:right>p95</th><th style=text-align:right>p99</th><th style=text-align:right>Max</th></tr></thead><tbody>"),ul=p("<div class=card><div class=card-header><div class=card-title>Per-route latency"),dl=p("<div class=empty>No requests recorded yet"),hl=p("<tr><td></td><td style=text-align:right></td><td style=text-align:right></td><td style=text-align:right></td><td style=text-align:right></td><td style=text-align:right></td><td style=text-align:right>"),fl=p("<div class=card><div class=card-header><div class=card-title></div><div class=card-value>"),gl=()=>{const[e,t]=y(null),[r,n]=y(null),s=async()=>{try{t(await H.routes()),n(null)}catch(c){n(c instanceof Error?c.message:String(c))}};he(()=>{s();const c=setInterval(()=>{s()},2e3);return()=>clearInterval(c)});const i=O(()=>{const c=e();return c?Object.entries(c.routeLatency).map(([a,o])=>({key:a,...o,avg:o.count>0?o.totalMs/o.count:0})).sort((a,o)=>o.count-a.count):[]});return[u($,{get when(){return r()},children:c=>(()=>{var a=il(),o=a.firstChild.nextSibling;return l(o,c),a})()}),u($,{get when(){return e()},get fallback(){return al()},children:c=>[(()=>{var a=ol();return l(a,u(se,{title:"Requests",metric:"requests",get value(){return c().requests.toString()}}),null),l(a,u(se,{title:"Server errors",metric:"server-errors",get value(){return c().serverErrors.toString()}}),null),l(a,u(se,{title:"Client errors",metric:"client-errors",get value(){return c().clientErrors.toString()}}),null),l(a,u(se,{title:"Error rate",metric:"error-rate",get value(){return Te(c().errorRate)}}),null),l(a,u(se,{title:"Uptime",metric:"uptime",get value(){return He(c().uptimeSeconds)}}),null),a})(),(()=>{var a=ul();return a.firstChild,l(a,u($,{get when(){return i().length>0},get fallback(){return dl()},get children(){var o=cl(),h=o.firstChild,f=h.firstChild.firstChild.nextSibling.nextSibling;f.firstChild;var d=f.nextSibling;d.firstChild;var g=d.nextSibling;g.firstChild;var v=g.nextSibling;v.firstChild;var m=v.nextSibling;m.firstChild;var x=h.nextSibling;return l(f,u(U,{metric:"latency.avg",placement:"bottom"}),null),l(d,u(U,{metric:"latency.p50",placement:"bottom"}),null),l(g,u(U,{metric:"latency.p95",placement:"bottom"}),null),l(v,u(U,{metric:"latency.p99",placement:"bottom"}),null),l(m,u(U,{metric:"latency.max",placement:"bottom"}),null),l(x,u(A,{get each(){return i()},children:_=>(()=>{var w=hl(),k=w.firstChild,E=k.nextSibling,M=E.nextSibling,B=M.nextSibling,K=B.nextSibling,ve=K.nextSibling,me=ve.nextSibling;return l(k,()=>_.key),l(E,()=>_.count),l(M,()=>Z(_.avg)),l(B,()=>Z(_.p50)),l(K,()=>Z(_.p95)),l(ve,()=>Z(_.p99)),l(me,()=>Z(_.maxMs)),w})()})),o}}),null),a})()]})]},se=e=>(()=>{var t=fl(),r=t.firstChild.firstChild,n=r.nextSibling;return l(r,()=>e.title,null),l(r,u($,{get when(){return e.metric},children:s=>u(U,{get metric(){return s()}})}),null),l(n,()=>e.value),t})(),pl=p('<button type=button class="text-slate-500 hover:text-slate-300 p-1"aria-label=Back><svg class="w-4 h-4"fill=none stroke=currentColor viewBox="0 0 24 24"><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M15 19l-7-7 7-7">'),pt=p('<div class="flex flex-wrap gap-1">'),vl=p('<div class="bg-slate-800/50 rounded-lg border border-slate-700 p-3 space-y-2 text-sm">'),ml=p("<span>"),bl=p('<div class="fixed inset-0 z-50 bg-slate-950/80 flex items-center justify-center p-4"><div class="bg-slate-900 border border-slate-700 rounded-2xl p-6 max-w-2xl w-full shadow-2xl max-h-[90vh] overflow-y-auto"><div class="flex items-start justify-between mb-4"><div><div class="flex items-center gap-2 mb-1"><h2 class="text-base font-semibold font-mono text-slate-200 break-all"></h2></div><div class="flex flex-wrap gap-2 mt-2"><span></span><span class="bg-slate-700/50 text-slate-300 px-2 py-0.5 rounded text-xs font-semibold"></span><span></span></div></div><button type=button class="text-slate-500 hover:text-slate-300 p-1"aria-label=Close><svg class="w-5 h-5"fill=none stroke=currentColor viewBox="0 0 24 24"><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M6 18L18 6M6 6l12 12">'),vt=p('<span class="text-slate-600 text-sm">None'),$l=p('<button type=button class="bg-slate-800 text-kick-500 hover:bg-slate-700 px-2.5 py-1 rounded text-xs font-mono border border-slate-700 transition-colors">'),xl=p('<button type=button class="bg-slate-800 text-amber-400 hover:bg-slate-700 px-2.5 py-1 rounded text-xs font-mono border border-slate-700 transition-colors">'),_l=p('<div class=mb-4><h3 class="text-xs font-semibold uppercase tracking-wider text-slate-500 mb-2">'),yl=p('<div class="flex justify-between"><span class=text-slate-400></span><span class=tabular-nums>'),[Be,ue]=y(null),[wl,Le]=y([]);function Ee(e){Le([]),ue(e)}function mt(e){const t=Be();t&&t!==e&&Le(r=>[...r,t]),ue(e)}function Sl(){Le(e=>{if(e.length===0)return ue(null),e;const t=e.slice(0,-1);return ue(e[e.length-1]),t})}function bt(){ue(null),Le([])}var kl=()=>{const e=O(()=>{const r=Be();if(!r)return null;const n=C.container().find(s=>s.token===r);return n||{token:r,kind:void 0,scope:void 0,dependencies:[]}}),t=O(()=>{const r=Be();return r?C.container().filter(n=>n.dependencies?.includes(r)).map(n=>n.token):[]});return u($,{get when(){return e()},children:r=>(()=>{var n=bl(),s=n.firstChild,i=s.firstChild.firstChild,c=i.firstChild,a=c.firstChild,o=c.nextSibling.firstChild,h=o.nextSibling,f=h.nextSibling,d=i.nextSibling;return n.$$click=g=>{g.target===g.currentTarget&&bt()},l(c,u($,{get when(){return wl().length>0},get children(){var g=pl();return g.$$click=Sl,g}}),a),l(a,()=>r().token),l(o,()=>r().kind??"unknown"),l(h,()=>r().scope??"singleton"),l(f,()=>El(r())),d.$$click=bt,l(s,u($e,{title:"Dependencies",get children(){return u($,{get when(){return(r().dependencies?.length??0)>0},get fallback(){return vt()},get children(){var g=pt();return l(g,u(A,{get each(){return r().dependencies},children:v=>(()=>{var m=$l();return m.$$click=()=>mt(v),l(m,v),m})()})),g}})}}),null),l(s,u($e,{title:"Dependents",get children(){return u($,{get when(){return t().length>0},get fallback(){return vt()},get children(){var g=pt();return l(g,u(A,{get each(){return t()},children:v=>(()=>{var m=xl();return m.$$click=()=>mt(v),l(m,v),m})()})),g}})}}),null),l(s,u($e,{title:"Resolve stats",get children(){var g=vl();return l(g,u(xe,{label:"Resolve count",get value(){return String(r().resolveCount??0)}}),null),l(g,u($,{get when(){return r().firstResolved},children:v=>u(xe,{label:"First resolved",get value(){return new Date(v()).toLocaleString()}})}),null),l(g,u($,{get when(){return r().lastResolved},children:v=>u(xe,{label:"Last resolved",get value(){return new Date(v()).toLocaleString()}})}),null),l(g,u($,{get when(){return r().resolveDurationMs!=null},get children(){return u(xe,{label:"Resolution duration",get value(){return`${(r().resolveDurationMs??0).toFixed(2)} ms`}})}}),null),g}}),null),l(s,u($e,{title:"PostConstruct",get children(){var g=ml();return l(g,()=>r().postConstructStatus??"none"),S(()=>q(g,`px-2 py-0.5 rounded text-xs font-semibold ${Ml(r().postConstructStatus)}`)),g}}),null),S(g=>{var v=`px-2 py-0.5 rounded text-xs font-semibold ${Cl(r().kind)}`,m=`px-2 py-0.5 rounded text-xs font-semibold ${Tl(r())}`;return v!==g.e&&q(o,g.e=v),m!==g.t&&q(f,g.t=m),g},{e:void 0,t:void 0}),n})()})},$e=e=>(()=>{var t=_l(),r=t.firstChild;return l(r,()=>e.title),l(t,()=>e.children,null),t})(),xe=e=>(()=>{var t=yl(),r=t.firstChild,n=r.nextSibling;return l(r,()=>e.label),l(n,()=>e.value),t})();function Cl(e){return e==="controller"?"bg-violet-900/50 text-violet-300":e==="service"?"bg-blue-900/50 text-blue-300":e==="repository"?"bg-teal-900/50 text-teal-300":"bg-slate-700/50 text-slate-300"}function Tl(e){return e.postConstructStatus==="failed"?"bg-red-900/50 text-red-300":e.instantiated?"bg-emerald-900/50 text-emerald-300":"bg-amber-900/50 text-amber-300"}function El(e){return e.postConstructStatus==="failed"?"failed":e.instantiated?"active":"registered"}function Ml(e){return e==="done"?"bg-emerald-900/50 text-emerald-300":e==="failed"?"bg-red-900/50 text-red-300":"bg-slate-700/50 text-slate-400"}z(["click"]);var Al=p("<div class=overflow-x-auto><table><thead><tr><th class=w-6 aria-label=expand></th><th>Token</th><th>Kind</th><th>Scope</th><th>Status</th><th class=text-right>Resolves</th><th class=text-right>Deps</th></tr></thead><tbody>"),Ll=p('<div class="bg-slate-900 rounded-xl border border-slate-800 p-5"><div class="flex flex-col gap-3 mb-4"><div class=relative><svg class="absolute left-3 top-2.5 w-4 h-4 text-slate-500"fill=none stroke=currentColor viewBox="0 0 24 24"aria-hidden=true><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path></svg><input type=text placeholder="Search tokens…"class="w-full bg-slate-800 border border-slate-700 rounded-lg pl-10 pr-4 py-2 text-sm text-slate-200 placeholder-slate-500 focus:outline-none focus:border-kick-500"></div><div class="flex flex-col sm:flex-row gap-3"><div class="flex gap-1 items-center"><span class="text-xs text-slate-500 mr-1">Kind:</span></div><div class="flex gap-1 items-center"><span class="text-xs text-slate-500 mr-1">Scope:'),$t=p("<button type=button>"),Rl=p("<div class=empty>"),ql=p('<tr class="cursor-pointer select-none"><td><svg fill=none stroke=currentColor viewBox="0 0 24 24"aria-hidden=true><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M9 5l7 7-7 7"></path></svg></td><td class="font-mono text-sm"></td><td><span></span></td><td><span class="bg-slate-700/50 text-slate-300 px-2 py-0.5 rounded text-xs font-semibold"></span></td><td><span></span></td><td class="text-right tabular-nums"></td><td class="text-right text-slate-500 text-xs">'),jl=p('<tr><td colspan=7 class="bg-slate-800/30 px-6 py-4 border-b border-slate-800">'),Ol=p('<div class="flex flex-wrap gap-1">'),Pl=p('<div class="flex justify-between"><span class=text-slate-400>Duration</span><span class=tabular-nums>ms'),Bl=p('<div class="grid grid-cols-1 md:grid-cols-2 gap-4"><div><h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 mb-2">Dependencies</h4></div><div><h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 mb-2">Resolve Stats</h4><div class="space-y-1 text-sm"><div class="flex justify-between"><span class=text-slate-400>Resolve count</span><span class=tabular-nums></span></div></div></div><div><h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 mb-2">PostConstruct</h4><span></span></div><div class="md:col-span-2 flex justify-end"><button type=button class="px-3 py-1.5 text-xs font-semibold rounded-lg bg-kick-500/20 text-kick-500 border border-kick-500/30 hover:bg-kick-500/30 transition-colors">View full details'),Nl=p('<span class="text-slate-600 text-sm">None'),Il=p('<button type=button class="bg-slate-700/50 text-kick-500 hover:bg-slate-700 px-2 py-0.5 rounded text-xs font-mono transition-colors">'),Dl=p('<div class="flex justify-between"><span class=text-slate-400>First resolved</span><span class=text-xs>'),Ul=p('<div class="flex justify-between"><span class=text-slate-400>Last resolved</span><span class=text-xs>'),zl=["ALL","controller","service","repository","other"],Hl=["ALL","singleton","transient","request"],Fl=()=>{const[e,t]=y(""),[r,n]=y("ALL"),[s,i]=y("ALL"),[c,a]=y(new Set),o=O(()=>{let d=C.container();if(r()!=="ALL"){const v=r();d=d.filter(m=>v==="other"?!["controller","service","repository"].includes(m.kind??""):m.kind===v)}s()!=="ALL"&&(d=d.filter(v=>v.scope===s()));const g=e().trim().toLowerCase();return g&&(d=d.filter(v=>v.token.toLowerCase().includes(g))),d}),h=Ge(()=>o(),{pageSize:20}),f=d=>{a(g=>{const v=new Set(g);return v.has(d)?v.delete(d):v.add(d),v})};return(()=>{var d=Ll(),g=d.firstChild.firstChild,v=g.firstChild.nextSibling,m=g.nextSibling.firstChild;m.firstChild;var x=m.nextSibling;return x.firstChild,v.$$input=_=>t(_.currentTarget.value),l(m,u(A,{each:zl,children:_=>(()=>{var w=$t();return w.$$click=()=>n(_),l(w,_),S(()=>q(w,`px-3 py-1.5 text-xs font-semibold rounded-lg transition-colors border ${r()===_?Kl(_):"bg-slate-800 text-slate-400 border-slate-700 hover:text-slate-200"}`)),w})()}),null),l(x,u(A,{each:Hl,children:_=>(()=>{var w=$t();return w.$$click=()=>i(_),l(w,_),S(()=>q(w,`px-3 py-1.5 text-xs font-semibold rounded-lg transition-colors border ${s()===_?"bg-kick-500/20 text-kick-500 border-kick-500/30":"bg-slate-800 text-slate-400 border-slate-700 hover:text-slate-200"}`)),w})()}),null),l(d,u($,{get when(){return h.page().length>0},get fallback(){return(()=>{var _=Rl();return l(_,()=>e()||r()!=="ALL"||s()!=="ALL"?"No tokens match the current filter":"No DI registrations"),_})()},get children(){return[(()=>{var _=Al(),w=_.firstChild.firstChild,k=w.firstChild.firstChild.nextSibling.nextSibling.nextSibling.nextSibling.nextSibling;k.firstChild;var E=w.nextSibling;return l(k,u(U,{metric:"resolve.count",placement:"bottom"}),null),l(E,u(A,{get each(){return h.page()},children:M=>[(()=>{var B=ql(),K=B.firstChild,ve=K.firstChild,me=K.nextSibling,Ke=me.nextSibling,Qe=Ke.firstChild,We=Ke.nextSibling,Dt=We.firstChild,Je=We.nextSibling,Ye=Je.firstChild,Xe=Je.nextSibling,Ut=Xe.nextSibling;return B.$$click=()=>f(M.token),l(me,()=>M.token),l(Qe,()=>M.kind??"unknown"),l(Dt,()=>M.scope??"—"),l(Ye,()=>Wl(M)),l(Xe,()=>M.resolveCount??0),l(Ut,()=>M.dependencies?.length??0),S(X=>{var Ze=`w-3 h-3 text-slate-500 transition-transform ${c().has(M.token)?"rotate-90":""}`,et=`px-2 py-0.5 rounded text-xs font-semibold ${Vl(M.kind)}`,tt=`px-2 py-0.5 rounded text-xs font-semibold ${Ql(M)}`;return Ze!==X.e&&I(ve,"class",X.e=Ze),et!==X.t&&q(Qe,X.t=et),tt!==X.a&&q(Ye,X.a=tt),X},{e:void 0,t:void 0,a:void 0}),B})(),u($,{get when(){return c().has(M.token)},get children(){var B=jl(),K=B.firstChild;return l(K,u(Gl,{registration:M})),B}})]})),_})(),u(Ve,{pager:h})]}}),null),S(()=>v.value=e()),d})()},Gl=e=>(()=>{var t=Bl(),r=t.firstChild;r.firstChild;var n=r.nextSibling,s=n.firstChild.nextSibling,i=s.firstChild.firstChild.nextSibling,c=n.nextSibling,a=c.firstChild;a.firstChild;var o=a.nextSibling,h=c.nextSibling.firstChild;return l(r,u($,{get when(){return(e.registration.dependencies?.length??0)>0},get fallback(){return Nl()},get children(){var f=Ol();return l(f,u(A,{get each(){return e.registration.dependencies},children:d=>(()=>{var g=Il();return g.$$click=v=>{v.stopPropagation(),Ee(d)},I(g,"title",`Open detail for ${d}`),l(g,d),g})()})),f}}),null),l(i,()=>e.registration.resolveCount??0),l(s,u($,{get when(){return e.registration.firstResolved},children:f=>(()=>{var d=Dl(),g=d.firstChild.nextSibling;return l(g,()=>new Date(f()).toLocaleTimeString()),d})()}),null),l(s,u($,{get when(){return e.registration.lastResolved},children:f=>(()=>{var d=Ul(),g=d.firstChild.nextSibling;return l(g,()=>new Date(f()).toLocaleTimeString()),d})()}),null),l(s,u($,{get when(){return e.registration.resolveDurationMs!=null},get children(){var f=Pl(),d=f.firstChild.nextSibling,g=d.firstChild;return l(d,()=>(e.registration.resolveDurationMs??0).toFixed(2),g),f}}),null),l(a,u(U,{metric:"post-construct"}),null),l(o,()=>e.registration.postConstructStatus??"none"),h.$$click=f=>{f.stopPropagation(),Ee(e.registration.token)},S(()=>q(o,`px-2 py-0.5 rounded text-xs font-semibold ${Jl(e.registration.postConstructStatus)}`)),t})();function Vl(e){return e==="controller"?"bg-violet-900/50 text-violet-300":e==="service"?"bg-blue-900/50 text-blue-300":e==="repository"?"bg-teal-900/50 text-teal-300":"bg-slate-700/50 text-slate-300"}function Kl(e){return e==="controller"?"bg-violet-900/50 text-violet-300 border-violet-700/50":e==="service"?"bg-blue-900/50 text-blue-300 border-blue-700/50":e==="repository"?"bg-teal-900/50 text-teal-300 border-teal-700/50":e==="other"?"bg-slate-700/50 text-slate-300 border-slate-600/50":"bg-kick-500/20 text-kick-500 border-kick-500/30"}function Ql(e){return e.postConstructStatus==="failed"?"bg-red-900/50 text-red-300":e.instantiated?"bg-emerald-900/50 text-emerald-300":"bg-amber-900/50 text-amber-300"}function Wl(e){return e.postConstructStatus==="failed"?"failed":e.instantiated?"active":"registered"}function Jl(e){return e==="done"?"bg-emerald-900/50 text-emerald-300":e==="failed"?"bg-red-900/50 text-red-300":"bg-slate-700/50 text-slate-400"}z(["input","click"]);var Yl=p('<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">'),Xl=p('<div class="bg-slate-900 rounded-xl border border-slate-800 p-5"><div class="relative mb-4"><svg class="absolute left-3 top-2.5 w-4 h-4 text-slate-500"fill=none stroke=currentColor viewBox="0 0 24 24"aria-hidden=true><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path></svg><input type=text placeholder="Search queues by name…"class="w-full bg-slate-800 border border-slate-700 rounded-lg pl-10 pr-4 py-2 text-sm text-slate-200 placeholder-slate-500 focus:outline-none focus:border-kick-500">'),Zl=p('<div class=card><div class=card-title>Queues</div><p class="text-slate-500 text-sm mt-2">QueueAdapter not detected. Install <code class="font-mono text-kick-500">@forinda/kickjs-queue</code> and register the adapter in your bootstrap to see queue stats here.'),es=p("<div class=empty>No queues registered"),ts=p("<div class=empty>No queues match the search"),rs=p('<div class="grid grid-cols-2 gap-2 text-sm">'),ns=p('<div class="bg-slate-800/50 rounded-lg border border-slate-700 p-4"><h3 class="font-mono text-sm font-semibold text-kick-500 mb-3 break-all">'),ls=p('<div class="text-red-400 text-sm">'),ss=p('<div class="flex justify-between"><span class=text-slate-400></span><span>'),is=()=>{const[e,t]=y(""),r=O(()=>{const s=C.queues().queues,i=e().trim().toLowerCase();return i?s.filter(c=>c.name.toLowerCase().includes(i)):s}),n=Ge(()=>r(),{pageSize:12});return u($,{get when(){return C.queues().enabled},get fallback(){return Zl()},get children(){return u($,{get when(){return C.queues().queues.length>0},get fallback(){return es()},get children(){var s=Xl(),i=s.firstChild.firstChild.nextSibling;return i.$$input=c=>t(c.currentTarget.value),l(s,u($,{get when(){return n.page().length>0},get fallback(){return ts()},get children(){return[(()=>{var c=Yl();return l(c,u(A,{get each(){return n.page()},children:a=>u(as,{queue:a})})),c})(),u(Ve,{pager:n})]}}),null),S(()=>i.value=e()),s}})}})},as=e=>(()=>{var t=ns(),r=t.firstChild;return l(r,()=>e.queue.name),l(t,u($,{get when(){return!e.queue.error},get fallback(){return(()=>{var n=ls();return l(n,()=>e.queue.error),n})()},get children(){var n=rs();return l(n,u(te,{label:"Waiting",get value(){return e.queue.waiting??0},colour:"text-amber-400"}),null),l(n,u(te,{label:"Active",get value(){return e.queue.active??0},colour:"text-blue-400"}),null),l(n,u(te,{label:"Completed",get value(){return e.queue.completed??0},colour:"text-emerald-400"}),null),l(n,u(te,{label:"Failed",get value(){return e.queue.failed??0},colour:"text-red-400"}),null),l(n,u(te,{label:"Delayed",get value(){return e.queue.delayed??0},colour:"text-violet-400"}),null),l(n,u(te,{label:"Paused",get value(){return e.queue.paused??0},colour:"text-slate-400"}),null),n}}),null),t})(),te=e=>(()=>{var t=ss(),r=t.firstChild,n=r.nextSibling;return l(r,()=>e.label),l(n,()=>e.value),S(()=>q(n,`font-semibold tabular-nums ${e.colour}`)),t})();z(["input"]);var os=p("<div class=space-y-6>"),cs=p('<div class="bg-slate-900 rounded-xl border border-slate-800 p-5"><div class="relative mb-4"><svg class="absolute left-3 top-2.5 w-4 h-4 text-slate-500"fill=none stroke=currentColor viewBox="0 0 24 24"aria-hidden=true><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path></svg><input type=text placeholder="Filter graph (token or kind)…"class="w-full bg-slate-800 border border-slate-700 rounded-lg pl-10 pr-4 py-2 text-sm text-slate-200 placeholder-slate-500 focus:outline-none focus:border-kick-500">'),us=p("<div class=empty>"),ds=p('<div><h3><span class="ml-2 text-slate-600 font-normal normal-case">(<!>)</span></h3><div class=space-y-1>'),hs=p('<span class="bg-slate-700/50 text-slate-400 px-1.5 py-0.5 rounded text-xs">'),fs=p('<span class="text-slate-600 text-xs ml-auto tabular-nums"> resolves'),gs=p('<div class="ml-8 mt-1 space-y-0.5">'),ps=p('<button type=button class="w-full text-left px-3 py-2 rounded-lg hover:bg-slate-800/50 transition-colors group"><div class="flex items-center gap-2"><span></span><span class="font-mono text-sm text-slate-200 break-all">'),vs=p('<div class="flex items-center gap-2 text-xs text-slate-500 hover:text-slate-300"><svg class="w-3 h-3 text-slate-600"fill=none stroke=currentColor viewBox="0 0 24 24"aria-hidden=true><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M13 7l5 5-5 5M6 12h12"></path></svg><span></span><span class=font-mono>'),ms=[{id:"controllers",label:"Controllers",match:e=>e==="controller"},{id:"services",label:"Services",match:e=>e==="service"},{id:"repositories",label:"Repositories",match:e=>e==="repository"},{id:"other",label:"Other",match:e=>!["controller","service","repository"].includes(e??"")}],bs=()=>{const[e,t]=y(""),r=O(()=>{const s=C.container(),i=e().trim().toLowerCase();return i?s.filter(c=>c.token.toLowerCase().includes(i)||(c.kind??"").toLowerCase().includes(i)):s}),n=O(()=>ms.map(s=>({...s,nodes:r().filter(i=>s.match(i.kind))})));return(()=>{var s=cs(),i=s.firstChild.firstChild.nextSibling;return i.$$input=c=>t(c.currentTarget.value),l(s,u($,{get when(){return r().length>0},get fallback(){return(()=>{var c=us();return l(c,()=>e()?"No nodes match the filter":"No DI registrations to graph"),c})()},get children(){var c=os();return l(c,u(A,{get each(){return n()},children:a=>u($,{get when(){return a.nodes.length>0},get children(){return u($s,{get label(){return a.label},get nodes(){return a.nodes}})}})})),c}}),null),S(()=>i.value=e()),s})()},$s=e=>(()=>{var t=ds(),r=t.firstChild,n=r.firstChild,s=n.firstChild.nextSibling;s.nextSibling;var i=r.nextSibling;return l(r,()=>e.label,n),l(n,()=>e.nodes.length,s),l(i,u(A,{get each(){return e.nodes},children:c=>u(xs,{node:c})})),S(()=>q(r,`text-xs font-semibold uppercase tracking-wider mb-2 ${_s(e.label)}`)),t})(),xs=e=>{const t=()=>e.node.dependencies??[];return(()=>{var r=ps(),n=r.firstChild,s=n.firstChild,i=s.nextSibling;return r.$$click=()=>Ee(e.node.token),l(s,()=>Ot(e.node.kind)),l(i,()=>e.node.token),l(n,u($,{get when(){return e.node.scope},get children(){var c=hs();return l(c,()=>e.node.scope),c}}),null),l(n,u($,{get when(){return(e.node.resolveCount??0)>0},get children(){var c=fs(),a=c.firstChild;return l(c,()=>e.node.resolveCount,a),c}}),null),l(r,u($,{get when(){return t().length>0},get children(){var c=gs();return l(c,u(A,{get each(){return t()},children:a=>(()=>{var o=vs(),h=o.firstChild.nextSibling,f=h.nextSibling;return o.$$click=d=>{d.stopPropagation(),Ee(a)},l(h,()=>ys(a)),l(f,a),S(()=>q(h,`px-1.5 py-0.5 rounded text-xs font-semibold ${ws(a)}`)),o})()})),c}}),null),S(()=>q(s,`px-2 py-0.5 rounded text-xs font-semibold ${Pt(e.node.kind)}`)),r})()};function Ot(e){return e==="controller"?"ctrl":e==="service"?"svc":e==="repository"?"repo":"other"}function Pt(e){return e==="controller"?"bg-violet-900/50 text-violet-300":e==="service"?"bg-blue-900/50 text-blue-300":e==="repository"?"bg-teal-900/50 text-teal-300":"bg-slate-700/50 text-slate-300"}function _s(e){return e==="Controllers"?"text-violet-400":e==="Services"?"text-blue-400":e==="Repositories"?"text-teal-400":"text-slate-400"}function ys(e){return Ot(C.container().find(t=>t.token===e)?.kind)}function ws(e){return Pt(C.container().find(t=>t.token===e)?.kind)}z(["input","click"]);var Ss=p("<div style=display:flex;flex-direction:column;height:100%>"),ks=p('<iframe title="custom devtools tab"sandbox="allow-scripts allow-same-origin allow-forms"style=flex:1;width:100%;border:none;background:var(--bg)>'),Cs=p("<div style=padding:16px><div class=card>"),Ts=p("<div style=color:var(--text-dim);font-size:12px>"),Es=p('<div style="display:flex;align-items:center;justify-content:space-between;padding:8px 0;border-bottom:1px solid var(--border)"><div><div style=font-weight:600></div></div><button type=button class=tab style="border:1px solid var(--border);border-radius:4px;padding:6px 14px;border-bottom-color:var(--border)">'),Ms=p("<div class=card><div class=card-title>Last response</div><code>"),As=p("<div style=padding:16px;flex:1;overflow:auto>"),Ls=e=>(()=>{var t=Ss();return l(t,u($,{get when(){return e.tab.view.type==="iframe"},get children(){return u(Rs,{get view(){return e.tab.view}})}}),null),l(t,u($,{get when(){return e.tab.view.type==="launch"},get children(){return u(qs,{get view(){return e.tab.view},get tabId(){return e.tab.id}})}}),null),l(t,u($,{get when(){return e.tab.view.type==="html"},get children(){return u(js,{get view(){return e.tab.view}})}}),null),t})(),Rs=e=>{const t=()=>{const r=e.view.src,n=(r.startsWith("http")||r.startsWith("//"),r),s=le();return s?`${n}${n.includes("?")?"&":"?"}token=${encodeURIComponent(s)}`:n};return(()=>{var r=ks();return S(()=>I(r,"src",t())),r})()},qs=e=>{const[t,r]=y(null),[n,s]=y(null),i=async c=>{r(c),s(null);try{const a=`${pe()}/tabs/${encodeURIComponent(e.tabId)}/actions/${encodeURIComponent(c)}`,o=le(),h=await fetch(o?`${a}?token=${encodeURIComponent(o)}`:a,{method:"POST",headers:o?{"x-devtools-token":o}:void 0});s(`${h.status} ${h.statusText}`)}catch(a){s(a instanceof Error?a.message:String(a))}finally{r(null)}};return(()=>{var c=Cs(),a=c.firstChild;return l(a,u(A,{get each(){return e.view.actions},children:o=>(()=>{var h=Es(),f=h.firstChild,d=f.firstChild,g=f.nextSibling;return l(d,()=>o.label),l(f,u($,{get when(){return o.description},get children(){var v=Ts();return l(v,()=>o.description),v}}),null),g.$$click=()=>{i(o.id)},l(g,()=>t()===o.id?"Running…":"Run"),S(()=>g.disabled=t()===o.id),h})()})),l(c,u($,{get when(){return n()},children:o=>(()=>{var h=Ms(),f=h.firstChild.nextSibling;return l(f,o),h})()}),null),c})()},js=e=>(()=>{var t=As();return S(()=>t.innerHTML=e.view.html),t})();z(["click"]);var Me=!1,ae=null,we=null;async function Os(){return j.setConnectionStatus("connecting"),await Ne(),we=Fe("/stream",e=>{if(!Me){if(j.setConnectionStatus("live"),Bt(),e.type==="metrics"){Ps(e),j.touch();return}if(e.type==="container"){Ne();return}}},()=>{Me||(j.setConnectionStatus("polling"),Bs())}),Ns}async function Ne(){const e=await Promise.allSettled([H.health(),H.metrics(),H.routeRegistry(),H.container(),H.queues(),H.ws()]);if(e.every(a=>a.status==="rejected"&&a.reason instanceof qt)){j.setAuthRequired(!0),j.setConnectionStatus("disconnected");return}C.authRequired()&&(j.setAuthRequired(!1),j.setAuthError(null));const[t,r,n,s,i,c]=e;t.status==="fulfilled"&&j.setHealth({status:t.value.status,errorRate:t.value.errorRate,uptime:t.value.uptime,adapters:t.value.adapters??{}}),r.status==="fulfilled"&&j.setMetrics({requests:r.value.requests,serverErrors:r.value.serverErrors,clientErrors:r.value.clientErrors,errorRate:r.value.errorRate,uptimeSeconds:r.value.uptimeSeconds,startedAt:r.value.startedAt}),n.status==="fulfilled"&&j.setRoutes(n.value.routes??[]),s.status==="fulfilled"&&j.setContainer(s.value.registrations??[]),i.status==="fulfilled"&&j.setQueues({enabled:i.value.enabled,queues:i.value.queues??[]}),c.status==="fulfilled"&&j.setWs(c.value),j.touch()}function Ps(e){const t=C.metrics();if(!t)return;j.setMetrics({...t,requests:e.requestCount,serverErrors:e.errorCount,clientErrors:e.clientErrorCount,errorRate:e.errorRate,uptimeSeconds:e.uptimeSeconds});const r=C.health();r&&j.setHealth({...r,uptime:e.uptimeSeconds,errorRate:e.errorRate})}function Bs(){ae||(ae=setInterval(()=>{Me||Ne()},5e3))}function Bt(){ae&&(clearInterval(ae),ae=null)}function Ns(){Me=!0,Bt(),we&&(we(),we=null),j.setConnectionStatus("disconnected")}var Is=p('<div class="fixed inset-0 z-[60] bg-slate-950/90 flex items-center justify-center p-4"><div class="bg-slate-900 border border-slate-700 rounded-2xl p-8 max-w-md w-full shadow-2xl"><div class="text-center mb-6"><h2 class="text-xl font-bold text-kick-500 mb-2">⚡ KickJS DevTools</h2><p class="text-sm text-slate-400">Enter your DevTools token to continue.</p><p class="text-xs text-slate-600 mt-1">The token is printed in the server console on startup, e.g. <code class="font-mono text-slate-500">[token: abc123…]</code></p></div><form><input type=text autofocus placeholder="Paste your token here…"class="w-full bg-slate-800 border border-slate-700 rounded-lg px-4 py-3 text-sm text-slate-200 placeholder-slate-500 focus:outline-none focus:border-kick-500 font-mono mb-3"><button type=submit class="w-full bg-kick-500 hover:bg-kick-600 text-white font-semibold py-2.5 rounded-lg transition-colors disabled:opacity-50">'),Ds=p('<p class="text-red-400 text-sm mb-3">'),Us=()=>{const[e,t]=y(""),[r,n]=y(!1),s=async()=>{const i=e().trim();if(!i){j.setAuthError("Token is required");return}n(!0),j.setAuthError(null);try{Lt(i),await H.health(),j.setAuthRequired(!1),j.setAuthError(null),t("")}catch{j.setAuthError("Invalid token — request was rejected.")}finally{n(!1)}};return u($,{get when(){return C.authRequired()},get children(){var i=Is(),c=i.firstChild.firstChild.nextSibling,a=c.firstChild,o=a.nextSibling;return c.addEventListener("submit",h=>{h.preventDefault(),s()}),a.$$input=h=>t(h.currentTarget.value),l(c,u($,{get when(){return C.authError()},children:h=>(()=>{var f=Ds();return l(f,h),f})()}),o),l(o,()=>r()?"Verifying…":"Authenticate"),S(()=>o.disabled=r()),S(()=>a.value=e()),i}})};z(["input"]);var zs=p('<span aria-hidden=true style="width:1px;background:var(--border);margin:6px 8px">'),Hs=p('<div class=card style=border-color:var(--warn);margin-top:16px><div class=card-title style=color:var(--warn)> custom-tab issue(s)</div><ul style="margin:8px 0 0;padding-left:20px;font-family:var(--font-mono);font-size:12px">'),Fs=p("<div class=app><header class=dt-header><div class=dt-header-brand><span class=dt-bolt aria-hidden=true>⚡</span><h1>KickJS DevTools</h1></div></header><nav class=tabs role=tablist></nav><main class=tab-body>"),xt=p("<button type=button role=tab>"),Gs=p("<span class=tab-badge>"),Vs=p("<li>: "),Ks=p("<div class=dt-conn><span aria-hidden=true></span><span class=dt-conn-label></span><span class=dt-conn-sep>·</span><span class=dt-conn-ts>Updated ");function Nt(){return[{id:"overview",label:"Overview"},{id:"runtime",label:"Runtime"},{id:"memory",label:"Memory"},{id:"topology",label:"Topology"},{id:"routes",label:"Routes",count:()=>C.routes().length||void 0},{id:"metrics",label:"Metrics"},{id:"container",label:"Container",count:()=>C.container().length||void 0},{id:"queues",label:"Queues",count:()=>C.queues().queues.length||void 0},{id:"graph",label:"Graph",count:()=>C.container().length||void 0}]}var Qs=new Set(Nt().map(e=>e.id)),Ws=()=>{const[e,t]=y((()=>{try{const h=localStorage.getItem("kickjs-devtools-tab");if(h)return h}catch{}return"overview"})()),[r,n]=y([]),[s,i]=y([]),c=Nt();he(()=>{H.tabs().then(({tabs:f,errors:d})=>{n(f.filter(g=>!Qs.has(g.id))),i(d)}).catch(()=>{});let h=null;Os().then(f=>{h=f}),fe(()=>h?.())});const a=h=>{t(h);try{localStorage.setItem("kickjs-devtools-tab",h)}catch{}queueMicrotask(()=>{document.querySelector(`[role="tab"][data-tab-id="${h}"]`)?.scrollIntoView({behavior:"smooth",inline:"center",block:"nearest"})})},o=()=>r().find(h=>h.id===e());return(()=>{var h=Fs(),f=h.firstChild;f.firstChild;var d=f.nextSibling,g=d.nextSibling;return l(f,u(Js,{}),null),l(d,u(A,{each:c,children:v=>(()=>{var m=xt();return m.$$click=()=>a(v.id),l(m,()=>v.label,null),l(m,u($,{get when(){return v.count?.()},children:x=>(()=>{var _=Gs();return l(_,x),_})()}),null),S(x=>{var _=v.id,w=`tab ${e()===v.id?"active":""}`,k=e()===v.id;return _!==x.e&&I(m,"data-tab-id",x.e=_),w!==x.t&&q(m,x.t=w),k!==x.a&&I(m,"aria-selected",x.a=k),x},{e:void 0,t:void 0,a:void 0}),m})()}),null),l(d,u($,{get when(){return r().length>0},get children(){return zs()}}),null),l(d,u(A,{get each(){return r()},children:v=>(()=>{var m=xt();return m.$$click=()=>a(v.id),l(m,()=>v.title),S(x=>{var _=v.id,w=`tab ${e()===v.id?"active":""}`,k=e()===v.id,E=v.title;return _!==x.e&&I(m,"data-tab-id",x.e=_),w!==x.t&&q(m,x.t=w),k!==x.a&&I(m,"aria-selected",x.a=k),E!==x.o&&I(m,"title",x.o=E),x},{e:void 0,t:void 0,a:void 0,o:void 0}),m})()}),null),l(g,u($,{get when(){return e()==="overview"},get children(){return u(Gr,{})}}),null),l(g,u($,{get when(){return e()==="runtime"},get children(){return u(nn,{})}}),null),l(g,u($,{get when(){return e()==="memory"},get children(){return u(xn,{})}}),null),l(g,u($,{get when(){return e()==="topology"},get children(){return u(Gn,{})}}),null),l(g,u($,{get when(){return e()==="routes"},get children(){return u(ll,{})}}),null),l(g,u($,{get when(){return e()==="metrics"},get children(){return u(gl,{})}}),null),l(g,u($,{get when(){return e()==="container"},get children(){return u(Fl,{})}}),null),l(g,u($,{get when(){return e()==="queues"},get children(){return u(is,{})}}),null),l(g,u($,{get when(){return e()==="graph"},get children(){return u(bs,{})}}),null),l(g,u($,{get when(){return o()},children:v=>u(Ls,{get tab(){return v()}})}),null),l(g,u($,{get when(){return Ue(()=>s().length>0)()&&e()==="overview"},get children(){var v=Hs(),m=v.firstChild,x=m.firstChild,_=m.nextSibling;return l(m,()=>s().length,x),l(_,u(A,{get each(){return s()},children:w=>(()=>{var k=Vs(),E=k.firstChild;return l(k,()=>w.source,E),l(k,()=>w.reason,null),k})()})),v}}),null),l(h,u(kl,{}),null),l(h,u(Us,{}),null),h})()},Js=()=>{const e=r=>r==="live"?"Live":r==="polling"?"Polling":r==="disconnected"?"Disconnected":"Connecting…",t=r=>r?r.toLocaleTimeString():"never";return(()=>{var r=Ks(),n=r.firstChild,s=n.nextSibling,i=s.nextSibling.nextSibling;return i.firstChild,l(s,()=>e(C.connectionStatus())),l(i,()=>t(C.lastUpdate()),null),S(()=>q(n,`dt-pulse dt-pulse-${C.connectionStatus()}`)),r})()};z(["click"]);var It=document.getElementById("root");if(!It)throw new Error("#root not found");nr(()=>u(Ws,{}),It);
|
|
1
|
+
(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const s of document.querySelectorAll('link[rel="modulepreload"]'))n(s);new MutationObserver(s=>{for(const i of s)if(i.type==="childList")for(const u of i.addedNodes)u.tagName==="LINK"&&u.rel==="modulepreload"&&n(u)}).observe(document,{childList:!0,subtree:!0});function r(s){const i={};return s.integrity&&(i.integrity=s.integrity),s.referrerPolicy&&(i.referrerPolicy=s.referrerPolicy),s.crossOrigin==="use-credentials"?i.credentials="include":s.crossOrigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function n(s){if(s.ep)return;s.ep=!0;const i=r(s);fetch(s.href,i)}})();var L={context:void 0,registry:void 0,effects:void 0,done:!1,getContextId(){return nt(this.context.count)},getNextContextId(){return nt(this.context.count++)}};function nt(e){const t=String(e),r=t.length-1;return L.context.id+(r?String.fromCharCode(96+r):"")+t}function Oe(e){L.context=e}function Kt(){return{...L.context,id:L.getNextContextId(),count:0}}var Qt=(e,t)=>e===t,Wt=Symbol("solid-track"),Ce={equals:Qt},lt=null,_t=Tt,F=1,de=2,wt={owned:null,cleanups:null,context:null,owner:null},E=null,x=null,ge=null,re=null,R=null,B=null,N=null,Re=0;function we(e,t){const r=R,n=E,s=e.length===0,i=t===void 0?n:t,u=s?wt:{owned:null,cleanups:null,context:i?i.context:null,owner:i},o=s?e:()=>e(()=>Q(()=>Y(u)));E=u,R=null;try{return W(o,!0)}finally{R=r,E=n}}function _(e,t){t=t?Object.assign({},Ce,t):Ce;const r={value:e,observers:null,observerSlots:null,comparator:t.equals||void 0},n=s=>(typeof s=="function"&&(x&&x.running&&x.sources.has(r)?s=s(r.tValue):s=s(r.value)),Ct(r,s));return[kt.bind(r),n]}function S(e,t,r){const n=ze(e,t,!1,F);ge&&x&&x.running?B.push(n):pe(n)}function St(e,t,r){_t=er;const n=ze(e,t,!1,F),s=Be&&Yt(Be);s&&(n.suspense=s),(!r||!r.render)&&(n.user=!0),N?N.push(n):pe(n)}function P(e,t,r){r=r?Object.assign({},Ce,r):Ce;const n=ze(e,t,!0,0);return n.observers=null,n.observerSlots=null,n.comparator=r.equals||void 0,ge&&x&&x.running?(n.tState=F,B.push(n)):pe(n),kt.bind(n)}function Q(e){if(!re&&R===null)return e();const t=R;R=null;try{return re?re.untrack(e):e()}finally{R=t}}function ve(e){St(()=>Q(e))}function le(e){return E===null||(E.cleanups===null?E.cleanups=[e]:E.cleanups.push(e)),e}function Jt(e){if(x&&x.running)return e(),x.done;const t=R,r=E;return Promise.resolve().then(()=>{R=t,E=r;let n;return(ge||Be)&&(n=x||(x={sources:new Set,effects:[],promises:new Set,disposed:new Set,queue:new Set,running:!0}),n.done||(n.done=new Promise(s=>n.resolve=s)),n.running=!0),W(e,!1),R=E=null,n?n.done:void 0})}var[vi,st]=_(!1);function Yt(e){let t;return E&&E.context&&(t=E.context[e.id])!==void 0?t:e.defaultValue}var Be;function kt(){const e=x&&x.running;if(this.sources&&(e?this.tState:this.state))if((e?this.tState:this.state)===F)pe(this);else{const t=B;B=null,W(()=>Te(this),!1),B=t}if(R){const t=this.observers?this.observers.length:0;R.sources?(R.sources.push(this),R.sourceSlots.push(t)):(R.sources=[this],R.sourceSlots=[t]),this.observers?(this.observers.push(R),this.observerSlots.push(R.sources.length-1)):(this.observers=[R],this.observerSlots=[R.sources.length-1])}return e&&x.sources.has(this)?this.tValue:this.value}function Ct(e,t,r){let n=x&&x.running&&x.sources.has(e)?e.tValue:e.value;if(!e.comparator||!e.comparator(n,t)){if(x){const s=x.running;(s||!r&&x.sources.has(e))&&(x.sources.add(e),e.tValue=t),s||(e.value=t)}else e.value=t;e.observers&&e.observers.length&&W(()=>{for(let s=0;s<e.observers.length;s+=1){const i=e.observers[s],u=x&&x.running;u&&x.disposed.has(i)||((u?!i.tState:!i.state)&&(i.pure?B.push(i):N.push(i),i.observers&&Mt(i)),u?i.tState=F:i.state=F)}if(B.length>1e6)throw B=[],new Error},!1)}return t}function pe(e){if(!e.fn)return;Y(e);const t=Re;it(e,x&&x.running&&x.sources.has(e)?e.tValue:e.value,t),x&&!x.running&&x.sources.has(e)&&queueMicrotask(()=>{W(()=>{x&&(x.running=!0),R=E=e,it(e,e.tValue,t),R=E=null},!1)})}function it(e,t,r){let n;const s=E,i=R;R=E=e;try{n=e.fn(t)}catch(u){return e.pure&&(x&&x.running?(e.tState=F,e.tOwned&&e.tOwned.forEach(Y),e.tOwned=void 0):(e.state=F,e.owned&&e.owned.forEach(Y),e.owned=null)),e.updatedAt=r+1,He(u)}finally{R=i,E=s}(!e.updatedAt||e.updatedAt<=r)&&(e.updatedAt!=null&&"observers"in e?Ct(e,n,!0):x&&x.running&&e.pure?(x.sources.has(e)||(e.value=n),x.sources.add(e),e.tValue=n):e.value=n,e.updatedAt=r)}function ze(e,t,r,n=F,s){const i={fn:e,state:n,updatedAt:null,owned:null,sources:null,sourceSlots:null,cleanups:null,value:t,owner:E,context:E?E.context:null,pure:r};if(x&&x.running&&(i.state=0,i.tState=n),E===null||E!==wt&&(x&&x.running&&E.pure?E.tOwned?E.tOwned.push(i):E.tOwned=[i]:E.owned?E.owned.push(i):E.owned=[i]),re&&i.fn){const u=i.fn,[o,a]=_(void 0,{equals:!1}),h=re.factory(u,a);le(()=>h.dispose());let f;const d=()=>Jt(a).then(()=>{f&&(f.dispose(),f=void 0)});i.fn=g=>(o(),x&&x.running?(f||(f=re.factory(u,d)),f.track(g)):h.track(g))}return i}function he(e){const t=x&&x.running;if((t?e.tState:e.state)===0)return;if((t?e.tState:e.state)===de)return Te(e);if(e.suspense&&Q(e.suspense.inFallback))return e.suspense.effects.push(e);const r=[e];for(;(e=e.owner)&&(!e.updatedAt||e.updatedAt<Re);){if(t&&x.disposed.has(e))return;(t?e.tState:e.state)&&r.push(e)}for(let n=r.length-1;n>=0;n--){if(e=r[n],t){let s=e,i=r[n+1];for(;(s=s.owner)&&s!==i;)if(x.disposed.has(s))return}if((t?e.tState:e.state)===F)pe(e);else if((t?e.tState:e.state)===de){const s=B;B=null,W(()=>Te(e,r[0]),!1),B=s}}}function W(e,t){if(B)return e();let r=!1;t||(B=[]),N?r=!0:N=[],Re++;try{const n=e();return Xt(r),n}catch(n){r||(N=null),B=null,He(n)}}function Xt(e){if(B&&(ge&&x&&x.running?Zt(B):Tt(B),B=null),e)return;let t;if(x){if(!x.promises.size&&!x.queue.size){const n=x.sources,s=x.disposed;N.push.apply(N,x.effects),t=x.resolve;for(const i of N)"tState"in i&&(i.state=i.tState),delete i.tState;x=null,W(()=>{for(const i of s)Y(i);for(const i of n){if(i.value=i.tValue,i.owned)for(let u=0,o=i.owned.length;u<o;u++)Y(i.owned[u]);i.tOwned&&(i.owned=i.tOwned),delete i.tValue,delete i.tOwned,i.tState=0}st(!1)},!1)}else if(x.running){x.running=!1,x.effects.push.apply(x.effects,N),N=null,st(!0);return}}const r=N;N=null,r.length&&W(()=>_t(r),!1),t&&t()}function Tt(e){for(let t=0;t<e.length;t++)he(e[t])}function Zt(e){for(let t=0;t<e.length;t++){const r=e[t],n=x.queue;n.has(r)||(n.add(r),ge(()=>{n.delete(r),W(()=>{x.running=!0,he(r)},!1),x&&(x.running=!1)}))}}function er(e){let t,r=0;for(t=0;t<e.length;t++){const n=e[t];n.user?e[r++]=n:he(n)}if(L.context){if(L.count){L.effects||(L.effects=[]),L.effects.push(...e.slice(0,r));return}Oe()}for(L.effects&&(L.done||!L.count)&&(e=[...L.effects,...e],r+=L.effects.length,delete L.effects),t=0;t<r;t++)he(e[t])}function Te(e,t){const r=x&&x.running;r?e.tState=0:e.state=0;for(let n=0;n<e.sources.length;n+=1){const s=e.sources[n];if(s.sources){const i=r?s.tState:s.state;i===F?s!==t&&(!s.updatedAt||s.updatedAt<Re)&&he(s):i===de&&Te(s,t)}}}function Mt(e){const t=x&&x.running;for(let r=0;r<e.observers.length;r+=1){const n=e.observers[r];(t?!n.tState:!n.state)&&(t?n.tState=de:n.state=de,n.pure?B.push(n):N.push(n),n.observers&&Mt(n))}}function Y(e){let t;if(e.sources)for(;e.sources.length;){const r=e.sources.pop(),n=e.sourceSlots.pop(),s=r.observers;if(s&&s.length){const i=s.pop(),u=r.observerSlots.pop();n<s.length&&(i.sourceSlots[u]=n,s[n]=i,r.observerSlots[n]=u)}}if(e.tOwned){for(t=e.tOwned.length-1;t>=0;t--)Y(e.tOwned[t]);delete e.tOwned}if(x&&x.running&&e.pure)Et(e,!0);else if(e.owned){for(t=e.owned.length-1;t>=0;t--)Y(e.owned[t]);e.owned=null}if(e.cleanups){for(t=e.cleanups.length-1;t>=0;t--)e.cleanups[t]();e.cleanups=null}x&&x.running?e.tState=0:e.state=0}function Et(e,t){if(t||(e.tState=0,x.disposed.add(e)),e.owned)for(let r=0;r<e.owned.length;r++)Et(e.owned[r])}function tr(e){return e instanceof Error?e:new Error(typeof e=="string"?e:"Unknown error",{cause:e})}function at(e,t,r){try{for(const n of t)n(e)}catch(n){He(n,r&&r.owner||null)}}function He(e,t=E){const r=lt&&t&&t.context&&t.context[lt],n=tr(e);if(!r)throw n;N?N.push({fn(){at(n,r,t)},state:F}):at(n,r,t)}var rr=Symbol("fallback");function ot(e){for(let t=0;t<e.length;t++)e[t]()}function nr(e,t,r={}){let n=[],s=[],i=[],u=0,o=t.length>1?[]:null;return le(()=>ot(i)),()=>{let a=e()||[],h=a.length,f,d;return a[Wt],Q(()=>{let p,m,$,y,w,M,k,T,I;if(h===0)u!==0&&(ot(i),i=[],n=[],s=[],u=0,o&&(o=[])),r.fallback&&(n=[rr],s[0]=we(K=>(i[0]=K,r.fallback())),u=1);else if(u===0){for(s=new Array(h),d=0;d<h;d++)n[d]=a[d],s[d]=we(g);u=h}else{for($=new Array(h),y=new Array(h),o&&(w=new Array(h)),M=0,k=Math.min(u,h);M<k&&n[M]===a[M];M++);for(k=u-1,T=h-1;k>=M&&T>=M&&n[k]===a[T];k--,T--)$[T]=s[k],y[T]=i[k],o&&(w[T]=o[k]);for(p=new Map,m=new Array(T+1),d=T;d>=M;d--)I=a[d],f=p.get(I),m[d]=f===void 0?-1:f,p.set(I,d);for(f=M;f<=k;f++)I=n[f],d=p.get(I),d!==void 0&&d!==-1?($[d]=s[f],y[d]=i[f],o&&(w[d]=o[f]),d=m[d],p.set(I,d)):i[f]();for(d=M;d<h;d++)d in $?(s[d]=$[d],i[d]=y[d],o&&(o[d]=w[d],o[d](d))):s[d]=we(g);s=s.slice(0,u=h),n=a.slice(0)}return s});function g(p){if(i[d]=p,o){const[m,$]=_(d);return o[d]=$,t(a[d],m)}return t(a[d])}}}var lr=!1;function c(e,t){if(lr&&L.context){const r=L.context;Oe(Kt());const n=Q(()=>e(t||{}));return Oe(r),n}return Q(()=>e(t||{}))}var sr=e=>`Stale read from <${e}>.`;function A(e){const t="fallback"in e&&{fallback:()=>e.fallback};return P(nr(()=>e.each,e.children,t||void 0))}function b(e){const t=e.keyed,r=P(()=>e.when,void 0,void 0),n=t?r:P(r,void 0,{equals:(s,i)=>!s==!i});return P(()=>{const s=n();if(s){const i=e.children;return typeof i=="function"&&i.length>0?Q(()=>i(t?s:()=>{if(!Q(n))throw sr("Show");return r()})):i}return e.fallback},void 0,void 0)}var Fe=e=>P(()=>e());function ir(e,t,r){let n=r.length,s=t.length,i=n,u=0,o=0,a=t[s-1].nextSibling,h=null;for(;u<s||o<i;){if(t[u]===r[o]){u++,o++;continue}for(;t[s-1]===r[i-1];)s--,i--;if(s===u){const f=i<n?o?r[o-1].nextSibling:r[i-o]:a;for(;o<i;)e.insertBefore(r[o++],f)}else if(i===o)for(;u<s;)(!h||!h.has(t[u]))&&t[u].remove(),u++;else if(t[u]===r[i-1]&&r[o]===t[s-1]){const f=t[--s].nextSibling;e.insertBefore(r[o++],t[u++].nextSibling),e.insertBefore(r[--i],f),t[s]=r[i]}else{if(!h){h=new Map;let d=o;for(;d<i;)h.set(r[d],d++)}const f=h.get(t[u]);if(f!=null)if(o<f&&f<i){let d=u,g=1,p;for(;++d<s&&d<i&&!((p=h.get(t[d]))==null||p!==f+g);)g++;if(g>f-o){const m=t[u];for(;o<f;)e.insertBefore(r[o++],m)}else e.replaceChild(r[o++],t[u++])}else u++;else t[u++].remove()}}}var ct="_$DX_DELEGATE";function ar(e,t,r,n={}){let s;return we(i=>{s=i,t===document?e():l(t,e(),t.firstChild?null:void 0,r)},n.owner),()=>{s(),t.textContent=""}}function v(e,t,r,n){let s;const i=()=>{const o=n?document.createElementNS("http://www.w3.org/1998/Math/MathML","template"):document.createElement("template");return o.innerHTML=e,r?o.content.firstChild.firstChild:n?o.firstChild:o.content.firstChild},u=t?()=>Q(()=>document.importNode(s||(s=i()),!0)):()=>(s||(s=i())).cloneNode(!0);return u.cloneNode=u,u}function z(e,t=window.document){const r=t[ct]||(t[ct]=new Set);for(let n=0,s=e.length;n<s;n++){const i=e[n];r.has(i)||(r.add(i),t.addEventListener(i,or))}}function O(e,t,r){Ge(e)||(r==null?e.removeAttribute(t):e.setAttribute(t,r))}function q(e,t){Ge(e)||(t==null?e.removeAttribute("class"):e.className=t)}function l(e,t,r,n){if(r!==void 0&&!n&&(n=[]),typeof t!="function")return Me(e,t,n,r);S(s=>Me(e,t(),s,r),n)}function Ge(e){return!!L.context&&!L.done&&(!e||e.isConnected)}function or(e){if(L.registry&&L.events&&L.events.find(([a,h])=>h===e))return;let t=e.target;const r=`$$${e.type}`,n=e.target,s=e.currentTarget,i=a=>Object.defineProperty(e,"target",{configurable:!0,value:a}),u=()=>{const a=t[r];if(a&&!t.disabled){const h=t[`${r}Data`];if(h!==void 0?a.call(t,h,e):a.call(t,e),e.cancelBubble)return}return t.host&&typeof t.host!="string"&&!t.host._$host&&t.contains(e.target)&&i(t.host),!0},o=()=>{for(;u()&&(t=t._$host||t.parentNode||t.host););};if(Object.defineProperty(e,"currentTarget",{configurable:!0,get(){return t||document}}),L.registry&&!L.done&&(L.done=_$HY.done=!0),e.composedPath){const a=e.composedPath();i(a[0]);for(let h=0;h<a.length-2&&(t=a[h],!!u());h++){if(t._$host){t=t._$host,o();break}if(t.parentNode===s)break}}else o();i(n)}function Me(e,t,r,n,s){const i=Ge(e);if(i){!r&&(r=[...e.childNodes]);let a=[];for(let h=0;h<r.length;h++){const f=r[h];f.nodeType===8&&f.data.slice(0,2)==="!$"?f.remove():a.push(f)}r=a}for(;typeof r=="function";)r=r();if(t===r)return r;const u=typeof t,o=n!==void 0;if(e=o&&r[0]&&r[0].parentNode||e,u==="string"||u==="number"){if(i||u==="number"&&(t=t.toString(),t===r))return r;if(o){let a=r[0];a&&a.nodeType===3?a.data!==t&&(a.data=t):a=document.createTextNode(t),r=ee(e,r,n,a)}else r!==""&&typeof r=="string"?r=e.firstChild.data=t:r=e.textContent=t}else if(t==null||u==="boolean"){if(i)return r;r=ee(e,r,n)}else{if(u==="function")return S(()=>{let a=t();for(;typeof a=="function";)a=a();r=Me(e,a,r,n)}),()=>r;if(Array.isArray(t)){const a=[],h=r&&Array.isArray(r);if(Ie(a,t,r,s))return S(()=>r=Me(e,a,r,n,!0)),()=>r;if(i){if(!a.length)return r;if(n===void 0)return r=[...e.childNodes];let f=a[0];if(f.parentNode!==e)return r;const d=[f];for(;(f=f.nextSibling)!==n;)d.push(f);return r=d}if(a.length===0){if(r=ee(e,r,n),o)return r}else h?r.length===0?ut(e,a,n):ir(e,r,a):(r&&ee(e),ut(e,a));r=a}else if(t.nodeType){if(i&&t.parentNode)return r=o?[t]:t;if(Array.isArray(r)){if(o)return r=ee(e,r,n,t);ee(e,r,null,t)}else r==null||r===""||!e.firstChild?e.appendChild(t):e.replaceChild(t,e.firstChild);r=t}}return r}function Ie(e,t,r,n){let s=!1;for(let i=0,u=t.length;i<u;i++){let o=t[i],a=r&&r[e.length],h;if(!(o==null||o===!0||o===!1))if((h=typeof o)=="object"&&o.nodeType)e.push(o);else if(Array.isArray(o))s=Ie(e,o,a)||s;else if(h==="function")if(n){for(;typeof o=="function";)o=o();s=Ie(e,Array.isArray(o)?o:[o],Array.isArray(a)?a:[a])||s}else e.push(o),s=!0;else{const f=String(o);a&&a.nodeType===3&&a.data===f?e.push(a):e.push(document.createTextNode(f))}}return s}function ut(e,t,r=null){for(let n=0,s=t.length;n<s;n++)e.insertBefore(t[n],r)}function ee(e,t,r,n){if(r===void 0)return e.textContent="";const s=n||document.createTextNode("");if(t.length){let i=!1;for(let u=t.length-1;u>=0;u--){const o=t[u];if(s!==o){const a=o.parentNode===e;!i&&!u?a?e.replaceChild(s,o):e.insertBefore(s,r):a&&o.remove()}else i=!0}}else e.insertBefore(s,r);return[s]}var At="kickjs-devtools-theme";function cr(){try{const e=localStorage.getItem(At);if(e==="dark"||e==="light"||e==="system")return e}catch{}return"system"}function ur(){return typeof window>"u"||!window.matchMedia?"dark":window.matchMedia("(prefers-color-scheme: light)").matches?"light":"dark"}var[Lt,dr]=_(cr()),[hr,fr]=_(ur());if(typeof window<"u"&&window.matchMedia){const e=window.matchMedia("(prefers-color-scheme: light)"),t=r=>fr(r.matches?"light":"dark");e.addEventListener("change",t)}var je=Lt;function Rt(){const e=Lt();return e==="system"?hr():e}function gr(e){dr(e);try{localStorage.setItem(At,e)}catch{}}function vr(){St(()=>{const e=Rt();document.documentElement.dataset.theme=e}),le(()=>{delete document.documentElement.dataset.theme})}var[pr,mr]=_("connecting"),[br,dt]=_(null),[xr,$r]=_(!1),[yr,_r]=_(null),[wr,Sr]=_(null),[kr,Cr]=_(null),[Tr,Mr]=_([]),[Er,Ar]=_([]),[Lr,Rr]=_({enabled:!1,queues:[]}),[qr,jr]=_({enabled:!1}),C={connectionStatus:pr,lastUpdate:br,authRequired:xr,authError:yr,health:wr,metrics:kr,routes:Tr,container:Er,queues:Lr,ws:qr},j={setConnectionStatus:mr,setLastUpdate:dt,setAuthRequired:$r,setAuthError:_r,setHealth:Sr,setMetrics:Cr,setRoutes:Mr,setContainer:Ar,setQueues:Rr,setWs:jr,touch(){dt(new Date)}};function D(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KiB`:e<1024*1024*1024?`${(e/1024/1024).toFixed(1)} MiB`:`${(e/1024/1024/1024).toFixed(2)} GiB`}function Pr(e){if(e===0)return"0";const t=e*60;return Math.abs(t)<1024*1024?`${(t/1024).toFixed(1)} KiB/min`:`${(t/1024/1024).toFixed(1)} MiB/min`}function Z(e){return e<1?`${e.toFixed(2)} ms`:e<100?`${e.toFixed(1)} ms`:`${Math.round(e)} ms`}function Ve(e){const t=Math.floor(e);return t<60?`${t}s`:t<3600?`${Math.floor(t/60)}m ${t%60}s`:`${Math.floor(t/3600)}h ${Math.floor(t%3600/60)}m ${t%60}s`}function Ee(e){return`${Math.round(e*100)}%`}var Or=v('<span class=dt-tip tabindex=0><svg class=dt-tip-icon viewBox="0 0 24 24"aria-hidden=true><circle cx=12 cy=12 r=9 fill=none stroke=currentColor stroke-width=1.5></circle><path d="M12 8h.01M12 11v6"stroke=currentColor stroke-width=2 stroke-linecap=round fill=none></path></svg><span role=tooltip>'),Br=v('<button type=button class="dt-tip dt-tip-clickable"><svg class=dt-tip-icon viewBox="0 0 24 24"aria-hidden=true><circle cx=12 cy=12 r=9 fill=none stroke=currentColor stroke-width=1.5></circle><path d="M12 8h.01M12 11v6"stroke=currentColor stroke-width=2 stroke-linecap=round fill=none>'),Ir=v('<div class="fixed inset-0 z-50 bg-slate-950/80 flex items-center justify-center p-4"><div class="bg-slate-900 border border-slate-700 rounded-2xl p-6 max-w-lg w-full shadow-2xl max-h-[90vh] overflow-y-auto"><div class="flex items-start justify-between mb-4"><h2 class="text-lg font-semibold text-slate-200"></h2><button type=button class="text-slate-500 hover:text-slate-300 p-1"aria-label=Close><svg class="w-5 h-5"fill=none stroke=currentColor viewBox="0 0 24 24"><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M6 18L18 6M6 6l12 12"></path></svg></button></div><div class="text-sm text-slate-300 space-y-3">'),Ne={"heap.used":{short:"V8-allocated memory currently used by JavaScript objects.",detail:"Grows as your code allocates objects, shrinks after GC frees them. A consistently rising heap-used line on the sparkline is the textbook leak signature."},"heap.total":{short:"V8-allocated memory the JS heap is currently sized to use.",detail:"Larger than heap-used; V8 reserves headroom so allocations don't pause to grow the heap. Bumps up in 1-8 MiB jumps as the heap expands."},rss:{short:"Total memory resident in physical RAM for this Node process.",detail:'Includes the JS heap, native buffers, V8 internal structures, and code. Always larger than heap-used; the gap is "everything the OS sees" minus "JS objects".'},external:{short:"Memory used by C++ objects bound to JS (Buffers, native bindings)."},"array-buffers":{short:"Memory used by ArrayBuffer / SharedArrayBuffer instances."},"event-loop.p99":{short:"99% of event-loop ticks completed within this time.",detail:"Sustained values above ~50ms mean some synchronous operation is blocking the loop. Common culprits: large JSON.parse, sync crypto, blocking DB drivers."},gc:{short:"Garbage-collector activity since process start.",detail:"Total run count and cumulative pause time. Frequent GC with low reclaim ratio = leak; rare GC with healthy reclaim = good citizen."},"leak.risk":{short:"Heap-growth slope over the recent window — stable / warn / critical.",detail:"Bucketed from heap-growth in MB/min: <5 = ok, <20 = warn, ≥20 = critical. Critical sustained for >5 minutes is the moment to capture a heap snapshot."},"gc.reclaim":{short:"Average ratio of memory freed by each GC pass.",detail:"Trending toward zero means GC can't free anything — strong leak indicator. Healthy apps reclaim 20-60% on each major GC."},"heap.utilization":{short:"Fraction of V8's hard heap-size limit currently in use.",detail:"Approaching 1 means the process is close to OOM. Use --max-old-space-size to raise the limit if your workload is memory-bound."},requests:{short:"Total HTTP requests handled since process start."},"server-errors":{short:"5xx responses — server-side failures."},"client-errors":{short:"4xx responses — bad client input, missing routes, auth denials."},"error-rate":{short:"Server errors as a percentage of total requests.",detail:"Computed across the lifetime of the process. Spikes typically signal upstream dependency failures; sustained elevation = code bug."},uptime:{short:"How long this Node process has been running."},"latency.avg":{short:"Mean response time per route (sum of all calls / call count)."},"latency.p50":{short:"Median — half the requests complete faster than this."},"latency.p95":{short:"95% of requests complete within this time."},"latency.p99":{short:"99% of requests complete within this time. Outlier-sensitive."},"latency.max":{short:"Slowest single response observed since process start."},"resolve.count":{short:"Number of times this token was resolved from the DI container."},"resolve.duration":{short:"How long the container took to resolve this token (ms)."},"post-construct":{short:"@PostConstruct lifecycle status: done / failed / none.",detail:'A failed PostConstruct means the service registered but its async init threw. The token is left in a "registered" state; resolve() will throw the original error.'}},U=e=>{const t=()=>e.text??Ne[e.metric??""]?.short??"",r=e.placement??"top";return(()=>{var n=Or(),s=n.firstChild.nextSibling;return q(s,`dt-tip-pop dt-tip-pop-${r}`),l(s,t),S(()=>O(n,"aria-label",t())),n})()},Nr=e=>{const[t,r]=_(!1);return[(()=>{var n=Br();return n.$$click=()=>r(!0),S(()=>O(n,"aria-label",`More info: ${e.title}`)),n})(),c(b,{get when(){return t()},get children(){return c(Dr,{get title(){return e.title},onClose:()=>r(!1),get children(){return e.children}})}})]},Dr=e=>(()=>{var t=Ir(),r=t.firstChild.firstChild,n=r.firstChild,s=n.nextSibling,i=r.nextSibling;return t.$$click=u=>{u.target===u.currentTarget&&e.onClose()},l(n,()=>e.title),s.$$click=()=>e.onClose(),l(i,()=>e.children),t})();z(["click"]);var Ur=v('<div class="grid grid-cols-1 md:grid-cols-3 gap-4">'),zr=v('<div class="bg-surface-1 rounded-xl border border-border p-5"><h2 class="text-xs font-semibold uppercase tracking-wider text-text-muted mb-3">Health'),qt=v('<p class="text-text-muted italic">Loading…'),Hr=v("<span>"),ne=v('<span class="font-semibold tabular-nums">'),jt=v("<div class=mt-1>"),Fr=v('<div class="border-t border-border mt-2 pt-2"><button type=button class="text-xs text-text-muted hover:text-text-strong flex items-center gap-1"><svg fill=none stroke=currentColor viewBox="0 0 24 24"aria-hidden=true><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M9 5l7 7-7 7"></path></svg>Adapters (<!>)'),Gr=v('<div class="flex items-center justify-between py-1"><span class="text-text-secondary text-sm"></span><span>'),Vr=v('<div class="bg-surface-1 rounded-xl border border-border p-5"><h2 class="text-xs font-semibold uppercase tracking-wider text-text-muted mb-3">Metrics'),Kr=v('<span class="font-semibold tabular-nums text-red-400">'),Qr=v('<span class="font-semibold tabular-nums text-amber-400">'),Wr=v('<span class="font-semibold text-sm">'),Jr=v('<span class="font-semibold tabular-nums text-emerald-400">'),Yr=v('<div class="border-t border-border mt-2 pt-2"><button type=button class="text-xs text-text-muted hover:text-text-strong flex items-center gap-1"><svg fill=none stroke=currentColor viewBox="0 0 24 24"aria-hidden=true><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M9 5l7 7-7 7"></path></svg>Namespaces (<!>)'),Xr=v('<div class="bg-surface-1 rounded-xl border border-border p-5"><h2 class="text-xs font-semibold uppercase tracking-wider text-text-muted mb-3">WebSocket'),Zr=v('<p class="text-text-muted italic">No WsAdapter detected'),en=v('<div class="flex items-center justify-between py-1"><span class="text-text-secondary text-sm font-mono"></span><span class=text-sm> conn / <!> handlers'),tn=v('<div class="flex items-center justify-between mb-2"><span class=text-text-secondary>'),rn=()=>(()=>{var e=Ur();return l(e,c(nn,{}),null),l(e,c(ln,{}),null),l(e,c(sn,{}),null),e})(),nn=()=>{const[e,t]=_(!1);return(()=>{var r=zr();return r.firstChild,l(r,c(b,{get when(){return C.health()},get fallback(){return qt()},children:n=>[c(G,{label:"Status",get children(){var s=Hr();return l(s,()=>n().status),S(()=>q(s,`badge ${an(n().status)}`)),s}}),c(G,{label:"Uptime",get children(){var s=ne();return l(s,()=>Ve(n().uptime)),s}}),c(G,{label:"Error rate",get children(){var s=ne();return l(s,()=>Ee(n().errorRate),null),l(s,c(U,{metric:"error-rate"}),null),s}}),c(b,{get when(){return Object.keys(n().adapters).length>0},get children(){var s=Fr(),i=s.firstChild,u=i.firstChild,o=u.nextSibling.nextSibling;return o.nextSibling,i.$$click=()=>t(a=>!a),l(i,()=>Object.keys(n().adapters).length,o),l(s,c(b,{get when(){return e()},get children(){var a=jt();return l(a,c(A,{get each(){return Object.entries(n().adapters)},children:([h,f])=>(()=>{var d=Gr(),g=d.firstChild,p=g.nextSibling;return l(g,h),q(p,`badge ${f==="running"?"badge-ok":"badge-warn"}`),l(p,f),d})()})),a}}),null),S(()=>O(u,"class",`w-3 h-3 transition-transform ${e()?"rotate-90":""}`)),s}})]}),null),r})()},ln=()=>(()=>{var e=Vr();return e.firstChild,l(e,c(b,{get when(){return C.metrics()},get fallback(){return qt()},children:t=>[c(G,{label:"Total requests",get children(){var r=ne();return l(r,()=>t().requests.toLocaleString()),r}}),c(G,{label:"5xx errors",get children(){var r=Kr();return l(r,()=>t().serverErrors),r}}),c(G,{label:"4xx errors",get children(){var r=Qr();return l(r,()=>t().clientErrors),r}}),c(G,{label:"Started",get children(){var r=Wr();return l(r,()=>new Date(t().startedAt).toLocaleTimeString()),r}})]}),null),e})(),sn=()=>{const[e,t]=_(!1);return(()=>{var r=Xr();return r.firstChild,l(r,c(b,{get when(){return C.ws().enabled},get fallback(){return Zr()},get children(){return[c(G,{label:"Active",get children(){var n=Jr();return l(n,()=>C.ws().activeConnections??0),n}}),c(G,{label:"Total",get children(){var n=ne();return l(n,()=>C.ws().totalConnections??0),n}}),c(G,{label:"Messages in",get children(){var n=ne();return l(n,()=>C.ws().messagesReceived??0),n}}),c(G,{label:"Messages out",get children(){var n=ne();return l(n,()=>C.ws().messagesSent??0),n}}),c(b,{get when(){return Fe(()=>!!C.ws().namespaces)()&&Object.keys(C.ws().namespaces??{}).length>0},get children(){var n=Yr(),s=n.firstChild,i=s.firstChild,u=i.nextSibling.nextSibling;return u.nextSibling,s.$$click=()=>t(o=>!o),l(s,()=>Object.keys(C.ws().namespaces??{}).length,u),l(n,c(b,{get when(){return e()},get children(){var o=jt();return l(o,c(A,{get each(){return Object.entries(C.ws().namespaces??{})},children:([a,h])=>(()=>{var f=en(),d=f.firstChild,g=d.nextSibling,p=g.firstChild,m=p.nextSibling;return m.nextSibling,l(d,a),l(g,()=>h.connections,p),l(g,()=>h.handlers,m),f})()})),o}}),null),S(()=>O(i,"class",`w-3 h-3 transition-transform ${e()?"rotate-90":""}`)),n}})]}}),null),r})()},G=e=>(()=>{var t=tn(),r=t.firstChild;return l(r,()=>e.label),l(t,()=>e.children,null),t})();function an(e){return e==="healthy"?"badge-ok":e==="degraded"?"badge-warn":"badge-critical"}z(["click"]);var on=v("<svg class=sparkline preserveAspectRatio=none aria-hidden=true><path fill=none stroke-width=1.5 stroke-linejoin=round stroke-linecap=round>"),Se=e=>{const t=()=>e.width??200,n=P(()=>{const s=e.values;if(s.length<2)return"";const i=Math.min(...s),u=Math.max(...s)-i||1,o=t()/(s.length-1),a=f=>40-(f-i)/u*36-2;let h=`M0 ${a(s[0]).toFixed(2)}`;for(let f=1;f<s.length;f++)h+=` L${(f*o).toFixed(2)} ${a(s[f]).toFixed(2)}`;return h});return(()=>{var s=on(),i=s.firstChild;return S(u=>{var o=`0 0 ${t()} 40`,a=n(),h=e.stroke??"var(--color-accent)";return o!==u.e&&O(s,"viewBox",u.e=o),a!==u.t&&O(i,"d",u.t=a),h!==u.a&&O(i,"stroke",u.a=h),u},{e:void 0,t:void 0,a:void 0}),s})()};function me(){return document.body.dataset.base??"/_debug"}var Pt="kickjs_devtools_token",cn=30,ce=null;function se(){if(ce)return ce;const e=new URLSearchParams(location.search).get("token");if(e){Ot(e);const r=new URL(location.href);return r.searchParams.delete("token"),history.replaceState({},"",r.toString()),e}const t=document.cookie.match(new RegExp(`${Pt}=([^;]+)`));return t?(ce=decodeURIComponent(t[1]),ce):null}function Ot(e){ce=e,document.cookie=`${Pt}=${encodeURIComponent(e)}; path=/; max-age=${3600*24*cn}; SameSite=Lax`}function Bt(e){const t=se();return t?`${e}${e.includes("?")?"&":"?"}token=${encodeURIComponent(t)}`:e}var It=class extends Error{constructor(){super("AUTH_REQUIRED"),this.name="AuthRequiredError"}};async function V(e){const t=Bt(`${me()}${e}`),r=await fetch(t,{headers:un()});if(r.status===401||r.status===403)throw new It;if(!r.ok)throw new Error(`GET ${e} failed: ${r.status} ${r.statusText}`);return await r.json()}function un(){const e=se();return e?{"x-devtools-token":e}:{}}var H={runtime:()=>V("/runtime"),topology:()=>V("/topology"),metrics:()=>V("/metrics"),routes:()=>V("/metrics"),routeRegistry:()=>V("/routes"),container:()=>V("/container"),health:()=>V("/health"),queues:()=>V("/queues"),ws:()=>V("/ws"),tabs:()=>V("/tabs")};function Ke(e,t,r){const n=Bt(`${me()}${e}`),s=new EventSource(n);return s.onmessage=i=>{try{t(JSON.parse(i.data))}catch(u){console.warn("SSE parse failed",u)}},r&&(s.onerror=r),()=>s.close()}var dn=v("<div class=status><span><span></span></span><span> samples"),hn=v("<div class=empty>Loading runtime metrics…"),fn=v("<div class=empty style=padding:0;text-align:left;font-size:11px>GC: <!> runs, <!> total"),ht=v("<div class=grid>"),gn=v("<div class=card><div class=card-header><div class=card-title></div><div class=card-value>"),Pe=60,vn=()=>{const[e,t]=_(null),[r,n]=_([]),[s,i]=_([]),[u,o]=_([]),[a,h]=_(!1),f=d=>{t(d),n(g=>[...g,d.memory.heapUsed].slice(-Pe)),i(g=>[...g,d.memory.rss].slice(-Pe)),o(g=>[...g,d.eventLoop.p99].slice(-Pe))};return ve(()=>{H.runtime().then(d=>{for(const g of d.history)f(g);h(!0)}).catch(()=>h(!1)),le(Ke("/runtime/stream",d=>{h(!0),f(d)},()=>h(!1)))}),[c(b,{get when(){return e()},get fallback(){return hn()},children:d=>[(()=>{var g=ht();return l(g,c(J,{title:"Heap used",metric:"heap.used",get value(){return D(d().memory.heapUsed)},get children(){return c(Se,{get values(){return r()}})}}),null),l(g,c(J,{title:"RSS",metric:"rss",get value(){return D(d().memory.rss)},get children(){return c(Se,{get values(){return s()}})}}),null),l(g,c(J,{title:"Event loop p99",metric:"event-loop.p99",get value(){return Z(d().eventLoop.p99)},get children(){return c(Se,{get values(){return u()}})}}),null),l(g,c(J,{title:"Uptime",metric:"uptime",get value(){return Ve(d().uptimeSec)},get children(){var p=fn(),m=p.firstChild.nextSibling,$=m.nextSibling.nextSibling;return $.nextSibling,l(p,()=>d().gc.count,m),l(p,()=>Z(d().gc.totalPauseMs),$),p}}),null),g})(),(()=>{var g=ht();return l(g,c(J,{title:"External",metric:"external",get value(){return D(d().memory.external)}}),null),l(g,c(J,{title:"Array buffers",metric:"array-buffers",get value(){return D(d().memory.arrayBuffers)}}),null),l(g,c(J,{title:"Heap total",metric:"heap.total",get value(){return D(d().memory.heapTotal)}}),null),l(g,c(J,{title:"CPU (last sample)",get value(){return`${(d().cpu.userMicros/1e3).toFixed(1)} ms u / ${(d().cpu.systemMicros/1e3).toFixed(1)} ms s`}}),null),g})()]}),(()=>{var d=dn(),g=d.firstChild,p=g.firstChild,m=g.nextSibling,$=m.firstChild;return l(g,()=>a()?"streaming":"reconnecting…",null),l(m,()=>r().length,$),S(()=>q(p,`status-dot ${a()?"connected":"disconnected"}`)),d})()]},J=e=>(()=>{var t=gn(),r=t.firstChild.firstChild,n=r.nextSibling;return l(r,()=>e.title,null),l(r,c(b,{get when(){return e.metric},children:s=>c(U,{get metric(){return s()}})}),null),l(n,()=>e.value),l(t,()=>e.children,null),t})(),pn=v("<div class=status><span><span></span></span><span> samples"),mn=v("<div class=empty>Loading memory metrics…"),ft=v("<p>"),bn=v("<p><strong>Severity buckets</strong> (heap-growth in MB/min):"),xn=v('<ul class="list-disc pl-5 space-y-1"><li><span class="badge badge-ok">ok</span> < 5 MB/min — typical operation.</li><li><span class="badge badge-warn">warn</span> < 20 MB/min — investigate if sustained > 5 minutes.</li><li><span class="badge badge-critical">critical</span> ≥ 20 MB/min — capture a heap snapshot now.'),$n=v("<div class=card><div class=card-header><div class=card-title>Leak risk</div><span></span></div><div style=display:flex;justify-content:space-between;align-items:baseline><div class=card-value> growth</div><div class=card-value style=font-size:13px;color:var(--text-dim)>GC reclaim<!> <!> • heap util<!> "),yn=v("<div class=grid>"),_n=v("<table><thead><tr><th>Type</th><th style=text-align:right>Count</th></tr></thead><tbody>"),wn=v("<div class=card><div class=card-header><div class=card-title>Active handles</div><div class=card-value>"),Sn=v("<div class=empty>No handle inventory available on this runtime."),kn=v("<tr><td></td><td style=text-align:right>"),Cn=v("<div class=card><div class=card-header><div class=card-title></div><div class=card-value>"),Tn=v('<div class=card><div class=card-header><div class=card-title>Heap snapshot</div><div class=card-value style=font-size:13px;color:var(--text-dim)>~<!> estimate</div></div><p style="margin:0 0 12px;color:var(--text-dim);font-size:12px">Captures a V8 heap snapshot for retained-size analysis in Chrome DevTools (Memory tab, Load profile). Capture blocks the event loop for several seconds — avoid in production.</p><div style=display:flex;align-items:center;gap:12px><button type=button class=tab style="border:1px solid var(--accent);border-radius:4px;padding:6px 14px;border-bottom-color:var(--accent);color:var(--accent)">'),Mn=v("<span style=color:var(--text-dim);font-size:12px;font-family:var(--font-mono)>Last: <!> (<!>)"),Nt=v('<p style="margin:8px 0 0;color:var(--critical);font-size:12px;font-family:var(--font-mono)">'),En=v('<div class=card><div class=card-header><div class=card-title>Force GC</div></div><p style="margin:0 0 12px;color:var(--text-dim);font-size:12px">Triggers a synchronous V8 GC pass to confirm whether heap growth is real retention or just uncollected garbage. Requires <code>node --expose-gc</code>.</p><div style=display:flex;align-items:center;gap:12px;flex-wrap:wrap><button type=button class=tab style="border:1px solid var(--accent);border-radius:4px;padding:6px 14px;border-bottom-color:var(--accent);color:var(--accent)">'),An=v("<span style=color:var(--text-dim);font-size:12px;font-family:var(--font-mono)>Reclaimed <!> (<!> → <!>) in <!>ms"),gt=60,Ln=()=>{const[e,t]=_(null),[r,n]=_([]),[s,i]=_(!1),u=a=>{t(a),n(h=>[...h,a.snapshot.memory.heapUsed].slice(-gt))};ve(()=>{H.runtime().then(a=>{a.latest&&(u({snapshot:a.latest,health:a.health}),n(a.history.map(h=>h.memory.heapUsed).slice(-gt))),i(!0)}).catch(()=>i(!1)),le(Ke("/memory/stream",a=>{i(!0),u(a)},()=>i(!1)))});const o=P(()=>{const a=e();return a?Object.entries(a.health.handlesByType).sort((h,f)=>f[1]-h[1]):[]});return[c(b,{get when(){return e()},get fallback(){return mn()},children:a=>[(()=>{var h=$n(),f=h.firstChild,d=f.firstChild;d.firstChild;var g=d.nextSibling,p=f.nextSibling.firstChild,m=p.firstChild,$=p.nextSibling,y=$.firstChild.nextSibling,w=y.nextSibling.nextSibling,M=w.nextSibling.nextSibling;return M.nextSibling,l(d,c(Nr,{title:"What is leak risk?",get children(){return[(()=>{var k=ft();return l(k,()=>Ne["leak.risk"].short),k})(),(()=>{var k=ft();return l(k,()=>Ne["leak.risk"].detail),k})(),bn(),xn()]}}),null),l(g,()=>a().health.heapGrowthSeverity),l(p,()=>Pr(a().health.heapGrowthBytesPerSec),m),l($,c(U,{metric:"gc.reclaim"}),y),l($,()=>Ee(a().health.gcReclaimRatio),w),l($,c(U,{metric:"heap.utilization"}),M),l($,()=>Ee(a().health.heapUtilization),null),l(h,c(Se,{get values(){return r()}}),null),S(()=>q(g,`badge badge-${a().health.heapGrowthSeverity}`)),h})(),(()=>{var h=yn();return l(h,c($e,{title:"Heap used",metric:"heap.used",get value(){return D(a().snapshot.memory.heapUsed)}}),null),l(h,c($e,{title:"Heap total",metric:"heap.total",get value(){return D(a().snapshot.memory.heapTotal)}}),null),l(h,c($e,{title:"RSS",metric:"rss",get value(){return D(a().snapshot.memory.rss)}}),null),l(h,c($e,{title:"External",metric:"external",get value(){return D(a().snapshot.memory.external)}}),null),h})(),(()=>{var h=wn(),f=h.firstChild.firstChild.nextSibling;return l(f,()=>a().health.activeHandles),l(h,c(b,{get when(){return o().length>0},get fallback(){return Sn()},get children(){var d=_n(),g=d.firstChild.nextSibling;return l(g,c(A,{get each(){return o()},children:([p,m])=>(()=>{var $=kn(),y=$.firstChild,w=y.nextSibling;return l(y,p),l(w,m),$})()})),d}}),null),h})(),c(Rn,{get heapTotal(){return a().snapshot.memory.heapTotal}}),c(Pn,{})]}),(()=>{var a=pn(),h=a.firstChild,f=h.firstChild,d=h.nextSibling,g=d.firstChild;return l(h,()=>s()?"streaming":"reconnecting…",null),l(d,()=>r().length,g),S(()=>q(f,`status-dot ${s()?"connected":"disconnected"}`)),a})()]},$e=e=>(()=>{var t=Cn(),r=t.firstChild.firstChild,n=r.nextSibling;return l(r,()=>e.title,null),l(r,c(b,{get when(){return e.metric},children:s=>c(U,{get metric(){return s()}})}),null),l(n,()=>e.value),t})(),Rn=e=>{const[t,r]=_(!1),[n,s]=_(null),[i,u]=_(null),o=async()=>{r(!0),s(null);try{const a=se(),h=`${me()}/memory/snapshot${a?`?token=${encodeURIComponent(a)}`:""}`,f=await fetch(h,{method:"POST",headers:a?{"x-devtools-token":a}:void 0});if(!f.ok){let p=`${f.status} ${f.statusText}`;try{const m=await f.json();m.error&&(p=m.error)}catch{}throw new Error(p)}const d=await f.blob(),g=qn(f.headers.get("content-disposition"))??`kickjs-heap-${Date.now()}.heapsnapshot`;jn(d,g),u({name:g,sizeBytes:d.size})}catch(a){s(a instanceof Error?a.message:String(a))}finally{r(!1)}};return(()=>{var a=Tn(),h=a.firstChild,f=h.firstChild.nextSibling,d=f.firstChild.nextSibling;d.nextSibling;var g=h.nextSibling.nextSibling,p=g.firstChild;return l(f,()=>D(e.heapTotal),d),p.$$click=()=>{o()},l(p,()=>t()?"Capturing…":"Take snapshot"),l(g,c(b,{get when(){return i()},children:m=>(()=>{var $=Mn(),y=$.firstChild.nextSibling,w=y.nextSibling.nextSibling;return w.nextSibling,l($,()=>m().name,y),l($,()=>D(m().sizeBytes),w),$})()}),null),l(a,c(b,{get when(){return n()},children:m=>(()=>{var $=Nt();return l($,m),$})()}),null),S(()=>p.disabled=t()),a})()};function qn(e){if(!e)return null;const t=/filename="?([^";]+)"?/.exec(e);return t?t[1]:null}function jn(e,t){const r=URL.createObjectURL(e),n=document.createElement("a");n.href=r,n.download=t,document.body.appendChild(n),n.click(),document.body.removeChild(n),URL.revokeObjectURL(r)}var Pn=()=>{const[e,t]=_(!1),[r,n]=_(null),[s,i]=_(null),u=async()=>{t(!0),i(null);try{const o=se(),a=`${me()}/memory/gc${o?`?token=${encodeURIComponent(o)}`:""}`,h=await fetch(a,{method:"POST",headers:o?{"x-devtools-token":o}:void 0});if(!h.ok){let f=`${h.status} ${h.statusText}`;try{const d=await h.json();d.error&&(f=d.error)}catch{}throw new Error(f)}n(await h.json())}catch(o){i(o instanceof Error?o.message:String(o))}finally{t(!1)}};return(()=>{var o=En(),a=o.firstChild.nextSibling.nextSibling,h=a.firstChild;return h.$$click=()=>{u()},l(h,()=>e()?"Collecting…":"Run GC"),l(a,c(b,{get when(){return r()},children:f=>(()=>{var d=An(),g=d.firstChild.nextSibling,p=g.nextSibling.nextSibling,m=p.nextSibling.nextSibling,$=m.nextSibling.nextSibling;return $.nextSibling,l(d,()=>D(f().reclaimedBytes),g),l(d,()=>D(f().before),p),l(d,()=>D(f().after),m),l(d,()=>f().elapsedMs,$),d})()}),null),l(o,c(b,{get when(){return s()},children:f=>(()=>{var d=Nt();return l(d,f),d})()}),null),S(()=>h.disabled=e()),o})()};z(["click"]);var On=v('<div class="flex items-center justify-between mt-4 pt-3 border-t border-slate-800 text-xs text-slate-500"><div class="flex items-center gap-3"><span>Showing <!>–<!> of </span><label class="flex items-center gap-1"><span class=text-slate-600>Per page</span><select class="bg-slate-800 border border-slate-700 rounded px-1.5 py-0.5 text-slate-200"></select></label></div><div class="flex items-center gap-1"><button type=button class="px-2.5 py-1 rounded border border-slate-700 bg-slate-800 hover:bg-slate-700 disabled:opacity-30">Prev</button><button type=button class="px-2.5 py-1 rounded border border-slate-700 bg-slate-800 hover:bg-slate-700 disabled:opacity-30">Next'),Bn=v("<option>"),In=v('<span class="px-1 text-slate-600">…'),Nn=v("<button type=button>"),Dn=[5,10,15,20,25,50,100];function ie(e,t={}){const r=t.pageSizeChoices??Dn,[n,s]=_(t.pageSize??r[0]??5),[i,u]=_(1),o=P(()=>Math.max(1,Math.ceil(e().length/n()))),a=P(()=>Math.min(i(),o()));return{source:e,page:P(()=>{const h=(a()-1)*n();return e().slice(h,h+n())}),current:a,total:o,pageSize:n,pageSizeChoices:r,range:P(()=>{const h=e().length;return h===0?{start:0,end:0,total:0}:{start:(a()-1)*n()+1,end:Math.min(a()*n(),h),total:h}}),goto(h){u(Math.max(1,Math.min(h,o())))},next(){u(h=>Math.min(h+1,o()))},prev(){u(h=>Math.max(h-1,1))},setPageSize(h){s(h);const f=(a()-1)*n();u(Math.max(1,Math.floor(f/h)+1))}}}var ae=e=>{const t=P(()=>{const r=e.pager.total(),n=e.pager.current();if(r<=7)return Array.from({length:r},(o,a)=>a+1);const s=[1],i=Math.max(2,n-1),u=Math.min(r-1,n+1);i>2&&s.push("gap");for(let o=i;o<=u;o++)s.push(o);return u<r-1&&s.push("gap"),s.push(r),s});return c(b,{get when(){return e.pager.total()>1||e.pager.source().length>e.pager.pageSize()},get children(){var r=On(),n=r.firstChild,s=n.firstChild,i=s.firstChild.nextSibling,u=i.nextSibling.nextSibling;u.nextSibling;var o=s.nextSibling.firstChild.nextSibling,a=n.nextSibling,h=a.firstChild,f=h.nextSibling;return l(s,()=>e.pager.range().start,i),l(s,()=>e.pager.range().end,u),l(s,()=>e.pager.range().total,null),o.addEventListener("change",d=>e.pager.setPageSize(Number(d.currentTarget.value))),l(o,c(A,{get each(){return e.pager.pageSizeChoices},children:d=>(()=>{var g=Bn();return g.value=d,l(g,d),g})()})),h.$$click=()=>e.pager.prev(),l(a,c(A,{get each(){return t()},children:d=>c(b,{when:d==="gap",get fallback(){return(()=>{var g=Nn();return g.$$click=()=>e.pager.goto(d),l(g,d),S(()=>q(g,`px-2.5 py-1 rounded border ${d===e.pager.current()?"border-kick-500/30 bg-kick-500/20 text-kick-500":"border-slate-700 bg-slate-800 hover:bg-slate-700"}`)),g})()},get children(){return In()}})}),f),f.$$click=()=>e.pager.next(),S(d=>{var g=e.pager.current()===1,p=e.pager.current()===e.pager.total();return g!==d.e&&(h.disabled=d.e=g),p!==d.t&&(f.disabled=d.t=p),d},{e:void 0,t:void 0}),S(()=>o.value=e.pager.pageSize()),r}})};z(["click"]);var Un=v('<div style=display:flex;justify-content:space-between;align-items:center;margin-bottom:12px><h2 style=margin:0;font-size:16px>Topology</h2><button type=button class=tab style="border:1px solid var(--border);border-radius:4px;padding:4px 12px;border-bottom-color:var(--border)">'),zn=v("<div class=card style=border-color:var(--critical)><div class=card-title style=color:var(--critical)>Topology error</div><code>"),Hn=v("<div class=empty>Loading topology…"),Fn=v('<div class=card style=border-color:var(--warn)><div class=card-title style=color:var(--warn)> introspect failure(s)</div><ul style="margin:8px 0 0;padding-left:20px;font-family:var(--font-mono);font-size:12px">'),Gn=v("<li>/<!>: "),Vn=v("<table><thead><tr><th>Key</th><th>Source</th><th>Depends on</th></tr></thead><tbody>"),Kn=v("<div class=card><div class=card-header><div class=card-title>Contributors (<!>)"),Qn=v("<div class=empty>No contributors registered"),Wn=v("<tr><td><span class=tree-key></span></td><td></td><td>"),Jn=v("<table><thead><tr><th>Token</th><th>Scope</th><th>Kind</th><th>Resolved</th></tr></thead><tbody>"),Yn=v("<div class=card><div class=card-header><div class=card-title>DI tokens (<!>)"),Xn=v("<div class=empty>No DI tokens registered"),Zn=v("<tr><td><span class=tree-key></span></td><td></td><td></td><td>"),el=v("<div class=card><div class=card-header><div class=card-title>"),tl=v("<div class=empty>"),rl=v("<span class=tree-meta>v"),nl=v("<div class=tree-meta>provides: "),ll=v("<div class=tree-node><span class=tree-key>"),sl=v("<div class=tree-meta>"),il=v("<span style=margin-right:12px>: <strong style=color:var(--text)>"),al=()=>{const[e,t]=_(null),[r,n]=_(null),[s,i]=_(!1),u=async()=>{i(!0),n(null);try{t(await H.topology())}catch(o){n(o instanceof Error?o.message:String(o))}finally{i(!1)}};return ve(()=>{u()}),[(()=>{var o=Un(),a=o.firstChild.nextSibling;return a.$$click=()=>{u()},l(a,()=>s()?"Refreshing…":"Refresh"),S(()=>a.disabled=s()),o})(),c(b,{get when(){return r()},children:o=>(()=>{var a=zn(),h=a.firstChild.nextSibling;return l(h,o),a})()}),c(b,{get when(){return e()},get fallback(){return Hn()},children:o=>[c(b,{get when(){return o().errors.length>0},get children(){var a=Fn(),h=a.firstChild,f=h.firstChild,d=h.nextSibling;return l(h,()=>o().errors.length,f),l(d,c(A,{get each(){return o().errors},children:g=>(()=>{var p=Gn(),m=p.firstChild,$=m.nextSibling;return $.nextSibling,l(p,()=>g.kind,m),l(p,()=>g.name,$),l(p,()=>g.message,null),p})()})),a}}),c(vt,{get title(){return`Plugins (${o().plugins.length})`},get items(){return o().plugins},empty:"No plugins registered"}),c(vt,{get title(){return`Adapters (${o().adapters.length})`},get items(){return o().adapters},empty:"No adapters registered"}),c(ol,{get rows(){return o().contributors}}),c(cl,{get rows(){return o().diTokens}})]})]},ol=e=>{const t=P(()=>e.rows??[]),r=ie(t);return(()=>{var n=Kn(),s=n.firstChild.firstChild,i=s.firstChild.nextSibling;return i.nextSibling,l(s,()=>t().length,i),l(n,c(b,{get when(){return t().length>0},get fallback(){return Qn()},get children(){return[(()=>{var u=Vn(),o=u.firstChild.nextSibling;return l(o,c(A,{get each(){return r.page()},children:a=>(()=>{var h=Wn(),f=h.firstChild,d=f.firstChild,g=f.nextSibling,p=g.nextSibling;return l(d,()=>a.key),l(g,()=>a.source),l(p,()=>a.dependsOn.join(", ")||"—"),h})()})),u})(),c(ae,{pager:r})]}}),null),n})()},cl=e=>{const t=P(()=>e.rows??[]),r=ie(t);return(()=>{var n=Yn(),s=n.firstChild.firstChild,i=s.firstChild.nextSibling;return i.nextSibling,l(s,()=>t().length,i),l(n,c(b,{get when(){return t().length>0},get fallback(){return Xn()},get children(){return[(()=>{var u=Jn(),o=u.firstChild.nextSibling;return l(o,c(A,{get each(){return r.page()},children:a=>(()=>{var h=Zn(),f=h.firstChild,d=f.firstChild,g=f.nextSibling,p=g.nextSibling,m=p.nextSibling;return l(d,()=>a.token),l(g,()=>a.scope),l(p,()=>a.kind),l(m,()=>a.instantiated?"yes":"no"),h})()})),u})(),c(ae,{pager:r})]}}),null),n})()},vt=e=>(()=>{var t=el(),r=t.firstChild.firstChild;return l(r,()=>e.title),l(t,c(b,{get when(){return e.items.length>0},get fallback(){return(()=>{var n=tl();return l(n,()=>e.empty),n})()},get children(){return c(A,{get each(){return e.items},children:n=>c(ul,{item:n})})}}),null),t})(),ul=e=>(()=>{var t=ll(),r=t.firstChild;return l(r,()=>e.item.name),l(t,c(b,{get when(){return e.item.version},get children(){var n=rl();return n.firstChild,l(n,()=>e.item.version,null),n}}),null),l(t,c(b,{get when(){return e.item.tokens?.provides.length},get children(){var n=nl();return n.firstChild,l(n,()=>e.item.tokens?.provides.join(", "),null),n}}),null),l(t,c(b,{get when(){return e.item.metrics},children:n=>(()=>{var s=sl();return l(s,c(A,{get each(){return Object.entries(n())},children:([i,u])=>(()=>{var o=il(),a=o.firstChild,h=a.nextSibling;return l(o,i,a),l(h,u),o})()})),s})()}),null),t})();z(["click"]);var dl=v("<div class=overflow-x-auto><table><thead><tr><th>Method</th><th>Path</th><th>Controller</th><th>Handler</th><th>Middleware</th></tr></thead><tbody>"),hl=v('<div class="bg-surface-1 rounded-xl border border-border p-5"><div class="flex flex-col sm:flex-row gap-3 mb-4"><div class="relative flex-1"><svg class="absolute left-3 top-2.5 w-4 h-4 text-text-muted"fill=none stroke=currentColor viewBox="0 0 24 24"aria-hidden=true><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path></svg><input type=text placeholder="Search routes (path, controller, handler)…"class="w-full bg-surface-2 border border-border-strong rounded-lg pl-10 pr-4 py-2 text-sm text-text-body placeholder:text-text-muted focus:outline-none focus:border-kick-500"></div><div class="flex gap-1">'),fl=v("<button type=button>"),gl=v("<div class=empty>"),vl=v('<tr><td><span></span></td><td class="font-mono text-sm"></td><td></td><td class=text-text-secondary></td><td class="text-text-muted text-xs">'),pl=["ALL","GET","POST","PUT","DELETE","PATCH"],ml=()=>{const[e,t]=_(""),[r,n]=_("ALL"),s=P(()=>{let u=C.routes();r()!=="ALL"&&(u=u.filter(a=>a.method.toUpperCase()===r()));const o=e().trim().toLowerCase();return o&&(u=u.filter(a=>a.path.toLowerCase().includes(o)||a.controller.toLowerCase().includes(o)||a.handler.toLowerCase().includes(o))),u}),i=ie(()=>s());return(()=>{var u=hl(),o=u.firstChild.firstChild,a=o.firstChild.nextSibling,h=o.nextSibling;return a.$$input=f=>t(f.currentTarget.value),l(h,c(A,{each:pl,children:f=>(()=>{var d=fl();return d.$$click=()=>n(f),l(d,f),S(()=>q(d,`px-3 py-1.5 text-xs font-semibold rounded-lg transition-colors border ${r()===f?"bg-kick-500/20 text-kick-500 border-kick-500/30":"bg-surface-2 text-text-secondary border-border-strong hover:text-text-body"}`)),d})()})),l(u,c(b,{get when(){return i.page().length>0},get fallback(){return(()=>{var f=gl();return l(f,()=>e()||r()!=="ALL"?"No routes match the current filter":"No routes registered"),f})()},get children(){return[(()=>{var f=dl(),d=f.firstChild.firstChild.nextSibling;return l(d,c(A,{get each(){return i.page()},children:g=>(()=>{var p=vl(),m=p.firstChild,$=m.firstChild,y=m.nextSibling,w=y.nextSibling,M=w.nextSibling,k=M.nextSibling;return l($,()=>g.method),l(y,()=>g.path),l(w,()=>g.controller),l(M,()=>g.handler),l(k,(()=>{var T=Fe(()=>!!g.middleware.length);return()=>T()?g.middleware.join(", "):"—"})()),S(()=>q($,`text-xs font-bold ${bl(g.method)}`)),p})()})),f})(),c(ae,{pager:i})]}}),null),S(()=>a.value=e()),u})()};function bl(e){const t=e.toUpperCase();return t==="GET"?"text-emerald-400":t==="POST"?"text-cyan-400":t==="PUT"||t==="PATCH"?"text-amber-400":t==="DELETE"?"text-red-400":"text-text-secondary"}z(["input","click"]);var xl=v("<div class=card style=border-color:var(--critical)><div class=card-title style=color:var(--critical)>Failed to load metrics</div><code>"),$l=v("<div class=empty>Loading route metrics…"),yl=v("<div class=grid>"),_l=v("<table><thead><tr><th>Route</th><th style=text-align:right>Calls</th><th style=text-align:right>Avg</th><th style=text-align:right>p50</th><th style=text-align:right>p95</th><th style=text-align:right>p99</th><th style=text-align:right>Max</th></tr></thead><tbody>"),wl=v("<div class=card><div class=card-header><div class=card-title>Per-route latency"),Sl=v("<div class=empty>No requests recorded yet"),kl=v("<tr><td></td><td style=text-align:right></td><td style=text-align:right></td><td style=text-align:right></td><td style=text-align:right></td><td style=text-align:right></td><td style=text-align:right>"),Cl=v("<div class=card><div class=card-header><div class=card-title></div><div class=card-value>"),Tl=()=>{const[e,t]=_(null),[r,n]=_(null),s=async()=>{try{t(await H.routes()),n(null)}catch(u){n(u instanceof Error?u.message:String(u))}};ve(()=>{s();const u=setInterval(()=>{s()},2e3);return()=>clearInterval(u)});const i=P(()=>{const u=e();return u?Object.entries(u.routeLatency).map(([o,a])=>({key:o,...a,avg:a.count>0?a.totalMs/a.count:0})).sort((o,a)=>a.count-o.count):[]});return[c(b,{get when(){return r()},children:u=>(()=>{var o=xl(),a=o.firstChild.nextSibling;return l(a,u),o})()}),c(b,{get when(){return e()},get fallback(){return $l()},children:u=>[(()=>{var o=yl();return l(o,c(oe,{title:"Requests",metric:"requests",get value(){return u().requests.toString()}}),null),l(o,c(oe,{title:"Server errors",metric:"server-errors",get value(){return u().serverErrors.toString()}}),null),l(o,c(oe,{title:"Client errors",metric:"client-errors",get value(){return u().clientErrors.toString()}}),null),l(o,c(oe,{title:"Error rate",metric:"error-rate",get value(){return Ee(u().errorRate)}}),null),l(o,c(oe,{title:"Uptime",metric:"uptime",get value(){return Ve(u().uptimeSeconds)}}),null),o})(),(()=>{var o=wl();return o.firstChild,l(o,c(b,{get when(){return i().length>0},get fallback(){return Sl()},get children(){var a=_l(),h=a.firstChild,f=h.firstChild.firstChild.nextSibling.nextSibling;f.firstChild;var d=f.nextSibling;d.firstChild;var g=d.nextSibling;g.firstChild;var p=g.nextSibling;p.firstChild;var m=p.nextSibling;m.firstChild;var $=h.nextSibling;return l(f,c(U,{metric:"latency.avg",placement:"bottom"}),null),l(d,c(U,{metric:"latency.p50",placement:"bottom"}),null),l(g,c(U,{metric:"latency.p95",placement:"bottom"}),null),l(p,c(U,{metric:"latency.p99",placement:"bottom"}),null),l(m,c(U,{metric:"latency.max",placement:"bottom"}),null),l($,c(A,{get each(){return i()},children:y=>(()=>{var w=kl(),M=w.firstChild,k=M.nextSibling,T=k.nextSibling,I=T.nextSibling,K=I.nextSibling,be=K.nextSibling,xe=be.nextSibling;return l(M,()=>y.key),l(k,()=>y.count),l(T,()=>Z(y.avg)),l(I,()=>Z(y.p50)),l(K,()=>Z(y.p95)),l(be,()=>Z(y.p99)),l(xe,()=>Z(y.maxMs)),w})()})),a}}),null),o})()]})]},oe=e=>(()=>{var t=Cl(),r=t.firstChild.firstChild,n=r.nextSibling;return l(r,()=>e.title,null),l(r,c(b,{get when(){return e.metric},children:s=>c(U,{get metric(){return s()}})}),null),l(n,()=>e.value),t})(),Ml=v('<button type=button class="text-text-muted hover:text-text-strong p-1"aria-label=Back><svg class="w-4 h-4"fill=none stroke=currentColor viewBox="0 0 24 24"><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M15 19l-7-7 7-7">'),pt=v('<div class="flex flex-wrap gap-1">'),El=v('<div class="bg-surface-2/50 rounded-lg border border-border-strong p-3 space-y-2 text-sm">'),Al=v("<span>"),Ll=v('<div class="fixed inset-0 z-50 bg-black/70 flex items-center justify-center p-4"><div class="bg-surface-1 border border-border-strong rounded-2xl p-6 max-w-2xl w-full shadow-2xl max-h-[90vh] overflow-y-auto"><div class="flex items-start justify-between mb-4"><div><div class="flex items-center gap-2 mb-1"><h2 class="text-base font-semibold font-mono text-text-body break-all"></h2></div><div class="flex flex-wrap gap-2 mt-2"><span></span><span class="bg-border-strong/50 text-text-strong px-2 py-0.5 rounded text-xs font-semibold"></span><span></span></div></div><button type=button class="text-slate-500 hover:text-slate-300 p-1"aria-label=Close><svg class="w-5 h-5"fill=none stroke=currentColor viewBox="0 0 24 24"><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M6 18L18 6M6 6l12 12">'),mt=v('<span class="text-text-muted text-sm">None'),Rl=v('<button type=button class="bg-surface-2 text-kick-500 hover:bg-border-strong px-2.5 py-1 rounded text-xs font-mono border border-border-strong transition-colors">'),ql=v('<button type=button class="bg-surface-2 text-amber-400 hover:bg-border-strong px-2.5 py-1 rounded text-xs font-mono border border-border-strong transition-colors">'),jl=v('<div class=mb-4><h3 class="text-xs font-semibold uppercase tracking-wider text-text-muted mb-2">'),Pl=v('<div class="flex justify-between"><span class=text-text-secondary></span><span class=tabular-nums>'),[De,fe]=_(null),[Ol,qe]=_([]);function Ae(e){qe([]),fe(e)}function bt(e){const t=De();t&&t!==e&&qe(r=>[...r,t]),fe(e)}function Bl(){qe(e=>{if(e.length===0)return fe(null),e;const t=e.slice(0,-1);return fe(e[e.length-1]),t})}function xt(){fe(null),qe([])}var Il=()=>{const e=P(()=>{const r=De();if(!r)return null;const n=C.container().find(s=>s.token===r);return n||{token:r,kind:void 0,scope:void 0,dependencies:[]}}),t=P(()=>{const r=De();return r?C.container().filter(n=>n.dependencies?.includes(r)).map(n=>n.token):[]});return c(b,{get when(){return e()},children:r=>(()=>{var n=Ll(),s=n.firstChild,i=s.firstChild.firstChild,u=i.firstChild,o=u.firstChild,a=u.nextSibling.firstChild,h=a.nextSibling,f=h.nextSibling,d=i.nextSibling;return n.$$click=g=>{g.target===g.currentTarget&&xt()},l(u,c(b,{get when(){return Ol().length>0},get children(){var g=Ml();return g.$$click=Bl,g}}),o),l(o,()=>r().token),l(a,()=>r().kind??"unknown"),l(h,()=>r().scope??"singleton"),l(f,()=>Ul(r())),d.$$click=xt,l(s,c(ye,{title:"Dependencies",get children(){return c(b,{get when(){return(r().dependencies?.length??0)>0},get fallback(){return mt()},get children(){var g=pt();return l(g,c(A,{get each(){return r().dependencies},children:p=>(()=>{var m=Rl();return m.$$click=()=>bt(p),l(m,p),m})()})),g}})}}),null),l(s,c(ye,{title:"Dependents",get children(){return c(b,{get when(){return t().length>0},get fallback(){return mt()},get children(){var g=pt();return l(g,c(A,{get each(){return t()},children:p=>(()=>{var m=ql();return m.$$click=()=>bt(p),l(m,p),m})()})),g}})}}),null),l(s,c(ye,{title:"Resolve stats",get children(){var g=El();return l(g,c(_e,{label:"Resolve count",get value(){return String(r().resolveCount??0)}}),null),l(g,c(b,{get when(){return r().firstResolved},children:p=>c(_e,{label:"First resolved",get value(){return new Date(p()).toLocaleString()}})}),null),l(g,c(b,{get when(){return r().lastResolved},children:p=>c(_e,{label:"Last resolved",get value(){return new Date(p()).toLocaleString()}})}),null),l(g,c(b,{get when(){return r().resolveDurationMs!=null},get children(){return c(_e,{label:"Resolution duration",get value(){return`${(r().resolveDurationMs??0).toFixed(2)} ms`}})}}),null),g}}),null),l(s,c(ye,{title:"PostConstruct",get children(){var g=Al();return l(g,()=>r().postConstructStatus??"none"),S(()=>q(g,`px-2 py-0.5 rounded text-xs font-semibold ${zl(r().postConstructStatus)}`)),g}}),null),S(g=>{var p=`px-2 py-0.5 rounded text-xs font-semibold ${Nl(r().kind)}`,m=`px-2 py-0.5 rounded text-xs font-semibold ${Dl(r())}`;return p!==g.e&&q(a,g.e=p),m!==g.t&&q(f,g.t=m),g},{e:void 0,t:void 0}),n})()})},ye=e=>(()=>{var t=jl(),r=t.firstChild;return l(r,()=>e.title),l(t,()=>e.children,null),t})(),_e=e=>(()=>{var t=Pl(),r=t.firstChild,n=r.nextSibling;return l(r,()=>e.label),l(n,()=>e.value),t})();function Nl(e){return e==="controller"?"bg-violet-900/50 text-violet-300":e==="service"?"bg-blue-900/50 text-blue-300":e==="repository"?"bg-teal-900/50 text-teal-300":"bg-border-strong/50 text-text-strong"}function Dl(e){return e.postConstructStatus==="failed"?"bg-red-900/50 text-red-300":e.instantiated?"bg-emerald-900/50 text-emerald-300":"bg-amber-900/50 text-amber-300"}function Ul(e){return e.postConstructStatus==="failed"?"failed":e.instantiated?"active":"registered"}function zl(e){return e==="done"?"bg-emerald-900/50 text-emerald-300":e==="failed"?"bg-red-900/50 text-red-300":"bg-border-strong/50 text-text-secondary"}z(["click"]);var Hl=v("<div class=overflow-x-auto><table><thead><tr><th class=w-6 aria-label=expand></th><th>Token</th><th>Kind</th><th>Scope</th><th>Status</th><th class=text-right>Resolves</th><th class=text-right>Deps</th></tr></thead><tbody>"),Fl=v('<div class="bg-surface-1 rounded-xl border border-border p-5"><div class="flex flex-col gap-3 mb-4"><div class=relative><svg class="absolute left-3 top-2.5 w-4 h-4 text-text-muted"fill=none stroke=currentColor viewBox="0 0 24 24"aria-hidden=true><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path></svg><input type=text placeholder="Search tokens…"class="w-full bg-surface-2 border border-border-strong rounded-lg pl-10 pr-4 py-2 text-sm text-text-body placeholder:text-text-muted focus:outline-none focus:border-kick-500"></div><div class="flex flex-col sm:flex-row gap-3"><div class="flex gap-1 items-center"><span class="text-xs text-text-muted mr-1">Kind:</span></div><div class="flex gap-1 items-center"><span class="text-xs text-text-muted mr-1">Scope:'),$t=v("<button type=button>"),Gl=v("<div class=empty>"),Vl=v('<tr class="cursor-pointer select-none"><td><svg fill=none stroke=currentColor viewBox="0 0 24 24"aria-hidden=true><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M9 5l7 7-7 7"></path></svg></td><td class="font-mono text-sm"></td><td><span></span></td><td><span class="bg-border-strong/50 text-text-strong px-2 py-0.5 rounded text-xs font-semibold"></span></td><td><span></span></td><td class="text-right tabular-nums"></td><td class="text-right text-text-muted text-xs">'),Kl=v('<tr><td colspan=7 class="bg-surface-2/30 px-6 py-4 border-b border-border">'),Ql=v('<div class="flex flex-wrap gap-1">'),Wl=v('<div class="flex justify-between"><span class=text-text-secondary>Duration</span><span class=tabular-nums>ms'),Jl=v('<div class="grid grid-cols-1 md:grid-cols-2 gap-4"><div><h4 class="text-xs font-semibold uppercase tracking-wider text-text-muted mb-2">Dependencies</h4></div><div><h4 class="text-xs font-semibold uppercase tracking-wider text-text-muted mb-2">Resolve Stats</h4><div class="space-y-1 text-sm"><div class="flex justify-between"><span class=text-text-secondary>Resolve count</span><span class=tabular-nums></span></div></div></div><div><h4 class="text-xs font-semibold uppercase tracking-wider text-text-muted mb-2">PostConstruct</h4><span></span></div><div class="md:col-span-2 flex justify-end"><button type=button class="px-3 py-1.5 text-xs font-semibold rounded-lg bg-kick-500/20 text-kick-500 border border-kick-500/30 hover:bg-kick-500/30 transition-colors">View full details'),Yl=v('<span class="text-text-muted text-sm">None'),Xl=v('<button type=button class="bg-border-strong/50 text-kick-500 hover:bg-border-strong px-2 py-0.5 rounded text-xs font-mono transition-colors">'),Zl=v('<div class="flex justify-between"><span class=text-text-secondary>First resolved</span><span class=text-xs>'),es=v('<div class="flex justify-between"><span class=text-text-secondary>Last resolved</span><span class=text-xs>'),ts=["ALL","controller","service","repository","other"],rs=["ALL","singleton","transient","request"],ns=()=>{const[e,t]=_(""),[r,n]=_("ALL"),[s,i]=_("ALL"),[u,o]=_(new Set),a=P(()=>{let d=C.container();if(r()!=="ALL"){const p=r();d=d.filter(m=>p==="other"?!["controller","service","repository"].includes(m.kind??""):m.kind===p)}s()!=="ALL"&&(d=d.filter(p=>p.scope===s()));const g=e().trim().toLowerCase();return g&&(d=d.filter(p=>p.token.toLowerCase().includes(g))),d}),h=ie(()=>a()),f=d=>{o(g=>{const p=new Set(g);return p.has(d)?p.delete(d):p.add(d),p})};return(()=>{var d=Fl(),g=d.firstChild.firstChild,p=g.firstChild.nextSibling,m=g.nextSibling.firstChild;m.firstChild;var $=m.nextSibling;return $.firstChild,p.$$input=y=>t(y.currentTarget.value),l(m,c(A,{each:ts,children:y=>(()=>{var w=$t();return w.$$click=()=>n(y),l(w,y),S(()=>q(w,`px-3 py-1.5 text-xs font-semibold rounded-lg transition-colors border ${r()===y?is(y):"bg-surface-2 text-text-secondary border-border-strong hover:text-text-body"}`)),w})()}),null),l($,c(A,{each:rs,children:y=>(()=>{var w=$t();return w.$$click=()=>i(y),l(w,y),S(()=>q(w,`px-3 py-1.5 text-xs font-semibold rounded-lg transition-colors border ${s()===y?"bg-kick-500/20 text-kick-500 border-kick-500/30":"bg-surface-2 text-text-secondary border-border-strong hover:text-text-body"}`)),w})()}),null),l(d,c(b,{get when(){return h.page().length>0},get fallback(){return(()=>{var y=Gl();return l(y,()=>e()||r()!=="ALL"||s()!=="ALL"?"No tokens match the current filter":"No DI registrations"),y})()},get children(){return[(()=>{var y=Hl(),w=y.firstChild.firstChild,M=w.firstChild.firstChild.nextSibling.nextSibling.nextSibling.nextSibling.nextSibling;M.firstChild;var k=w.nextSibling;return l(M,c(U,{metric:"resolve.count",placement:"bottom"}),null),l(k,c(A,{get each(){return h.page()},children:T=>[(()=>{var I=Vl(),K=I.firstChild,be=K.firstChild,xe=K.nextSibling,Qe=xe.nextSibling,We=Qe.firstChild,Je=Qe.nextSibling,Gt=Je.firstChild,Ye=Je.nextSibling,Xe=Ye.firstChild,Ze=Ye.nextSibling,Vt=Ze.nextSibling;return I.$$click=()=>f(T.token),l(xe,()=>T.token),l(We,()=>T.kind??"unknown"),l(Gt,()=>T.scope??"—"),l(Xe,()=>os(T)),l(Ze,()=>T.resolveCount??0),l(Vt,()=>T.dependencies?.length??0),S(X=>{var et=`w-3 h-3 text-text-muted transition-transform ${u().has(T.token)?"rotate-90":""}`,tt=`px-2 py-0.5 rounded text-xs font-semibold ${ss(T.kind)}`,rt=`px-2 py-0.5 rounded text-xs font-semibold ${as(T)}`;return et!==X.e&&O(be,"class",X.e=et),tt!==X.t&&q(We,X.t=tt),rt!==X.a&&q(Xe,X.a=rt),X},{e:void 0,t:void 0,a:void 0}),I})(),c(b,{get when(){return u().has(T.token)},get children(){var I=Kl(),K=I.firstChild;return l(K,c(ls,{registration:T})),I}})]})),y})(),c(ae,{pager:h})]}}),null),S(()=>p.value=e()),d})()},ls=e=>(()=>{var t=Jl(),r=t.firstChild;r.firstChild;var n=r.nextSibling,s=n.firstChild.nextSibling,i=s.firstChild.firstChild.nextSibling,u=n.nextSibling,o=u.firstChild;o.firstChild;var a=o.nextSibling,h=u.nextSibling.firstChild;return l(r,c(b,{get when(){return(e.registration.dependencies?.length??0)>0},get fallback(){return Yl()},get children(){var f=Ql();return l(f,c(A,{get each(){return e.registration.dependencies},children:d=>(()=>{var g=Xl();return g.$$click=p=>{p.stopPropagation(),Ae(d)},O(g,"title",`Open detail for ${d}`),l(g,d),g})()})),f}}),null),l(i,()=>e.registration.resolveCount??0),l(s,c(b,{get when(){return e.registration.firstResolved},children:f=>(()=>{var d=Zl(),g=d.firstChild.nextSibling;return l(g,()=>new Date(f()).toLocaleTimeString()),d})()}),null),l(s,c(b,{get when(){return e.registration.lastResolved},children:f=>(()=>{var d=es(),g=d.firstChild.nextSibling;return l(g,()=>new Date(f()).toLocaleTimeString()),d})()}),null),l(s,c(b,{get when(){return e.registration.resolveDurationMs!=null},get children(){var f=Wl(),d=f.firstChild.nextSibling,g=d.firstChild;return l(d,()=>(e.registration.resolveDurationMs??0).toFixed(2),g),f}}),null),l(o,c(U,{metric:"post-construct"}),null),l(a,()=>e.registration.postConstructStatus??"none"),h.$$click=f=>{f.stopPropagation(),Ae(e.registration.token)},S(()=>q(a,`px-2 py-0.5 rounded text-xs font-semibold ${cs(e.registration.postConstructStatus)}`)),t})();function ss(e){return e==="controller"?"bg-violet-900/50 text-violet-300":e==="service"?"bg-blue-900/50 text-blue-300":e==="repository"?"bg-teal-900/50 text-teal-300":"bg-border-strong/50 text-text-strong"}function is(e){return e==="controller"?"bg-violet-900/50 text-violet-300 border-violet-700/50":e==="service"?"bg-blue-900/50 text-blue-300 border-blue-700/50":e==="repository"?"bg-teal-900/50 text-teal-300 border-teal-700/50":e==="other"?"bg-border-strong/50 text-text-strong border-border-strong/50":"bg-kick-500/20 text-kick-500 border-kick-500/30"}function as(e){return e.postConstructStatus==="failed"?"bg-red-900/50 text-red-300":e.instantiated?"bg-emerald-900/50 text-emerald-300":"bg-amber-900/50 text-amber-300"}function os(e){return e.postConstructStatus==="failed"?"failed":e.instantiated?"active":"registered"}function cs(e){return e==="done"?"bg-emerald-900/50 text-emerald-300":e==="failed"?"bg-red-900/50 text-red-300":"bg-border-strong/50 text-text-secondary"}z(["input","click"]);var us=v('<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">'),ds=v('<div class="bg-surface-1 rounded-xl border border-border p-5"><div class="relative mb-4"><svg class="absolute left-3 top-2.5 w-4 h-4 text-text-muted"fill=none stroke=currentColor viewBox="0 0 24 24"aria-hidden=true><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path></svg><input type=text placeholder="Search queues by name…"class="w-full bg-surface-2 border border-border-strong rounded-lg pl-10 pr-4 py-2 text-sm text-text-body placeholder:text-text-muted focus:outline-none focus:border-kick-500">'),hs=v('<div class=card><div class=card-title>Queues</div><p class="text-text-muted text-sm mt-2">QueueAdapter not detected. Install <code class="font-mono text-kick-500">@forinda/kickjs-queue</code> and register the adapter in your bootstrap to see queue stats here.'),fs=v("<div class=empty>No queues registered"),gs=v("<div class=empty>No queues match the search"),vs=v('<div class="grid grid-cols-2 gap-2 text-sm">'),ps=v('<div class="bg-surface-2/50 rounded-lg border border-border-strong p-4"><h3 class="font-mono text-sm font-semibold text-kick-500 mb-3 break-all">'),ms=v('<div class="text-red-400 text-sm">'),bs=v('<div class="flex justify-between"><span class=text-text-secondary></span><span>'),xs=()=>{const[e,t]=_(""),r=P(()=>{const s=C.queues().queues,i=e().trim().toLowerCase();return i?s.filter(u=>u.name.toLowerCase().includes(i)):s}),n=ie(()=>r());return c(b,{get when(){return C.queues().enabled},get fallback(){return hs()},get children(){return c(b,{get when(){return C.queues().queues.length>0},get fallback(){return fs()},get children(){var s=ds(),i=s.firstChild.firstChild.nextSibling;return i.$$input=u=>t(u.currentTarget.value),l(s,c(b,{get when(){return n.page().length>0},get fallback(){return gs()},get children(){return[(()=>{var u=us();return l(u,c(A,{get each(){return n.page()},children:o=>c($s,{queue:o})})),u})(),c(ae,{pager:n})]}}),null),S(()=>i.value=e()),s}})}})},$s=e=>(()=>{var t=ps(),r=t.firstChild;return l(r,()=>e.queue.name),l(t,c(b,{get when(){return!e.queue.error},get fallback(){return(()=>{var n=ms();return l(n,()=>e.queue.error),n})()},get children(){var n=vs();return l(n,c(te,{label:"Waiting",get value(){return e.queue.waiting??0},colour:"text-amber-400"}),null),l(n,c(te,{label:"Active",get value(){return e.queue.active??0},colour:"text-blue-400"}),null),l(n,c(te,{label:"Completed",get value(){return e.queue.completed??0},colour:"text-emerald-400"}),null),l(n,c(te,{label:"Failed",get value(){return e.queue.failed??0},colour:"text-red-400"}),null),l(n,c(te,{label:"Delayed",get value(){return e.queue.delayed??0},colour:"text-violet-400"}),null),l(n,c(te,{label:"Paused",get value(){return e.queue.paused??0},colour:"text-text-secondary"}),null),n}}),null),t})(),te=e=>(()=>{var t=bs(),r=t.firstChild,n=r.nextSibling;return l(r,()=>e.label),l(n,()=>e.value),S(()=>q(n,`font-semibold tabular-nums ${e.colour}`)),t})();z(["input"]);var ys=v("<div class=space-y-6>"),_s=v('<div class="bg-surface-1 rounded-xl border border-border p-5"><div class="relative mb-4"><svg class="absolute left-3 top-2.5 w-4 h-4 text-text-muted"fill=none stroke=currentColor viewBox="0 0 24 24"aria-hidden=true><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path></svg><input type=text placeholder="Filter graph (token or kind)…"class="w-full bg-surface-2 border border-border-strong rounded-lg pl-10 pr-4 py-2 text-sm text-text-body placeholder:text-text-muted focus:outline-none focus:border-kick-500">'),ws=v("<div class=empty>"),Ss=v("<div class=space-y-1>"),ks=v('<div><button type=button><svg fill=none stroke=currentColor viewBox="0 0 24 24"aria-hidden=true><path stroke-linecap=round stroke-linejoin=round stroke-width=2.5 d="M9 5l7 7-7 7"></path></svg><span></span><span class="ml-2 text-text-muted font-normal normal-case">(<!>)'),Cs=v('<span class="bg-border-strong/50 text-text-secondary px-1.5 py-0.5 rounded text-xs">'),Ts=v('<span class="text-text-muted text-xs ml-auto tabular-nums"> resolves'),Ms=v('<div class="ml-8 mt-1 space-y-0.5">'),Es=v('<button type=button class="w-full text-left px-3 py-2 rounded-lg hover:bg-surface-2/50 transition-colors group"><div class="flex items-center gap-2"><span></span><span class="font-mono text-sm text-text-body break-all">'),As=v('<div class="flex items-center gap-2 text-xs text-text-muted hover:text-text-strong"><svg class="w-3 h-3 text-text-muted"fill=none stroke=currentColor viewBox="0 0 24 24"aria-hidden=true><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M13 7l5 5-5 5M6 12h12"></path></svg><span></span><span class=font-mono>'),Ls=[{id:"controllers",label:"Controllers",match:e=>e==="controller"},{id:"services",label:"Services",match:e=>e==="service"},{id:"repositories",label:"Repositories",match:e=>e==="repository"},{id:"other",label:"Other",match:e=>!["controller","service","repository"].includes(e??"")}],Rs=()=>{const[e,t]=_(""),r=P(()=>{const s=C.container(),i=e().trim().toLowerCase();return i?s.filter(u=>u.token.toLowerCase().includes(i)||(u.kind??"").toLowerCase().includes(i)):s}),n=P(()=>Ls.map(s=>({...s,nodes:r().filter(i=>s.match(i.kind))})));return(()=>{var s=_s(),i=s.firstChild.firstChild.nextSibling;return i.$$input=u=>t(u.currentTarget.value),l(s,c(b,{get when(){return r().length>0},get fallback(){return(()=>{var u=ws();return l(u,()=>e()?"No nodes match the filter":"No DI registrations to graph"),u})()},get children(){var u=ys();return l(u,c(A,{get each(){return n()},children:o=>c(b,{get when(){return o.nodes.length>0},get children(){return c(qs,{get label(){return o.label},get nodes(){return o.nodes}})}})})),u}}),null),S(()=>i.value=e()),s})()},qs=e=>{const t=P(()=>e.nodes??[]),r=ie(t),n=`kickjs-devtools-graph-collapsed-${e.label}`,s=()=>{try{return localStorage.getItem(n)==="1"}catch{return!1}},[i,u]=_(s()),o=()=>{const a=!i();u(a);try{a?localStorage.setItem(n,"1"):localStorage.removeItem(n)}catch{}};return(()=>{var a=ks(),h=a.firstChild,f=h.firstChild,d=f.nextSibling,g=d.nextSibling,p=g.firstChild.nextSibling;return p.nextSibling,h.$$click=o,l(d,()=>e.label),l(g,()=>t().length,p),l(a,c(b,{get when(){return!i()},get children(){return[(()=>{var m=Ss();return l(m,c(A,{get each(){return r.page()},children:$=>c(js,{node:$})})),m})(),c(b,{get when(){return r.total()>1},get children(){return c(ae,{pager:r})}})]}}),null),S(m=>{var $=!i(),y=`w-full flex items-center text-left text-xs font-semibold uppercase tracking-wider mb-2 ${Ps(e.label)} cursor-pointer hover:opacity-80 transition-opacity`,w=`w-3 h-3 mr-1.5 transition-transform ${i()?"":"rotate-90"}`;return $!==m.e&&O(h,"aria-expanded",m.e=$),y!==m.t&&q(h,m.t=y),w!==m.a&&O(f,"class",m.a=w),m},{e:void 0,t:void 0,a:void 0}),a})()},js=e=>{const t=()=>e.node.dependencies??[];return(()=>{var r=Es(),n=r.firstChild,s=n.firstChild,i=s.nextSibling;return r.$$click=()=>Ae(e.node.token),l(s,()=>Dt(e.node.kind)),l(i,()=>e.node.token),l(n,c(b,{get when(){return e.node.scope},get children(){var u=Cs();return l(u,()=>e.node.scope),u}}),null),l(n,c(b,{get when(){return(e.node.resolveCount??0)>0},get children(){var u=Ts(),o=u.firstChild;return l(u,()=>e.node.resolveCount,o),u}}),null),l(r,c(b,{get when(){return t().length>0},get children(){var u=Ms();return l(u,c(A,{get each(){return t()},children:o=>(()=>{var a=As(),h=a.firstChild.nextSibling,f=h.nextSibling;return a.$$click=d=>{d.stopPropagation(),Ae(o)},l(h,()=>Os(o)),l(f,o),S(()=>q(h,`px-1.5 py-0.5 rounded text-xs font-semibold ${Bs(o)}`)),a})()})),u}}),null),S(()=>q(s,`px-2 py-0.5 rounded text-xs font-semibold ${Ut(e.node.kind)}`)),r})()};function Dt(e){return e==="controller"?"ctrl":e==="service"?"svc":e==="repository"?"repo":"other"}function Ut(e){return e==="controller"?"bg-violet-900/50 text-violet-300":e==="service"?"bg-blue-900/50 text-blue-300":e==="repository"?"bg-teal-900/50 text-teal-300":"bg-border-strong/50 text-text-strong"}function Ps(e){return e==="Controllers"?"text-violet-400":e==="Services"?"text-blue-400":e==="Repositories"?"text-teal-400":"text-text-secondary"}function Os(e){return Dt(C.container().find(t=>t.token===e)?.kind)}function Bs(e){return Ut(C.container().find(t=>t.token===e)?.kind)}z(["input","click"]);var Is=v("<div style=display:flex;flex-direction:column;height:100%>"),Ns=v('<iframe title="custom devtools tab"sandbox="allow-scripts allow-same-origin allow-forms"style=flex:1;width:100%;border:none;background:var(--bg)>'),Ds=v("<div style=padding:16px><div class=card>"),Us=v("<div style=color:var(--text-dim);font-size:12px>"),zs=v('<div style="display:flex;align-items:center;justify-content:space-between;padding:8px 0;border-bottom:1px solid var(--border)"><div><div style=font-weight:600></div></div><button type=button class=tab style="border:1px solid var(--border);border-radius:4px;padding:6px 14px;border-bottom-color:var(--border)">'),Hs=v("<div class=card><div class=card-title>Last response</div><code>"),Fs=v("<div style=padding:16px;flex:1;overflow:auto>"),Gs=e=>(()=>{var t=Is();return l(t,c(b,{get when(){return e.tab.view.type==="iframe"},get children(){return c(Vs,{get view(){return e.tab.view}})}}),null),l(t,c(b,{get when(){return e.tab.view.type==="launch"},get children(){return c(Ks,{get view(){return e.tab.view},get tabId(){return e.tab.id}})}}),null),l(t,c(b,{get when(){return e.tab.view.type==="html"},get children(){return c(Qs,{get view(){return e.tab.view}})}}),null),t})(),Vs=e=>{const t=()=>{const r=e.view.src,n=(r.startsWith("http")||r.startsWith("//"),r),s=se();return s?`${n}${n.includes("?")?"&":"?"}token=${encodeURIComponent(s)}`:n};return(()=>{var r=Ns();return S(()=>O(r,"src",t())),r})()},Ks=e=>{const[t,r]=_(null),[n,s]=_(null),i=async u=>{r(u),s(null);try{const o=`${me()}/tabs/${encodeURIComponent(e.tabId)}/actions/${encodeURIComponent(u)}`,a=se(),h=await fetch(a?`${o}?token=${encodeURIComponent(a)}`:o,{method:"POST",headers:a?{"x-devtools-token":a}:void 0});s(`${h.status} ${h.statusText}`)}catch(o){s(o instanceof Error?o.message:String(o))}finally{r(null)}};return(()=>{var u=Ds(),o=u.firstChild;return l(o,c(A,{get each(){return e.view.actions},children:a=>(()=>{var h=zs(),f=h.firstChild,d=f.firstChild,g=f.nextSibling;return l(d,()=>a.label),l(f,c(b,{get when(){return a.description},get children(){var p=Us();return l(p,()=>a.description),p}}),null),g.$$click=()=>{i(a.id)},l(g,()=>t()===a.id?"Running…":"Run"),S(()=>g.disabled=t()===a.id),h})()})),l(u,c(b,{get when(){return n()},children:a=>(()=>{var h=Hs(),f=h.firstChild.nextSibling;return l(f,a),h})()}),null),u})()},Qs=e=>(()=>{var t=Fs();return S(()=>t.innerHTML=e.view.html),t})();z(["click"]);var Le=!1,ue=null,ke=null;async function Ws(){return j.setConnectionStatus("connecting"),await Ue(),ke=Ke("/stream",e=>{if(!Le){if(j.setConnectionStatus("live"),zt(),e.type==="metrics"){Js(e),j.touch();return}if(e.type==="container"){Ue();return}}},()=>{Le||(j.setConnectionStatus("polling"),Ys())}),Xs}async function Ue(){const e=await Promise.allSettled([H.health(),H.metrics(),H.routeRegistry(),H.container(),H.queues(),H.ws()]);if(e.every(o=>o.status==="rejected"&&o.reason instanceof It)){j.setAuthRequired(!0),j.setConnectionStatus("disconnected");return}C.authRequired()&&(j.setAuthRequired(!1),j.setAuthError(null));const[t,r,n,s,i,u]=e;t.status==="fulfilled"&&j.setHealth({status:t.value.status,errorRate:t.value.errorRate,uptime:t.value.uptime,adapters:t.value.adapters??{}}),r.status==="fulfilled"&&j.setMetrics({requests:r.value.requests,serverErrors:r.value.serverErrors,clientErrors:r.value.clientErrors,errorRate:r.value.errorRate,uptimeSeconds:r.value.uptimeSeconds,startedAt:r.value.startedAt}),n.status==="fulfilled"&&j.setRoutes(n.value.routes??[]),s.status==="fulfilled"&&j.setContainer(s.value.registrations??[]),i.status==="fulfilled"&&j.setQueues({enabled:i.value.enabled,queues:i.value.queues??[]}),u.status==="fulfilled"&&j.setWs(u.value),j.touch()}function Js(e){const t=C.metrics();if(!t)return;j.setMetrics({...t,requests:e.requestCount,serverErrors:e.errorCount,clientErrors:e.clientErrorCount,errorRate:e.errorRate,uptimeSeconds:e.uptimeSeconds});const r=C.health();r&&j.setHealth({...r,uptime:e.uptimeSeconds,errorRate:e.errorRate})}function Ys(){ue||(ue=setInterval(()=>{Le||Ue()},5e3))}function zt(){ue&&(clearInterval(ue),ue=null)}function Xs(){Le=!0,zt(),ke&&(ke(),ke=null),j.setConnectionStatus("disconnected")}var Zs=v('<div class="fixed inset-0 z-[60] bg-slate-950/90 flex items-center justify-center p-4"><div class="bg-slate-900 border border-slate-700 rounded-2xl p-8 max-w-md w-full shadow-2xl"><div class="text-center mb-6"><h2 class="text-xl font-bold text-kick-500 mb-2">⚡ KickJS DevTools</h2><p class="text-sm text-slate-400">Enter your DevTools token to continue.</p><p class="text-xs text-slate-600 mt-1">The token is printed in the server console on startup, e.g. <code class="font-mono text-slate-500">[token: abc123…]</code></p></div><form><input type=text autofocus placeholder="Paste your token here…"class="w-full bg-slate-800 border border-slate-700 rounded-lg px-4 py-3 text-sm text-slate-200 placeholder-slate-500 focus:outline-none focus:border-kick-500 font-mono mb-3"><button type=submit class="w-full bg-kick-500 hover:bg-kick-600 text-white font-semibold py-2.5 rounded-lg transition-colors disabled:opacity-50">'),ei=v('<p class="text-red-400 text-sm mb-3">'),ti=()=>{const[e,t]=_(""),[r,n]=_(!1),s=async()=>{const i=e().trim();if(!i){j.setAuthError("Token is required");return}n(!0),j.setAuthError(null);try{Ot(i),await H.health(),j.setAuthRequired(!1),j.setAuthError(null),t("")}catch{j.setAuthError("Invalid token — request was rejected.")}finally{n(!1)}};return c(b,{get when(){return C.authRequired()},get children(){var i=Zs(),u=i.firstChild.firstChild.nextSibling,o=u.firstChild,a=o.nextSibling;return u.addEventListener("submit",h=>{h.preventDefault(),s()}),o.$$input=h=>t(h.currentTarget.value),l(u,c(b,{get when(){return C.authError()},children:h=>(()=>{var f=ei();return l(f,h),f})()}),a),l(a,()=>r()?"Verifying…":"Authenticate"),S(()=>a.disabled=r()),S(()=>o.value=e()),i}})};z(["input"]);var ri=v('<span aria-hidden=true style="width:1px;background:var(--border);margin:6px 8px">'),ni=v('<div class=card style=border-color:var(--warn);margin-top:16px><div class=card-title style=color:var(--warn)> custom-tab issue(s)</div><ul style="margin:8px 0 0;padding-left:20px;font-family:var(--font-mono);font-size:12px">'),li=v("<div class=app><header class=dt-header><div class=dt-header-brand><span class=dt-bolt aria-hidden=true>⚡</span><h1>KickJS DevTools</h1></div><div style=display:flex;align-items:center;gap:12px></div></header><nav class=tabs role=tablist></nav><main class=tab-body>"),yt=v("<button type=button role=tab>"),si=v("<span class=tab-badge>"),ii=v("<li>: "),ai=v("<div class=dt-conn><span aria-hidden=true></span><span class=dt-conn-label></span><span class=dt-conn-sep>·</span><span class=dt-conn-ts>Updated "),oi=v('<svg viewBox="0 0 24 24"fill=none stroke=currentColor stroke-width=2><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z">'),ci=v("<button type=button class=dt-theme-toggle>"),ui=v('<svg viewBox="0 0 24 24"fill=none stroke=currentColor stroke-width=2><circle cx=12 cy=12 r=4></circle><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41">');function Ht(){return[{id:"overview",label:"Overview"},{id:"runtime",label:"Runtime"},{id:"memory",label:"Memory"},{id:"topology",label:"Topology"},{id:"routes",label:"Routes",count:()=>C.routes().length||void 0},{id:"metrics",label:"Metrics"},{id:"container",label:"Container",count:()=>C.container().length||void 0},{id:"queues",label:"Queues",count:()=>C.queues().queues.length||void 0},{id:"graph",label:"Graph",count:()=>C.container().length||void 0}]}var di=new Set(Ht().map(e=>e.id)),hi=()=>{const[e,t]=_((()=>{try{const h=localStorage.getItem("kickjs-devtools-tab");if(h)return h}catch{}return"overview"})()),[r,n]=_([]),[s,i]=_([]),u=Ht();ve(()=>{H.tabs().then(({tabs:f,errors:d})=>{n(f.filter(g=>!di.has(g.id))),i(d)}).catch(()=>{});let h=null;Ws().then(f=>{h=f}),le(()=>h?.()),vr()});const o=h=>{t(h);try{localStorage.setItem("kickjs-devtools-tab",h)}catch{}queueMicrotask(()=>{document.querySelector(`[role="tab"][data-tab-id="${h}"]`)?.scrollIntoView({behavior:"smooth",inline:"center",block:"nearest"})})},a=()=>r().find(h=>h.id===e());return(()=>{var h=li(),f=h.firstChild,d=f.firstChild.nextSibling,g=f.nextSibling,p=g.nextSibling;return l(d,c(fi,{}),null),l(d,c(gi,{}),null),l(g,c(A,{each:u,children:m=>(()=>{var $=yt();return $.$$click=()=>o(m.id),l($,()=>m.label,null),l($,c(b,{get when(){return m.count?.()},children:y=>(()=>{var w=si();return l(w,y),w})()}),null),S(y=>{var w=m.id,M=`tab ${e()===m.id?"active":""}`,k=e()===m.id;return w!==y.e&&O($,"data-tab-id",y.e=w),M!==y.t&&q($,y.t=M),k!==y.a&&O($,"aria-selected",y.a=k),y},{e:void 0,t:void 0,a:void 0}),$})()}),null),l(g,c(b,{get when(){return r().length>0},get children(){return ri()}}),null),l(g,c(A,{get each(){return r()},children:m=>(()=>{var $=yt();return $.$$click=()=>o(m.id),l($,()=>m.title),S(y=>{var w=m.id,M=`tab ${e()===m.id?"active":""}`,k=e()===m.id,T=m.title;return w!==y.e&&O($,"data-tab-id",y.e=w),M!==y.t&&q($,y.t=M),k!==y.a&&O($,"aria-selected",y.a=k),T!==y.o&&O($,"title",y.o=T),y},{e:void 0,t:void 0,a:void 0,o:void 0}),$})()}),null),l(p,c(b,{get when(){return e()==="overview"},get children(){return c(rn,{})}}),null),l(p,c(b,{get when(){return e()==="runtime"},get children(){return c(vn,{})}}),null),l(p,c(b,{get when(){return e()==="memory"},get children(){return c(Ln,{})}}),null),l(p,c(b,{get when(){return e()==="topology"},get children(){return c(al,{})}}),null),l(p,c(b,{get when(){return e()==="routes"},get children(){return c(ml,{})}}),null),l(p,c(b,{get when(){return e()==="metrics"},get children(){return c(Tl,{})}}),null),l(p,c(b,{get when(){return e()==="container"},get children(){return c(ns,{})}}),null),l(p,c(b,{get when(){return e()==="queues"},get children(){return c(xs,{})}}),null),l(p,c(b,{get when(){return e()==="graph"},get children(){return c(Rs,{})}}),null),l(p,c(b,{get when(){return a()},children:m=>c(Gs,{get tab(){return m()}})}),null),l(p,c(b,{get when(){return Fe(()=>s().length>0)()&&e()==="overview"},get children(){var m=ni(),$=m.firstChild,y=$.firstChild,w=$.nextSibling;return l($,()=>s().length,y),l(w,c(A,{get each(){return s()},children:M=>(()=>{var k=ii(),T=k.firstChild;return l(k,()=>M.source,T),l(k,()=>M.reason,null),k})()})),m}}),null),l(h,c(Il,{}),null),l(h,c(ti,{}),null),h})()},fi=()=>{const e=r=>r==="live"?"Live":r==="polling"?"Polling":r==="disconnected"?"Disconnected":"Connecting…",t=r=>r?r.toLocaleTimeString():"never";return(()=>{var r=ai(),n=r.firstChild,s=n.nextSibling,i=s.nextSibling.nextSibling;return i.firstChild,l(s,()=>e(C.connectionStatus())),l(i,()=>t(C.lastUpdate()),null),S(()=>q(n,`dt-pulse dt-pulse-${C.connectionStatus()}`)),r})()},gi=()=>{const e=()=>{gr(je()==="system"?"light":je()==="light"?"dark":"system")},t=()=>{const r=je();return`Theme: ${r==="system"?"follow system":r} (click to cycle)`};return(()=>{var r=ci();return r.$$click=e,l(r,c(b,{get when(){return Rt()==="dark"},get fallback(){return ui()},get children(){return oi()}})),S(n=>{var s=t(),i=t();return s!==n.e&&O(r,"aria-label",n.e=s),i!==n.t&&O(r,"title",n.t=i),n},{e:void 0,t:void 0}),r})()};z(["click"]);var Ft=document.getElementById("root");if(!Ft)throw new Error("#root not found");ar(()=>c(hi,{}),Ft);
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
/*! tailwindcss v4.2.4 | MIT License | https://tailwindcss.com */
|
|
2
|
-
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after{--tw-space-y-reverse:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-leading:initial}::backdrop{--tw-space-y-reverse:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-leading:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-300:#ffa3a3;--color-red-400:#ff6568;--color-red-900:#82181a;--color-amber-300:#ffd236;--color-amber-400:#fcbb00;--color-amber-900:#7b3306;--color-emerald-300:#5ee9b5;--color-emerald-400:#00d294;--color-emerald-900:#004e3b;--color-teal-300:#46ecd5;--color-teal-400:#00d3bd;--color-teal-700:#00776e;--color-teal-900:#0b4f4a;--color-cyan-400:#00d2ef;--color-blue-300:#90c5ff;--color-blue-400:#54a2ff;--color-blue-700:#1447e6;--color-blue-900:#1c398e;--color-violet-300:#c4b4ff;--color-violet-400:#a685ff;--color-violet-700:#7008e7;--color-violet-900:#4d179a;--color-slate-200:#e2e8f0;--color-slate-300:#cad5e2;--color-slate-400:#90a1b9;--color-slate-500:#62748e;--color-slate-600:#45556c;--color-slate-700:#314158;--color-slate-800:#1d293d;--color-slate-900:#0f172b;--color-slate-950:#020618;--color-white:#fff;--spacing:.25rem;--container-md:28rem;--container-lg:32rem;--container-2xl:42rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-wide:.025em;--tracking-wider:.05em;--radius-lg:.5rem;--radius-xl:.75rem;--radius-2xl:1rem;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-kick-500:#38bdf8;--color-kick-600:#0284c7}@supports (color:lab(0% 0 0)){:root,:host{--color-red-300:lab(76.5514% 36.422 15.5335);--color-red-400:lab(63.7053% 60.745 31.3109);--color-red-900:lab(28.5139% 44.5539 29.0463);--color-amber-300:lab(86.4156% 6.13147 78.3961);--color-amber-400:lab(80.1641% 16.6016 99.2089);--color-amber-900:lab(31.2288% 30.2627 40.0378);--color-emerald-300:lab(83.9203% -48.7124 13.8849);--color-emerald-400:lab(75.0771% -60.7313 19.4147);--color-emerald-900:lab(28.8637% -26.9249 5.45986);--color-teal-300:lab(84.8977% -48.1516 -1.3321);--color-teal-400:lab(76.0109% -53.3483 -2.27906);--color-teal-700:lab(44.4134% -33.1436 -4.22149);--color-teal-900:lab(29.506% -21.4706 -3.59886);--color-cyan-400:lab(76.6045% -40.9406 -29.6231);--color-blue-300:lab(77.5052% -6.4629 -36.42);--color-blue-400:lab(65.0361% -1.42065 -56.9802);--color-blue-700:lab(36.9089% 35.0961 -85.6872);--color-blue-900:lab(26.1542% 15.7545 -51.5504);--color-violet-300:lab(76.7419% 18.3911 -37.0706);--color-violet-400:lab(62.8239% 34.9159 -60.0512);--color-violet-700:lab(35.2783% 67.9912 -88.793);--color-violet-900:lab(24.3783% 45.7525 -61.4902);--color-slate-200:lab(91.7353% -.998765 -4.76968);--color-slate-300:lab(84.7652% -1.94535 -7.93337);--color-slate-400:lab(65.5349% -2.25151 -14.5072);--color-slate-500:lab(48.0876% -2.03595 -16.5814);--color-slate-600:lab(35.5623% -1.74978 -15.4316);--color-slate-700:lab(26.9569% -1.47016 -15.6993);--color-slate-800:lab(16.132% -.318035 -14.6672);--color-slate-900:lab(7.78673% 1.82345 -15.0537);--color-slate-950:lab(1.76974% 1.32743 -9.28855)}}}@layer base{*,:after,:before{box-sizing:border-box;border:0 solid;margin:0;padding:0}::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components{.app{background-color:var(--color-slate-950);min-height:100vh;font-family:var(--font-sans);color:var(--color-slate-200);flex-direction:column;display:flex}.tabs{gap:calc(var(--spacing) * 1);border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--color-slate-800);background-color:var(--color-slate-900);padding-inline:calc(var(--spacing) * 4);padding-top:calc(var(--spacing) * 3);white-space:nowrap;scrollbar-width:thin;scrollbar-color:var(--color-slate-700) transparent;display:flex;overflow-x:auto}.tabs::-webkit-scrollbar{height:6px}.tabs::-webkit-scrollbar-track{background:0 0}.tabs::-webkit-scrollbar-thumb{background:var(--color-slate-700);border-radius:3px}.tab{cursor:pointer;border-top-left-radius:var(--radius-lg);border-top-right-radius:var(--radius-lg);border-style:var(--tw-border-style);padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 2);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--color-slate-400);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));background:0 0;border-width:1px;border-color:#0000;flex-shrink:0}.tab:hover{background-color:#1d293d99}@supports (color:color-mix(in lab, red, red)){.tab:hover{background-color:color-mix(in oklab, var(--color-slate-800) 60%, transparent)}}.tab:hover{color:var(--color-slate-200)}.tab.active{border-color:var(--color-slate-700);border-bottom-color:var(--color-slate-800);background-color:var(--color-slate-800);color:var(--color-kick-500)}.tab-body{padding:calc(var(--spacing) * 6);flex:1}.card{margin-bottom:calc(var(--spacing) * 4);border-radius:var(--radius-xl);border-style:var(--tw-border-style);border-width:1px;border-color:var(--color-slate-800);background-color:var(--color-slate-900);padding:calc(var(--spacing) * 5)}.card-header{margin-bottom:calc(var(--spacing) * 3);justify-content:space-between;align-items:center;display:flex}.card-title{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider);color:var(--color-slate-500);text-transform:uppercase}.card-value{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--color-slate-200);--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.grid{margin-bottom:calc(var(--spacing) * 4);gap:calc(var(--spacing) * 4);grid-template-columns:repeat(1,minmax(0,1fr));display:grid}@media (min-width:48rem){.grid{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width:64rem){.grid{grid-template-columns:repeat(3,minmax(0,1fr))}}table{width:100%;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}thead tr{border-bottom-style:var(--tw-border-style);border-bottom-width:2px;border-color:var(--color-slate-700)}th{padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);text-align:left;--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--color-slate-400)}tbody tr{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--color-slate-800)}tbody tr:hover{background-color:#1d293d66}@supports (color:color-mix(in lab, red, red)){tbody tr:hover{background-color:color-mix(in oklab, var(--color-slate-800) 40%, transparent)}}td{padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2)}.badge{padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * .5);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);border-radius:.25rem}.badge-ok{background-color:#004e3b80}@supports (color:color-mix(in lab, red, red)){.badge-ok{background-color:color-mix(in oklab, var(--color-emerald-900) 50%, transparent)}}.badge-ok{color:var(--color-emerald-300)}.badge-warn{background-color:#7b330680}@supports (color:color-mix(in lab, red, red)){.badge-warn{background-color:color-mix(in oklab, var(--color-amber-900) 50%, transparent)}}.badge-warn{color:var(--color-amber-300)}.badge-critical{background-color:#82181a80}@supports (color:color-mix(in lab, red, red)){.badge-critical{background-color:color-mix(in oklab, var(--color-red-900) 50%, transparent)}}.badge-critical{color:var(--color-red-300)}.empty{padding-block:calc(var(--spacing) * 8);text-align:center;color:var(--color-slate-500);font-style:italic}.tree-node{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--color-slate-800);padding-block:calc(var(--spacing) * 2)}.tree-node:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}.tree-key{font-family:var(--font-mono);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--color-slate-200)}.tree-meta{margin-top:calc(var(--spacing) * 1);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--color-slate-500)}.status{margin-top:calc(var(--spacing) * 4);padding-inline:calc(var(--spacing) * 2);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--color-slate-500);justify-content:space-between;align-items:center;display:flex}.status-dot{margin-right:calc(var(--spacing) * 1);height:calc(var(--spacing) * 2);width:calc(var(--spacing) * 2);border-radius:3.40282e38px;display:inline-block}.status-dot.connected{background-color:var(--color-emerald-400)}.status-dot.disconnected{background-color:var(--color-red-400)}.dt-header{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--color-slate-800);background-color:var(--color-slate-900);padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 3);justify-content:space-between;align-items:center;display:flex}.dt-header-brand{align-items:center;gap:calc(var(--spacing) * 2);display:flex}.dt-header-brand h1{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.dt-bolt{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));--tw-leading:1;color:var(--color-kick-500);line-height:1}.dt-conn{align-items:center;gap:calc(var(--spacing) * 1.5);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--color-slate-500);display:flex}.dt-conn-label{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--color-slate-300)}.dt-conn-sep{color:var(--color-slate-600)}.dt-pulse{height:calc(var(--spacing) * 2);width:calc(var(--spacing) * 2);border-radius:3.40282e38px;display:inline-block}.dt-pulse-live{animation:var(--animate-pulse);background-color:var(--color-emerald-400)}.dt-pulse-polling{animation:var(--animate-pulse);background-color:var(--color-amber-400)}.dt-pulse-connecting{background-color:var(--color-slate-500)}.dt-pulse-disconnected{background-color:var(--color-red-400)}.tab-badge{margin-left:calc(var(--spacing) * 1.5);background-color:var(--color-slate-700);padding-inline:calc(var(--spacing) * 1.5);padding-block:calc(var(--spacing) * .5);vertical-align:middle;--tw-font-weight:var(--font-weight-semibold);font-size:10px;font-weight:var(--font-weight-semibold);color:var(--color-slate-300);border-radius:3.40282e38px}.tab.active .tab-badge{background-color:var(--color-kick-500);color:var(--color-white)}}@layer utilities{.invisible{visibility:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.inset-0{inset:calc(var(--spacing) * 0)}.start{inset-inline-start:var(--spacing)}.end{inset-inline-end:var(--spacing)}.top-2\.5{top:calc(var(--spacing) * 2.5)}.left-3{left:calc(var(--spacing) * 3)}.z-50{z-index:50}.z-\[60\]{z-index:60}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mr-1{margin-right:calc(var(--spacing) * 1)}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.ml-2{margin-left:calc(var(--spacing) * 2)}.ml-8{margin-left:calc(var(--spacing) * 8)}.ml-auto{margin-left:auto}.block{display:block}.flex{display:flex}.grid{display:grid}.inline{display:inline}.table{display:table}.h-3{height:calc(var(--spacing) * 3)}.h-4{height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.max-h-\[90vh\]{max-height:90vh}.w-3{width:calc(var(--spacing) * 3)}.w-4{width:calc(var(--spacing) * 4)}.w-5{width:calc(var(--spacing) * 5)}.w-6{width:calc(var(--spacing) * 6)}.w-full{width:100%}.max-w-2xl{max-width:var(--container-2xl)}.max-w-lg{max-width:var(--container-lg)}.max-w-md{max-width:var(--container-md)}.flex-1{flex:1}.grow{flex-grow:1}.rotate-90{rotate:90deg}.cursor-pointer{cursor:pointer}.list-disc{list-style-type:disc}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-1{gap:calc(var(--spacing) * 1)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}:where(.space-y-0\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * .5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * .5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)))}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-lg{border-radius:var(--radius-lg)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-blue-700\/50{border-color:#1447e680}@supports (color:color-mix(in lab, red, red)){.border-blue-700\/50{border-color:color-mix(in oklab, var(--color-blue-700) 50%, transparent)}}.border-kick-500\/30{border-color:#38bdf84d}@supports (color:color-mix(in lab, red, red)){.border-kick-500\/30{border-color:color-mix(in oklab, var(--color-kick-500) 30%, transparent)}}.border-slate-600\/50{border-color:#45556c80}@supports (color:color-mix(in lab, red, red)){.border-slate-600\/50{border-color:color-mix(in oklab, var(--color-slate-600) 50%, transparent)}}.border-slate-700{border-color:var(--color-slate-700)}.border-slate-800{border-color:var(--color-slate-800)}.border-teal-700\/50{border-color:#00776e80}@supports (color:color-mix(in lab, red, red)){.border-teal-700\/50{border-color:color-mix(in oklab, var(--color-teal-700) 50%, transparent)}}.border-violet-700\/50{border-color:#7008e780}@supports (color:color-mix(in lab, red, red)){.border-violet-700\/50{border-color:color-mix(in oklab, var(--color-violet-700) 50%, transparent)}}.bg-amber-900\/50{background-color:#7b330680}@supports (color:color-mix(in lab, red, red)){.bg-amber-900\/50{background-color:color-mix(in oklab, var(--color-amber-900) 50%, transparent)}}.bg-blue-900\/50{background-color:#1c398e80}@supports (color:color-mix(in lab, red, red)){.bg-blue-900\/50{background-color:color-mix(in oklab, var(--color-blue-900) 50%, transparent)}}.bg-emerald-900\/50{background-color:#004e3b80}@supports (color:color-mix(in lab, red, red)){.bg-emerald-900\/50{background-color:color-mix(in oklab, var(--color-emerald-900) 50%, transparent)}}.bg-kick-500{background-color:var(--color-kick-500)}.bg-kick-500\/20{background-color:#38bdf833}@supports (color:color-mix(in lab, red, red)){.bg-kick-500\/20{background-color:color-mix(in oklab, var(--color-kick-500) 20%, transparent)}}.bg-red-900\/50{background-color:#82181a80}@supports (color:color-mix(in lab, red, red)){.bg-red-900\/50{background-color:color-mix(in oklab, var(--color-red-900) 50%, transparent)}}.bg-slate-700\/50{background-color:#31415880}@supports (color:color-mix(in lab, red, red)){.bg-slate-700\/50{background-color:color-mix(in oklab, var(--color-slate-700) 50%, transparent)}}.bg-slate-800{background-color:var(--color-slate-800)}.bg-slate-800\/30{background-color:#1d293d4d}@supports (color:color-mix(in lab, red, red)){.bg-slate-800\/30{background-color:color-mix(in oklab, var(--color-slate-800) 30%, transparent)}}.bg-slate-800\/50{background-color:#1d293d80}@supports (color:color-mix(in lab, red, red)){.bg-slate-800\/50{background-color:color-mix(in oklab, var(--color-slate-800) 50%, transparent)}}.bg-slate-900{background-color:var(--color-slate-900)}.bg-slate-950\/80{background-color:#020618cc}@supports (color:color-mix(in lab, red, red)){.bg-slate-950\/80{background-color:color-mix(in oklab, var(--color-slate-950) 80%, transparent)}}.bg-slate-950\/90{background-color:#020618e6}@supports (color:color-mix(in lab, red, red)){.bg-slate-950\/90{background-color:color-mix(in oklab, var(--color-slate-950) 90%, transparent)}}.bg-teal-900\/50{background-color:#0b4f4a80}@supports (color:color-mix(in lab, red, red)){.bg-teal-900\/50{background-color:color-mix(in oklab, var(--color-teal-900) 50%, transparent)}}.bg-violet-900\/50{background-color:#4d179a80}@supports (color:color-mix(in lab, red, red)){.bg-violet-900\/50{background-color:color-mix(in oklab, var(--color-violet-900) 50%, transparent)}}.p-1{padding:calc(var(--spacing) * 1)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-5{padding:calc(var(--spacing) * 5)}.p-6{padding:calc(var(--spacing) * 6)}.p-8{padding:calc(var(--spacing) * 8)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pt-3{padding-top:calc(var(--spacing) * 3)}.pr-4{padding-right:calc(var(--spacing) * 4)}.pl-5{padding-left:calc(var(--spacing) * 5)}.pl-10{padding-left:calc(var(--spacing) * 10)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.font-mono{font-family:var(--font-mono)}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.break-all{word-break:break-all}.text-amber-300{color:var(--color-amber-300)}.text-amber-400{color:var(--color-amber-400)}.text-blue-300{color:var(--color-blue-300)}.text-blue-400{color:var(--color-blue-400)}.text-cyan-400{color:var(--color-cyan-400)}.text-emerald-300{color:var(--color-emerald-300)}.text-emerald-400{color:var(--color-emerald-400)}.text-kick-500{color:var(--color-kick-500)}.text-red-300{color:var(--color-red-300)}.text-red-400{color:var(--color-red-400)}.text-slate-200{color:var(--color-slate-200)}.text-slate-300{color:var(--color-slate-300)}.text-slate-400{color:var(--color-slate-400)}.text-slate-500{color:var(--color-slate-500)}.text-slate-600{color:var(--color-slate-600)}.text-teal-300{color:var(--color-teal-300)}.text-teal-400{color:var(--color-teal-400)}.text-violet-300{color:var(--color-violet-300)}.text-violet-400{color:var(--color-violet-400)}.text-white{color:var(--color-white)}.normal-case{text-transform:none}.uppercase{text-transform:uppercase}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.placeholder-slate-500::placeholder{color:var(--color-slate-500)}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.select-none{-webkit-user-select:none;user-select:none}@media (hover:hover){.hover\:bg-kick-500\/30:hover{background-color:#38bdf84d}@supports (color:color-mix(in lab, red, red)){.hover\:bg-kick-500\/30:hover{background-color:color-mix(in oklab, var(--color-kick-500) 30%, transparent)}}.hover\:bg-kick-600:hover{background-color:var(--color-kick-600)}.hover\:bg-slate-700:hover{background-color:var(--color-slate-700)}.hover\:bg-slate-800\/50:hover{background-color:#1d293d80}@supports (color:color-mix(in lab, red, red)){.hover\:bg-slate-800\/50:hover{background-color:color-mix(in oklab, var(--color-slate-800) 50%, transparent)}}.hover\:text-slate-200:hover{color:var(--color-slate-200)}.hover\:text-slate-300:hover{color:var(--color-slate-300)}}.focus\:border-kick-500:focus{border-color:var(--color-kick-500)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.disabled\:opacity-30:disabled{opacity:.3}.disabled\:opacity-50:disabled{opacity:.5}@media (min-width:40rem){.sm\:flex-row{flex-direction:row}}@media (min-width:48rem){.md\:col-span-2{grid-column:span 2/span 2}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media (min-width:64rem){.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}}.dt-tip{vertical-align:middle;color:var(--color-slate-500);cursor:help;align-items:center;margin-left:4px;display:inline-flex;position:relative}.dt-tip-clickable{cursor:pointer;color:var(--color-slate-500);background:0 0;border:none;padding:0}.dt-tip-clickable:hover,.dt-tip:hover{color:var(--color-kick-500)}.dt-tip-icon{flex-shrink:0;width:14px;height:14px}.dt-tip-pop{z-index:100;visibility:hidden;opacity:0;width:max-content;max-width:240px;color:var(--color-slate-200);background:var(--color-slate-800);border:1px solid var(--color-slate-700);pointer-events:none;white-space:normal;border-radius:6px;padding:6px 10px;font-size:11px;font-weight:400;line-height:1.4;transition:opacity .12s,visibility .12s;position:absolute;box-shadow:0 4px 12px #0000004d}.dt-tip-pop-top{bottom:calc(100% + 6px);left:50%;transform:translate(-50%)}.dt-tip-pop-bottom{top:calc(100% + 6px);left:50%;transform:translate(-50%)}.dt-tip:hover .dt-tip-pop,.dt-tip:focus-within .dt-tip-pop{visibility:visible;opacity:1}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-leading{syntax:"*";inherits:false}@keyframes pulse{50%{opacity:.5}}
|
|
2
|
+
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after{--tw-space-y-reverse:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-leading:initial}::backdrop{--tw-space-y-reverse:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-leading:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-300:#ffa3a3;--color-red-400:#ff6568;--color-red-900:#82181a;--color-amber-300:#ffd236;--color-amber-400:#fcbb00;--color-amber-900:#7b3306;--color-emerald-300:#5ee9b5;--color-emerald-400:#00d294;--color-emerald-900:#004e3b;--color-teal-300:#46ecd5;--color-teal-400:#00d3bd;--color-teal-700:#00776e;--color-teal-900:#0b4f4a;--color-cyan-400:#00d2ef;--color-blue-300:#90c5ff;--color-blue-400:#54a2ff;--color-blue-700:#1447e6;--color-blue-900:#1c398e;--color-violet-300:#c4b4ff;--color-violet-400:#a685ff;--color-violet-700:#7008e7;--color-violet-900:#4d179a;--color-slate-200:#e2e8f0;--color-slate-300:#cad5e2;--color-slate-400:#90a1b9;--color-slate-500:#62748e;--color-slate-600:#45556c;--color-slate-700:#314158;--color-slate-800:#1d293d;--color-slate-900:#0f172b;--color-slate-950:#020618;--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-md:28rem;--container-lg:32rem;--container-2xl:42rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-wide:.025em;--tracking-wider:.05em;--leading-tight:1.25;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--radius-2xl:1rem;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-kick-500:#e0b020;--color-kick-600:#b08812;--color-app-bg:#0e1320;--color-app-text:#e2e8f0;--color-surface-1:#161c2e;--color-surface-2:#1a2236;--color-surface-hover:#232c44;--color-border:#1f2940;--color-border-strong:#334155;--color-text-strong:#f1f5f9;--color-text-body:#e2e8f0;--color-text-secondary:#cbd5e1;--color-text-muted:#94a3b8;--color-accent:var(--color-kick-500);--color-accent-on:#1a1308;--color-tooltip-bg:#0f172a;--color-tooltip-text:#e2e8f0;--color-tooltip-border:#334155;--bg:var(--color-app-bg);--text:var(--color-app-text);--text-dim:var(--color-text-secondary);--accent:var(--color-kick-500);--border:var(--color-border);--critical:#ef4444;--warn:#f59e0b}@supports (color:lab(0% 0 0)){:root,:host{--color-red-300:lab(76.5514% 36.422 15.5335);--color-red-400:lab(63.7053% 60.745 31.3109);--color-red-900:lab(28.5139% 44.5539 29.0463);--color-amber-300:lab(86.4156% 6.13147 78.3961);--color-amber-400:lab(80.1641% 16.6016 99.2089);--color-amber-900:lab(31.2288% 30.2627 40.0378);--color-emerald-300:lab(83.9203% -48.7124 13.8849);--color-emerald-400:lab(75.0771% -60.7313 19.4147);--color-emerald-900:lab(28.8637% -26.9249 5.45986);--color-teal-300:lab(84.8977% -48.1516 -1.3321);--color-teal-400:lab(76.0109% -53.3483 -2.27906);--color-teal-700:lab(44.4134% -33.1436 -4.22149);--color-teal-900:lab(29.506% -21.4706 -3.59886);--color-cyan-400:lab(76.6045% -40.9406 -29.6231);--color-blue-300:lab(77.5052% -6.4629 -36.42);--color-blue-400:lab(65.0361% -1.42065 -56.9802);--color-blue-700:lab(36.9089% 35.0961 -85.6872);--color-blue-900:lab(26.1542% 15.7545 -51.5504);--color-violet-300:lab(76.7419% 18.3911 -37.0706);--color-violet-400:lab(62.8239% 34.9159 -60.0512);--color-violet-700:lab(35.2783% 67.9912 -88.793);--color-violet-900:lab(24.3783% 45.7525 -61.4902);--color-slate-200:lab(91.7353% -.998765 -4.76968);--color-slate-300:lab(84.7652% -1.94535 -7.93337);--color-slate-400:lab(65.5349% -2.25151 -14.5072);--color-slate-500:lab(48.0876% -2.03595 -16.5814);--color-slate-600:lab(35.5623% -1.74978 -15.4316);--color-slate-700:lab(26.9569% -1.47016 -15.6993);--color-slate-800:lab(16.132% -.318035 -14.6672);--color-slate-900:lab(7.78673% 1.82345 -15.0537);--color-slate-950:lab(1.76974% 1.32743 -9.28855)}}}@layer base{*,:after,:before{box-sizing:border-box;border:0 solid;margin:0;padding:0}::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components{.app{background-color:var(--color-app-bg);min-height:100vh;font-family:var(--font-sans);color:var(--color-app-text);flex-direction:column;display:flex}.tabs{gap:calc(var(--spacing) * 1);border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--color-border);background-color:var(--color-surface-2);padding-inline:calc(var(--spacing) * 4);padding-top:calc(var(--spacing) * 3);white-space:nowrap;scrollbar-width:thin;scrollbar-color:var(--color-border-strong) transparent;display:flex;overflow-x:auto}.tabs::-webkit-scrollbar{height:6px}.tabs::-webkit-scrollbar-track{background:0 0}.tabs::-webkit-scrollbar-thumb{background:var(--color-border-strong);border-radius:3px}.tab{cursor:pointer;border-top-left-radius:var(--radius-lg);border-top-right-radius:var(--radius-lg);border-style:var(--tw-border-style);padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 2);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--color-text-secondary);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));background:0 0;border-width:1px;border-color:#0000;flex-shrink:0}.tab:hover{background-color:var(--color-surface-hover);color:var(--color-text-strong)}.tab.active{border-color:var(--color-border-strong);background-color:var(--color-surface-1);color:var(--color-accent);border-bottom-color:var(--color-surface-1)}.tab-body{padding:calc(var(--spacing) * 6);flex:1}.card{margin-bottom:calc(var(--spacing) * 4);border-radius:var(--radius-xl);border-style:var(--tw-border-style);border-width:1px;border-color:var(--color-border);background-color:var(--color-surface-1);padding:calc(var(--spacing) * 5);transition-property:box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));box-shadow:0 1px 2px #0000000a,0 1px 3px #0000000f}.card:hover{box-shadow:0 4px 6px -1px #00000014,0 2px 4px -2px #0000000f}[data-theme=dark] .card{box-shadow:0 1px 2px #0000004d,0 1px 3px #0003}[data-theme=dark] .card:hover{border-color:var(--color-border-strong);box-shadow:0 4px 6px -1px #00000080,0 2px 4px -2px #00000059}.card-header{margin-bottom:calc(var(--spacing) * 3);justify-content:space-between;align-items:center;display:flex}.card-title{--tw-font-weight:var(--font-weight-semibold);font-size:11px;font-weight:var(--font-weight-semibold);--tw-tracking:.06em;letter-spacing:.06em;color:var(--color-text-muted);text-transform:uppercase}.card-value{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height));--tw-leading:var(--leading-tight);line-height:var(--leading-tight);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--color-text-strong);--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.card-subvalue{margin-top:calc(var(--spacing) * 1);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--color-text-secondary)}.grid{margin-bottom:calc(var(--spacing) * 4);gap:calc(var(--spacing) * 5);grid-template-columns:repeat(1,minmax(0,1fr));display:grid}@media (min-width:48rem){.grid{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width:64rem){.grid{grid-template-columns:repeat(3,minmax(0,1fr))}}table{width:100%;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}thead tr{border-bottom-style:var(--tw-border-style);border-bottom-width:2px;border-color:var(--color-border-strong)}th{padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);text-align:left;--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--color-text-secondary)}tbody tr{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--color-border)}tbody tr:hover{background-color:#232c4466}@supports (color:color-mix(in lab, red, red)){tbody tr:hover{background-color:color-mix(in oklab, var(--color-surface-hover) 40%, transparent)}}td{padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2)}.badge{padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * .5);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);border-radius:.25rem}.badge-ok{background-color:#004e3b80}@supports (color:color-mix(in lab, red, red)){.badge-ok{background-color:color-mix(in oklab, var(--color-emerald-900) 50%, transparent)}}.badge-ok{color:var(--color-emerald-300)}.badge-warn{background-color:#7b330680}@supports (color:color-mix(in lab, red, red)){.badge-warn{background-color:color-mix(in oklab, var(--color-amber-900) 50%, transparent)}}.badge-warn{color:var(--color-amber-300)}.badge-critical{background-color:#82181a80}@supports (color:color-mix(in lab, red, red)){.badge-critical{background-color:color-mix(in oklab, var(--color-red-900) 50%, transparent)}}.badge-critical{color:var(--color-red-300)}.empty{padding-block:calc(var(--spacing) * 8);text-align:center;color:var(--color-text-secondary);font-style:italic}.tree-node{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--color-border);padding-block:calc(var(--spacing) * 2)}.tree-node:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}.tree-key{font-family:var(--font-mono);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--color-text-strong)}.tree-meta{margin-top:calc(var(--spacing) * 1);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--color-text-secondary)}.status{margin-top:calc(var(--spacing) * 4);padding-inline:calc(var(--spacing) * 2);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--color-text-secondary);justify-content:space-between;align-items:center;display:flex}.status-dot{margin-right:calc(var(--spacing) * 1);height:calc(var(--spacing) * 2);width:calc(var(--spacing) * 2);border-radius:3.40282e38px;display:inline-block}.status-dot.connected{background-color:var(--color-emerald-400)}.status-dot.disconnected{background-color:var(--color-red-400)}.dt-header{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--color-border);background-color:var(--color-surface-2);padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 3);justify-content:space-between;align-items:center;display:flex}.dt-header-brand{align-items:center;gap:calc(var(--spacing) * 2);display:flex}.dt-header-brand h1{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide);color:var(--color-text-strong)}.dt-bolt{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));--tw-leading:1;color:var(--color-accent);line-height:1}.dt-conn{align-items:center;gap:calc(var(--spacing) * 1.5);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--color-text-secondary);display:flex}.dt-conn-label{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--color-text-strong)}.dt-conn-sep{color:var(--color-text-muted)}.dt-pulse{height:calc(var(--spacing) * 2);width:calc(var(--spacing) * 2);border-radius:3.40282e38px;display:inline-block}.dt-pulse-live{animation:var(--animate-pulse);background-color:var(--color-emerald-400)}.dt-pulse-polling{animation:var(--animate-pulse);background-color:var(--color-amber-400)}.dt-pulse-connecting{background-color:var(--color-text-muted)}.dt-pulse-disconnected{background-color:var(--color-red-400)}.tab-badge{margin-left:calc(var(--spacing) * 1.5);background-color:var(--color-border-strong);padding-inline:calc(var(--spacing) * 1.5);padding-block:calc(var(--spacing) * .5);vertical-align:middle;--tw-font-weight:var(--font-weight-semibold);font-size:10px;font-weight:var(--font-weight-semibold);color:var(--color-text-secondary);border-radius:3.40282e38px}.tab.active .tab-badge{background-color:var(--color-accent);color:var(--color-accent-on)}}@layer utilities{.collapse{visibility:collapse}.invisible{visibility:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.inset-0{inset:calc(var(--spacing) * 0)}.start{inset-inline-start:var(--spacing)}.end{inset-inline-end:var(--spacing)}.top-2\.5{top:calc(var(--spacing) * 2.5)}.left-3{left:calc(var(--spacing) * 3)}.z-50{z-index:50}.z-\[60\]{z-index:60}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mr-1{margin-right:calc(var(--spacing) * 1)}.mr-1\.5{margin-right:calc(var(--spacing) * 1.5)}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.ml-2{margin-left:calc(var(--spacing) * 2)}.ml-8{margin-left:calc(var(--spacing) * 8)}.ml-auto{margin-left:auto}.block{display:block}.flex{display:flex}.grid{display:grid}.inline{display:inline}.table{display:table}.h-3{height:calc(var(--spacing) * 3)}.h-4{height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.max-h-\[90vh\]{max-height:90vh}.w-3{width:calc(var(--spacing) * 3)}.w-4{width:calc(var(--spacing) * 4)}.w-5{width:calc(var(--spacing) * 5)}.w-6{width:calc(var(--spacing) * 6)}.w-full{width:100%}.max-w-2xl{max-width:var(--container-2xl)}.max-w-lg{max-width:var(--container-lg)}.max-w-md{max-width:var(--container-md)}.flex-1{flex:1}.grow{flex-grow:1}.rotate-90{rotate:90deg}.cursor-pointer{cursor:pointer}.list-disc{list-style-type:disc}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-1{gap:calc(var(--spacing) * 1)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}:where(.space-y-0\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * .5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * .5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)))}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-lg{border-radius:var(--radius-lg)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-blue-700\/50{border-color:#1447e680}@supports (color:color-mix(in lab, red, red)){.border-blue-700\/50{border-color:color-mix(in oklab, var(--color-blue-700) 50%, transparent)}}.border-border{border-color:var(--color-border)}.border-border-strong{border-color:var(--color-border-strong)}.border-border-strong\/50{border-color:#33415580}@supports (color:color-mix(in lab, red, red)){.border-border-strong\/50{border-color:color-mix(in oklab, var(--color-border-strong) 50%, transparent)}}.border-kick-500\/30{border-color:#e0b0204d}@supports (color:color-mix(in lab, red, red)){.border-kick-500\/30{border-color:color-mix(in oklab, var(--color-kick-500) 30%, transparent)}}.border-slate-700{border-color:var(--color-slate-700)}.border-slate-800{border-color:var(--color-slate-800)}.border-teal-700\/50{border-color:#00776e80}@supports (color:color-mix(in lab, red, red)){.border-teal-700\/50{border-color:color-mix(in oklab, var(--color-teal-700) 50%, transparent)}}.border-violet-700\/50{border-color:#7008e780}@supports (color:color-mix(in lab, red, red)){.border-violet-700\/50{border-color:color-mix(in oklab, var(--color-violet-700) 50%, transparent)}}.bg-amber-900\/50{background-color:#7b330680}@supports (color:color-mix(in lab, red, red)){.bg-amber-900\/50{background-color:color-mix(in oklab, var(--color-amber-900) 50%, transparent)}}.bg-black\/70{background-color:#000000b3}@supports (color:color-mix(in lab, red, red)){.bg-black\/70{background-color:color-mix(in oklab, var(--color-black) 70%, transparent)}}.bg-blue-900\/50{background-color:#1c398e80}@supports (color:color-mix(in lab, red, red)){.bg-blue-900\/50{background-color:color-mix(in oklab, var(--color-blue-900) 50%, transparent)}}.bg-border-strong\/50{background-color:#33415580}@supports (color:color-mix(in lab, red, red)){.bg-border-strong\/50{background-color:color-mix(in oklab, var(--color-border-strong) 50%, transparent)}}.bg-emerald-900\/50{background-color:#004e3b80}@supports (color:color-mix(in lab, red, red)){.bg-emerald-900\/50{background-color:color-mix(in oklab, var(--color-emerald-900) 50%, transparent)}}.bg-kick-500{background-color:var(--color-kick-500)}.bg-kick-500\/20{background-color:#e0b02033}@supports (color:color-mix(in lab, red, red)){.bg-kick-500\/20{background-color:color-mix(in oklab, var(--color-kick-500) 20%, transparent)}}.bg-red-900\/50{background-color:#82181a80}@supports (color:color-mix(in lab, red, red)){.bg-red-900\/50{background-color:color-mix(in oklab, var(--color-red-900) 50%, transparent)}}.bg-slate-800{background-color:var(--color-slate-800)}.bg-slate-900{background-color:var(--color-slate-900)}.bg-slate-950\/80{background-color:#020618cc}@supports (color:color-mix(in lab, red, red)){.bg-slate-950\/80{background-color:color-mix(in oklab, var(--color-slate-950) 80%, transparent)}}.bg-slate-950\/90{background-color:#020618e6}@supports (color:color-mix(in lab, red, red)){.bg-slate-950\/90{background-color:color-mix(in oklab, var(--color-slate-950) 90%, transparent)}}.bg-surface-1{background-color:var(--color-surface-1)}.bg-surface-2{background-color:var(--color-surface-2)}.bg-surface-2\/30{background-color:#1a22364d}@supports (color:color-mix(in lab, red, red)){.bg-surface-2\/30{background-color:color-mix(in oklab, var(--color-surface-2) 30%, transparent)}}.bg-surface-2\/50{background-color:#1a223680}@supports (color:color-mix(in lab, red, red)){.bg-surface-2\/50{background-color:color-mix(in oklab, var(--color-surface-2) 50%, transparent)}}.bg-teal-900\/50{background-color:#0b4f4a80}@supports (color:color-mix(in lab, red, red)){.bg-teal-900\/50{background-color:color-mix(in oklab, var(--color-teal-900) 50%, transparent)}}.bg-violet-900\/50{background-color:#4d179a80}@supports (color:color-mix(in lab, red, red)){.bg-violet-900\/50{background-color:color-mix(in oklab, var(--color-violet-900) 50%, transparent)}}.p-1{padding:calc(var(--spacing) * 1)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-5{padding:calc(var(--spacing) * 5)}.p-6{padding:calc(var(--spacing) * 6)}.p-8{padding:calc(var(--spacing) * 8)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pt-3{padding-top:calc(var(--spacing) * 3)}.pr-4{padding-right:calc(var(--spacing) * 4)}.pl-5{padding-left:calc(var(--spacing) * 5)}.pl-10{padding-left:calc(var(--spacing) * 10)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.font-mono{font-family:var(--font-mono)}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.break-all{word-break:break-all}.text-amber-300{color:var(--color-amber-300)}.text-amber-400{color:var(--color-amber-400)}.text-blue-300{color:var(--color-blue-300)}.text-blue-400{color:var(--color-blue-400)}.text-cyan-400{color:var(--color-cyan-400)}.text-emerald-300{color:var(--color-emerald-300)}.text-emerald-400{color:var(--color-emerald-400)}.text-kick-500{color:var(--color-kick-500)}.text-red-300{color:var(--color-red-300)}.text-red-400{color:var(--color-red-400)}.text-slate-200{color:var(--color-slate-200)}.text-slate-300{color:var(--color-slate-300)}.text-slate-400{color:var(--color-slate-400)}.text-slate-500{color:var(--color-slate-500)}.text-slate-600{color:var(--color-slate-600)}.text-teal-300{color:var(--color-teal-300)}.text-teal-400{color:var(--color-teal-400)}.text-text-body{color:var(--color-text-body)}.text-text-muted{color:var(--color-text-muted)}.text-text-secondary{color:var(--color-text-secondary)}.text-text-strong{color:var(--color-text-strong)}.text-violet-300{color:var(--color-violet-300)}.text-violet-400{color:var(--color-violet-400)}.text-white{color:var(--color-white)}.normal-case{text-transform:none}.uppercase{text-transform:uppercase}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.placeholder-slate-500::placeholder{color:var(--color-slate-500)}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.select-none{-webkit-user-select:none;user-select:none}.placeholder\:text-text-muted::placeholder{color:var(--color-text-muted)}@media (hover:hover){.hover\:bg-border-strong:hover{background-color:var(--color-border-strong)}.hover\:bg-kick-500\/30:hover{background-color:#e0b0204d}@supports (color:color-mix(in lab, red, red)){.hover\:bg-kick-500\/30:hover{background-color:color-mix(in oklab, var(--color-kick-500) 30%, transparent)}}.hover\:bg-kick-600:hover{background-color:var(--color-kick-600)}.hover\:bg-slate-700:hover{background-color:var(--color-slate-700)}.hover\:bg-surface-2\/50:hover{background-color:#1a223680}@supports (color:color-mix(in lab, red, red)){.hover\:bg-surface-2\/50:hover{background-color:color-mix(in oklab, var(--color-surface-2) 50%, transparent)}}.hover\:text-slate-300:hover{color:var(--color-slate-300)}.hover\:text-text-body:hover{color:var(--color-text-body)}.hover\:text-text-strong:hover{color:var(--color-text-strong)}.hover\:opacity-80:hover{opacity:.8}}.focus\:border-kick-500:focus{border-color:var(--color-kick-500)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.disabled\:opacity-30:disabled{opacity:.3}.disabled\:opacity-50:disabled{opacity:.5}@media (min-width:40rem){.sm\:flex-row{flex-direction:row}}@media (min-width:48rem){.md\:col-span-2{grid-column:span 2/span 2}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media (min-width:64rem){.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}}[data-theme=dark]{--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}[data-theme=light]{--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light}:root{--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}[data-theme=light]{--color-kick-400:#b88712;--color-kick-500:#a07810;--color-kick-600:#7a5a08;--color-kick-purple-400:#7c4ee8;--color-kick-purple-500:#6d39d9;--color-kick-purple-600:#5b25c2;--color-app-bg:#f8fafc;--color-app-text:#0f172a;--color-surface-1:#fff;--color-surface-2:#f1f5f9;--color-surface-hover:#e2e8f0;--color-border:#e2e8f0;--color-border-strong:#cbd5e1;--color-text-strong:#0f172a;--color-text-body:#1e293b;--color-text-secondary:#475569;--color-text-muted:#64748b;--color-accent-on:#fff;--color-tooltip-bg:#1e293b;--color-tooltip-text:#f1f5f9;--color-tooltip-border:#475569}.dt-theme-toggle{height:calc(var(--spacing) * 7);width:calc(var(--spacing) * 7);cursor:pointer;border-radius:var(--radius-md);border-style:var(--tw-border-style);color:var(--color-text-secondary);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));background-color:#0000;border-width:1px;border-color:#0000;justify-content:center;align-items:center;display:inline-flex}@media (hover:hover){.dt-theme-toggle:hover{border-color:var(--color-border-strong);background-color:var(--color-surface-hover);color:var(--color-text-strong)}}.dt-theme-toggle svg{width:16px;height:16px}.dt-tip{vertical-align:middle;color:var(--color-text-secondary);cursor:help;align-items:center;margin-left:4px;display:inline-flex;position:relative}.dt-tip-clickable{cursor:pointer;color:var(--color-text-secondary);background:0 0;border:none;padding:0}.dt-tip-clickable:hover,.dt-tip:hover{color:var(--color-accent)}.dt-tip-icon{flex-shrink:0;width:14px;height:14px}.dt-tip-pop{z-index:100;visibility:hidden;opacity:0;width:max-content;max-width:240px;color:var(--color-tooltip-text);background:var(--color-tooltip-bg);border:1px solid var(--color-tooltip-border);pointer-events:none;white-space:normal;border-radius:6px;padding:6px 10px;font-size:11px;font-weight:400;line-height:1.4;transition:opacity .12s,visibility .12s;position:absolute;box-shadow:0 4px 12px #0000004d}.dt-tip-pop-top{bottom:calc(100% + 6px);left:50%;transform:translate(-50%)}.dt-tip-pop-bottom{top:calc(100% + 6px);left:50%;transform:translate(-50%)}.dt-tip:hover .dt-tip-pop,.dt-tip:focus-within .dt-tip-pop{visibility:visible;opacity:1}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-leading{syntax:"*";inherits:false}@keyframes pulse{50%{opacity:.5}}
|
|
3
3
|
/*$vite$:1*/
|
package/public/spa/index.html
CHANGED
|
@@ -1,10 +1,34 @@
|
|
|
1
1
|
<!doctype html>
|
|
2
|
-
<html lang="en">
|
|
2
|
+
<html lang="en" data-theme="dark">
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<meta name="color-scheme" content="dark light" />
|
|
7
7
|
<title>KickJS DevTools</title>
|
|
8
|
+
<!--
|
|
9
|
+
Inline pre-paint script — reads the persisted theme + system
|
|
10
|
+
preference and sets data-theme BEFORE the SPA bundle loads.
|
|
11
|
+
Without this, dark/light flips visibly when the SPA mounts.
|
|
12
|
+
-->
|
|
13
|
+
<script>
|
|
14
|
+
(function () {
|
|
15
|
+
try {
|
|
16
|
+
var stored = localStorage.getItem('kickjs-devtools-theme')
|
|
17
|
+
var resolved = stored
|
|
18
|
+
if (!resolved || resolved === 'system') {
|
|
19
|
+
resolved =
|
|
20
|
+
window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches
|
|
21
|
+
? 'light'
|
|
22
|
+
: 'dark'
|
|
23
|
+
}
|
|
24
|
+
if (resolved === 'light' || resolved === 'dark') {
|
|
25
|
+
document.documentElement.dataset.theme = resolved
|
|
26
|
+
}
|
|
27
|
+
} catch (e) {
|
|
28
|
+
/* localStorage unavailable — keep the SSR default. */
|
|
29
|
+
}
|
|
30
|
+
})()
|
|
31
|
+
</script>
|
|
8
32
|
<script type="module" crossorigin src="/_debug/assets/index.js"></script>
|
|
9
33
|
<link rel="stylesheet" crossorigin href="/_debug/assets/style.css">
|
|
10
34
|
</head>
|