@coherent.js/devtools 1.0.0-rc.6 → 1.0.1

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.
Files changed (2) hide show
  1. package/package.json +4 -3
  2. package/types/index.d.ts +579 -360
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coherent.js/devtools",
3
- "version": "1.0.0-rc.6",
3
+ "version": "1.0.1",
4
4
  "description": "Developer tools for Coherent.js applications - tree-shakable modular exports",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -62,7 +62,7 @@
62
62
  "author": "Coherent.js Team",
63
63
  "license": "MIT",
64
64
  "peerDependencies": {
65
- "@coherent.js/core": "1.0.0-rc.6"
65
+ "@coherent.js/core": "1.0.1"
66
66
  },
67
67
  "repository": {
68
68
  "type": "git",
@@ -83,6 +83,7 @@
83
83
  "build": "node build.mjs",
84
84
  "clean": "rm -rf dist",
85
85
  "test": "vitest run",
86
- "test:watch": "vitest"
86
+ "test:watch": "vitest",
87
+ "typecheck": "tsc -p tsconfig.typecheck.json --noEmit"
87
88
  }
88
89
  }
package/types/index.d.ts CHANGED
@@ -3,540 +3,759 @@
3
3
  * @module @coherent.js/devtools
4
4
  */
5
5
 
6
- import type { CoherentNode, ComponentInstance, ComponentProps } from '@coherent.js/core';
7
-
8
6
  // ============================================================================
9
- // Logger Types
7
+ // Logger
10
8
  // ============================================================================
11
9
 
12
- /**
13
- * Log level enumeration
14
- */
15
- export enum LogLevel {
16
- TRACE = 0,
17
- DEBUG = 1,
18
- INFO = 2,
19
- WARN = 3,
20
- ERROR = 4,
21
- FATAL = 5
22
- }
10
+ /** Severity levels, ordered from most to least verbose. */
11
+ export const LogLevel: {
12
+ readonly TRACE: 0;
13
+ readonly DEBUG: 1;
14
+ readonly INFO: 2;
15
+ readonly WARN: 3;
16
+ readonly ERROR: 4;
17
+ readonly FATAL: 5;
18
+ };
19
+
20
+ /** One of the {@link LogLevel} values. */
21
+ export type LogLevelValue = 0 | 1 | 2 | 3 | 4 | 5;
23
22
 
24
- /**
25
- * Logger configuration options
26
- */
27
23
  export interface LoggerOptions {
28
- /** Minimum log level to output */
29
- level?: LogLevel;
30
- /** Prefix for all log messages */
24
+ /** Minimum level to emit; defaults to `LogLevel.INFO` */
25
+ level?: LogLevelValue;
26
+ /** Prefix on every line; defaults to `'[Coherent]'` */
31
27
  prefix?: string;
32
- /** Include timestamp in output */
28
+ /** Include a timestamp; defaults to `true` */
33
29
  timestamp?: boolean;
34
- /** Use colored output */
30
+ /** Colorize output; defaults to `true` */
35
31
  colors?: boolean;
36
- /** Maximum logs to keep in memory */
32
+ /** Cap on retained entries; defaults to `1000` */
37
33
  maxLogs?: number;
38
- /** Maximum buffer size */
34
+ /** Cap on buffered entries; defaults to `1000` */
39
35
  maxBufferSize?: number;
40
- /** Enable log grouping */
36
+ /** Allow `group()`/`groupEnd()`; defaults to `true` */
41
37
  grouping?: boolean;
42
- /** Buffer logs before output */
38
+ /** Buffer instead of writing immediately; defaults to `false` */
43
39
  buffer?: boolean;
44
- /** Sample rate (0-1) for high-volume logging */
40
+ /** Fraction of entries to keep, 0 to 1; defaults to `1.0` */
45
41
  sampleRate?: number;
46
- /** Suppress all output */
42
+ /** Record without writing anywhere; defaults to `false` */
47
43
  silent?: boolean;
48
- /** Custom output handler */
49
- output?: ((log: LogEntry) => void) | null;
50
- /** Filter by categories */
44
+ /** Write here instead of the console */
45
+ output?: ((entry: LogEntry) => void) | null;
46
+ /** Only emit these categories */
51
47
  categories?: string[] | null;
52
- /** Custom filter function */
53
- filter?: ((log: LogEntry) => boolean) | null;
48
+ /** Drop entries this rejects */
49
+ filter?: ((entry: LogEntry) => boolean) | null;
50
+ [option: string]: unknown;
54
51
  }
55
52
 
56
- /**
57
- * Log entry structure
58
- */
59
53
  export interface LogEntry {
60
- /** Log level */
61
- level: LogLevel;
62
- /** Log message */
54
+ id: string;
55
+ level: LogLevelValue;
56
+ levelName: string;
63
57
  message: string;
64
- /** Timestamp (ms since epoch) */
58
+ data: Record<string, unknown>;
65
59
  timestamp: number;
66
- /** Additional data */
67
- data?: unknown[];
68
- /** Log category */
69
60
  category?: string;
70
- /** Additional context */
61
+ group?: string;
71
62
  context?: Record<string, unknown>;
72
63
  }
73
64
 
