@vipin733/nodescope 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/LICENSE +21 -0
- package/README.md +412 -0
- package/dist/chunk-6H665NNC.js +198 -0
- package/dist/chunk-6KBKW63X.js +145 -0
- package/dist/chunk-BOBKU5LG.js +163 -0
- package/dist/chunk-OF6NKXP5.js +44 -0
- package/dist/chunk-V5BR4MSS.js +195 -0
- package/dist/index.cjs +2926 -0
- package/dist/index.d.cts +928 -0
- package/dist/index.d.ts +928 -0
- package/dist/index.js +2092 -0
- package/dist/memory-5GF7O2HJ.js +7 -0
- package/dist/mysql-KNBA3N7P.js +7 -0
- package/dist/postgresql-XD7N5SFI.js +7 -0
- package/dist/sqlite-DMOIPBIO.js +7 -0
- package/package.json +108 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,928 @@
|
|
|
1
|
+
import * as http from 'http';
|
|
2
|
+
import { RequestHandler } from 'express';
|
|
3
|
+
import { Hono, MiddlewareHandler } from 'hono';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Entry types that NodeScope can capture and display
|
|
7
|
+
*/
|
|
8
|
+
type EntryType = 'request' | 'query' | 'cache' | 'log' | 'exception' | 'http_client' | 'event' | 'job' | 'schedule' | 'dump';
|
|
9
|
+
/**
|
|
10
|
+
* Log levels for the log watcher
|
|
11
|
+
*/
|
|
12
|
+
type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
13
|
+
/**
|
|
14
|
+
* Cache operations
|
|
15
|
+
*/
|
|
16
|
+
type CacheOperation = 'get' | 'set' | 'delete' | 'hit' | 'miss' | 'flush';
|
|
17
|
+
/**
|
|
18
|
+
* Job status
|
|
19
|
+
*/
|
|
20
|
+
type JobStatus = 'pending' | 'processing' | 'completed' | 'failed';
|
|
21
|
+
/**
|
|
22
|
+
* HTTP methods
|
|
23
|
+
*/
|
|
24
|
+
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS';
|
|
25
|
+
/**
|
|
26
|
+
* Base entry that all captured data extends
|
|
27
|
+
*/
|
|
28
|
+
interface Entry {
|
|
29
|
+
/** Unique identifier for this entry */
|
|
30
|
+
id: string;
|
|
31
|
+
/** Batch ID to group related entries (e.g., all entries from one request) */
|
|
32
|
+
batchId: string;
|
|
33
|
+
/** Type of entry */
|
|
34
|
+
type: EntryType;
|
|
35
|
+
/** Entry-specific content */
|
|
36
|
+
content: Record<string, unknown>;
|
|
37
|
+
/** Searchable tags */
|
|
38
|
+
tags: string[];
|
|
39
|
+
/** When this entry was created */
|
|
40
|
+
createdAt: Date;
|
|
41
|
+
/** Duration in milliseconds (if applicable) */
|
|
42
|
+
duration?: number;
|
|
43
|
+
/** Memory usage in bytes (if applicable) */
|
|
44
|
+
memoryUsage?: number;
|
|
45
|
+
}
|
|
46
|
+
interface RequestEntryContent {
|
|
47
|
+
method: HttpMethod;
|
|
48
|
+
url: string;
|
|
49
|
+
path: string;
|
|
50
|
+
query: Record<string, string | string[]>;
|
|
51
|
+
headers: Record<string, string>;
|
|
52
|
+
body?: unknown;
|
|
53
|
+
ip?: string;
|
|
54
|
+
userAgent?: string;
|
|
55
|
+
session?: Record<string, unknown>;
|
|
56
|
+
response: {
|
|
57
|
+
status: number;
|
|
58
|
+
headers: Record<string, string>;
|
|
59
|
+
body?: unknown;
|
|
60
|
+
size?: number;
|
|
61
|
+
};
|
|
62
|
+
middleware?: string[];
|
|
63
|
+
controllerAction?: string;
|
|
64
|
+
}
|
|
65
|
+
interface QueryEntryContent {
|
|
66
|
+
sql: string;
|
|
67
|
+
bindings: unknown[];
|
|
68
|
+
connection: string;
|
|
69
|
+
database?: string;
|
|
70
|
+
slow: boolean;
|
|
71
|
+
rowCount?: number;
|
|
72
|
+
}
|
|
73
|
+
interface CacheEntryContent {
|
|
74
|
+
key: string;
|
|
75
|
+
value?: unknown;
|
|
76
|
+
operation: CacheOperation;
|
|
77
|
+
driver: string;
|
|
78
|
+
ttl?: number;
|
|
79
|
+
tags?: string[];
|
|
80
|
+
}
|
|
81
|
+
interface LogEntryContent {
|
|
82
|
+
level: LogLevel;
|
|
83
|
+
message: string;
|
|
84
|
+
context?: Record<string, unknown>;
|
|
85
|
+
channel?: string;
|
|
86
|
+
}
|
|
87
|
+
interface ExceptionEntryContent {
|
|
88
|
+
class: string;
|
|
89
|
+
message: string;
|
|
90
|
+
stack: string;
|
|
91
|
+
file?: string;
|
|
92
|
+
line?: number;
|
|
93
|
+
context?: Record<string, unknown>;
|
|
94
|
+
previous?: ExceptionEntryContent;
|
|
95
|
+
}
|
|
96
|
+
interface HttpClientEntryContent {
|
|
97
|
+
method: HttpMethod;
|
|
98
|
+
url: string;
|
|
99
|
+
headers: Record<string, string>;
|
|
100
|
+
body?: unknown;
|
|
101
|
+
response: {
|
|
102
|
+
status: number;
|
|
103
|
+
headers: Record<string, string>;
|
|
104
|
+
body?: unknown;
|
|
105
|
+
size?: number;
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
interface EventEntryContent {
|
|
109
|
+
name: string;
|
|
110
|
+
payload: unknown;
|
|
111
|
+
listeners: string[];
|
|
112
|
+
broadcast?: {
|
|
113
|
+
channel: string;
|
|
114
|
+
event: string;
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
interface JobEntryContent {
|
|
118
|
+
name: string;
|
|
119
|
+
queue: string;
|
|
120
|
+
data: unknown;
|
|
121
|
+
status: JobStatus;
|
|
122
|
+
attempts: number;
|
|
123
|
+
maxAttempts?: number;
|
|
124
|
+
error?: string;
|
|
125
|
+
}
|
|
126
|
+
interface ScheduleEntryContent {
|
|
127
|
+
command: string;
|
|
128
|
+
description?: string;
|
|
129
|
+
expression: string;
|
|
130
|
+
output?: string;
|
|
131
|
+
exitCode?: number;
|
|
132
|
+
}
|
|
133
|
+
interface DumpEntryContent {
|
|
134
|
+
dump: unknown;
|
|
135
|
+
file?: string;
|
|
136
|
+
line?: number;
|
|
137
|
+
}
|
|
138
|
+
type StorageDriver = 'memory' | 'sqlite' | 'postgresql' | 'mysql';
|
|
139
|
+
interface WatcherConfig {
|
|
140
|
+
request?: boolean | RequestWatcherOptions;
|
|
141
|
+
query?: boolean | QueryWatcherOptions;
|
|
142
|
+
cache?: boolean | CacheWatcherOptions;
|
|
143
|
+
log?: boolean | LogWatcherOptions;
|
|
144
|
+
exception?: boolean | ExceptionWatcherOptions;
|
|
145
|
+
httpClient?: boolean | HttpClientWatcherOptions;
|
|
146
|
+
event?: boolean | EventWatcherOptions;
|
|
147
|
+
job?: boolean | JobWatcherOptions;
|
|
148
|
+
schedule?: boolean | ScheduleWatcherOptions;
|
|
149
|
+
dump?: boolean;
|
|
150
|
+
}
|
|
151
|
+
interface RequestWatcherOptions {
|
|
152
|
+
enabled?: boolean;
|
|
153
|
+
/** Maximum response body size to capture (in KB) */
|
|
154
|
+
sizeLimit?: number;
|
|
155
|
+
/** Paths to ignore */
|
|
156
|
+
ignorePaths?: string[];
|
|
157
|
+
/** Whether to capture request body */
|
|
158
|
+
captureBody?: boolean;
|
|
159
|
+
/** Whether to capture response body */
|
|
160
|
+
captureResponse?: boolean;
|
|
161
|
+
/** Headers to hide from capture */
|
|
162
|
+
hideHeaders?: string[];
|
|
163
|
+
}
|
|
164
|
+
interface QueryWatcherOptions {
|
|
165
|
+
enabled?: boolean;
|
|
166
|
+
/** Threshold in ms to mark a query as slow */
|
|
167
|
+
slowThreshold?: number;
|
|
168
|
+
}
|
|
169
|
+
interface CacheWatcherOptions {
|
|
170
|
+
enabled?: boolean;
|
|
171
|
+
}
|
|
172
|
+
interface LogWatcherOptions {
|
|
173
|
+
enabled?: boolean;
|
|
174
|
+
/** Minimum log level to capture */
|
|
175
|
+
level?: LogLevel;
|
|
176
|
+
}
|
|
177
|
+
interface ExceptionWatcherOptions {
|
|
178
|
+
enabled?: boolean;
|
|
179
|
+
}
|
|
180
|
+
interface HttpClientWatcherOptions {
|
|
181
|
+
enabled?: boolean;
|
|
182
|
+
/** Maximum response body size to capture (in KB) */
|
|
183
|
+
sizeLimit?: number;
|
|
184
|
+
}
|
|
185
|
+
interface EventWatcherOptions {
|
|
186
|
+
enabled?: boolean;
|
|
187
|
+
/** Events to ignore */
|
|
188
|
+
ignore?: string[];
|
|
189
|
+
}
|
|
190
|
+
interface JobWatcherOptions {
|
|
191
|
+
enabled?: boolean;
|
|
192
|
+
}
|
|
193
|
+
interface ScheduleWatcherOptions {
|
|
194
|
+
enabled?: boolean;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Main NodeScope configuration
|
|
198
|
+
*/
|
|
199
|
+
interface NodeScopeConfig {
|
|
200
|
+
/** Enable or disable NodeScope */
|
|
201
|
+
enabled?: boolean;
|
|
202
|
+
/** Storage driver to use */
|
|
203
|
+
storage?: StorageDriver;
|
|
204
|
+
/** Database connection URL (for sqlite, postgresql, mysql) */
|
|
205
|
+
databaseUrl?: string;
|
|
206
|
+
/** Path where the dashboard will be served */
|
|
207
|
+
dashboardPath?: string;
|
|
208
|
+
/** Watcher configurations */
|
|
209
|
+
watchers?: WatcherConfig;
|
|
210
|
+
/** Enable real-time WebSocket updates */
|
|
211
|
+
realtime?: boolean;
|
|
212
|
+
/** Prune entries older than this many hours */
|
|
213
|
+
pruneAfterHours?: number;
|
|
214
|
+
/** Custom authorization check for dashboard access */
|
|
215
|
+
authorization?: (req: unknown) => boolean | Promise<boolean>;
|
|
216
|
+
/** Callback to filter entries before recording */
|
|
217
|
+
filter?: (entry: Entry) => boolean;
|
|
218
|
+
/** Callback to add custom tags to entries */
|
|
219
|
+
tag?: (entry: Entry) => string[];
|
|
220
|
+
}
|
|
221
|
+
interface ListOptions {
|
|
222
|
+
type?: EntryType;
|
|
223
|
+
batchId?: string;
|
|
224
|
+
tags?: string[];
|
|
225
|
+
search?: string;
|
|
226
|
+
before?: Date;
|
|
227
|
+
after?: Date;
|
|
228
|
+
limit?: number;
|
|
229
|
+
offset?: number;
|
|
230
|
+
}
|
|
231
|
+
interface PaginatedResult<T> {
|
|
232
|
+
data: T[];
|
|
233
|
+
total: number;
|
|
234
|
+
limit: number;
|
|
235
|
+
offset: number;
|
|
236
|
+
hasMore: boolean;
|
|
237
|
+
}
|
|
238
|
+
interface StorageStats {
|
|
239
|
+
totalEntries: number;
|
|
240
|
+
entriesByType: Record<EntryType, number>;
|
|
241
|
+
oldestEntry?: Date;
|
|
242
|
+
newestEntry?: Date;
|
|
243
|
+
storageSize?: number;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Abstract storage adapter interface.
|
|
248
|
+
* All storage implementations must implement this interface.
|
|
249
|
+
*/
|
|
250
|
+
interface StorageAdapter {
|
|
251
|
+
/** Initialize the storage (create tables, etc.) */
|
|
252
|
+
initialize(): Promise<void>;
|
|
253
|
+
/** Save a single entry */
|
|
254
|
+
save(entry: Entry): Promise<void>;
|
|
255
|
+
/** Save multiple entries in a batch */
|
|
256
|
+
saveBatch(entries: Entry[]): Promise<void>;
|
|
257
|
+
/** Find an entry by ID */
|
|
258
|
+
find(id: string): Promise<Entry | null>;
|
|
259
|
+
/** List entries with filtering and pagination */
|
|
260
|
+
list(options?: ListOptions): Promise<PaginatedResult<Entry>>;
|
|
261
|
+
/** Get entries by batch ID */
|
|
262
|
+
findByBatch(batchId: string): Promise<Entry[]>;
|
|
263
|
+
/** Prune entries older than the given date */
|
|
264
|
+
prune(beforeDate: Date): Promise<number>;
|
|
265
|
+
/** Clear all entries */
|
|
266
|
+
clear(): Promise<void>;
|
|
267
|
+
/** Get storage statistics */
|
|
268
|
+
stats(): Promise<StorageStats>;
|
|
269
|
+
/** Close connections (cleanup) */
|
|
270
|
+
close(): Promise<void>;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Create a storage adapter based on configuration
|
|
274
|
+
*/
|
|
275
|
+
declare function createStorageAdapter(driver: string, options?: {
|
|
276
|
+
databaseUrl?: string;
|
|
277
|
+
}): Promise<StorageAdapter>;
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Base class for all watchers.
|
|
281
|
+
* Provides common functionality for creating entries.
|
|
282
|
+
*/
|
|
283
|
+
declare abstract class BaseWatcher<TContent = unknown> {
|
|
284
|
+
/** The type of entries this watcher creates */
|
|
285
|
+
abstract readonly type: EntryType;
|
|
286
|
+
/** Whether this watcher is enabled */
|
|
287
|
+
enabled: boolean;
|
|
288
|
+
/**
|
|
289
|
+
* Create an entry from captured data
|
|
290
|
+
*/
|
|
291
|
+
protected createEntry(content: TContent, options?: {
|
|
292
|
+
batchId?: string;
|
|
293
|
+
tags?: string[];
|
|
294
|
+
duration?: number;
|
|
295
|
+
memoryUsage?: number;
|
|
296
|
+
}): Entry;
|
|
297
|
+
/**
|
|
298
|
+
* Optional filter to exclude certain entries
|
|
299
|
+
*/
|
|
300
|
+
filter?(entry: Entry): boolean;
|
|
301
|
+
/**
|
|
302
|
+
* Optional callback to add custom tags
|
|
303
|
+
*/
|
|
304
|
+
tag?(entry: Entry): string[];
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Context passed through the request lifecycle
|
|
308
|
+
*/
|
|
309
|
+
interface RequestContext {
|
|
310
|
+
batchId: string;
|
|
311
|
+
startTime: number;
|
|
312
|
+
startMemory?: number;
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Create a new request context
|
|
316
|
+
*/
|
|
317
|
+
declare function createRequestContext(): RequestContext;
|
|
318
|
+
/**
|
|
319
|
+
* Calculate duration from request context
|
|
320
|
+
*/
|
|
321
|
+
declare function getDuration(ctx: RequestContext): number;
|
|
322
|
+
/**
|
|
323
|
+
* Calculate memory delta from request context
|
|
324
|
+
*/
|
|
325
|
+
declare function getMemoryDelta(ctx: RequestContext): number | undefined;
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Request watcher - captures HTTP requests and responses
|
|
329
|
+
*/
|
|
330
|
+
declare class RequestWatcher extends BaseWatcher<RequestEntryContent> {
|
|
331
|
+
readonly type: "request";
|
|
332
|
+
private options;
|
|
333
|
+
constructor(options?: RequestWatcherOptions);
|
|
334
|
+
/**
|
|
335
|
+
* Record a request/response pair
|
|
336
|
+
*/
|
|
337
|
+
record(data: {
|
|
338
|
+
batchId: string;
|
|
339
|
+
startTime: number;
|
|
340
|
+
method: string;
|
|
341
|
+
url: string;
|
|
342
|
+
path: string;
|
|
343
|
+
query: Record<string, string | string[]>;
|
|
344
|
+
headers: Record<string, string>;
|
|
345
|
+
body?: unknown;
|
|
346
|
+
ip?: string;
|
|
347
|
+
userAgent?: string;
|
|
348
|
+
session?: Record<string, unknown>;
|
|
349
|
+
response: {
|
|
350
|
+
status: number;
|
|
351
|
+
headers: Record<string, string>;
|
|
352
|
+
body?: unknown;
|
|
353
|
+
};
|
|
354
|
+
middleware?: string[];
|
|
355
|
+
controllerAction?: string;
|
|
356
|
+
}): Entry | null;
|
|
357
|
+
private filterHeaders;
|
|
358
|
+
private truncateBody;
|
|
359
|
+
private getBodySize;
|
|
360
|
+
private generateTags;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Query watcher - captures database queries
|
|
365
|
+
*/
|
|
366
|
+
declare class QueryWatcher extends BaseWatcher<QueryEntryContent> {
|
|
367
|
+
readonly type: "query";
|
|
368
|
+
private slowThreshold;
|
|
369
|
+
constructor(options?: QueryWatcherOptions);
|
|
370
|
+
/**
|
|
371
|
+
* Record a database query
|
|
372
|
+
*/
|
|
373
|
+
record(data: {
|
|
374
|
+
batchId?: string;
|
|
375
|
+
sql: string;
|
|
376
|
+
bindings?: unknown[];
|
|
377
|
+
connection?: string;
|
|
378
|
+
database?: string;
|
|
379
|
+
duration: number;
|
|
380
|
+
rowCount?: number;
|
|
381
|
+
}): Entry;
|
|
382
|
+
private extractQueryType;
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Wrap a Prisma client to automatically track queries
|
|
386
|
+
*/
|
|
387
|
+
declare function wrapPrisma<T extends object>(prisma: T, watcher: QueryWatcher, batchId?: string): T;
|
|
388
|
+
/**
|
|
389
|
+
* Create a query interceptor for raw database drivers
|
|
390
|
+
*/
|
|
391
|
+
declare function createQueryInterceptor(watcher: QueryWatcher, batchId?: string): {
|
|
392
|
+
/**
|
|
393
|
+
* Wrap a query function to track its execution
|
|
394
|
+
*/
|
|
395
|
+
wrap<TArgs extends unknown[], TResult>(queryFn: (...args: TArgs) => Promise<TResult>, getSql: (...args: TArgs) => string, getBindings?: (...args: TArgs) => unknown[]): (...args: TArgs) => Promise<TResult>;
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Cache watcher - captures cache operations
|
|
400
|
+
*/
|
|
401
|
+
declare class CacheWatcher extends BaseWatcher<CacheEntryContent> {
|
|
402
|
+
readonly type: "cache";
|
|
403
|
+
constructor(options?: CacheWatcherOptions);
|
|
404
|
+
/**
|
|
405
|
+
* Record a cache operation
|
|
406
|
+
*/
|
|
407
|
+
record(data: {
|
|
408
|
+
batchId?: string;
|
|
409
|
+
key: string;
|
|
410
|
+
value?: unknown;
|
|
411
|
+
operation: CacheOperation;
|
|
412
|
+
driver?: string;
|
|
413
|
+
ttl?: number;
|
|
414
|
+
tags?: string[];
|
|
415
|
+
duration?: number;
|
|
416
|
+
}): Entry;
|
|
417
|
+
private truncateValue;
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Create a wrapper around a cache client to track operations
|
|
421
|
+
*/
|
|
422
|
+
declare function createCacheWrapper<T extends object>(cache: T, watcher: CacheWatcher, driver: string, batchId?: string): T;
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Log watcher - captures application logs
|
|
426
|
+
*/
|
|
427
|
+
declare class LogWatcher extends BaseWatcher<LogEntryContent> {
|
|
428
|
+
readonly type: "log";
|
|
429
|
+
private minLevel;
|
|
430
|
+
constructor(options?: LogWatcherOptions);
|
|
431
|
+
/**
|
|
432
|
+
* Record a log entry
|
|
433
|
+
*/
|
|
434
|
+
record(data: {
|
|
435
|
+
batchId?: string;
|
|
436
|
+
level: LogLevel;
|
|
437
|
+
message: string;
|
|
438
|
+
context?: Record<string, unknown>;
|
|
439
|
+
channel?: string;
|
|
440
|
+
}): Entry | null;
|
|
441
|
+
/**
|
|
442
|
+
* Create a logger instance that automatically records to NodeScope
|
|
443
|
+
*/
|
|
444
|
+
createLogger(batchId?: string, channel?: string): {
|
|
445
|
+
debug: (message: string, context?: Record<string, unknown>) => Entry | null;
|
|
446
|
+
info: (message: string, context?: Record<string, unknown>) => Entry | null;
|
|
447
|
+
warn: (message: string, context?: Record<string, unknown>) => Entry | null;
|
|
448
|
+
error: (message: string, context?: Record<string, unknown>) => Entry | null;
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Intercept console methods to capture logs
|
|
453
|
+
*/
|
|
454
|
+
declare function interceptConsole(watcher: LogWatcher, batchIdFn?: () => string | undefined): () => void;
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Exception watcher - captures errors and exceptions
|
|
458
|
+
*/
|
|
459
|
+
declare class ExceptionWatcher extends BaseWatcher<ExceptionEntryContent> {
|
|
460
|
+
readonly type: "exception";
|
|
461
|
+
constructor(options?: ExceptionWatcherOptions);
|
|
462
|
+
/**
|
|
463
|
+
* Record an exception
|
|
464
|
+
*/
|
|
465
|
+
record(data: {
|
|
466
|
+
batchId?: string;
|
|
467
|
+
error: Error;
|
|
468
|
+
context?: Record<string, unknown>;
|
|
469
|
+
}): Entry;
|
|
470
|
+
private errorToContent;
|
|
471
|
+
private extractLocation;
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* Set up global error handlers to capture uncaught exceptions
|
|
475
|
+
*/
|
|
476
|
+
declare function setupGlobalErrorHandlers(watcher: ExceptionWatcher, onEntry: (entry: Entry) => void): () => void;
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* HTTP Client watcher - captures outgoing HTTP requests
|
|
480
|
+
*/
|
|
481
|
+
declare class HttpClientWatcher extends BaseWatcher<HttpClientEntryContent> {
|
|
482
|
+
readonly type: "http_client";
|
|
483
|
+
private sizeLimit;
|
|
484
|
+
constructor(options?: HttpClientWatcherOptions);
|
|
485
|
+
/**
|
|
486
|
+
* Record an outgoing HTTP request
|
|
487
|
+
*/
|
|
488
|
+
record(data: {
|
|
489
|
+
batchId?: string;
|
|
490
|
+
method: string;
|
|
491
|
+
url: string;
|
|
492
|
+
headers: Record<string, string>;
|
|
493
|
+
body?: unknown;
|
|
494
|
+
response: {
|
|
495
|
+
status: number;
|
|
496
|
+
headers: Record<string, string>;
|
|
497
|
+
body?: unknown;
|
|
498
|
+
};
|
|
499
|
+
duration: number;
|
|
500
|
+
}): Entry;
|
|
501
|
+
private sanitizeHeaders;
|
|
502
|
+
private truncateBody;
|
|
503
|
+
private getBodySize;
|
|
504
|
+
}
|
|
505
|
+
/**
|
|
506
|
+
* Wrap the global fetch to track outgoing requests
|
|
507
|
+
*/
|
|
508
|
+
declare function wrapFetch(watcher: HttpClientWatcher, batchIdFn?: () => string | undefined): typeof fetch;
|
|
509
|
+
/**
|
|
510
|
+
* Install fetch wrapper globally
|
|
511
|
+
*/
|
|
512
|
+
declare function interceptFetch(watcher: HttpClientWatcher, batchIdFn?: () => string | undefined): () => void;
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* Event watcher - captures application events
|
|
516
|
+
*/
|
|
517
|
+
declare class EventWatcher extends BaseWatcher<EventEntryContent> {
|
|
518
|
+
readonly type: "event";
|
|
519
|
+
private ignorePatterns;
|
|
520
|
+
constructor(options?: EventWatcherOptions);
|
|
521
|
+
/**
|
|
522
|
+
* Record an event
|
|
523
|
+
*/
|
|
524
|
+
record(data: {
|
|
525
|
+
batchId?: string;
|
|
526
|
+
name: string;
|
|
527
|
+
payload?: unknown;
|
|
528
|
+
listeners?: string[];
|
|
529
|
+
broadcast?: {
|
|
530
|
+
channel: string;
|
|
531
|
+
event: string;
|
|
532
|
+
};
|
|
533
|
+
}): Entry | null;
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* Simple event emitter with NodeScope integration
|
|
537
|
+
*/
|
|
538
|
+
declare class TrackedEventEmitter {
|
|
539
|
+
private listeners;
|
|
540
|
+
private watcher;
|
|
541
|
+
private batchIdFn?;
|
|
542
|
+
constructor(watcher: EventWatcher, batchIdFn?: () => string | undefined);
|
|
543
|
+
on(event: string, handler: Function, handlerName?: string): void;
|
|
544
|
+
off(event: string, handler: Function): void;
|
|
545
|
+
emit(event: string, payload?: unknown): void;
|
|
546
|
+
listenerCount(event: string): number;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/**
|
|
550
|
+
* Job watcher - captures background job processing
|
|
551
|
+
*/
|
|
552
|
+
declare class JobWatcher extends BaseWatcher<JobEntryContent> {
|
|
553
|
+
readonly type: "job";
|
|
554
|
+
constructor(options?: JobWatcherOptions);
|
|
555
|
+
/**
|
|
556
|
+
* Record a job
|
|
557
|
+
*/
|
|
558
|
+
record(data: {
|
|
559
|
+
batchId?: string;
|
|
560
|
+
name: string;
|
|
561
|
+
queue?: string;
|
|
562
|
+
data?: unknown;
|
|
563
|
+
status: JobStatus;
|
|
564
|
+
attempts?: number;
|
|
565
|
+
maxAttempts?: number;
|
|
566
|
+
error?: string;
|
|
567
|
+
duration?: number;
|
|
568
|
+
}): Entry;
|
|
569
|
+
/**
|
|
570
|
+
* Create a job tracker that can be used to track job lifecycle
|
|
571
|
+
*/
|
|
572
|
+
createJobTracker(name: string, options?: {
|
|
573
|
+
batchId?: string;
|
|
574
|
+
queue?: string;
|
|
575
|
+
data?: unknown;
|
|
576
|
+
maxAttempts?: number;
|
|
577
|
+
}): {
|
|
578
|
+
start: () => Entry;
|
|
579
|
+
complete: (duration?: number) => Entry;
|
|
580
|
+
fail: (error: Error | string, duration?: number) => Entry;
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
/**
|
|
584
|
+
* Wrap a job processor function to automatically track execution
|
|
585
|
+
*/
|
|
586
|
+
declare function wrapJobProcessor<TData, TResult>(watcher: JobWatcher, name: string, processor: (data: TData) => Promise<TResult>, options?: {
|
|
587
|
+
queue?: string;
|
|
588
|
+
maxAttempts?: number;
|
|
589
|
+
}): (data: TData) => Promise<TResult>;
|
|
590
|
+
|
|
591
|
+
interface ApiRequest {
|
|
592
|
+
method: string;
|
|
593
|
+
url: string;
|
|
594
|
+
query: Record<string, string | string[] | undefined>;
|
|
595
|
+
body?: unknown;
|
|
596
|
+
}
|
|
597
|
+
interface ApiResponse {
|
|
598
|
+
status: number;
|
|
599
|
+
body: unknown;
|
|
600
|
+
headers?: Record<string, string>;
|
|
601
|
+
}
|
|
602
|
+
/**
|
|
603
|
+
* API handler for the NodeScope dashboard
|
|
604
|
+
*/
|
|
605
|
+
declare class ApiHandler {
|
|
606
|
+
private storage;
|
|
607
|
+
constructor(storage: StorageAdapter);
|
|
608
|
+
/**
|
|
609
|
+
* Handle an API request
|
|
610
|
+
*/
|
|
611
|
+
handle(req: ApiRequest): Promise<ApiResponse>;
|
|
612
|
+
private listEntries;
|
|
613
|
+
private getEntry;
|
|
614
|
+
private getBatch;
|
|
615
|
+
private getStats;
|
|
616
|
+
private clearEntries;
|
|
617
|
+
private pruneEntries;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
interface WebSocketClient {
|
|
621
|
+
send: (data: string) => void;
|
|
622
|
+
readyState: number;
|
|
623
|
+
}
|
|
624
|
+
interface RealTimeServerOptions {
|
|
625
|
+
heartbeatInterval?: number;
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
628
|
+
* WebSocket server for real-time updates
|
|
629
|
+
*/
|
|
630
|
+
declare class RealTimeServer {
|
|
631
|
+
private clients;
|
|
632
|
+
private heartbeatInterval?;
|
|
633
|
+
private readonly heartbeatMs;
|
|
634
|
+
constructor(options?: RealTimeServerOptions);
|
|
635
|
+
/**
|
|
636
|
+
* Handle a new WebSocket connection
|
|
637
|
+
*/
|
|
638
|
+
handleConnection(ws: WebSocketClient): void;
|
|
639
|
+
/**
|
|
640
|
+
* Handle WebSocket disconnection
|
|
641
|
+
*/
|
|
642
|
+
handleDisconnection(ws: WebSocketClient): void;
|
|
643
|
+
/**
|
|
644
|
+
* Broadcast a new entry to all connected clients
|
|
645
|
+
*/
|
|
646
|
+
broadcastEntry(entry: Entry): void;
|
|
647
|
+
/**
|
|
648
|
+
* Broadcast stats update to all clients
|
|
649
|
+
*/
|
|
650
|
+
broadcastStats(stats: Record<string, unknown>): void;
|
|
651
|
+
/**
|
|
652
|
+
* Start heartbeat to keep connections alive
|
|
653
|
+
*/
|
|
654
|
+
startHeartbeat(): void;
|
|
655
|
+
/**
|
|
656
|
+
* Stop heartbeat
|
|
657
|
+
*/
|
|
658
|
+
stopHeartbeat(): void;
|
|
659
|
+
/**
|
|
660
|
+
* Get number of connected clients
|
|
661
|
+
*/
|
|
662
|
+
get clientCount(): number;
|
|
663
|
+
private broadcast;
|
|
664
|
+
private sendTo;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
/**
|
|
668
|
+
* Main NodeScope class
|
|
669
|
+
*/
|
|
670
|
+
declare class NodeScope {
|
|
671
|
+
private config;
|
|
672
|
+
private storage;
|
|
673
|
+
private apiHandler;
|
|
674
|
+
private realTimeServer;
|
|
675
|
+
private initialized;
|
|
676
|
+
private cleanupFns;
|
|
677
|
+
readonly requestWatcher: RequestWatcher;
|
|
678
|
+
readonly queryWatcher: QueryWatcher;
|
|
679
|
+
readonly cacheWatcher: CacheWatcher;
|
|
680
|
+
readonly logWatcher: LogWatcher;
|
|
681
|
+
readonly exceptionWatcher: ExceptionWatcher;
|
|
682
|
+
readonly httpClientWatcher: HttpClientWatcher;
|
|
683
|
+
readonly eventWatcher: EventWatcher;
|
|
684
|
+
readonly jobWatcher: JobWatcher;
|
|
685
|
+
private currentBatchId?;
|
|
686
|
+
constructor(config?: NodeScopeConfig);
|
|
687
|
+
/**
|
|
688
|
+
* Initialize storage and start background processes
|
|
689
|
+
*/
|
|
690
|
+
initialize(): Promise<void>;
|
|
691
|
+
/**
|
|
692
|
+
* Record an entry to storage and broadcast
|
|
693
|
+
*/
|
|
694
|
+
recordEntry(entry: Entry): Promise<void>;
|
|
695
|
+
/**
|
|
696
|
+
* Get the current batch ID
|
|
697
|
+
*/
|
|
698
|
+
get batchId(): string | undefined;
|
|
699
|
+
/**
|
|
700
|
+
* Create a new request context
|
|
701
|
+
*/
|
|
702
|
+
createContext(): {
|
|
703
|
+
batchId: string;
|
|
704
|
+
startTime: number;
|
|
705
|
+
};
|
|
706
|
+
/**
|
|
707
|
+
* Get the dashboard path
|
|
708
|
+
*/
|
|
709
|
+
get dashboardPath(): string;
|
|
710
|
+
/**
|
|
711
|
+
* Get the API handler
|
|
712
|
+
*/
|
|
713
|
+
get api(): ApiHandler;
|
|
714
|
+
/**
|
|
715
|
+
* Get the real-time server
|
|
716
|
+
*/
|
|
717
|
+
get realtime(): RealTimeServer;
|
|
718
|
+
/**
|
|
719
|
+
* Get storage adapter
|
|
720
|
+
*/
|
|
721
|
+
getStorage(): StorageAdapter;
|
|
722
|
+
/**
|
|
723
|
+
* Check if NodeScope is enabled
|
|
724
|
+
*/
|
|
725
|
+
get isEnabled(): boolean;
|
|
726
|
+
/**
|
|
727
|
+
* Check authorization
|
|
728
|
+
*/
|
|
729
|
+
checkAuthorization(req: unknown): Promise<boolean>;
|
|
730
|
+
/**
|
|
731
|
+
* Cleanup and close connections
|
|
732
|
+
*/
|
|
733
|
+
close(): Promise<void>;
|
|
734
|
+
}
|
|
735
|
+
/**
|
|
736
|
+
* Get or create the default NodeScope instance
|
|
737
|
+
*/
|
|
738
|
+
declare function getNodeScope(): NodeScope;
|
|
739
|
+
/**
|
|
740
|
+
* Initialize NodeScope with configuration
|
|
741
|
+
*/
|
|
742
|
+
declare function initNodeScope(config?: NodeScopeConfig): Promise<NodeScope>;
|
|
743
|
+
|
|
744
|
+
interface MemoryStorageOptions {
|
|
745
|
+
/** Maximum number of entries to keep */
|
|
746
|
+
maxEntries?: number;
|
|
747
|
+
}
|
|
748
|
+
/**
|
|
749
|
+
* In-memory storage adapter.
|
|
750
|
+
* Fast but data is lost on restart.
|
|
751
|
+
* Great for development and testing.
|
|
752
|
+
*/
|
|
753
|
+
declare class MemoryStorage implements StorageAdapter {
|
|
754
|
+
private entries;
|
|
755
|
+
private entriesByBatch;
|
|
756
|
+
private entriesByType;
|
|
757
|
+
private readonly maxEntries;
|
|
758
|
+
constructor(options?: MemoryStorageOptions);
|
|
759
|
+
initialize(): Promise<void>;
|
|
760
|
+
save(entry: Entry): Promise<void>;
|
|
761
|
+
saveBatch(entries: Entry[]): Promise<void>;
|
|
762
|
+
find(id: string): Promise<Entry | null>;
|
|
763
|
+
list(options?: ListOptions): Promise<PaginatedResult<Entry>>;
|
|
764
|
+
findByBatch(batchId: string): Promise<Entry[]>;
|
|
765
|
+
prune(beforeDate: Date): Promise<number>;
|
|
766
|
+
clear(): Promise<void>;
|
|
767
|
+
stats(): Promise<StorageStats>;
|
|
768
|
+
close(): Promise<void>;
|
|
769
|
+
private addToIndexes;
|
|
770
|
+
private removeFromIndexes;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
/**
|
|
774
|
+
* SQLite storage adapter.
|
|
775
|
+
* Persistent storage using better-sqlite3.
|
|
776
|
+
* Great for local development with persistence.
|
|
777
|
+
*/
|
|
778
|
+
declare class SQLiteStorage implements StorageAdapter {
|
|
779
|
+
private db;
|
|
780
|
+
private readonly dbPath;
|
|
781
|
+
constructor(dbPath: string);
|
|
782
|
+
initialize(): Promise<void>;
|
|
783
|
+
save(entry: Entry): Promise<void>;
|
|
784
|
+
saveBatch(entries: Entry[]): Promise<void>;
|
|
785
|
+
find(id: string): Promise<Entry | null>;
|
|
786
|
+
list(options?: ListOptions): Promise<PaginatedResult<Entry>>;
|
|
787
|
+
findByBatch(batchId: string): Promise<Entry[]>;
|
|
788
|
+
prune(beforeDate: Date): Promise<number>;
|
|
789
|
+
clear(): Promise<void>;
|
|
790
|
+
stats(): Promise<StorageStats>;
|
|
791
|
+
close(): Promise<void>;
|
|
792
|
+
private rowToEntry;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
/**
|
|
796
|
+
* PostgreSQL storage adapter.
|
|
797
|
+
* Production-ready with connection pooling and JSONB support.
|
|
798
|
+
*/
|
|
799
|
+
declare class PostgreSQLStorage implements StorageAdapter {
|
|
800
|
+
private pool;
|
|
801
|
+
private readonly connectionString;
|
|
802
|
+
constructor(connectionString: string);
|
|
803
|
+
initialize(): Promise<void>;
|
|
804
|
+
save(entry: Entry): Promise<void>;
|
|
805
|
+
saveBatch(entries: Entry[]): Promise<void>;
|
|
806
|
+
find(id: string): Promise<Entry | null>;
|
|
807
|
+
list(options?: ListOptions): Promise<PaginatedResult<Entry>>;
|
|
808
|
+
findByBatch(batchId: string): Promise<Entry[]>;
|
|
809
|
+
prune(beforeDate: Date): Promise<number>;
|
|
810
|
+
clear(): Promise<void>;
|
|
811
|
+
stats(): Promise<StorageStats>;
|
|
812
|
+
close(): Promise<void>;
|
|
813
|
+
private rowToEntry;
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
/**
|
|
817
|
+
* MySQL storage adapter.
|
|
818
|
+
* Production-ready with connection pooling and JSON support.
|
|
819
|
+
*/
|
|
820
|
+
declare class MySQLStorage implements StorageAdapter {
|
|
821
|
+
private pool;
|
|
822
|
+
private readonly connectionString;
|
|
823
|
+
constructor(connectionString: string);
|
|
824
|
+
initialize(): Promise<void>;
|
|
825
|
+
save(entry: Entry): Promise<void>;
|
|
826
|
+
saveBatch(entries: Entry[]): Promise<void>;
|
|
827
|
+
find(id: string): Promise<Entry | null>;
|
|
828
|
+
list(options?: ListOptions): Promise<PaginatedResult<Entry>>;
|
|
829
|
+
findByBatch(batchId: string): Promise<Entry[]>;
|
|
830
|
+
prune(beforeDate: Date): Promise<number>;
|
|
831
|
+
clear(): Promise<void>;
|
|
832
|
+
stats(): Promise<StorageStats>;
|
|
833
|
+
close(): Promise<void>;
|
|
834
|
+
private rowToEntry;
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
declare module 'express' {
|
|
838
|
+
interface Request {
|
|
839
|
+
nodescope?: {
|
|
840
|
+
batchId: string;
|
|
841
|
+
startTime: number;
|
|
842
|
+
};
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
type ExpressApp = {
|
|
846
|
+
use: (path: string | RequestHandler, ...handlers: RequestHandler[]) => void;
|
|
847
|
+
};
|
|
848
|
+
/**
|
|
849
|
+
* Create Express middleware for NodeScope
|
|
850
|
+
*/
|
|
851
|
+
declare function createExpressMiddleware(nodescope: NodeScope): RequestHandler;
|
|
852
|
+
/**
|
|
853
|
+
* Mount all NodeScope routes on an Express app
|
|
854
|
+
*/
|
|
855
|
+
declare function mountExpressRoutes(app: ExpressApp, nodescope: NodeScope): Promise<void>;
|
|
856
|
+
/**
|
|
857
|
+
* Attach WebSocket handler to an HTTP server for real-time updates
|
|
858
|
+
* Requires 'ws' package: npm install ws @types/ws
|
|
859
|
+
*/
|
|
860
|
+
declare function attachWebSocket(server: http.Server, nodescope: NodeScope, options?: {
|
|
861
|
+
path?: string;
|
|
862
|
+
}): void;
|
|
863
|
+
|
|
864
|
+
declare module 'hono' {
|
|
865
|
+
interface ContextVariableMap {
|
|
866
|
+
nodescope: {
|
|
867
|
+
batchId: string;
|
|
868
|
+
startTime: number;
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
/**
|
|
873
|
+
* Create Hono middleware for NodeScope
|
|
874
|
+
*/
|
|
875
|
+
declare function createHonoMiddleware(nodescope: NodeScope): MiddlewareHandler;
|
|
876
|
+
/**
|
|
877
|
+
* Create Hono routes for NodeScope dashboard
|
|
878
|
+
*/
|
|
879
|
+
declare function createHonoDashboardRoutes(nodescope: NodeScope): Hono;
|
|
880
|
+
/**
|
|
881
|
+
* Create a simple Hono middleware that sets up everything
|
|
882
|
+
*/
|
|
883
|
+
declare function nodescope(config?: NodeScopeConfig): MiddlewareHandler;
|
|
884
|
+
|
|
885
|
+
interface FastifyRequest {
|
|
886
|
+
url: string;
|
|
887
|
+
method: string;
|
|
888
|
+
query: Record<string, unknown>;
|
|
889
|
+
headers: Record<string, string>;
|
|
890
|
+
body: unknown;
|
|
891
|
+
ip: string;
|
|
892
|
+
routeOptions?: {
|
|
893
|
+
url?: string;
|
|
894
|
+
};
|
|
895
|
+
nodescope?: {
|
|
896
|
+
batchId: string;
|
|
897
|
+
startTime: number;
|
|
898
|
+
};
|
|
899
|
+
}
|
|
900
|
+
interface FastifyReply {
|
|
901
|
+
statusCode: number;
|
|
902
|
+
getHeaders(): Record<string, string>;
|
|
903
|
+
status(code: number): FastifyReply;
|
|
904
|
+
type(contentType: string): FastifyReply;
|
|
905
|
+
send(payload: unknown): FastifyReply;
|
|
906
|
+
}
|
|
907
|
+
interface FastifyInstance {
|
|
908
|
+
addHook(name: string, handler: (...args: any[]) => Promise<void>): void;
|
|
909
|
+
get(path: string, handler: (request: FastifyRequest, reply: FastifyReply) => Promise<FastifyReply>): void;
|
|
910
|
+
all(path: string, handler: (request: FastifyRequest, reply: FastifyReply) => Promise<FastifyReply>): void;
|
|
911
|
+
log: {
|
|
912
|
+
error: (...args: any[]) => void;
|
|
913
|
+
};
|
|
914
|
+
}
|
|
915
|
+
/**
|
|
916
|
+
* Create Fastify plugin for NodeScope
|
|
917
|
+
*/
|
|
918
|
+
declare function fastifyNodeScope(fastify: FastifyInstance, options: {
|
|
919
|
+
nodescope: NodeScope;
|
|
920
|
+
}): Promise<void>;
|
|
921
|
+
|
|
922
|
+
/**
|
|
923
|
+
* Get the embedded dashboard HTML
|
|
924
|
+
* This is a simple HTML page that loads the dashboard React app
|
|
925
|
+
*/
|
|
926
|
+
declare function getDashboardHtml(basePath: string): string;
|
|
927
|
+
|
|
928
|
+
export { ApiHandler, BaseWatcher, type CacheEntryContent, type CacheOperation, CacheWatcher, type CacheWatcherOptions, type DumpEntryContent, type Entry, type EntryType, type EventEntryContent, EventWatcher, type EventWatcherOptions, type ExceptionEntryContent, ExceptionWatcher, type ExceptionWatcherOptions, type HttpClientEntryContent, HttpClientWatcher, type HttpClientWatcherOptions, type HttpMethod, type JobEntryContent, type JobStatus, JobWatcher, type JobWatcherOptions, type ListOptions, type LogEntryContent, type LogLevel, LogWatcher, type LogWatcherOptions, MemoryStorage, MySQLStorage, NodeScope, type NodeScopeConfig, type PaginatedResult, PostgreSQLStorage, type QueryEntryContent, QueryWatcher, type QueryWatcherOptions, RealTimeServer, type RequestContext, type RequestEntryContent, RequestWatcher, type RequestWatcherOptions, SQLiteStorage, type ScheduleEntryContent, type ScheduleWatcherOptions, type StorageAdapter, type StorageDriver, type StorageStats, TrackedEventEmitter, type WatcherConfig, attachWebSocket, createCacheWrapper, createExpressMiddleware, createHonoDashboardRoutes, createHonoMiddleware, createQueryInterceptor, createRequestContext, createStorageAdapter, fastifyNodeScope, getDashboardHtml, getDuration, getMemoryDelta, getNodeScope, initNodeScope, interceptConsole, interceptFetch, mountExpressRoutes, nodescope, setupGlobalErrorHandlers, wrapFetch, wrapJobProcessor, wrapPrisma };
|