@singhak/nodeui-core 0.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/constants.ts","../src/ring-buffer.ts","../src/safety.ts","../src/confirmations.ts","../src/registry.ts","../src/static.ts","../src/providers/sampler.ts","../src/providers/startup-tracker.ts","../src/providers/memory.ts","../src/providers/cpu.ts","../src/providers/event-loop.ts","../src/providers/health.ts","../src/providers/heap-snapshot.ts","../src/providers/requests.ts","../src/providers/metrics.ts","../src/providers/env.ts","../src/providers/routes.ts","../src/providers/logs.ts","../src/sse.ts","../src/server.ts"],"sourcesContent":["/**\n * @nodeui/core — framework-neutral engine and safety gate for the NodeUI\n * developer console. Serves the bundled React console and the observability\n * REST API to loopback-only, dev-activated Node.js applications.\n */\n\nexport * from './types';\nexport * from './constants';\nexport * from './ring-buffer';\nexport * from './safety';\nexport * from './confirmations';\nexport * from './registry';\nexport * from './static';\nexport * from './providers';\nexport { startSse, type SseStream } from './sse';\nexport { createNodeUI, serializeEnvelope } from './server';\nexport type { NodeUIOptions, NodeUIServer, NodeUIMiddleware } from './server';\n","/** Replacement value used when masking secret values. */\nexport const SECRET_MASKED = '[REDACTED]';\n\n/** Default ring buffer capacity for the log viewer. */\nexport const DEFAULT_LOG_SIZE = 500;\n","/**\n * Fixed-size ring buffer. When full, pushing drops the oldest item.\n * Used for the HTTP request log to keep memory bounded.\n */\nexport class RingBuffer<T> {\n private buffer: Array<T | undefined>;\n private head = 0;\n private count = 0;\n readonly capacity: number;\n\n constructor(size: number) {\n if (!Number.isInteger(size) || size <= 0) {\n throw new Error('RingBuffer size must be a positive integer');\n }\n this.capacity = size;\n this.buffer = new Array<T | undefined>(size);\n }\n\n push(item: T): void {\n this.buffer[(this.head + this.count) % this.capacity] = item;\n if (this.count < this.capacity) {\n this.count += 1;\n } else {\n this.head = (this.head + 1) % this.capacity;\n }\n }\n\n get length(): number {\n return this.count;\n }\n\n toArray(): T[] {\n return this.slice(0, this.count);\n }\n\n /**\n * Returns up to `limit` items starting at `offset`, oldest first.\n */\n slice(offset = 0, limit?: number): T[] {\n const capped = limit === undefined ? this.count : Math.max(0, limit);\n const out: T[] = [];\n for (let i = 0; i < this.count && out.length < capped; i += 1) {\n if (i >= offset) out.push(this.buffer[(this.head + i) % this.capacity] as T);\n }\n return out;\n }\n}\n","import { SECRET_MASKED } from './constants';\n\n/** Keys whose values are redacted in any panel output. */\nexport const SECRET_KEY_PATTERN = /token|key|secret|password|credential/i;\n\nexport interface ActivationDecision {\n active: boolean;\n reason: string;\n}\n\n/**\n * Safety-gate activation. The console is active when `NODEUI_ENABLED=true`\n * or when `NODE_ENV` is not `production`. `NODEUI_ENABLED=false` explicitly\n * disables it everywhere (including development). Otherwise it fails closed.\n */\nexport function resolveActivation(env: Record<string, string | undefined>): ActivationDecision {\n if (env.NODEUI_ENABLED === 'true') {\n return { active: true, reason: 'activated by NODEUI_ENABLED=true' };\n }\n if (env.NODEUI_ENABLED === 'false') {\n return { active: false, reason: 'inactive: explicitly disabled by NODEUI_ENABLED=false' };\n }\n if (env.NODE_ENV !== 'production') {\n return {\n active: true,\n reason: `activated by NODE_ENV=\"${env.NODE_ENV ?? 'unset'}\" (non-production)`,\n };\n }\n return {\n active: false,\n reason: \"inactive: NODE_ENV=production and NODEUI_ENABLED is not 'true' (fail-closed)\",\n };\n}\n\n/** True when the socket address is a loopback address. */\nexport function isLoopbackAddress(address: string | undefined): boolean {\n if (!address) return false;\n return (\n address.startsWith('127.') ||\n address === '::1' ||\n address.startsWith('::ffff:127.') ||\n address === 'localhost'\n );\n}\n\n/**\n * Deep-clone a value, replacing any value under a key matching the secret\n * pattern with `[REDACTED]`. The input is not mutated.\n */\nexport function maskSecrets<T>(value: T, pattern: RegExp = SECRET_KEY_PATTERN): T {\n if (value !== null && typeof value === 'object') {\n if (Array.isArray(value)) {\n return value.map((v) => maskSecrets(v, pattern)) as T;\n }\n const record = value as Record<string, unknown>;\n const keys = Object.keys(record);\n if (\n keys.length === 2 &&\n keys.includes('key') &&\n keys.includes('value') &&\n typeof record.key === 'string'\n ) {\n const masked = pattern.test(record.key) ? SECRET_MASKED : record.value;\n return { key: record.key, value: maskSecrets(masked, pattern) } as T;\n }\n const out: Record<string, unknown> = {};\n for (const [key, v] of Object.entries(value)) {\n if (pattern.test(key)) {\n out[key] = SECRET_MASKED;\n } else {\n out[key] = maskSecrets(v, pattern);\n }\n }\n return out as T;\n }\n return value;\n}\n","import { randomBytes } from 'node:crypto';\nimport type { ConfirmIssued } from './types';\n\n/**\n * Single-use, expiring confirmation nonces. Mutating actions (such as heap\n * snapshots) require a nonce issued here, presented via the\n * `x-nodeui-confirm` header, which is consumed exactly once.\n */\nexport class ConfirmationStore {\n private nonces = new Map<string, number>();\n\n constructor(private readonly ttlMs: number) {}\n\n issue(): ConfirmIssued {\n this.prune();\n const nonce = randomBytes(16).toString('hex');\n const expiresAtMs = Date.now() + this.ttlMs;\n this.nonces.set(nonce, expiresAtMs);\n return { nonce, expiresAtMs, ttlMs: this.ttlMs };\n }\n\n /** Consumes `nonce` and returns true only if it was valid and unexpired. */\n consume(nonce: string): boolean {\n this.prune();\n const expiresAt = this.nonces.get(nonce);\n if (expiresAt === undefined) return false;\n this.nonces.delete(nonce);\n return Date.now() <= expiresAt;\n }\n\n /** Number of currently valid nonces (after pruning). */\n size(): number {\n this.prune();\n return this.nonces.size;\n }\n\n /** Removes expired nonces. */\n prune(): void {\n const now = Date.now();\n for (const [nonce, expiresAt] of this.nonces) {\n if (expiresAt <= now) this.nonces.delete(nonce);\n }\n }\n}\n","import type { NodeUIProvider, PanelId } from './types';\n\n/** Ordered registry of the standard panel providers. */\nexport class ProviderRegistry {\n private providers = new Map<PanelId, NodeUIProvider>();\n\n register(provider: NodeUIProvider): void {\n this.providers.set(provider.id, provider);\n }\n\n get(id: PanelId): NodeUIProvider | undefined {\n return this.providers.get(id);\n }\n\n ids(): PanelId[] {\n return [...this.providers.keys()];\n }\n\n all(): NodeUIProvider[] {\n return [...this.providers.values()];\n }\n}\n","import { createReadStream, existsSync, statSync } from 'node:fs';\nimport type { Readable } from 'node:stream';\nimport { join, resolve, sep } from 'node:path';\n\nconst MIME_TYPES: Record<string, string> = {\n '.html': 'text/html; charset=utf-8',\n '.js': 'text/javascript; charset=utf-8',\n '.mjs': 'text/javascript; charset=utf-8',\n '.css': 'text/css; charset=utf-8',\n '.svg': 'image/svg+xml',\n '.json': 'application/json; charset=utf-8',\n '.png': 'image/png',\n '.ico': 'image/x-icon',\n '.map': 'application/json; charset=utf-8',\n '.woff': 'font/woff',\n '.woff2': 'font/woff2',\n '.webmanifest': 'application/manifest+json',\n};\n\nexport interface StaticAsset {\n content: Readable;\n contentType: string;\n length: number;\n}\n\n/**\n * Resolves a URL path to a file inside `rootDir`, serving `index.html` for\n * directories and falling back to `index.html` for unknown paths (SPA).\n * Returns null when the path would escape `rootDir`.\n */\nexport function resolveStaticAsset(rootDir: string, urlPath: string): StaticAsset | null {\n const relative = urlPath === '' ? 'index.html' : urlPath.replace(/^\\/+/, '');\n const candidate = resolve(rootDir, relative);\n const rootWithSep = rootDir.endsWith(sep) ? rootDir : rootDir + sep;\n if (candidate !== rootDir && !candidate.startsWith(rootWithSep)) {\n return null;\n }\n\n let file = candidate;\n if (existsSync(file) && statSync(file).isDirectory()) {\n file = join(file, 'index.html');\n }\n if (!existsSync(file) || !statSync(file).isFile()) {\n file = join(rootDir, 'index.html');\n }\n if (!existsSync(file)) {\n return null;\n }\n\n const ext = file.slice(file.lastIndexOf('.')).toLowerCase();\n const stat = statSync(file);\n return {\n content: createReadStream(file),\n contentType: MIME_TYPES[ext] ?? 'application/octet-stream',\n length: stat.size,\n };\n}\n","export interface SamplerOptions<T> {\n intervalMs: number;\n collect: () => T;\n onSample: (sample: T) => void;\n}\n\n/**\n * Wraps a tracked `setInterval`. Idempotent `start`, guaranteed `stop`,\n * and a `collect` that never throws into the event loop. All timers are\n * cleared on `stop` — no leaks on hot reload.\n */\nexport class Sampler<T> {\n private timer: NodeJS.Timeout | null = null;\n\n constructor(private readonly opts: SamplerOptions<T>) {}\n\n start(): void {\n if (this.timer) return;\n const run = (): void => {\n try {\n this.opts.onSample(this.opts.collect());\n } catch {\n // sampling must never throw into the event loop\n }\n };\n this.timer = setInterval(run, this.opts.intervalMs);\n run();\n }\n\n stop(): void {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n }\n\n get isRunning(): boolean {\n return this.timer !== null;\n }\n}\n","import type { StartupData, StartupMark } from '../types';\n\n/** Records ordered bootstrap timing marks. */\nexport class StartupTracker {\n private startedAtMs = Date.now();\n private marks: StartupMark[] = [];\n\n mark(name: string): void {\n const atMs = Date.now();\n this.marks.push({ name, atMs, sinceFirstMs: atMs - this.startedAtMs });\n }\n\n getData(): StartupData {\n return { startedAtMs: this.startedAtMs, marks: [...this.marks] };\n }\n\n reset(): void {\n this.startedAtMs = Date.now();\n this.marks = [];\n }\n}\n","import { freemem, totalmem } from 'node:os';\nimport type { MemoryData, NodeUIProvider, ProviderContext } from '../types';\nimport { Sampler } from './sampler';\n\nconst ZEROED: MemoryData = {\n heapUsed: 0,\n heapTotal: 0,\n rss: 0,\n external: 0,\n totalMem: 0,\n freeMem: 0,\n sampleAtMs: 0,\n};\n\n/** Samples `process.memoryUsage()` plus OS totals on the poll interval. */\nexport class MemoryProvider implements NodeUIProvider<MemoryData> {\n readonly id = 'memory' as const;\n\n private sampler: Sampler<MemoryData> | null = null;\n private latest: MemoryData = ZEROED;\n\n private collect(): MemoryData {\n const usage = process.memoryUsage();\n return {\n heapUsed: usage.heapUsed,\n heapTotal: usage.heapTotal,\n rss: usage.rss,\n external: usage.external,\n totalMem: totalmem(),\n freeMem: freemem(),\n sampleAtMs: Date.now(),\n };\n }\n\n start(ctx: ProviderContext): void {\n if (this.sampler) return;\n this.sampler = new Sampler({\n intervalMs: ctx.config.pollIntervalMs,\n collect: () => this.collect(),\n onSample: (sample) => {\n this.latest = sample;\n ctx.store[this.id] = sample;\n },\n });\n this.sampler.start();\n }\n\n stop(): void {\n this.sampler?.stop();\n this.sampler = null;\n }\n\n get(): { ok: true; data: MemoryData } {\n return { ok: true, data: this.latest };\n }\n}\n","import type { CpuData, NodeUIProvider, ProviderContext } from '../types';\nimport { Sampler } from './sampler';\n\nexport interface CpuUsageSnapshot {\n user: number;\n system: number;\n}\n\n/**\n * Injectable clock so CPU delta math is unit-testable. `nowUs` returns the\n * wall clock in microseconds; `cpuUsage` returns cumulative microseconds of\n * user/system CPU time since process start (like `process.cpuUsage()`).\n */\nexport interface CpuClock {\n nowUs: () => bigint;\n cpuUsage: () => CpuUsageSnapshot;\n /** Test hook: advance to the next scripted step. */\n tick?: () => void;\n}\n\nconst defaultClock: CpuClock = {\n nowUs: () => process.hrtime.bigint() / 1000n,\n cpuUsage: () => process.cpuUsage(),\n};\n\nconst ZEROED: CpuData = { userPercent: 0, systemPercent: 0, totalPercent: 0, sampleAtMs: 0 };\n\ninterface CpuPoint {\n cpu: CpuUsageSnapshot;\n atUs: bigint;\n}\n\nfunction clampPercent(v: number): number {\n return Math.min(100, Math.max(0, v));\n}\n\n/** Computes CPU usage percent via deltas of `process.cpuUsage()`. */\nexport class CpuProvider implements NodeUIProvider<CpuData> {\n readonly id = 'cpu' as const;\n\n private sampler: Sampler<CpuData> | null = null;\n private latest: CpuData = ZEROED;\n private last: CpuPoint | null = null;\n\n constructor(private readonly clock: CpuClock = defaultClock) {}\n\n /** Runs one sampling step immediately; called by the sampler on each tick. */\n collect(): CpuData {\n const cpu = this.clock.cpuUsage();\n const atUs = this.clock.nowUs();\n let sample: CpuData = { ...ZEROED, sampleAtMs: Date.now() };\n if (this.last) {\n const userUs = cpu.user - this.last.cpu.user;\n const systemUs = cpu.system - this.last.cpu.system;\n const elapsedUs = Number(atUs - this.last.atUs);\n if (elapsedUs > 0) {\n sample = {\n userPercent: clampPercent((userUs / elapsedUs) * 100),\n systemPercent: clampPercent((systemUs / elapsedUs) * 100),\n totalPercent: clampPercent(((userUs + systemUs) / elapsedUs) * 100),\n sampleAtMs: Date.now(),\n };\n }\n }\n this.last = { cpu, atUs };\n this.latest = sample;\n return sample;\n }\n\n start(ctx: ProviderContext): void {\n if (this.sampler) return;\n this.sampler = new Sampler({\n intervalMs: ctx.config.pollIntervalMs,\n collect: () => this.collect(),\n onSample: (sample) => {\n this.latest = sample;\n ctx.store[this.id] = sample;\n },\n });\n this.sampler.start();\n }\n\n stop(): void {\n this.sampler?.stop();\n this.sampler = null;\n }\n\n get(): { ok: true; data: CpuData } {\n return { ok: true, data: this.latest };\n }\n}\n","import type { EventLoopSample, NodeUIProvider, ProviderContext } from '../types';\nimport { Sampler } from './sampler';\n\nexport interface EventLoopClock {\n /** Current time in nanoseconds. */\n nowNs: () => bigint;\n}\n\nconst defaultClock: EventLoopClock = {\n nowNs: () => process.hrtime.bigint(),\n};\n\nconst MAX_KEPT_SAMPLES = 600;\n\nconst ZEROED: EventLoopSample = {\n currentMs: 0,\n maxMs: 0,\n avgMs: 0,\n count: 0,\n sampleAtMs: 0,\n};\n\n/**\n * Measures event-loop lag from a background timer: each tick reports how far\n * behind the nominal interval the loop actually was. Keeps a rolling window\n * of samples so the panel can show current/max/average lag.\n */\nexport class EventLoopLagProvider implements NodeUIProvider<EventLoopSample> {\n readonly id = 'event-loop' as const;\n\n private sampler: Sampler<EventLoopSample> | null = null;\n private samples: number[] = [];\n private latest: EventLoopSample = ZEROED;\n private lastFireNs: bigint | null = null;\n\n constructor(private readonly clock: EventLoopClock = defaultClock) {}\n\n /** Runs one measurement tick; called by the sampler on each interval. */\n collect(intervalMs: number): EventLoopSample {\n const nowNs = this.clock.nowNs();\n let lagMs = 0;\n if (this.lastFireNs !== null) {\n const elapsedMs = Number(nowNs - this.lastFireNs) / 1e6;\n lagMs = Math.max(0, elapsedMs - intervalMs);\n }\n this.lastFireNs = nowNs;\n\n this.samples.push(lagMs);\n if (this.samples.length > MAX_KEPT_SAMPLES) this.samples.shift();\n\n const count = this.samples.length;\n const total = this.samples.reduce((acc, v) => acc + v, 0);\n const sample: EventLoopSample = {\n currentMs: lagMs,\n maxMs: Math.max(...this.samples),\n avgMs: count > 0 ? total / count : 0,\n count,\n sampleAtMs: Date.now(),\n };\n this.latest = sample;\n return sample;\n }\n\n start(ctx: ProviderContext): void {\n if (this.sampler) return;\n this.lastFireNs = this.clock.nowNs();\n this.sampler = new Sampler({\n intervalMs: ctx.config.pollIntervalMs,\n collect: () => this.collect(ctx.config.pollIntervalMs),\n onSample: (sample) => {\n this.latest = sample;\n ctx.store[this.id] = sample;\n },\n });\n this.sampler.start();\n }\n\n stop(): void {\n this.sampler?.stop();\n this.sampler = null;\n }\n\n get(): { ok: true; data: EventLoopSample } {\n return { ok: true, data: this.latest };\n }\n}\n","import type {\n EventLoopSample,\n HealthData,\n MemoryData,\n NodeUIProvider,\n ProviderContext,\n} from '../types';\n\nconst LAG_OK_MS = 50;\nconst LAG_DEGRADED_MS = 200;\n\ntype StoredMemory = Partial<MemoryData>;\ntype StoredEventLoop = Partial<EventLoopSample>;\n\n/** Derives process + event-loop health from the latest sampled values. */\nexport class HealthProvider implements NodeUIProvider<HealthData> {\n readonly id = 'health' as const;\n\n get(ctx: ProviderContext): { ok: true; data: HealthData } {\n const loop = ctx.store['event-loop'] as StoredEventLoop | undefined;\n const memory = ctx.store.memory as StoredMemory | undefined;\n const lagMs = typeof loop?.currentMs === 'number' ? loop.currentMs : null;\n const totalMem = typeof memory?.totalMem === 'number' ? memory.totalMem : 0;\n const rss = typeof memory?.rss === 'number' ? memory.rss : 0;\n const memoryUsedPercent = totalMem > 0 ? (rss / totalMem) * 100 : null;\n\n let status: HealthData['status'];\n let statusReason: string;\n if (lagMs === null) {\n status = 'unknown';\n statusReason = 'no event-loop samples yet (open the Event-loop panel)';\n } else if (lagMs < LAG_OK_MS) {\n status = 'ok';\n statusReason = `event-loop lag ${lagMs.toFixed(1)}ms below ${LAG_OK_MS}ms`;\n } else if (lagMs < LAG_DEGRADED_MS) {\n status = 'degraded';\n statusReason = `event-loop lag ${lagMs.toFixed(1)}ms between ${LAG_OK_MS}ms and ${LAG_DEGRADED_MS}ms`;\n } else {\n status = 'critical';\n statusReason = `event-loop lag ${lagMs.toFixed(1)}ms above ${LAG_DEGRADED_MS}ms`;\n }\n\n return {\n ok: true,\n data: {\n status,\n statusReason,\n uptimeSeconds: Math.round(process.uptime()),\n pid: process.pid,\n nodeVersion: process.version,\n platform: process.platform,\n eventLoopLagMs: lagMs,\n memoryUsedPercent,\n },\n };\n }\n}\n","import { mkdir, stat } from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport { writeHeapSnapshot } from 'node:v8';\nimport type {\n HeapSnapshotData,\n HeapSnapshotPanelData,\n NodeUIProvider,\n ProviderContext,\n ProviderResult,\n} from '../types';\n\nfunction defaultSnapshotDir(): string {\n return process.env.NODEUI_HEAP_SNAPSHOT_DIR ?? tmpdir();\n}\n\n/**\n * Heap snapshots via `v8.writeHeapSnapshot`. The panel is read-only; the\n * actual file write happens only through `takeSnapshot`, which the server\n * gates behind a confirmation nonce.\n */\nexport class HeapSnapshotProvider implements NodeUIProvider<HeapSnapshotPanelData> {\n readonly id = 'heap-snapshot' as const;\n\n private lastSnapshot: HeapSnapshotData | null = null;\n\n get(): { ok: true; data: HeapSnapshotPanelData } {\n return { ok: true, data: { supported: true, lastSnapshot: this.lastSnapshot } };\n }\n\n async takeSnapshot(ctx: ProviderContext): Promise<ProviderResult<HeapSnapshotData>> {\n const dir = ctx.config.heapSnapshotDir || defaultSnapshotDir();\n const stamp = new Date().toISOString().replace(/[:.]/g, '-');\n const fileName = `nodeui-heap-${process.pid}-${stamp}.heapsnapshot`;\n const filePath = join(dir, fileName);\n try {\n await mkdir(dir, { recursive: true });\n writeHeapSnapshot(filePath);\n const fileStat = await stat(filePath);\n const data: HeapSnapshotData = {\n fileName,\n filePath,\n sizeBytes: fileStat.size,\n createdAtMs: Date.now(),\n };\n this.lastSnapshot = data;\n return { ok: true, data };\n } catch (err) {\n return {\n ok: false,\n error: {\n code: 'heap-snapshot-failed',\n message: err instanceof Error ? err.message : 'heap snapshot failed',\n },\n };\n }\n }\n}\n","import type { NodeUIProvider, RequestEntry, RequestsData } from '../types';\nimport { RingBuffer } from '../ring-buffer';\n\nconst RESPONSE_PAGE_SIZE = 100;\n\n/** Fixed-size ring buffer of recent HTTP requests, recorded via middleware hook. */\nexport class RequestsProvider implements NodeUIProvider<RequestsData> {\n readonly id = 'requests' as const;\n\n private buffer: RingBuffer<RequestEntry>;\n private nextId = 1;\n\n constructor(size: number) {\n this.buffer = new RingBuffer<RequestEntry>(size);\n }\n\n record(entry: Omit<RequestEntry, 'id'>): void {\n this.buffer.push({ id: this.nextId, ...entry });\n this.nextId += 1;\n }\n\n get length(): number {\n return this.buffer.length;\n }\n\n get(): { ok: true; data: RequestsData } {\n const entries = this.buffer.slice(Math.max(0, this.buffer.length - RESPONSE_PAGE_SIZE));\n return { ok: true, data: { total: this.buffer.length, entries } };\n }\n}\n","import type { MetricsBucket, MetricsData, NodeUIProvider } from '../types';\n\nconst WINDOW_SECONDS = 60;\n\n/**\n * Records one-second buckets of request counts and error counts, derived from\n * the request recorder in the server middleware. Errors are responses with\n * status >= 500.\n */\nexport class MetricsProvider implements NodeUIProvider<MetricsData> {\n readonly id = 'metrics' as const;\n\n private buckets: MetricsBucket[] = [];\n private readonly nowMs: () => number;\n\n constructor(nowMs: () => number = Date.now) {\n this.nowMs = nowMs;\n }\n\n /** Ticks the current second bucket for one completed request. */\n record(status: number): void {\n const ts = Math.floor(this.nowMs() / 1000) * 1000;\n const last = this.buckets[this.buckets.length - 1];\n if (last && last.ts === ts) {\n last.requests += 1;\n if (status >= 500) last.errors += 1;\n return;\n }\n this.buckets.push({ ts, requests: 1, errors: status >= 500 ? 1 : 0 });\n if (this.buckets.length > WINDOW_SECONDS + 1) {\n this.buckets.splice(0, this.buckets.length - WINDOW_SECONDS);\n }\n }\n\n get(): { ok: true; data: MetricsData } {\n const now = Math.floor(this.nowMs() / 1000) * 1000;\n const start = now - (WINDOW_SECONDS - 1) * 1000;\n const byTs = new Map<number, MetricsBucket>(this.buckets.map((b) => [b.ts, b]));\n const buckets: MetricsBucket[] = [];\n for (let ts = start; ts <= now; ts += 1000) {\n const existing = byTs.get(ts);\n buckets.push(existing ? { ...existing } : { ts, requests: 0, errors: 0 });\n }\n return { ok: true, data: { buckets } };\n }\n}\n","import type { EnvData, EnvEntry, NodeUIProvider, ProviderContext } from '../types';\n\nfunction stringify(value: unknown): string {\n if (value === undefined) return '';\n if (typeof value === 'string') return value;\n return JSON.stringify(value);\n}\n\nfunction toEntries(source: Record<string, unknown>): EnvEntry[] {\n return Object.entries(source)\n .map(([key, value]) => ({ key, value: stringify(value) }))\n .sort((a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0));\n}\n\n/**\n * Environment and app-config viewer. The environment comes from the process\n * env snapshot; secret masking is applied later at serialization time.\n */\nexport class EnvProvider implements NodeUIProvider<EnvData> {\n readonly id = 'env' as const;\n\n get(ctx: ProviderContext): { ok: true; data: EnvData } {\n const environment = toEntries(ctx.env as Record<string, unknown>);\n const rawConfig = ctx.store['app-config'];\n let config: EnvEntry[] | null = null;\n if (rawConfig !== undefined) {\n const resolved = typeof rawConfig === 'function' ? rawConfig() : rawConfig;\n if (resolved !== undefined && resolved !== null) {\n config = toEntries(resolved as Record<string, unknown>);\n }\n }\n return { ok: true, data: { environment, config } };\n }\n}\n","import type { NodeUIProvider, ProviderContext, RouteEntry, RoutesData } from '../types';\n\ninterface RouterLayer {\n name?: string;\n path?: string;\n route?: {\n path?: string;\n methods?: Record<string, boolean>;\n stack?: Array<{ handle?: { name?: string } }>;\n };\n handle?: { stack?: RouterLayer[] };\n}\n\nfunction joinPath(prefix: string, sub: string): string {\n if (!sub || sub === '/') return prefix || '/';\n return `${prefix.replace(/\\/+$/, '')}/${sub.replace(/^\\/+/, '')}`;\n}\n\n/**\n * Recursively walks an Express-style router stack, extracting concrete\n * method + path + handler entries. Middleware-only layers are skipped.\n *\n * NOTE: This intentionally relies on Express router internals\n * (`router.stack`, `layer.route`, `layer.handle.stack`), which are stable in\n * Express 4 and 5 but not part of the public API. If a future Express\n * release changes the shape, this is the only place that needs updating —\n * the walk degrades to an empty list rather than throwing.\n */\nexport function extractRoutes(router: unknown): RouteEntry[] {\n const out: RouteEntry[] = [];\n const seen = new Set<string>();\n let stack: unknown;\n try {\n stack = (router as { stack?: unknown } | undefined)?.stack;\n } catch {\n return out;\n }\n if (!Array.isArray(stack)) return out;\n\n const walk = (layers: RouterLayer[], prefix: string): void => {\n for (const layer of layers) {\n if (!layer || typeof layer !== 'object') continue;\n if (layer.route && typeof layer.route.path === 'string') {\n const path = joinPath(prefix, layer.route.path);\n const methods = Object.entries(layer.route.methods ?? {})\n .filter(([, enabled]) => enabled)\n .map(([method]) => method.toUpperCase());\n const handler = layer.route.stack?.[0]?.handle?.name || 'anonymous';\n if (methods.length === 0) continue;\n for (const method of methods) {\n const key = `${method} ${path}`;\n if (seen.has(key)) continue;\n seen.add(key);\n out.push({ method, path, handler });\n }\n continue;\n }\n const nested = layer.handle?.stack;\n if (Array.isArray(nested)) {\n walk(nested, joinPath(prefix, layer.path ?? ''));\n }\n }\n };\n\n try {\n walk(stack as RouterLayer[], '');\n } catch {\n return [];\n }\n out.sort((a, b) => a.path.localeCompare(b.path) || a.method.localeCompare(b.method));\n return out;\n}\n\n/**\n * Lists the HTTP routes of the host application by introspecting the Express\n * router captured from `req.app._router` (or `req.app.router` on Express 5)\n * on the first handled request. Results are cached per router reference so\n * repeated fetches do not re-walk the stack.\n */\nexport class RoutesProvider implements NodeUIProvider<RoutesData> {\n readonly id = 'routes' as const;\n\n private cache = new WeakMap<object, RouteEntry[]>();\n\n get(\n ctx: ProviderContext,\n ): { ok: true; data: RoutesData } | { ok: false; error: { code: string; message: string } } {\n const router = ctx.store['express-router'];\n if (!router) {\n return {\n ok: false,\n error: {\n code: 'router-unavailable',\n message: 'No Express router captured yet. Send at least one request through the app.',\n },\n };\n }\n if (typeof router !== 'object' && typeof router !== 'function') {\n return {\n ok: false,\n error: {\n code: 'router-invalid',\n message: 'Captured router has an unexpected shape; route listing is unavailable.',\n },\n };\n }\n let routes = this.cache.get(router as object);\n if (!routes) {\n routes = extractRoutes(router);\n this.cache.set(router as object, routes);\n }\n return { ok: true, data: { routes } };\n }\n}\n","import { DEFAULT_LOG_SIZE } from '../constants';\nimport { RingBuffer } from '../ring-buffer';\nimport type { LogEntry, LogLevel, LogsData, NodeUIProvider, ProviderContext } from '../types';\n\nconst CONSOLE_METHODS: Array<[keyof Console, LogLevel]> = [\n ['debug', 'debug'],\n ['info', 'info'],\n ['log', 'info'],\n ['warn', 'warn'],\n ['error', 'error'],\n];\n\nfunction formatArg(arg: unknown): string {\n if (typeof arg === 'string') return arg;\n try {\n const json = JSON.stringify(arg);\n return json === undefined ? String(arg) : json;\n } catch {\n return String(arg);\n }\n}\n\nlet refs = 0;\nconst pushes = new Set<(entry: Omit<LogEntry, 'timestamp'>) => void>();\nconst wrappers = new Map<keyof Console, (...args: unknown[]) => void>();\nlet originals: Partial<Record<keyof Console, (...args: unknown[]) => void>> = {};\n\nfunction consoleRef(): Record<string, (...args: unknown[]) => void> {\n return console as unknown as Record<string, (...args: unknown[]) => void>;\n}\n\nfunction installWrappers(): void {\n for (const [method, level] of CONSOLE_METHODS) {\n const original = consoleRef()[method];\n originals[method] = original;\n const wrapper = (...args: unknown[]): void => {\n for (const push of pushes) {\n try {\n push({ level, message: args.map(formatArg).join(' ') });\n } catch {\n // interception must never throw into the caller\n }\n }\n if (original) original(...args);\n };\n wrappers.set(method, wrapper);\n consoleRef()[method] = wrapper;\n }\n}\n\nfunction uninstallWrappers(): void {\n for (const [method] of CONSOLE_METHODS) {\n const current = consoleRef()[method];\n if (current === wrappers.get(method)) {\n const original = originals[method];\n if (original) {\n consoleRef()[method] = original;\n } else {\n delete consoleRef()[method];\n }\n }\n // If another layer patched console after us, the current method is not\n // ours — leave the chain intact so the host app's interceptor survives.\n }\n wrappers.clear();\n originals = {};\n}\n\n/**\n * Wraps `console.debug/info/log/warn/error` to tee entries to every active\n * `push` callback. Refcounted: the first install replaces the methods, the\n * last release restores the originals. Supports concurrent consumers (e.g.\n * multiple `createNodeUI()` instances) — each registers its own push and is\n * removed independently. Never throws into the caller.\n */\nexport function interceptConsole(push: (entry: Omit<LogEntry, 'timestamp'>) => void): () => void {\n refs += 1;\n pushes.add(push);\n if (refs === 1) installWrappers();\n return () => {\n pushes.delete(push);\n refs = Math.max(0, refs - 1);\n if (refs === 0) uninstallWrappers();\n };\n}\n\n/**\n * Log viewer provider. While active it intercepts `console.*` output and\n * also accepts entries pushed via {@link addSource}. Filtering happens\n * server-side via `ctx.query.level` and `ctx.query.query`.\n */\nexport class LogsProvider implements NodeUIProvider<LogsData> {\n readonly id = 'logs' as const;\n\n private buffer: RingBuffer<LogEntry>;\n private release: (() => void) | null = null;\n\n constructor(size: number = DEFAULT_LOG_SIZE) {\n this.buffer = new RingBuffer<LogEntry>(size);\n }\n\n start(): void {\n if (this.release) return;\n this.release = interceptConsole(({ level, message }) => {\n this.buffer.push({ level, message, timestamp: Date.now() });\n });\n }\n\n stop(): void {\n this.release?.();\n this.release = null;\n }\n\n /** Pushes an external entry (logger adapter). */\n addSource(entry: { level: LogLevel; message: string }): void {\n this.buffer.push({ ...entry, timestamp: Date.now() });\n }\n\n get(ctx: ProviderContext): { ok: true; data: LogsData } {\n let entries = this.buffer.toArray();\n const level = ctx.query?.level;\n if (level) entries = entries.filter((e) => e.level === level);\n const query = ctx.query?.query;\n if (query) {\n const needle = query.toLowerCase();\n entries = entries.filter((e) => e.message.toLowerCase().includes(needle));\n }\n return { ok: true, data: { entries } };\n }\n}\n","import type { ServerResponse } from 'node:http';\n\nexport interface SseStream {\n send(payload: unknown): void;\n heartbeat(): void;\n close(): void;\n}\n\n/**\n * Minimal Server-Sent Events writer over a raw HTTP response. Events are\n * emitted as `data: <json>\\n\\n`; heartbeats as `:ping\\n\\n`.\n */\nexport function startSse(res: ServerResponse): SseStream {\n let closed = false;\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n 'X-Accel-Buffering': 'no',\n });\n res.flushHeaders?.();\n\n return {\n send(payload: unknown): void {\n if (closed || res.destroyed) return;\n res.write(`data: ${JSON.stringify(payload)}\\n\\n`);\n },\n heartbeat(): void {\n if (closed || res.destroyed) return;\n res.write(':ping\\n\\n');\n },\n close(): void {\n if (closed || res.destroyed) return;\n closed = true;\n res.end();\n },\n };\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http';\nimport { tmpdir } from 'node:os';\nimport { resolve } from 'node:path';\nimport type {\n ApiEnvelope,\n ConfigData,\n ConfirmIssued,\n HeapSnapshotData,\n LogLevel,\n NodeUIConfig,\n NodeUIProvider,\n PanelId,\n ProviderContext,\n ProviderResult,\n StartupData,\n} from './types';\nimport { maskSecrets, resolveActivation, SECRET_KEY_PATTERN } from './safety';\nimport { isLoopbackAddress } from './safety';\nimport { ConfirmationStore } from './confirmations';\nimport { DEFAULT_LOG_SIZE } from './constants';\nimport { startSse } from './sse';\nimport { ProviderRegistry } from './registry';\nimport { resolveStaticAsset } from './static';\nimport { MemoryProvider } from './providers/memory';\nimport { CpuProvider } from './providers/cpu';\nimport { EventLoopLagProvider } from './providers/event-loop';\nimport { HealthProvider } from './providers/health';\nimport { HeapSnapshotProvider } from './providers/heap-snapshot';\nimport { StartupTracker } from './providers/startup-tracker';\nimport { RequestsProvider } from './providers/requests';\nimport { MetricsProvider, LogsProvider, EnvProvider, RoutesProvider } from './providers';\n\nexport interface NodeUIOptions {\n /** URL path prefix. Default `/nodeui` (or `NODEUI_PATH`). */\n path?: string;\n /** Interface the console considers its own. Default `127.0.0.1` (or `NODEUI_HOST`). */\n host?: string;\n /** Informational port of the host application. */\n port?: number;\n /** Ring buffer capacity for the request log. Default 500. */\n requestLogSize?: number;\n /** Ring buffer capacity for the log viewer. Default 500. */\n logSize?: number;\n /** App config surfaced in the env panel; may be an object or a getter. */\n config?: unknown | (() => unknown);\n /** Sampling/polling interval in ms. Default 2000. */\n pollIntervalMs?: number;\n /** Explicit activation override. Defaults to env-based activation. */\n enabled?: boolean;\n /** Environment snapshot. Defaults to `process.env`. */\n env?: Record<string, string | undefined>;\n /** Whether secret masking applies to panel output. Default true. */\n maskSecrets?: boolean;\n /** Idle time after which background samplers stop. Default 60000. */\n inactivityTimeoutMs?: number;\n /** TTL for mutation confirmation nonces. Default 60000. */\n confirmTtlMs?: number;\n /** Directory for heap snapshot files. Defaults to the OS temp dir. */\n heapSnapshotDir?: string;\n}\n\nexport interface NodeUIServer {\n readonly config: NodeUIConfig;\n readonly active: boolean;\n readonly activationReason: string;\n /** Express/Nest compatible middleware that serves the console and API. */\n middleware(): NodeUIMiddleware;\n /** Direct request handling (no `next`); used for tests and adapters. */\n handle(req: IncomingMessage, res: ServerResponse): Promise<void>;\n /** Records a bootstrap timing mark, e.g. `mark(\"listening\")`. */\n mark(name: string): void;\n /** Whether a background-sampling provider is currently running. */\n isProviderActive(id: PanelId): boolean;\n /** Pushes an external log entry into the log viewer (logger adapter). */\n addLogSource(entry: { level: LogLevel; message: string }): void;\n /** Stops all timers and background samplers. */\n shutdown(): void;\n}\n\nexport type NodeUIMiddleware = (\n req: IncomingMessage,\n res: ServerResponse,\n next: () => void,\n) => void;\n\nconst STATIC_ROOT = resolve(__dirname, '..', 'static');\n\nconst SSE_HEARTBEAT_MS = 15_000;\n\n/**\n * Serializes an API envelope to JSON, applying secret masking so values\n * under keys like `TOKEN`/`KEY`/`SECRET`/`PASSWORD` never reach the UI.\n */\nexport function serializeEnvelope<T>(envelope: ApiEnvelope<T>): string {\n return JSON.stringify(maskSecrets(envelope));\n}\n\nfunction pathnameOf(req: IncomingMessage): string {\n const raw = (req as IncomingMessage & { originalUrl?: string }).originalUrl ?? req.url ?? '/';\n try {\n return new URL(raw, 'http://localhost').pathname;\n } catch {\n return raw;\n }\n}\n\nfunction normalizePath(value: string): string {\n const trimmed = value.trim();\n if (!trimmed.startsWith('/')) throw new Error(`NODEUI_PATH must start with \"/\", got \"${value}\"`);\n return trimmed.replace(/\\/+$/, '') || '/';\n}\n\nfunction positiveInt(value: number | undefined, fallback: number, name: string): number {\n const n = value === undefined ? fallback : value;\n if (!Number.isInteger(n) || n <= 0) throw new Error(`${name} must be a positive integer`);\n return n;\n}\n\nexport function createNodeUI(options: NodeUIOptions = {}): NodeUIServer {\n const env = options.env ?? process.env;\n\n const activation =\n options.enabled !== undefined\n ? {\n active: options.enabled,\n reason: options.enabled\n ? 'explicitly enabled via options'\n : 'explicitly disabled via options',\n }\n : resolveActivation(env);\n\n const path = normalizePath(options.path ?? env.NODEUI_PATH ?? '/nodeui');\n const host = options.host ?? env.NODEUI_HOST ?? '127.0.0.1';\n const config: NodeUIConfig = {\n path,\n host,\n port: options.port ?? (env.NODEUI_PORT ? Number(env.NODEUI_PORT) : 0),\n requestLogSize: positiveInt(\n options.requestLogSize,\n env.NODEUI_REQUEST_LOG_SIZE ? Number(env.NODEUI_REQUEST_LOG_SIZE) : 500,\n 'NODEUI_REQUEST_LOG_SIZE',\n ),\n logSize: positiveInt(\n options.logSize,\n env.NODEUI_LOG_SIZE ? Number(env.NODEUI_LOG_SIZE) : DEFAULT_LOG_SIZE,\n 'NODEUI_LOG_SIZE',\n ),\n pollIntervalMs: positiveInt(\n options.pollIntervalMs,\n env.NODEUI_POLL_INTERVAL_MS ? Number(env.NODEUI_POLL_INTERVAL_MS) : 2000,\n 'NODEUI_POLL_INTERVAL_MS',\n ),\n enabled: activation.active,\n activationReason: activation.reason,\n maskSecrets: options.maskSecrets ?? true,\n inactivityTimeoutMs: positiveInt(\n options.inactivityTimeoutMs,\n env.NODEUI_INACTIVITY_TIMEOUT_MS ? Number(env.NODEUI_INACTIVITY_TIMEOUT_MS) : 60_000,\n 'NODEUI_INACTIVITY_TIMEOUT_MS',\n ),\n confirmTtlMs: positiveInt(\n options.confirmTtlMs,\n env.NODEUI_CONFIRM_TTL_MS ? Number(env.NODEUI_CONFIRM_TTL_MS) : 60_000,\n 'NODEUI_CONFIRM_TTL_MS',\n ),\n heapSnapshotDir: options.heapSnapshotDir ?? env.NODEUI_HEAP_SNAPSHOT_DIR ?? tmpdir(),\n };\n\n if (!isLoopbackAddress(config.host)) {\n console.warn(\n `[nodeui] NODEUI_HOST is set to non-loopback \"${config.host}\". ` +\n 'The developer console will be reachable from other hosts; only do this deliberately.',\n );\n }\n\n const ctx: ProviderContext = { config, env, store: {} };\n if (options.config !== undefined) {\n ctx.store['app-config'] = options.config;\n }\n const registry = new ProviderRegistry();\n registry.register(new HealthProvider());\n registry.register(new MemoryProvider());\n registry.register(new CpuProvider());\n registry.register(new EventLoopLagProvider());\n registry.register(new HeapSnapshotProvider());\n\n const startupTracker = new StartupTracker();\n startupTracker.mark('nodeui.init');\n const startupProvider: NodeUIProvider<StartupData> = {\n id: 'startup',\n get: () => ({ ok: true, data: startupTracker.getData() }),\n };\n registry.register(startupProvider);\n\n const requestsProvider = new RequestsProvider(config.requestLogSize);\n registry.register(requestsProvider);\n\n const metricsProvider = new MetricsProvider();\n registry.register(metricsProvider);\n\n const logsProvider = new LogsProvider(config.logSize);\n registry.register(logsProvider);\n\n const envProvider = new EnvProvider();\n registry.register(envProvider);\n const routesProvider = new RoutesProvider();\n registry.register(routesProvider);\n\n const confirmations = new ConfirmationStore(config.confirmTtlMs);\n const activeProviders = new Set<PanelId>();\n let inactivityTimer: NodeJS.Timeout | null = null;\n\n function stopAll(): void {\n for (const id of activeProviders) {\n registry.get(id)?.stop?.(ctx);\n }\n activeProviders.clear();\n if (inactivityTimer) {\n clearTimeout(inactivityTimer);\n inactivityTimer = null;\n }\n }\n\n function resetInactivityTimer(): void {\n if (inactivityTimer) clearTimeout(inactivityTimer);\n inactivityTimer = setTimeout(stopAll, config.inactivityTimeoutMs);\n if (typeof inactivityTimer.unref === 'function') inactivityTimer.unref();\n }\n\n function ensureActive(id: PanelId): void {\n if (!activeProviders.has(id)) {\n registry.get(id)?.start?.(ctx);\n activeProviders.add(id);\n }\n resetInactivityTimer();\n }\n\n function sendJson(res: ServerResponse, status: number, envelope: ApiEnvelope<unknown>): void {\n const body = serializeEnvelope(envelope);\n res.writeHead(status, {\n 'Content-Type': 'application/json',\n 'Content-Length': Buffer.byteLength(body),\n 'Cache-Control': 'no-store',\n });\n res.end(body);\n }\n\n function notFound(res: ServerResponse): void {\n sendJson(res, 404, { ok: false, error: { code: 'not-found', message: 'Not found' } });\n }\n\n function isUnderPath(urlPath: string): boolean {\n return urlPath === path || urlPath.startsWith(`${path}/`);\n }\n\n async function servePanel(\n res: ServerResponse,\n id: PanelId,\n query?: Record<string, string>,\n ): Promise<void> {\n ensureActive(id);\n const provider = registry.get(id);\n if (!provider) return notFound(res);\n const requestCtx = query ? { ...ctx, query } : ctx;\n const result = (await provider.get(requestCtx)) as ProviderResult<unknown>;\n sendJson(res, result.ok ? 200 : 500, result);\n }\n\n function configData(): ConfigData {\n return {\n enabled: config.enabled,\n activationReason: config.activationReason,\n path: config.path,\n host: config.host,\n port: config.port,\n requestLogSize: config.requestLogSize,\n logSize: config.logSize,\n pollIntervalMs: config.pollIntervalMs,\n panels: registry.ids(),\n masking: { enabled: config.maskSecrets, pattern: SECRET_KEY_PATTERN.source },\n };\n }\n\n function issueConfirmation(res: ServerResponse): void {\n const issued: ConfirmIssued = confirmations.issue();\n sendJson(res, 200, { ok: true, data: issued });\n }\n\n async function takeHeapSnapshot(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const header = req.headers['x-nodeui-confirm'];\n const nonce = Array.isArray(header) ? header[0] : header;\n if (typeof nonce !== 'string' || !confirmations.consume(nonce)) {\n sendJson(res, 409, {\n ok: false,\n error: {\n code: 'confirmation-required',\n message:\n 'This mutating action needs a fresh confirmation nonce. Issue one via ' +\n 'POST ' +\n `${path}/api/confirmations` +\n ' and repeat the request with an x-nodeui-confirm header.',\n },\n });\n return;\n }\n const heapProvider = registry.get('heap-snapshot');\n if (!heapProvider || !('takeSnapshot' in heapProvider)) return notFound(res);\n const result = (await (heapProvider as HeapSnapshotProvider).takeSnapshot(\n ctx,\n )) as ProviderResult<HeapSnapshotData>;\n sendJson(res, result.ok ? 200 : 500, result);\n }\n\n async function handleLive(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const search = new URL(req.url ?? '/', 'http://localhost').searchParams;\n const requested = (search.get('panels') ?? '').split(',').filter(Boolean);\n const panels = (\n requested.length > 0\n ? requested.filter((id): id is PanelId => registry.get(id as PanelId) !== undefined)\n : registry.ids()\n ).filter((value, index, self) => self.indexOf(value) === index);\n\n if (panels.length === 0) return notFound(res);\n\n const stream = startSse(res);\n const push = async (): Promise<void> => {\n for (const id of panels) {\n ensureActive(id);\n const provider = registry.get(id);\n if (!provider) continue;\n const result = (await provider.get(ctx)) as ProviderResult<unknown>;\n stream.send({ panel: id, envelope: result });\n }\n };\n void push();\n const pushTimer = setInterval(() => void push(), config.pollIntervalMs);\n const heartbeatTimer = setInterval(() => stream.heartbeat(), SSE_HEARTBEAT_MS);\n if (typeof pushTimer.unref === 'function') pushTimer.unref();\n if (typeof heartbeatTimer.unref === 'function') heartbeatTimer.unref();\n\n const cleanup = (): void => {\n clearInterval(pushTimer);\n clearInterval(heartbeatTimer);\n stream.close();\n };\n req.on('close', cleanup);\n res.on('close', cleanup);\n }\n\n async function handleApi(\n req: IncomingMessage,\n res: ServerResponse,\n apiPath: string,\n ): Promise<void> {\n const method = (req.method ?? 'GET').toUpperCase();\n if (method === 'GET' && apiPath === '/config') {\n sendJson(res, 200, { ok: true, data: configData() });\n return;\n }\n if (method === 'GET' && apiPath === '/live') {\n return handleLive(req, res);\n }\n if (method === 'GET') {\n const panel = registry.get(apiPath.slice(1) as PanelId);\n if (panel) {\n const query = Object.fromEntries(new URL(req.url ?? '/', 'http://localhost').searchParams);\n return servePanel(res, panel.id, query);\n }\n }\n if (method === 'POST') {\n if (apiPath === '/confirmations') {\n issueConfirmation(res);\n return;\n }\n if (apiPath === '/heap-snapshot') {\n return takeHeapSnapshot(req, res);\n }\n }\n notFound(res);\n }\n\n function serveStatic(req: IncomingMessage, res: ServerResponse, urlPath: string): void {\n const relative = urlPath.slice(path.length);\n const asset = resolveStaticAsset(STATIC_ROOT, relative);\n if (!asset) {\n sendJson(res, 404, { ok: false, error: { code: 'not-found', message: 'Not found' } });\n return;\n }\n res.writeHead(200, {\n 'Content-Type': asset.contentType,\n 'Content-Length': asset.length,\n 'Cache-Control': 'no-cache',\n });\n asset.content.pipe(res);\n }\n\n function guardLoopback(req: IncomingMessage, res: ServerResponse): boolean {\n if (isLoopbackAddress(config.host)) {\n const remote = req.socket.remoteAddress;\n if (!isLoopbackAddress(remote)) {\n sendJson(res, 403, {\n ok: false,\n error: {\n code: 'forbidden',\n message: 'nodeui is loopback-only; requests from other hosts are rejected',\n },\n });\n return false;\n }\n }\n return true;\n }\n\n async function handleNodeUIPath(\n req: IncomingMessage,\n res: ServerResponse,\n urlPath: string,\n ): Promise<void> {\n if (!guardLoopback(req, res)) return;\n const apiBase = `${path}/api`;\n if (urlPath === apiBase || urlPath.startsWith(`${apiBase}/`)) {\n await handleApi(req, res, urlPath.slice(apiBase.length));\n return;\n }\n serveStatic(req, res, urlPath);\n }\n\n function captureRouter(req: IncomingMessage): void {\n if (ctx.store['express-router'] !== undefined) return;\n const app = (req as IncomingMessage & { app?: { _router?: unknown; router?: unknown } }).app;\n if (!app) return;\n let router: unknown;\n try {\n // Express 4 and 5 both expose the router on `_router` once the app has\n // handled a request. Reading it directly avoids Express 4's deprecated\n // `app.router` getter, which throws on access.\n router = app._router;\n } catch {\n router = undefined;\n }\n if (router === undefined) {\n try {\n router = app.router;\n } catch {\n router = undefined;\n }\n }\n if (router) {\n ctx.store['express-router'] = router;\n }\n }\n\n function recordAppRequest(req: IncomingMessage, res: ServerResponse): void {\n const started = process.hrtime.bigint();\n const timestampMs = Date.now();\n res.on('finish', () => {\n const durationMs = Number(process.hrtime.bigint() - started) / 1e6;\n requestsProvider.record({\n method: req.method ?? '?',\n path: pathnameOf(req),\n status: res.statusCode,\n durationMs,\n timestampMs,\n ip: req.socket.remoteAddress ?? 'unknown',\n });\n metricsProvider.record(res.statusCode);\n });\n }\n\n const server: NodeUIServer = {\n get config() {\n return config;\n },\n get active() {\n return config.enabled;\n },\n get activationReason() {\n return config.activationReason;\n },\n middleware(): NodeUIMiddleware {\n return (req, res, next) => {\n captureRouter(req);\n if (!config.enabled) {\n next();\n return;\n }\n const urlPath = pathnameOf(req);\n if (isUnderPath(urlPath)) {\n void handleNodeUIPath(req, res, urlPath);\n return;\n }\n recordAppRequest(req, res);\n next();\n };\n },\n async handle(req, res): Promise<void> {\n captureRouter(req);\n if (!config.enabled) {\n notFound(res);\n return;\n }\n const urlPath = pathnameOf(req);\n if (isUnderPath(urlPath)) {\n await handleNodeUIPath(req, res, urlPath);\n return;\n }\n notFound(res);\n },\n mark(name: string): void {\n startupTracker.mark(name);\n },\n isProviderActive(id: PanelId): boolean {\n return activeProviders.has(id);\n },\n addLogSource(entry: { level: LogLevel; message: string }): void {\n logsProvider.addSource(entry);\n },\n shutdown(): void {\n stopAll();\n },\n };\n\n return server;\n}\n"],"mappings":"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","names":["stat","ZEROED","defaultClock","ZEROED","import_node_os","import_node_path","import_node_os","import_node_path"]}