@codebaz/nextdoctor-agent 0.1.0-beta.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 (80) hide show
  1. package/.turbo/turbo-build.log +3 -0
  2. package/README.md +568 -0
  3. package/dist/detectors/__tests__/cold-start-threshold.test.d.ts +2 -0
  4. package/dist/detectors/__tests__/cold-start-threshold.test.d.ts.map +1 -0
  5. package/dist/detectors/__tests__/cold-start-threshold.test.js +156 -0
  6. package/dist/detectors/__tests__/cold-start-threshold.test.js.map +1 -0
  7. package/dist/detectors/__tests__/dynamic-route-candidate.test.d.ts +2 -0
  8. package/dist/detectors/__tests__/dynamic-route-candidate.test.d.ts.map +1 -0
  9. package/dist/detectors/__tests__/dynamic-route-candidate.test.js +318 -0
  10. package/dist/detectors/__tests__/dynamic-route-candidate.test.js.map +1 -0
  11. package/dist/detectors/__tests__/fetch-no-cache.test.d.ts +2 -0
  12. package/dist/detectors/__tests__/fetch-no-cache.test.d.ts.map +1 -0
  13. package/dist/detectors/__tests__/fetch-no-cache.test.js +199 -0
  14. package/dist/detectors/__tests__/fetch-no-cache.test.js.map +1 -0
  15. package/dist/detectors/base-detector.d.ts +17 -0
  16. package/dist/detectors/base-detector.d.ts.map +1 -0
  17. package/dist/detectors/base-detector.js +50 -0
  18. package/dist/detectors/base-detector.js.map +1 -0
  19. package/dist/detectors/cold-start-threshold.detector.d.ts +11 -0
  20. package/dist/detectors/cold-start-threshold.detector.d.ts.map +1 -0
  21. package/dist/detectors/cold-start-threshold.detector.js +87 -0
  22. package/dist/detectors/cold-start-threshold.detector.js.map +1 -0
  23. package/dist/detectors/dynamic-route-candidate.detector.d.ts +23 -0
  24. package/dist/detectors/dynamic-route-candidate.detector.d.ts.map +1 -0
  25. package/dist/detectors/dynamic-route-candidate.detector.js +96 -0
  26. package/dist/detectors/dynamic-route-candidate.detector.js.map +1 -0
  27. package/dist/detectors/fetch-no-cache.detector.d.ts +12 -0
  28. package/dist/detectors/fetch-no-cache.detector.d.ts.map +1 -0
  29. package/dist/detectors/fetch-no-cache.detector.js +178 -0
  30. package/dist/detectors/fetch-no-cache.detector.js.map +1 -0
  31. package/dist/detectors/index.d.ts +28 -0
  32. package/dist/detectors/index.d.ts.map +1 -0
  33. package/dist/detectors/index.js +97 -0
  34. package/dist/detectors/index.js.map +1 -0
  35. package/dist/detectors/types.d.ts +32 -0
  36. package/dist/detectors/types.d.ts.map +1 -0
  37. package/dist/detectors/types.js +2 -0
  38. package/dist/detectors/types.js.map +1 -0
  39. package/dist/index.d.ts +10 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +7 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/init.d.ts +133 -0
  44. package/dist/init.d.ts.map +1 -0
  45. package/dist/init.js +363 -0
  46. package/dist/init.js.map +1 -0
  47. package/dist/middleware.d.ts +10 -0
  48. package/dist/middleware.d.ts.map +1 -0
  49. package/dist/middleware.js +61 -0
  50. package/dist/middleware.js.map +1 -0
  51. package/dist/optimization.d.ts +43 -0
  52. package/dist/optimization.d.ts.map +1 -0
  53. package/dist/optimization.js +139 -0
  54. package/dist/optimization.js.map +1 -0
  55. package/dist/system-monitor.d.ts +124 -0
  56. package/dist/system-monitor.d.ts.map +1 -0
  57. package/dist/system-monitor.js +221 -0
  58. package/dist/system-monitor.js.map +1 -0
  59. package/dist/types.d.ts +61 -0
  60. package/dist/types.d.ts.map +1 -0
  61. package/dist/types.js +14 -0
  62. package/dist/types.js.map +1 -0
  63. package/package.json +55 -0
  64. package/src/detectors/__tests__/cold-start-threshold.test.ts +183 -0
  65. package/src/detectors/__tests__/dynamic-route-candidate.test.ts +365 -0
  66. package/src/detectors/__tests__/fetch-no-cache.test.ts +239 -0
  67. package/src/detectors/base-detector.ts +69 -0
  68. package/src/detectors/cold-start-threshold.detector.ts +95 -0
  69. package/src/detectors/dynamic-route-candidate.detector.ts +107 -0
  70. package/src/detectors/fetch-no-cache.detector.ts +204 -0
  71. package/src/detectors/index.ts +127 -0
  72. package/src/detectors/types.ts +38 -0
  73. package/src/index.ts +60 -0
  74. package/src/init.ts +424 -0
  75. package/src/middleware.ts +75 -0
  76. package/src/optimization.ts +164 -0
  77. package/src/system-monitor.ts +295 -0
  78. package/src/types.ts +66 -0
  79. package/tsconfig.json +11 -0
  80. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,124 @@
