@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.
Files changed (130) hide show
  1. package/CHANGELOG.md +564 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1393 -0
  4. package/bin/README.md +71 -0
  5. package/bin/clodo-service.js +416 -0
  6. package/bin/security/security-cli.js +96 -0
  7. package/bin/service-management/README.md +74 -0
  8. package/bin/service-management/create-service.js +129 -0
  9. package/bin/service-management/init-service.js +102 -0
  10. package/bin/service-management/init-service.js.backup +889 -0
  11. package/bin/shared/config/customer-cli.js +293 -0
  12. package/dist/config/ConfigurationManager.js +159 -0
  13. package/dist/config/CustomerConfigCLI.js +220 -0
  14. package/dist/config/FeatureManager.js +426 -0
  15. package/dist/config/customers.js +441 -0
  16. package/dist/config/domains.js +180 -0
  17. package/dist/config/features.js +225 -0
  18. package/dist/config/index.js +6 -0
  19. package/dist/database/database-orchestrator.js +730 -0
  20. package/dist/database/index.js +4 -0
  21. package/dist/deployment/auditor.js +971 -0
  22. package/dist/deployment/index.js +10 -0
  23. package/dist/deployment/rollback-manager.js +523 -0
  24. package/dist/deployment/testers/api-tester.js +80 -0
  25. package/dist/deployment/testers/auth-tester.js +129 -0
  26. package/dist/deployment/testers/core.js +217 -0
  27. package/dist/deployment/testers/database-tester.js +105 -0
  28. package/dist/deployment/testers/index.js +74 -0
  29. package/dist/deployment/testers/load-tester.js +120 -0
  30. package/dist/deployment/testers/performance-tester.js +105 -0
  31. package/dist/deployment/validator.js +558 -0
  32. package/dist/deployment/wrangler-deployer.js +574 -0
  33. package/dist/handlers/GenericRouteHandler.js +532 -0
  34. package/dist/index.js +39 -0
  35. package/dist/migration/MigrationAdapters.js +562 -0
  36. package/dist/modules/ModuleManager.js +668 -0
  37. package/dist/modules/security.js +98 -0
  38. package/dist/orchestration/cross-domain-coordinator.js +1083 -0
  39. package/dist/orchestration/index.js +5 -0
  40. package/dist/orchestration/modules/DeploymentCoordinator.js +258 -0
  41. package/dist/orchestration/modules/DomainResolver.js +196 -0
  42. package/dist/orchestration/modules/StateManager.js +332 -0
  43. package/dist/orchestration/multi-domain-orchestrator.js +255 -0
  44. package/dist/routing/EnhancedRouter.js +158 -0
  45. package/dist/schema/SchemaManager.js +778 -0
  46. package/dist/security/ConfigurationValidator.js +490 -0
  47. package/dist/security/DeploymentManager.js +208 -0
  48. package/dist/security/SecretGenerator.js +142 -0
  49. package/dist/security/SecurityCLI.js +228 -0
  50. package/dist/security/index.js +51 -0
  51. package/dist/security/patterns/environment-rules.js +66 -0
  52. package/dist/security/patterns/insecure-patterns.js +21 -0
  53. package/dist/service-management/ConfirmationEngine.js +411 -0
  54. package/dist/service-management/ErrorTracker.js +294 -0
  55. package/dist/service-management/GenerationEngine.js +3109 -0
  56. package/dist/service-management/InputCollector.js +237 -0
  57. package/dist/service-management/ServiceCreator.js +229 -0
  58. package/dist/service-management/ServiceInitializer.js +448 -0
  59. package/dist/service-management/ServiceOrchestrator.js +638 -0
  60. package/dist/service-management/handlers/ConfigMutator.js +130 -0
  61. package/dist/service-management/handlers/ConfirmationHandler.js +71 -0
  62. package/dist/service-management/handlers/GenerationHandler.js +80 -0
  63. package/dist/service-management/handlers/InputHandler.js +59 -0
  64. package/dist/service-management/handlers/ValidationHandler.js +203 -0
  65. package/dist/service-management/index.js +7 -0
  66. package/dist/services/GenericDataService.js +488 -0
  67. package/dist/shared/cloudflare/domain-discovery.js +562 -0
  68. package/dist/shared/cloudflare/domain-manager.js +912 -0
  69. package/dist/shared/cloudflare/index.js +8 -0
  70. package/dist/shared/cloudflare/ops.js +387 -0
  71. package/dist/shared/config/cache.js +1167 -0
  72. package/dist/shared/config/command-config-manager.js +174 -0
  73. package/dist/shared/config/customer-cli.js +258 -0
  74. package/dist/shared/config/index.js +9 -0
  75. package/dist/shared/config/manager.js +289 -0
  76. package/dist/shared/database/connection-manager.js +338 -0
  77. package/dist/shared/database/index.js +7 -0
  78. package/dist/shared/database/orchestrator.js +632 -0
  79. package/dist/shared/deployment/auditor.js +971 -0
  80. package/dist/shared/deployment/index.js +10 -0
  81. package/dist/shared/deployment/rollback-manager.js +523 -0
  82. package/dist/shared/deployment/validator.js +558 -0
  83. package/dist/shared/index.js +32 -0
  84. package/dist/shared/monitoring/health-checker.js +250 -0
  85. package/dist/shared/monitoring/index.js +8 -0
  86. package/dist/shared/monitoring/memory-manager.js +382 -0
  87. package/dist/shared/monitoring/production-monitor.js +390 -0
  88. package/dist/shared/production-tester/api-tester.js +80 -0
  89. package/dist/shared/production-tester/auth-tester.js +129 -0
  90. package/dist/shared/production-tester/core.js +217 -0
  91. package/dist/shared/production-tester/database-tester.js +105 -0
  92. package/dist/shared/production-tester/index.js +74 -0
  93. package/dist/shared/production-tester/load-tester.js +120 -0
  94. package/dist/shared/production-tester/performance-tester.js +105 -0
  95. package/dist/shared/security/api-token-manager.js +296 -0
  96. package/dist/shared/security/index.js +8 -0
  97. package/dist/shared/security/secret-generator.js +918 -0
  98. package/dist/shared/security/secure-token-manager.js +379 -0
  99. package/dist/shared/utils/error-recovery.js +240 -0
  100. package/dist/shared/utils/graceful-shutdown-manager.js +380 -0
  101. package/dist/shared/utils/index.js +9 -0
  102. package/dist/shared/utils/interactive-prompts.js +134 -0
  103. package/dist/shared/utils/rate-limiter.js +249 -0
  104. package/dist/utils/ErrorHandler.js +173 -0
  105. package/dist/utils/deployment/config-cache.js +1160 -0
  106. package/dist/utils/deployment/index.js +6 -0
  107. package/dist/utils/deployment/interactive-prompts.js +97 -0
  108. package/dist/utils/deployment/secret-generator.js +896 -0
  109. package/dist/utils/dirname-helper.js +35 -0
  110. package/dist/utils/domain-config.js +159 -0
  111. package/dist/utils/error-recovery.js +240 -0
  112. package/dist/utils/esm-helper.js +52 -0
  113. package/dist/utils/framework-config.js +481 -0
  114. package/dist/utils/graceful-shutdown-manager.js +379 -0
  115. package/dist/utils/health-checker.js +114 -0
  116. package/dist/utils/index.js +36 -0
  117. package/dist/utils/prompt-handler.js +98 -0
  118. package/dist/utils/usage-tracker.js +252 -0
  119. package/dist/utils/validation.js +112 -0
  120. package/dist/version/VersionDetector.js +723 -0
  121. package/dist/worker/index.js +4 -0
  122. package/dist/worker/integration.js +332 -0
  123. package/docs/FRAMEWORK-ARCHITECTURE-OVERVIEW.md +206 -0
  124. package/docs/INTEGRATION_GUIDE.md +2045 -0
  125. package/docs/README.md +82 -0
  126. package/docs/SECURITY.md +242 -0
  127. package/docs/deployment/deployment-guide.md +540 -0
  128. package/docs/overview.md +280 -0
  129. package/package.json +176 -0
  130. package/types/index.d.ts +575 -0
