@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.
- package/README.md +82 -0
- package/dist/index.cjs +1240 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.mts +582 -0
- package/dist/index.d.ts +582 -0
- package/dist/index.mjs +1194 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +63 -0
- package/static/assets/index-DbLC8b3x.css +1 -0
- package/static/assets/index-DowJtJYZ.js +10 -0
- package/static/index.html +13 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,582 @@
|
|
|
1
|
+
import { Readable } from 'node:stream';
|
|
2
|
+
import { ServerResponse, IncomingMessage } from 'node:http';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Shared typed contract for the NodeUI developer console.
|
|
6
|
+
*
|
|
7
|
+
* The core engine, both adapters, and the browser console all speak this
|
|
8
|
+
* contract. Every provider returns a {@link ProviderResult}; every REST
|
|
9
|
+
* endpoint returns an {@link ApiEnvelope} which is the same shape.
|
|
10
|
+
*/
|
|
11
|
+
type PanelId = 'health' | 'memory' | 'cpu' | 'event-loop' | 'heap-snapshot' | 'startup' | 'requests' | 'env' | 'routes' | 'logs' | 'metrics';
|
|
12
|
+
/** Resolved, validated console configuration. */
|
|
13
|
+
interface NodeUIConfig {
|
|
14
|
+
/** URL path prefix where the console and its API are served. Default `/nodeui`. */
|
|
15
|
+
path: string;
|
|
16
|
+
/** Interface the console considers its own. Default `127.0.0.1`. */
|
|
17
|
+
host: string;
|
|
18
|
+
/** Informational port of the host application. */
|
|
19
|
+
port: number;
|
|
20
|
+
/** Ring buffer capacity for the HTTP request log. Default 500. */
|
|
21
|
+
requestLogSize: number;
|
|
22
|
+
/** Ring buffer capacity for the log viewer. Default 500. */
|
|
23
|
+
logSize: number;
|
|
24
|
+
/** Sampling/polling interval in ms. Default 2000. */
|
|
25
|
+
pollIntervalMs: number;
|
|
26
|
+
/** Whether the console is active (see {@link resolveActivation}). */
|
|
27
|
+
enabled: boolean;
|
|
28
|
+
/** Human-readable explanation of the activation decision. */
|
|
29
|
+
activationReason: string;
|
|
30
|
+
/** Whether secret masking is applied to panel output. Default true. */
|
|
31
|
+
maskSecrets: boolean;
|
|
32
|
+
/** Idle time after which background samplers stop. Default 60000. */
|
|
33
|
+
inactivityTimeoutMs: number;
|
|
34
|
+
/** TTL for mutation confirmation nonces. Default 60000. */
|
|
35
|
+
confirmTtlMs: number;
|
|
36
|
+
/** Directory where heap snapshot files are written. */
|
|
37
|
+
heapSnapshotDir: string;
|
|
38
|
+
}
|
|
39
|
+
/** Context handed to every provider call. */
|
|
40
|
+
interface ProviderContext {
|
|
41
|
+
config: NodeUIConfig;
|
|
42
|
+
/** Environment snapshot (injectable for tests; defaults to `process.env`). */
|
|
43
|
+
env: Record<string, string | undefined>;
|
|
44
|
+
/** Shared scratch pad providers can read/write. */
|
|
45
|
+
store: Record<string, unknown>;
|
|
46
|
+
/** Query parameters of the current API request (e.g. `?level=`). */
|
|
47
|
+
query?: Record<string, string>;
|
|
48
|
+
}
|
|
49
|
+
interface ProviderError {
|
|
50
|
+
/** Stable machine-readable code, e.g. `confirmation-required`. */
|
|
51
|
+
code: string;
|
|
52
|
+
/** Human-readable message. */
|
|
53
|
+
message: string;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Typed provider result. Success carries `data`; failure carries a
|
|
57
|
+
* `ProviderError`. Providers never throw to the caller.
|
|
58
|
+
*/
|
|
59
|
+
type ProviderResult<T> = {
|
|
60
|
+
ok: true;
|
|
61
|
+
data: T;
|
|
62
|
+
} | {
|
|
63
|
+
ok: false;
|
|
64
|
+
error: ProviderError;
|
|
65
|
+
};
|
|
66
|
+
/** The envelope returned by every REST endpoint. */
|
|
67
|
+
type ApiEnvelope<T> = ProviderResult<T>;
|
|
68
|
+
/**
|
|
69
|
+
* One provider per panel. Providers that sample in the background implement
|
|
70
|
+
* `start`/`stop`; the server starts them lazily on first view and stops them
|
|
71
|
+
* after a period of inactivity.
|
|
72
|
+
*/
|
|
73
|
+
interface NodeUIProvider<T = unknown> {
|
|
74
|
+
readonly id: PanelId;
|
|
75
|
+
start?(ctx: ProviderContext): void;
|
|
76
|
+
stop?(ctx: ProviderContext): void;
|
|
77
|
+
get(ctx: ProviderContext): ProviderResult<T> | Promise<ProviderResult<T>>;
|
|
78
|
+
}
|
|
79
|
+
/** Event-loop lag sample. */
|
|
80
|
+
interface EventLoopSample {
|
|
81
|
+
currentMs: number;
|
|
82
|
+
maxMs: number;
|
|
83
|
+
avgMs: number;
|
|
84
|
+
count: number;
|
|
85
|
+
sampleAtMs: number;
|
|
86
|
+
}
|
|
87
|
+
interface MemoryData {
|
|
88
|
+
heapUsed: number;
|
|
89
|
+
heapTotal: number;
|
|
90
|
+
rss: number;
|
|
91
|
+
external: number;
|
|
92
|
+
totalMem: number;
|
|
93
|
+
freeMem: number;
|
|
94
|
+
sampleAtMs: number;
|
|
95
|
+
}
|
|
96
|
+
interface CpuData {
|
|
97
|
+
userPercent: number;
|
|
98
|
+
systemPercent: number;
|
|
99
|
+
totalPercent: number;
|
|
100
|
+
sampleAtMs: number;
|
|
101
|
+
}
|
|
102
|
+
interface HealthData {
|
|
103
|
+
status: 'ok' | 'degraded' | 'critical' | 'unknown';
|
|
104
|
+
statusReason: string;
|
|
105
|
+
uptimeSeconds: number;
|
|
106
|
+
pid: number;
|
|
107
|
+
nodeVersion: string;
|
|
108
|
+
platform: string;
|
|
109
|
+
eventLoopLagMs: number | null;
|
|
110
|
+
memoryUsedPercent: number | null;
|
|
111
|
+
}
|
|
112
|
+
interface StartupMark {
|
|
113
|
+
name: string;
|
|
114
|
+
atMs: number;
|
|
115
|
+
/** Milliseconds since the first recorded mark. */
|
|
116
|
+
sinceFirstMs: number;
|
|
117
|
+
}
|
|
118
|
+
interface StartupData {
|
|
119
|
+
startedAtMs: number;
|
|
120
|
+
marks: StartupMark[];
|
|
121
|
+
}
|
|
122
|
+
interface RequestEntry {
|
|
123
|
+
id: number;
|
|
124
|
+
method: string;
|
|
125
|
+
path: string;
|
|
126
|
+
status: number;
|
|
127
|
+
durationMs: number;
|
|
128
|
+
timestampMs: number;
|
|
129
|
+
ip: string;
|
|
130
|
+
}
|
|
131
|
+
interface RequestsData {
|
|
132
|
+
total: number;
|
|
133
|
+
entries: RequestEntry[];
|
|
134
|
+
}
|
|
135
|
+
interface EnvEntry {
|
|
136
|
+
key: string;
|
|
137
|
+
value: string;
|
|
138
|
+
}
|
|
139
|
+
interface EnvData {
|
|
140
|
+
environment: EnvEntry[];
|
|
141
|
+
config: EnvEntry[] | null;
|
|
142
|
+
}
|
|
143
|
+
interface RouteEntry {
|
|
144
|
+
method: string;
|
|
145
|
+
path: string;
|
|
146
|
+
handler: string;
|
|
147
|
+
}
|
|
148
|
+
interface RoutesData {
|
|
149
|
+
routes: RouteEntry[];
|
|
150
|
+
}
|
|
151
|
+
type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
152
|
+
interface LogEntry {
|
|
153
|
+
level: LogLevel;
|
|
154
|
+
message: string;
|
|
155
|
+
timestamp: number;
|
|
156
|
+
}
|
|
157
|
+
interface LogsData {
|
|
158
|
+
entries: LogEntry[];
|
|
159
|
+
}
|
|
160
|
+
interface MetricsBucket {
|
|
161
|
+
ts: number;
|
|
162
|
+
requests: number;
|
|
163
|
+
errors: number;
|
|
164
|
+
}
|
|
165
|
+
interface MetricsData {
|
|
166
|
+
buckets: MetricsBucket[];
|
|
167
|
+
}
|
|
168
|
+
interface HeapSnapshotData {
|
|
169
|
+
fileName: string;
|
|
170
|
+
filePath: string;
|
|
171
|
+
sizeBytes: number;
|
|
172
|
+
createdAtMs: number;
|
|
173
|
+
}
|
|
174
|
+
interface HeapSnapshotPanelData {
|
|
175
|
+
supported: boolean;
|
|
176
|
+
lastSnapshot: HeapSnapshotData | null;
|
|
177
|
+
}
|
|
178
|
+
interface ConfirmIssued {
|
|
179
|
+
nonce: string;
|
|
180
|
+
expiresAtMs: number;
|
|
181
|
+
ttlMs: number;
|
|
182
|
+
}
|
|
183
|
+
interface ConfigData {
|
|
184
|
+
enabled: boolean;
|
|
185
|
+
activationReason: string;
|
|
186
|
+
path: string;
|
|
187
|
+
host: string;
|
|
188
|
+
port: number;
|
|
189
|
+
requestLogSize: number;
|
|
190
|
+
logSize: number;
|
|
191
|
+
pollIntervalMs: number;
|
|
192
|
+
panels: PanelId[];
|
|
193
|
+
masking: {
|
|
194
|
+
enabled: boolean;
|
|
195
|
+
pattern: string;
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/** Replacement value used when masking secret values. */
|
|
200
|
+
declare const SECRET_MASKED = "[REDACTED]";
|
|
201
|
+
/** Default ring buffer capacity for the log viewer. */
|
|
202
|
+
declare const DEFAULT_LOG_SIZE = 500;
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Fixed-size ring buffer. When full, pushing drops the oldest item.
|
|
206
|
+
* Used for the HTTP request log to keep memory bounded.
|
|
207
|
+
*/
|
|
208
|
+
declare class RingBuffer<T> {
|
|
209
|
+
private buffer;
|
|
210
|
+
private head;
|
|
211
|
+
private count;
|
|
212
|
+
readonly capacity: number;
|
|
213
|
+
constructor(size: number);
|
|
214
|
+
push(item: T): void;
|
|
215
|
+
get length(): number;
|
|
216
|
+
toArray(): T[];
|
|
217
|
+
/**
|
|
218
|
+
* Returns up to `limit` items starting at `offset`, oldest first.
|
|
219
|
+
*/
|
|
220
|
+
slice(offset?: number, limit?: number): T[];
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** Keys whose values are redacted in any panel output. */
|
|
224
|
+
declare const SECRET_KEY_PATTERN: RegExp;
|
|
225
|
+
interface ActivationDecision {
|
|
226
|
+
active: boolean;
|
|
227
|
+
reason: string;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Safety-gate activation. The console is active when `NODEUI_ENABLED=true`
|
|
231
|
+
* or when `NODE_ENV` is not `production`. `NODEUI_ENABLED=false` explicitly
|
|
232
|
+
* disables it everywhere (including development). Otherwise it fails closed.
|
|
233
|
+
*/
|
|
234
|
+
declare function resolveActivation(env: Record<string, string | undefined>): ActivationDecision;
|
|
235
|
+
/** True when the socket address is a loopback address. */
|
|
236
|
+
declare function isLoopbackAddress(address: string | undefined): boolean;
|
|
237
|
+
/**
|
|
238
|
+
* Deep-clone a value, replacing any value under a key matching the secret
|
|
239
|
+
* pattern with `[REDACTED]`. The input is not mutated.
|
|
240
|
+
*/
|
|
241
|
+
declare function maskSecrets<T>(value: T, pattern?: RegExp): T;
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Single-use, expiring confirmation nonces. Mutating actions (such as heap
|
|
245
|
+
* snapshots) require a nonce issued here, presented via the
|
|
246
|
+
* `x-nodeui-confirm` header, which is consumed exactly once.
|
|
247
|
+
*/
|
|
248
|
+
declare class ConfirmationStore {
|
|
249
|
+
private readonly ttlMs;
|
|
250
|
+
private nonces;
|
|
251
|
+
constructor(ttlMs: number);
|
|
252
|
+
issue(): ConfirmIssued;
|
|
253
|
+
/** Consumes `nonce` and returns true only if it was valid and unexpired. */
|
|
254
|
+
consume(nonce: string): boolean;
|
|
255
|
+
/** Number of currently valid nonces (after pruning). */
|
|
256
|
+
size(): number;
|
|
257
|
+
/** Removes expired nonces. */
|
|
258
|
+
prune(): void;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/** Ordered registry of the standard panel providers. */
|
|
262
|
+
declare class ProviderRegistry {
|
|
263
|
+
private providers;
|
|
264
|
+
register(provider: NodeUIProvider): void;
|
|
265
|
+
get(id: PanelId): NodeUIProvider | undefined;
|
|
266
|
+
ids(): PanelId[];
|
|
267
|
+
all(): NodeUIProvider[];
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
interface StaticAsset {
|
|
271
|
+
content: Readable;
|
|
272
|
+
contentType: string;
|
|
273
|
+
length: number;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Resolves a URL path to a file inside `rootDir`, serving `index.html` for
|
|
277
|
+
* directories and falling back to `index.html` for unknown paths (SPA).
|
|
278
|
+
* Returns null when the path would escape `rootDir`.
|
|
279
|
+
*/
|
|
280
|
+
declare function resolveStaticAsset(rootDir: string, urlPath: string): StaticAsset | null;
|
|
281
|
+
|
|
282
|
+
interface SamplerOptions<T> {
|
|
283
|
+
intervalMs: number;
|
|
284
|
+
collect: () => T;
|
|
285
|
+
onSample: (sample: T) => void;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Wraps a tracked `setInterval`. Idempotent `start`, guaranteed `stop`,
|
|
289
|
+
* and a `collect` that never throws into the event loop. All timers are
|
|
290
|
+
* cleared on `stop` — no leaks on hot reload.
|
|
291
|
+
*/
|
|
292
|
+
declare class Sampler<T> {
|
|
293
|
+
private readonly opts;
|
|
294
|
+
private timer;
|
|
295
|
+
constructor(opts: SamplerOptions<T>);
|
|
296
|
+
start(): void;
|
|
297
|
+
stop(): void;
|
|
298
|
+
get isRunning(): boolean;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/** Records ordered bootstrap timing marks. */
|
|
302
|
+
declare class StartupTracker {
|
|
303
|
+
private startedAtMs;
|
|
304
|
+
private marks;
|
|
305
|
+
mark(name: string): void;
|
|
306
|
+
getData(): StartupData;
|
|
307
|
+
reset(): void;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/** Samples `process.memoryUsage()` plus OS totals on the poll interval. */
|
|
311
|
+
declare class MemoryProvider implements NodeUIProvider<MemoryData> {
|
|
312
|
+
readonly id: "memory";
|
|
313
|
+
private sampler;
|
|
314
|
+
private latest;
|
|
315
|
+
private collect;
|
|
316
|
+
start(ctx: ProviderContext): void;
|
|
317
|
+
stop(): void;
|
|
318
|
+
get(): {
|
|
319
|
+
ok: true;
|
|
320
|
+
data: MemoryData;
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
interface CpuUsageSnapshot {
|
|
325
|
+
user: number;
|
|
326
|
+
system: number;
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Injectable clock so CPU delta math is unit-testable. `nowUs` returns the
|
|
330
|
+
* wall clock in microseconds; `cpuUsage` returns cumulative microseconds of
|
|
331
|
+
* user/system CPU time since process start (like `process.cpuUsage()`).
|
|
332
|
+
*/
|
|
333
|
+
interface CpuClock {
|
|
334
|
+
nowUs: () => bigint;
|
|
335
|
+
cpuUsage: () => CpuUsageSnapshot;
|
|
336
|
+
/** Test hook: advance to the next scripted step. */
|
|
337
|
+
tick?: () => void;
|
|
338
|
+
}
|
|
339
|
+
/** Computes CPU usage percent via deltas of `process.cpuUsage()`. */
|
|
340
|
+
declare class CpuProvider implements NodeUIProvider<CpuData> {
|
|
341
|
+
private readonly clock;
|
|
342
|
+
readonly id: "cpu";
|
|
343
|
+
private sampler;
|
|
344
|
+
private latest;
|
|
345
|
+
private last;
|
|
346
|
+
constructor(clock?: CpuClock);
|
|
347
|
+
/** Runs one sampling step immediately; called by the sampler on each tick. */
|
|
348
|
+
collect(): CpuData;
|
|
349
|
+
start(ctx: ProviderContext): void;
|
|
350
|
+
stop(): void;
|
|
351
|
+
get(): {
|
|
352
|
+
ok: true;
|
|
353
|
+
data: CpuData;
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
interface EventLoopClock {
|
|
358
|
+
/** Current time in nanoseconds. */
|
|
359
|
+
nowNs: () => bigint;
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Measures event-loop lag from a background timer: each tick reports how far
|
|
363
|
+
* behind the nominal interval the loop actually was. Keeps a rolling window
|
|
364
|
+
* of samples so the panel can show current/max/average lag.
|
|
365
|
+
*/
|
|
366
|
+
declare class EventLoopLagProvider implements NodeUIProvider<EventLoopSample> {
|
|
367
|
+
private readonly clock;
|
|
368
|
+
readonly id: "event-loop";
|
|
369
|
+
private sampler;
|
|
370
|
+
private samples;
|
|
371
|
+
private latest;
|
|
372
|
+
private lastFireNs;
|
|
373
|
+
constructor(clock?: EventLoopClock);
|
|
374
|
+
/** Runs one measurement tick; called by the sampler on each interval. */
|
|
375
|
+
collect(intervalMs: number): EventLoopSample;
|
|
376
|
+
start(ctx: ProviderContext): void;
|
|
377
|
+
stop(): void;
|
|
378
|
+
get(): {
|
|
379
|
+
ok: true;
|
|
380
|
+
data: EventLoopSample;
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/** Derives process + event-loop health from the latest sampled values. */
|
|
385
|
+
declare class HealthProvider implements NodeUIProvider<HealthData> {
|
|
386
|
+
readonly id: "health";
|
|
387
|
+
get(ctx: ProviderContext): {
|
|
388
|
+
ok: true;
|
|
389
|
+
data: HealthData;
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Heap snapshots via `v8.writeHeapSnapshot`. The panel is read-only; the
|
|
395
|
+
* actual file write happens only through `takeSnapshot`, which the server
|
|
396
|
+
* gates behind a confirmation nonce.
|
|
397
|
+
*/
|
|
398
|
+
declare class HeapSnapshotProvider implements NodeUIProvider<HeapSnapshotPanelData> {
|
|
399
|
+
readonly id: "heap-snapshot";
|
|
400
|
+
private lastSnapshot;
|
|
401
|
+
get(): {
|
|
402
|
+
ok: true;
|
|
403
|
+
data: HeapSnapshotPanelData;
|
|
404
|
+
};
|
|
405
|
+
takeSnapshot(ctx: ProviderContext): Promise<ProviderResult<HeapSnapshotData>>;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/** Fixed-size ring buffer of recent HTTP requests, recorded via middleware hook. */
|
|
409
|
+
declare class RequestsProvider implements NodeUIProvider<RequestsData> {
|
|
410
|
+
readonly id: "requests";
|
|
411
|
+
private buffer;
|
|
412
|
+
private nextId;
|
|
413
|
+
constructor(size: number);
|
|
414
|
+
record(entry: Omit<RequestEntry, 'id'>): void;
|
|
415
|
+
get length(): number;
|
|
416
|
+
get(): {
|
|
417
|
+
ok: true;
|
|
418
|
+
data: RequestsData;
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Records one-second buckets of request counts and error counts, derived from
|
|
424
|
+
* the request recorder in the server middleware. Errors are responses with
|
|
425
|
+
* status >= 500.
|
|
426
|
+
*/
|
|
427
|
+
declare class MetricsProvider implements NodeUIProvider<MetricsData> {
|
|
428
|
+
readonly id: "metrics";
|
|
429
|
+
private buckets;
|
|
430
|
+
private readonly nowMs;
|
|
431
|
+
constructor(nowMs?: () => number);
|
|
432
|
+
/** Ticks the current second bucket for one completed request. */
|
|
433
|
+
record(status: number): void;
|
|
434
|
+
get(): {
|
|
435
|
+
ok: true;
|
|
436
|
+
data: MetricsData;
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* Environment and app-config viewer. The environment comes from the process
|
|
442
|
+
* env snapshot; secret masking is applied later at serialization time.
|
|
443
|
+
*/
|
|
444
|
+
declare class EnvProvider implements NodeUIProvider<EnvData> {
|
|
445
|
+
readonly id: "env";
|
|
446
|
+
get(ctx: ProviderContext): {
|
|
447
|
+
ok: true;
|
|
448
|
+
data: EnvData;
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Recursively walks an Express-style router stack, extracting concrete
|
|
454
|
+
* method + path + handler entries. Middleware-only layers are skipped.
|
|
455
|
+
*
|
|
456
|
+
* NOTE: This intentionally relies on Express router internals
|
|
457
|
+
* (`router.stack`, `layer.route`, `layer.handle.stack`), which are stable in
|
|
458
|
+
* Express 4 and 5 but not part of the public API. If a future Express
|
|
459
|
+
* release changes the shape, this is the only place that needs updating —
|
|
460
|
+
* the walk degrades to an empty list rather than throwing.
|
|
461
|
+
*/
|
|
462
|
+
declare function extractRoutes(router: unknown): RouteEntry[];
|
|
463
|
+
/**
|
|
464
|
+
* Lists the HTTP routes of the host application by introspecting the Express
|
|
465
|
+
* router captured from `req.app._router` (or `req.app.router` on Express 5)
|
|
466
|
+
* on the first handled request. Results are cached per router reference so
|
|
467
|
+
* repeated fetches do not re-walk the stack.
|
|
468
|
+
*/
|
|
469
|
+
declare class RoutesProvider implements NodeUIProvider<RoutesData> {
|
|
470
|
+
readonly id: "routes";
|
|
471
|
+
private cache;
|
|
472
|
+
get(ctx: ProviderContext): {
|
|
473
|
+
ok: true;
|
|
474
|
+
data: RoutesData;
|
|
475
|
+
} | {
|
|
476
|
+
ok: false;
|
|
477
|
+
error: {
|
|
478
|
+
code: string;
|
|
479
|
+
message: string;
|
|
480
|
+
};
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Wraps `console.debug/info/log/warn/error` to tee entries to every active
|
|
486
|
+
* `push` callback. Refcounted: the first install replaces the methods, the
|
|
487
|
+
* last release restores the originals. Supports concurrent consumers (e.g.
|
|
488
|
+
* multiple `createNodeUI()` instances) — each registers its own push and is
|
|
489
|
+
* removed independently. Never throws into the caller.
|
|
490
|
+
*/
|
|
491
|
+
declare function interceptConsole(push: (entry: Omit<LogEntry, 'timestamp'>) => void): () => void;
|
|
492
|
+
/**
|
|
493
|
+
* Log viewer provider. While active it intercepts `console.*` output and
|
|
494
|
+
* also accepts entries pushed via {@link addSource}. Filtering happens
|
|
495
|
+
* server-side via `ctx.query.level` and `ctx.query.query`.
|
|
496
|
+
*/
|
|
497
|
+
declare class LogsProvider implements NodeUIProvider<LogsData> {
|
|
498
|
+
readonly id: "logs";
|
|
499
|
+
private buffer;
|
|
500
|
+
private release;
|
|
501
|
+
constructor(size?: number);
|
|
502
|
+
start(): void;
|
|
503
|
+
stop(): void;
|
|
504
|
+
/** Pushes an external entry (logger adapter). */
|
|
505
|
+
addSource(entry: {
|
|
506
|
+
level: LogLevel;
|
|
507
|
+
message: string;
|
|
508
|
+
}): void;
|
|
509
|
+
get(ctx: ProviderContext): {
|
|
510
|
+
ok: true;
|
|
511
|
+
data: LogsData;
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
interface SseStream {
|
|
516
|
+
send(payload: unknown): void;
|
|
517
|
+
heartbeat(): void;
|
|
518
|
+
close(): void;
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* Minimal Server-Sent Events writer over a raw HTTP response. Events are
|
|
522
|
+
* emitted as `data: <json>\n\n`; heartbeats as `:ping\n\n`.
|
|
523
|
+
*/
|
|
524
|
+
declare function startSse(res: ServerResponse): SseStream;
|
|
525
|
+
|
|
526
|
+
interface NodeUIOptions {
|
|
527
|
+
/** URL path prefix. Default `/nodeui` (or `NODEUI_PATH`). */
|
|
528
|
+
path?: string;
|
|
529
|
+
/** Interface the console considers its own. Default `127.0.0.1` (or `NODEUI_HOST`). */
|
|
530
|
+
host?: string;
|
|
531
|
+
/** Informational port of the host application. */
|
|
532
|
+
port?: number;
|
|
533
|
+
/** Ring buffer capacity for the request log. Default 500. */
|
|
534
|
+
requestLogSize?: number;
|
|
535
|
+
/** Ring buffer capacity for the log viewer. Default 500. */
|
|
536
|
+
logSize?: number;
|
|
537
|
+
/** App config surfaced in the env panel; may be an object or a getter. */
|
|
538
|
+
config?: unknown | (() => unknown);
|
|
539
|
+
/** Sampling/polling interval in ms. Default 2000. */
|
|
540
|
+
pollIntervalMs?: number;
|
|
541
|
+
/** Explicit activation override. Defaults to env-based activation. */
|
|
542
|
+
enabled?: boolean;
|
|
543
|
+
/** Environment snapshot. Defaults to `process.env`. */
|
|
544
|
+
env?: Record<string, string | undefined>;
|
|
545
|
+
/** Whether secret masking applies to panel output. Default true. */
|
|
546
|
+
maskSecrets?: boolean;
|
|
547
|
+
/** Idle time after which background samplers stop. Default 60000. */
|
|
548
|
+
inactivityTimeoutMs?: number;
|
|
549
|
+
/** TTL for mutation confirmation nonces. Default 60000. */
|
|
550
|
+
confirmTtlMs?: number;
|
|
551
|
+
/** Directory for heap snapshot files. Defaults to the OS temp dir. */
|
|
552
|
+
heapSnapshotDir?: string;
|
|
553
|
+
}
|
|
554
|
+
interface NodeUIServer {
|
|
555
|
+
readonly config: NodeUIConfig;
|
|
556
|
+
readonly active: boolean;
|
|
557
|
+
readonly activationReason: string;
|
|
558
|
+
/** Express/Nest compatible middleware that serves the console and API. */
|
|
559
|
+
middleware(): NodeUIMiddleware;
|
|
560
|
+
/** Direct request handling (no `next`); used for tests and adapters. */
|
|
561
|
+
handle(req: IncomingMessage, res: ServerResponse): Promise<void>;
|
|
562
|
+
/** Records a bootstrap timing mark, e.g. `mark("listening")`. */
|
|
563
|
+
mark(name: string): void;
|
|
564
|
+
/** Whether a background-sampling provider is currently running. */
|
|
565
|
+
isProviderActive(id: PanelId): boolean;
|
|
566
|
+
/** Pushes an external log entry into the log viewer (logger adapter). */
|
|
567
|
+
addLogSource(entry: {
|
|
568
|
+
level: LogLevel;
|
|
569
|
+
message: string;
|
|
570
|
+
}): void;
|
|
571
|
+
/** Stops all timers and background samplers. */
|
|
572
|
+
shutdown(): void;
|
|
573
|
+
}
|
|
574
|
+
type NodeUIMiddleware = (req: IncomingMessage, res: ServerResponse, next: () => void) => void;
|
|
575
|
+
/**
|
|
576
|
+
* Serializes an API envelope to JSON, applying secret masking so values
|
|
577
|
+
* under keys like `TOKEN`/`KEY`/`SECRET`/`PASSWORD` never reach the UI.
|
|
578
|
+
*/
|
|
579
|
+
declare function serializeEnvelope<T>(envelope: ApiEnvelope<T>): string;
|
|
580
|
+
declare function createNodeUI(options?: NodeUIOptions): NodeUIServer;
|
|
581
|
+
|
|
582
|
+
export { type ActivationDecision, type ApiEnvelope, type ConfigData, type ConfirmIssued, ConfirmationStore, type CpuClock, type CpuData, CpuProvider, type CpuUsageSnapshot, DEFAULT_LOG_SIZE, type EnvData, type EnvEntry, EnvProvider, type EventLoopClock, EventLoopLagProvider, type EventLoopSample, type HealthData, HealthProvider, type HeapSnapshotData, type HeapSnapshotPanelData, HeapSnapshotProvider, type LogEntry, type LogLevel, type LogsData, LogsProvider, type MemoryData, MemoryProvider, type MetricsBucket, type MetricsData, MetricsProvider, type NodeUIConfig, type NodeUIMiddleware, type NodeUIOptions, type NodeUIProvider, type NodeUIServer, type PanelId, type ProviderContext, type ProviderError, ProviderRegistry, type ProviderResult, type RequestEntry, type RequestsData, RequestsProvider, RingBuffer, type RouteEntry, type RoutesData, RoutesProvider, SECRET_KEY_PATTERN, SECRET_MASKED, Sampler, type SamplerOptions, type SseStream, type StartupData, type StartupMark, StartupTracker, type StaticAsset, createNodeUI, extractRoutes, interceptConsole, isLoopbackAddress, maskSecrets, resolveActivation, resolveStaticAsset, serializeEnvelope, startSse };
|