@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.
- package/CHANGELOG.md +29 -0
- package/bin/clodo-service.js +29 -989
- package/bin/database/enterprise-db-manager.js +7 -5
- package/bin/security/security-cli.js +0 -0
- package/bin/service-management/create-service.js +0 -0
- package/bin/service-management/init-service.js +0 -0
- package/bin/shared/cloudflare/domain-discovery.js +11 -10
- package/bin/shared/cloudflare/ops.js +1 -1
- package/bin/shared/config/ConfigurationManager.js +539 -0
- package/bin/shared/config/index.js +13 -1
- package/bin/shared/database/connection-manager.js +2 -2
- package/bin/shared/database/orchestrator.js +5 -4
- package/bin/shared/deployment/auditor.js +9 -8
- package/bin/shared/logging/Logger.js +214 -0
- package/bin/shared/monitoring/production-monitor.js +21 -9
- package/bin/shared/utils/ErrorHandler.js +675 -0
- package/bin/shared/utils/error-recovery.js +33 -13
- package/bin/shared/utils/file-manager.js +162 -0
- package/bin/shared/utils/formatters.js +247 -0
- package/bin/shared/utils/index.js +14 -4
- package/bin/shared/validation/ValidationRegistry.js +143 -0
- package/dist/deployment/auditor.js +23 -8
- package/dist/deployment/orchestration/BaseDeploymentOrchestrator.js +426 -0
- package/dist/deployment/orchestration/EnterpriseOrchestrator.js +401 -0
- package/dist/deployment/orchestration/PortfolioOrchestrator.js +273 -0
- package/dist/deployment/orchestration/SingleServiceOrchestrator.js +231 -0
- package/dist/deployment/orchestration/UnifiedDeploymentOrchestrator.js +662 -0
- package/dist/deployment/orchestration/index.js +17 -0
- package/dist/index.js +12 -0
- package/dist/orchestration/modules/DomainResolver.js +8 -6
- package/dist/orchestration/multi-domain-orchestrator.js +13 -1
- package/dist/security/index.js +2 -2
- package/dist/service-management/ConfirmationEngine.js +8 -7
- package/dist/service-management/ErrorTracker.js +7 -2
- package/dist/service-management/InputCollector.js +31 -16
- package/dist/service-management/ServiceCreator.js +22 -7
- package/dist/service-management/ServiceInitializer.js +12 -18
- package/dist/shared/cloudflare/domain-discovery.js +11 -10
- package/dist/shared/cloudflare/ops.js +1 -1
- package/dist/shared/config/ConfigurationManager.js +519 -0
- package/dist/shared/config/index.js +5 -1
- package/dist/shared/database/connection-manager.js +2 -2
- package/dist/shared/database/orchestrator.js +13 -4
- package/dist/shared/deployment/auditor.js +23 -8
- package/dist/shared/logging/Logger.js +209 -0
- package/dist/shared/monitoring/production-monitor.js +24 -8
- package/dist/{utils → shared/utils}/ErrorHandler.js +306 -28
- package/dist/shared/utils/error-recovery.js +33 -13
- package/dist/shared/utils/file-manager.js +155 -0
- package/dist/shared/utils/formatters.js +215 -0
- package/dist/shared/utils/index.js +14 -4
- package/dist/shared/validation/ValidationRegistry.js +126 -0
- package/dist/utils/config/unified-config-manager.js +14 -12
- package/dist/utils/deployment/config-cache.js +3 -1
- package/dist/utils/deployment/secret-generator.js +32 -29
- package/dist/utils/framework-config.js +6 -3
- package/dist/utils/ui-structures-loader.js +3 -0
- package/dist/worker/integration.js +11 -1
- package/package.json +31 -3
- package/dist/config/FeatureManager.js +0 -426
- package/dist/config/features.js +0 -230
- 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 '
|
|
30
|
-
import { DeploymentAuditor } from '
|
|
31
|
-
import { CrossDomainCoordinator } from '
|
|
32
|
-
|
|
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:
|
|
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:
|
|
233
|
-
staging:
|
|
234
|
-
development:
|
|
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:
|
|
238
|
-
staging:
|
|
239
|
-
development:
|
|
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:
|
|
243
|
-
staging:
|
|
244
|
-
development:
|
|
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/
|
|
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/
|
|
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/
|
|
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,
|