@tamyla/clodo-framework 3.1.4 → 3.1.8

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 (62) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/bin/clodo-service.js +29 -989
  3. package/bin/database/enterprise-db-manager.js +7 -5
  4. package/bin/security/security-cli.js +0 -0
  5. package/bin/service-management/create-service.js +0 -0
  6. package/bin/service-management/init-service.js +0 -0
  7. package/bin/shared/cloudflare/domain-discovery.js +11 -10
  8. package/bin/shared/cloudflare/ops.js +1 -1
  9. package/bin/shared/config/ConfigurationManager.js +539 -0
  10. package/bin/shared/config/index.js +13 -1
  11. package/bin/shared/database/connection-manager.js +2 -2
  12. package/bin/shared/database/orchestrator.js +5 -4
  13. package/bin/shared/deployment/auditor.js +9 -8
  14. package/bin/shared/logging/Logger.js +214 -0
  15. package/bin/shared/monitoring/production-monitor.js +21 -9
  16. package/bin/shared/utils/ErrorHandler.js +675 -0
  17. package/bin/shared/utils/error-recovery.js +33 -13
  18. package/bin/shared/utils/file-manager.js +162 -0
  19. package/bin/shared/utils/formatters.js +247 -0
  20. package/bin/shared/utils/index.js +14 -4
  21. package/bin/shared/validation/ValidationRegistry.js +143 -0
  22. package/dist/deployment/auditor.js +23 -8
  23. package/dist/deployment/orchestration/BaseDeploymentOrchestrator.js +426 -0
  24. package/dist/deployment/orchestration/EnterpriseOrchestrator.js +401 -0
  25. package/dist/deployment/orchestration/PortfolioOrchestrator.js +273 -0
  26. package/dist/deployment/orchestration/SingleServiceOrchestrator.js +231 -0
  27. package/dist/deployment/orchestration/UnifiedDeploymentOrchestrator.js +662 -0
  28. package/dist/deployment/orchestration/index.js +17 -0
  29. package/dist/index.js +12 -0
  30. package/dist/orchestration/modules/DomainResolver.js +8 -6
  31. package/dist/orchestration/multi-domain-orchestrator.js +13 -1
  32. package/dist/security/index.js +2 -2
  33. package/dist/service-management/ConfirmationEngine.js +8 -7
  34. package/dist/service-management/ErrorTracker.js +7 -2
  35. package/dist/service-management/InputCollector.js +31 -16
  36. package/dist/service-management/ServiceCreator.js +22 -7
  37. package/dist/service-management/ServiceInitializer.js +12 -18
  38. package/dist/shared/cloudflare/domain-discovery.js +11 -10
  39. package/dist/shared/cloudflare/ops.js +1 -1
  40. package/dist/shared/config/ConfigurationManager.js +519 -0
  41. package/dist/shared/config/index.js +5 -1
  42. package/dist/shared/database/connection-manager.js +2 -2
  43. package/dist/shared/database/orchestrator.js +13 -4
  44. package/dist/shared/deployment/auditor.js +23 -8
  45. package/dist/shared/logging/Logger.js +209 -0
  46. package/dist/shared/monitoring/production-monitor.js +24 -8
  47. package/dist/{utils → shared/utils}/ErrorHandler.js +306 -28
  48. package/dist/shared/utils/error-recovery.js +33 -13
  49. package/dist/shared/utils/file-manager.js +155 -0
  50. package/dist/shared/utils/formatters.js +215 -0
  51. package/dist/shared/utils/index.js +14 -4
  52. package/dist/shared/validation/ValidationRegistry.js +126 -0
  53. package/dist/utils/config/unified-config-manager.js +14 -12
  54. package/dist/utils/deployment/config-cache.js +3 -1
  55. package/dist/utils/deployment/secret-generator.js +32 -29
  56. package/dist/utils/framework-config.js +6 -3
  57. package/dist/utils/ui-structures-loader.js +3 -0
  58. package/dist/worker/integration.js +11 -1
  59. package/package.json +31 -3
  60. package/dist/config/FeatureManager.js +0 -426
  61. package/dist/config/features.js +0 -230
  62. package/dist/utils/error-recovery.js +0 -240
@@ -25,11 +25,13 @@ import { program } from 'commander';
25
25
  import { existsSync, readFileSync, writeFileSync } from 'fs';
