@tamyla/clodo-framework 3.1.5 → 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 +22 -0
- package/bin/clodo-service.js +29 -947
- 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 +18 -12
- 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
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
import { existsSync, writeFileSync, appendFileSync, mkdirSync, readFileSync, readdirSync, statSync } from 'fs';
|
|
20
20
|
import { join, dirname } from 'path';
|
|
21
21
|
import { execSync } from 'child_process';
|
|
22
|
+
import { logger } from '../logging/Logger.js';
|
|
22
23
|
export class DeploymentAuditor {
|
|
23
24
|
constructor(options = {}) {
|
|
24
25
|
this.config = {
|
|
@@ -302,7 +303,9 @@ export class DeploymentAuditor {
|
|
|
302
303
|
logPhase(deploymentId, phaseName, action, details = {}) {
|
|
303
304
|
const deployment = this.currentSession.deployments.get(deploymentId);
|
|
304
305
|
if (!deployment) {
|
|
305
|
-
|
|
306
|
+
logger.warn('Deployment not found for phase logging', {
|
|
307
|
+
deploymentId
|
|
308
|
+
});
|
|
306
309
|
return;
|
|
307
310
|
}
|
|
308
311
|
const phaseEvent = {
|
|
@@ -360,7 +363,9 @@ export class DeploymentAuditor {
|
|
|
360
363
|
error: errorDetails.error,
|
|
361
364
|
context
|
|
362
365
|
});
|
|
363
|
-
|
|
366
|
+
logger.error('Deployment error logged', {
|
|
367
|
+
deploymentId
|
|
368
|
+
});
|
|
364
369
|
}
|
|
365
370
|
|
|
366
371
|
/**
|
|
@@ -539,7 +544,9 @@ export class DeploymentAuditor {
|
|
|
539
544
|
appendFileSync(csvFile, csvEntry + '\n');
|
|
540
545
|
}
|
|
541
546
|
} catch (error) {
|
|
542
|
-
|
|
547
|
+
logger.error('Failed to write audit log', {
|
|
548
|
+
error: error.message
|
|
549
|
+
});
|
|
543
550
|
}
|
|
544
551
|
}
|
|
545
552
|
|
|
@@ -562,7 +569,9 @@ export class DeploymentAuditor {
|
|
|
562
569
|
timestamp: new Date()
|
|
563
570
|
});
|
|
564
571
|
} catch (error) {
|
|
565
|
-
|
|
572
|
+
logger.error('Failed to rotate log file', {
|
|
573
|
+
error: error.message
|
|
574
|
+
});
|
|
566
575
|
}
|
|
567
576
|
}
|
|
568
577
|
|
|
@@ -574,7 +583,9 @@ export class DeploymentAuditor {
|
|
|
574
583
|
generateDeploymentReport(deploymentId) {
|
|
575
584
|
const deployment = this.currentSession.deployments.get(deploymentId);
|
|
576
585
|
if (!deployment) {
|
|
577
|
-
|
|
586
|
+
logger.warn('Cannot generate report: deployment not found', {
|
|
587
|
+
deploymentId
|
|
588
|
+
});
|
|
578
589
|
return null;
|
|
579
590
|
}
|
|
580
591
|
const reportData = {
|
|
@@ -813,7 +824,7 @@ export class DeploymentAuditor {
|
|
|
813
824
|
*/
|
|
814
825
|
async sendSecurityAlert(securityEvent) {
|
|
815
826
|
if (!this.config.alertWebhook) {
|
|
816
|
-
|
|
827
|
+
logger.warn('Security alert webhook not configured');
|
|
817
828
|
return;
|
|
818
829
|
}
|
|
819
830
|
const alert = {
|
|
@@ -831,7 +842,9 @@ export class DeploymentAuditor {
|
|
|
831
842
|
event: securityEvent
|
|
832
843
|
});
|
|
833
844
|
} catch (error) {
|
|
834
|
-
|
|
845
|
+
logger.error('Failed to send security alert', {
|
|
846
|
+
error: error.message
|
|
847
|
+
});
|
|
835
848
|
}
|
|
836
849
|
}
|
|
837
850
|
|
|
@@ -890,7 +903,9 @@ export class DeploymentAuditor {
|
|
|
890
903
|
this.logAuditEvent('AUDIT_CLEANUP_COMPLETED', 'SYSTEM', cleanupResults);
|
|
891
904
|
console.log(`🧹 Audit cleanup completed: ${cleanupResults.filesRemoved} files removed`);
|
|
892
905
|
} catch (error) {
|
|
893
|
-
|
|
906
|
+
logger.error('Audit cleanup failed', {
|
|
907
|
+
error: error.message
|
|
908
|
+
});
|
|
894
909
|
cleanupResults.errors.push({
|
|
895
910
|
general: error.message
|
|
896
911
|
});
|
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base Deployment Orchestrator
|
|
3
|
+
*
|
|
4
|
+
* Abstract base class for all deployment orchestration patterns.
|
|
5
|
+
* Provides unified phase pipeline, phase state management, and error handling.
|
|
6
|
+
*
|
|
7
|
+
* Phase Pipeline:
|
|
8
|
+
* 1. Initialization → 2. Validation → 3. Preparation → 4. Deployment → 5. Verification → 6. Monitoring
|
|
9
|
+
*
|
|
10
|
+
* All subclasses must implement phase-specific methods:
|
|
11
|
+
* - onInitialize()
|
|
12
|
+
* - onValidation()
|
|
13
|
+
* - onPrepare()
|
|
14
|
+
* - onDeploy()
|
|
15
|
+
* - onVerify()
|
|
16
|
+
* - onMonitor()
|
|
17
|
+
*
|
|
18
|
+
* @class BaseDeploymentOrchestrator
|
|
19
|
+
* @abstract
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { ErrorHandler } from '../../shared/utils/ErrorHandler.js';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Phase state and execution order
|
|
26
|
+
*/
|
|
27
|
+
const DEPLOYMENT_PHASES = {
|
|
28
|
+
INITIALIZATION: 'initialization',
|
|
29
|
+
VALIDATION: 'validation',
|
|
30
|
+
PREPARATION: 'preparation',
|
|
31
|
+
DEPLOYMENT: 'deployment',
|
|
32
|
+
VERIFICATION: 'verification',
|
|
33
|
+
MONITORING: 'monitoring'
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Phase execution order
|
|
38
|
+
*/
|
|
39
|
+
const PHASE_SEQUENCE = [DEPLOYMENT_PHASES.INITIALIZATION, DEPLOYMENT_PHASES.VALIDATION, DEPLOYMENT_PHASES.PREPARATION, DEPLOYMENT_PHASES.DEPLOYMENT, DEPLOYMENT_PHASES.VERIFICATION, DEPLOYMENT_PHASES.MONITORING];
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Base Deployment Orchestrator - Abstract orchestration framework
|
|
43
|
+
*/
|
|
44
|
+
export class BaseDeploymentOrchestrator {
|
|
45
|
+
/**
|
|
46
|
+
* Constructor
|
|
47
|
+
* @param {Object} options - Configuration options
|
|
48
|
+
* @param {string} options.deploymentId - Unique deployment identifier
|
|
49
|
+
* @param {Object} options.config - Deployment configuration
|
|
50
|
+
* @param {Object} options.auditor - Deployment auditor instance (optional)
|
|
51
|
+
*/
|
|
52
|
+
constructor(options = {}) {
|
|
53
|
+
this.deploymentId = options.deploymentId || `deploy-${Date.now()}`;
|
|
54
|
+
this.config = options.config || {};
|
|
55
|
+
this.auditor = options.auditor;
|
|
56
|
+
|
|
57
|
+
// Phase state management
|
|
58
|
+
this.currentPhase = null;
|
|
59
|
+
this.phaseStates = new Map();
|
|
60
|
+
this.phaseResults = new Map();
|
|
61
|
+
this.phaseErrors = new Map();
|
|
62
|
+
this.startTime = Date.now();
|
|
63
|
+
this.phaseTimings = new Map();
|
|
64
|
+
|
|
65
|
+
// Execution context
|
|
66
|
+
this.executionContext = {
|
|
67
|
+
deploymentId: this.deploymentId,
|
|
68
|
+
startTime: this.startTime,
|
|
69
|
+
phases: {},
|
|
70
|
+
errors: []
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Execute complete deployment orchestration
|
|
76
|
+
* Runs through all phases in sequence with error handling and recovery
|
|
77
|
+
*
|
|
78
|
+
* @param {Object} options - Execution options
|
|
79
|
+
* @returns {Promise<Object>} Deployment result
|
|
80
|
+
* @throws {Error} If critical phase fails
|
|
81
|
+
*/
|
|
82
|
+
async execute(options = {}) {
|
|
83
|
+
const {
|
|
84
|
+
continueOnError = false
|
|
85
|
+
} = options;
|
|
86
|
+
try {
|
|
87
|
+
console.log(`🎯 Starting deployment orchestration: ${this.deploymentId}`);
|
|
88
|
+
console.log(`📊 Phases: ${PHASE_SEQUENCE.join(' → ')}`);
|
|
89
|
+
console.log('');
|
|
90
|
+
|
|
91
|
+
// Execute each phase in sequence
|
|
92
|
+
for (const phase of PHASE_SEQUENCE) {
|
|
93
|
+
try {
|
|
94
|
+
const result = await this.executePhase(phase);
|
|
95
|
+
this.phaseResults.set(phase, result);
|
|
96
|
+
|
|
97
|
+
// Log phase success
|
|
98
|
+
if (this.auditor) {
|
|
99
|
+
this.auditor.logPhase(this.deploymentId, phase, 'complete', {
|
|
100
|
+
result
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
console.log(`✅ Phase '${phase}' completed successfully`);
|
|
104
|
+
} catch (error) {
|
|
105
|
+
// Store phase error
|
|
106
|
+
this.phaseErrors.set(phase, error);
|
|
107
|
+
console.error(`❌ Phase '${phase}' failed: ${error.message}`);
|
|
108
|
+
|
|
109
|
+
// Log phase error
|
|
110
|
+
if (this.auditor) {
|
|
111
|
+
this.auditor.logError(this.deploymentId, error, {
|
|
112
|
+
phase,
|
|
113
|
+
context: this.executionContext
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Handle critical phases
|
|
118
|
+
if (this.isCriticalPhase(phase)) {
|
|
119
|
+
if (!continueOnError) {
|
|
120
|
+
throw error;
|
|
121
|
+
}
|
|
122
|
+
console.warn(`⚠️ Continuing despite critical phase failure in '${phase}'`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Generate execution summary
|
|
128
|
+
const summary = this.generateExecutionSummary();
|
|
129
|
+
console.log('');
|
|
130
|
+
console.log(`✅ Deployment orchestration completed: ${this.deploymentId}`);
|
|
131
|
+
console.log(`📈 Execution time: ${this.getExecutionTime()}ms`);
|
|
132
|
+
return summary;
|
|
133
|
+
} catch (error) {
|
|
134
|
+
// Log fatal error to auditor if available
|
|
135
|
+
if (this.auditor) {
|
|
136
|
+
this.auditor.logError(this.deploymentId, error, {
|
|
137
|
+
fatal: true,
|
|
138
|
+
phase: this.currentPhase,
|
|
139
|
+
context: this.executionContext
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Re-throw the error without additional wrapping
|
|
144
|
+
throw error;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Execute single phase
|
|
150
|
+
* @private
|
|
151
|
+
* @param {string} phase - Phase name
|
|
152
|
+
* @returns {Promise<Object>} Phase result
|
|
153
|
+
*/
|
|
154
|
+
async executePhase(phase) {
|
|
155
|
+
this.currentPhase = phase;
|
|
156
|
+
const phaseStartTime = Date.now();
|
|
157
|
+
console.log(`\n🔄 Executing phase: '${phase}'`);
|
|
158
|
+
console.log(` ├─ Phase state: pending → executing → complete`);
|
|
159
|
+
|
|
160
|
+
// Update phase state
|
|
161
|
+
this.phaseStates.set(phase, 'executing');
|
|
162
|
+
try {
|
|
163
|
+
// Validate phase method exists
|
|
164
|
+
const phaseMethod = `on${this.capitalize(phase)}`;
|
|
165
|
+
if (typeof this[phaseMethod] !== 'function') {
|
|
166
|
+
throw new Error(`Phase method '${phaseMethod}' not implemented in ${this.constructor.name}`);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Execute phase-specific logic
|
|
170
|
+
const result = await this[phaseMethod]();
|
|
171
|
+
|
|
172
|
+
// Record phase timing
|
|
173
|
+
const phaseDuration = Date.now() - phaseStartTime;
|
|
174
|
+
this.phaseTimings.set(phase, phaseDuration);
|
|
175
|
+
|
|
176
|
+
// Update phase state
|
|
177
|
+
this.phaseStates.set(phase, 'complete');
|
|
178
|
+
return {
|
|
179
|
+
phase,
|
|
180
|
+
status: 'success',
|
|
181
|
+
result,
|
|
182
|
+
duration: phaseDuration,
|
|
183
|
+
timestamp: new Date().toISOString()
|
|
184
|
+
};
|
|
185
|
+
} catch (error) {
|
|
186
|
+
// Record error and re-throw
|
|
187
|
+
const phaseDuration = Date.now() - phaseStartTime;
|
|
188
|
+
this.phaseTimings.set(phase, phaseDuration);
|
|
189
|
+
this.phaseStates.set(phase, 'error');
|
|
190
|
+
throw error;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Determine if phase is critical to deployment success
|
|
196
|
+
* Critical phases: initialization, validation, deployment
|
|
197
|
+
* Non-critical: monitoring, verification (can warn instead)
|
|
198
|
+
*
|
|
199
|
+
* @private
|
|
200
|
+
* @param {string} phase - Phase name
|
|
201
|
+
* @returns {boolean} True if phase is critical
|
|
202
|
+
*/
|
|
203
|
+
isCriticalPhase(phase) {
|
|
204
|
+
const criticalPhases = [DEPLOYMENT_PHASES.INITIALIZATION, DEPLOYMENT_PHASES.DEPLOYMENT];
|
|
205
|
+
return criticalPhases.includes(phase);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Generate comprehensive execution summary
|
|
210
|
+
* @private
|
|
211
|
+
* @returns {Object} Execution summary
|
|
212
|
+
*/
|
|
213
|
+
generateExecutionSummary() {
|
|
214
|
+
const summary = {
|
|
215
|
+
deploymentId: this.deploymentId,
|
|
216
|
+
orchestrator: this.constructor.name,
|
|
217
|
+
totalDuration: this.getExecutionTime(),
|
|
218
|
+
phases: {},
|
|
219
|
+
stats: {
|
|
220
|
+
total: PHASE_SEQUENCE.length,
|
|
221
|
+
completed: 0,
|
|
222
|
+
failed: 0,
|
|
223
|
+
skipped: 0
|
|
224
|
+
},
|
|
225
|
+
errors: Array.from(this.phaseErrors.entries()).map(([phase, error]) => ({
|
|
226
|
+
phase,
|
|
227
|
+
message: error.message,
|
|
228
|
+
severity: this.isCriticalPhase(phase) ? 'critical' : 'warning'
|
|
229
|
+
}))
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
// Add phase details to summary
|
|
233
|
+
for (const phase of PHASE_SEQUENCE) {
|
|
234
|
+
const state = this.phaseStates.get(phase);
|
|
235
|
+
const duration = this.phaseTimings.get(phase) || 0;
|
|
236
|
+
summary.phases[phase] = {
|
|
237
|
+
state,
|
|
238
|
+
duration,
|
|
239
|
+
result: this.phaseResults.get(phase),
|
|
240
|
+
error: this.phaseErrors.get(phase)?.message
|
|
241
|
+
};
|
|
242
|
+
if (state === 'complete') summary.stats.completed++;
|
|
243
|
+
if (state === 'error') summary.stats.failed++;
|
|
244
|
+
if (!state) summary.stats.skipped++;
|
|
245
|
+
}
|
|
246
|
+
summary.stats.successRate = Math.round(summary.stats.completed / summary.stats.total * 100);
|
|
247
|
+
return summary;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Get total execution time in milliseconds
|
|
252
|
+
* @returns {number} Execution time in ms
|
|
253
|
+
*/
|
|
254
|
+
getExecutionTime() {
|
|
255
|
+
return Date.now() - this.startTime;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Get phase status
|
|
260
|
+
* @param {string} phase - Phase name
|
|
261
|
+
* @returns {string} Phase state: 'pending', 'executing', 'complete', 'error'
|
|
262
|
+
*/
|
|
263
|
+
getPhaseStatus(phase) {
|
|
264
|
+
return this.phaseStates.get(phase) || 'pending';
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Get all phase results
|
|
269
|
+
* @returns {Map<string, Object>} Map of phase results
|
|
270
|
+
*/
|
|
271
|
+
getPhaseResults() {
|
|
272
|
+
return new Map(this.phaseResults);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Get specific phase result
|
|
277
|
+
* @param {string} phase - Phase name
|
|
278
|
+
* @returns {Object} Phase result or null
|
|
279
|
+
*/
|
|
280
|
+
getPhaseResult(phase) {
|
|
281
|
+
return this.phaseResults.get(phase) || null;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Get execution context
|
|
286
|
+
* @returns {Object} Current execution context
|
|
287
|
+
*/
|
|
288
|
+
getExecutionContext() {
|
|
289
|
+
return {
|
|
290
|
+
...this.executionContext,
|
|
291
|
+
currentPhase: this.currentPhase,
|
|
292
|
+
phaseStates: Object.fromEntries(this.phaseStates),
|
|
293
|
+
phaseTimings: Object.fromEntries(this.phaseTimings),
|
|
294
|
+
totalDuration: this.getExecutionTime()
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Capitalize first letter of string and convert hyphens to camelCase
|
|
300
|
+
* Used for method name generation with special handling for phase names
|
|
301
|
+
*
|
|
302
|
+
* @private
|
|
303
|
+
* @param {string} str - String to capitalize
|
|
304
|
+
* @returns {string} Capitalized camelCase string
|
|
305
|
+
*/
|
|
306
|
+
capitalize(str) {
|
|
307
|
+
// Special mappings for phase names to method names
|
|
308
|
+
const phaseToMethodMap = {
|
|
309
|
+
'initialization': 'Initialize',
|
|
310
|
+
'validation': 'Validation',
|
|
311
|
+
'preparation': 'Prepare',
|
|
312
|
+
'deployment': 'Deploy',
|
|
313
|
+
'verification': 'Verify',
|
|
314
|
+
'monitoring': 'Monitor'
|
|
315
|
+
};
|
|
316
|
+
if (phaseToMethodMap[str]) {
|
|
317
|
+
return phaseToMethodMap[str];
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Generic camelCase converter for extensibility
|
|
321
|
+
return str.split('-').map((word, idx) => idx === 0 ? word.charAt(0).toUpperCase() + word.slice(1) : word.charAt(0).toUpperCase() + word.slice(1)).join('');
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Phase lifecycle methods (to be implemented by subclasses)
|
|
326
|
+
* Each phase must be implemented in concrete orchestrator
|
|
327
|
+
*/
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Initialization phase
|
|
331
|
+
* Setup and validate deployment environment
|
|
332
|
+
*
|
|
333
|
+
* @abstract
|
|
334
|
+
* @returns {Promise<Object>} Initialization result
|
|
335
|
+
*/
|
|
336
|
+
async onInitialize() {
|
|
337
|
+
throw new Error(`onInitialize() must be implemented in ${this.constructor.name}`);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Validation phase
|
|
342
|
+
* Validate all prerequisites and configurations
|
|
343
|
+
*
|
|
344
|
+
* @abstract
|
|
345
|
+
* @returns {Promise<Object>} Validation result
|
|
346
|
+
*/
|
|
347
|
+
async onValidation() {
|
|
348
|
+
throw new Error(`onValidation() must be implemented in ${this.constructor.name}`);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Preparation phase
|
|
353
|
+
* Prepare resources and deployment artifacts
|
|
354
|
+
*
|
|
355
|
+
* @abstract
|
|
356
|
+
* @returns {Promise<Object>} Preparation result
|
|
357
|
+
*/
|
|
358
|
+
async onPrepare() {
|
|
359
|
+
throw new Error(`onPrepare() must be implemented in ${this.constructor.name}`);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Deployment phase
|
|
364
|
+
* Execute actual deployment operations
|
|
365
|
+
*
|
|
366
|
+
* @abstract
|
|
367
|
+
* @returns {Promise<Object>} Deployment result
|
|
368
|
+
*/
|
|
369
|
+
async onDeploy() {
|
|
370
|
+
throw new Error(`onDeploy() must be implemented in ${this.constructor.name}`);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Verification phase
|
|
375
|
+
* Verify deployment success and health
|
|
376
|
+
*
|
|
377
|
+
* @abstract
|
|
378
|
+
* @returns {Promise<Object>} Verification result
|
|
379
|
+
*/
|
|
380
|
+
async onVerify() {
|
|
381
|
+
throw new Error(`onVerify() must be implemented in ${this.constructor.name}`);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Monitoring phase
|
|
386
|
+
* Setup monitoring and alerting for deployed service
|
|
387
|
+
*
|
|
388
|
+
* @abstract
|
|
389
|
+
* @returns {Promise<Object>} Monitoring result
|
|
390
|
+
*/
|
|
391
|
+
async onMonitor() {
|
|
392
|
+
throw new Error(`onMonitor() must be implemented in ${this.constructor.name}`);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Static helper to get deployment phases
|
|
397
|
+
* @static
|
|
398
|
+
* @returns {Object} Phase constants
|
|
399
|
+
*/
|
|
400
|
+
static getPhases() {
|
|
401
|
+
return {
|
|
402
|
+
...DEPLOYMENT_PHASES
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Static helper to get phase sequence
|
|
408
|
+
* @static
|
|
409
|
+
* @returns {string[]} Ordered phase names
|
|
410
|
+
*/
|
|
411
|
+
static getPhaseSequence() {
|
|
412
|
+
return [...PHASE_SEQUENCE];
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Static helper to validate phase name
|
|
417
|
+
* @static
|
|
418
|
+
* @param {string} phase - Phase to validate
|
|
419
|
+
* @returns {boolean} True if valid phase
|
|
420
|
+
*/
|
|
421
|
+
static isValidPhase(phase) {
|
|
422
|
+
return PHASE_SEQUENCE.includes(phase);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
export default BaseDeploymentOrchestrator;
|
|
426
|
+
export { DEPLOYMENT_PHASES, PHASE_SEQUENCE };
|