@devilsdev/rag-pipeline-utils 2.2.1 → 2.3.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.
Files changed (40) hide show
  1. package/README.md +244 -11
  2. package/contracts/contract-schema.json +189 -0
  3. package/dist/index.cjs +19 -0
  4. package/dist/index.mjs +15 -1
  5. package/package.json +3 -2
  6. package/src/cli/commands/wizard.js +627 -0
  7. package/src/cli/input-sanitization-middleware.js +356 -0
  8. package/src/cli/templates/development.template.json +64 -0
  9. package/src/cli/templates/minimal.template.json +33 -0
  10. package/src/cli/templates/production.template.json +104 -0
  11. package/src/cli/templates/testing.template.json +45 -0
  12. package/src/config/connection-pool-config.json +259 -0
  13. package/src/config/memory-optimization.js +414 -0
  14. package/src/config/redaction-patterns.json +150 -0
  15. package/src/config/sanitization-rules.json +323 -0
  16. package/src/core/plugin-registry.js +266 -20
  17. package/src/dag/core/error-context.js +391 -0
  18. package/src/dag/core/execution-scheduler.js +350 -0
  19. package/src/dag/core/topology-validation.js +415 -0
  20. package/src/dag/dag-engine.js +26 -424
  21. package/src/dev/README.md +126 -0
  22. package/src/dev/dev-server.js +356 -0
  23. package/src/dev/examples/hot-reload-usage.js +355 -0
  24. package/src/dev/hot-reload.js +807 -0
  25. package/src/enterprise/sso-integration.js +67 -25
  26. package/src/index.js +19 -0
  27. package/src/observability/event-logger.js +62 -2
  28. package/src/plugins/optimized-openai-embedder.js +169 -0
  29. package/src/security/jwt-config.js +431 -0
  30. package/src/security/jwt-validator.js +701 -0
  31. package/src/utils/api-client-pool-integration.js +436 -0
  32. package/src/utils/batch-processor.js +710 -0
  33. package/src/utils/connection-pool.js +605 -0
  34. package/src/utils/contract-validator.js +460 -0
  35. package/src/utils/error-formatter.js +603 -0
  36. package/src/utils/examples/error-formatter-usage.js +351 -0
  37. package/src/utils/input-sanitizer.js +967 -0
  38. package/src/utils/memory-monitor.js +800 -0
  39. package/src/utils/secure-logger-config.js +352 -0
  40. package/src/utils/secure-logger.js +576 -0