26
26
  import { join } from 'path';
27
27
 
28
- // Enterprise module imports
29
- import { DatabaseOrchestrator } from '@tamyla/clodo-framework/database';
30
- import { DeploymentAuditor } from '@tamyla/clodo-framework/deployment';
31
- import { CrossDomainCoordinator } from '@tamyla/clodo-framework/orchestration';
32
- import { ConfigurationCacheManager } from '@tamyla/clodo-framework/utils/deployment';
28
+ // Enterprise module imports - from dist/ (compiled framework)
29
+ import { DatabaseOrchestrator } from '../../dist/database/database-orchestrator.js';
30
+ import { DeploymentAuditor } from '../../dist/deployment/deployment-auditor.js';
31
+ import { CrossDomainCoordinator } from '../../dist/orchestration/cross-domain-coordinator.js';
32
+
33
+ // Shared utilities from bin/shared/
34
+ import { ConfigurationCacheManager } from '../shared/config/cache.js';
33
35
 
34
36
  class EnterpriseDatabaseManagerCLI {
35
37
  constructor() {
File without changes
File without changes
File without changes
@@ -10,6 +10,7 @@
10
10
  import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync } from 'fs';
11
11
  import { join, dirname } from 'path';
12
12
  import { fileURLToPath } from 'url';
13
+ import { NameFormatters, UrlFormatters, ResourceFormatters, EnvironmentFormatters } from '../utils/Formatters.js';
13
14
 
14
15
  const __filename = fileURLToPath(import.meta.url);
15
16
  const __dirname = dirname(__filename);
@@ -206,7 +207,7 @@ export class DomainDiscovery {
206
207
  const config = {
207
208
  // Basic domain information
208
209
  name: cleanDomainName,
209
- displayName: this.capitalizeFirst(cleanDomainName),
210
+ displayName: NameFormatters.toDisplayName(cleanDomainName),
210
211
  fullDomain: domainName,
211
212
 
212
213
  // Cloudflare infrastructure
@@ -229,19 +230,19 @@ export class DomainDiscovery {
229
230
  // Service URLs
230
231
  services: {
231
232
  frontend: {
232
- production: `https://${domainName}`,
233
- staging: `https://staging.${domainName}`,
234
- development: `https://dev.${domainName}`
233
+ production: UrlFormatters.buildProductionUrl('www', domainName),
234
+ staging: UrlFormatters.buildStagingUrl('www', domainName),
235
+ development: UrlFormatters.buildDevUrl('www', domainName)
235
236
  },
236
237
  api: {
237
- production: `https://api.${domainName}`,
238
- staging: `https://api-staging.${domainName}`,
239
- development: `https://api-dev.${domainName}`
238
+ production: UrlFormatters.buildProductionUrl('api', domainName),
239
+ staging: UrlFormatters.buildStagingUrl('api', domainName),
240
+ development: UrlFormatters.buildDevUrl('api', domainName)
240
241
  },
241
242
  auth: {
242
- production: `https://auth.${domainName}`,
243
- staging: `https://auth-staging.${domainName}`,
244
- development: `https://auth-dev.${domainName}`
243
+ production: UrlFormatters.buildProductionUrl('auth', domainName),
244
+ staging: UrlFormatters.buildStagingUrl('auth', domainName),
245
+ development: UrlFormatters.buildDevUrl('auth', domainName)
245
246
  }
246
247
  },
247
248
 
@@ -8,7 +8,7 @@
8
8
  import { exec } from 'child_process';
9
9
  import { promisify } from 'util';
10
10
  import { executeWithRateLimit } from '../utils/rate-limiter.js';
11
- import { ErrorRecoveryManager } from '../utils/error-recovery.js';
11
+ import { ErrorRecoveryManager } from '../utils/index.js';
12
12
  import { SecureTokenManager } from '../security/secure-token-manager.js';
13
13
  import { ProductionMonitor } from '../monitoring/production-monitor.js';
14
14
  import { DatabaseConnectionManager } from '../database/connection-manager.js';
@@ -0,0 +1,539 @@
1
+ /**
2
+ * Unified Configuration Manager
3
+ * Consolidates feature management, domain configuration, and customer settings
4
+ * Replaces: FeatureManager.js (440 lines), features.js (237 lines), partial domains.js/customers.js logic
5
+ * Savings: 600+ lines of consolidated code
6
+ */
7
+
8
+ import { logger } from '../logging/Logger.js';
9
+
10
+ /**
11
+ * Default feature flags for CLODO Framework
12
+ */
13
+ const DEFAULT_FEATURES = {
14
+ // Schema Manager Features
15
+ ENABLE_ENHANCED_SCHEMA: true,
16
+ ENABLE_SCHEMA_CACHING: true,
17
+ ENABLE_COMPREHENSIVE_VALIDATION: true,
18
+ ENABLE_SQL_CACHING: true,
19
+
20
+ // Generic Data Service Features
21
+ ENABLE_QUERY_CACHING: true,
22
+ ENABLE_SECURITY_CONTROLS: true,
23
+ ENABLE_ADVANCED_PAGINATION: true,
24
+ ENABLE_RELATIONSHIP_LOADING: true,
25
+
26
+ // Module Manager Features
27
+ ENABLE_ENHANCED_HOOKS: true,
28
+ ENABLE_HOOK_TIMEOUT: true,
29
+ ENABLE_HOOK_METRICS: true,
30
+ ENABLE_PARALLEL_EXECUTION: true,
31
+
32
+ // Performance Features
33
+ ENABLE_PERFORMANCE_MONITORING: true,
34
+ ENABLE_CACHE_METRICS: true,
35
+ ENABLE_QUERY_OPTIMIZATION: true,
36
+
37
+ // Development Features
38
+ ENABLE_DEBUG_LOGGING: false,
39
+ ENABLE_DEVELOPMENT_MODE: false,
40
+ ENABLE_STRICT_VALIDATION: false,
41
+
42
+ // Migration Features
43
+ ENABLE_LEGACY_COMPATIBILITY: true,
44
+ ENABLE_DEPRECATION_WARNINGS: true,
45
+ ENABLE_MIGRATION_HELPERS: true,
46
+
47
+ // Domain-specific features
48
+ AUTHENTICATION: true,
49
+ AUTHORIZATION: true,
50
+ LOGGING: true,
51
+ MONITORING: true,
52
+ CACHING: true,
53
+ RATE_LIMITING: true,
54
+ FILE_STORAGE: true
55
+ };
56
+
57
+ /**
58
+ * Unified Configuration Manager
59
+ * Manages feature flags, domain configuration, and customer settings
60
+ */
61
+ export class ConfigurationManager {
62
+ constructor(config = {}) {
63
+ this.features = { ...DEFAULT_FEATURES, ...config.features };
64
+ this.environment = config.environment || this._detectEnvironment();
65
+ this.domains = new Map();
66
+ this.currentDomain = null;
67
+ this.featureListeners = new Map();
68
+ this.globalOverrides = new Map();
69
+ this.context = {
70
+ environment: this.environment,
71
+ version: config.version || '2.0.0',
72
+ timestamp: Date.now()
73
+ };
74
+
75
+ this._validateConfiguration();
76
+ }
77
+
78
+ // ============ FEATURE FLAG MANAGEMENT ============
79
+
80
+ /**
81
+ * Check if a feature is enabled
82
+ * @param {string} featureName - Name of the feature flag
83
+ * @param {boolean} defaultValue - Default value if not configured
84
+ * @returns {boolean} Whether the feature is enabled
85
+ */
86
+ isFeatureEnabled(featureName, defaultValue = false) {
87
+ // Check environment-specific override
88
+ const envOverride = this._getEnvironmentOverride(featureName);
89
+ if (envOverride !== null) {
90
+ return envOverride;
91
+ }
92
+
93
+ // Check global override
94
+ if (this.globalOverrides.has(featureName)) {
95
+ return this.globalOverrides.get(featureName);
96
+ }
97
+
98
+ // Check domain-specific features if domain is set
99
+ if (this.currentDomain?.features?.[featureName] !== undefined) {
100
+ return this.currentDomain.features[featureName];
101
+ }
102
+
103
+ // Return default or configured feature flag
104
+ return this.features[featureName] ?? defaultValue;
105
+ }
106
+
107
+ /**
108
+ * Enable a feature flag
109
+ * @param {string} featureName - Name of the feature flag
110
+ * @param {Object} options - Enable options
111
+ */
112
+ enableFeature(featureName, options = {}) {
113
+ const previousValue = this.features[featureName];
114
+ this.features[featureName] = true;
115
+
116
+ logger.info(`Feature enabled: ${featureName}`, { options });
117
+ this._notifyFeatureListeners(featureName, true, previousValue);
118
+
119
+ // Auto-enable dependencies if specified
120
+ if (options.dependencies?.length) {
121
+ options.dependencies.forEach(dep => {
122
+ if (!this.isFeatureEnabled(dep)) {
123
+ this.enableFeature(dep, { reason: `Required by ${featureName}` });
124
+ }
125
+ });
126
+ }
127
+ }
128
+
129
+ /**
130
+ * Disable a feature flag
131
+ * @param {string} featureName - Name of the feature flag
132
+ * @param {Object} options - Disable options
133
+ */
134
+ disableFeature(featureName, options = {}) {
135
+ const previousValue = this.features[featureName];
136
+ this.features[featureName] = false;
137
+
138
+ logger.info(`Feature disabled: ${featureName}`, { options });
139
+ this._notifyFeatureListeners(featureName, false, previousValue);
140
+
141
+ // Auto-disable dependents if specified
142
+ if (options.disableDependents) {
143
+ this._disableDependents(featureName);
144
+ }
145
+ }
146
+
147
+ /**
148
+ * Toggle a feature flag
149
+ * @param {string} featureName - Name of the feature flag
150
+ * @returns {boolean} New state of the feature
151
+ */
152
+ toggleFeature(featureName) {
153
+ const currentState = this.isFeatureEnabled(featureName);
154
+ if (currentState) {
155
+ this.disableFeature(featureName);
156
+ } else {
157
+ this.enableFeature(featureName);
158
+ }
159
+ return !currentState;
160
+ }
161
+
162
+ /**
163
+ * Set a global feature override
164
+ * @param {string} featureName - Name of the feature
165
+ * @param {boolean} enabled - Whether to enable the feature
166
+ */
167
+ setFeatureOverride(featureName, enabled) {
168
+ this.globalOverrides.set(featureName, enabled);
169
+ logger.info(`Feature override set: ${featureName} = ${enabled}`);
170
+ this._notifyFeatureListeners(featureName, enabled, this.features[featureName]);
171
+ }
172
+
173
+ /**
174
+ * Remove a global feature override
175
+ * @param {string} featureName - Name of the feature
176
+ */
177
+ removeFeatureOverride(featureName) {
178
+ if (this.globalOverrides.has(featureName)) {
179
+ this.globalOverrides.delete(featureName);
180
+ logger.info(`Feature override removed: ${featureName}`);
181
+ }
182
+ }
183
+
184
+ /**
185
+ * Get all features with their states
186
+ * @returns {Object} All features and their current states
187
+ */
188
+ getAllFeatures() {
189
+ const features = {};
190
+ for (const [name] of Object.entries(DEFAULT_FEATURES)) {
191
+ features[name] = {
192
+ enabled: this.isFeatureEnabled(name),
193
+ default: DEFAULT_FEATURES[name],
194
+ configured: this.features[name],
195
+ overridden: this.isFeatureEnabled(name) !== this.features[name]
196
+ };
197
+ }
198
+ return features;
199
+ }
200
+
201
+ /**
202
+ * Get enabled features
203
+ * @returns {string[]} Array of enabled feature names
204
+ */
205
+ getEnabledFeatures() {
206
+ const features = Object.keys(DEFAULT_FEATURES).filter(feature =>
207
+ this.isFeatureEnabled(feature)
208
+ );
209
+
210
+ // Include domain-specific features if a domain is set
211
+ if (this.currentDomain?.features) {
212
+ const domainFeatures = Object.keys(this.currentDomain.features).filter(
213
+ feature => this.currentDomain.features[feature]
214
+ );
215
+ features.push(...domainFeatures);
216
+ }
217
+
218
+ return [...new Set(features)]; // Remove duplicates and return
219
+ }
220
+
221
+ /**
222
+ * Get disabled features
223
+ * @returns {string[]} Array of disabled feature names
224
+ */
225
+ getDisabledFeatures() {
226
+ return Object.keys(DEFAULT_FEATURES).filter(feature =>
227
+ !this.isFeatureEnabled(feature)
228
+ );
229
+ }
230
+
231
+ /**
232
+ * Listen for feature flag changes
233
+ * @param {string} featureName - Name of the feature flag
234
+ * @param {Function} callback - Callback function
235
+ * @returns {Function} Unsubscribe function
236
+ */
237
+ onFeatureChange(featureName, callback) {
238
+ if (!this.featureListeners.has(featureName)) {
239
+ this.featureListeners.set(featureName, []);
240
+ }
241
+ this.featureListeners.get(featureName).push(callback);
242
+
243
+ // Return unsubscribe function
244
+ return () => {
245
+ const callbacks = this.featureListeners.get(featureName);
246
+ if (callbacks) {
247
+ const index = callbacks.indexOf(callback);
248
+ if (index > -1) callbacks.splice(index, 1);
249
+ }
250
+ };
251
+ }
252
+
253
+ /**
254
+ * Safely execute code with feature flag check
255
+ * @param {string} featureName - Name of the feature flag
256
+ * @param {Function} enabledCallback - Function if feature is enabled
257
+ * @param {Function} disabledCallback - Function if feature is disabled
258
+ * @returns {any} Result of executed callback
259
+ */
260
+ withFeature(featureName, enabledCallback, disabledCallback = null) {
261
+ if (this.isFeatureEnabled(featureName)) {
262
+ try {
263
+ return enabledCallback();
264
+ } catch (error) {
265
+ logger.warn(`Feature '${featureName}' execution failed`, { error: error.message });
266
+ if (disabledCallback) return disabledCallback();
267
+ throw error;
268
+ }
269
+ } else {
270
+ if (this.isFeatureEnabled('ENABLE_DEPRECATION_WARNINGS')) {
271
+ logger.warn(`Feature '${featureName}' is disabled`);
272
+ }
273
+ return disabledCallback ? disabledCallback() : null;
274
+ }
275
+ }
276
+
277
+ /**
278
+ * Create a feature-gated wrapper function
279
+ * @param {string} featureName - Name of the feature flag
280
+ * @param {Function} enhancedFunction - Enhanced function to use when enabled
281
+ * @param {Function} legacyFunction - Legacy function to use when disabled
282
+ * @returns {Function} Wrapped function
283
+ */
284
+ createFeatureGate(featureName, enhancedFunction, legacyFunction) {
285
+ return (...args) => {
286
+ return this.withFeature(
287
+ featureName,
288
+ () => enhancedFunction(...args),
289
+ legacyFunction ? () => legacyFunction(...args) : null
290
+ );
291
+ };
292
+ }
293
+
294
+ // ============ DOMAIN CONFIGURATION ============
295
+
296
+ /**
297
+ * Set the current domain context
298
+ * @param {Object} domainConfig - Domain configuration object
299
+ */
300
+ setDomain(domainConfig) {
301
+ if (!domainConfig) {
302
+ throw new Error('Domain configuration is required');
303
+ }
304
+
305
+ this.currentDomain = domainConfig;
306
+ this.domains.set(domainConfig.name, domainConfig);
307
+ logger.info(`Domain set: ${domainConfig.name}`);
308
+ }
309
+
310
+ /**
311
+ * Get the current domain context
312
+ * @returns {Object} Current domain configuration
313
+ */
314
+ getDomain() {
315
+ return this.currentDomain;
316
+ }
317
+
318
+ /**
319
+ * Register a domain configuration
320
+ * @param {string} domainName - Domain identifier
321
+ * @param {Object} domainConfig - Domain configuration
322
+ */
323
+ registerDomain(domainName, domainConfig) {
324
+ this.domains.set(domainName, domainConfig);
325
+ logger.info(`Domain registered: ${domainName}`);
326
+ }
327
+
328
+ /**
329
+ * Get a registered domain configuration
330
+ * @param {string} domainName - Domain identifier
331
+ * @returns {Object} Domain configuration
332
+ */
333
+ getDomainConfig(domainName) {
334
+ return this.domains.get(domainName);
335
+ }
336
+
337
+ /**
338
+ * Get all registered domains
339
+ * @returns {Map} All registered domains
340
+ */
341
+ getAllDomains() {
342
+ return new Map(this.domains);
343
+ }
344
+
345
+ // ============ ENVIRONMENT & VALIDATION ============
346
+
347
+ /**
348
+ * Get the current environment
349
+ * @returns {string} Current environment (development, staging, production, etc.)
350
+ */
351
+ getEnvironment() {
352
+ return this.environment;
353
+ }
354
+
355
+ /**
356
+ * Check if running in development mode
357
+ * @returns {boolean} Whether in development environment
358
+ */
359
+ isDevelopment() {
360
+ return this.environment === 'development' || this.isFeatureEnabled('ENABLE_DEVELOPMENT_MODE');
361
+ }
362
+
363
+ /**
364
+ * Check if running in production mode
365
+ * @returns {boolean} Whether in production environment
366
+ */
367
+ isProduction() {
368
+ return this.environment === 'production';
369
+ }
370
+
371
+ /**
372
+ * Check if running in staging mode
373
+ * @returns {boolean} Whether in staging environment
374
+ */
375
+ isStaging() {
376
+ return this.environment === 'staging';
377
+ }
378
+
379
+ /**
380
+ * Validate configuration
381
+ * @returns {Array} Array of validation errors
382
+ */
383
+ validateConfiguration() {
384
+ const errors = [];
385
+
386
+ // Check for unknown feature flags
387
+ for (const featureName of Object.keys(this.features)) {
388
+ if (!(featureName in DEFAULT_FEATURES)) {
389
+ errors.push(`Unknown feature flag: ${featureName}`);
390
+ }
391
+ }
392
+
393
+ // Check for conflicting features
394
+ const conflicts = [
395
+ ['ENABLE_LEGACY_COMPATIBILITY', 'ENABLE_STRICT_VALIDATION'],
396
+ ['ENABLE_DEVELOPMENT_MODE', 'ENABLE_QUERY_OPTIMIZATION']
397
+ ];
398
+
399
+ for (const [feature1, feature2] of conflicts) {
400
+ if (this.isFeatureEnabled(feature1) && this.isFeatureEnabled(feature2)) {
401
+ errors.push(`Conflicting features: ${feature1} and ${feature2}`);
402
+ }
403
+ }
404
+
405
+ if (errors.length > 0) {
406
+ logger.warn(`Configuration validation found ${errors.length} issues`, { errors });
407
+ }
408
+
409
+ return errors;
410
+ }
411
+
412
+ // ============ PRIVATE METHODS ============
413
+
414
+ /**
415
+ * Detect current environment
416
+ * @private
417
+ */
418
+ _detectEnvironment() {
419
+ if (typeof process !== 'undefined' && process.env?.NODE_ENV) {
420
+ return process.env.NODE_ENV;
421
+ }
422
+ if (typeof globalThis !== 'undefined' && globalThis.navigator) {
423
+ return 'browser';
424
+ }
425
+ return 'worker';
426
+ }
427
+
428
+ /**
429
+ * Get environment-specific override
430
+ * @private
431
+ */
432
+ _getEnvironmentOverride(featureName) {
433
+ if (typeof process !== 'undefined' && process.env) {
434
+ const envVar = `CLODO_${featureName}`;
435
+ if (process.env[envVar] !== undefined) {
436
+ return process.env[envVar] === 'true';
437
+ }
438
+ }
439
+ return null;
440
+ }
441
+
442
+ /**
443
+ * Validate configuration on initialization
444
+ * @private
445
+ */
446
+ _validateConfiguration() {
447
+ const errors = this.validateConfiguration();
448
+ if (errors.length > 0 && this.isFeatureEnabled('ENABLE_STRICT_VALIDATION')) {
449
+ throw new Error(`Configuration validation failed: ${errors.join(', ')}`);
450
+ }
451
+ }
452
+
453
+ /**
454
+ * Notify feature listeners
455
+ * @private
456
+ */
457
+ _notifyFeatureListeners(featureName, newValue, previousValue) {
458
+ const callbacks = this.featureListeners.get(featureName);
459
+ if (callbacks) {
460
+ callbacks.forEach(callback => {
461
+ try {
462
+ callback(newValue, previousValue, featureName);
463
+ } catch (error) {
464
+ logger.error(`Feature listener error for '${featureName}'`, { error: error.message });
465
+ }
466
+ });
467
+ }
468
+ }
469
+
470
+ /**
471
+ * Disable features that depend on this one
472
+ * @private
473
+ */
474
+ _disableDependents(featureName) {
475
+ const dependents = this._findDependents(featureName);
476
+ dependents.forEach(dependent => {
477
+ if (this.isFeatureEnabled(dependent)) {
478
+ this.disableFeature(dependent, {
479
+ reason: `Dependency ${featureName} was disabled`,
480
+ cascade: true
481
+ });
482
+ }
483
+ });
484
+ }
485
+
486
+ /**
487
+ * Find features that depend on this one
488
+ * @private
489
+ */
490
+ _findDependents(featureName) {
491
+ const dependencies = {
492
+ 'ENABLE_ENHANCED_SCHEMA': ['ENABLE_SCHEMA_CACHING', 'ENABLE_COMPREHENSIVE_VALIDATION'],
493
+ 'ENABLE_QUERY_CACHING': ['ENABLE_CACHE_METRICS'],
494
+ 'ENABLE_ENHANCED_HOOKS': ['ENABLE_HOOK_TIMEOUT', 'ENABLE_HOOK_METRICS']
495
+ };
496
+
497
+ const dependents = [];
498
+ for (const [feature, deps] of Object.entries(dependencies)) {
499
+ if (deps.includes(featureName)) {
500
+ dependents.push(feature);
501
+ }
502
+ }
503
+
504
+ return dependents;
505
+ }
506
+ }
507
+
508
+ // Global singleton instance
509
+ export const configManager = new ConfigurationManager();
510
+
511
+ /**
512
+ * Convenience functions for common operations
513
+ */
514
+ export const isFeatureEnabled = (featureName, defaultValue = false) =>
515
+ configManager.isFeatureEnabled(featureName, defaultValue);
516
+
517
+ export const getEnabledFeatures = () =>
518
+ configManager.getEnabledFeatures();
519
+
520
+ export const withFeature = (featureName, enabledCallback, disabledCallback = null) =>
521
+ configManager.withFeature(featureName, enabledCallback, disabledCallback);
522
+
523
+ /**
524
+ * Feature flag constants
525
+ */
526
+ export const FEATURES = Object.keys(DEFAULT_FEATURES).reduce((acc, key) => {
527
+ acc[key] = key;
528
+ return acc;
529
+ }, {});
530
+
531
+ export const COMMON_FEATURES = {
532
+ AUTHENTICATION: 'AUTHENTICATION',
533
+ AUTHORIZATION: 'AUTHORIZATION',
534
+ LOGGING: 'LOGGING',
535
+ MONITORING: 'MONITORING',
536
+ CACHING: 'CACHING',
537
+ RATE_LIMITING: 'RATE_LIMITING',
538
+ FILE_STORAGE: 'FILE_STORAGE'
539
+ };
@@ -1,9 +1,21 @@
1
1
  /**
2
2
  * Configuration Module
3
3
  * Exports all configuration management utilities
4
+ * Includes consolidated ConfigurationManager from Phase 3.2
4
5
  */
5
6
 
6
7
  export { ConfigCache } from './cache.js';
7
8
  export { ConfigManager } from './manager.js';
8
9
  export { CommandConfigManager } from './command-config-manager.js';
9
- export { CustomerConfigurationManager } from '../../../dist/config/customers.js';
10
+ export { CustomerConfigurationManager } from '../../../dist/config/customers.js';
11
+
12
+ // Phase 3.2 consolidated configuration management
13
+ export {
14
+ ConfigurationManager,
15
+ configManager,
16
+ isFeatureEnabled,
17
+ getEnabledFeatures,
18
+ withFeature,
19
+ FEATURES,
20
+ COMMON_FEATURES
21
+ } from './ConfigurationManager.js';
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import { executeSql } from '../cloudflare/ops.js';
7
- import { ErrorRecoveryManager } from '../utils/error-recovery.js';
7
+ import { ErrorRecoveryManager } from '../utils/index.js';
8
8
 
9
9
  export class DatabaseConnectionManager {
10
10
  constructor(options = {}) {
@@ -36,7 +36,7 @@ export class DatabaseConnectionManager {
36
36
  };
37
37
 
38
38
  // Initialize error recovery with loaded config
39
- const { ErrorRecoveryManager } = await import('../utils/error-recovery.js');
39
+ const { ErrorRecoveryManager } = await import('../utils/index.js');
40
40
  this.errorRecovery = new ErrorRecoveryManager({
41
41
  maxRetries: this.config.maxRetries,
42
42
  retryDelay: this.config.retryDelay,