@tamyla/clodo-framework 3.1.21 → 3.1.22

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 (169) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +53 -0
  3. package/dist/bin/clodo-service.js +47 -15
  4. package/dist/bin/commands/deploy.js +115 -83
  5. package/dist/bin/commands/helpers/deployment-ui.js +138 -0
  6. package/dist/bin/commands/helpers/deployment-verification.js +251 -0
  7. package/dist/bin/commands/helpers/error-recovery.js +80 -0
  8. package/dist/bin/commands/helpers/resource-detection.js +113 -0
  9. package/dist/bin/commands/validate.js +1 -1
  10. package/dist/bin/security/security-cli.js +1 -1
  11. package/dist/bin/shared/cache/configuration-cache.js +82 -0
  12. package/dist/bin/shared/cloudflare/domain-manager.js +1 -1
  13. package/dist/bin/shared/cloudflare/index.js +1 -1
  14. package/dist/bin/shared/cloudflare/ops.js +6 -4
  15. package/dist/bin/shared/config/ConfigurationManager.js +23 -1
  16. package/dist/bin/shared/config/command-config-manager.js +19 -3
  17. package/dist/bin/shared/config/index.js +1 -1
  18. package/dist/bin/shared/deployment/credential-collector.js +30 -7
  19. package/dist/bin/shared/deployment/index.js +2 -2
  20. package/dist/bin/shared/deployment/rollback-manager.js +4 -520
  21. package/dist/bin/shared/deployment/utilities/d1-error-recovery.js +177 -0
  22. package/dist/bin/shared/deployment/validator.js +40 -10
  23. package/dist/bin/shared/deployment/workflows/deployment-summary.js +214 -0
  24. package/dist/bin/shared/deployment/workflows/interactive-confirmation.js +188 -0
  25. package/dist/bin/shared/deployment/workflows/interactive-database-workflow.js +234 -0
  26. package/dist/bin/shared/deployment/workflows/interactive-domain-info-gatherer.js +240 -0
  27. package/dist/bin/shared/deployment/workflows/interactive-secret-workflow.js +228 -0
  28. package/dist/bin/shared/deployment/workflows/interactive-testing-workflow.js +235 -0
  29. package/dist/bin/shared/deployment/workflows/interactive-validation.js +218 -0
  30. package/dist/bin/shared/error-handling/error-classifier.js +46 -0
  31. package/dist/bin/shared/monitoring/health-checker.js +129 -1
  32. package/dist/bin/shared/monitoring/memory-manager.js +17 -6
  33. package/dist/bin/shared/routing/domain-router.js +1 -1
  34. package/dist/bin/shared/utils/deployment-validator.js +97 -0
  35. package/dist/bin/shared/utils/formatters.js +10 -0
  36. package/dist/bin/shared/utils/index.js +13 -1
  37. package/dist/bin/shared/utils/interactive-prompts.js +34 -18
  38. package/dist/bin/shared/utils/progress-manager.js +2 -2
  39. package/dist/bin/shared/utils/progress-spinner.js +53 -0
  40. package/dist/bin/shared/utils/sensitive-redactor.js +91 -0
  41. package/dist/bin/shared/validation/ValidationRegistry.js +1 -1
  42. package/dist/security/index.js +1 -1
  43. package/dist/security/patterns/insecure-patterns.js +1 -1
  44. package/dist/utils/constants.js +102 -0
  45. package/dist/utils/deployment/wrangler-config-manager.js +215 -48
  46. package/dist/utils/framework-config.js +2 -2
  47. package/dist/utils/interactive-prompts.js +10 -59
  48. package/package.json +16 -8
  49. package/dist/bin/clodo-service-old.js +0 -868
  50. package/dist/bin/clodo-service-test.js +0 -10
  51. package/dist/bin/commands/assess.js +0 -91
  52. package/dist/bin/commands/create.js +0 -77
  53. package/dist/bin/commands/diagnose.js +0 -83
  54. package/dist/bin/commands/helpers.js +0 -138
  55. package/dist/bin/commands/update.js +0 -75
  56. package/dist/bin/database/deployment-db-manager.js +0 -423
  57. package/dist/bin/database/enterprise-db-manager.js +0 -457
  58. package/dist/bin/database/wrangler-d1-manager.js +0 -685
  59. package/dist/bin/deployment/enterprise-deploy.js +0 -877
  60. package/dist/bin/deployment/master-deploy.js +0 -1376
  61. package/dist/bin/deployment/modular-enterprise-deploy.js +0 -466
  62. package/dist/bin/deployment/modules/DeploymentConfiguration.js +0 -395
  63. package/dist/bin/deployment/modules/DeploymentOrchestrator.js +0 -492
  64. package/dist/bin/deployment/modules/EnvironmentManager.js +0 -517
  65. package/dist/bin/deployment/modules/MonitoringIntegration.js +0 -560
  66. package/dist/bin/deployment/modules/ValidationManager.js +0 -342
  67. package/dist/bin/deployment/orchestration/BaseDeploymentOrchestrator.js +0 -426
  68. package/dist/bin/deployment/orchestration/EnterpriseOrchestrator.js +0 -401
  69. package/dist/bin/deployment/orchestration/PortfolioOrchestrator.js +0 -273
  70. package/dist/bin/deployment/orchestration/SingleServiceOrchestrator.js +0 -231
  71. package/dist/bin/deployment/orchestration/UnifiedDeploymentOrchestrator.js +0 -662
  72. package/dist/bin/deployment/test-interactive-utils.js +0 -66
  73. package/dist/bin/portfolio/portfolio-manager.js +0 -487
  74. package/dist/bin/service-management/create-service.js +0 -122
  75. package/dist/bin/service-management/init-service.js +0 -79
  76. package/dist/config/customers.js +0 -623
  77. package/dist/config/domains.js +0 -186
  78. package/dist/config/index.js +0 -6
  79. package/dist/database/database-orchestrator.js +0 -795
  80. package/dist/database/index.js +0 -4
  81. package/dist/deployment/index.js +0 -11
  82. package/dist/deployment/orchestration/BaseDeploymentOrchestrator.js +0 -426
  83. package/dist/deployment/orchestration/EnterpriseOrchestrator.js +0 -401
  84. package/dist/deployment/orchestration/PortfolioOrchestrator.js +0 -273
  85. package/dist/deployment/orchestration/SingleServiceOrchestrator.js +0 -231
  86. package/dist/deployment/orchestration/UnifiedDeploymentOrchestrator.js +0 -662
  87. package/dist/deployment/orchestration/index.js +0 -17
  88. package/dist/deployment/rollback-manager.js +0 -36
  89. package/dist/deployment/wrangler-deployer.js +0 -640
  90. package/dist/handlers/GenericRouteHandler.js +0 -532
  91. package/dist/migration/MigrationAdapters.js +0 -562
  92. package/dist/modules/ModuleManager.js +0 -668
  93. package/dist/modules/security.js +0 -96
  94. package/dist/orchestration/cross-domain-coordinator.js +0 -1083
  95. package/dist/orchestration/index.js +0 -5
  96. package/dist/orchestration/modules/DeploymentCoordinator.js +0 -368
  97. package/dist/orchestration/modules/DomainResolver.js +0 -198
  98. package/dist/orchestration/modules/StateManager.js +0 -332
  99. package/dist/orchestration/multi-domain-orchestrator.js +0 -724
  100. package/dist/routing/EnhancedRouter.js +0 -158
  101. package/dist/schema/SchemaManager.js +0 -778
  102. package/dist/service-management/ConfirmationEngine.js +0 -412
  103. package/dist/service-management/ErrorTracker.js +0 -299
  104. package/dist/service-management/GenerationEngine.js +0 -447
  105. package/dist/service-management/InputCollector.js +0 -619
  106. package/dist/service-management/ServiceCreator.js +0 -265
  107. package/dist/service-management/ServiceInitializer.js +0 -453
  108. package/dist/service-management/ServiceOrchestrator.js +0 -633
  109. package/dist/service-management/generators/BaseGenerator.js +0 -233
  110. package/dist/service-management/generators/GeneratorRegistry.js +0 -254
  111. package/dist/service-management/generators/cicd/CiWorkflowGenerator.js +0 -87
  112. package/dist/service-management/generators/cicd/DeployWorkflowGenerator.js +0 -106
  113. package/dist/service-management/generators/code/ServiceHandlersGenerator.js +0 -235
  114. package/dist/service-management/generators/code/ServiceMiddlewareGenerator.js +0 -116
  115. package/dist/service-management/generators/code/ServiceUtilsGenerator.js +0 -246
  116. package/dist/service-management/generators/code/WorkerIndexGenerator.js +0 -143
  117. package/dist/service-management/generators/config/DevelopmentEnvGenerator.js +0 -101
  118. package/dist/service-management/generators/config/DomainsConfigGenerator.js +0 -175
  119. package/dist/service-management/generators/config/EnvExampleGenerator.js +0 -178
  120. package/dist/service-management/generators/config/ProductionEnvGenerator.js +0 -97
  121. package/dist/service-management/generators/config/StagingEnvGenerator.js +0 -97
  122. package/dist/service-management/generators/config/WranglerTomlGenerator.js +0 -238
  123. package/dist/service-management/generators/core/PackageJsonGenerator.js +0 -243
  124. package/dist/service-management/generators/core/SiteConfigGenerator.js +0 -115
  125. package/dist/service-management/generators/documentation/ApiDocsGenerator.js +0 -331
  126. package/dist/service-management/generators/documentation/ConfigurationDocsGenerator.js +0 -294
  127. package/dist/service-management/generators/documentation/DeploymentDocsGenerator.js +0 -244
  128. package/dist/service-management/generators/documentation/ReadmeGenerator.js +0 -196
  129. package/dist/service-management/generators/schemas/ServiceSchemaGenerator.js +0 -190
  130. package/dist/service-management/generators/scripts/DeployScriptGenerator.js +0 -123
  131. package/dist/service-management/generators/scripts/HealthCheckScriptGenerator.js +0 -101
  132. package/dist/service-management/generators/scripts/SetupScriptGenerator.js +0 -88
  133. package/dist/service-management/generators/service-types/StaticSiteGenerator.js +0 -342
  134. package/dist/service-management/generators/testing/EslintConfigGenerator.js +0 -85
  135. package/dist/service-management/generators/testing/IntegrationTestsGenerator.js +0 -237
  136. package/dist/service-management/generators/testing/JestConfigGenerator.js +0 -72
  137. package/dist/service-management/generators/testing/UnitTestsGenerator.js +0 -277
  138. package/dist/service-management/generators/tooling/DockerComposeGenerator.js +0 -71
  139. package/dist/service-management/generators/tooling/GitignoreGenerator.js +0 -143
  140. package/dist/service-management/generators/utils/FileWriter.js +0 -179
  141. package/dist/service-management/generators/utils/PathResolver.js +0 -157
  142. package/dist/service-management/generators/utils/ServiceManifestGenerator.js +0 -111
  143. package/dist/service-management/generators/utils/TemplateEngine.js +0 -185
  144. package/dist/service-management/generators/utils/index.js +0 -18
  145. package/dist/service-management/handlers/ConfirmationHandler.js +0 -71
  146. package/dist/service-management/handlers/GenerationHandler.js +0 -80
  147. package/dist/service-management/handlers/InputHandler.js +0 -59
  148. package/dist/service-management/handlers/ValidationHandler.js +0 -203
  149. package/dist/service-management/index.js +0 -14
  150. package/dist/service-management/routing/DomainRouteMapper.js +0 -311
  151. package/dist/service-management/routing/RouteGenerator.js +0 -266
  152. package/dist/service-management/routing/WranglerRoutesBuilder.js +0 -273
  153. package/dist/service-management/routing/index.js +0 -14
  154. package/dist/service-management/services/DirectoryStructureService.js +0 -56
  155. package/dist/service-management/services/GenerationCoordinator.js +0 -208
  156. package/dist/service-management/services/GeneratorRegistry.js +0 -174
  157. package/dist/services/GenericDataService.js +0 -501
  158. package/dist/ui-structures/concepts/second-order-acquisition-strategy.md +0 -286
  159. package/dist/ui-structures/concepts/service-lifecycle-management.md +0 -150
  160. package/dist/ui-structures/concepts/service-manifest-guide.md +0 -309
  161. package/dist/ui-structures/concepts/three-tier-categorization-strategy.md +0 -231
  162. package/dist/ui-structures/creation/automated-generation-ui.json +0 -246
  163. package/dist/ui-structures/creation/core-inputs-ui.json +0 -217
  164. package/dist/ui-structures/creation/smart-confirmable-ui.json +0 -451
  165. package/dist/ui-structures/reference/absolutely-required-inputs.json +0 -315
  166. package/dist/ui-structures/reference/service-manifest-template.json +0 -342
  167. package/dist/version/VersionDetector.js +0 -723
  168. package/dist/worker/index.js +0 -4
  169. package/dist/worker/integration.js +0 -351
