@tamyla/clodo-framework 1.0.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 (130) hide show
  1. package/CHANGELOG.md +564 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1393 -0
  4. package/bin/README.md +71 -0
  5. package/bin/clodo-service.js +416 -0
  6. package/bin/security/security-cli.js +96 -0
  7. package/bin/service-management/README.md +74 -0
  8. package/bin/service-management/create-service.js +129 -0
  9. package/bin/service-management/init-service.js +102 -0
  10. package/bin/service-management/init-service.js.backup +889 -0
  11. package/bin/shared/config/customer-cli.js +293 -0
  12. package/dist/config/ConfigurationManager.js +159 -0
  13. package/dist/config/CustomerConfigCLI.js +220 -0
  14. package/dist/config/FeatureManager.js +426 -0
  15. package/dist/config/customers.js +441 -0
  16. package/dist/config/domains.js +180 -0
  17. package/dist/config/features.js +225 -0
  18. package/dist/config/index.js +6 -0
  19. package/dist/database/database-orchestrator.js +730 -0
  20. package/dist/database/index.js +4 -0
  21. package/dist/deployment/auditor.js +971 -0
  22. package/dist/deployment/index.js +10 -0
  23. package/dist/deployment/rollback-manager.js +523 -0
  24. package/dist/deployment/testers/api-tester.js +80 -0
  25. package/dist/deployment/testers/auth-tester.js +129 -0
  26. package/dist/deployment/testers/core.js +217 -0
  27. package/dist/deployment/testers/database-tester.js +105 -0
  28. package/dist/deployment/testers/index.js +74 -0
  29. package/dist/deployment/testers/load-tester.js +120 -0
  30. package/dist/deployment/testers/performance-tester.js +105 -0
  31. package/dist/deployment/validator.js +558 -0
  32. package/dist/deployment/wrangler-deployer.js +574 -0
  33. package/dist/handlers/GenericRouteHandler.js +532 -0
  34. package/dist/index.js +39 -0
  35. package/dist/migration/MigrationAdapters.js +562 -0
  36. package/dist/modules/ModuleManager.js +668 -0
  37. package/dist/modules/security.js +98 -0
  38. package/dist/orchestration/cross-domain-coordinator.js +1083 -0
  39. package/dist/orchestration/index.js +5 -0
  40. package/dist/orchestration/modules/DeploymentCoordinator.js +258 -0
  41. package/dist/orchestration/modules/DomainResolver.js +196 -0
  42. package/dist/orchestration/modules/StateManager.js +332 -0
  43. package/dist/orchestration/multi-domain-orchestrator.js +255 -0
  44. package/dist/routing/EnhancedRouter.js +158 -0
  45. package/dist/schema/SchemaManager.js +778 -0
  46. package/dist/security/ConfigurationValidator.js +490 -0
  47. package/dist/security/DeploymentManager.js +208 -0
  48. package/dist/security/SecretGenerator.js +142 -0
  49. package/dist/security/SecurityCLI.js +228 -0
  50. package/dist/security/index.js +51 -0
  51. package/dist/security/patterns/environment-rules.js +66 -0
  52. package/dist/security/patterns/insecure-patterns.js +21 -0
  53. package/dist/service-management/ConfirmationEngine.js +411 -0
  54. package/dist/service-management/ErrorTracker.js +294 -0
  55. package/dist/service-management/GenerationEngine.js +3109 -0
  56. package/dist/service-management/InputCollector.js +237 -0
  57. package/dist/service-management/ServiceCreator.js +229 -0
  58. package/dist/service-management/ServiceInitializer.js +448 -0
  59. package/dist/service-management/ServiceOrchestrator.js +638 -0
  60. package/dist/service-management/handlers/ConfigMutator.js +130 -0
  61. package/dist/service-management/handlers/ConfirmationHandler.js +71 -0
  62. package/dist/service-management/handlers/GenerationHandler.js +80 -0
  63. package/dist/service-management/handlers/InputHandler.js +59 -0
  64. package/dist/service-management/handlers/ValidationHandler.js +203 -0
  65. package/dist/service-management/index.js +7 -0
  66. package/dist/services/GenericDataService.js +488 -0
  67. package/dist/shared/cloudflare/domain-discovery.js +562 -0
  68. package/dist/shared/cloudflare/domain-manager.js +912 -0
  69. package/dist/shared/cloudflare/index.js +8 -0
  70. package/dist/shared/cloudflare/ops.js +387 -0
  71. package/dist/shared/config/cache.js +1167 -0
  72. package/dist/shared/config/command-config-manager.js +174 -0
  73. package/dist/shared/config/customer-cli.js +258 -0
  74. package/dist/shared/config/index.js +9 -0
  75. package/dist/shared/config/manager.js +289 -0
  76. package/dist/shared/database/connection-manager.js +338 -0
  77. package/dist/shared/database/index.js +7 -0
  78. package/dist/shared/database/orchestrator.js +632 -0
  79. package/dist/shared/deployment/auditor.js +971 -0
  80. package/dist/shared/deployment/index.js +10 -0
  81. package/dist/shared/deployment/rollback-manager.js +523 -0
  82. package/dist/shared/deployment/validator.js +558 -0
  83. package/dist/shared/index.js +32 -0
  84. package/dist/shared/monitoring/health-checker.js +250 -0
  85. package/dist/shared/monitoring/index.js +8 -0
  86. package/dist/shared/monitoring/memory-manager.js +382 -0
  87. package/dist/shared/monitoring/production-monitor.js +390 -0
  88. package/dist/shared/production-tester/api-tester.js +80 -0
  89. package/dist/shared/production-tester/auth-tester.js +129 -0
  90. package/dist/shared/production-tester/core.js +217 -0
  91. package/dist/shared/production-tester/database-tester.js +105 -0
  92. package/dist/shared/production-tester/index.js +74 -0
  93. package/dist/shared/production-tester/load-tester.js +120 -0
  94. package/dist/shared/production-tester/performance-tester.js +105 -0
  95. package/dist/shared/security/api-token-manager.js +296 -0
  96. package/dist/shared/security/index.js +8 -0
  97. package/dist/shared/security/secret-generator.js +918 -0
  98. package/dist/shared/security/secure-token-manager.js +379 -0
  99. package/dist/shared/utils/error-recovery.js +240 -0
  100. package/dist/shared/utils/graceful-shutdown-manager.js +380 -0
  101. package/dist/shared/utils/index.js +9 -0
  102. package/dist/shared/utils/interactive-prompts.js +134 -0
  103. package/dist/shared/utils/rate-limiter.js +249 -0
  104. package/dist/utils/ErrorHandler.js +173 -0
  105. package/dist/utils/deployment/config-cache.js +1160 -0
  106. package/dist/utils/deployment/index.js +6 -0
  107. package/dist/utils/deployment/interactive-prompts.js +97 -0
  108. package/dist/utils/deployment/secret-generator.js +896 -0
  109. package/dist/utils/dirname-helper.js +35 -0
  110. package/dist/utils/domain-config.js +159 -0
  111. package/dist/utils/error-recovery.js +240 -0
  112. package/dist/utils/esm-helper.js +52 -0
  113. package/dist/utils/framework-config.js +481 -0
  114. package/dist/utils/graceful-shutdown-manager.js +379 -0
  115. package/dist/utils/health-checker.js +114 -0
  116. package/dist/utils/index.js +36 -0
  117. package/dist/utils/prompt-handler.js +98 -0
  118. package/dist/utils/usage-tracker.js +252 -0
  119. package/dist/utils/validation.js +112 -0
  120. package/dist/version/VersionDetector.js +723 -0
  121. package/dist/worker/index.js +4 -0
  122. package/dist/worker/integration.js +332 -0
  123. package/docs/FRAMEWORK-ARCHITECTURE-OVERVIEW.md +206 -0
  124. package/docs/INTEGRATION_GUIDE.md +2045 -0
  125. package/docs/README.md +82 -0
  126. package/docs/SECURITY.md +242 -0
  127. package/docs/deployment/deployment-guide.md +540 -0
  128. package/docs/overview.md +280 -0
  129. package/package.json +176 -0
  130. package/types/index.d.ts +575 -0
