@tamyla/clodo-framework 2.0.20 → 3.0.3

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 (54) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/bin/clodo-service.js +1 -1
  3. package/bin/database/README.md +33 -0
  4. package/bin/database/deployment-db-manager.js +527 -0
  5. package/bin/database/enterprise-db-manager.js +736 -0
  6. package/bin/database/wrangler-d1-manager.js +775 -0
  7. package/bin/shared/cloudflare/domain-discovery.js +636 -0
  8. package/bin/shared/cloudflare/domain-manager.js +952 -0
  9. package/bin/shared/cloudflare/index.js +8 -0
  10. package/bin/shared/cloudflare/ops.js +359 -0
  11. package/bin/shared/config/index.js +1 -1
  12. package/bin/shared/database/connection-manager.js +374 -0
  13. package/bin/shared/database/index.js +7 -0
  14. package/bin/shared/database/orchestrator.js +726 -0
  15. package/bin/shared/deployment/auditor.js +969 -0
  16. package/bin/shared/deployment/index.js +10 -0
  17. package/bin/shared/deployment/rollback-manager.js +570 -0
  18. package/bin/shared/deployment/validator.js +779 -0
  19. package/bin/shared/index.js +32 -0
  20. package/bin/shared/monitoring/health-checker.js +484 -0
  21. package/bin/shared/monitoring/index.js +8 -0
  22. package/bin/shared/monitoring/memory-manager.js +387 -0
  23. package/bin/shared/monitoring/production-monitor.js +391 -0
  24. package/bin/shared/production-tester/api-tester.js +82 -0
  25. package/bin/shared/production-tester/auth-tester.js +132 -0
  26. package/bin/shared/production-tester/core.js +197 -0
  27. package/bin/shared/production-tester/database-tester.js +109 -0
  28. package/bin/shared/production-tester/index.js +77 -0
  29. package/bin/shared/production-tester/load-tester.js +131 -0
  30. package/bin/shared/production-tester/performance-tester.js +103 -0
  31. package/bin/shared/security/api-token-manager.js +312 -0
  32. package/bin/shared/security/index.js +8 -0
  33. package/bin/shared/security/secret-generator.js +937 -0
  34. package/bin/shared/security/secure-token-manager.js +398 -0
  35. package/bin/shared/utils/error-recovery.js +225 -0
  36. package/bin/shared/utils/graceful-shutdown-manager.js +390 -0
  37. package/bin/shared/utils/index.js +9 -0
  38. package/bin/shared/utils/interactive-prompts.js +146 -0
  39. package/bin/shared/utils/interactive-utils.js +530 -0
  40. package/bin/shared/utils/rate-limiter.js +246 -0
  41. package/dist/database/database-orchestrator.js +34 -12
  42. package/dist/deployment/index.js +2 -2
  43. package/dist/orchestration/multi-domain-orchestrator.js +26 -10
  44. package/dist/service-management/GenerationEngine.js +76 -28
  45. package/dist/service-management/ServiceInitializer.js +5 -3
  46. package/dist/shared/cloudflare/domain-manager.js +1 -1
  47. package/dist/shared/cloudflare/ops.js +27 -12
  48. package/dist/shared/config/index.js +1 -1
  49. package/dist/shared/deployment/index.js +2 -2
  50. package/dist/shared/security/secret-generator.js +4 -2
  51. package/dist/shared/utils/error-recovery.js +1 -1
  52. package/dist/shared/utils/graceful-shutdown-manager.js +4 -3
  53. package/dist/utils/deployment/secret-generator.js +19 -6
  54. package/package.json +4 -2