@@ -11,7 +11,7 @@
11
11
  import chalk from 'chalk';
12
12
  import { askUser, askPassword, askChoice, closePrompts } from '../utils/interactive-prompts.js';
13
13
  import { ApiTokenManager } from '../security/api-token-manager.js';
14
- import { CloudflareAPI } from "../../../utils/cloudflare/api.js";
14
+ import { CloudflareAPI } from '../../../utils/cloudflare/api.js';
15
15
  export class DeploymentCredentialCollector {
16
16
  constructor(options = {}) {
17
17
  this.servicePath = options.servicePath || '.';
@@ -32,13 +32,16 @@ export class DeploymentCredentialCollector {
32
32
  const startCredentials = {
33
33
  token: options.token || process.env.CLOUDFLARE_API_TOKEN || null,
34
34
  accountId: options.accountId || process.env.CLOUDFLARE_ACCOUNT_ID || null,
35
- zoneId: options.zoneId || process.env.CLOUDFLARE_ZONE_ID || null
35
+ zoneId: options.zoneId || process.env.CLOUDFLARE_ZONE_ID || null,
36
+ zoneName: null // Will be populated when fetching zone
36
37
  };
37
38
 
38
39
  // All credentials provided - quick path
39
40
  if (startCredentials.token && startCredentials.accountId && startCredentials.zoneId) {
40
41
  if (!this.quiet) {
41
- console.log(chalk.green('\n✅ All credentials provided via flags or environment variables'));
42
+ const tokenSource = options.token ? '--token flag' : 'environment variable';
43
+ console.log(chalk.blue(`\nℹ️ Using credentials from: ${tokenSource}`));
44
+ console.log(chalk.green('✅ All credentials provided via flags or environment variables'));
42
45
  }
43
46
  return startCredentials;
44
47
  }
@@ -65,6 +68,7 @@ export class DeploymentCredentialCollector {
65
68
  }
66
69
  let accountId = startCredentials.accountId;
67
70
  let zoneId = startCredentials.zoneId;
71
+ let zoneName = startCredentials.zoneName;
68
72
  try {
69
73
  const cloudflareAPI = new CloudflareAPI(token);
70
74
 
@@ -86,7 +90,9 @@ export class DeploymentCredentialCollector {
86
90
 
87
91
  // If zone ID not provided, fetch from Cloudflare
88
92
  if (!zoneId) {
89
- zoneId = await this.fetchZoneId(cloudflareAPI);
93
+ const zoneInfo = await this.fetchZoneId(cloudflareAPI);
94
+ zoneId = zoneInfo.id;
95
+ zoneName = zoneInfo.name;
90
96
  }
91
97
  } catch (error) {
92
98
  console.error(chalk.red(`\n❌ Credential validation failed:`));
@@ -96,10 +102,21 @@ export class DeploymentCredentialCollector {
96
102
  if (!this.quiet) {
97
103
  console.log(chalk.green('\n✅ All credentials collected and validated\n'));
98
104
  }
105
+
106
+ // Return structured Cloudflare settings object
107
+ // This encapsulates all zone-specific configuration for multi-domain deployments
99
108
  return {
100
109
  token,
101
110
  accountId,
102
- zoneId
111
+ zoneId,
112
+ zoneName,
113
+ // Convenience: cloudflareSettings object for passing to orchestrators
114
+ cloudflareSettings: {
115
+ token,
116
+ accountId,
117
+ zoneId,
118
+ zoneName
119
+ }
103
120
  };
104
121
  }
105
122
 
@@ -197,7 +214,10 @@ export class DeploymentCredentialCollector {
197
214
  if (!this.quiet) {
198
215
  console.log(chalk.green(`✅ Found domain: ${zones[0].name}\n`));
199
216
  }
200
- return zones[0].id;
217
+ return {
218
+ id: zones[0].id,
219
+ name: zones[0].name
220
+ };
201
221
  }
202
222
 
203
223
  // Multiple zones - let user choose
@@ -210,7 +230,10 @@ export class DeploymentCredentialCollector {
210
230
  if (!this.quiet) {
211
231
  console.log(chalk.green(`✅ Selected: ${selectedZone.name}\n`));
212
232
  }
213
- return selectedZone.id;
233
+ return {
234
+ id: selectedZone.id,
235
+ name: selectedZone.name
236
+ };
214
237
  } catch (error) {
215
238
  console.error(chalk.red('❌ Failed to fetch domains:'));
216
239
  console.error(chalk.yellow(error.message));
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  export { DeploymentValidator } from './validator.js';
7
- export { MultiDomainOrchestrator } from '../../src/orchestration/multi-domain-orchestrator.js';
8
- export { CrossDomainCoordinator } from '../../src/orchestration/cross-domain-coordinator.js';
7
+ export { MultiDomainOrchestrator } from '../../orchestration/multi-domain-orchestrator.js';
8
+ export { CrossDomainCoordinator } from '../../orchestration/cross-domain-coordinator.js';
9
9
  export { DeploymentAuditor } from './auditor.js';
10
10
  export { RollbackManager } from './rollback-manager.js';
@@ -1,523 +1,7 @@
1
- #!/usr/bin/env node
2
-
3
1
  /**
4
- * Rollback Manager Module
5
- * Enterprise-grade rollback system for safe deployment recovery
6
- *
7
- * Extracted from bulletproof-deploy.js with enhancements
2
+ * Rollback Manager - Deployment Module Re-export
3
+ *
4
+ * Re-exports the RollbackManager for deployment operations
8
5
  */
9
- import { access, readFile, writeFile, mkdir, copyFile } from 'fs/promises';
10
- import { promisify } from 'util';
11
- import { exec } from 'child_process';
12
- const execAsync = promisify(exec);
13
- import { join, dirname } from 'path';
14
-
15
- /**
16
- * Advanced Rollback Manager
17
- * Provides comprehensive rollback capabilities for deployment failures
18
- */
19
- export class RollbackManager {
20
- constructor(options = {}) {
21
- this.deploymentId = options.deploymentId || this.generateRollbackId();
22
- this.environment = options.environment || 'production';
23
- this.dryRun = options.dryRun || false;
24
- this.retryAttempts = options.retryAttempts || 3;
25
- this.retryDelay = options.retryDelay || 2000;
26
-
27
- // Rollback state tracking
28
- this.rollbackPlan = {
29
- id: this.deploymentId,
30
- created: new Date(),
31
- actions: [],
32
- backups: new Map(),
33
- status: 'initialized',
34
- executedActions: [],
35
- failedActions: [],
36
- totalActions: 0
37
- };
38
-
39
- // Backup directories
40
- this.backupPaths = {
41
- root: 'backups',
42
- deployment: join('backups', 'deployments', this.deploymentId),
43
- configs: join('backups', 'configs', this.deploymentId),
44
- secrets: join('backups', 'secrets', this.deploymentId),
45
- database: join('backups', 'database', this.deploymentId)
46
- };
47
-
48
- // Note: Async initialization required - call initialize() after construction
49
- }
50
-
51
- /**
52
- * Initialize the rollback manager asynchronously
53
- */
54
- async initialize() {
55
- await this.initializeRollbackSystem();
56
- }
57
-
58
- /**
59
- * Generate unique rollback identifier
60
- * @returns {string} Rollback ID
61
- */
62
- generateRollbackId() {
63
- const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
64
- const random = Math.random().toString(36).substring(2, 8);
65
- return `rollback-${timestamp}-${random}`;
66
- }
67
-
68
- /**
69
- * Initialize rollback system and create backup directories
70
- */
71
- async initializeRollbackSystem() {
72
- console.log('🔄 Rollback System v1.0');
73
- console.log('========================');
74
- console.log(`🆔 Rollback ID: ${this.rollbackPlan.id}`);
75
- console.log(`🌍 Environment: ${this.environment}`);
76
- console.log(`🔍 Mode: ${this.dryRun ? 'DRY RUN' : 'LIVE ROLLBACK'}`);
77
- console.log('');
78
-
79
- // Create backup directories
80
- for (const path of Object.values(this.backupPaths)) {
81
- try {
82
- await access(path);
83
- } catch {
84
- await mkdir(path, {
85
- recursive: true
86
- });
87
- }
88
- }
89
- this.logRollbackEvent('SYSTEM_INITIALIZED', {
90
- backupPaths: this.backupPaths,
91
- environment: this.environment
92
- });
93
- }
94
-
95
- /**
96
- * Add rollback action to the plan
97
- * @param {Object} action - Rollback action configuration
98
- */
99
- addRollbackAction(action) {
100
- const rollbackAction = {
101
- id: `action-${this.rollbackPlan.actions.length + 1}`,
102
- timestamp: new Date(),
103
- ...action
104
- };
105
- this.rollbackPlan.actions.push(rollbackAction);
106
- this.rollbackPlan.totalActions++;
107
- this.logRollbackEvent('ACTION_ADDED', rollbackAction);
108
- console.log(`📝 Rollback action added: ${action.type} - ${action.description || 'No description'}`);
109
- }
110
-
111
- /**
112
- * Create backup of current state before deployment
113
- * @param {Object} options - Backup options
114
- * @returns {Promise<Object>} Backup manifest
115
- */
116
- async createStateBackup(options = {}) {
117
- console.log('💾 Creating deployment state backup...');
118
- const backupManifest = {
119
- id: this.deploymentId,
120
- timestamp: new Date(),
121
- environment: this.environment,
122
- files: [],
123
- cloudflareState: {},
124
- databaseState: {}
125
- };
126
- try {
127
- // Backup configuration files
128
- await this.backupConfigurationFiles(backupManifest);
129
-
130
- // Backup Cloudflare state
131
- if (options.includeCloudflare !== false) {
132
- await this.backupCloudflareState(backupManifest);
133
- }
134
-
135
- // Backup database state
136
- if (options.includeDatabase !== false) {
137
- await this.backupDatabaseState(backupManifest);
138
- }
139
-
140
- // Save backup manifest
141
- const manifestPath = join(this.backupPaths.deployment, 'backup-manifest.json');
142
- await writeFile(manifestPath, JSON.stringify(backupManifest, null, 2));
143
- this.rollbackPlan.backups.set('state', backupManifest);
144
- this.logRollbackEvent('BACKUP_CREATED', {
145
- files: backupManifest.files.length,
146
- manifestPath
147
- });
148
- console.log(`✅ State backup created: ${backupManifest.files.length} files backed up`);
149
- return backupManifest;
150
- } catch (error) {
151
- this.logRollbackEvent('BACKUP_FAILED', {
152
- error: error.message
153
- });
154
- throw new Error(`State backup failed: ${error.message}`);
155
- }
156
- }
157
-
158
- /**
159
- * Backup configuration files
160
- * @param {Object} manifest - Backup manifest to update
161
- */
162
- async backupConfigurationFiles(manifest) {
163
- const configFiles = ['package.json', 'wrangler.toml', '.env', 'src/config/domains.js'];
164
- for (const file of configFiles) {
165
- try {
166
- await access(file);
167
- const backupPath = join(this.backupPaths.configs, file.replace(/[/\\]/g, '_'));
168
- const backupDir = dirname(backupPath);
169
- try {
170
- await access(backupDir);
171
- } catch {
172
- await mkdir(backupDir, {
173
- recursive: true
174
- });
175
- }
176
- await copyFile(file, backupPath);
177
- manifest.files.push({
178
- original: file,
179
- backup: backupPath,
180
- timestamp: new Date()
181
- });
182
- console.log(` 📄 Backed up: ${file}`);
183
-
184
- // Add restoration action
185
- this.addRollbackAction({
186
- type: 'restore-file',
187
- description: `Restore ${file}`,
188
- original: file,
189
- backup: backupPath,
190
- command: `copy "${backupPath}" "${file}"`,
191
- priority: 1
192
- });
193
- } catch (error) {
194
- console.warn(` ⚠️ Failed to backup ${file}: ${error.message}`);
195
- }
196
- }
197
- }
198
-
199
- /**
200
- * Backup Cloudflare worker and secrets state
201
- * @param {Object} manifest - Backup manifest to update
202
- */
203
- async backupCloudflareState(manifest) {
204
- try {
205
- console.log(' ☁️ Backing up Cloudflare state...');
206
-
207
- // Get current worker list
208
- const workerList = await this.executeCommand('npx wrangler list', {
209
- timeout: 30000
210
- });
211
- manifest.cloudflareState.workers = workerList;
212
-
213
- // Get current secrets (we can't read values, but we can list keys)
214
- try {
215
- const secretsList = await this.executeCommand('npx wrangler secret list', {
216
- timeout: 30000
217
- });
218
- manifest.cloudflareState.secrets = secretsList;
219
- } catch (error) {
220
- console.log(` ⚠️ Could not backup secrets list: ${error.message}`);
221
- }
222
-
223
- // Save Cloudflare state
224
- const cloudflareBackupPath = join(this.backupPaths.deployment, 'cloudflare-state.json');
225
- await writeFile(cloudflareBackupPath, JSON.stringify(manifest.cloudflareState, null, 2));
226
- console.log(' ✅ Cloudflare state backed up');
227
- } catch (error) {
228
- console.log(` ⚠️ Cloudflare backup failed: ${error.message}`);
229
- }
230
- }
231
-
232
- /**
233
- * Backup database state
234
- * @param {Object} manifest - Backup manifest to update
235
- */
236
- async backupDatabaseState(manifest) {
237
- try {
238
- console.log(' 🗄️ Backing up database state...');
239
-
240
- // Get D1 database list
241
- const dbList = await this.executeCommand('npx wrangler d1 list', {
242
- timeout: 30000
243
- });
244
- manifest.databaseState.databases = dbList;
245
-
246
- // Save database state
247
- const dbBackupPath = join(this.backupPaths.database, 'database-state.json');
248
- await writeFile(dbBackupPath, JSON.stringify(manifest.databaseState, null, 2));
249
- console.log(' ✅ Database state backed up');
250
- } catch (error) {
251
- console.log(` ⚠️ Database backup failed: ${error.message}`);
252
- }
253
- }
254
-
255
- /**
256
- * Execute rollback plan
257
- * @returns {Promise<Object>} Rollback results
258
- */
259
- async executeRollback() {
260
- console.log('\n🔄 EXECUTING ROLLBACK PLAN');
261
- console.log('===========================');
262
- console.log(`📊 Total Actions: ${this.rollbackPlan.totalActions}`);
263
- console.log(`🆔 Rollback ID: ${this.rollbackPlan.id}`);
264
- console.log('');
265
- this.rollbackPlan.status = 'executing';
266
- this.rollbackPlan.startTime = new Date();
267
- const results = {
268
- rollbackId: this.rollbackPlan.id,
269
- successful: [],
270
- failed: [],
271
- skipped: [],
272
- totalActions: this.rollbackPlan.totalActions
273
- };
274
- try {
275
- // Sort actions by priority (higher priority first)
276
- const sortedActions = this.rollbackPlan.actions.sort((a, b) => (b.priority || 0) - (a.priority || 0));
277
- for (const action of sortedActions) {
278
- const actionResult = await this.executeRollbackAction(action);
279
- if (actionResult.success) {
280
- results.successful.push(actionResult);
281
- this.rollbackPlan.executedActions.push(action);
282
- } else {
283
- results.failed.push(actionResult);
284
- this.rollbackPlan.failedActions.push(action);
285
-
286
- // Stop on critical failures unless forced to continue
287
- if (action.critical !== false && !action.continueOnFailure) {
288
- console.log(`❌ Critical rollback action failed: ${action.type}`);
289
- break;
290
- }
291
- }
292
- }
293
- this.rollbackPlan.status = results.failed.length === 0 ? 'completed' : 'partial';
294
- this.rollbackPlan.endTime = new Date();
295
- const duration = (this.rollbackPlan.endTime - this.rollbackPlan.startTime) / 1000;
296
- console.log('\n📊 ROLLBACK SUMMARY');
297
- console.log('===================');
298
- console.log(`✅ Successful: ${results.successful.length}`);
299
- console.log(`❌ Failed: ${results.failed.length}`);
300
- console.log(`⏸️ Skipped: ${results.skipped.length}`);
301
- console.log(`⏱️ Duration: ${duration.toFixed(1)}s`);
302
- console.log(`🏁 Status: ${this.rollbackPlan.status.toUpperCase()}`);
303
- if (results.failed.length > 0) {
304
- console.log('\n❌ Failed Actions:');
305
- results.failed.forEach(failure => {
306
- console.log(` - ${failure.action.type}: ${failure.error}`);
307
- });
308
- }
309
-
310
- // Save rollback report
311
- await this.saveRollbackReport(results);
312
- this.logRollbackEvent('ROLLBACK_COMPLETED', {
313
- status: this.rollbackPlan.status,
314
- successful: results.successful.length,
315
- failed: results.failed.length,
316
- duration
317
- });
318
- return results;
319
- } catch (error) {
320
- this.rollbackPlan.status = 'failed';
321
- this.rollbackPlan.endTime = new Date();
322
- this.logRollbackEvent('ROLLBACK_FAILED', {
323
- error: error.message
324
- });
325
- throw new Error(`Rollback execution failed: ${error.message}`);
326
- }
327
- }
328
-
329
- /**
330
- * Execute individual rollback action
331
- * @param {Object} action - Action to execute
332
- * @returns {Promise<Object>} Action result
333
- */
334
- async executeRollbackAction(action) {
335
- console.log(`🔄 Rolling back: ${action.type} - ${action.description || action.id}`);
336
- const result = {
337
- actionId: action.id,
338
- action: action,
339
- success: false,
340
- error: null,
341
- timestamp: new Date()
342
- };
343
- try {
344
- if (this.dryRun) {
345
- console.log(` 🔍 DRY RUN: Would execute ${action.type}`);
346
- result.success = true;
347
- result.dryRun = true;
348
- return result;
349
- }
350
-
351
- // Execute based on action type
352
- switch (action.type) {
353
- case 'restore-file':
354
- await this.restoreFile(action);
355
- break;
356
- case 'delete-secret':
357
- await this.deleteSecret(action);
358
- break;
359
- case 'delete-database':
360
- await this.deleteDatabase(action);
361
- break;
362
- case 'delete-worker':
363
- await this.deleteWorker(action);
364
- break;
365
- case 'custom-command':
366
- await this.executeCustomCommand(action);
367
- break;
368
- default:
369
- if (action.command) {
370
- await this.executeCommand(action.command, {
371
- timeout: action.timeout || 30000
372
- });
373
- } else {
374
- throw new Error(`Unknown rollback action type: ${action.type}`);
375
- }
376
- }
377
- result.success = true;
378
- console.log(` ✅ Rollback completed: ${action.type}`);
379
- } catch (error) {
380
- result.error = error.message;
381
- console.log(` ❌ Rollback failed: ${action.type} - ${error.message}`);
382
- }
383
- return result;
384
- }
385
-
386
- // Individual rollback action implementations
387
-
388
- async restoreFile(action) {
389
- try {
390
- await access(action.backup);
391
- } catch {
392
- throw new Error(`Backup file not found: ${action.backup}`);
393
- }
394
- await copyFile(action.backup, action.original);
395
- console.log(` 📄 Restored ${action.original}`);
396
- }
397
- async deleteSecret(action) {
398
- const command = action.command || `npx wrangler secret delete ${action.key} --env ${this.environment}`;
399
- await this.executeCommand(command, {
400
- timeout: 30000
401
- });
402
- console.log(` 🔐 Deleted secret: ${action.key}`);
403
- }
404
- async deleteDatabase(action) {
405
- const command = action.command || `npx wrangler d1 delete ${action.name} --skip-confirmation`;
406
- await this.executeCommand(command, {
407
- timeout: 60000
408
- });
409
- console.log(` 🗄️ Deleted database: ${action.name}`);
410
- }
411
- async deleteWorker(action) {
412
- const command = action.command || `npx wrangler delete ${action.name} --env ${this.environment}`;
413
- await this.executeCommand(command, {
414
- timeout: 60000
415
- });
416
- console.log(` ⚡ Deleted worker: ${action.name}`);
417
- }
418
- async executeCustomCommand(action) {
419
- await this.executeCommand(action.command, {
420
- timeout: action.timeout || 30000
421
- });
422
- console.log(` 🔧 Executed: ${action.description}`);
423
- }
424
-
425
- // Utility methods
426
-
427
- async executeCommand(command, options = {}) {
428
- const timeout = options.timeout || 30000;
429
- for (let attempt = 1; attempt <= this.retryAttempts; attempt++) {
430
- try {
431
- const {
432
- stdout
433
- } = await execAsync(command, {
434
- encoding: 'utf8',
435
- stdio: options.stdio || 'pipe',
436
- timeout
437
- });
438
- return stdout;
439
- } catch (error) {
440
- if (attempt === this.retryAttempts) {
441
- throw error;
442
- }
443
- console.log(` ⚠️ Attempt ${attempt}/${this.retryAttempts} failed, retrying...`);
444
- await new Promise(resolve => setTimeout(resolve, this.retryDelay));
445
- }
446
- }
447
- }
448
- async saveRollbackReport(results) {
449
- const report = {
450
- rollbackId: this.rollbackPlan.id,
451
- environment: this.environment,
452
- timestamp: new Date(),
453
- plan: this.rollbackPlan,
454
- results,
455
- summary: {
456
- totalActions: results.totalActions,
457
- successful: results.successful.length,
458
- failed: results.failed.length,
459
- successRate: (results.successful.length / results.totalActions * 100).toFixed(1)
460
- }
461
- };
462
- const reportPath = join(this.backupPaths.deployment, 'rollback-report.json');
463
- await writeFile(reportPath, JSON.stringify(report, null, 2));
464
- console.log(`📊 Rollback report saved: ${reportPath}`);
465
- }
466
- logRollbackEvent(event, details = {}) {
467
- const logEntry = {
468
- timestamp: new Date().toISOString(),
469
- rollbackId: this.rollbackPlan.id,
470
- event,
471
- details
472
- };
473
-
474
- // Log to file if not in dry run mode (fire and forget)
475
- if (!this.dryRun) {
476
- (async () => {
477
- try {
478
- const logPath = join(this.backupPaths.deployment, 'rollback-log.json');
479
- let logs = [];
480
- try {
481
- const logData = await readFile(logPath, 'utf8');
482
- logs = JSON.parse(logData);
483
- } catch {
484
- // File doesn't exist, start with empty logs
485
- }
486
- logs.push(logEntry);
487
- await writeFile(logPath, JSON.stringify(logs, null, 2));
488
- } catch (error) {
489
- console.warn(`⚠️ Failed to log rollback event: ${error.message}`);
490
- }
491
- })();
492
- }
493
- }
494
-
495
- /**
496
- * Get rollback plan status
497
- * @returns {Object} Current rollback plan status
498
- */
499
- getStatus() {
500
- return {
501
- id: this.rollbackPlan.id,
502
- status: this.rollbackPlan.status,
503
- totalActions: this.rollbackPlan.totalActions,
504
- executedActions: this.rollbackPlan.executedActions.length,
505
- failedActions: this.rollbackPlan.failedActions.length,
506
- created: this.rollbackPlan.created,
507
- lastUpdated: new Date()
508
- };
509
- }
510
6
 
511
- /**
512
- * Clear rollback plan (use with caution)
513
- */
514
- clearRollbackPlan() {
515
- this.rollbackPlan.actions = [];
516
- this.rollbackPlan.totalActions = 0;
517
- this.rollbackPlan.executedActions = [];
518
- this.rollbackPlan.failedActions = [];
519
- this.logRollbackEvent('PLAN_CLEARED');
520
- console.log('🧹 Rollback plan cleared');
521
- }
522
- }
523
- export default RollbackManager;
7
+ export { RollbackManager } from '../../../deployment/rollback-manager.js';