@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,668 @@
1
+ /**
2
+ * Pluggable Business Logic Modules
3
+ * Allows domain-specific logic to be added as optional modules
4
+ */
5
+
6
+ export class ModuleManager {
7
+ constructor() {
8
+ this.modules = new Map();
9
+ this.hooks = new Map();
10
+
11
+ // Enterprise configuration
12
+ this.config = {
13
+ defaultTimeout: 5000,
14
+ // 5 seconds default timeout per hook
15
+ maxConcurrentHooks: 10,
16
+ // Maximum concurrent hook executions
17
+ enableHookIsolation: true,
18
+ // Isolate hook execution contexts
19
+ enableMetrics: true,
20
+ // Track hook performance metrics
21
+ retryFailedHooks: false,
22
+ // Retry failed hooks (disabled by default)
23
+ maxRetries: 2 // Maximum retry attempts
24
+ };
25
+
26
+ // Hook execution metrics
27
+ this.metrics = {
28
+ totalExecutions: 0,
29
+ totalFailures: 0,
30
+ totalTimeouts: 0,
31
+ executionTimes: new Map(),
32
+ // hookName -> array of execution times
33
+ failureReasons: new Map() // hookName -> array of failure reasons
34
+ };
35
+
36
+ // Active hook executions for timeout management
37
+ this.activeExecutions = new Map();
38
+ }
39
+
40
+ /**
41
+ * Register a business logic module
42
+ * @param {string} moduleName - Name of the module
43
+ * @param {Object} module - Module definition
44
+ */
45
+ registerModule(moduleName, module) {
46
+ this.modules.set(moduleName, {
47
+ name: moduleName,
48
+ ...module
49
+ });
50
+
51
+ // Register hooks
52
+ if (module.hooks) {
53
+ Object.entries(module.hooks).forEach(([hookName, hookFn]) => {
54
+ if (!this.hooks.has(hookName)) {
55
+ this.hooks.set(hookName, []);
56
+ }
57
+ this.hooks.get(hookName).push({
58
+ module: moduleName,
59
+ fn: hookFn
60
+ });
61
+ });
62
+ }
63
+ console.log(`✅ Registered module: ${moduleName}`);
64
+ }
65
+
66
+ /**
67
+ * Get a registered module
68
+ * @param {string} moduleName - Name of the module
69
+ * @returns {Object} Module definition
70
+ */
71
+ getModule(moduleName) {
72
+ return this.modules.get(moduleName);
73
+ }
74
+
75
+ /**
76
+ * Check if a module is registered
77
+ * @param {string} moduleName - Name of the module
78
+ * @returns {boolean}
79
+ */
80
+ hasModule(moduleName) {
81
+ return this.modules.has(moduleName);
82
+ }
83
+
84
+ /**
85
+ * Execute hooks for a specific event with enterprise-grade features
86
+ * @param {string} hookName - Name of the hook
87
+ * @param {Object} context - Execution context
88
+ * @param {Object} options - Execution options
89
+ * @param {...any} args - Additional arguments
90
+ * @returns {Promise<Object>} Hook execution results with metadata
91
+ */
92
+ async executeHooks(hookName, context, options = {}, ...args) {
93
+ const executionId = this._generateExecutionId();
94
+ const startTime = Date.now();
95
+ const executionOptions = {
96
+ timeout: options.timeout || this.config.defaultTimeout,
97
+ parallel: options.parallel || false,
98
+ stopOnError: options.stopOnError || false,
99
+ retryOnFailure: options.retryOnFailure || this.config.retryFailedHooks,
100
+ maxRetries: options.maxRetries || this.config.maxRetries,
101
+ ...options
102
+ };
103
+ const hooks = this.hooks.get(hookName) || [];
104
+ const results = [];
105
+ let totalErrors = 0;
106
+ let totalTimeouts = 0;
107
+
108
+ // Track active execution
109
+ this.activeExecutions.set(executionId, {
110
+ hookName,
111
+ startTime,
112
+ hooks: hooks.length,
113
+ options: executionOptions
114
+ });
115
+ try {
116
+ if (executionOptions.parallel && hooks.length > 1) {
117
+ // Parallel execution with concurrency control
118
+ const results = await this._executeHooksParallel(hooks, hookName, context, executionOptions, args);
119
+ totalErrors = results.filter(r => !r.success).length;
120
+ totalTimeouts = results.filter(r => r.timeout).length;
121
+ return this._buildExecutionResult(executionId, hookName, results, startTime, totalErrors, totalTimeouts);
122
+ } else {
123
+ // Sequential execution
124
+ for (const hook of hooks) {
125
+ const hookResult = await this._executeHookWithRetry(hook, hookName, context, executionOptions, args);
126
+ results.push(hookResult);
127
+ if (!hookResult.success) {
128
+ totalErrors++;
129
+ if (hookResult.timeout) totalTimeouts++;
130
+
131
+ // Stop on error if configured
132
+ if (executionOptions.stopOnError) {
133
+ console.warn(`Stopping hook execution for '${hookName}' due to error in module '${hook.module}'`);
134
+ break;
135
+ }
136
+ }
137
+ }
138
+ }
139
+ return this._buildExecutionResult(executionId, hookName, results, startTime, totalErrors, totalTimeouts);
140
+ } finally {
141
+ // Clean up active execution tracking
142
+ this.activeExecutions.delete(executionId);
143
+
144
+ // Update metrics
145
+ this._updateMetrics(hookName, Date.now() - startTime, totalErrors, totalTimeouts);
146
+ }
147
+ }
148
+
149
+ /**
150
+ * Execute a single hook with retry logic
151
+ * @param {Object} hook - Hook configuration
152
+ * @param {string} hookName - Hook name
153
+ * @param {Object} context - Execution context
154
+ * @param {Object} options - Execution options
155
+ * @param {Array} args - Hook arguments
156
+ * @returns {Promise<Object>} Hook result
157
+ * @private
158
+ */
159
+ async _executeHookWithRetry(hook, hookName, context, options, args) {
160
+ let lastError = null;
161
+ let attempts = 0;
162
+ const maxAttempts = options.retryOnFailure ? options.maxRetries + 1 : 1;
163
+ while (attempts < maxAttempts) {
164
+ attempts++;
165
+ try {
166
+ const result = await this._executeHookWithTimeout(hook, hookName, context, options, args);
167
+
168
+ // Success - log retry success if this wasn't the first attempt
169
+ if (attempts > 1) {
170
+ console.info(`Hook '${hookName}' in module '${hook.module}' succeeded on attempt ${attempts}`);
171
+ }
172
+ return {
173
+ module: hook.module,
174
+ result,
175
+ success: true,
176
+ attempts,
177
+ executionTime: result.executionTime,
178
+ timeout: false
179
+ };
180
+ } catch (error) {
181
+ lastError = error;
182
+ if (attempts < maxAttempts && options.retryOnFailure) {
183
+ console.warn(`Hook '${hookName}' in module '${hook.module}' failed (attempt ${attempts}/${maxAttempts}): ${error.message}. Retrying...`);
184
+
185
+ // Wait before retry with exponential backoff
186
+ await this._sleep(Math.min(1000 * Math.pow(2, attempts - 1), 5000));
187
+ }
188
+ }
189
+ }
190
+
191
+ // All retry attempts failed
192
+ const isTimeout = lastError.name === 'TimeoutError';
193
+ console.error(`Hook '${hookName}' in module '${hook.module}' failed after ${attempts} attempts:`, lastError.message);
194
+ return {
195
+ module: hook.module,
196
+ error: lastError.message,
197
+ success: false,
198
+ attempts,
199
+ timeout: isTimeout,
200
+ errorType: lastError.name || 'UnknownError'
201
+ };
202
+ }
203
+
204
+ /**
205
+ * Execute a hook with timeout protection
206
+ * @param {Object} hook - Hook configuration
207
+ * @param {string} hookName - Hook name
208
+ * @param {Object} context - Execution context
209
+ * @param {Object} options - Execution options
210
+ * @param {Array} args - Hook arguments
211
+ * @returns {Promise<Object>} Hook result with execution time
212
+ * @private
213
+ */
214
+ async _executeHookWithTimeout(hook, hookName, context, options, args) {
215
+ const startTime = Date.now();
216
+
217
+ // Create isolated context if enabled
218
+ const executionContext = options.enableHookIsolation !== false ? this._createIsolatedContext(context, hook.module) : context;
219
+ const timeoutPromise = new Promise((_, reject) => {
220
+ setTimeout(() => {
221
+ const error = new Error(`Hook execution timeout after ${options.timeout}ms`);
222
+ error.name = 'TimeoutError';
223
+ reject(error);
224
+ }, options.timeout);
225
+ });
226
+ try {
227
+ const result = await Promise.race([hook.fn(executionContext, ...args), timeoutPromise]);
228
+ return {
229
+ result,
230
+ executionTime: Date.now() - startTime
231
+ };
232
+ } catch (error) {
233
+ // Add execution time to error context
234
+ error.executionTime = Date.now() - startTime;
235
+ throw error;
236
+ }
237
+ }
238
+
239
+ /**
240
+ * Execute hooks in parallel with concurrency control
241
+ * @param {Array} hooks - Hook configurations
242
+ * @param {string} hookName - Hook name
243
+ * @param {Object} context - Execution context
244
+ * @param {Object} options - Execution options
245
+ * @param {Array} args - Hook arguments
246
+ * @returns {Promise<Array>} Hook results
247
+ * @private
248
+ */
249
+ async _executeHooksParallel(hooks, hookName, context, options, args) {
250
+ const concurrencyLimit = Math.min(hooks.length, this.config.maxConcurrentHooks);
251
+ const results = new Array(hooks.length);
252
+
253
+ // Create execution promises
254
+ const executeHook = async hookIndex => {
255
+ const hook = hooks[hookIndex];
256
+ const result = await this._executeHookWithRetry(hook, hookName, context, options, args);
257
+ results[hookIndex] = result;
258
+ return result;
259
+ };
260
+
261
+ // Execute with concurrency control
262
+ const promises = [];
263
+ for (let i = 0; i < hooks.length; i += concurrencyLimit) {
264
+ const batch = [];
265
+ for (let j = i; j < Math.min(i + concurrencyLimit, hooks.length); j++) {
266
+ batch.push(executeHook(j));
267
+ }
268
+ promises.push(...batch);
269
+
270
+ // Wait for current batch before starting next (if not fully parallel)
271
+ if (i + concurrencyLimit < hooks.length) {
272
+ await Promise.all(batch);
273
+ }
274
+ }
275
+
276
+ // Wait for all executions to complete
277
+ await Promise.all(promises);
278
+ return results;
279
+ }
280
+
281
+ /**
282
+ * Get all registered modules
283
+ * @returns {Map} All modules
284
+ */
285
+ getAllModules() {
286
+ return this.modules;
287
+ }
288
+
289
+ /**
290
+ * Get hook execution metrics
291
+ * @param {string} hookName - Optional: specific hook name
292
+ * @returns {Object} Execution metrics
293
+ */
294
+ getMetrics(hookName = null) {
295
+ if (hookName) {
296
+ return {
297
+ executions: this.metrics.executionTimes.get(hookName)?.length || 0,
298
+ averageTime: this._calculateAverageTime(hookName),
299
+ failures: this.metrics.failureReasons.get(hookName)?.length || 0,
300
+ successRate: this._calculateSuccessRate(hookName)
301
+ };
302
+ }
303
+ return {
304
+ totalExecutions: this.metrics.totalExecutions,
305
+ totalFailures: this.metrics.totalFailures,
306
+ totalTimeouts: this.metrics.totalTimeouts,
307
+ overallSuccessRate: this._calculateOverallSuccessRate(),
308
+ hookMetrics: this._getAllHookMetrics()
309
+ };
310
+ }
311
+
312
+ /**
313
+ * Clear execution metrics
314
+ * @param {string} hookName - Optional: specific hook to clear
315
+ */
316
+ clearMetrics(hookName = null) {
317
+ if (hookName) {
318
+ this.metrics.executionTimes.delete(hookName);
319
+ this.metrics.failureReasons.delete(hookName);
320
+ } else {
321
+ this.metrics.totalExecutions = 0;
322
+ this.metrics.totalFailures = 0;
323
+ this.metrics.totalTimeouts = 0;
324
+ this.metrics.executionTimes.clear();
325
+ this.metrics.failureReasons.clear();
326
+ }
327
+ }
328
+
329
+ /**
330
+ * Update module manager configuration
331
+ * @param {Object} config - New configuration options
332
+ */
333
+ updateConfig(config) {
334
+ this.config = {
335
+ ...this.config,
336
+ ...config
337
+ };
338
+ }
339
+
340
+ /**
341
+ * Get active hook executions
342
+ * @returns {Array} Active executions
343
+ */
344
+ getActiveExecutions() {
345
+ const now = Date.now();
346
+ return Array.from(this.activeExecutions.entries()).map(([id, execution]) => ({
347
+ id,
348
+ hookName: execution.hookName,
349
+ duration: now - execution.startTime,
350
+ hookCount: execution.hooks,
351
+ options: execution.options
352
+ }));
353
+ }
354
+
355
+ // Private helper methods
356
+
357
+ /**
358
+ * Generate unique execution ID
359
+ * @returns {string} Execution ID
360
+ * @private
361
+ */
362
+ _generateExecutionId() {
363
+ return `exec_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
364
+ }
365
+
366
+ /**
367
+ * Create isolated execution context
368
+ * @param {Object} originalContext - Original context
369
+ * @param {string} moduleName - Module name
370
+ * @returns {Object} Isolated context
371
+ * @private
372
+ */
373
+ _createIsolatedContext(originalContext, moduleName) {
374
+ return {
375
+ ...originalContext,
376
+ _module: moduleName,
377
+ _isolated: true,
378
+ _timestamp: Date.now()
379
+ };
380
+ }
381
+
382
+ /**
383
+ * Sleep utility for retry delays
384
+ * @param {number} ms - Milliseconds to sleep
385
+ * @returns {Promise<void>}
386
+ * @private
387
+ */
388
+ _sleep(ms) {
389
+ return new Promise(resolve => setTimeout(resolve, ms));
390
+ }
391
+
392
+ /**
393
+ * Build comprehensive execution result
394
+ * @param {string} executionId - Execution ID
395
+ * @param {string} hookName - Hook name
396
+ * @param {Array} results - Individual hook results
397
+ * @param {number} startTime - Execution start time
398
+ * @param {number} totalErrors - Total error count
399
+ * @param {number} totalTimeouts - Total timeout count
400
+ * @returns {Object} Execution result
401
+ * @private
402
+ */
403
+ _buildExecutionResult(executionId, hookName, results, startTime, totalErrors, totalTimeouts) {
404
+ const executionTime = Date.now() - startTime;
405
+ const successfulHooks = results.filter(r => r.success);
406
+ const failedHooks = results.filter(r => !r.success);
407
+ return {
408
+ executionId,
409
+ hookName,
410
+ executionTime,
411
+ totalHooks: results.length,
412
+ successful: successfulHooks.length,
413
+ failed: failedHooks.length,
414
+ timeouts: totalTimeouts,
415
+ successRate: results.length > 0 ? successfulHooks.length / results.length * 100 : 0,
416
+ results,
417
+ summary: {
418
+ overallSuccess: totalErrors === 0,
419
+ hasTimeouts: totalTimeouts > 0,
420
+ partialSuccess: successfulHooks.length > 0 && failedHooks.length > 0
421
+ }
422
+ };
423
+ }
424
+
425
+ /**
426
+ * Update execution metrics
427
+ * @param {string} hookName - Hook name
428
+ * @param {number} executionTime - Execution time
429
+ * @param {number} errorCount - Error count
430
+ * @param {number} timeoutCount - Timeout count
431
+ * @private
432
+ */
433
+ _updateMetrics(hookName, executionTime, errorCount, timeoutCount) {
434
+ if (!this.config.enableMetrics) return;
435
+ this.metrics.totalExecutions++;
436
+ this.metrics.totalFailures += errorCount;
437
+ this.metrics.totalTimeouts += timeoutCount;
438
+ if (!this.metrics.executionTimes.has(hookName)) {
439
+ this.metrics.executionTimes.set(hookName, []);
440
+ }
441
+ this.metrics.executionTimes.get(hookName).push(executionTime);
442
+
443
+ // Keep only last 100 execution times per hook to prevent memory leaks
444
+ const times = this.metrics.executionTimes.get(hookName);
445
+ if (times.length > 100) {
446
+ times.splice(0, times.length - 100);
447
+ }
448
+ }
449
+
450
+ /**
451
+ * Calculate average execution time for a hook
452
+ * @param {string} hookName - Hook name
453
+ * @returns {number} Average time in ms
454
+ * @private
455
+ */
456
+ _calculateAverageTime(hookName) {
457
+ const times = this.metrics.executionTimes.get(hookName) || [];
458
+ if (times.length === 0) return 0;
459
+ return times.reduce((sum, time) => sum + time, 0) / times.length;
460
+ }
461
+
462
+ /**
463
+ * Calculate success rate for a hook
464
+ * @param {string} hookName - Hook name
465
+ * @returns {number} Success rate percentage
466
+ * @private
467
+ */
468
+ _calculateSuccessRate(hookName) {
469
+ const executions = this.metrics.executionTimes.get(hookName)?.length || 0;
470
+ const failures = this.metrics.failureReasons.get(hookName)?.length || 0;
471
+ if (executions === 0) return 100;
472
+ return (executions - failures) / executions * 100;
473
+ }
474
+
475
+ /**
476
+ * Calculate overall success rate
477
+ * @returns {number} Overall success rate percentage
478
+ * @private
479
+ */
480
+ _calculateOverallSuccessRate() {
481
+ if (this.metrics.totalExecutions === 0) return 100;
482
+ return (this.metrics.totalExecutions - this.metrics.totalFailures) / this.metrics.totalExecutions * 100;
483
+ }
484
+
485
+ /**
486
+ * Get metrics for all hooks
487
+ * @returns {Object} All hook metrics
488
+ * @private
489
+ */
490
+ _getAllHookMetrics() {
491
+ const metrics = {};
492
+ for (const hookName of this.metrics.executionTimes.keys()) {
493
+ metrics[hookName] = this.getMetrics(hookName);
494
+ }
495
+ return metrics;
496
+ }
497
+ }
498
+
499
+ // Create singleton instance
500
+ export const moduleManager = new ModuleManager();
501
+
502
+ // Pre-register existing modules for backward compatibility
503
+
504
+ // Authentication Module
505
+ moduleManager.registerModule('auth', {
506
+ name: 'auth',
507
+ description: 'Authentication and user management',
508
+ // Custom methods
509
+ methods: {
510
+ async createMagicLink(dataService, email, userId, expiresMinutes = 15) {
511
+ const expiresAt = new Date();
512
+ expiresAt.setMinutes(expiresAt.getMinutes() + expiresMinutes);
513
+ return await dataService.create({
514
+ token: crypto.randomUUID(),
515
+ user_id: userId,
516
+ email,
517
+ expires_at: expiresAt.toISOString()
518
+ });
519
+ },
520
+ async verifyMagicLink(dataService, token) {
521
+ const magicLink = await dataService.findById(token);
522
+ if (!magicLink) {
523
+ throw new Error('Magic link not found');
524
+ }
525
+ if (new Date() > new Date(magicLink.expires_at)) {
526
+ throw new Error('Magic link expired');
527
+ }
528
+ if (magicLink.used) {
529
+ throw new Error('Magic link already used');
530
+ }
531
+
532
+ // Mark as used
533
+ await dataService.update(token, {
534
+ used: 1
535
+ });
536
+ return magicLink;
537
+ },
538
+ async createAuthToken(dataService, userId, type = 'access', expiresHours = 24) {
539
+ const expiresAt = expiresHours ? new Date(Date.now() + expiresHours * 60 * 60 * 1000).toISOString() : null;
540
+ return await dataService.create({
541
+ token: crypto.randomUUID(),
542
+ user_id: userId,
543
+ type,
544
+ expires_at: expiresAt
545
+ });
546
+ },
547
+ async validateToken(dataService, token, type = null) {
548
+ const tokenRecord = await dataService.find({
549
+ token
550
+ })[0];
551
+ if (!tokenRecord) {
552
+ return null;
553
+ }
554
+ if (type && tokenRecord.type !== type) {
555
+ return null;
556
+ }
557
+ if (tokenRecord.expires_at && new Date() > new Date(tokenRecord.expires_at)) {
558
+ return null;
559
+ }
560
+ return tokenRecord;
561
+ }
562
+ },
563
+ // Hooks
564
+ hooks: {
565
+ 'user.created': async (context, userData) => {
566
+ console.log(`Auth module: User created: ${userData.email}`);
567
+ // Could send welcome email, create default settings, etc.
568
+ },
569
+ 'user.deleted': async (context, userId) => {
570
+ console.log(`Auth module: User deleted: ${userId}`);
571
+ // Could clean up related data, revoke sessions, etc.
572
+ }
573
+ }
574
+ });
575
+
576
+ // File Management Module
577
+ moduleManager.registerModule('files', {
578
+ name: 'files',
579
+ description: 'File upload and management',
580
+ methods: {
581
+ async createFileRecord(dataService, fileData) {
582
+ return await dataService.create({
583
+ ...fileData,
584
+ status: fileData.status || 'uploaded'
585
+ });
586
+ },
587
+ async updateFileStatus(dataService, fileId, status) {
588
+ return await dataService.update(fileId, {
589
+ status,
590
+ updated_at: new Date().toISOString()
591
+ });
592
+ },
593
+ async getUserFiles(dataService, userId, status = null) {
594
+ const criteria = {
595
+ user_id: userId
596
+ };
597
+ if (status) {
598
+ criteria.status = status;
599
+ }
600
+ return await dataService.find(criteria);
601
+ },
602
+ async getFileStats(dataService, userId) {
603
+ const allFiles = await dataService.find({
604
+ user_id: userId
605
+ });
606
+ const stats = {
607
+ total: allFiles.length,
608
+ byStatus: {},
609
+ totalSize: 0
610
+ };
611
+ allFiles.forEach(file => {
612
+ stats.byStatus[file.status] = (stats.byStatus[file.status] || 0) + 1;
613
+ stats.totalSize += file.size || 0;
614
+ });
615
+ return stats;
616
+ }
617
+ },
618
+ hooks: {
619
+ 'file.uploaded': async (context, fileData) => {
620
+ console.log(`Files module: File uploaded: ${fileData.filename}`);
621
+ // Could trigger processing, virus scanning, etc.
622
+ },
623
+ 'file.deleted': async (context, fileId) => {
624
+ console.log(`Files module: File deleted: ${fileId}`);
625
+ // Could clean up physical files, update storage quotas, etc.
626
+ }
627
+ }
628
+ });
629
+
630
+ // Logging Module
631
+ moduleManager.registerModule('logging', {
632
+ name: 'logging',
633
+ description: 'Centralized logging and audit trails',
634
+ methods: {
635
+ async logActivity(dataService, level, message, userId = null, metadata = {}) {
636
+ return await dataService.create({
637
+ level: level.toUpperCase(),
638
+ message,
639
+ user_id: userId,
640
+ metadata: JSON.stringify(metadata)
641
+ });
642
+ },
643
+ async getUserActivity(dataService, userId, limit = 50) {
644
+ return await dataService.find({
645
+ user_id: userId
646
+ }, {
647
+ limit,
648
+ orderBy: 'timestamp DESC'
649
+ });
650
+ },
651
+ async getRecentLogs(dataService, level = null, limit = 100) {
652
+ const criteria = {};
653
+ if (level) {
654
+ criteria.level = level.toUpperCase();
655
+ }
656
+ return await dataService.find(criteria, {
657
+ limit,
658
+ orderBy: 'timestamp DESC'
659
+ });
660
+ }
661
+ },
662
+ hooks: {
663
+ 'system.cleanup': async (context, cleanupData) => {
664
+ await context.loggingService.logActivity('INFO', `Data cleanup performed: ${cleanupData.operation}`, null, cleanupData);
665
+ }
666
+ }
667
+ });
668
+ console.log('✅ Module Manager initialized with core modules');