@@ -0,0 +1,391 @@
1
+ /**
2
+ * Production Monitoring Module
3
+ * Implements structured logging, metrics collection, and alerting
4
+ */
5
+
6
+ import { writeFile, appendFile, mkdir } from 'fs/promises';
7
+ import { join } from 'path';
8
+
9
+ export class ProductionMonitor {
10
+ constructor(options = {}) {
11
+ this.config = {
12
+ logLevel: options.logLevel || 'info',
13
+ logDir: options.logDir || 'logs',
14
+ metricsInterval: options.metricsInterval || 60000, // 1 minute
15
+ alertThresholds: {
16
+ errorRate: options.errorRateThreshold || 0.05, // 5% error rate
17
+ responseTime: options.responseTimeThreshold || 5000, // 5 seconds
18
+ memoryUsage: options.memoryUsageThreshold || 0.8, // 80% memory usage
19
+ ...options.alertThresholds
20
+ },
21
+ enableMetrics: options.enableMetrics !== false,
22
+ enableAlerts: options.enableAlerts !== false,
23
+ alertWebhook: options.alertWebhook,
24
+ ...options
25
+ };
26
+
27
+ this.metrics = {
28
+ startTime: new Date(),
29
+ requests: { total: 0, successful: 0, failed: 0 },
30
+ responseTimes: [],
31
+ errors: [],
32
+ memoryUsage: [],
33
+ customMetrics: new Map()
34
+ };
35
+
36
+ this.logLevels = {
37
+ debug: 0,
38
+ info: 1,
39
+ warn: 2,
40
+ error: 3,
41
+ fatal: 4
42
+ };
43
+
44
+ this.alerts = [];
45
+ this.isMonitoring = false;
46
+ }
47
+
48
+ /**
49
+ * Start monitoring
50
+ */
51
+ async startMonitoring() {
52
+ if (this.isMonitoring) return;
53
+
54
+ this.isMonitoring = true;
55
+ await this.ensureLogDirectory();
56
+
57
+ // Start metrics collection
58
+ if (this.config.enableMetrics) {
59
+ this.metricsInterval = setInterval(() => {
60
+ this.collectSystemMetrics();
61
+ this.checkAlertThresholds();
62
+ }, this.config.metricsInterval);
63
+ }
64
+
65
+ this.log('info', 'Production monitoring started', {
66
+ config: this.config,
67
+ startTime: this.metrics.startTime
68
+ });
69
+ }
70
+
71
+ /**
72
+ * Stop monitoring
73
+ */
74
+ async stopMonitoring() {
75
+ if (!this.isMonitoring) return;
76
+
77
+ this.isMonitoring = false;
78
+
79
+ if (this.metricsInterval) {
80
+ clearInterval(this.metricsInterval);
81
+ }
82
+
83
+ await this.saveMetrics();
84
+ this.log('info', 'Production monitoring stopped');
85
+ }
86
+
87
+ /**
88
+ * Log a message with structured data
89
+ */
90
+ async log(level, message, data = {}) {
91
+ if (this.logLevels[level] < this.logLevels[this.config.logLevel]) {
92
+ return;
93
+ }
94
+
95
+ const logEntry = {
96
+ timestamp: new Date(),
97
+ level,
98
+ message,
99
+ data,
100
+ process: {
101
+ pid: process.pid,
102
+ memory: process.memoryUsage(),
103
+ uptime: process.uptime()
104
+ }
105
+ };
106
+
107
+ // Console output for development
108
+ const consoleMethod = level === 'error' || level === 'fatal' ? 'error' :
109
+ level === 'warn' ? 'warn' : 'log';
110
+ console[consoleMethod](`[${level.toUpperCase()}] ${message}`, data);
111
+
112
+ // File logging
113
+ try {
114
+ const logFile = join(this.config.logDir, `${new Date().toISOString().split('T')[0]}.log`);
115
+ const logLine = JSON.stringify(logEntry) + '\n';
116
+ await appendFile(logFile, logLine);
117
+ } catch (error) {
118
+ console.error('Failed to write log file:', error);
119
+ }
120
+
121
+ // Track errors for metrics
122
+ if (level === 'error' || level === 'fatal') {
123
+ this.metrics.errors.push(logEntry);
124
+ }
125
+ }
126
+
127
+ /**
128
+ * Record a request
129
+ */
130
+ recordRequest(success = true, responseTime = 0, metadata = {}) {
131
+ this.metrics.requests.total++;
132
+
133
+ if (success) {
134
+ this.metrics.requests.successful++;
135
+ } else {
136
+ this.metrics.requests.failed++;
137
+ }
138
+
139
+ if (responseTime > 0) {
140
+ this.metrics.responseTimes.push({
141
+ time: responseTime,
142
+ timestamp: new Date(),
143
+ success,
144
+ ...metadata
145
+ });
146
+
147
+ // Keep only last 1000 response times
148
+ if (this.metrics.responseTimes.length > 1000) {
149
+ this.metrics.responseTimes.shift();
150
+ }
151
+ }
152
+ }
153
+
154
+ /**
155
+ * Record a custom metric
156
+ */
157
+ recordMetric(name, value, tags = {}) {
158
+ if (!this.metrics.customMetrics.has(name)) {
159
+ this.metrics.customMetrics.set(name, []);
160
+ }
161
+
162
+ const metrics = this.metrics.customMetrics.get(name);
163
+ metrics.push({
164
+ value,
165
+ timestamp: new Date(),
166
+ tags
167
+ });
168
+
169
+ // Keep only last 100 values per metric
170
+ if (metrics.length > 100) {
171
+ metrics.shift();
172
+ }
173
+ }
174
+
175
+ /**
176
+ * Collect system metrics
177
+ */
178
+ collectSystemMetrics() {
179
+ const memUsage = process.memoryUsage();
180
+ const memoryData = {
181
+ rss: memUsage.rss,
182
+ heapUsed: memUsage.heapUsed,
183
+ heapTotal: memUsage.heapTotal,
184
+ external: memUsage.external,
185
+ timestamp: new Date()
186
+ };
187
+
188
+ this.metrics.memoryUsage.push(memoryData);
189
+
190
+ // Keep only last 100 memory readings
191
+ if (this.metrics.memoryUsage.length > 100) {
192
+ this.metrics.memoryUsage.shift();
193
+ }
194
+
195
+ // Record memory usage as custom metric
196
+ this.recordMetric('memory_usage_percent', (memUsage.heapUsed / memUsage.heapTotal) * 100);
197
+ this.recordMetric('memory_heap_used_mb', memUsage.heapUsed / 1024 / 1024);
198
+ }
199
+
200
+ /**
201
+ * Check alert thresholds and trigger alerts
202
+ */
203
+ checkAlertThresholds() {
204
+ const now = Date.now();
205
+
206
+ // Check error rate
207
+ const recentRequests = this.getRecentRequests(5 * 60 * 1000); // Last 5 minutes
208
+ if (recentRequests.total > 10) { // Only check if we have enough data
209
+ const errorRate = recentRequests.failed / recentRequests.total;
210
+ if (errorRate > this.config.alertThresholds.errorRate) {
211
+ this.triggerAlert('HIGH_ERROR_RATE', {
212
+ errorRate: errorRate * 100,
213
+ threshold: this.config.alertThresholds.errorRate * 100,
214
+ recentRequests
215
+ });
216
+ }
217
+ }
218
+
219
+ // Check response time
220
+ const avgResponseTime = this.getAverageResponseTime(5 * 60 * 1000);
221
+ if (avgResponseTime > this.config.alertThresholds.responseTime) {
222
+ this.triggerAlert('HIGH_RESPONSE_TIME', {
223
+ averageResponseTime: avgResponseTime,
224
+ threshold: this.config.alertThresholds.responseTime
225
+ });
226
+ }
227
+
228
+ // Check memory usage
229
+ const currentMemory = this.metrics.memoryUsage[this.metrics.memoryUsage.length - 1];
230
+ if (currentMemory) {
231
+ const memoryUsagePercent = currentMemory.heapUsed / currentMemory.heapTotal;
232
+ if (memoryUsagePercent > this.config.alertThresholds.memoryUsage) {
233
+ this.triggerAlert('HIGH_MEMORY_USAGE', {
234
+ memoryUsagePercent: memoryUsagePercent * 100,
235
+ threshold: this.config.alertThresholds.memoryUsage * 100,
236
+ heapUsed: currentMemory.heapUsed,
237
+ heapTotal: currentMemory.heapTotal
238
+ });
239
+ }
240
+ }
241
+ }
242
+
243
+ /**
244
+ * Trigger an alert
245
+ */
246
+ async triggerAlert(type, data) {
247
+ const alert = {
248
+ id: `alert_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
249
+ type,
250
+ timestamp: new Date(),
251
+ data,
252
+ acknowledged: false
253
+ };
254
+
255
+ this.alerts.push(alert);
256
+
257
+ // Keep only last 100 alerts
258
+ if (this.alerts.length > 100) {
259
+ this.alerts.shift();
260
+ }
261
+
262
+ // Log the alert
263
+ await this.log('error', `Alert triggered: ${type}`, data);
264
+
265
+ // Send webhook if configured
266
+ if (this.config.alertWebhook) {
267
+ try {
268
+ await this.sendWebhookAlert(alert);
269
+ } catch (error) {
270
+ await this.log('error', 'Failed to send alert webhook', { error: error.message });
271
+ }
272
+ }
273
+ }
274
+
275
+ /**
276
+ * Send webhook alert
277
+ */
278
+ async sendWebhookAlert(alert) {
279
+ if (!this.config.alertWebhook) return;
280
+
281
+ // In a real implementation, you'd use fetch or axios to send the webhook
282
+ // For now, just log it
283
+ await this.log('info', 'Alert webhook would be sent', {
284
+ webhook: this.config.alertWebhook,
285
+ alert
286
+ });
287
+ }
288
+
289
+ /**
290
+ * Get recent requests within time window
291
+ */
292
+ getRecentRequests(timeWindowMs) {
293
+ const cutoff = Date.now() - timeWindowMs;
294
+ const recent = this.metrics.responseTimes.filter(r => r.timestamp.getTime() > cutoff);
295
+
296
+ return {
297
+ total: recent.length,
298
+ successful: recent.filter(r => r.success).length,
299
+ failed: recent.filter(r => !r.success).length
300
+ };
301
+ }
302
+
303
+ /**
304
+ * Get average response time within time window
305
+ */
306
+ getAverageResponseTime(timeWindowMs) {
307
+ const cutoff = Date.now() - timeWindowMs;
308
+ const recent = this.metrics.responseTimes.filter(r => r.timestamp.getTime() > cutoff);
309
+
310
+ if (recent.length === 0) return 0;
311
+
312
+ const totalTime = recent.reduce((sum, r) => sum + r.time, 0);
313
+ return totalTime / recent.length;
314
+ }
315
+
316
+ /**
317
+ * Get current metrics summary
318
+ */
319
+ getMetricsSummary() {
320
+ const uptime = Date.now() - this.metrics.startTime.getTime();
321
+
322
+ return {
323
+ uptime,
324
+ requests: { ...this.metrics.requests },
325
+ errorRate: this.metrics.requests.total > 0 ?
326
+ (this.metrics.requests.failed / this.metrics.requests.total) * 100 : 0,
327
+ averageResponseTime: this.getAverageResponseTime(60 * 60 * 1000), // Last hour
328
+ memoryUsage: this.metrics.memoryUsage[this.metrics.memoryUsage.length - 1],
329
+ activeAlerts: this.alerts.filter(a => !a.acknowledged).length,
330
+ totalAlerts: this.alerts.length
331
+ };
332
+ }
333
+
334
+ /**
335
+ * Get detailed metrics
336
+ */
337
+ getDetailedMetrics() {
338
+ return {
339
+ ...this.getMetricsSummary(),
340
+ responseTimes: this.metrics.responseTimes.slice(-100), // Last 100
341
+ memoryUsage: this.metrics.memoryUsage.slice(-20), // Last 20 readings
342
+ errors: this.metrics.errors.slice(-50), // Last 50 errors
343
+ alerts: this.alerts.slice(-20), // Last 20 alerts
344
+ customMetrics: Object.fromEntries(this.metrics.customMetrics)
345
+ };
346
+ }
347
+
348
+ /**
349
+ * Save metrics to file
350
+ */
351
+ async saveMetrics() {
352
+ try {
353
+ const metricsFile = join(this.config.logDir, 'metrics.json');
354
+ const metricsData = this.getDetailedMetrics();
355
+ await writeFile(metricsFile, JSON.stringify(metricsData, null, 2));
356
+ } catch (error) {
357
+ console.error('Failed to save metrics:', error);
358
+ }
359
+ }
360
+
361
+ /**
362
+ * Ensure log directory exists
363
+ */
364
+ async ensureLogDirectory() {
365
+ try {
366
+ await mkdir(this.config.logDir, { recursive: true });
367
+ } catch (error) {
368
+ if (error.code !== 'EEXIST') {
369
+ throw error;
370
+ }
371
+ }
372
+ }
373
+
374
+ /**
375
+ * Acknowledge an alert
376
+ */
377
+ acknowledgeAlert(alertId) {
378
+ const alert = this.alerts.find(a => a.id === alertId);
379
+ if (alert) {
380
+ alert.acknowledged = true;
381
+ alert.acknowledgedAt = new Date();
382
+ }
383
+ }
384
+
385
+ /**
386
+ * Get unacknowledged alerts
387
+ */
388
+ getUnacknowledgedAlerts() {
389
+ return this.alerts.filter(a => !a.acknowledged);
390
+ }
391
+ }
@@ -0,0 +1,82 @@
1
+ /**
2
+ * API Testing Module
3
+ * Specialized module for API endpoint testing
4
+ */
5
+
6
+ import fetch from 'node-fetch';
7
+
8
+ export class ApiTester {
9
+ constructor(config) {
10
+ this.config = config;
11
+ }
12
+
13
+ async runApiTests(environment) {
14
+ const results = {
15
+ passed: 0,
16
+ failed: 0,
17
+ endpoints: []
18
+ };
19
+
20
+ // Define API endpoints to test
21
+ const endpoints = [
22
+ { name: 'Health Check', url: `https://${environment}.api.example.com/health`, method: 'GET' },
23
+ { name: 'API Status', url: `https://${environment}.api.example.com/status`, method: 'GET' },
24
+ { name: 'User Profile', url: `https://${environment}.api.example.com/api/v1/user/profile`, method: 'GET', auth: true }
25
+ ];
26
+
27
+ for (const endpoint of endpoints) {
28
+ try {
29
+ const startTime = Date.now();
30
+ const response = await this.testEndpoint(endpoint, environment);
31
+ const responseTime = Date.now() - startTime;
32
+
33
+ const result = {
34
+ name: endpoint.name,
35
+ url: endpoint.url,
36
+ method: endpoint.method,
37
+ status: response.status,
38
+ responseTime,
39
+ success: response.ok && responseTime < this.config.responseTimeThreshold
40
+ };
41
+
42
+ results.endpoints.push(result);
43
+
44
+ if (result.success) {
45
+ results.passed++;
46
+ } else {
47
+ results.failed++;
48
+ }
49
+
50
+ } catch (error) {
51
+ results.endpoints.push({
52
+ name: endpoint.name,
53
+ url: endpoint.url,
54
+ method: endpoint.method,
55
+ error: error.message,
56
+ success: false
57
+ });
58
+ results.failed++;
59
+ }
60
+ }
61
+
62
+ return results;
63
+ }
64
+
65
+ async testEndpoint(endpoint, environment) {
66
+ const options = {
67
+ method: endpoint.method,
68
+ timeout: this.config.timeout,
69
+ headers: {
70
+ 'User-Agent': 'ProductionTester/2.0',
71
+ 'Accept': 'application/json'
72
+ }
73
+ };
74
+
75
+ if (endpoint.auth) {
76
+ // Add authentication headers if needed
77
+ options.headers.Authorization = `Bearer ${process.env.TEST_API_TOKEN || 'test-token'}`;
78
+ }
79
+
80
+ return await fetch(endpoint.url, options);
81
+ }
82
+ }
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Authentication Testing Module
3
+ * Specialized module for authentication flow validation
4
+ */
5
+
6
+ import fetch from 'node-fetch';
7
+
8
+ export class AuthTester {
9
+ constructor(config) {
10
+ this.config = config;
11
+ }
12
+
13
+ async runAuthTests(environment) {
14
+ const results = {
15
+ passed: 0,
16
+ failed: 0,
17
+ flows: []
18
+ };
19
+
20
+ // Authentication flows to test
21
+ const flows = [
22
+ { name: 'Login Flow', test: () => this.testLoginFlow(environment) },
23
+ { name: 'Token Validation', test: () => this.testTokenValidation(environment) },
24
+ { name: 'Logout Flow', test: () => this.testLogoutFlow(environment) }
25
+ ];
26
+
27
+ for (const flow of flows) {
28
+ try {
29
+ const startTime = Date.now();
30
+ const result = await flow.test();
31
+ const duration = Date.now() - startTime;
32
+
33
+ const flowResult = {
34
+ name: flow.name,
35
+ duration,
36
+ success: result.success && duration < this.config.authFlowThreshold,
37
+ details: result
38
+ };
39
+
40
+ results.flows.push(flowResult);
41
+
42
+ if (flowResult.success) {
43
+ results.passed++;
44
+ } else {
45
+ results.failed++;
46
+ }
47
+
48
+ } catch (error) {
49
+ results.flows.push({
50
+ name: flow.name,
51
+ error: error.message,
52
+ success: false
53
+ });
54
+ results.failed++;
55
+ }
56
+ }
57
+
58
+ return results;
59
+ }
60
+
61
+ async testLoginFlow(environment) {
62
+ try {
63
+ // Simulate login request
64
+ const response = await fetch(`https://${environment}.api.example.com/auth/login`, {
65
+ method: 'POST',
66
+ headers: {
67
+ 'Content-Type': 'application/json',
68
+ 'User-Agent': 'AuthTester/2.0'
69
+ },
70
+ body: JSON.stringify({
71
+ username: 'test@example.com',
72
+ password: 'test-password'
73
+ }),
74
+ timeout: this.config.timeout
75
+ });
76
+
77
+ return {
78
+ success: response.ok,
79
+ status: response.status,
80
+ hasToken: response.headers.has('authorization') || response.headers.has('x-auth-token')
81
+ };
82
+
83
+ } catch (error) {
84
+ return { success: false, error: error.message };
85
+ }
86
+ }
87
+
88
+ async testTokenValidation(environment) {
89
+ try {
90
+ const token = process.env.TEST_AUTH_TOKEN || 'test-jwt-token';
91
+ const response = await fetch(`https://${environment}.api.example.com/auth/validate`, {
92
+ method: 'GET',
93
+ headers: {
94
+ 'Authorization': `Bearer ${token}`,
95
+ 'User-Agent': 'AuthTester/2.0'
96
+ },
97
+ timeout: this.config.timeout
98
+ });
99
+
100
+ return {
101
+ success: response.ok,
102
+ status: response.status,
103
+ valid: response.status === 200
104
+ };
105
+
106
+ } catch (error) {
107
+ return { success: false, error: error.message };
108
+ }
109
+ }
110
+
111
+ async testLogoutFlow(environment) {
112
+ try {
113
+ const token = process.env.TEST_AUTH_TOKEN || 'test-jwt-token';
114
+ const response = await fetch(`https://${environment}.api.example.com/auth/logout`, {
115
+ method: 'POST',
116
+ headers: {
117
+ 'Authorization': `Bearer ${token}`,
118
+ 'User-Agent': 'AuthTester/2.0'
119
+ },
120
+ timeout: this.config.timeout
121
+ });
122
+
123
+ return {
124
+ success: response.ok,
125
+ status: response.status
126
+ };
127
+
128
+ } catch (error) {
129
+ return { success: false, error: error.message };
130
+ }
131
+ }
132
+ }