1
+ import type { LogLevel } from './types.js';
2
+ export interface CPUMetrics {
3
+ timestamp: number;
4
+ usage: number;
5
+ loadAverage: {
6
+ oneMinute: number;
7
+ fiveMinutes: number;
8
+ fifteenMinutes: number;
9
+ };
10
+ coreCount: number;
11
+ systemLoadPerCore: number;
12
+ }
13
+ export interface MemoryMetrics {
14
+ timestamp: number;
15
+ heapUsed: number;
16
+ heapTotal: number;
17
+ external: number;
18
+ arrayBuffers: number;
19
+ heapUsagePercent: number;
20
+ systemMemoryUsed: number;
21
+ systemMemoryTotal: number;
22
+ systemMemoryUsagePercent: number;
23
+ }
24
+ export interface SystemMetrics {
25
+ cpu: CPUMetrics;
26
+ memory: MemoryMetrics;
27
+ uptime: number;
28
+ }
29
+ /**
30
+ * CPU Monitor - Real-time CPU usage tracking
31
+ */
32
+ export declare class CPUMonitor {
33
+ private static readonly SAMPLE_INTERVAL;
34
+ private lastCPUTimes;
35
+ private lastSampleTime;
36
+ private logFn?;
37
+ constructor(logFn?: (level: LogLevel, message: string, meta?: any) => void);
38
+ private initializeBaseline;
39
+ /**
40
+ * Calcula o uso de CPU em percentual
41
+ */
42
+ getCPUUsage(): CPUMetrics;
43
+ /**
44
+ * Monitora CPU e alerta se exceder threshold
45
+ */
46
+ checkCPUThreshold(threshold?: number): {
47
+ exceeded: boolean;
48
+ usage: number;
49
+ };
50
+ }
51
+ /**
52
+ * Memory Monitor - Real-time memory usage tracking
53
+ */
54
+ export declare class MemoryMonitor {
55
+ private logFn?;
56
+ constructor(logFn?: (level: LogLevel, message: string, meta?: any) => void);
57
+ /**
58
+ * Obtém métricas de memória
59
+ */
60
+ getMemoryMetrics(): MemoryMetrics;
61
+ /**
62
+ * Verifica se memória excedeu threshold
63
+ */
64
+ checkMemoryThreshold(threshold?: number): {
65
+ heapExceeded: boolean;
66
+ systemExceeded: boolean;
67
+ metrics: MemoryMetrics;
68
+ };
69
+ /**
70
+ * Formata bytes para string legível
71
+ */
72
+ formatBytes(bytes: number): string;
73
+ }
74
+ /**
75
+ * System Monitor - Unified system metrics collector
76
+ */
77
+ export declare class SystemMonitor {
78
+ private cpuMonitor;
79
+ private memoryMonitor;
80
+ private startTime;
81
+ private logFn?;
82
+ constructor(logFn?: (level: LogLevel, message: string, meta?: any) => void);
83
+ /**
84
+ * Coleta todas as métricas do sistema
85
+ */
86
+ getSystemMetrics(): SystemMetrics;
87
+ /**
88
+ * Monitora saúde geral do sistema
89
+ */
90
+ getSystemHealth(cpuThreshold?: number, memThreshold?: number): {
91
+ healthy: boolean;
92
+ warnings: string[];
93
+ metrics: SystemMetrics;
94
+ };
95
+ /**
96
+ * Dashboard-friendly summary
97
+ */
98
+ getSummary(): {
99
+ status: string;
100
+ cpu: {
101
+ usage: string;
102
+ cores: number;
103
+ load: {
104
+ oneMinute: number;
105
+ fiveMinutes: number;
106
+ fifteenMinutes: number;
107
+ };
108
+ };
109
+ memory: {
110
+ heap: {
111
+ used: string;
112
+ total: string;
113
+ usage: string;
114
+ };
115
+ system: {
116
+ used: string;
117
+ total: string;
118
+ usage: string;
119
+ };
120
+ };
121
+ warnings: string[];
122
+ };
123
+ }
124
+ //# sourceMappingURL=system-monitor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"system-monitor.d.ts","sourceRoot":"","sources":["../src/system-monitor.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE;QACX,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,EAAE,MAAM,CAAC;QACpB,cAAc,EAAE,MAAM,CAAC;KACxB,CAAC;IACF,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,wBAAwB,EAAE,MAAM,CAAC;CAClC;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,UAAU,CAAC;IAChB,MAAM,EAAE,aAAa,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAO;IAC9C,OAAO,CAAC,YAAY,CAAgB;IACpC,OAAO,CAAC,cAAc,CAAqB;IAC3C,OAAO,CAAC,KAAK,CAAC,CAAyD;gBAE3D,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,KAAK,IAAI;IAK1E,OAAO,CAAC,kBAAkB;IAY1B;;OAEG;IACH,WAAW,IAAI,UAAU;IA4CzB;;OAEG;IACH,iBAAiB,CAAC,SAAS,GAAE,MAAW,GAAG;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;CAmBhF;AAED;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,KAAK,CAAC,CAAyD;gBAE3D,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,KAAK,IAAI;IAI1E;;OAEG;IACH,gBAAgB,IAAI,aAAa;IAsBjC;;OAEG;IACH,oBAAoB,CAAC,SAAS,GAAE,MAAW,GAAG;QAC5C,YAAY,EAAE,OAAO,CAAC;QACtB,cAAc,EAAE,OAAO,CAAC;QACxB,OAAO,EAAE,aAAa,CAAC;KACxB;IAqBD;;OAEG;IACH,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;CAOnC;AAED;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,KAAK,CAAC,CAAyD;gBAE3D,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,KAAK,IAAI;IAM1E;;OAEG;IACH,gBAAgB,IAAI,aAAa;IAQjC;;OAEG;IACH,eAAe,CAAC,YAAY,GAAE,MAAW,EAAE,YAAY,GAAE,MAAW,GAAG;QACrE,OAAO,EAAE,OAAO,CAAC;QACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;QACnB,OAAO,EAAE,aAAa,CAAC;KACxB;IA0BD;;OAEG;IACH,UAAU;;;;;;2BApQG,MAAM;6BACJ,MAAM;gCACH,MAAM;;;;;;;;;;;;;;;;;CA4RzB"}
@@ -0,0 +1,221 @@
1
+ import { cpus, loadavg, totalmem, freemem } from 'os';
2
+ import { performance } from 'perf_hooks';
3
+ /**
4
+ * CPU Monitor - Real-time CPU usage tracking
5
+ */
6
+ export class CPUMonitor {
7
+ static SAMPLE_INTERVAL = 100; // ms
8
+ lastCPUTimes = [];
9
+ lastSampleTime = performance.now();
10
+ logFn;
11
+ constructor(logFn) {
12
+ this.logFn = logFn;
13
+ this.initializeBaseline();
14
+ }
15
+ initializeBaseline() {
16
+ const cpus_info = cpus();
17
+ this.lastCPUTimes = cpus_info.map((cpu) => {
18
+ return (cpu.times.user +
19
+ cpu.times.sys +
20
+ cpu.times.idle +
21
+ cpu.times.irq);
22
+ });
23
+ }
24
+ /**
25
+ * Calcula o uso de CPU em percentual
26
+ */
27
+ getCPUUsage() {
28
+ const cpus_info = cpus();
29
+ const coreCount = cpus_info.length;
30
+ const [one, five, fifteen] = loadavg();
31
+ // Calculate average CPU usage across all cores
32
+ let totalUsage = 0;
33
+ cpus_info.forEach((cpu, index) => {
34
+ const currentTime = cpu.times.user +
35
+ cpu.times.sys +
36
+ cpu.times.idle +
37
+ cpu.times.irq;
38
+ const lastTime = this.lastCPUTimes[index] || currentTime;
39
+ const timeDiff = currentTime - lastTime;
40
+ if (timeDiff > 0) {
41
+ const userTime = cpu.times.user - (this.lastCPUTimes[index] || 0);
42
+ const systemTime = cpu.times.sys - (this.lastCPUTimes[index] || 0);
43
+ const usage = ((userTime + systemTime) / timeDiff) * 100;
44
+ totalUsage += Math.min(100, Math.max(0, usage));
45
+ }
46
+ this.lastCPUTimes[index] = currentTime;
47
+ });
48
+ const averageUsage = totalUsage / coreCount;
49
+ const systemLoadPerCore = one / coreCount;
50
+ return {
51
+ timestamp: Date.now(),
52
+ usage: Math.round(averageUsage * 100) / 100,
53
+ loadAverage: {
54
+ oneMinute: Math.round(one * 100) / 100,
55
+ fiveMinutes: Math.round(five * 100) / 100,
56
+ fifteenMinutes: Math.round(fifteen * 100) / 100,
57
+ },
58
+ coreCount,
59
+ systemLoadPerCore: Math.round(systemLoadPerCore * 100) / 100,
60
+ };
61
+ }
62
+ /**
63
+ * Monitora CPU e alerta se exceder threshold
64
+ */
65
+ checkCPUThreshold(threshold = 80) {
66
+ const metrics = this.getCPUUsage();
67
+ const exceeded = metrics.usage > threshold;
68
+ if (exceeded && this.logFn) {
69
+ // @ts-ignore
70
+ this.logFn(2, `CPU usage exceeded threshold: ${metrics.usage}% > ${threshold}%`, {
71
+ usage: metrics.usage,
72
+ threshold,
73
+ cores: metrics.coreCount,
74
+ systemLoad: metrics.loadAverage,
75
+ });
76
+ }
77
+ return {
78
+ exceeded,
79
+ usage: metrics.usage,
80
+ };
81
+ }
82
+ }
83
+ /**
84
+ * Memory Monitor - Real-time memory usage tracking
85
+ */
86
+ export class MemoryMonitor {
87
+ logFn;
88
+ constructor(logFn) {
89
+ this.logFn = logFn;
90
+ }
91
+ /**
92
+ * Obtém métricas de memória
93
+ */
94
+ getMemoryMetrics() {
95
+ const memUsage = process.memoryUsage();
96
+ const systemTotal = totalmem();
97
+ const systemFree = freemem();
98
+ const systemUsed = systemTotal - systemFree;
99
+ const heapUsagePercent = (memUsage.heapUsed / memUsage.heapTotal) * 100;
100
+ const systemMemoryUsagePercent = (systemUsed / systemTotal) * 100;
101
+ return {
102
+ timestamp: Date.now(),
103
+ heapUsed: memUsage.heapUsed,
104
+ heapTotal: memUsage.heapTotal,
105
+ external: memUsage.external,
106
+ arrayBuffers: memUsage.arrayBuffers || 0,
107
+ heapUsagePercent: Math.round(heapUsagePercent * 100) / 100,
108
+ systemMemoryUsed: systemUsed,
109
+ systemMemoryTotal: systemTotal,
110
+ systemMemoryUsagePercent: Math.round(systemMemoryUsagePercent * 100) / 100,
111
+ };
112
+ }
113
+ /**
114
+ * Verifica se memória excedeu threshold
115
+ */
116
+ checkMemoryThreshold(threshold = 85) {
117
+ const metrics = this.getMemoryMetrics();
118
+ const heapExceeded = metrics.heapUsagePercent > threshold;
119
+ const systemExceeded = metrics.systemMemoryUsagePercent > threshold;
120
+ if ((heapExceeded || systemExceeded) && this.logFn) {
121
+ // @ts-ignore
122
+ this.logFn(2, 'Memory threshold exceeded', {
123
+ heap: `${metrics.heapUsagePercent}% (${Math.round(metrics.heapUsed / 1024 / 1024)}MB)`,
124
+ system: `${metrics.systemMemoryUsagePercent}% (${Math.round(metrics.systemMemoryUsed / 1024 / 1024 / 1024)}GB)`,
125
+ threshold,
126
+ });
127
+ }
128
+ return {
129
+ heapExceeded,
130
+ systemExceeded,
131
+ metrics,
132
+ };
133
+ }
134
+ /**
135
+ * Formata bytes para string legível
136
+ */
137
+ formatBytes(bytes) {
138
+ if (bytes === 0)
139
+ return '0 B';
140
+ const k = 1024;
141
+ const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
142
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
143
+ return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];
144
+ }
145
+ }
146
+ /**
147
+ * System Monitor - Unified system metrics collector
148
+ */
149
+ export class SystemMonitor {
150
+ cpuMonitor;
151
+ memoryMonitor;
152
+ startTime = Date.now();
153
+ logFn;
154
+ constructor(logFn) {
155
+ this.logFn = logFn;
156
+ this.cpuMonitor = new CPUMonitor(logFn);
157
+ this.memoryMonitor = new MemoryMonitor(logFn);
158
+ }
159
+ /**
160
+ * Coleta todas as métricas do sistema
161
+ */
162
+ getSystemMetrics() {
163
+ return {
164
+ cpu: this.cpuMonitor.getCPUUsage(),
165
+ memory: this.memoryMonitor.getMemoryMetrics(),
166
+ uptime: Date.now() - this.startTime,
167
+ };
168
+ }
169
+ /**
170
+ * Monitora saúde geral do sistema
171
+ */
172
+ getSystemHealth(cpuThreshold = 80, memThreshold = 85) {
173
+ const metrics = this.getSystemMetrics();
174
+ const warnings = [];
175
+ const { exceeded: cpuExceeded, usage: cpuUsage } = this.cpuMonitor.checkCPUThreshold(cpuThreshold);
176
+ const { heapExceeded, systemExceeded } = this.memoryMonitor.checkMemoryThreshold(memThreshold);
177
+ if (cpuExceeded) {
178
+ warnings.push(`High CPU usage: ${cpuUsage}% (threshold: ${cpuThreshold}%)`);
179
+ }
180
+ if (heapExceeded) {
181
+ warnings.push(`High heap memory: ${metrics.memory.heapUsagePercent}% (threshold: ${memThreshold}%)`);
182
+ }
183
+ if (systemExceeded) {
184
+ warnings.push(`High system memory: ${metrics.memory.systemMemoryUsagePercent}% (threshold: ${memThreshold}%)`);
185
+ }
186
+ return {
187
+ healthy: warnings.length === 0,
188
+ warnings,
189
+ metrics,
190
+ };
191
+ }
192
+ /**
193
+ * Dashboard-friendly summary
194
+ */
195
+ getSummary() {
196
+ const metrics = this.getSystemMetrics();
197
+ const health = this.getSystemHealth();
198
+ return {
199
+ status: health.healthy ? 'healthy' : 'warning',
200
+ cpu: {
201
+ usage: `${metrics.cpu.usage}%`,
202
+ cores: metrics.cpu.coreCount,
203
+ load: metrics.cpu.loadAverage,
204
+ },
205
+ memory: {
206
+ heap: {
207
+ used: this.memoryMonitor.formatBytes(metrics.memory.heapUsed),
208
+ total: this.memoryMonitor.formatBytes(metrics.memory.heapTotal),
209
+ usage: `${metrics.memory.heapUsagePercent}%`,
210
+ },
211
+ system: {
212
+ used: this.memoryMonitor.formatBytes(metrics.memory.systemMemoryUsed),
213
+ total: this.memoryMonitor.formatBytes(metrics.memory.systemMemoryTotal),
214
+ usage: `${metrics.memory.systemMemoryUsagePercent}%`,
215
+ },
216
+ },
217
+ warnings: health.warnings,
218
+ };
219
+ }
220
+ }
221
+ //# sourceMappingURL=system-monitor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"system-monitor.js","sourceRoot":"","sources":["../src/system-monitor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ export declare enum LogLevel {
2
+ DEBUG = 0,
3
+ INFO = 1,
4
+ WARN = 2,
5
+ ERROR = 3
6
+ }
7
+ export declare enum ExporterType {
8
+ OTLP_HTTP = "otlp-http",
9
+ VERCEL = "vercel",
10
+ NONE = "none"
11
+ }
12
+ export interface RetryPolicy {
13
+ maxRetries: number;
14
+ initialDelayMs: number;
15
+ maxDelayMs: number;
16
+ backoffMultiplier: number;
17
+ randomizationFactor: number;
18
+ }
19
+ export interface ExporterConfig {
20
+ type: ExporterType;
21
+ url?: string;
22
+ headers?: Record<string, string>;
23
+ batchSize?: number;
24
+ batchTimeoutMs?: number;
25
+ }
26
+ export interface NextDoctorConfig {
27
+ projectToken: string;
28
+ endpoint: string;
29
+ enabled?: boolean;
30
+ serviceName?: string;
31
+ version?: string;
32
+ environment?: 'development' | 'staging' | 'production';
33
+ logLevel?: LogLevel;
34
+ exporter?: ExporterConfig;
35
+ retryPolicy?: Partial<RetryPolicy>;
36
+ captureLogs?: boolean;
37
+ captureMetrics?: boolean;
38
+ captureExceptions?: boolean;
39
+ samplingRate?: number;
40
+ enableDebugLogging?: boolean;
41
+ timeout?: number;
42
+ }
43
+ export interface DetectedIssue {
44
+ id: string;
45
+ severity: 'info' | 'warning' | 'high' | 'critical';
46
+ message: string;
47
+ suggestion: string;
48
+ route?: string;
49
+ spanId?: string;
50
+ attributes?: Record<string, unknown>;
51
+ detectedAt: number;
52
+ }
53
+ export interface AgentHealth {
54
+ initialized: boolean;
55
+ isHealthy: boolean;
56
+ lastHealthCheckAt?: number;
57
+ exporterStatus: 'healthy' | 'degraded' | 'unreachable';
58
+ bufferedSpans: number;
59
+ errorCount: number;
60
+ }
61
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,oBAAY,QAAQ;IAClB,KAAK,IAAI;IACT,IAAI,IAAI;IACR,IAAI,IAAI;IACR,KAAK,IAAI;CACV;AAED,oBAAY,YAAY;IACtB,SAAS,cAAc;IACvB,MAAM,WAAW;IACjB,IAAI,SAAS;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,YAAY,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,aAAa,GAAG,SAAS,GAAG,YAAY,CAAC;IACvD,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,WAAW,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IACnC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,UAAU,CAAC;IACnD,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,OAAO,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,EAAE,SAAS,GAAG,UAAU,GAAG,aAAa,CAAC;IACvD,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB"}
package/dist/types.js ADDED
@@ -0,0 +1,14 @@
1
+ export var LogLevel;
2
+ (function (LogLevel) {
3
+ LogLevel[LogLevel["DEBUG"] = 0] = "DEBUG";
4
+ LogLevel[LogLevel["INFO"] = 1] = "INFO";
5
+ LogLevel[LogLevel["WARN"] = 2] = "WARN";
6
+ LogLevel[LogLevel["ERROR"] = 3] = "ERROR";
7
+ })(LogLevel || (LogLevel = {}));
8
+ export var ExporterType;
9
+ (function (ExporterType) {
10
+ ExporterType["OTLP_HTTP"] = "otlp-http";
11
+ ExporterType["VERCEL"] = "vercel";
12
+ ExporterType["NONE"] = "none";
13
+ })(ExporterType || (ExporterType = {}));
14
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,QAKX;AALD,WAAY,QAAQ;IAClB,yCAAS,CAAA;IACT,uCAAQ,CAAA;IACR,uCAAQ,CAAA;IACR,yCAAS,CAAA;AACX,CAAC,EALW,QAAQ,KAAR,QAAQ,QAKnB;AAED,MAAM,CAAN,IAAY,YAIX;AAJD,WAAY,YAAY;IACtB,uCAAuB,CAAA;IACvB,iCAAiB,CAAA;IACjB,6BAAa,CAAA;AACf,CAAC,EAJW,YAAY,KAAZ,YAAY,QAIvB"}
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@codebaz/nextdoctor-agent",
3
+ "version": "0.1.0-beta.1",
4
+ "type": "module",
5
+ "description": "NextDoctor agent for OpenTelemetry tracing and performance monitoring",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ },
13
+ "./middleware": {
14
+ "types": "./dist/middleware.d.ts",
15
+ "import": "./dist/middleware.js"
16
+ },
17
+ "./optimization": {
18
+ "types": "./dist/optimization.d.ts",
19
+ "import": "./dist/optimization.js"
20
+ },
21
+ "./system-monitor": {
22
+ "types": "./dist/system-monitor.d.ts",
23
+ "import": "./dist/system-monitor.js"
24
+ }
25
+ },
26
+ "dependencies": {
27
+ "@opentelemetry/api": "^1.9.1",
28
+ "@opentelemetry/auto-instrumentations-node": "^0.72.0",
29
+ "@opentelemetry/core": "^2.6.1",
30
+ "@opentelemetry/exporter-otlp-http": "^0.26.0",
31
+ "@opentelemetry/instrumentation": "^0.214.0",
32
+ "@opentelemetry/instrumentation-http": "^0.214.0",
33
+ "@opentelemetry/sdk-node": "^0.214.0",
34
+ "@opentelemetry/sdk-trace-base": "^2.6.1",
35
+ "@opentelemetry/sdk-trace-node": "^2.6.1",
36
+ "@vercel/otel": "^2.1.1"
37
+ },
38
+ "devDependencies": {
39
+ "@types/node": "^20.11.0",
40
+ "eslint": "^9.0.0",
41
+ "typescript": "^5.9.3",
42
+ "vitest": "^1.5.0",
43
+ "@workspace/typescript-config": "0.0.0",
44
+ "@workspace/eslint-config": "0.0.0"
45
+ },
46
+ "peerDependencies": {
47
+ "next": ">=14.0.0"
48
+ },
49
+ "scripts": {
50
+ "dev": "tsc --watch",
51
+ "build": "tsc --build",
52
+ "test": "vitest",
53
+ "lint": "eslint . --ext .ts"
54
+ }
55
+ }
@@ -0,0 +1,183 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import type { ReadableSpan } from '@opentelemetry/sdk-trace-base';
3
+ import { ColdStartThresholdDetector } from '../cold-start-threshold.detector.js';
4
+
5
+ function createMockSpan(overrides: Partial<ReadableSpan> = {}): ReadableSpan {
6
+ const defaultStartTime: [number, number] = [Math.floor(Date.now() / 1000), 0];
7
+ const defaultEndTime: [number, number] = [
8
+ defaultStartTime[0],
9
+ defaultStartTime[1] + 100_000_000, // 100ms
10
+ ];
11
+
12
+ return {
13
+ name: 'http.request',
14
+ spanContext: () => ({
15
+ traceId: 'test-trace',
16
+ spanId: 'test-span-' + Math.random().toString(36).substr(2, 9),
17
+ traceFlags: 0x01,
18
+ traceState: undefined,
19
+ isRecording: true,
20
+ }),
21
+ parentSpanId: undefined,
22
+ startTime: defaultStartTime,
23
+ endTime: defaultEndTime,
24
+ attributes: {
25
+ 'http.route': '/api/test',
26
+ ...overrides.attributes,
27
+ },
28
+ links: [],
29
+ events: [],
30
+ status: { code: 0 },
31
+ instrumentationLibrary: {
32
+ name: 'nextdoctor',
33
+ version: '0.1.0',
34
+ },
35
+ resource: {
36
+ attributes: {},
37
+ },
38
+ duration: defaultEndTime,
39
+ ended: true,
40
+ ...overrides,
41
+ } as ReadableSpan;
42
+ }
43
+
44
+ describe('ColdStartThresholdDetector', () => {
45
+ const detector = new ColdStartThresholdDetector();
46
+
47
+ it('detects cold start above threshold (800ms)', () => {
48
+ const issues = detector.detect([], {
49
+ runtime: 'edge',
50
+ startupTimeMs: 1200,
51
+ });
52
+
53
+ expect(issues).toHaveLength(1);
54
+ expect(issues[0]!.id).toBe('COLD_START_THRESHOLD');
55
+ expect(issues[0]!.severity).toBe('critical');
56
+ expect(issues[0]!.message).toContain('1200ms');
57
+ expect(issues[0]!.message).toContain('800ms');
58
+ });
59
+
60
+ it('ignores cold start below threshold', () => {
61
+ const issues = detector.detect([], {
62
+ runtime: 'edge',
63
+ startupTimeMs: 500,
64
+ });
65
+
66
+ expect(issues).toHaveLength(0);
67
+ });
68
+
69
+ it('detects cold start exactly at threshold', () => {
70
+ const issues = detector.detect([], {
71
+ runtime: 'edge',
72
+ startupTimeMs: 800,
73
+ });
74
+
75
+ // At threshold should pass (not exceed)
76
+ expect(issues).toHaveLength(0);
77
+ });
78
+
79
+ it('fires with 20+ spans when P99 - P50 > 2000ms', () => {
80
+ const spans = Array.from({ length: 20 }).map((_, i) => {
81
+ const durationNano = i < 10
82
+ ? 100_000_000 // 100ms (P50)
83
+ : 2500_000_000; // 2500ms (P99)
84
+
85
+ return createMockSpan({
86
+ name: 'http.request',
87
+ attributes: {
88
+ 'http.route': '/api/users',
89
+ },
90
+ startTime: [1000, 0],
91
+ endTime: [1000, durationNano],
92
+ spanContext: () => ({
93
+ traceId: 'test-trace',
94
+ spanId: `span-${i}`,
95
+ traceFlags: 0x01,
96
+ traceState: undefined,
97
+ isRecording: true,
98
+ }),
99
+ });
100
+ });
101
+
102
+ const issues = detector.detect(spans, {
103
+ runtime: 'edge',
104
+ route: '/api/users',
105
+ });
106
+
107
+ expect(issues.some(i => i.id === 'COLD_START_INTERMITTENT')).toBe(true);
108
+ const issue = issues.find(i => i.id === 'COLD_START_INTERMITTENT');
109
+ expect(issue?.severity).toBe('warning');
110
+ expect(issue?.message).toContain('high latency variance');
111
+ });
112
+
113
+ it('ignores low variance', () => {
114
+ const spans = Array.from({ length: 20 }).map((_, i) =>
115
+ createMockSpan({
116
+ name: 'http.request',
117
+ attributes: {
118
+ 'http.route': '/api/test',
119
+ },
120
+ startTime: [1000, 0],
121
+ endTime: [1000, 100_000_000 + i * 10_000_000], // 100-190ms range
122
+ spanContext: () => ({
123
+ traceId: 'test-trace',
124
+ spanId: `span-${i}`,
125
+ traceFlags: 0x01,
126
+ traceState: undefined,
127
+ isRecording: true,
128
+ }),
129
+ })
130
+ );
131
+
132
+ const issues = detector.detect(spans, {
133
+ runtime: 'edge',
134
+ route: '/api/test',
135
+ });
136
+
137
+ expect(issues.filter(i => i.id === 'COLD_START_INTERMITTENT')).toHaveLength(0);
138
+ });
139
+
140
+ it('does not fire with fewer than 20 spans for variance calculation', () => {
141
+ const spans = Array.from({ length: 19 }).map((_, i) =>
142
+ createMockSpan({
143
+ startTime: [1000, 0],
144
+ endTime: [1000, i < 2 ? 100_000_000 : 3000_000_000],
145
+ spanContext: () => ({
146
+ traceId: 'test-trace',
147
+ spanId: `span-${i}`,
148
+ traceFlags: 0x01,
149
+ traceState: undefined,
150
+ isRecording: true,
151
+ }),
152
+ })
153
+ );
154
+
155
+ const issues = detector.detect(spans, {
156
+ runtime: 'edge',
157
+ route: '/api/test',
158
+ });
159
+
160
+ expect(issues.every(i => i.id !== 'COLD_START_INTERMITTENT')).toBe(true);
161
+ });
162
+
163
+ it('includes suggestions in issue', () => {
164
+ const issues = detector.detect([], {
165
+ runtime: 'edge',
166
+ startupTimeMs: 1200,
167
+ });
168
+
169
+ expect(issues[0]!.suggestion).toContain('import');
170
+ expect(issues[0]!.suggestion).toContain('runtime');
171
+ });
172
+
173
+ it('includes attributes with threshold data', () => {
174
+ const issues = detector.detect([], {
175
+ runtime: 'edge',
176
+ startupTimeMs: 1200,
177
+ });
178
+
179
+ expect(issues[0]!.attributes?.startupTimeMs).toBe(1200);
180
+ expect(issues[0]!.attributes?.threshold).toBe(800);
181
+ expect(issues[0]!.attributes?.runtime).toBe('edge');
182
+ });
183
+ });