74
- /**
75
- * Development logger class
76
- */
65
+ /** Filter applied to entries before they are emitted. */
66
+ export interface LogFilter {
67
+ (entry: LogEntry): boolean;
68
+ }
69
+
70
+ export interface LogQuery {
71
+ level?: LogLevelValue;
72
+ category?: string;
73
+ /** Substring match against the message */
74
+ search?: string;
75
+ since?: number;
76
+ limit?: number;
77
+ }
78
+
79
+ /** Structured logger with levels, filters, grouping and buffering. */
77
80
  export class DevLogger {
78
81
  constructor(options?: LoggerOptions);
79
82
 
80
- /** Log at TRACE level */
81
- trace(message: string, ...data: unknown[]): void;
82
-
83
- /** Log at DEBUG level */
84
- debug(message: string, ...data: unknown[]): void;
83
+ options: LoggerOptions;
84
+ logs: LogEntry[];
85
+ filters: LogFilter[];
86
+ handlers: Array<(entry: LogEntry) => void>;
87
+ context: Record<string, unknown>;
85
88
 
86
- /** Log at INFO level */
87
- info(message: string, ...data: unknown[]): void;
89
+ /**
90
+ * Log at an explicit level, or under a category when the first argument is
91
+ * a category name.
92
+ */
93
+ log(categoryOrLevel: string | LogLevelValue, messageOrData: string | Record<string, unknown>, data?: Record<string, unknown>): void;
88
94
 
89
- /** Log at WARN level */
90
- warn(message: string, ...data: unknown[]): void;
95
+ trace(message: string, data?: Record<string, unknown>): void;
96
+ debug(message: string, data?: Record<string, unknown>): void;
97
+ info(message: string, data?: Record<string, unknown>): void;
98
+ warn(message: string, data?: Record<string, unknown>): void;
99
+ error(message: string, data?: Record<string, unknown>): void;
100
+ fatal(message: string, data?: Record<string, unknown>): void;
91
101
 
92
- /** Log at ERROR level */
93
- error(message: string, ...data: unknown[]): void;
102
+ /** Log at an explicit level */
103
+ logWithLevel(level: LogLevelValue, message: string, data?: Record<string, unknown>): void;
94
104
 
95
- /** Log at FATAL level */
96
- fatal(message: string, ...data: unknown[]): void;
105
+ /** Whether an entry passes the level, sampling and filters */
106
+ shouldLog(level: LogLevelValue, message: string, data?: Record<string, unknown>): boolean;
97
107
 
98
- /** Log at specific level */
99
- log(level: LogLevel, message: string, ...data: unknown[]): void;
108
+ addFilter(filter: LogFilter): void;
109
+ removeFilter(filter: LogFilter): void;
100
110
 
101
- /** Start a log group */
102
- group(label: string): void;
111
+ /** Add a sink invoked for every emitted entry */
112
+ addHandler(handler: (entry: LogEntry) => void): void;
113
+ removeHandler(handler: (entry: LogEntry) => void): void;
103
114
 
104
- /** End current log group */
115
+ /** Open a named group; nest by calling again */
116
+ group(name: string): void;
105
117
  groupEnd(): void;
106
118
 
107
- /** Clear all logs */
119
+ /** Retained entries, optionally narrowed */
120
+ getLogs(filter?: LogQuery): LogEntry[];
121
+
122
+ /** Entry counts by level and category */
123
+ getStats(): Record<string, unknown>;
124
+
125
+ /** Discard retained entries */
108
126
  clear(): void;
109
127
 
110
- /** Get all stored logs */
111
- getLogs(): LogEntry[];
128
+ /** Raise or lower the minimum level */
129
+ setLevel(level: LogLevelValue): void;
130
+
131
+ /** Serialize retained entries */
132
+ export(format?: 'array' | 'json' | 'csv' | 'text'): unknown;
112
133
 
113
- /** Set minimum log level */
114
- setLevel(level: LogLevel): void;
134
+ /** A logger that stamps every entry with extra context */
135
+ withContext(context: Record<string, unknown>): DevLogger;
115
136
 
116
- /** Add a log filter */
117
- addFilter(filter: (log: LogEntry) => boolean): void;
137
+ /** Render tabular data */
138
+ table(data: unknown): void;
118
139
 
119
- /** Remove a log filter */
120
- removeFilter(filter: (log: LogEntry) => boolean): void;
140
+ /** Start a named timer */
141
+ time(label: string): void;
142
+ /** Stop a named timer and log the elapsed time */
143
+ timeEnd(label: string): void;
144
+
145
+ /** Entries held back by `buffer` */
146
+ getBuffer(): LogEntry[];
147
+ /** Emit and clear the buffer */
148
+ flush(): void;
149
+ /** Drop the buffer without emitting */
150
+ clearBuffer(): void;
121
151
  }
122
152
 
123
- /**
124
- * Create a logger instance
125
- */
153
+ /** Create a {@link DevLogger}. */
126
154
  export function createLogger(options?: LoggerOptions): DevLogger;
127
155
 
128
- /**
129
- * Create a logger for a specific component
130
- */
156
+ /** A logger prefixed with a component name. */
131
157
  export function createComponentLogger(componentName: string, options?: LoggerOptions): DevLogger;
132
158
 
133
- /**
134
- * Create a logger that outputs to console
135
- */
136
- export function createConsoleLogger(): DevLogger;
159
+ /** A logger that writes straight to the console. */
160
+ export function createConsoleLogger(prefix?: string): DevLogger;
137
161
 
