@singhak/nodeui-core 0.3.0 → 0.5.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 +6 -4
- package/dist/index.cjs +1141 -63
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +313 -6
- package/dist/index.d.ts +313 -6
- package/dist/index.mjs +1131 -58
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -1
- package/static/assets/index-BrEFUVm9.css +1 -0
- package/static/assets/index-CH4-6sZB.js +12 -0
- package/static/index.html +3 -2
- package/static/assets/index-CJCpPtrr.js +0 -11
- package/static/assets/index-ChbLMdDF.css +0 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
2
|
import { Readable } from 'node:stream';
|
|
3
3
|
|
|
4
|
+
interface OtlpOptions {
|
|
5
|
+
/** Collector base URL (e.g. `http://localhost:4318`) or a full `/v1/traces` URL. */
|
|
6
|
+
endpoint: string;
|
|
7
|
+
/** `service.name` resource attribute. Default `OTEL_SERVICE_NAME` or `nodeui-app`. */
|
|
8
|
+
serviceName?: string;
|
|
9
|
+
/** Extra HTTP headers, e.g. an auth header for a hosted collector. */
|
|
10
|
+
headers?: Record<string, string>;
|
|
11
|
+
/** Export interval. Default 2000 ms. */
|
|
12
|
+
intervalMs?: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
4
15
|
/**
|
|
5
16
|
* Shared typed contract for the NodeUI developer console.
|
|
6
17
|
*
|
|
@@ -8,7 +19,8 @@ import { Readable } from 'node:stream';
|
|
|
8
19
|
* contract. Every provider returns a {@link ProviderResult}; every REST
|
|
9
20
|
* endpoint returns an {@link ApiEnvelope} which is the same shape.
|
|
10
21
|
*/
|
|
11
|
-
|
|
22
|
+
|
|
23
|
+
type BuiltInPanelId = 'health' | 'memory' | 'cpu' | 'event-loop' | 'heap-snapshot' | 'startup' | 'requests' | 'env' | 'routes' | 'logs' | 'metrics' | 'outgoing' | 'errors' | 'queries';
|
|
12
24
|
/**
|
|
13
25
|
* Panel identifier. Built-in panels are listed in {@link BuiltInPanelId};
|
|
14
26
|
* plugins may register any other string id (lowercase letters, digits, `-`).
|
|
@@ -34,6 +46,16 @@ interface NodeUIConfig {
|
|
|
34
46
|
activationReason: string;
|
|
35
47
|
/** Whether secret masking is applied to panel output. Default true. */
|
|
36
48
|
maskSecrets: boolean;
|
|
49
|
+
/** What extra request detail is recorded. */
|
|
50
|
+
requestDetail: Required<RequestDetailOptions>;
|
|
51
|
+
/** `'always'` runs outgoing/query/log capture from startup; `'lazy'` only while a panel is open. */
|
|
52
|
+
capture: 'always' | 'lazy';
|
|
53
|
+
/** Journal file for persisting recent activity across restarts, or null. */
|
|
54
|
+
persistFile: string | null;
|
|
55
|
+
/** Rotation threshold for the journal. */
|
|
56
|
+
persistMaxBytes: number;
|
|
57
|
+
/** OTLP/HTTP trace export settings, or null when disabled. */
|
|
58
|
+
otlp: OtlpOptions | null;
|
|
37
59
|
/** Idle time after which background samplers stop. Default 60000. */
|
|
38
60
|
inactivityTimeoutMs: number;
|
|
39
61
|
/** TTL for mutation confirmation nonces. Default 60000. */
|
|
@@ -154,10 +176,62 @@ interface RequestEntry {
|
|
|
154
176
|
durationMs: number;
|
|
155
177
|
timestampMs: number;
|
|
156
178
|
ip: string;
|
|
179
|
+
/** Matched route pattern (e.g. `/users/:id`) when the framework exposes it. */
|
|
180
|
+
route?: string;
|
|
181
|
+
/** Query parameters (secret-looking keys redacted). */
|
|
182
|
+
query?: Record<string, string>;
|
|
183
|
+
/** Request headers (credentials always redacted). */
|
|
184
|
+
headers?: Record<string, string>;
|
|
185
|
+
/** Captured request body (opt-in, size-capped, masked). */
|
|
186
|
+
requestBody?: string;
|
|
187
|
+
requestBodyTruncated?: boolean;
|
|
188
|
+
/** Captured response body (opt-in, size-capped, masked). */
|
|
189
|
+
responseBody?: string;
|
|
190
|
+
responseBodyTruncated?: boolean;
|
|
191
|
+
}
|
|
192
|
+
/** The optional, privacy-sensitive part of a {@link RequestEntry}. */
|
|
193
|
+
type RequestDetail = Pick<RequestEntry, 'query' | 'headers' | 'requestBody' | 'requestBodyTruncated' | 'responseBody' | 'responseBodyTruncated'>;
|
|
194
|
+
interface RequestDetailOptions {
|
|
195
|
+
/** Record query parameters. Default true. */
|
|
196
|
+
query?: boolean;
|
|
197
|
+
/** Record request headers (credential headers are always redacted). Default true. */
|
|
198
|
+
headers?: boolean;
|
|
199
|
+
/** Record request/response bodies of textual content types. Default false. */
|
|
200
|
+
bodies?: boolean;
|
|
201
|
+
/** Max bytes kept per body. Default 4096, max 1048576. */
|
|
202
|
+
maxBodyBytes?: number;
|
|
203
|
+
}
|
|
204
|
+
interface RouteStat {
|
|
205
|
+
method: string;
|
|
206
|
+
path: string;
|
|
207
|
+
count: number;
|
|
208
|
+
avgMs: number;
|
|
209
|
+
p95Ms: number;
|
|
210
|
+
errors: number;
|
|
211
|
+
}
|
|
212
|
+
interface RequestsSummary {
|
|
213
|
+
/** Requests currently held in the ring buffer. */
|
|
214
|
+
count: number;
|
|
215
|
+
errors: number;
|
|
216
|
+
/** `errors / count` in 0..1 (5xx only). */
|
|
217
|
+
errorRate: number;
|
|
218
|
+
avgMs: number;
|
|
219
|
+
p50Ms: number;
|
|
220
|
+
p95Ms: number;
|
|
221
|
+
p99Ms: number;
|
|
222
|
+
byStatus: {
|
|
223
|
+
'2xx': number;
|
|
224
|
+
'3xx': number;
|
|
225
|
+
'4xx': number;
|
|
226
|
+
'5xx': number;
|
|
227
|
+
};
|
|
228
|
+
/** Busiest/slowest routes, slowest p95 first (at most 8). */
|
|
229
|
+
routes: RouteStat[];
|
|
157
230
|
}
|
|
158
231
|
interface RequestsData {
|
|
159
232
|
total: number;
|
|
160
233
|
entries: RequestEntry[];
|
|
234
|
+
summary: RequestsSummary;
|
|
161
235
|
}
|
|
162
236
|
interface EnvEntry {
|
|
163
237
|
key: string;
|
|
@@ -180,6 +254,8 @@ interface LogEntry {
|
|
|
180
254
|
level: LogLevel;
|
|
181
255
|
message: string;
|
|
182
256
|
timestamp: number;
|
|
257
|
+
/** Id of the app request being handled when this was logged. */
|
|
258
|
+
requestId?: number;
|
|
183
259
|
}
|
|
184
260
|
interface LogsData {
|
|
185
261
|
entries: LogEntry[];
|
|
@@ -201,6 +277,53 @@ interface OutgoingRequestEntry {
|
|
|
201
277
|
durationMs: number;
|
|
202
278
|
timestampMs: number;
|
|
203
279
|
error?: string;
|
|
280
|
+
/** Id of the app request that triggered this call. */
|
|
281
|
+
requestId?: number;
|
|
282
|
+
}
|
|
283
|
+
interface QueryEntry {
|
|
284
|
+
id: number;
|
|
285
|
+
/** Driver or ORM the query came from, e.g. `pg`, `mysql2`, `prisma`. */
|
|
286
|
+
system: string;
|
|
287
|
+
/** Statement text. Parameter values are never recorded. */
|
|
288
|
+
sql: string;
|
|
289
|
+
durationMs: number;
|
|
290
|
+
timestampMs: number;
|
|
291
|
+
rowCount?: number;
|
|
292
|
+
error?: string;
|
|
293
|
+
/** Id of the app request that issued the query. */
|
|
294
|
+
requestId?: number;
|
|
295
|
+
/** At or above the configured `slowQueryMs`. */
|
|
296
|
+
slow?: boolean;
|
|
297
|
+
/** Same statement repeated within one request (N+1 suspect). */
|
|
298
|
+
nPlusOne?: boolean;
|
|
299
|
+
repeats?: number;
|
|
300
|
+
}
|
|
301
|
+
interface QueriesData {
|
|
302
|
+
total: number;
|
|
303
|
+
failed: number;
|
|
304
|
+
slow: number;
|
|
305
|
+
nPlusOneGroups: number;
|
|
306
|
+
slowQueryMs: number;
|
|
307
|
+
entries: QueryEntry[];
|
|
308
|
+
}
|
|
309
|
+
type ErrorSource = 'request' | 'uncaught' | 'rejection' | 'manual';
|
|
310
|
+
/** Errors with the same fingerprint (type, message shape, top frames) grouped together. */
|
|
311
|
+
interface ErrorGroup {
|
|
312
|
+
id: string;
|
|
313
|
+
name: string;
|
|
314
|
+
message: string;
|
|
315
|
+
stack: string;
|
|
316
|
+
source: ErrorSource;
|
|
317
|
+
count: number;
|
|
318
|
+
firstSeenMs: number;
|
|
319
|
+
lastSeenMs: number;
|
|
320
|
+
lastRequestId?: number;
|
|
321
|
+
lastRoute?: string;
|
|
322
|
+
lastStatus?: number;
|
|
323
|
+
}
|
|
324
|
+
interface ErrorsData {
|
|
325
|
+
total: number;
|
|
326
|
+
groups: ErrorGroup[];
|
|
204
327
|
}
|
|
205
328
|
interface OutgoingData {
|
|
206
329
|
total: number;
|
|
@@ -236,7 +359,7 @@ interface ConfigData {
|
|
|
236
359
|
enabled: boolean;
|
|
237
360
|
pattern: string;
|
|
238
361
|
};
|
|
239
|
-
|
|
362
|
+
locked: boolean;
|
|
240
363
|
/** Plugin panel ids and titles, in registration order. */
|
|
241
364
|
plugins: Array<{
|
|
242
365
|
id: PanelId;
|
|
@@ -288,9 +411,13 @@ interface ActivationDecision {
|
|
|
288
411
|
declare function resolveActivation(env: Record<string, string | undefined>): ActivationDecision;
|
|
289
412
|
/** True when the socket address is a loopback address. */
|
|
290
413
|
declare function isLoopbackAddress(address: string | undefined): boolean;
|
|
414
|
+
/** True when `entry` is an exact IP or an IPv4/IPv6 CIDR that {@link matchesAddress} understands. */
|
|
415
|
+
declare function isValidAddressEntry(entry: string): boolean;
|
|
291
416
|
/**
|
|
292
|
-
* True when `address` matches one of `allowed`, each an exact IP or
|
|
293
|
-
*
|
|
417
|
+
* True when `address` matches one of `allowed`, each an exact IP or a CIDR
|
|
418
|
+
* (e.g. `172.17.0.0/16`, the default Docker bridge network, or `fd00::/8`).
|
|
419
|
+
* IPv4-mapped IPv6 addresses compare as their IPv4 form; IPv6 literals compare
|
|
420
|
+
* by value, so `::1` equals `0:0:0:0:0:0:0:1`.
|
|
294
421
|
*/
|
|
295
422
|
declare function matchesAddress(address: string | undefined, allowed: readonly string[]): boolean;
|
|
296
423
|
/** Extracts the lower-cased hostname from a `Host` header value (no port). */
|
|
@@ -363,6 +490,12 @@ declare class ProviderRegistry {
|
|
|
363
490
|
all(): NodeUIProvider[];
|
|
364
491
|
}
|
|
365
492
|
|
|
493
|
+
/**
|
|
494
|
+
* Directory holding the prebuilt console (`index.html` and assets). It ships
|
|
495
|
+
* inside this package, so the UI always matches the API it talks to. Use it to
|
|
496
|
+
* serve the console from your own host or gateway.
|
|
497
|
+
*/
|
|
498
|
+
declare function uiAssetsDir(): string;
|
|
366
499
|
interface StaticAsset {
|
|
367
500
|
content: Readable;
|
|
368
501
|
contentType: string;
|
|
@@ -495,6 +628,89 @@ declare class HealthProvider implements NodeUIProvider<HealthData> {
|
|
|
495
628
|
}>;
|
|
496
629
|
}
|
|
497
630
|
|
|
631
|
+
/** Same normalized statement this many times within one request is flagged as N+1. */
|
|
632
|
+
declare const N_PLUS_ONE_THRESHOLD = 5;
|
|
633
|
+
type Recorder$1 = (entry: Omit<QueryEntry, 'id'>) => void;
|
|
634
|
+
/** Loads an optional driver from the host app's dependency tree. */
|
|
635
|
+
type DriverLoader = (name: string) => unknown;
|
|
636
|
+
/** Collapses literals so repeated statements compare equal. */
|
|
637
|
+
declare function normalizeSql(sql: string): string;
|
|
638
|
+
/**
|
|
639
|
+
* Refcounted instrumentation of installed database drivers (`pg`, `mysql2`),
|
|
640
|
+
* resolved from the host app's dependencies. Drivers that are not installed are
|
|
641
|
+
* skipped. The last release restores the original methods.
|
|
642
|
+
*/
|
|
643
|
+
declare function interceptQueries(record: Recorder$1, load?: DriverLoader): () => void;
|
|
644
|
+
interface QueriesProviderOptions {
|
|
645
|
+
size: number;
|
|
646
|
+
slowQueryMs: number;
|
|
647
|
+
loader?: DriverLoader;
|
|
648
|
+
}
|
|
649
|
+
/** Recent database queries with slow-query and N+1 flags. */
|
|
650
|
+
declare class QueriesProvider implements NodeUIProvider<QueriesData> {
|
|
651
|
+
private readonly options;
|
|
652
|
+
readonly id: "queries";
|
|
653
|
+
private buffer;
|
|
654
|
+
private nextId;
|
|
655
|
+
private release;
|
|
656
|
+
private failed;
|
|
657
|
+
/** Called with every newly recorded entry (persistence hook). */
|
|
658
|
+
onRecord?: (entry: QueryEntry) => void;
|
|
659
|
+
constructor(options: QueriesProviderOptions);
|
|
660
|
+
start(): void;
|
|
661
|
+
stop(): void;
|
|
662
|
+
record(entry: Omit<QueryEntry, 'id'>): void;
|
|
663
|
+
/** Re-inserts journaled entries without re-emitting them. */
|
|
664
|
+
restore(entries: readonly QueryEntry[]): void;
|
|
665
|
+
get(): {
|
|
666
|
+
ok: true;
|
|
667
|
+
data: QueriesData;
|
|
668
|
+
};
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
/** A single occurrence in a serializable form (for the persistence journal). */
|
|
672
|
+
interface ErrorEvent {
|
|
673
|
+
name: string;
|
|
674
|
+
message: string;
|
|
675
|
+
stack: string;
|
|
676
|
+
source: ErrorSource;
|
|
677
|
+
at: number;
|
|
678
|
+
requestId?: number;
|
|
679
|
+
route?: string;
|
|
680
|
+
status?: number;
|
|
681
|
+
}
|
|
682
|
+
/** Groups equal failures: same type, same message shape (numbers and ids collapsed), same origin. */
|
|
683
|
+
declare function fingerprintError(name: string, message: string, stack: string): string;
|
|
684
|
+
/**
|
|
685
|
+
* Groups errors by fingerprint with counts. Process-level failures are observed
|
|
686
|
+
* with `uncaughtExceptionMonitor`, which never changes Node's crash behaviour
|
|
687
|
+
* (unlike an `uncaughtException` or `unhandledRejection` listener, which would
|
|
688
|
+
* suppress the default exit).
|
|
689
|
+
*/
|
|
690
|
+
declare class ErrorsProvider implements NodeUIProvider<ErrorsData> {
|
|
691
|
+
readonly id: "errors";
|
|
692
|
+
private groups;
|
|
693
|
+
private total;
|
|
694
|
+
private listener;
|
|
695
|
+
/** Called with every newly recorded occurrence (persistence hook). */
|
|
696
|
+
onRecord?: (event: ErrorEvent) => void;
|
|
697
|
+
/** Starts observing process-level failures. Idempotent. */
|
|
698
|
+
attach(): void;
|
|
699
|
+
detach(): void;
|
|
700
|
+
record(error: unknown, source: ErrorSource, context?: {
|
|
701
|
+
requestId?: number;
|
|
702
|
+
route?: string;
|
|
703
|
+
status?: number;
|
|
704
|
+
}): void;
|
|
705
|
+
/** Re-applies journaled occurrences without re-emitting them. */
|
|
706
|
+
restore(events: readonly ErrorEvent[]): void;
|
|
707
|
+
private apply;
|
|
708
|
+
get(): {
|
|
709
|
+
ok: true;
|
|
710
|
+
data: ErrorsData;
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
|
|
498
714
|
type Recorder = (entry: Omit<OutgoingRequestEntry, 'id'>) => void;
|
|
499
715
|
/**
|
|
500
716
|
* Refcounted instrumentation of outgoing HTTP calls made via `http`,
|
|
@@ -509,10 +725,14 @@ declare class OutgoingProvider implements NodeUIProvider<OutgoingData> {
|
|
|
509
725
|
private nextId;
|
|
510
726
|
private failed;
|
|
511
727
|
private release;
|
|
728
|
+
/** Called with every newly recorded entry (persistence hook). */
|
|
729
|
+
onRecord?: (entry: OutgoingRequestEntry) => void;
|
|
512
730
|
constructor(size: number);
|
|
513
731
|
start(): void;
|
|
514
732
|
stop(): void;
|
|
515
733
|
record(entry: Omit<OutgoingRequestEntry, 'id'>): void;
|
|
734
|
+
/** Re-inserts journaled entries without re-emitting them. */
|
|
735
|
+
restore(entries: readonly OutgoingRequestEntry[]): void;
|
|
516
736
|
get(): {
|
|
517
737
|
ok: true;
|
|
518
738
|
data: OutgoingData;
|
|
@@ -534,13 +754,20 @@ declare class HeapSnapshotProvider implements NodeUIProvider<HeapSnapshotPanelDa
|
|
|
534
754
|
takeSnapshot(ctx: ProviderContext): Promise<ProviderResult<HeapSnapshotData>>;
|
|
535
755
|
}
|
|
536
756
|
|
|
757
|
+
declare function summarizeRequests(entries: readonly RequestEntry[]): RequestsSummary;
|
|
537
758
|
/** Fixed-size ring buffer of recent HTTP requests, recorded via middleware hook. */
|
|
538
759
|
declare class RequestsProvider implements NodeUIProvider<RequestsData> {
|
|
539
760
|
readonly id: "requests";
|
|
540
761
|
private buffer;
|
|
541
762
|
private nextId;
|
|
763
|
+
/** Called with every newly recorded entry (persistence hook). */
|
|
764
|
+
onRecord?: (entry: RequestEntry) => void;
|
|
542
765
|
constructor(size: number);
|
|
543
|
-
|
|
766
|
+
/** Reserves an id up front so in-flight work can be attributed to the request. */
|
|
767
|
+
reserveId(): number;
|
|
768
|
+
record(entry: Omit<RequestEntry, 'id'>, id?: number): void;
|
|
769
|
+
/** Re-inserts journaled entries without re-emitting them. */
|
|
770
|
+
restore(entries: readonly RequestEntry[]): void;
|
|
544
771
|
get length(): number;
|
|
545
772
|
get(): {
|
|
546
773
|
ok: true;
|
|
@@ -641,6 +868,21 @@ declare class LogsProvider implements NodeUIProvider<LogsData> {
|
|
|
641
868
|
};
|
|
642
869
|
}
|
|
643
870
|
|
|
871
|
+
declare const DEFAULT_REQUEST_DETAIL: Required<RequestDetailOptions>;
|
|
872
|
+
|
|
873
|
+
/** Id of the app request the current async call chain belongs to, if any. */
|
|
874
|
+
declare function currentRequestId(): number | undefined;
|
|
875
|
+
/**
|
|
876
|
+
* Runs `fn` inside the request's context when it was recorded by the NodeUI
|
|
877
|
+
* middleware (otherwise just calls `fn`). For adapters that own the `next` call.
|
|
878
|
+
*/
|
|
879
|
+
declare function runInRequestContext<T>(req: IncomingMessage, fn: () => T): T;
|
|
880
|
+
/**
|
|
881
|
+
* Attributes the rest of the current async chain to the request. For adapters
|
|
882
|
+
* (Fastify) whose hooks cannot wrap the downstream handler in `run`.
|
|
883
|
+
*/
|
|
884
|
+
declare function enterRequestContext(req: IncomingMessage): void;
|
|
885
|
+
|
|
644
886
|
interface SseStream {
|
|
645
887
|
send(payload: unknown): void;
|
|
646
888
|
heartbeat(): void;
|
|
@@ -673,6 +915,38 @@ interface NodeUIOptions {
|
|
|
673
915
|
env?: Record<string, string | undefined>;
|
|
674
916
|
/** Whether secret masking applies to panel output. Default true. */
|
|
675
917
|
maskSecrets?: boolean;
|
|
918
|
+
/**
|
|
919
|
+
* Extra detail recorded per request: query, headers (credentials always
|
|
920
|
+
* redacted) and, opt-in, textual bodies (or `NODEUI_CAPTURE_BODIES=true`).
|
|
921
|
+
* `false` records none of it.
|
|
922
|
+
*/
|
|
923
|
+
captureRequestDetail?: boolean | RequestDetailOptions;
|
|
924
|
+
/**
|
|
925
|
+
* Keep recent requests, outgoing calls, queries and errors in an NDJSON
|
|
926
|
+
* journal so they survive a restart (or `NODEUI_PERSIST_FILE`). Off by
|
|
927
|
+
* default. The file is private (0600), masked, and rotated at `maxBytes`
|
|
928
|
+
* (default 5 MiB). It holds whatever the console records, so keep it out of
|
|
929
|
+
* version control.
|
|
930
|
+
*/
|
|
931
|
+
persist?: string | {
|
|
932
|
+
file: string;
|
|
933
|
+
maxBytes?: number;
|
|
934
|
+
};
|
|
935
|
+
/**
|
|
936
|
+
* When the outgoing-call, query and log instrumentation runs. `'always'`
|
|
937
|
+
* (default) records from startup, so you can open the console after a problem
|
|
938
|
+
* and still see what led to it. `'lazy'` installs the hooks only while a panel
|
|
939
|
+
* is open and removes them after `inactivityTimeoutMs`, for zero cost when
|
|
940
|
+
* nobody is looking (or `NODEUI_CAPTURE=lazy`). Buffers are bounded either way.
|
|
941
|
+
*/
|
|
942
|
+
capture?: 'always' | 'lazy';
|
|
943
|
+
/**
|
|
944
|
+
* Export requests, outgoing calls and queries as OTLP/HTTP JSON spans to a
|
|
945
|
+
* collector (or `NODEUI_OTLP_ENDPOINT`). Off by default. Enabling it keeps
|
|
946
|
+
* outgoing and query instrumentation running and sends (masked) telemetry to
|
|
947
|
+
* the given endpoint, so point it at a local collector.
|
|
948
|
+
*/
|
|
949
|
+
otlp?: string | OtlpOptions;
|
|
676
950
|
/** Idle time after which background samplers stop. Default 60000. */
|
|
677
951
|
inactivityTimeoutMs?: number;
|
|
678
952
|
/** TTL for mutation confirmation nonces. Default 60000. */
|
|
@@ -703,6 +977,10 @@ interface NodeUIOptions {
|
|
|
703
977
|
healthChecks?: Record<string, HealthCheck>;
|
|
704
978
|
/** Max recorded outgoing HTTP calls. Default 200. */
|
|
705
979
|
outgoingLogSize?: number;
|
|
980
|
+
/** Max recorded database queries. Default 200. */
|
|
981
|
+
queryLogSize?: number;
|
|
982
|
+
/** Queries at or above this duration are flagged slow. Default 100 ms. */
|
|
983
|
+
slowQueryMs?: number;
|
|
706
984
|
}
|
|
707
985
|
interface NodeUIServer {
|
|
708
986
|
readonly config: NodeUIConfig;
|
|
@@ -726,6 +1004,35 @@ interface NodeUIServer {
|
|
|
726
1004
|
level: LogLevel;
|
|
727
1005
|
message: string;
|
|
728
1006
|
}): void;
|
|
1007
|
+
/**
|
|
1008
|
+
* Records a database query from an ORM or driver hook that NodeUI does not
|
|
1009
|
+
* patch itself (Sequelize `logging`, TypeORM logger, ...). Parameters are not recorded.
|
|
1010
|
+
*/
|
|
1011
|
+
recordQuery(query: {
|
|
1012
|
+
system: string;
|
|
1013
|
+
sql: string;
|
|
1014
|
+
durationMs: number;
|
|
1015
|
+
rowCount?: number;
|
|
1016
|
+
error?: string;
|
|
1017
|
+
}): void;
|
|
1018
|
+
/**
|
|
1019
|
+
* Subscribes to a Prisma client's query events. Create the client with
|
|
1020
|
+
* `log: [{ emit: 'event', level: 'query' }]`.
|
|
1021
|
+
*/
|
|
1022
|
+
trackPrisma(client: {
|
|
1023
|
+
$on(event: 'query', cb: (e: {
|
|
1024
|
+
query: string;
|
|
1025
|
+
duration: number | bigint;
|
|
1026
|
+
}) => void): void;
|
|
1027
|
+
}): void;
|
|
1028
|
+
/**
|
|
1029
|
+
* Records a handled error (e.g. from a framework error hook) so it appears in
|
|
1030
|
+
* the Errors panel, attributed to the current request when there is one.
|
|
1031
|
+
*/
|
|
1032
|
+
recordError(error: unknown, context?: {
|
|
1033
|
+
route?: string;
|
|
1034
|
+
status?: number;
|
|
1035
|
+
}): void;
|
|
729
1036
|
/** Stops all timers and background samplers. */
|
|
730
1037
|
shutdown(): void;
|
|
731
1038
|
}
|
|
@@ -737,4 +1044,4 @@ type NodeUIMiddleware = (req: IncomingMessage, res: ServerResponse, next: () =>
|
|
|
737
1044
|
declare function serializeEnvelope<T>(envelope: ApiEnvelope<T>, mask?: boolean): string;
|
|
738
1045
|
declare function createNodeUI(options?: NodeUIOptions): NodeUIServer;
|
|
739
1046
|
|
|
740
|
-
export { AUTH_COOKIE, type ActivationDecision, type ApiEnvelope, type BuiltInPanelId, 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 GuardOptions, type GuardResult, type HealthCheck, type HealthCheckResult, 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 OutgoingData, OutgoingProvider, type OutgoingRequestEntry, 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, createGuard, createNodeUI, extractRoutes, hostnameFromHostHeader, interceptConsole, interceptOutgoing, isLoopbackAddress, isLoopbackHostname, maskSecretText, maskSecrets, matchesAddress, resolveActivation, resolveStaticAsset, serializeEnvelope, startSse };
|
|
1047
|
+
export { AUTH_COOKIE, type ActivationDecision, type ApiEnvelope, type BuiltInPanelId, type ConfigData, type ConfirmIssued, ConfirmationStore, type CpuClock, type CpuData, CpuProvider, type CpuUsageSnapshot, DEFAULT_LOG_SIZE, DEFAULT_REQUEST_DETAIL, type EnvData, type EnvEntry, EnvProvider, type ErrorGroup, type ErrorSource, type ErrorsData, ErrorsProvider, type EventLoopClock, EventLoopLagProvider, type EventLoopSample, type GuardOptions, type GuardResult, type HealthCheck, type HealthCheckResult, type HealthData, HealthProvider, type HeapSnapshotData, type HeapSnapshotPanelData, HeapSnapshotProvider, type LogEntry, type LogLevel, type LogsData, LogsProvider, type MemoryData, MemoryProvider, type MetricsBucket, type MetricsData, MetricsProvider, N_PLUS_ONE_THRESHOLD, type NodeUIConfig, type NodeUIMiddleware, type NodeUIOptions, type NodeUIProvider, type NodeUIServer, type OutgoingData, OutgoingProvider, type OutgoingRequestEntry, type PanelId, type ProviderContext, type ProviderError, ProviderRegistry, type ProviderResult, type QueriesData, QueriesProvider, type QueryEntry, type RequestDetail, type RequestDetailOptions, type RequestEntry, type RequestsData, RequestsProvider, type RequestsSummary, RingBuffer, type RouteEntry, type RouteStat, type RoutesData, RoutesProvider, SECRET_KEY_PATTERN, SECRET_MASKED, Sampler, type SamplerOptions, type SseStream, type StartupData, type StartupMark, StartupTracker, type StaticAsset, createGuard, createNodeUI, currentRequestId, enterRequestContext, extractRoutes, fingerprintError, hostnameFromHostHeader, interceptConsole, interceptOutgoing, interceptQueries, isLoopbackAddress, isLoopbackHostname, isValidAddressEntry, maskSecretText, maskSecrets, matchesAddress, normalizeSql, resolveActivation, resolveStaticAsset, runInRequestContext, serializeEnvelope, startSse, summarizeRequests, uiAssetsDir };
|