@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.
- package/CHANGELOG.md +564 -0
- package/LICENSE +21 -0
- package/README.md +1393 -0
- package/bin/README.md +71 -0
- package/bin/clodo-service.js +416 -0
- package/bin/security/security-cli.js +96 -0
- package/bin/service-management/README.md +74 -0
- package/bin/service-management/create-service.js +129 -0
- package/bin/service-management/init-service.js +102 -0
- package/bin/service-management/init-service.js.backup +889 -0
- package/bin/shared/config/customer-cli.js +293 -0
- package/dist/config/ConfigurationManager.js +159 -0
- package/dist/config/CustomerConfigCLI.js +220 -0
- package/dist/config/FeatureManager.js +426 -0
- package/dist/config/customers.js +441 -0
- package/dist/config/domains.js +180 -0
- package/dist/config/features.js +225 -0
- package/dist/config/index.js +6 -0
- package/dist/database/database-orchestrator.js +730 -0
- package/dist/database/index.js +4 -0
- package/dist/deployment/auditor.js +971 -0
- package/dist/deployment/index.js +10 -0
- package/dist/deployment/rollback-manager.js +523 -0
- package/dist/deployment/testers/api-tester.js +80 -0
- package/dist/deployment/testers/auth-tester.js +129 -0
- package/dist/deployment/testers/core.js +217 -0
- package/dist/deployment/testers/database-tester.js +105 -0
- package/dist/deployment/testers/index.js +74 -0
- package/dist/deployment/testers/load-tester.js +120 -0
- package/dist/deployment/testers/performance-tester.js +105 -0
- package/dist/deployment/validator.js +558 -0
- package/dist/deployment/wrangler-deployer.js +574 -0
- package/dist/handlers/GenericRouteHandler.js +532 -0
- package/dist/index.js +39 -0
- package/dist/migration/MigrationAdapters.js +562 -0
- package/dist/modules/ModuleManager.js +668 -0
- package/dist/modules/security.js +98 -0
- package/dist/orchestration/cross-domain-coordinator.js +1083 -0
- package/dist/orchestration/index.js +5 -0
- package/dist/orchestration/modules/DeploymentCoordinator.js +258 -0
- package/dist/orchestration/modules/DomainResolver.js +196 -0
- package/dist/orchestration/modules/StateManager.js +332 -0
- package/dist/orchestration/multi-domain-orchestrator.js +255 -0
- package/dist/routing/EnhancedRouter.js +158 -0
- package/dist/schema/SchemaManager.js +778 -0
- package/dist/security/ConfigurationValidator.js +490 -0
- package/dist/security/DeploymentManager.js +208 -0
- package/dist/security/SecretGenerator.js +142 -0
- package/dist/security/SecurityCLI.js +228 -0
- package/dist/security/index.js +51 -0
- package/dist/security/patterns/environment-rules.js +66 -0
- package/dist/security/patterns/insecure-patterns.js +21 -0
- package/dist/service-management/ConfirmationEngine.js +411 -0
- package/dist/service-management/ErrorTracker.js +294 -0
- package/dist/service-management/GenerationEngine.js +3109 -0
- package/dist/service-management/InputCollector.js +237 -0
- package/dist/service-management/ServiceCreator.js +229 -0
- package/dist/service-management/ServiceInitializer.js +448 -0
- package/dist/service-management/ServiceOrchestrator.js +638 -0
- package/dist/service-management/handlers/ConfigMutator.js +130 -0
- package/dist/service-management/handlers/ConfirmationHandler.js +71 -0
- package/dist/service-management/handlers/GenerationHandler.js +80 -0
- package/dist/service-management/handlers/InputHandler.js +59 -0
- package/dist/service-management/handlers/ValidationHandler.js +203 -0
- package/dist/service-management/index.js +7 -0
- package/dist/services/GenericDataService.js +488 -0
- package/dist/shared/cloudflare/domain-discovery.js +562 -0
- package/dist/shared/cloudflare/domain-manager.js +912 -0
- package/dist/shared/cloudflare/index.js +8 -0
- package/dist/shared/cloudflare/ops.js +387 -0
- package/dist/shared/config/cache.js +1167 -0
- package/dist/shared/config/command-config-manager.js +174 -0
- package/dist/shared/config/customer-cli.js +258 -0
- package/dist/shared/config/index.js +9 -0
- package/dist/shared/config/manager.js +289 -0
- package/dist/shared/database/connection-manager.js +338 -0
- package/dist/shared/database/index.js +7 -0
- package/dist/shared/database/orchestrator.js +632 -0
- package/dist/shared/deployment/auditor.js +971 -0
- package/dist/shared/deployment/index.js +10 -0
- package/dist/shared/deployment/rollback-manager.js +523 -0
- package/dist/shared/deployment/validator.js +558 -0
- package/dist/shared/index.js +32 -0
- package/dist/shared/monitoring/health-checker.js +250 -0
- package/dist/shared/monitoring/index.js +8 -0
- package/dist/shared/monitoring/memory-manager.js +382 -0
- package/dist/shared/monitoring/production-monitor.js +390 -0
- package/dist/shared/production-tester/api-tester.js +80 -0
- package/dist/shared/production-tester/auth-tester.js +129 -0
- package/dist/shared/production-tester/core.js +217 -0
- package/dist/shared/production-tester/database-tester.js +105 -0
- package/dist/shared/production-tester/index.js +74 -0
- package/dist/shared/production-tester/load-tester.js +120 -0
- package/dist/shared/production-tester/performance-tester.js +105 -0
- package/dist/shared/security/api-token-manager.js +296 -0
- package/dist/shared/security/index.js +8 -0
- package/dist/shared/security/secret-generator.js +918 -0
- package/dist/shared/security/secure-token-manager.js +379 -0
- package/dist/shared/utils/error-recovery.js +240 -0
- package/dist/shared/utils/graceful-shutdown-manager.js +380 -0
- package/dist/shared/utils/index.js +9 -0
- package/dist/shared/utils/interactive-prompts.js +134 -0
- package/dist/shared/utils/rate-limiter.js +249 -0
- package/dist/utils/ErrorHandler.js +173 -0
- package/dist/utils/deployment/config-cache.js +1160 -0
- package/dist/utils/deployment/index.js +6 -0
- package/dist/utils/deployment/interactive-prompts.js +97 -0
- package/dist/utils/deployment/secret-generator.js +896 -0
- package/dist/utils/dirname-helper.js +35 -0
- package/dist/utils/domain-config.js +159 -0
- package/dist/utils/error-recovery.js +240 -0
- package/dist/utils/esm-helper.js +52 -0
- package/dist/utils/framework-config.js +481 -0
- package/dist/utils/graceful-shutdown-manager.js +379 -0
- package/dist/utils/health-checker.js +114 -0
- package/dist/utils/index.js +36 -0
- package/dist/utils/prompt-handler.js +98 -0
- package/dist/utils/usage-tracker.js +252 -0
- package/dist/utils/validation.js +112 -0
- package/dist/version/VersionDetector.js +723 -0
- package/dist/worker/index.js +4 -0
- package/dist/worker/integration.js +332 -0
- package/docs/FRAMEWORK-ARCHITECTURE-OVERVIEW.md +206 -0
- package/docs/INTEGRATION_GUIDE.md +2045 -0
- package/docs/README.md +82 -0
- package/docs/SECURITY.md +242 -0
- package/docs/deployment/deployment-guide.md +540 -0
- package/docs/overview.md +280 -0
- package/package.json +176 -0
- package/types/index.d.ts +575 -0
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* State Manager Module
|
|
3
|
+
* Handles portfolio state tracking, audit logging, and rollback planning
|
|
4
|
+
* Extracted from MultiDomainOrchestrator for focused responsibility
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { writeFile, mkdir, access } from 'fs/promises';
|
|
8
|
+
import { join } from 'path';
|
|
9
|
+
import { randomBytes } from 'crypto';
|
|
10
|
+
export class StateManager {
|
|
11
|
+
constructor(options = {}) {
|
|
12
|
+
this.environment = options.environment || 'production';
|
|
13
|
+
this.dryRun = options.dryRun || false;
|
|
14
|
+
this.logDirectory = options.logDirectory || 'deployments';
|
|
15
|
+
this.enablePersistence = options.enablePersistence !== false;
|
|
16
|
+
this.rollbackEnabled = options.rollbackEnabled !== false;
|
|
17
|
+
|
|
18
|
+
// Initialize portfolio state
|
|
19
|
+
this.portfolioState = this.initializePortfolioState(options);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Initialize portfolio state structure
|
|
24
|
+
* @param {Object} options - Initialization options
|
|
25
|
+
* @returns {Object} Portfolio state object
|
|
26
|
+
*/
|
|
27
|
+
initializePortfolioState(options = {}) {
|
|
28
|
+
return {
|
|
29
|
+
orchestrationId: this.generateOrchestrationId(),
|
|
30
|
+
startTime: new Date(),
|
|
31
|
+
endTime: null,
|
|
32
|
+
environment: this.environment,
|
|
33
|
+
totalDomains: options.domains?.length || 0,
|
|
34
|
+
completedDomains: 0,
|
|
35
|
+
failedDomains: 0,
|
|
36
|
+
domainStates: new Map(),
|
|
37
|
+
rollbackPlan: [],
|
|
38
|
+
auditLog: [],
|
|
39
|
+
metadata: {
|
|
40
|
+
dryRun: this.dryRun,
|
|
41
|
+
persistenceEnabled: this.enablePersistence,
|
|
42
|
+
rollbackEnabled: this.rollbackEnabled
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Generate unique orchestration ID for tracking portfolio deployments
|
|
49
|
+
* @returns {string} Unique orchestration identifier
|
|
50
|
+
*/
|
|
51
|
+
generateOrchestrationId() {
|
|
52
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
53
|
+
const random = randomBytes(6).toString('hex');
|
|
54
|
+
return `orchestration-${timestamp}-${random}`;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Generate deployment ID for individual domain
|
|
59
|
+
* @param {string} domain - Domain name
|
|
60
|
+
* @returns {string} Unique deployment identifier
|
|
61
|
+
*/
|
|
62
|
+
generateDeploymentId(domain) {
|
|
63
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
64
|
+
const random = randomBytes(4).toString('hex');
|
|
65
|
+
return `deploy-${domain}-${timestamp}-${random}`;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Initialize domain states for portfolio
|
|
70
|
+
* @param {Array} domains - Array of domain names
|
|
71
|
+
* @returns {Promise<void>}
|
|
72
|
+
*/
|
|
73
|
+
async initializeDomainStates(domains) {
|
|
74
|
+
this.portfolioState.totalDomains = domains.length;
|
|
75
|
+
domains.forEach(domain => {
|
|
76
|
+
this.portfolioState.domainStates.set(domain, {
|
|
77
|
+
domain,
|
|
78
|
+
deploymentId: this.generateDeploymentId(domain),
|
|
79
|
+
phase: 'pending',
|
|
80
|
+
status: 'pending',
|
|
81
|
+
startTime: null,
|
|
82
|
+
endTime: null,
|
|
83
|
+
error: null,
|
|
84
|
+
rollbackActions: [],
|
|
85
|
+
metadata: {
|
|
86
|
+
created: new Date().toISOString(),
|
|
87
|
+
environment: this.environment
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
await this.logAuditEvent('PORTFOLIO_INITIALIZED', 'ALL', {
|
|
92
|
+
totalDomains: domains.length,
|
|
93
|
+
domains: domains
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Update domain state
|
|
99
|
+
* @param {string} domain - Domain name
|
|
100
|
+
* @param {Object} updates - State updates
|
|
101
|
+
* @returns {Object} Updated domain state
|
|
102
|
+
*/
|
|
103
|
+
updateDomainState(domain, updates) {
|
|
104
|
+
const domainState = this.portfolioState.domainStates.get(domain);
|
|
105
|
+
if (!domainState) {
|
|
106
|
+
throw new Error(`Domain state not found: ${domain}`);
|
|
107
|
+
}
|
|
108
|
+
Object.assign(domainState, updates, {
|
|
109
|
+
lastUpdated: new Date().toISOString()
|
|
110
|
+
});
|
|
111
|
+
return domainState;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Get domain state
|
|
116
|
+
* @param {string} domain - Domain name
|
|
117
|
+
* @returns {Object|null} Domain state or null if not found
|
|
118
|
+
*/
|
|
119
|
+
getDomainState(domain) {
|
|
120
|
+
return this.portfolioState.domainStates.get(domain) || null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Get portfolio state summary
|
|
125
|
+
* @returns {Object} Portfolio state summary
|
|
126
|
+
*/
|
|
127
|
+
getPortfolioSummary() {
|
|
128
|
+
const states = Array.from(this.portfolioState.domainStates.values());
|
|
129
|
+
return {
|
|
130
|
+
orchestrationId: this.portfolioState.orchestrationId,
|
|
131
|
+
environment: this.environment,
|
|
132
|
+
totalDomains: this.portfolioState.totalDomains,
|
|
133
|
+
completed: states.filter(s => s.status === 'completed').length,
|
|
134
|
+
failed: states.filter(s => s.status === 'failed').length,
|
|
135
|
+
inProgress: states.filter(s => s.status === 'deploying').length,
|
|
136
|
+
pending: states.filter(s => s.status === 'pending').length,
|
|
137
|
+
startTime: this.portfolioState.startTime,
|
|
138
|
+
endTime: this.portfolioState.endTime,
|
|
139
|
+
duration: this.portfolioState.endTime ? this.portfolioState.endTime - this.portfolioState.startTime : Date.now() - this.portfolioState.startTime,
|
|
140
|
+
auditLogSize: this.portfolioState.auditLog.length
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Log audit event for tracking
|
|
146
|
+
* @param {string} event - Event type
|
|
147
|
+
* @param {string} domain - Domain or 'ALL' for portfolio events
|
|
148
|
+
* @param {Object} details - Event details
|
|
149
|
+
* @returns {Promise<void>}
|
|
150
|
+
*/
|
|
151
|
+
async logAuditEvent(event, domain, details = {}) {
|
|
152
|
+
const auditEntry = {
|
|
153
|
+
timestamp: new Date().toISOString(),
|
|
154
|
+
orchestrationId: this.portfolioState.orchestrationId,
|
|
155
|
+
event,
|
|
156
|
+
domain,
|
|
157
|
+
details,
|
|
158
|
+
sequenceNumber: this.portfolioState.auditLog.length + 1
|
|
159
|
+
};
|
|
160
|
+
this.portfolioState.auditLog.push(auditEntry);
|
|
161
|
+
|
|
162
|
+
// Save to file for persistence (fire and forget)
|
|
163
|
+
if (this.enablePersistence && !this.dryRun) {
|
|
164
|
+
try {
|
|
165
|
+
await this.saveAuditLog();
|
|
166
|
+
} catch (error) {
|
|
167
|
+
console.warn(`⚠️ Failed to save audit log: ${error.message}`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Add rollback action for domain
|
|
174
|
+
* @param {string} domain - Domain name
|
|
175
|
+
* @param {Object} action - Rollback action
|
|
176
|
+
*/
|
|
177
|
+
addRollbackAction(domain, action) {
|
|
178
|
+
const domainState = this.getDomainState(domain);
|
|
179
|
+
if (domainState) {
|
|
180
|
+
domainState.rollbackActions.push({
|
|
181
|
+
...action,
|
|
182
|
+
timestamp: new Date().toISOString(),
|
|
183
|
+
id: randomBytes(4).toString('hex')
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Add to portfolio rollback plan
|
|
188
|
+
this.portfolioState.rollbackPlan.push({
|
|
189
|
+
domain,
|
|
190
|
+
action: {
|
|
191
|
+
...action,
|
|
192
|
+
timestamp: new Date().toISOString()
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Get rollback plan for portfolio or specific domain
|
|
199
|
+
* @param {string} [domain] - Optional domain filter
|
|
200
|
+
* @returns {Array} Rollback actions
|
|
201
|
+
*/
|
|
202
|
+
getRollbackPlan(domain = null) {
|
|
203
|
+
if (domain) {
|
|
204
|
+
return this.portfolioState.rollbackPlan.filter(item => item.domain === domain);
|
|
205
|
+
}
|
|
206
|
+
return this.portfolioState.rollbackPlan;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Mark deployment as started
|
|
211
|
+
* @param {string} domain - Domain name
|
|
212
|
+
*/
|
|
213
|
+
markDeploymentStarted(domain) {
|
|
214
|
+
this.updateDomainState(domain, {
|
|
215
|
+
status: 'deploying',
|
|
216
|
+
startTime: new Date()
|
|
217
|
+
});
|
|
218
|
+
this.portfolioState.completedDomains++;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Mark deployment as completed
|
|
223
|
+
* @param {string} domain - Domain name
|
|
224
|
+
* @param {Object} result - Deployment result
|
|
225
|
+
*/
|
|
226
|
+
markDeploymentCompleted(domain, result = {}) {
|
|
227
|
+
this.updateDomainState(domain, {
|
|
228
|
+
status: 'completed',
|
|
229
|
+
endTime: new Date(),
|
|
230
|
+
result
|
|
231
|
+
});
|
|
232
|
+
this.portfolioState.completedDomains++;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Mark deployment as failed
|
|
237
|
+
* @param {string} domain - Domain name
|
|
238
|
+
* @param {Error|string} error - Error details
|
|
239
|
+
*/
|
|
240
|
+
markDeploymentFailed(domain, error) {
|
|
241
|
+
this.updateDomainState(domain, {
|
|
242
|
+
status: 'failed',
|
|
243
|
+
endTime: new Date(),
|
|
244
|
+
error: error instanceof Error ? error.message : error
|
|
245
|
+
});
|
|
246
|
+
this.portfolioState.failedDomains++;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Mark portfolio as completed
|
|
251
|
+
*/
|
|
252
|
+
markPortfolioCompleted() {
|
|
253
|
+
this.portfolioState.endTime = new Date();
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Save audit log to file
|
|
258
|
+
* @returns {Promise<void>}
|
|
259
|
+
*/
|
|
260
|
+
async saveAuditLog() {
|
|
261
|
+
if (!this.enablePersistence) return;
|
|
262
|
+
try {
|
|
263
|
+
// Ensure log directory exists
|
|
264
|
+
try {
|
|
265
|
+
await access(this.logDirectory);
|
|
266
|
+
} catch {
|
|
267
|
+
await mkdir(this.logDirectory, {
|
|
268
|
+
recursive: true
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
const logFile = join(this.logDirectory, `${this.portfolioState.orchestrationId}.json`);
|
|
272
|
+
const logData = {
|
|
273
|
+
orchestrationId: this.portfolioState.orchestrationId,
|
|
274
|
+
environment: this.environment,
|
|
275
|
+
startTime: this.portfolioState.startTime,
|
|
276
|
+
endTime: this.portfolioState.endTime,
|
|
277
|
+
summary: this.getPortfolioSummary(),
|
|
278
|
+
domainStates: Array.from(this.portfolioState.domainStates.entries()).reduce((obj, [key, value]) => {
|
|
279
|
+
obj[key] = value;
|
|
280
|
+
return obj;
|
|
281
|
+
}, {}),
|
|
282
|
+
rollbackPlan: this.portfolioState.rollbackPlan,
|
|
283
|
+
auditLog: this.portfolioState.auditLog,
|
|
284
|
+
metadata: this.portfolioState.metadata
|
|
285
|
+
};
|
|
286
|
+
await writeFile(logFile, JSON.stringify(logData, null, 2));
|
|
287
|
+
} catch (error) {
|
|
288
|
+
console.warn(`⚠️ Failed to save audit log: ${error.message}`);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Get audit log entries
|
|
294
|
+
* @param {Object} filter - Filter options
|
|
295
|
+
* @returns {Array} Filtered audit entries
|
|
296
|
+
*/
|
|
297
|
+
getAuditLog(filter = {}) {
|
|
298
|
+
let entries = this.portfolioState.auditLog;
|
|
299
|
+
if (filter.event) {
|
|
300
|
+
entries = entries.filter(entry => entry.event === filter.event);
|
|
301
|
+
}
|
|
302
|
+
if (filter.domain) {
|
|
303
|
+
entries = entries.filter(entry => entry.domain === filter.domain);
|
|
304
|
+
}
|
|
305
|
+
if (filter.since) {
|
|
306
|
+
entries = entries.filter(entry => new Date(entry.timestamp) >= filter.since);
|
|
307
|
+
}
|
|
308
|
+
return entries;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Clear state (for testing or reset)
|
|
313
|
+
*/
|
|
314
|
+
clearState() {
|
|
315
|
+
this.portfolioState = this.initializePortfolioState();
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Get state statistics
|
|
320
|
+
* @returns {Object} State statistics
|
|
321
|
+
*/
|
|
322
|
+
getStateStats() {
|
|
323
|
+
return {
|
|
324
|
+
orchestrationId: this.portfolioState.orchestrationId,
|
|
325
|
+
domainCount: this.portfolioState.domainStates.size,
|
|
326
|
+
auditLogSize: this.portfolioState.auditLog.length,
|
|
327
|
+
rollbackActionsCount: this.portfolioState.rollbackPlan.length,
|
|
328
|
+
persistenceEnabled: this.enablePersistence,
|
|
329
|
+
dryRun: this.dryRun
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
}
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Multi-Domain Orchestrator Module
|
|
5
|
+
* Enterprise-grade deployment orchestration with state management,
|
|
6
|
+
* rollback capabilities, and portfolio-wide coordination
|
|
7
|
+
*
|
|
8
|
+
* Now uses modular architecture for improved maintainability and testability
|
|
9
|
+
*/
|
|
10
|
+
import { DomainResolver } from './modules/DomainResolver.js';
|
|
11
|
+
import { DeploymentCoordinator } from './modules/DeploymentCoordinator.js';
|
|
12
|
+
import { StateManager } from './modules/StateManager.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Multi-Domain Deployment Orchestrator
|
|
16
|
+
* Manages enterprise-level deployments across multiple domains with comprehensive state tracking
|
|
17
|
+
*
|
|
18
|
+
* REFACTORED: Now uses modular components for domain resolution, deployment coordination, and state management
|
|
19
|
+
*/
|
|
20
|
+
export class MultiDomainOrchestrator {
|
|
21
|
+
constructor(options = {}) {
|
|
22
|
+
this.domains = options.domains || [];
|
|
23
|
+
this.environment = options.environment || 'production';
|
|
24
|
+
this.dryRun = options.dryRun || false;
|
|
25
|
+
this.skipTests = options.skipTests || false;
|
|
26
|
+
this.parallelDeployments = options.parallelDeployments || 3;
|
|
27
|
+
|
|
28
|
+
// Initialize modular components
|
|
29
|
+
this.domainResolver = new DomainResolver({
|
|
30
|
+
environment: this.environment,
|
|
31
|
+
validationLevel: options.validationLevel || 'basic',
|
|
32
|
+
cacheEnabled: options.cacheEnabled !== false
|
|
33
|
+
});
|
|
34
|
+
this.deploymentCoordinator = new DeploymentCoordinator({
|
|
35
|
+
parallelDeployments: this.parallelDeployments,
|
|
36
|
+
skipTests: this.skipTests,
|
|
37
|
+
dryRun: this.dryRun,
|
|
38
|
+
environment: this.environment,
|
|
39
|
+
batchPauseMs: options.batchPauseMs || 2000
|
|
40
|
+
});
|
|
41
|
+
this.stateManager = new StateManager({
|
|
42
|
+
environment: this.environment,
|
|
43
|
+
dryRun: this.dryRun,
|
|
44
|
+
domains: this.domains,
|
|
45
|
+
enablePersistence: options.enablePersistence !== false,
|
|
46
|
+
rollbackEnabled: options.rollbackEnabled !== false
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// Legacy compatibility: expose portfolioState for backward compatibility
|
|
50
|
+
this.portfolioState = this.stateManager.portfolioState;
|
|
51
|
+
|
|
52
|
+
// Note: Async initialization required - call initialize() after construction
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Initialize the orchestrator asynchronously
|
|
57
|
+
* Uses modular components for domain resolution and state initialization
|
|
58
|
+
*/
|
|
59
|
+
async initialize() {
|
|
60
|
+
console.log('🌐 Multi-Domain Orchestrator v2.0 (Modular)');
|
|
61
|
+
console.log('===========================================');
|
|
62
|
+
console.log(`📊 Portfolio: ${this.domains.length} domains`);
|
|
63
|
+
console.log(`🌍 Environment: ${this.environment}`);
|
|
64
|
+
console.log(`🆔 Orchestration ID: ${this.portfolioState.orchestrationId}`);
|
|
65
|
+
console.log(`🔍 Mode: ${this.dryRun ? 'DRY RUN' : 'LIVE DEPLOYMENT'}`);
|
|
66
|
+
console.log(`⚡ Parallel Deployments: ${this.parallelDeployments}`);
|
|
67
|
+
console.log('🧩 Modular Components: DomainResolver, DeploymentCoordinator, StateManager');
|
|
68
|
+
console.log('');
|
|
69
|
+
|
|
70
|
+
// Initialize all modular components
|
|
71
|
+
await this.stateManager.initializeDomainStates(this.domains);
|
|
72
|
+
|
|
73
|
+
// Pre-resolve all domain configurations if domains are specified
|
|
74
|
+
if (this.domains.length > 0) {
|
|
75
|
+
const configs = await this.domainResolver.resolveMultipleDomains(this.domains);
|
|
76
|
+
|
|
77
|
+
// Update domain states with resolved configurations
|
|
78
|
+
for (const [domain, config] of Object.entries(configs)) {
|
|
79
|
+
const domainState = this.portfolioState.domainStates.get(domain);
|
|
80
|
+
if (domainState) {
|
|
81
|
+
domainState.config = config;
|
|
82
|
+
this.stateManager.updateDomainState(domain, {
|
|
83
|
+
config
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
await this.stateManager.logAuditEvent('orchestrator_initialized', {
|
|
89
|
+
domains: this.domains,
|
|
90
|
+
environment: this.environment,
|
|
91
|
+
modularComponents: ['DomainResolver', 'DeploymentCoordinator', 'StateManager']
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Legacy method for backward compatibility
|
|
97
|
+
* @deprecated Use stateManager.generateOrchestrationId() instead
|
|
98
|
+
*/
|
|
99
|
+
generateOrchestrationId() {
|
|
100
|
+
return this.stateManager.generateOrchestrationId();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Legacy method for backward compatibility
|
|
105
|
+
* @deprecated Use stateManager.generateDeploymentId() instead
|
|
106
|
+
*/
|
|
107
|
+
generateDeploymentId(domain) {
|
|
108
|
+
return this.stateManager.generateDeploymentId(domain);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Legacy method for backward compatibility
|
|
113
|
+
* @deprecated Use domainResolver.generateDomainConfig() instead
|
|
114
|
+
*/
|
|
115
|
+
generateDomainConfig(domain) {
|
|
116
|
+
return this.domainResolver.generateDomainConfig(domain);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Deploy to single domain using modular deployment coordinator
|
|
121
|
+
* @param {string} domain - Domain to deploy
|
|
122
|
+
* @returns {Promise<Object>} Deployment result
|
|
123
|
+
*/
|
|
124
|
+
async deploySingleDomain(domain) {
|
|
125
|
+
const domainState = this.portfolioState.domainStates.get(domain);
|
|
126
|
+
if (!domainState) {
|
|
127
|
+
throw new Error(`Domain ${domain} not found in portfolio`);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Create handlers that delegate to our legacy methods for backward compatibility
|
|
131
|
+
const handlers = {
|
|
132
|
+
validation: d => this.validateDomainPrerequisites(d),
|
|
133
|
+
initialization: d => this.initializeDomainDeployment(d),
|
|
134
|
+
database: d => this.setupDomainDatabase(d),
|
|
135
|
+
secrets: d => this.handleDomainSecrets(d),
|
|
136
|
+
deployment: d => this.deployDomainWorker(d),
|
|
137
|
+
'post-validation': d => this.validateDomainDeployment(d)
|
|
138
|
+
};
|
|
139
|
+
return await this.deploymentCoordinator.deploySingleDomain(domain, domainState, handlers);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Deploy to multiple domains using modular deployment coordinator
|
|
144
|
+
* @returns {Promise<Object>} Portfolio deployment results
|
|
145
|
+
*/
|
|
146
|
+
async deployPortfolio() {
|
|
147
|
+
// Create handlers that delegate to our legacy methods for backward compatibility
|
|
148
|
+
const handlers = {
|
|
149
|
+
validation: d => this.validateDomainPrerequisites(d),
|
|
150
|
+
initialization: d => this.initializeDomainDeployment(d),
|
|
151
|
+
database: d => this.setupDomainDatabase(d),
|
|
152
|
+
secrets: d => this.handleDomainSecrets(d),
|
|
153
|
+
deployment: d => this.deployDomainWorker(d),
|
|
154
|
+
'post-validation': d => this.validateDomainDeployment(d)
|
|
155
|
+
};
|
|
156
|
+
return await this.deploymentCoordinator.deployPortfolio(this.domains, this.portfolioState.domainStates, handlers);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Legacy method for backward compatibility
|
|
161
|
+
* @deprecated Use deploymentCoordinator.createDeploymentBatches() instead
|
|
162
|
+
*/
|
|
163
|
+
createDeploymentBatches() {
|
|
164
|
+
return this.deploymentCoordinator.createDeploymentBatches(this.domains);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Legacy method for backward compatibility
|
|
169
|
+
* @deprecated Use stateManager.logAuditEvent() instead
|
|
170
|
+
*/
|
|
171
|
+
logAuditEvent(event, domain, details = {}) {
|
|
172
|
+
return this.stateManager.logAuditEvent(event, domain, details);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Legacy method for backward compatibility
|
|
177
|
+
* @deprecated Use stateManager.saveAuditLog() instead
|
|
178
|
+
*/
|
|
179
|
+
async saveAuditLog() {
|
|
180
|
+
return await this.stateManager.saveAuditLog();
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Legacy method for backward compatibility
|
|
185
|
+
* @deprecated Use domainResolver.validateDomainPrerequisites() instead
|
|
186
|
+
*/
|
|
187
|
+
async validateDomainPrerequisites(domain) {
|
|
188
|
+
return await this.domainResolver.validateDomainPrerequisites(domain);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Legacy method for backward compatibility
|
|
193
|
+
* @deprecated Use deploymentCoordinator.initializeDomainDeployment() instead
|
|
194
|
+
*/
|
|
195
|
+
async initializeDomainDeployment(domain) {
|
|
196
|
+
return await this.deploymentCoordinator.initializeDomainDeployment(domain);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Legacy method for backward compatibility
|
|
201
|
+
* @deprecated Use deploymentCoordinator.setupDomainDatabase() instead
|
|
202
|
+
*/
|
|
203
|
+
async setupDomainDatabase(domain) {
|
|
204
|
+
return await this.deploymentCoordinator.setupDomainDatabase(domain);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Legacy method for backward compatibility
|
|
209
|
+
* @deprecated Use deploymentCoordinator.handleDomainSecrets() instead
|
|
210
|
+
*/
|
|
211
|
+
async handleDomainSecrets(domain) {
|
|
212
|
+
return await this.deploymentCoordinator.handleDomainSecrets(domain);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Legacy method for backward compatibility
|
|
217
|
+
* @deprecated Use deploymentCoordinator.deployDomainWorker() instead
|
|
218
|
+
*/
|
|
219
|
+
async deployDomainWorker(domain) {
|
|
220
|
+
return await this.deploymentCoordinator.deployDomainWorker(domain);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Legacy method for backward compatibility
|
|
225
|
+
* @deprecated Use deploymentCoordinator.validateDomainDeployment() instead
|
|
226
|
+
*/
|
|
227
|
+
async validateDomainDeployment(domain) {
|
|
228
|
+
return await this.deploymentCoordinator.validateDomainDeployment(domain);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Get rollback plan using state manager
|
|
233
|
+
* @returns {Array} Rollback plan from state manager
|
|
234
|
+
*/
|
|
235
|
+
getRollbackPlan() {
|
|
236
|
+
return this.stateManager.portfolioState.rollbackPlan;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Execute rollback using state manager
|
|
241
|
+
* @returns {Promise<Object>} Rollback result
|
|
242
|
+
*/
|
|
243
|
+
async executeRollback() {
|
|
244
|
+
return await this.stateManager.executeRollback();
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Get portfolio statistics from state manager
|
|
249
|
+
* @returns {Object} Portfolio statistics
|
|
250
|
+
*/
|
|
251
|
+
getPortfolioStats() {
|
|
252
|
+
return this.stateManager.getPortfolioSummary();
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
export default MultiDomainOrchestrator;
|