138
162
  // ============================================================================
139
- // Inspector Types
163
+ // Inspector
140
164
  // ============================================================================
141
165
 
142
- /**
143
- * Inspector configuration options
144
- */
145
166
  export interface InspectorOptions {
146
- /** Track inspection history */
167
+ /** Retain past inspections; defaults to `true` */
147
168
  trackHistory?: boolean;
148
- /** Maximum history entries */
169
+ /** Cap on retained inspections; defaults to `100` */
149
170
  maxHistory?: number;
150
- /** Verbose output */
171
+ /** Log each inspection; defaults to `false` */
151
172
  verbose?: boolean;
173
+ [option: string]: unknown;
152
174
  }
153
175
 
154
- /**
155
- * Component analysis result
156
- */
157
- export interface ComponentAnalysis {
158
- /** Component type */
159
- type: string;
160
- /** Whether component is valid */
161
- valid: boolean;
162
- /** Validation issues */
163
- issues: string[];
164
- /** Warnings */
165
- warnings: string[];
166
- }
167
-
168
- /**
169
- * Component tree node
170
- */
171
176
  export interface ComponentTreeNode {
172
- /** Component type/name */
173
177
  type: string;
174
- /** Tag name (if element) */
175
- tagName?: string;
176
- /** Child nodes */
177
- children: ComponentTreeNode[];
178
- /** Tree depth */
179
- depth: number;
180
- /** Component name */
181
178
  name?: string;
182
- /** Component ID */
183
- id?: string;
184
- /** Props */
185
179
  props?: Record<string, unknown>;
186
- /** State */
187
- state?: Record<string, unknown>;
188
- /** Render count */
189
- renderCount?: number;
180
+ children?: ComponentTreeNode[];
181
+ depth?: number;
182
+ [key: string]: unknown;
190
183
  }
191
184
 
192
- /**
193
- * Component statistics
194
- */
195
185
  export interface ComponentStats {
196
- /** Maximum depth */
197
186
  depth: number;
198
- /** Total element count */
187
+ nodeCount: number;
199
188
  elementCount: number;
200
- /** Complexity score */
201
189
  complexity: number;
202
- /** Total node count */
203
- nodeCount: number;
190
+ [key: string]: unknown;
204
191
  }
205
192
 