@@ -0,0 +1,638 @@
1
+ /**
2
+ * ServiceOrchestrator - Unified Three-Tier Service Management
3
+ *
4
+ * Coordinates the three-tier service creation process:
5
+ * 1. Core Input Collection (6 required inputs)
6
+ * 2. Smart Confirmations (15 derived values)
7
+ * 3. Automated Generation (67 configurations + service manifest)
8
+ */
9
+
10
+ // Modular handler imports
11
+ import { InputHandler } from './handlers/InputHandler.js';
12
+ import { ConfirmationHandler } from './handlers/ConfirmationHandler.js';
13
+ import { GenerationHandler } from './handlers/GenerationHandler.js';
14
+ import { ConfigMutator } from './handlers/ConfigMutator.js';
15
+ import { ValidationHandler } from './handlers/ValidationHandler.js';
16
+
17
+ // Legacy imports for backward compatibility
18
+ import { ServiceCreator } from './ServiceCreator.js';
19
+ import { ErrorTracker } from './ErrorTracker.js';
20
+ import chalk from 'chalk';
21
+ import fs from 'fs/promises';
22
+ import path from 'path';
23
+ export class ServiceOrchestrator {
24
+ constructor(options = {}) {
25
+ this.interactive = options.interactive !== false;
26
+ this.outputPath = options.outputPath || '.';
27
+ this.templatePath = options.templatePath || './templates';
28
+
29
+ // Initialize modular handler components
30
+ this.inputHandler = new InputHandler({
31
+ interactive: this.interactive
32
+ });
33
+ this.confirmationHandler = new ConfirmationHandler({
34
+ interactive: this.interactive
35
+ });
36
+ this.generationHandler = new GenerationHandler({
37
+ outputPath: this.outputPath,
38
+ templatePath: this.templatePath
39
+ });
40
+ this.configMutator = new ConfigMutator();
41
+ this.validationHandler = new ValidationHandler();
42
+
43
+ // Initialize legacy components for backward compatibility
44
+ this.serviceCreator = new ServiceCreator();
45
+ this.errorTracker = new ErrorTracker();
46
+ }
47
+
48
+ /**
49
+ * Run the complete three-tier service creation process interactively
50
+ */
51
+ async runInteractive() {
52
+ console.log(chalk.cyan('🚀 Clodo Framework - Interactive Service Creator'));
53
+ console.log(chalk.white('Welcome to the unified service creation wizard!\n'));
54
+ try {
55
+ // Tier 1: Collect 6 core inputs
56
+ console.log(chalk.yellow('📝 Tier 1: Core Input Collection'));
57
+ console.log(chalk.white('Collecting 6 required inputs for your service...\n'));
58
+ const coreInputs = await this.inputHandler.collectCoreInputs();
59
+
60
+ // Tier 2: Smart confirmations for 15 derived values
61
+ const confirmedValues = await this.confirmationHandler.generateAndConfirm(coreInputs);
62
+
63
+ // Tier 3: Automated generation of 67 components
64
+ console.log(chalk.yellow('⚙️ Tier 3: Automated Generation'));
65
+ console.log(chalk.white('Generating 67 configuration files and service components...\n'));
66
+ const generationResult = await this.generationHandler.generateService(coreInputs, confirmedValues, {
67
+ outputPath: this.outputPath
68
+ });
69
+
70
+ // Display results
71
+ this.displayResults(generationResult);
72
+ } catch (error) {
73
+ throw new Error(`Service creation failed: ${error.message}`);
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Run service creation in non-interactive mode with provided inputs
79
+ */
80
+ async runNonInteractive(coreInputs) {
81
+ console.log(chalk.cyan('🚀 Clodo Framework - Non-Interactive Service Creator'));
82
+ try {
83
+ // Validate inputs
84
+ await this.inputHandler.validateCoreInputs(coreInputs);
85
+
86
+ // Generate derived values automatically
87
+ const confirmedValues = await this.confirmationHandler.generateAndConfirm(coreInputs);
88
+
89
+ // Generate service using GenerationHandler
90
+ const generationResult = await this.generationHandler.generateService(coreInputs, confirmedValues, {
91
+ outputPath: this.outputPath
92
+ });
93
+ console.log(chalk.green(`✓ Service "${coreInputs.serviceName}" created successfully`));
94
+ } catch (error) {
95
+ throw new Error(`Non-interactive service creation failed: ${error.message}`);
96
+ }
97
+ }
98
+
99
+ /**
100
+ * Validate an existing service configuration
101
+ */
102
+ async validateService(servicePath) {
103
+ return await this.validationHandler.validateService(servicePath);
104
+ }
105
+
106
+ /**
107
+ * Run comprehensive service diagnostics (delegated to ValidationHandler)
108
+ */
109
+ async diagnoseServiceBasic(servicePath, options = {}) {
110
+ return await this.validationHandler.diagnoseService(servicePath);
111
+ }
112
+
113
+ /**
114
+ * Legacy validateService implementation for compatibility
115
+ */
116
+ async _legacyValidateService(servicePath) {
117
+ try {
118
+ const issues = [];
119
+
120
+ // Check for required files
121
+ const requiredFiles = ['package.json', 'src/config/domains.js', 'src/worker/index.js', 'wrangler.toml'];
122
+ for (const file of requiredFiles) {
123
+ const filePath = path.join(servicePath, file);
124
+ try {
125
+ await fs.access(filePath);
126
+ } catch {
127
+ issues.push(`Missing required file: ${file}`);
128
+ }
129
+ }
130
+
131
+ // Validate package.json
132
+ try {
133
+ const packageJson = JSON.parse(await fs.readFile(path.join(servicePath, 'package.json'), 'utf8'));
134
+ if (!packageJson.name || !packageJson.version) {
135
+ issues.push('Invalid package.json: missing name or version');
136
+ }
137
+ } catch {
138
+ issues.push('Invalid package.json format');
139
+ }
140
+
141
+ // Validate domain configuration
142
+ try {
143
+ const domainConfig = await fs.readFile(path.join(servicePath, 'src/config/domains.js'), 'utf8');
144
+ if (!domainConfig.includes('createDomainConfigSchema')) {
145
+ issues.push('Domain configuration missing Clodo Framework integration');
146
+ }
147
+ } catch {
148
+ issues.push('Cannot read domain configuration');
149
+ }
150
+ return {
151
+ valid: issues.length === 0,
152
+ issues
153
+ };
154
+ } catch (error) {
155
+ throw new Error(`Service validation failed: ${error.message}`);
156
+ }
157
+ }
158
+
159
+ /**
160
+ * Display generation results to user
161
+ */
162
+ displayResults(generationResult) {
163
+ console.log(chalk.green('\n✅ Service Generation Complete!'));
164
+ if (generationResult.serviceManifest) {
165
+ // New GenerationEngine format
166
+ console.log(chalk.white(`Service: ${generationResult.serviceName}`));
167
+ console.log(chalk.white(`Path: ${generationResult.servicePath}`));
168
+ console.log(chalk.white(`Files Generated: ${generationResult.fileCount}`));
169
+ console.log(chalk.cyan('\n📁 Generated Files:'));
170
+ generationResult.generatedFiles.forEach(file => {
171
+ console.log(chalk.white(` ✓ ${path.relative(process.cwd(), file)}`));
172
+ });
173
+ console.log(chalk.cyan('\n📋 Service Manifest:'));
174
+ console.log(chalk.white(` Location: clodo-service-manifest.json`));
175
+ } else {
176
+ // Legacy format (for backward compatibility)
177
+ console.log(chalk.white(`Service: ${generationResult.serviceName}`));
178
+ console.log(chalk.white(`Type: ${generationResult.serviceType}`));
179
+ console.log(chalk.white(`Domain: ${generationResult.domainName}`));
180
+ console.log(chalk.white(`Environment: ${generationResult.environment}`));
181
+ console.log(chalk.cyan('\n📁 Generated Files:'));
182
+ generationResult.generatedFiles.forEach(file => {
183
+ console.log(chalk.white(` ✓ ${file}`));
184
+ });
185
+ console.log(chalk.cyan('\n🔧 Configured Features:'));
186
+ generationResult.features.forEach(feature => {
187
+ console.log(chalk.white(` ✓ ${feature}`));
188
+ });
189
+ if (generationResult.serviceManifest) {
190
+ console.log(chalk.cyan('\n📋 Service Manifest:'));
191
+ console.log(chalk.white(` Location: ${generationResult.serviceManifest}`));
192
+ }
193
+ }
194
+ }
195
+
196
+ /**
197
+ * Auto-detect service path from current working directory
198
+ */
199
+ async detectServicePath() {
200
+ try {
201
+ // Check if current directory is a service
202
+ const currentDir = process.cwd();
203
+ if (await this.isServiceDirectory(currentDir)) {
204
+ return currentDir;
205
+ }
206
+
207
+ // Check parent directories
208
+ let checkDir = path.dirname(currentDir);
209
+ while (checkDir !== path.dirname(checkDir)) {
210
+ // Stop at root
211
+ if (await this.isServiceDirectory(checkDir)) {
212
+ return checkDir;
213
+ }
214
+ checkDir = path.dirname(checkDir);
215
+ }
216
+ return null;
217
+ } catch (error) {
218
+ return null;
219
+ }
220
+ }
221
+
222
+ /**
223
+ * Check if a directory is a Clodo service
224
+ */
225
+ async isServiceDirectory(dirPath) {
226
+ try {
227
+ const requiredFiles = ['package.json', 'src/config/domains.js', 'wrangler.toml'];
228
+ for (const file of requiredFiles) {
229
+ await fs.access(path.join(dirPath, file));
230
+ }
231
+ return true;
232
+ } catch {
233
+ return false;
234
+ }
235
+ }
236
+
237
+ /**
238
+ * Run interactive service update
239
+ */
240
+ async runInteractiveUpdate(servicePath) {
241
+ console.log(chalk.cyan('🔄 Interactive Service Update'));
242
+ console.log(chalk.white(`Updating service at: ${servicePath}\n`));
243
+
244
+ // Load current service configuration
245
+ const currentConfig = await this.loadServiceConfiguration(servicePath);
246
+ console.log(chalk.cyan('Current Configuration:'));
247
+ console.log(chalk.white(` Service: ${currentConfig.serviceName}`));
248
+ console.log(chalk.white(` Type: ${currentConfig.serviceType}`));
249
+ console.log(chalk.white(` Domain: ${currentConfig.domainName}`));
250
+ console.log(chalk.white(` Environment: ${currentConfig.environment}\n`));
251
+
252
+ // Interactive update menu
253
+ const updateOptions = {
254
+ 1: {
255
+ name: 'Domain Configuration',
256
+ action: () => this.updateDomainConfig(servicePath, currentConfig)
257
+ },
258
+ 2: {
259
+ name: 'Cloudflare Settings',
260
+ action: () => this.updateCloudflareConfig(servicePath, currentConfig)
261
+ },
262
+ 3: {
263
+ name: 'Environment Settings',
264
+ action: () => this.updateEnvironmentConfig(servicePath, currentConfig)
265
+ },
266
+ 4: {
267
+ name: 'Feature Flags',
268
+ action: () => this.updateFeatureFlags(servicePath, currentConfig)
269
+ },
270
+ 5: {
271
+ name: 'Regenerate All Configs',
272
+ action: () => this.regenerateAllConfigs(servicePath, currentConfig)
273
+ },
274
+ 6: {
275
+ name: 'Fix Configuration Errors',
276
+ action: () => this.fixConfigurationErrors(servicePath)
277
+ }
278
+ };
279
+ for (;;) {
280
+ console.log(chalk.cyan('What would you like to update?'));
281
+ Object.entries(updateOptions).forEach(([key, option]) => {
282
+ console.log(chalk.white(` ${key}. ${option.name}`));
283
+ });
284
+ console.log(chalk.white(' 0. Exit update mode\n'));
285
+ const choice = await this.promptUser('Enter your choice (0-6): ');
286
+ if (choice === '0') {
287
+ break;
288
+ }
289
+ const option = updateOptions[choice];
290
+ if (option) {
291
+ try {
292
+ await option.action();
293
+ console.log(chalk.green(`✓ ${option.name} updated successfully`));
294
+ } catch (error) {
295
+ this.errorTracker.captureError(error, {
296
+ action: option.name,
297
+ servicePath
298
+ });
299
+ console.log(chalk.red(`✗ Failed to update ${option.name}: ${error.message}`));
300
+ }
301
+ } else {
302
+ console.log(chalk.red('Invalid choice. Please select 0-6.'));
303
+ }
304
+ }
305
+ }
306
+
307
+ /**
308
+ * Run non-interactive service update
309
+ */
310
+ async runNonInteractiveUpdate(servicePath, options) {
311
+ console.log(chalk.cyan('🔄 Non-Interactive Service Update'));
312
+ const currentConfig = await this.loadServiceConfiguration(servicePath);
313
+ let hasChanges = false;
314
+ try {
315
+ // Update domain if specified
316
+ if (options.domainName) {
317
+ await this.updateDomainConfig(servicePath, currentConfig, {
318
+ domainName: options.domainName
319
+ });
320
+ hasChanges = true;
321
+ }
322
+
323
+ // Update Cloudflare settings
324
+ if (options.cloudflareToken || options.cloudflareAccountId || options.cloudflareZoneId) {
325
+ const cfUpdates = {};
326
+ if (options.cloudflareToken) cfUpdates.token = options.cloudflareToken;
327
+ if (options.cloudflareAccountId) cfUpdates.accountId = options.cloudflareAccountId;
328
+ if (options.cloudflareZoneId) cfUpdates.zoneId = options.cloudflareZoneId;
329
+ await this.updateCloudflareConfig(servicePath, currentConfig, cfUpdates);
330
+ hasChanges = true;
331
+ }
332
+
333
+ // Update environment
334
+ if (options.environment) {
335
+ await this.updateEnvironmentConfig(servicePath, currentConfig, {
336
+ environment: options.environment
337
+ });
338
+ hasChanges = true;
339
+ }
340
+
341
+ // Update features
342
+ if (options.addFeature || options.removeFeature) {
343
+ const featureUpdates = {};
344
+ if (options.addFeature) featureUpdates.add = options.addFeature;
345
+ if (options.removeFeature) featureUpdates.remove = options.removeFeature;
346
+ await this.updateFeatureFlags(servicePath, currentConfig, featureUpdates);
347
+ hasChanges = true;
348
+ }
349
+
350
+ // Regenerate configs if requested
351
+ if (options.regenerateConfigs) {
352
+ await this.regenerateAllConfigs(servicePath, currentConfig);
353
+ hasChanges = true;
354
+ }
355
+
356
+ // Fix errors if requested
357
+ if (options.fixErrors) {
358
+ await this.fixConfigurationErrors(servicePath);
359
+ hasChanges = true;
360
+ }
361
+ if (!hasChanges) {
362
+ console.log(chalk.yellow('No update options specified. Use --help to see available options.'));
363
+ }
364
+ } catch (error) {
365
+ this.errorTracker.captureError(error, {
366
+ options,
367
+ servicePath
368
+ });
369
+ throw error;
370
+ }
371
+ }
372
+
373
+ /**
374
+ * Load current service configuration
375
+ */
376
+ async loadServiceConfiguration(servicePath) {
377
+ try {
378
+ // Load package.json
379
+ const packageJson = JSON.parse(await fs.readFile(path.join(servicePath, 'package.json'), 'utf8'));
380
+
381
+ // Load domain configuration
382
+ const domainConfig = await fs.readFile(path.join(servicePath, 'src/config/domains.js'), 'utf8');
383
+
384
+ // Extract configuration from domain config (simplified parsing)
385
+ const config = {
386
+ serviceName: packageJson.name,
387
+ serviceType: this.extractServiceTypeFromConfig(domainConfig),
388
+ domainName: this.extractDomainFromConfig(domainConfig),
389
+ environment: this.extractEnvironmentFromConfig(domainConfig),
390
+ cloudflareAccountId: this.extractCloudflareAccountId(domainConfig),
391
+ cloudflareZoneId: this.extractCloudflareZoneId(domainConfig),
392
+ features: this.extractFeaturesFromConfig(domainConfig)
393
+ };
394
+ return config;
395
+ } catch (error) {
396
+ throw new Error(`Failed to load service configuration: ${error.message}`);
397
+ }
398
+ }
399
+
400
+ /**
401
+ * Update domain configuration using ConfigMutator
402
+ */
403
+ async updateDomainConfig(servicePath, currentConfig, updates = null) {
404
+ if (!updates && this.interactive) {
405
+ // Interactive mode - use confirmation handler
406
+ const newDomain = await this.confirmationHandler.promptHandler.prompt(`Current domain: ${currentConfig.domainName}\nNew domain name: `);
407
+ if (!newDomain || newDomain === currentConfig.domainName) {
408
+ console.log(chalk.yellow('Domain unchanged'));
409
+ return;
410
+ }
411
+ updates = {
412
+ domainName: newDomain
413
+ };
414
+ }
415
+ return await this.configMutator.updateDomainConfig(servicePath, currentConfig, updates);
416
+ }
417
+
418
+ /**
419
+ * Update Cloudflare configuration using ConfigMutator
420
+ */
421
+ async updateCloudflareConfig(servicePath, currentConfig, updates = null) {
422
+ return await this.configMutator.updateCloudflareConfig(servicePath, currentConfig, updates);
423
+ }
424
+
425
+ /**
426
+ * Update environment configuration using ConfigMutator
427
+ */
428
+ async updateEnvironmentConfig(servicePath, currentConfig, updates = null) {
429
+ return await this.configMutator.updateEnvironmentConfig(servicePath, currentConfig, updates);
430
+ }
431
+
432
+ /**
433
+ * Update feature flags using ConfigMutator
434
+ */
435
+ async updateFeatureFlags(servicePath, currentConfig, updates = null) {
436
+ return await this.configMutator.updateFeatureConfig(servicePath, currentConfig, updates);
437
+ }
438
+
439
+ /**
440
+ * Regenerate all configuration files
441
+ */
442
+ async regenerateAllConfigs(servicePath, currentConfig) {
443
+ console.log(chalk.cyan('Regenerating all configuration files...'));
444
+
445
+ // This would call the generation engine to recreate all configs
446
+ // For now, just mark as needing implementation
447
+ console.log(chalk.yellow('⚠️ Config regeneration not yet implemented'));
448
+ }
449
+
450
+ /**
451
+ * Fix common configuration errors
452
+ */
453
+ async fixConfigurationErrors(servicePath) {
454
+ console.log(chalk.cyan('Attempting to fix configuration errors...'));
455
+ const issues = await this.validateService(servicePath);
456
+ if (issues.valid) {
457
+ console.log(chalk.green('No issues found to fix'));
458
+ return;
459
+ }
460
+
461
+ // Attempt to fix common issues
462
+ for (const issue of issues.issues) {
463
+ try {
464
+ if (issue.includes('Missing required file')) {
465
+ console.log(chalk.yellow(`Cannot auto-fix missing file: ${issue}`));
466
+ } else if (issue.includes('Invalid package.json')) {
467
+ console.log(chalk.yellow(`Cannot auto-fix package.json: ${issue}`));
468
+ } else {
469
+ console.log(chalk.yellow(`Unknown issue, cannot auto-fix: ${issue}`));
470
+ }
471
+ } catch (error) {
472
+ console.log(chalk.red(`Failed to fix issue: ${error.message}`));
473
+ }
474
+ }
475
+ }
476
+
477
+ /**
478
+ * Diagnose service issues
479
+ */
480
+ async diagnoseService(servicePath, options = {}) {
481
+ console.log(chalk.cyan('🔍 Running comprehensive service diagnosis...'));
482
+ const diagnosis = {
483
+ serviceName: null,
484
+ errors: [],
485
+ warnings: [],
486
+ recommendations: []
487
+ };
488
+ try {
489
+ // Load basic configuration
490
+ const config = await this.loadServiceConfiguration(servicePath);
491
+ diagnosis.serviceName = config.serviceName;
492
+
493
+ // Check file structure
494
+ const requiredFiles = ['package.json', 'src/config/domains.js', 'src/worker/index.js', 'wrangler.toml'];
495
+ for (const file of requiredFiles) {
496
+ try {
497
+ await fs.access(path.join(servicePath, file));
498
+ } catch {
499
+ diagnosis.errors.push({
500
+ message: `Missing required file: ${file}`,
501
+ location: servicePath,
502
+ suggestion: `Run 'clodo-service update --regenerate-configs' to recreate missing files`
503
+ });
504
+ }
505
+ }
506
+
507
+ // Validate package.json
508
+ try {
509
+ const packageJson = JSON.parse(await fs.readFile(path.join(servicePath, 'package.json'), 'utf8'));
510
+ if (!packageJson.name) {
511
+ diagnosis.errors.push({
512
+ message: 'package.json missing name field',
513
+ location: 'package.json',
514
+ suggestion: 'Add a name field to package.json'
515
+ });
516
+ }
517
+ } catch (error) {
518
+ diagnosis.errors.push({
519
+ message: `Invalid package.json: ${error.message}`,
520
+ location: 'package.json',
521
+ suggestion: 'Fix JSON syntax in package.json'
522
+ });
523
+ }
524
+
525
+ // Check domain configuration
526
+ try {
527
+ const domainConfig = await fs.readFile(path.join(servicePath, 'src/config/domains.js'), 'utf8');
528
+ if (!domainConfig.includes('createDomainConfigSchema')) {
529
+ diagnosis.warnings.push({
530
+ message: 'Domain configuration may not be using Clodo Framework schema',
531
+ location: 'src/config/domains.js',
532
+ suggestion: 'Ensure domain config uses createDomainConfigSchema from @tamyla/clodo-framework'
533
+ });
534
+ }
535
+ } catch (error) {
536
+ diagnosis.errors.push({
537
+ message: 'Cannot read domain configuration',
538
+ location: 'src/config/domains.js',
539
+ suggestion: 'Check file permissions and syntax'
540
+ });
541
+ }
542
+
543
+ // Deep scan if requested
544
+ if (options.deepScan) {
545
+ // Check for common issues
546
+ diagnosis.recommendations.push('Consider running tests to validate service functionality');
547
+ diagnosis.recommendations.push('Check Cloudflare authentication if deployment fails');
548
+ diagnosis.recommendations.push('Verify all dependencies are installed with npm install');
549
+ }
550
+ } catch (error) {
551
+ diagnosis.errors.push({
552
+ message: `Diagnosis failed: ${error.message}`,
553
+ location: 'general',
554
+ suggestion: 'Check service directory structure and permissions'
555
+ });
556
+ }
557
+ return diagnosis;
558
+ }
559
+
560
+ /**
561
+ * Export diagnostic report
562
+ */
563
+ async exportDiagnosticReport(diagnosis, filePath) {
564
+ const report = {
565
+ timestamp: new Date().toISOString(),
566
+ serviceName: diagnosis.serviceName,
567
+ summary: {
568
+ errors: diagnosis.errors.length,
569
+ warnings: diagnosis.warnings.length,
570
+ recommendations: diagnosis.recommendations.length
571
+ },
572
+ errors: diagnosis.errors,
573
+ warnings: diagnosis.warnings,
574
+ recommendations: diagnosis.recommendations
575
+ };
576
+ await fs.writeFile(filePath, JSON.stringify(report, null, 2), 'utf8');
577
+ }
578
+
579
+ /**
580
+ * Generate service using legacy ServiceCreator (placeholder for GenerationEngine)
581
+ */
582
+ async generateWithLegacyCreator({
583
+ coreInputs,
584
+ confirmedValues,
585
+ outputPath,
586
+ templatePath
587
+ }) {
588
+ console.log(chalk.gray('Using legacy ServiceCreator for generation...\n'));
589
+
590
+ // This would normally use the GenerationEngine, but for now we'll create a basic result
591
+ return {
592
+ serviceName: coreInputs.serviceName,
593
+ serviceType: coreInputs.serviceType,
594
+ domainName: coreInputs.domainName,
595
+ environment: coreInputs.environment,
596
+ generatedFiles: ['package.json', 'src/config/domains.js', 'src/worker/index.js', 'wrangler.toml', 'README.md'],
597
+ features: Object.keys(confirmedValues.features || {}),
598
+ serviceManifest: null // TODO: Generate service manifest
599
+ };
600
+ }
601
+
602
+ /**
603
+ * Prompt user for input using shared PromptHandler
604
+ */
605
+ async promptUser(question) {
606
+ if (!this.interactive) {
607
+ return '';
608
+ }
609
+ return await this.confirmationHandler.promptHandler.prompt(question);
610
+ }
611
+
612
+ // Helper methods for extracting config values (simplified implementations)
613
+ extractServiceTypeFromConfig(config) {
614
+ return 'generic';
615
+ }
616
+ extractDomainFromConfig(config) {
617
+ return 'unknown';
618
+ }
619
+ extractEnvironmentFromConfig(config) {
620
+ return 'development';
621
+ }
622
+ extractCloudflareAccountId(config) {
623
+ return null;
624
+ }
625
+ extractCloudflareZoneId(config) {
626
+ return null;
627
+ }
628
+ extractFeaturesFromConfig(config) {
629
+ return [];
630
+ }
631
+
632
+ /**
633
+ * Escape special regex characters for safe replacement
634
+ */
635
+ escapeRegExp(string) {
636
+ return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
637
+ }
638
+ }