@@ -0,0 +1,250 @@
1
+ /**
2
+ * Health Checker Module
3
+ * Endpoint health checking and validation utilities
4
+ *
5
+ * Consolidates health checking across 20+ scripts
6
+ */
7
+
8
+ import { exec, execSync } from 'child_process';
9
+ import { promisify } from 'util';
10
+ import https from 'https';
11
+ import http from 'http';
12
+ const execAsync = promisify(exec);
13
+
14
+ // Load framework configuration
15
+ const {
16
+ frameworkConfig
17
+ } = await import('../../../src/utils/framework-config.js');
18
+ const timing = frameworkConfig.getTiming();
19
+ function makeHttpRequest(url, method = 'GET', timeout = 5000) {
20
+ return new Promise((resolve, reject) => {
21
+ const protocol = url.startsWith('https:') ? https : http;
22
+ const req = protocol.request(url, {
23
+ method,
24
+ timeout
25
+ }, res => {
26
+ let data = '';
27
+ res.on('data', chunk => data += chunk);
28
+ res.on('end', () => {
29
+ resolve({
30
+ data,
31
+ statusCode: res.statusCode
32
+ });
33
+ });
34
+ });
35
+ req.on('error', err => {
36
+ reject(err);
37
+ });
38
+ req.on('timeout', () => {
39
+ req.destroy();
40
+ reject(new Error('Request timed out'));
41
+ });
42
+ req.end();
43
+ });
44
+ }
45
+ export async function checkHealth(url, timeout = timing.healthCheckTimeout) {
46
+ return new Promise((resolve, reject) => {
47
+ const protocol = url.startsWith('https:') ? https : http;
48
+ const healthUrl = `${url}/health`;
49
+ const req = protocol.get(healthUrl, {
50
+ timeout
51
+ }, res => {
52
+ let data = '';
53
+ res.on('data', chunk => data += chunk);
54
+ res.on('end', () => {
55
+ try {
56
+ const response = JSON.parse(data);
57
+ if (response.status === 'healthy' || response.status === 'ok') {
58
+ resolve({
59
+ status: 'ok',
60
+ framework: response.framework,
61
+ message: 'Service is healthy',
62
+ url: healthUrl,
63
+ timestamp: new Date().toISOString()
64
+ });
65
+ } else {
66
+ resolve({
67
+ status: 'error',
68
+ message: `Service reported unhealthy: ${response.status}`,
69
+ url: healthUrl,
70
+ timestamp: new Date().toISOString()
71
+ });
72
+ }
73
+ } catch (e) {
74
+ resolve({
75
+ status: 'error',
76
+ message: 'Invalid JSON response from health endpoint',
77
+ url: healthUrl,
78
+ timestamp: new Date().toISOString()
79
+ });
80
+ }
81
+ });
82
+ });
83
+ req.on('error', err => {
84
+ reject({
85
+ status: 'error',
86
+ message: `Health check failed: ${err.message}`,
87
+ url: healthUrl,
88
+ timestamp: new Date().toISOString()
89
+ });
90
+ });
91
+ req.on('timeout', () => {
92
+ req.destroy();
93
+ reject({
94
+ status: 'error',
95
+ message: 'Health check timed out',
96
+ url: healthUrl,
97
+ timestamp: new Date().toISOString()
98
+ });
99
+ });
100
+ });
101
+ }
102
+ export async function waitForDeployment(url, maxWaitTime = timing.deploymentTimeout, interval = timing.deploymentInterval) {
103
+ const startTime = Date.now();
104
+ let attempts = 0;
105
+ console.log(`⏳ Waiting for deployment at ${url}...`);
106
+ while (Date.now() - startTime < maxWaitTime) {
107
+ try {
108
+ attempts++;
109
+ console.log(` 🔍 Attempt ${attempts}: Checking health...`);
110
+ const health = await checkHealth(url);
111
+ if (health.status === 'ok') {
112
+ console.log(` ✅ Deployment active! Framework: ${health.framework?.name || 'Unknown'}`);
113
+ return health;
114
+ }
115
+ } catch (error) {
116
+ console.log(` ⏳ Not ready yet: ${error.message}`);
117
+ }
118
+ await new Promise(resolve => setTimeout(resolve, interval));
119
+ }
120
+ throw new Error(`Deployment verification timed out after ${maxWaitTime}ms (${attempts} attempts)`);
121
+ }
122
+ export async function validateEndpoints(baseUrl, endpoints = [], timeout = timing.endpointValidationTimeout) {
123
+ console.log(`🔍 Validating ${endpoints.length} endpoints...`);
124
+ const results = [];
125
+ for (const endpoint of endpoints) {
126
+ try {
127
+ const url = endpoint.startsWith('http') ? endpoint : `${baseUrl}${endpoint}`;
128
+ console.log(` Testing: ${endpoint}`);
129
+ const result = await makeHttpRequest(url, 'GET', timeout);
130
+ results.push({
131
+ endpoint,
132
+ url,
133
+ status: 'ok',
134
+ response: result.data.substring(0, 200) + (result.data.length > 200 ? '...' : '')
135
+ });
136
+ console.log(` ✅ OK`);
137
+ } catch (error) {
138
+ results.push({
139
+ endpoint,
140
+ url: endpoint.startsWith('http') ? endpoint : `${baseUrl}${endpoint}`,
141
+ status: 'failed',
142
+ error: error.message
143
+ });
144
+ console.log(` ❌ Failed: ${error.message}`);
145
+ }
146
+ }
147
+ const successful = results.filter(r => r.status === 'ok').length;
148
+ const failed = results.filter(r => r.status === 'failed').length;
149
+ console.log(`📊 Results: ${successful} passed, ${failed} failed`);
150
+ return {
151
+ summary: {
152
+ successful,
153
+ failed,
154
+ total: results.length
155
+ },
156
+ results,
157
+ allPassed: failed === 0
158
+ };
159
+ }
160
+ export async function quickHealthCheck(url) {
161
+ try {
162
+ const health = await checkHealth(url, 5000);
163
+ return {
164
+ isHealthy: true,
165
+ details: health
166
+ };
167
+ } catch (error) {
168
+ return {
169
+ isHealthy: false,
170
+ error: error.message
171
+ };
172
+ }
173
+ }
174
+ export async function comprehensiveHealthCheck(url) {
175
+ console.log(`🏥 Running comprehensive health check for ${url}...`);
176
+ const checks = {
177
+ basic: {
178
+ endpoint: '/health',
179
+ description: 'Basic health check'
180
+ },
181
+ auth: {
182
+ endpoint: '/auth/magic-link',
183
+ description: 'Authentication endpoint',
184
+ method: 'POST'
185
+ },
186
+ users: {
187
+ endpoint: '/users/profile',
188
+ description: 'User profile endpoint',
189
+ requiresAuth: true
190
+ },
191
+ framework: {
192
+ endpoint: '/framework/models',
193
+ description: 'Framework models'
194
+ }
195
+ };
196
+ const results = {};
197
+ for (const [name, config] of Object.entries(checks)) {
198
+ try {
199
+ console.log(` Testing ${config.description}...`);
200
+ if (config.requiresAuth) {
201
+ console.log(` ⏭️ Skipped (requires authentication)`);
202
+ results[name] = {
203
+ status: 'skipped',
204
+ reason: 'requires authentication'
205
+ };
206
+ continue;
207
+ }
208
+ const endpoint = `${url}${config.endpoint}`;
209
+ const method = config.method || 'GET';
210
+ const response = await makeHttpRequest(endpoint, method, 5000);
211
+ results[name] = {
212
+ status: 'ok',
213
+ endpoint: config.endpoint,
214
+ response: response.data.substring(0, 100) + (response.data.length > 100 ? '...' : '')
215
+ };
216
+ console.log(` ✅ ${config.description} - OK`);
217
+ } catch (error) {
218
+ results[name] = {
219
+ status: 'failed',
220
+ endpoint: config.endpoint,
221
+ error: error.message
222
+ };
223
+ console.log(` ❌ ${config.description} - ${error.message}`);
224
+ }
225
+ }
226
+ const passed = Object.values(results).filter(r => r.status === 'ok').length;
227
+ const total = Object.keys(results).length;
228
+ console.log(`📊 Health check complete: ${passed}/${total} checks passed`);
229
+ return {
230
+ summary: {
231
+ passed,
232
+ total,
233
+ success: passed === total
234
+ },
235
+ results,
236
+ timestamp: new Date().toISOString()
237
+ };
238
+ }
239
+ export function formatHealthReport(healthData) {
240
+ const lines = ['🏥 HEALTH REPORT', '===============', '', `🕐 Timestamp: ${healthData.timestamp || new Date().toISOString()}`, `🌐 URL: ${healthData.url || 'Unknown'}`, `📊 Status: ${healthData.status || 'Unknown'}`];
241
+ if (healthData.framework) {
242
+ lines.push('');
243
+ lines.push('🏗️ Framework Details:');
244
+ lines.push(` 📦 Name: ${healthData.framework.name || 'Unknown'}`);
245
+ lines.push(` 📊 Models: ${healthData.framework.models?.length || 0}`);
246
+ lines.push(` 🛣️ Routes: ${healthData.framework.routes?.length || 0}`);
247
+ lines.push(` 🔧 Modules: ${healthData.framework.modules?.length || 0}`);
248
+ }
249
+ return lines.join('\n');
250
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Monitoring Module
3
+ * Exports all monitoring and health check utilities
4
+ */
5
+
6
+ export { HealthChecker } from './health-checker.js';
7
+ export { ProductionMonitor } from './production-monitor.js';
8
+ export { MemoryManager } from './memory-manager.js';
@@ -0,0 +1,382 @@
1
+ /**
2
+ * Memory Manager
3
+ * Implements memory leak prevention and cleanup routines for long-running processes
4
+ */
5
+
6
+ export class MemoryManager {
7
+ constructor(options = {}) {
8
+ this.config = {
9
+ gcInterval: options.gcInterval || 300000,
10
+ // 5 minutes
11
+ memoryThreshold: options.memoryThreshold || 0.8,
12
+ // 80% of heap
13
+ maxHeapSize: options.maxHeapSize || 512 * 1024 * 1024,
14
+ // 512MB
15
+ enableGcHints: options.enableGcHints !== false,
16
+ cleanupInterval: options.cleanupInterval || 60000,
17
+ // 1 minute
18
+ leakDetection: options.leakDetection !== false,
19
+ ...options
20
+ };
21
+ this.gcIntervalId = null;
22
+ this.cleanupIntervalId = null;
23
+ this.memoryStats = [];
24
+ this.eventListeners = new Set();
25
+ this.timers = new Set();
26
+ this.intervals = new Set();
27
+ this.isMonitoring = false;
28
+
29
+ // Bind methods to preserve context
30
+ this.gcCallback = this.gcCallback.bind(this);
31
+ this.cleanupCallback = this.cleanupCallback.bind(this);
32
+ }
33
+
34
+ /**
35
+ * Start memory monitoring and cleanup
36
+ */
37
+ startMonitoring() {
38
+ if (this.isMonitoring) return;
39
+ this.isMonitoring = true;
40
+ if (this.config.enableGcHints) {
41
+ this.gcIntervalId = setInterval(this.gcCallback, this.config.gcInterval);
42
+ this.gcIntervalId.unref?.(); // Don't keep process alive
43
+ }
44
+ this.cleanupIntervalId = setInterval(this.cleanupCallback, this.config.cleanupInterval);
45
+ this.cleanupIntervalId.unref?.();
46
+
47
+ // Register process cleanup handlers
48
+ this.registerProcessHandlers();
49
+ console.log('🧠 Memory monitoring started');
50
+ }
51
+
52
+ /**
53
+ * Stop memory monitoring
54
+ */
55
+ stopMonitoring() {
56
+ if (!this.isMonitoring) return;
57
+ this.isMonitoring = false;
58
+ if (this.gcIntervalId) {
59
+ clearInterval(this.gcIntervalId);
60
+ this.gcIntervalId = null;
61
+ }
62
+ if (this.cleanupIntervalId) {
63
+ clearInterval(this.cleanupIntervalId);
64
+ this.cleanupIntervalId = null;
65
+ }
66
+ this.unregisterProcessHandlers();
67
+ console.log('🧠 Memory monitoring stopped');
68
+ }
69
+
70
+ /**
71
+ * Garbage collection callback
72
+ */
73
+ gcCallback() {
74
+ const memUsage = process.memoryUsage();
75
+
76
+ // Store memory stats for trend analysis
77
+ this.memoryStats.push({
78
+ timestamp: Date.now(),
79
+ ...memUsage
80
+ });
81
+
82
+ // Keep only last 100 readings
83
+ if (this.memoryStats.length > 100) {
84
+ this.memoryStats.shift();
85
+ }
86
+
87
+ // Check memory thresholds
88
+ const heapUsagePercent = memUsage.heapUsed / memUsage.heapTotal;
89
+ if (heapUsagePercent > this.config.memoryThreshold) {
90
+ console.warn(`⚠️ High memory usage detected: ${(heapUsagePercent * 100).toFixed(1)}%`);
91
+
92
+ // Force garbage collection if available
93
+ if (global.gc) {
94
+ console.log('🗑️ Running forced garbage collection');
95
+ global.gc();
96
+ }
97
+
98
+ // Run cleanup routines
99
+ this.runCleanupRoutines();
100
+ }
101
+
102
+ // Check for memory leaks
103
+ if (this.config.leakDetection) {
104
+ this.detectMemoryLeaks();
105
+ }
106
+ }
107
+
108
+ /**
109
+ * Cleanup callback
110
+ */
111
+ cleanupCallback() {
112
+ this.runCleanupRoutines();
113
+ }
114
+
115
+ /**
116
+ * Run cleanup routines
117
+ */
118
+ runCleanupRoutines() {
119
+ // Clear expired cache entries
120
+ this.clearExpiredCache();
121
+
122
+ // Clean up event listeners
123
+ this.cleanupEventListeners();
124
+
125
+ // Clean up timers and intervals
126
+ this.cleanupTimers();
127
+
128
+ // Force garbage collection hint
129
+ if (global.gc) {
130
+ global.gc();
131
+ }
132
+ }
133
+
134
+ /**
135
+ * Clear expired cache entries
136
+ */
137
+ clearExpiredCache() {
138
+ // This would integrate with cache managers
139
+ // For now, just hint that caches should be cleaned
140
+ if (typeof global !== 'undefined' && global.cacheManagers) {
141
+ global.cacheManagers.forEach(manager => {
142
+ if (typeof manager.cleanup === 'function') {
143
+ manager.cleanup();
144
+ }
145
+ });
146
+ }
147
+ }
148
+
149
+ /**
150
+ * Clean up event listeners
151
+ */
152
+ cleanupEventListeners() {
153
+ // Remove listeners that are no longer needed
154
+ // This is a placeholder - actual implementation would track listeners
155
+ }
156
+
157
+ /**
158
+ * Clean up timers and intervals
159
+ */
160
+ cleanupTimers() {
161
+ // Clear any timers that may have been leaked
162
+ // This is a placeholder - actual implementation would track timers
163
+ }
164
+
165
+ /**
166
+ * Detect memory leaks
167
+ */
168
+ detectMemoryLeaks() {
169
+ if (this.memoryStats.length < 10) return;
170
+ const recent = this.memoryStats.slice(-10);
171
+ const older = this.memoryStats.slice(-20, -10);
172
+ if (recent.length === 0 || older.length === 0) return;
173
+ const recentAvg = recent.reduce((sum, stat) => sum + stat.heapUsed, 0) / recent.length;
174
+ const olderAvg = older.reduce((sum, stat) => sum + stat.heapUsed, 0) / older.length;
175
+ const growthRate = (recentAvg - olderAvg) / olderAvg;
176
+ if (growthRate > 0.1) {
177
+ // 10% growth
178
+ console.warn(`🚨 Potential memory leak detected: ${(growthRate * 100).toFixed(1)}% growth over time`);
179
+ }
180
+ }
181
+
182
+ /**
183
+ * Register process signal handlers
184
+ */
185
+ registerProcessHandlers() {
186
+ // Handle graceful shutdown
187
+ process.on('SIGTERM', () => this.gracefulShutdown('SIGTERM'));
188
+ process.on('SIGINT', () => this.gracefulShutdown('SIGINT'));
189
+
190
+ // Handle uncaught exceptions
191
+ process.on('uncaughtException', error => {
192
+ console.error('💥 Uncaught exception:', error);
193
+ this.gracefulShutdown('uncaughtException');
194
+ });
195
+
196
+ // Handle unhandled promise rejections
197
+ process.on('unhandledRejection', (reason, promise) => {
198
+ console.error('💥 Unhandled rejection at:', promise, 'reason:', reason);
199
+ this.gracefulShutdown('unhandledRejection');
200
+ });
201
+ }
202
+
203
+ /**
204
+ * Unregister process signal handlers
205
+ */
206
+ unregisterProcessHandlers() {
207
+ process.removeAllListeners('SIGTERM');
208
+ process.removeAllListeners('SIGINT');
209
+ process.removeAllListeners('uncaughtException');
210
+ process.removeAllListeners('unhandledRejection');
211
+ }
212
+
213
+ /**
214
+ * Graceful shutdown
215
+ */
216
+ gracefulShutdown(reason) {
217
+ console.log(`🛑 Graceful shutdown initiated: ${reason}`);
218
+
219
+ // Stop monitoring
220
+ this.stopMonitoring();
221
+
222
+ // Run final cleanup
223
+ this.runCleanupRoutines();
224
+
225
+ // Force final garbage collection
226
+ if (global.gc) {
227
+ global.gc();
228
+ }
229
+
230
+ // Exit gracefully
231
+ process.exit(0);
232
+ }
233
+
234
+ /**
235
+ * Track an event listener for cleanup
236
+ */
237
+ trackEventListener(emitter, event, listener) {
238
+ const tracked = {
239
+ emitter,
240
+ event,
241
+ listener
242
+ };
243
+ this.eventListeners.add(tracked);
244
+
245
+ // Return cleanup function
246
+ return () => {
247
+ emitter.removeListener(event, listener);
248
+ this.eventListeners.delete(tracked);
249
+ };
250
+ }
251
+
252
+ /**
253
+ * Track a timer for cleanup
254
+ */
255
+ trackTimer(timerId) {
256
+ this.timers.add(timerId);
257
+
258
+ // Return cleanup function
259
+ return () => {
260
+ clearTimeout(timerId);
261
+ this.timers.delete(timerId);
262
+ };
263
+ }
264
+
265
+ /**
266
+ * Track an interval for cleanup
267
+ */
268
+ trackInterval(intervalId) {
269
+ this.intervals.add(intervalId);
270
+
271
+ // Return cleanup function
272
+ return () => {
273
+ clearInterval(intervalId);
274
+ this.intervals.delete(intervalId);
275
+ };
276
+ }
277
+
278
+ /**
279
+ * Get memory statistics
280
+ */
281
+ getMemoryStats() {
282
+ const memUsage = process.memoryUsage();
283
+ return {
284
+ current: {
285
+ rss: memUsage.rss / 1024 / 1024,
286
+ // MB
287
+ heapUsed: memUsage.heapUsed / 1024 / 1024,
288
+ // MB
289
+ heapTotal: memUsage.heapTotal / 1024 / 1024,
290
+ // MB
291
+ external: memUsage.external / 1024 / 1024,
292
+ // MB
293
+ heapUsagePercent: memUsage.heapUsed / memUsage.heapTotal * 100
294
+ },
295
+ history: this.memoryStats.slice(-10),
296
+ // Last 10 readings
297
+ thresholds: {
298
+ memoryThreshold: this.config.memoryThreshold * 100,
299
+ maxHeapSize: this.config.maxHeapSize / 1024 / 1024
300
+ },
301
+ tracking: {
302
+ eventListeners: this.eventListeners.size,
303
+ timers: this.timers.size,
304
+ intervals: this.intervals.size
305
+ }
306
+ };
307
+ }
308
+
309
+ /**
310
+ * Force garbage collection (if available)
311
+ */
312
+ forceGc() {
313
+ if (global.gc) {
314
+ console.log('🗑️ Forced garbage collection');
315
+ global.gc();
316
+ return true;
317
+ }
318
+ return false;
319
+ }
320
+
321
+ /**
322
+ * Create a memory-safe interval
323
+ */
324
+ createSafeInterval(callback, delay) {
325
+ const intervalId = setInterval(() => {
326
+ try {
327
+ callback();
328
+ } catch (error) {
329
+ console.error('Error in safe interval:', error);
330
+ // Could remove the interval if it keeps failing
331
+ }
332
+ }, delay);
333
+ intervalId.unref?.();
334
+ return this.trackInterval(intervalId);
335
+ }
336
+
337
+ /**
338
+ * Create a memory-safe timeout
339
+ */
340
+ createSafeTimeout(callback, delay) {
341
+ const timeoutId = setTimeout(() => {
342
+ try {
343
+ callback();
344
+ } catch (error) {
345
+ console.error('Error in safe timeout:', error);
346
+ }
347
+ }, delay);
348
+ timeoutId.unref?.();
349
+ return this.trackTimer(timeoutId);
350
+ }
351
+ }
352
+
353
+ // Global memory manager instance
354
+ let globalMemoryManager = null;
355
+
356
+ /**
357
+ * Get the global memory manager instance
358
+ */
359
+ export function getMemoryManager(options = {}) {
360
+ if (!globalMemoryManager) {
361
+ globalMemoryManager = new MemoryManager(options);
362
+ }
363
+ return globalMemoryManager;
364
+ }
365
+
366
+ /**
367
+ * Start global memory monitoring
368
+ */
369
+ export function startMemoryMonitoring(options = {}) {
370
+ const manager = getMemoryManager(options);
371
+ manager.startMonitoring();
372
+ return manager;
373
+ }
374
+
375
+ /**
376
+ * Stop global memory monitoring
377
+ */
378
+ export function stopMemoryMonitoring() {
379
+ if (globalMemoryManager) {
380
+ globalMemoryManager.stopMonitoring();
381
+ }
382
+ }