206
- /**
207
- * Inspector data for a component
208
- */
209
- export interface InspectorData {
210
- /** Component instance */
211
- component: ComponentInstance;
212
- /** Component props */
213
- props: Record<string, unknown>;
214
- /** Component state */
215
- state: Record<string, unknown>;
216
- /** Rendered output */
217
- rendered: CoherentNode;
218
- /** Render time (ms) */
219
- renderTime: number;
220
- /** Update count */
221
- updateCount: number;
193
+ export interface ComponentAnalysis {
194
+ type: string;
195
+ valid: boolean;
196
+ issues: string[];
197
+ warnings: string[];
198
+ [key: string]: unknown;
222
199
  }
223
200
 
224
- /**
225
- * Full inspection result
226
- */
201
+ /** What one `inspect()` call produced. */
227
202
  export interface InspectionResult {
228
- /** Unique inspection ID */
229
203
  id: string;
230
- /** Inspection timestamp */
231
204
  timestamp: number;
232
- /** Time taken to inspect */
205
+ /** Time the inspection itself took, in ms */
233
206
  inspectionTime: number;
234
- /** Inspected component */
235
207
  component: unknown;
236
- /** Additional metadata */
237
208
  metadata: Record<string, unknown>;
238
- /** Component type */
239
209
  type: string;
240
- /** Component structure */
241
210
  structure: unknown;
242
- /** Component props */
243
211
  props: Record<string, unknown>;
244
- /** Tree depth */
245
212
  depth: number;
246
- /** Direct child count */
247
213
  childCount: number;
248
- /** Complexity score */
249
214
  complexity: number;
250
- /** Total node count */
251
215
  nodeCount: number;
252
- /** Analysis result */
253
216
  analysis: ComponentAnalysis;
254
- /** Component tree */
255
217
  tree: ComponentTreeNode;
256
- /** Statistics */
257
218
  stats: ComponentStats;
258
- /** Whether component is valid */
259
219
  valid: boolean;
260
- /** Validation issues */
261
220
  issues: string[];
262
- /** Errors found */
221
+ /** Alias of `issues` */
263
222
  errors: string[];
264
- /** Warnings found */
265
223
  warnings: string[];
266
224
  }
267
225
 
268
- /**
269
- * Component inspector class
270
- */
226
+ /** Analyzes component structure and keeps a history of inspections. */
271
227
  export class ComponentInspector {
272
228
  constructor(options?: InspectorOptions);
273
229
 
274
- /** Inspect a component */
230
+ options: InspectorOptions;
231
+ components: Map<string, InspectionResult>;
232
+ history: InspectionResult[];
233
+ inspectionCount: number;
234
+
235
+ /** Analyze a component and record the result */
275
236
  inspect(component: unknown, metadata?: Record<string, unknown>): InspectionResult;
276
237
 
277
- /** Get inspection history */
278
- getHistory(): InspectionResult[];
238
+ /** Props of the component's root element */
239
+ extractProps(component: unknown): Record<string, unknown>;
240
+
241
+ /** Type, validity, issues and warnings */
242
+ analyzeComponent(component: unknown): ComponentAnalysis;
279
243
 
280
- /** Get a specific inspection by ID */
244
+ /** Structural tree, capped at `maxDepth` */
245
+ buildComponentTree(component: unknown, depth?: number, maxDepth?: number): ComponentTreeNode;
246
+
247
+ /** Depth, node counts and complexity */
248
+ calculateStats(component: unknown): ComponentStats;
249
+
250
+ /** A past inspection by id */
281
251
  getComponent(id: string): InspectionResult | undefined;
282
252
 
283
- /** Clear inspection history */
253
+ /** Copy of the inspection history */
254
+ getHistory(): InspectionResult[];
255
+
256
+ /** Past inspections matching every criterion */
257
+ search(criteria: Record<string, unknown>): InspectionResult[];
258
+
259
+ /** Structural differences between two components */
260
+ compare(componentA: unknown, componentB: unknown): Record<string, unknown>;
261
+
262
+ /** Summary of everything inspected so far */
263
+ generateReport(): Record<string, unknown>;
264
+
265
+ /** Drop recorded inspections and history */
284
266
  clear(): void;
267
+ /** Drop history only */
268
+ clearHistory(): void;
269
+
270
+ /** Counts of inspections, components and issues */
271
+ getStats(): Record<string, unknown>;
272
+
273
+ /** Serialize recorded inspections */
274
+ export(): Record<string, unknown>;
285
275
  }
286
276
 
287
- /**
288
- * Create an inspector instance
289
- */
277
+ /** Create a {@link ComponentInspector}. */
290
278
  export function createInspector(options?: InspectorOptions): ComponentInspector;
291
279
 
292
- /**
293
- * Inspect a component
294
- */
295
- export function inspect(component: unknown, metadata?: Record<string, unknown>): InspectionResult;
280
+ /** Inspect a component with a throwaway inspector. */
281
+ export function inspect(component: unknown, options?: InspectorOptions): InspectionResult;
296
282
 
297
- /**
298
- * Validate a component structure
299
- */
300
- export function validateComponent(component: unknown): { valid: boolean; issues: string[] };
283
+ /** Throws when the component is structurally invalid. */
284
+ export function validateComponent(component: unknown): boolean;
301
285
 
302
286
  // ============================================================================
303
- // Profiler Types
287
+ // Profiler
304
288
  // ============================================================================
305
289
 
306
- /**
307
- * Profiler configuration options
308
- */
309
290
  export interface ProfilerOptions {
310
- /** Sample rate (0-1) */
291
+ /** Record anything at all; defaults to `true` */
292
+ enabled?: boolean;
293
+ /** Fraction of sessions and renders to record, 0 to 1; defaults to `1.0` */
311
294
  sampleRate?: number;
312
- /** Maximum samples to keep */
295
+ /** Above this many ms a render counts as slow; defaults to `16` */
296
+ slowThreshold?: number;
297
+ /** Sample heap usage where the runtime exposes it */
298
+ trackMemory?: boolean;
299
+ /** Cap on retained measurements; defaults to `1000` */
313
300
  maxSamples?: number;
314
- /** Auto-start profiling */
315
- autoStart?: boolean;
301
+ [option: string]: unknown;
316
302
  }
317
303
 
318
- /**
319
- * Performance measurement
320
- */
321
- export interface PerformanceMeasurement {
322
- /** Measurement name */
323
- name: string;
324
- /** Duration in ms */
325
- duration: number;
326
- /** Start time */
327
- startTime: number;
328
- /** End time */
329
- endTime: number;
330
- /** Additional metadata */
331
- metadata?: Record<string, unknown>;
304
+ export interface MemoryUsage {
305
+ used: number;
306
+ total: number;
307
+ limit: number;
332
308
  }
333
309
 
334
- /**
335
- * Profiler result for a component render
336
- */
337
- export interface ProfilerResult {
338
- /** Component name */
310
+ /** One recorded render. */
311
+ export interface RenderMeasurement {
312
+ id: string;
339
313
  componentName: string;
340
- /** Total duration */
341
- duration: number;
342
- /** Render phase */
343
- phase: 'mount' | 'update';
344
- /** Actual duration (excluding suspended time) */
345
- actualDuration: number;
346
- /** Base duration (without memoization) */
347
- baseDuration: number;
348
- /** Start time */
314
+ props: Record<string, unknown>;
349
315
  startTime: number;
350
- /** Commit time */
351
- commitTime: number;
316
+ endTime?: number;
317
+ duration?: number;
318
+ startMemory: MemoryUsage | null;
319
+ endMemory?: MemoryUsage | null;
320
+ memoryDelta?: number;
321
+ phase: string;
322
+ result?: Record<string, unknown>;
323
+ /** Whether `duration` exceeded `slowThreshold` */
324
+ slow?: boolean;
352
325
  }
353
326
 
354
- /**
355
- * Profile report for a measurement
356
- */
357
- export interface ProfileReport {
358
- /** All measurements */
359
- measurements: PerformanceMeasurement[];
360
- /** Total time */
361
- totalTime: number;
362
- /** Average time */
363
- averageTime: number;
364
- /** Minimum time */
365
- minTime: number;
366
- /** Maximum time */
367
- maxTime: number;
368
- /** Sample count */
369
- count: number;
327
+ /** A point in time inside a session. */
328
+ export interface ProfilerMark {
329
+ name: string;
330
+ timestamp: number;
331
+ data: Record<string, unknown>;
332
+ memory: MemoryUsage | null;
333
+ }
334
+
335
+ export interface ProfilerStatistics {
336
+ mean: number;
337
+ median: number;
338
+ min: number;
339
+ max: number;
340
+ stdDev: number;
341
+ }
342
+
343
+ export interface ProfilerMetrics {
344
+ totalOperations: number;
345
+ totalDuration: number;
346
+ operationCounts: Record<string, number>;
347
+ averageDuration: number;
348
+ memoryUsage: number | null;
349
+ }
350
+
351
+ export interface ProfilerReport {
352
+ summary: {
353
+ totalOperations: number;
354
+ averageDuration: number;
355
+ slowOperations: number;
356
+ };
357
+ statistics: ProfilerStatistics;
358
+ operations: Array<{ name: string; duration: number; timestamp: number }>;
359
+ bottlenecks: Array<{ name: string; duration: number; timestamp: number }>;
360
+ recommendations: unknown[];
361
+ timestamp: number;
362
+ }
363
+
364
+ export interface MeasurementQuery {
365
+ componentName?: string;
366
+ /** Only measurements flagged slow */
367
+ slow?: boolean;
368
+ minDuration?: number;
369
+ limit?: number;
370
370
  }
371
371
 
372
372
  /**
373
- * Performance profiler class
373
+ * Records render timings, session marks and memory usage.
374
+ *
375
+ * `start()` returns a session id — `null` when profiling is disabled or the
376
+ * call was sampled out — and every id-taking method tolerates `null`.
374
377
  */
375
378
  export class PerformanceProfiler {
376
379
  constructor(options?: ProfilerOptions);
377
380
 
378
- /** Start a measurement */
379
- start(name: string): void;
381
+ options: ProfilerOptions;
382
+ measurements: RenderMeasurement[];
383
+ sessions: Map<string, Record<string, unknown>>;
384
+ currentSession: Record<string, unknown> | null;
385
+ marks: Map<string, RenderMeasurement>;
386
+
387
+ /** Open a session; `null` when disabled or sampled out */
388
+ start(name?: string): string | null;
389
+
390
+ /** Close a session and return its analysis; `null` when unknown */
391
+ stop(sessionId: string | null): Record<string, unknown> | null;
392
+
393
+ /** Begin timing a render; `null` when disabled or sampled out */
394
+ startRender(componentName: string, props?: Record<string, unknown>): string | null;
395
+
396
+ /** Finish timing a render; `null` when the id is unknown */
397
+ endRender(measurementId: string | null, result?: Record<string, unknown>): RenderMeasurement | null;
398
+
399
+ /** Record a named point in the current session */
400
+ mark(name: string, data?: Record<string, unknown>): ProfilerMark;
401
+
402
+ /** Elapsed time between two marks; throws when either is missing */
403
+ measure(startMark: string, endMark: string): {
404
+ duration: number;
405
+ startMark: string;
406
+ endMark: string;
407
+ };
408
+
409
+ /** Heap usage, where the runtime exposes it */
410
+ getMemoryUsage(): MemoryUsage | null;
411
+
412
+ /** A mark in the current session by name */
413
+ findMark(name: string): ProfilerMark | null | undefined;
414
+
415
+ /** Retained measurements, optionally narrowed */
416
+ getMeasurements(filter?: MeasurementQuery): RenderMeasurement[];
380
417
 
381
- /** End a measurement */
382
- end(name: string): PerformanceMeasurement | null;
418
+ /** Aggregate one session's measurements */
419
+ analyzeSession(session: Record<string, unknown>): Record<string, unknown>;
383
420
 
384
- /** Measure a synchronous function */
385
- measure<T>(name: string, fn: () => T): T;
421
+ /** Group measurements by component name */
422
+ groupByComponent(measurements: RenderMeasurement[]): Record<string, unknown>;
386
423
 
387
- /** Measure an async function */
388
- measureAsync<T>(name: string, fn: () => Promise<T>): Promise<T>;
424
+ /** Totals, averages and the slowest recent renders */
425
+ getSummary(): Record<string, unknown>;
389
426
 
390
- /** Get profile report */
391
- getReport(name?: string): ProfileReport | Map<string, ProfileReport>;
427
+ /** Mean, median, min, max and standard deviation */
428
+ getStatistics(): ProfilerStatistics;
392
429
 
393
- /** Clear all measurements */
430
+ /** Measurements slower than the threshold, slowest first */
431
+ getBottlenecks(threshold?: number | null): Array<{
432
+ name: string;
433
+ duration: number;
434
+ timestamp: number;
435
+ }>;
436
+
437
+ /** Operation counts, totals and heap usage */
438
+ getMetrics(): ProfilerMetrics;
439
+
440
+ /** Statistics, metrics, bottlenecks and recommendations together */
441
+ generateReport(): ProfilerReport;
442
+
443
+ /** Serialize sessions, measurements and metrics */
444
+ export(): Record<string, unknown>;
445
+
446
+ /** Render the metrics as a printable block */
447
+ formatMetrics(): string;
448
+
449
+ /** Compare two sessions; `null` when either id is unknown */
450
+ compare(profileId1: string, profileId2: string): Record<string, unknown> | null;
451
+
452
+ /** Suggestions derived from the recorded measurements */
453
+ getRecommendations(): unknown[];
454
+
455
+ /** Drop measurements, sessions and marks */
394
456
  clear(): void;
395
457
 
396
- /** Reset profiler state */
397
- reset(): void;
458
+ /** Resume recording */
459
+ enable(): void;
460
+ /** Stop recording; `start()` and `startRender()` then return `null` */
461
+ disable(): void;
398
462
  }
399
463
 
400
- /**
401
- * Create a profiler instance
402
- */
464
+ /** Create a {@link PerformanceProfiler}. */
403
465
  export function createProfiler(options?: ProfilerOptions): PerformanceProfiler;
404
466
 
405
467
  /**
406
- * Measure a synchronous function
468
+ * Time an async function. Rejects with `{ error, duration }` when `fn` throws.
407
469
  */
408
- export function measure<T>(name: string, fn: () => T): T;
470
+ export function measure<T>(
471
+ name: string,
472
+ fn: () => T | Promise<T>,
473
+ profiler?: PerformanceProfiler | null
474
+ ): Promise<{ value: T; duration: number }>;
409
475
 
410
- /**
411
- * Profile a function and return result with duration
412
- */
413
- export function profile<T>(fn: () => T): { result: T; duration: number };
476
+ /** Wrap a function so calls to it can be profiled. */
477
+ export function profile<F extends (...args: never[]) => unknown>(fn: F): F;
414
478
 
415
479
  // ============================================================================
416
- // DevTools Configuration
480
+ // DevTools
417
481
  // ============================================================================
418
482
 
419
483
  /**
420
- * DevTools configuration options
484
+ * Development-only instrumentation: render interception, validation, hot
485
+ * reload and a browser panel.
486
+ *
487
+ * Enabled only when `NODE_ENV=development`, or on localhost / `?dev=true` in
488
+ * a browser. `isEnabled` is a property, not a method.
421
489
  */
422
- export interface DevToolsConfig {
423
- /** Enable devtools */
424
- enabled?: boolean;
425
- /** Log level */
426
- logLevel?: 'debug' | 'info' | 'warn' | 'error';
427
- /** Trace renders */
428
- traceRenders?: boolean;
429
- /** Trace state changes */
430
- traceState?: boolean;
431
- /** Show panel UI */
432
- panel?: boolean;
490
+ export class DevTools {
491
+ constructor(coherentInstance?: unknown);
492
+
493
+ coherent: unknown;
494
+ /** Whether instrumentation is active in this environment */
495
+ isEnabled: boolean;
496
+ renderHistory: unknown[];
497
+ componentRegistry: Map<string, unknown>;
498
+ warnings: unknown[];
499
+ errors: unknown[];
500
+ hotReloadEnabled: boolean;
501
+
502
+ /** Whether the environment looks like development */
503
+ shouldEnable(): boolean;
504
+
505
+ /** Install every hook; called by the constructor when enabled */
506
+ initialize(): void;
507
+
508
+ /** Report a component's type, structure and props */
509
+ inspectComponent(component: unknown): Record<string, unknown>;
510
+
511
+ /** Render the structure as an indented tree */
512
+ visualizeStructure(component: unknown, depth?: number, maxDepth?: number): string;
513
+
514
+ /** Suggestions for a specific component */
515
+ getOptimizationRecommendations(component: unknown): unknown[];
516
+
517
+ /** Aggregate timings from the render history */
518
+ getPerformanceInsights(): Record<string, unknown>;
519
+
520
+ /** Throws when the component is structurally invalid */
521
+ validateComponent(component: unknown): boolean;
522
+
523
+ /** Deep structural check, collecting issues instead of throwing */
524
+ deepValidateComponent(component: unknown, path?: string, depth?: number): unknown[];
525
+
526
+ /** Depth, breadth and node counts */
527
+ analyzeComplexity(component: unknown, depth?: number): Record<string, unknown>;
528
+
529
+ /** Drop render history, warnings and errors */
530
+ clearDevData(): void;
531
+
532
+ /** Turn one instrumentation feature on or off */
533
+ toggleFeature(feature: string): void;
534
+
535
+ /** Print a summary of the session to the console */
536
+ printDevSummary(): void;
433
537
  }
434
538
 
435
- /**
436
- * DevTools instance interface
437
- */
438
- export interface DevToolsInstance {
439
- /** Inspect a component */
440
- inspect(component: ComponentInstance): InspectorData;
539
+ /** Create a {@link DevTools} instance bound to a Coherent instance. */
540
+ export function createDevTools(coherentInstance?: unknown): DevTools;
441
541
 
442
- /** Log a message */
443
- log(level: string, message: string, data?: unknown): void;
542
+ // ============================================================================
543
+ // Component Visualizer
544
+ // ============================================================================
444
545
 
445
- /** Trace an event */
446
- trace(event: string, data?: unknown): void;
546
+ export interface VisualizerOptions {
547
+ /** Depth cap; defaults to `50` */
548
+ maxDepth?: number;
549
+ /** Include props; defaults to `true` */
550
+ showProps?: boolean;
551
+ /** Include metadata; defaults to `true` */
552
+ showMetadata?: boolean;
553
+ /** Emit ANSI colors; defaults to `true` */
554
+ colorOutput?: boolean;
555
+ /** One line per node; defaults to `false` */
556
+ compactMode?: boolean;
557
+ [option: string]: unknown;
558
+ }
447
559
 
448
- /** Get the component tree */
449
- getComponentTree(): ComponentTreeNode[];
560
+ export interface VisualizerStats {
561
+ totalComponents: number;
562
+ totalDepth: number;
563
+ staticComponents: number;
564
+ dynamicComponents: number;
565
+ /** Time spent building the visualization, in ms */
566
+ renderTime: number;
567
+ }
450
568
 
451
- /** Enable devtools */
452
- enable(): void;
569
+ export interface VisualizationResult {
570
+ /** The printable tree */
571
+ visualization: string;
572
+ stats: VisualizerStats;
573
+ tree: ComponentTreeNode;
574
+ }
453
575
 
454
- /** Disable devtools */
455
- disable(): void;
576
+ /** Renders a component tree as printable text, DOT or JSON. */
577
+ export class ComponentVisualizer {
578
+ constructor(options?: VisualizerOptions);
579
+
580
+ options: VisualizerOptions;
581
+ stats: VisualizerStats;
582
+
583
+ /** Build the tree and render it */
584
+ visualize(component: unknown, name?: string): VisualizationResult;
585
+
586
+ /** Build the tree without rendering */
587
+ buildTree(component: unknown, name: string, depth: number): ComponentTreeNode;
588
+
589
+ /** Render a prepared tree */
590
+ renderTree(tree: ComponentTreeNode): string;
456
591
 
457
- /** Check if enabled */
458
- isEnabled(): boolean;
592
+ /** Serialize a tree as JSON */
593
+ exportAsJSON(tree: ComponentTreeNode): string;
594
+
595
+ /** Serialize a tree as Graphviz DOT */
596
+ exportAsDOT(tree: ComponentTreeNode): string;
459
597
  }
460
598
 
599
+ /** Create a {@link ComponentVisualizer}. */
600
+ export function createComponentVisualizer(options?: VisualizerOptions): ComponentVisualizer;
601
+
602
+ /** Visualize with a throwaway visualizer. */
603
+ export function visualizeComponent(
604
+ component: unknown,
605
+ name?: string,
606
+ options?: VisualizerOptions
607
+ ): VisualizationResult;
608
+
609
+ /** {@link visualizeComponent}, printed to the console. */
610
+ export function logComponentTree(
611
+ component: unknown,
612
+ name?: string,
613
+ options?: VisualizerOptions
614
+ ): VisualizationResult;
615
+
461
616
  // ============================================================================
462
- // DevTools Class
617
+ // Performance Dashboard
463
618
  // ============================================================================
464
619
 
465
- /**
466
- * Combined DevTools options
467
- */
468
- export interface DevToolsOptions {
469
- /** Logger options */
470
- logger?: LoggerOptions;
471
- /** Inspector options */
472
- inspector?: InspectorOptions;
473
- /** Profiler options */
474
- profiler?: ProfilerOptions;
475
- /** Enable all tools */
476
- enabled?: boolean;
620
+ export interface DashboardOptions {
621
+ /** Metric refresh interval in ms; defaults to `5000` */
622
+ updateInterval?: number;
623
+ /** History points retained per category; defaults to `100` */
624
+ maxHistoryPoints?: number;
625
+ /** Raise alerts on threshold breaches; defaults to `true` */
626
+ enableAlerts?: boolean;
627
+ /** Derive recommendations; defaults to `true` */
628
+ enableRecommendations?: boolean;
629
+ /** Emit ANSI colors; defaults to `true` */
630
+ colorOutput?: boolean;
631
+ [option: string]: unknown;
477
632
  }
478
633
 
479
- /**
480
- * Combined DevTools class
481
- */
482
- export class DevTools {
483
- /** Logger instance */
484
- logger: DevLogger;
485
- /** Inspector instance */
486
- inspector: ComponentInspector;
487
- /** Profiler instance */
488
- profiler: PerformanceProfiler;
634
+ export interface DashboardMetrics {
635
+ api: Record<string, unknown>;
636
+ components: Record<string, unknown>;
637
+ fullstack: Record<string, unknown>;
638
+ }
489
639
 
490
- constructor(options?: DevToolsOptions);
640
+ /** Collects API, component and full-stack timings and renders them. */
641
+ export class PerformanceDashboard {
642
+ constructor(options?: DashboardOptions);
491
643
 
492
- /** Enable all tools */
493
- enable(): void;
644
+ options: DashboardOptions;
645
+ metrics: DashboardMetrics;
646
+ alerts: unknown[];
647
+ recommendations: unknown[];
648
+ startTime: number;
494
649
 
495
- /** Disable all tools */
496
- disable(): void;
650
+ /** Begin refreshing metrics on `updateInterval` */
651
+ startMonitoring(): void;
652
+ /** Stop refreshing */
653
+ stopMonitoring(): void;
497
654
 
498
- /** Check if enabled */
499
- isEnabled(): boolean;
655
+ recordAPIRequest(duration: number, routeType: string, cacheHit?: boolean): void;
656
+ recordComponentRender(
657
+ duration: number,
658
+ componentType: string,
659
+ cacheHit?: boolean,
660
+ memoryDelta?: number
661
+ ): void;
662
+ recordFullStackRequest(duration: number, error?: unknown, bottlenecks?: unknown[]): void;
500
663
 
501
- /** Clear all data */
502
- clear(): void;
664
+ /** Recompute derived metrics, alerts and recommendations */
665
+ updateMetrics(): void;
503
666
 
504
- /** Get combined report */
505
- getReport(): {
506
- logs: LogEntry[];
507
- inspections: InspectionResult[];
508
- profiles: Map<string, ProfileReport>;
509
- };
667
+ /** Cache hit ratio for one category */
668
+ getCacheHitRate(category: string): number;
669
+
670
+ /** Render the dashboard as printable text */
671
+ generateDashboard(): string;
672
+
673
+ /** Overall score derived from the current metrics */
674
+ calculatePerformanceScore(): number;
675
+
676
+ /** Serialize the current metrics */
677
+ exportMetrics(): Record<string, unknown>;
678
+
679
+ /** Clear every metric and alert */
680
+ reset(): void;
510
681
  }
511
682
 
512
- /**
513
- * Create a DevTools instance
514
- */
515
- export function createDevTools(options?: DevToolsOptions): DevTools;
683
+ /** Create a {@link PerformanceDashboard}. */
684
+ export function createPerformanceDashboard(options?: DashboardOptions): PerformanceDashboard;
685
+
686
+ /** Print a dashboard to the console and return it. */
687
+ export function showPerformanceDashboard(dashboard: PerformanceDashboard): PerformanceDashboard;
516
688
 
517
689
  // ============================================================================
518
- // Default Export
690
+ // Enhanced Errors
519
691
  // ============================================================================
520
692
 
521
- /**
522
- * Default devtools export
523
- */
524
- declare const devtools: {
525
- ComponentInspector: typeof ComponentInspector;
526
- createInspector: typeof createInspector;
527
- inspect: typeof inspect;
528
- validateComponent: typeof validateComponent;
529
- PerformanceProfiler: typeof PerformanceProfiler;
530
- createProfiler: typeof createProfiler;
531
- measure: typeof measure;
532
- profile: typeof profile;
533
- DevLogger: typeof DevLogger;
534
- LogLevel: typeof LogLevel;
535
- createLogger: typeof createLogger;
536
- createComponentLogger: typeof createComponentLogger;
537
- createConsoleLogger: typeof createConsoleLogger;
538
- DevTools: typeof DevTools;
539
- createDevTools: typeof createDevTools;
540
- };
693
+ export interface ErrorHandlerOptions {
694
+ /** How far to walk the component tree for context; defaults to `5` */
695
+ maxContextDepth?: number;
696
+ /** Keep the original stack; defaults to `true` */
697
+ includeStackTrace?: boolean;
698
+ /** Derive fix suggestions; defaults to `true` */
699
+ showSuggestions?: boolean;
700
+ /** Emit ANSI colors; defaults to `true` */
701
+ colorOutput?: boolean;
702
+ [option: string]: unknown;
703
+ }
704
+
705
+ /** An error with component context and suggested fixes attached. */
706
+ export interface EnhancedError {
707
+ originalError: Error;
708
+ message: string;
709
+ stack?: string;
710
+ timestamp: number;
711
+ component: Record<string, unknown> | null;
712
+ context: Record<string, unknown>;
713
+ suggestions: string[];
714
+ severity: string;
715
+ category: string;
716
+ componentContext?: Record<string, unknown>;
717
+ propValidation?: Record<string, unknown>;
718
+ }
719
+
720
+ /** Turns a raw error into one carrying component context and suggestions. */
721
+ export class EnhancedErrorHandler {
722
+ constructor(options?: ErrorHandlerOptions);
723
+
724
+ options: ErrorHandlerOptions;
725
+ errorHistory: EnhancedError[];
726
+
727
+ /** Enhance an error and record it; the last 100 are retained */
728
+ handleError(
729
+ error: Error,
730
+ component?: unknown,
731
+ context?: Record<string, unknown>
732
+ ): EnhancedError;
733
+
734
+ /** Type, validity and complexity of a component */
735
+ analyzeComponent(component: unknown): Record<string, unknown>;
736
+
737
+ /** Where the component sits in the tree */
738
+ getComponentContext(component: unknown, path?: string[]): Record<string, unknown>;
739
+
740
+ /** Prop problems that could explain the error */
741
+ validateProps(component: unknown): Record<string, unknown>;
742
+
743
+ /** Fixes matching the error's known patterns */
744
+ generateSuggestions(enhancedError: EnhancedError): string[];
745
+
746
+ /** Render an enhanced error for the console */
747
+ formatError(enhancedError: EnhancedError): string;
748
+
749
+ /** Counts by severity and category */
750
+ getErrorStats(): Record<string, unknown>;
751
+ }
752
+
753
+ /** Create an {@link EnhancedErrorHandler}. */
754
+ export function createEnhancedErrorHandler(options?: ErrorHandlerOptions): EnhancedErrorHandler;
541
755
 
542
- export default devtools;
756
+ /** Enhance an error, print it, and return it. */
757
+ export function handleEnhancedError(
758
+ error: Error,
759
+ component?: unknown,
760
+ context?: Record<string, unknown>
761
+ ): EnhancedError;