@@ -0,0 +1,800 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Enhanced Memory Monitor
5
+ *
6
+ * Advanced memory monitoring with leak detection, historical tracking,
7
+ * GC optimization, and actionable insights for long-running processes.
8
+ *
9
+ * Features:
10
+ * - Real-time memory usage tracking
11
+ * - Memory leak detection with trend analysis
12
+ * - Historical memory tracking with snapshots
13
+ * - GC optimization recommendations
14
+ * - Performance overhead measurement (<5%)
15
+ * - Actionable memory metrics
16
+ * - Integration with existing backpressure systems
17
+ *
18
+ * @module utils/memory-monitor
19
+ * @since 2.3.0
20
+ */
21
+
22
+ const { EventEmitter } = require('events');
23
+ const { performance } = require('perf_hooks');
24
+
25
+ /**
26
+ * Default configuration for memory monitoring
27
+ */
28
+ const DEFAULT_CONFIG = {
29
+ // Memory limits
30
+ maxMemoryMB: 512,
31
+ warningThreshold: 0.75, // 75% of max memory
32
+ criticalThreshold: 0.9, // 90% of max memory
33
+
34
+ // Sampling and history
35
+ samplingInterval: 5000, // Sample every 5 seconds
36
+ historySize: 100, // Keep last 100 samples
37
+ snapshotInterval: 60000, // Snapshot every minute
38
+
39
+ // Leak detection
40
+ leakDetectionEnabled: true,
41
+ leakThreshold: 5, // 5 consecutive increases = leak
42
+ leakRateThreshold: 0.05, // 5% growth per sample = leak
43
+
44
+ // GC hints
45
+ gcHintsEnabled: true,
46
+ gcThreshold: 0.85, // Suggest GC at 85%
47
+ autoGC: false, // Auto-trigger GC (requires --expose-gc)
48
+
49
+ // Performance
50
+ enableDetailedMetrics: true,
51
+ trackPerformanceOverhead: true,
52
+ };
53
+
54
+ /**
55
+ * Memory snapshot for historical tracking
56
+ */
57
+ class MemorySnapshot {
58
+ constructor(usage, timestamp = Date.now()) {
59
+ this.timestamp = timestamp;
60
+ this.heapUsed = usage.heapUsed;
61
+ this.heapTotal = usage.heapTotal;
62
+ this.external = usage.external;
63
+ this.rss = usage.rss;
64
+ this.arrayBuffers = usage.arrayBuffers || 0;
65
+ }
66
+
67
+ toJSON() {
68
+ return {
69
+ timestamp: this.timestamp,
70
+ heapUsedMB: Math.round(this.heapUsed / 1024 / 1024),
71
+ heapTotalMB: Math.round(this.heapTotal / 1024 / 1024),
72
+ externalMB: Math.round(this.external / 1024 / 1024),
73
+ rssMB: Math.round(this.rss / 1024 / 1024),
74
+ };
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Memory leak detector
80
+ */
81
+ class MemoryLeakDetector {
82
+ constructor(options = {}) {
83
+ this.leakThreshold = options.leakThreshold || 5;
84
+ this.leakRateThreshold = options.leakRateThreshold || 0.05;
85
+ this.consecutiveIncreases = 0;
86
+ this.lastHeapUsed = 0;
87
+ this.leakDetected = false;
88
+ this.leakHistory = [];
89
+ }
90
+
91
+ /**
92
+ * Analyze memory trend for leaks
93
+ *
94
+ * @param {number} currentHeapUsed - Current heap usage in bytes
95
+ * @returns {Object} Leak analysis result
96
+ */
97
+ analyze(currentHeapUsed) {
98
+ if (this.lastHeapUsed === 0) {
99
+ this.lastHeapUsed = currentHeapUsed;
100
+ return {
101
+ leakDetected: false,
102
+ consecutiveIncreases: 0,
103
+ increase: 0,
104
+ increaseRate: 0,
105
+ confidence: 0,
106
+ };
107
+ }
108
+
109
+ const increase = currentHeapUsed - this.lastHeapUsed;
110
+ const increaseRate = increase / this.lastHeapUsed;
111
+
112
+ if (increase > 0 && increaseRate > this.leakRateThreshold) {
113
+ this.consecutiveIncreases++;
114
+
115
+ // Record leak event
116
+ this.leakHistory.push({
117
+ timestamp: Date.now(),
118
+ heapUsed: currentHeapUsed,
119
+ increase,
120
+ increaseRate: increaseRate * 100,
121
+ });
122
+
123
+ // Keep only recent history
124
+ if (this.leakHistory.length > 50) {
125
+ this.leakHistory.shift();
126
+ }
127
+
128
+ // Detect leak
129
+ if (this.consecutiveIncreases >= this.leakThreshold) {
130
+ this.leakDetected = true;
131
+ }
132
+ } else {
133
+ this.consecutiveIncreases = Math.max(0, this.consecutiveIncreases - 1);
134
+ if (this.consecutiveIncreases === 0) {
135
+ this.leakDetected = false;
136
+ }
137
+ }
138
+
139
+ this.lastHeapUsed = currentHeapUsed;
140
+
141
+ return {
142
+ leakDetected: this.leakDetected,
143
+ consecutiveIncreases: this.consecutiveIncreases,
144
+ leakThreshold: this.leakThreshold,
145
+ increase,
146
+ increaseRate: increaseRate * 100,
147
+ confidence: Math.min(
148
+ 100,
149
+ (this.consecutiveIncreases / this.leakThreshold) * 100,
150
+ ),
151
+ };
152
+ }
153
+
154
+ /**
155
+ * Get leak trend analysis
156
+ */
157
+ getTrend() {
158
+ if (this.leakHistory.length < 2) {
159
+ return { trend: 'unknown', averageGrowthRate: 0 };
160
+ }
161
+
162
+ const recentHistory = this.leakHistory.slice(-10);
163
+ const avgGrowthRate =
164
+ recentHistory.reduce((sum, h) => sum + h.increaseRate, 0) /
165
+ recentHistory.length;
166
+
167
+ return {
168
+ trend:
169
+ avgGrowthRate > this.leakRateThreshold * 100 ? 'increasing' : 'stable',
170
+ averageGrowthRate: avgGrowthRate,
171
+ sampleCount: recentHistory.length,
172
+ };
173
+ }
174
+
175
+ /**
176
+ * Reset leak detector
177
+ */
178
+ reset() {
179
+ this.consecutiveIncreases = 0;
180
+ this.lastHeapUsed = 0;
181
+ this.leakDetected = false;
182
+ this.leakHistory = [];
183
+ }
184
+ }
185
+
186
+ /**
187
+ * GC optimizer
188
+ */
189
+ class GCOptimizer {
190
+ constructor(options = {}) {
191
+ this.gcThreshold = options.gcThreshold || 0.85;
192
+ this.autoGC = options.autoGC || false;
193
+ this.gcHistory = [];
194
+ this.lastGCTime = 0;
195
+ this.minGCInterval = 30000; // Minimum 30s between GCs
196
+ }
197
+
198
+ /**
199
+ * Analyze if GC should be triggered
200
+ *
201
+ * @param {number} memoryRatio - Current memory usage ratio
202
+ * @param {Object} usage - Memory usage object
203
+ * @returns {Object} GC recommendation
204
+ */
205
+ analyze(memoryRatio, usage) {
206
+ const now = Date.now();
207
+ const timeSinceLastGC = now - this.lastGCTime;
208
+
209
+ const shouldTriggerGC =
210
+ memoryRatio > this.gcThreshold && timeSinceLastGC > this.minGCInterval;
211
+
212
+ const recommendation = {
213
+ shouldTriggerGC,
214
+ reason: null,
215
+ canAutoGC: global.gc !== undefined,
216
+ timeSinceLastGC,
217
+ };
218
+
219
+ if (shouldTriggerGC) {
220
+ recommendation.reason = `Memory usage at ${(memoryRatio * 100).toFixed(1)}% (threshold: ${(this.gcThreshold * 100).toFixed(1)}%)`;
221
+
222
+ if (this.autoGC && global.gc) {
223
+ this.triggerGC();
224
+ recommendation.gcTriggered = true;
225
+ }
226
+ }
227
+
228
+ return recommendation;
229
+ }
230
+
231
+ /**
232
+ * Trigger garbage collection
233
+ */
234
+ triggerGC() {
235
+ if (!global.gc) {
236
+ return { triggered: false, reason: 'GC not exposed' };
237
+ }
238
+
239
+ const before = process.memoryUsage();
240
+ const startTime = performance.now();
241
+
242
+ try {
243
+ global.gc();
244
+
245
+ const after = process.memoryUsage();
246
+ const duration = performance.now() - startTime;
247
+ const freed = before.heapUsed - after.heapUsed;
248
+
249
+ this.lastGCTime = Date.now();
250
+
251
+ this.gcHistory.push({
252
+ timestamp: this.lastGCTime,
253
+ duration,
254
+ freedMB: Math.round(freed / 1024 / 1024),
255
+ heapBefore: Math.round(before.heapUsed / 1024 / 1024),
256
+ heapAfter: Math.round(after.heapUsed / 1024 / 1024),
257
+ });
258
+
259
+ // Keep only recent history
260
+ if (this.gcHistory.length > 50) {
261
+ this.gcHistory.shift();
262
+ }
263
+
264
+ return {
265
+ triggered: true,
266
+ duration,
267
+ freedMB: Math.round(freed / 1024 / 1024),
268
+ };
269
+ } catch (error) {
270
+ return { triggered: false, error: error.message };
271
+ }
272
+ }
273
+
274
+ /**
275
+ * Get GC statistics
276
+ */
277
+ getStats() {
278
+ if (this.gcHistory.length === 0) {
279
+ return { gcCount: 0 };
280
+ }
281
+
282
+ const avgDuration =
283
+ this.gcHistory.reduce((sum, gc) => sum + gc.duration, 0) /
284
+ this.gcHistory.length;
285
+ const totalFreed = this.gcHistory.reduce((sum, gc) => sum + gc.freedMB, 0);
286
+
287
+ return {
288
+ gcCount: this.gcHistory.length,
289
+ avgDuration: avgDuration.toFixed(2),
290
+ totalFreedMB: totalFreed,
291
+ avgFreedMB: (totalFreed / this.gcHistory.length).toFixed(2),
292
+ lastGC: this.gcHistory[this.gcHistory.length - 1],
293
+ };
294
+ }
295
+ }
296
+
297
+ /**
298
+ * Enhanced Memory Monitor Class
299
+ */
300
+ class EnhancedMemoryMonitor extends EventEmitter {
301
+ constructor(options = {}) {
302
+ super();
303
+
304
+ this.config = {
305
+ ...DEFAULT_CONFIG,
306
+ ...options,
307
+ };
308
+
309
+ // State
310
+ this.monitoring = false;
311
+ this.samplingInterval = null;
312
+ this.snapshotInterval = null;
313
+
314
+ // History
315
+ this.history = [];
316
+ this.snapshots = [];
317
+
318
+ // Components
319
+ this.leakDetector = new MemoryLeakDetector({
320
+ leakThreshold: this.config.leakThreshold,
321
+ leakRateThreshold: this.config.leakRateThreshold,
322
+ });
323
+
324
+ this.gcOptimizer = new GCOptimizer({
325
+ gcThreshold: this.config.gcThreshold,
326
+ autoGC: this.config.autoGC,
327
+ });
328
+
329
+ // Metrics
330
+ this.metrics = {
331
+ totalSamples: 0,
332
+ totalSnapshots: 0,
333
+ warningCount: 0,
334
+ criticalCount: 0,
335
+ leakDetections: 0,
336
+ gcSuggestions: 0,
337
+ gcTriggers: 0,
338
+ overheadMs: 0,
339
+ };
340
+
341
+ // Performance overhead tracking
342
+ this.overheadSamples = [];
343
+ }
344
+
345
+ /**
346
+ * Start monitoring
347
+ */
348
+ start() {
349
+ if (this.monitoring) {
350
+ return;
351
+ }
352
+
353
+ this.monitoring = true;
354
+ this.emit('start');
355
+
356
+ // Start sampling
357
+ this.samplingInterval = setInterval(() => {
358
+ this._sample();
359
+ }, this.config.samplingInterval);
360
+
361
+ // Start snapshots
362
+ if (this.config.snapshotInterval > 0) {
363
+ this.snapshotInterval = setInterval(() => {
364
+ this._takeSnapshot();
365
+ }, this.config.snapshotInterval);
366
+ }
367
+
368
+ // Don't keep process alive
369
+ if (this.samplingInterval.unref) {
370
+ this.samplingInterval.unref();
371
+ }
372
+ if (this.snapshotInterval && this.snapshotInterval.unref) {
373
+ this.snapshotInterval.unref();
374
+ }
375
+
376
+ // Take initial snapshot
377
+ this._takeSnapshot();
378
+ }
379
+
380
+ /**
381
+ * Stop monitoring
382
+ */
383
+ stop() {
384
+ if (!this.monitoring) {
385
+ return;
386
+ }
387
+
388
+ this.monitoring = false;
389
+
390
+ if (this.samplingInterval) {
391
+ clearInterval(this.samplingInterval);
392
+ this.samplingInterval = null;
393
+ }
394
+
395
+ if (this.snapshotInterval) {
396
+ clearInterval(this.snapshotInterval);
397
+ this.snapshotInterval = null;
398
+ }
399
+
400
+ this.emit('stop');
401
+ }
402
+
403
+ /**
404
+ * Take a memory sample
405
+ * @private
406
+ */
407
+ _sample() {
408
+ const startTime = performance.now();
409
+
410
+ try {
411
+ const usage = this._getMemoryUsage();
412
+ const maxMemoryBytes = this.config.maxMemoryMB * 1024 * 1024;
413
+ const ratio = usage.heapUsed / maxMemoryBytes;
414
+
415
+ // Add to history
416
+ this.history.push({
417
+ timestamp: Date.now(),
418
+ ...usage,
419
+ ratio,
420
+ });
421
+
422
+ // Trim history
423
+ if (this.history.length > this.config.historySize) {
424
+ this.history.shift();
425
+ }
426
+
427
+ this.metrics.totalSamples++;
428
+
429
+ // Check thresholds
430
+ if (ratio > this.config.criticalThreshold) {
431
+ this.metrics.criticalCount++;
432
+ this.emit('critical', {
433
+ ratio,
434
+ heapUsedMB: Math.round(usage.heapUsed / 1024 / 1024),
435
+ maxMemoryMB: this.config.maxMemoryMB,
436
+ });
437
+ } else if (ratio > this.config.warningThreshold) {
438
+ this.metrics.warningCount++;
439
+ this.emit('warning', {
440
+ ratio,
441
+ heapUsedMB: Math.round(usage.heapUsed / 1024 / 1024),
442
+ maxMemoryMB: this.config.maxMemoryMB,
443
+ });
444
+ }
445
+
446
+ // Leak detection
447
+ if (this.config.leakDetectionEnabled) {
448
+ const leakAnalysis = this.leakDetector.analyze(usage.heapUsed);
449
+
450
+ if (leakAnalysis.leakDetected && this.metrics.leakDetections === 0) {
451
+ this.metrics.leakDetections++;
452
+ this.emit('leak_detected', {
453
+ ...leakAnalysis,
454
+ heapUsedMB: Math.round(usage.heapUsed / 1024 / 1024),
455
+ trend: this.leakDetector.getTrend(),
456
+ });
457
+ }
458
+ }
459
+
460
+ // GC optimization
461
+ if (this.config.gcHintsEnabled) {
462
+ const gcAnalysis = this.gcOptimizer.analyze(ratio, usage);
463
+
464
+ if (gcAnalysis.shouldTriggerGC) {
465
+ this.metrics.gcSuggestions++;
466
+
467
+ if (gcAnalysis.gcTriggered) {
468
+ this.metrics.gcTriggers++;
469
+ this.emit('gc_triggered', gcAnalysis);
470
+ } else {
471
+ this.emit('gc_suggested', gcAnalysis);
472
+ }
473
+ }
474
+ }
475
+
476
+ // Track overhead
477
+ const overhead = performance.now() - startTime;
478
+ this.overheadSamples.push(overhead);
479
+ if (this.overheadSamples.length > 100) {
480
+ this.overheadSamples.shift();
481
+ }
482
+ this.metrics.overheadMs =
483
+ this.overheadSamples.reduce((a, b) => a + b, 0) /
484
+ this.overheadSamples.length;
485
+
486
+ this.emit('sample', {
487
+ usage,
488
+ ratio,
489
+ timestamp: Date.now(),
490
+ });
491
+ } catch (error) {
492
+ this.emit('error', error);
493
+ }
494
+ }
495
+
496
+ /**
497
+ * Take a memory snapshot
498
+ * @private
499
+ */
500
+ _takeSnapshot() {
501
+ try {
502
+ const usage = this._getMemoryUsage();
503
+ const snapshot = new MemorySnapshot(usage);
504
+
505
+ this.snapshots.push(snapshot);
506
+
507
+ // Trim snapshots
508
+ if (this.snapshots.length > 100) {
509
+ this.snapshots.shift();
510
+ }
511
+
512
+ this.metrics.totalSnapshots++;
513
+
514
+ this.emit('snapshot', snapshot);
515
+ } catch (error) {
516
+ this.emit('error', error);
517
+ }
518
+ }
519
+
520
+ /**
521
+ * Get current memory usage
522
+ * @private
523
+ */
524
+ _getMemoryUsage() {
525
+ if (typeof process.memoryUsage === 'function') {
526
+ return process.memoryUsage();
527
+ }
528
+
529
+ // Fallback for environments without process.memoryUsage
530
+ return {
531
+ heapUsed: 0,
532
+ heapTotal: 0,
533
+ external: 0,
534
+ rss: 0,
535
+ arrayBuffers: 0,
536
+ };
537
+ }
538
+
539
+ /**
540
+ * Get current memory metrics
541
+ */
542
+ getMetrics() {
543
+ const usage = this._getMemoryUsage();
544
+ const maxMemoryBytes = this.config.maxMemoryMB * 1024 * 1024;
545
+ const ratio = usage.heapUsed / maxMemoryBytes;
546
+
547
+ return {
548
+ // Current usage
549
+ current: {
550
+ heapUsedMB: Math.round(usage.heapUsed / 1024 / 1024),
551
+ heapTotalMB: Math.round(usage.heapTotal / 1024 / 1024),
552
+ externalMB: Math.round(usage.external / 1024 / 1024),
553
+ rssMB: Math.round(usage.rss / 1024 / 1024),
554
+ ratio: ratio,
555
+ percentage: Math.round(ratio * 100),
556
+ },
557
+
558
+ // Thresholds
559
+ thresholds: {
560
+ warning: this.config.warningThreshold,
561
+ critical: this.config.criticalThreshold,
562
+ maxMemoryMB: this.config.maxMemoryMB,
563
+ },
564
+
565
+ // Status
566
+ status:
567
+ ratio > this.config.criticalThreshold
568
+ ? 'critical'
569
+ : ratio > this.config.warningThreshold
570
+ ? 'warning'
571
+ : 'normal',
572
+
573
+ // Statistics
574
+ stats: {
575
+ ...this.metrics,
576
+ historySize: this.history.length,
577
+ snapshotCount: this.snapshots.length,
578
+ },
579
+
580
+ // Leak detection
581
+ leak: this.config.leakDetectionEnabled
582
+ ? {
583
+ detected: this.leakDetector.leakDetected,
584
+ consecutiveIncreases: this.leakDetector.consecutiveIncreases,
585
+ confidence: Math.min(
586
+ 100,
587
+ (this.leakDetector.consecutiveIncreases /
588
+ this.leakDetector.leakThreshold) *
589
+ 100,
590
+ ),
591
+ trend: this.leakDetector.getTrend(),
592
+ }
593
+ : null,
594
+
595
+ // GC stats
596
+ gc: this.config.gcHintsEnabled ? this.gcOptimizer.getStats() : null,
597
+
598
+ // Performance overhead
599
+ overhead: {
600
+ avgMs: this.metrics.overheadMs.toFixed(3),
601
+ percentage: (
602
+ (this.metrics.overheadMs / this.config.samplingInterval) *
603
+ 100
604
+ ).toFixed(2),
605
+ },
606
+ };
607
+ }
608
+
609
+ /**
610
+ * Get memory history
611
+ */
612
+ getHistory() {
613
+ return this.history.map((h) => ({
614
+ timestamp: h.timestamp,
615
+ heapUsedMB: Math.round(h.heapUsed / 1024 / 1024),
616
+ heapTotalMB: Math.round(h.heapTotal / 1024 / 1024),
617
+ ratio: h.ratio,
618
+ }));
619
+ }
620
+
621
+ /**
622
+ * Get memory snapshots
623
+ */
624
+ getSnapshots() {
625
+ return this.snapshots.map((s) => s.toJSON());
626
+ }
627
+
628
+ /**
629
+ * Get actionable recommendations
630
+ */
631
+ getRecommendations() {
632
+ const metrics = this.getMetrics();
633
+ const recommendations = [];
634
+
635
+ // High memory usage
636
+ if (metrics.status === 'critical') {
637
+ recommendations.push({
638
+ priority: 'high',
639
+ category: 'memory',
640
+ message: `Critical memory usage: ${metrics.current.percentage}%`,
641
+ action:
642
+ 'Reduce batch sizes, implement streaming, or increase memory limit',
643
+ });
644
+ } else if (metrics.status === 'warning') {
645
+ recommendations.push({
646
+ priority: 'medium',
647
+ category: 'memory',
648
+ message: `High memory usage: ${metrics.current.percentage}%`,
649
+ action: 'Monitor closely and consider optimizations',
650
+ });
651
+ }
652
+
653
+ // Memory leak
654
+ if (metrics.leak && metrics.leak.detected) {
655
+ recommendations.push({
656
+ priority: 'high',
657
+ category: 'leak',
658
+ message: `Memory leak detected with ${metrics.leak.confidence.toFixed(0)}% confidence`,
659
+ action:
660
+ 'Investigate increasing memory trend. Check for unclosed resources, event listeners, or circular references',
661
+ details: metrics.leak.trend,
662
+ });
663
+ }
664
+
665
+ // GC optimization
666
+ if (metrics.gc && metrics.current.ratio > this.config.gcThreshold) {
667
+ recommendations.push({
668
+ priority: 'medium',
669
+ category: 'gc',
670
+ message: `GC recommended at ${metrics.current.percentage}% memory usage`,
671
+ action: global.gc
672
+ ? 'Trigger manual GC or enable autoGC'
673
+ : 'Run with --expose-gc flag to enable manual GC',
674
+ });
675
+ }
676
+
677
+ // Performance overhead
678
+ if (parseFloat(metrics.overhead.percentage) > 5) {
679
+ recommendations.push({
680
+ priority: 'low',
681
+ category: 'performance',
682
+ message: `Monitoring overhead at ${metrics.overhead.percentage}%`,
683
+ action:
684
+ 'Consider increasing samplingInterval or disabling detailed metrics',
685
+ });
686
+ }
687
+
688
+ return recommendations;
689
+ }
690
+
691
+ /**
692
+ * Get comprehensive report
693
+ */
694
+ getReport() {
695
+ const metrics = this.getMetrics();
696
+ const recommendations = this.getRecommendations();
697
+
698
+ const report = [];
699
+
700
+ report.push('='.repeat(60));
701
+ report.push('ENHANCED MEMORY MONITOR REPORT');
702
+ report.push('='.repeat(60));
703
+
704
+ report.push('\nCurrent Memory Usage:');
705
+ report.push(` Heap Used: ${metrics.current.heapUsedMB} MB`);
706
+ report.push(` Heap Total: ${metrics.current.heapTotalMB} MB`);
707
+ report.push(` External: ${metrics.current.externalMB} MB`);
708
+ report.push(` RSS: ${metrics.current.rssMB} MB`);
709
+ report.push(` Usage: ${metrics.current.percentage}%`);
710
+ report.push(` Status: ${metrics.status.toUpperCase()}`);
711
+
712
+ report.push('\nStatistics:');
713
+ report.push(` Total Samples: ${metrics.stats.totalSamples}`);
714
+ report.push(` Snapshots: ${metrics.stats.snapshotCount}`);
715
+ report.push(` Warnings: ${metrics.stats.warningCount}`);
716
+ report.push(` Critical Events: ${metrics.stats.criticalCount}`);
717
+
718
+ if (metrics.leak) {
719
+ report.push('\nLeak Detection:');
720
+ report.push(
721
+ ` Status: ${metrics.leak.detected ? 'LEAK DETECTED' : 'No leak'}`,
722
+ );
723
+ report.push(` Confidence: ${metrics.leak.confidence.toFixed(0)}%`);
724
+ report.push(` Trend: ${metrics.leak.trend.trend}`);
725
+ if (metrics.leak.trend.averageGrowthRate > 0) {
726
+ report.push(
727
+ ` Avg Growth Rate: ${metrics.leak.trend.averageGrowthRate.toFixed(2)}%`,
728
+ );
729
+ }
730
+ }
731
+
732
+ if (metrics.gc) {
733
+ report.push('\nGarbage Collection:');
734
+ report.push(` GC Count: ${metrics.gc.gcCount}`);
735
+ report.push(` Suggestions: ${metrics.stats.gcSuggestions}`);
736
+ report.push(` Auto Triggers: ${metrics.stats.gcTriggers}`);
737
+ if (metrics.gc.gcCount > 0) {
738
+ report.push(` Avg Duration: ${metrics.gc.avgDuration}ms`);
739
+ report.push(` Total Freed: ${metrics.gc.totalFreedMB} MB`);
740
+ }
741
+ }
742
+
743
+ report.push('\nPerformance Overhead:');
744
+ report.push(` Avg Overhead: ${metrics.overhead.avgMs}ms per sample`);
745
+ report.push(` Percentage: ${metrics.overhead.percentage}%`);
746
+
747
+ if (recommendations.length > 0) {
748
+ report.push('\nRecommendations:');
749
+ recommendations.forEach((rec, i) => {
750
+ report.push(
751
+ `\n${i + 1}. [${rec.priority.toUpperCase()}] ${rec.category}`,
752
+ );
753
+ report.push(` ${rec.message}`);
754
+ report.push(` Action: ${rec.action}`);
755
+ });
756
+ }
757
+
758
+ report.push('\n' + '='.repeat(60));
759
+
760
+ return report.join('\n');
761
+ }
762
+
763
+ /**
764
+ * Reset monitor state
765
+ */
766
+ reset() {
767
+ this.history = [];
768
+ this.snapshots = [];
769
+ this.leakDetector.reset();
770
+ this.metrics = {
771
+ totalSamples: 0,
772
+ totalSnapshots: 0,
773
+ warningCount: 0,
774
+ criticalCount: 0,
775
+ leakDetections: 0,
776
+ gcSuggestions: 0,
777
+ gcTriggers: 0,
778
+ overheadMs: 0,
779
+ };
780
+ this.overheadSamples = [];
781
+
782
+ this.emit('reset');
783
+ }
784
+ }
785
+
786
+ /**
787
+ * Create memory monitor with default configuration
788
+ */
789
+ function createMemoryMonitor(options = {}) {
790
+ return new EnhancedMemoryMonitor(options);
791
+ }
792
+
793
+ module.exports = {
794
+ EnhancedMemoryMonitor,
795
+ MemoryLeakDetector,
796
+ GCOptimizer,
797
+ MemorySnapshot,
798
+ createMemoryMonitor,
799
+ DEFAULT_CONFIG,
800
+ };