@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
package/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ ## [3.1.22](https://github.com/tamylaa/clodo-framework/compare/v3.1.21...v3.1.22) (2025-11-05)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * clarify bin/ is private CLI implementation, not public API ([a092d30](https://github.com/tamylaa/clodo-framework/commit/a092d30c9c9c72f0bcb9d6b132175b4a6d6ce0bf))
7
+ * Separate clodo-enterprise: remove enterprise code/docs, fix imports, update README ([58aabff](https://github.com/tamylaa/clodo-framework/commit/58aabff0b0fa193cd2acf37027e43a872fccd8f2))
8
+ * wire helpers to shared infra and fix CloudflareAPI import casing ([7d0b27f](https://github.com/tamylaa/clodo-framework/commit/7d0b27f8dbd0a82f01d52a4d00324ab72507ab30))
9
+
1
10
  ## [3.1.21](https://github.com/tamylaa/clodo-framework/compare/v3.1.20...v3.1.21) (2025-10-28)
2
11
 
3
12
 
package/README.md CHANGED
@@ -8,6 +8,59 @@ A comprehensive framework for building enterprise-grade software architecture on
8
8
 
9
9
  Just like Clodo bricks snap together to build anything you can imagine, this framework provides the base components that your services snap into. Focus on your business logic while the framework handles the infrastructure, configuration, and deployment patterns.
10
10
 
11
+ ## Two Ways to Use Clodo Framework
12
+
13
+ ### šŸ“¦ As a Library (Public API)
14
+
15
+ Import framework modules into your project for programmatic use:
16
+
17
+ ```javascript
18
+ // Import core services
19
+ import { GenericDataService } from '@tamyla/clodo-framework/services';
20
+ import { EnhancedRouter } from '@tamyla/clodo-framework/routing';
21
+ import { CloudflareAPI } from '@tamyla/clodo-framework/utils/cloudflare';
22
+ import { DeploymentOrchestrator } from '@tamyla/clodo-framework/deployment';
23
+
24
+ // Use framework utilities
25
+ const api = new CloudflareAPI(token);
26
+ const zones = await api.listZones();
27
+ ```
28
+
29
+ **All public exports are defined in `package.json`** - use only these documented paths.
30
+
31
+ ### šŸ”§ As CLI Tools (Commands)
32
+
33
+ Run framework commands in your terminal:
34
+
35
+ ```bash
36
+ # Deploy your service
37
+ clodo-service deploy
38
+
39
+ # Create a new service
40
+ clodo-create-service my-service
41
+
42
+ # Security auditing
43
+ clodo-security audit
44
+ ```
45
+
46
+ **CLI tools are for terminal use only** - they use interactive prompts, colored output, and are not meant for programmatic import.
47
+
48
+ ### āš ļø Important: Don't Import from `dist/bin/`
49
+
50
+ The `bin/` directory contains CLI implementation details and should **never** be imported directly:
51
+
52
+ ```javascript
53
+ // āŒ WRONG - Don't do this
54
+ import { healthCheckWithBackoff } from '@tamyla/clodo-framework/dist/bin/shared/monitoring/health-checker.js';
55
+ import { deploymentUI } from '@tamyla/clodo-framework/dist/bin/commands/helpers/deployment-ui.js';
56
+
57
+ // āœ… CORRECT - Use public API
58
+ import { DeploymentOrchestrator } from '@tamyla/clodo-framework/deployment';
59
+ import { CloudflareAPI } from '@tamyla/clodo-framework/utils/cloudflare';
60
+ ```
61
+
62
+ If you need functionality that's currently only in `bin/`, please open an issue - we'll consider adding it to the public API.
63
+
11
64
  ## Project Structure
12
65
 
13
66
  The project is organized for maximum clarity and maintainability:
@@ -18,25 +18,54 @@
18
18
  import { Command } from 'commander';
19
19
  import chalk from 'chalk';
20
20
 
21
- // Import command registration functions
22
- import { registerCreateCommand } from './commands/create.js';
23
- import { registerDeployCommand } from './commands/deploy.js';
24
- import { registerValidateCommand } from './commands/validate.js';
25
- import { registerUpdateCommand } from './commands/update.js';
26
- import { registerDiagnoseCommand } from './commands/diagnose.js';
27
- import { registerAssessCommand } from './commands/assess.js';
28
-
29
21
  // Create program instance
30
22
  const program = new Command();
31
23
  program.name('clodo-service').description('Unified conversational CLI for Clodo Framework service lifecycle management').version('1.0.0');
32
24
 
33
- // Register all command modules
34
- registerCreateCommand(program);
35
- registerDeployCommand(program);
36
- registerValidateCommand(program);
37
- registerUpdateCommand(program);
38
- registerDiagnoseCommand(program);
39
- registerAssessCommand(program);
25
+ // Dynamically load available command modules
26
+ // This makes the CLI resilient if some commands are excluded from the package
27
+ async function registerAvailableCommands() {
28
+ const commands = [{
29
+ name: 'create',
30
+ path: './commands/create.js',
31
+ register: 'registerCreateCommand'
32
+ }, {
33
+ name: 'deploy',
34
+ path: './commands/deploy.js',
35
+ register: 'registerDeployCommand'
36
+ }, {
37
+ name: 'validate',
38
+ path: './commands/validate.js',
39
+ register: 'registerValidateCommand'
40
+ }, {
41
+ name: 'update',
42
+ path: './commands/update.js',
43
+ register: 'registerUpdateCommand'
44
+ }, {
45
+ name: 'diagnose',
46
+ path: './commands/diagnose.js',
47
+ register: 'registerDiagnoseCommand'
48
+ }, {
49
+ name: 'assess',
50
+ path: './commands/assess.js',
51
+ register: 'registerAssessCommand'
52
+ }, {
53
+ name: 'init-config',
54
+ path: './commands/init-config.js',
55
+ register: 'registerInitConfigCommand'
56
+ }];
57
+ for (const cmd of commands) {
58
+ try {
59
+ const module = await import(cmd.path);
60
+ if (module[cmd.register]) {
61
+ module[cmd.register](program);
62
+ }
63
+ } catch (error) {
64
+ // Command module not available in this package - skip silently
65
+ // This allows for minimal CLI distributions
66
+ }
67
+ }
68
+ }
40
69
 
41
70
  // List available service types
42
71
  program.command('list-types').description('List available service types and their features').action(() => {
@@ -58,5 +87,8 @@ program.command('list-types').description('List available service types and thei
58
87
  });
59
88
  });
60
89
 
90
+ // Register available commands dynamically
91
+ await registerAvailableCommands();
92
+
61
93
  // Parse command line arguments
62
94
  program.parse();
@@ -8,21 +8,29 @@
8
8
  * - Gathers credentials smartly: env vars → flags → interactive collection with auto-fetch
9
9
  * - Validates token and fetches account ID & zone ID from Cloudflare
10
10
  * - REFACTORED (Task 3.2): Integrates with MultiDomainOrchestrator for full deployment orchestration
11
+ * - REFACTORED (UX): Modularized with helper functions for better maintainability
11
12
  */
12
13
 
13
14
  import chalk from 'chalk';
14
- import { resolve } from 'path';
15
+ import { resolve, join } from 'path';
16
+ import { existsSync } from 'fs';
15
17
  import { ManifestLoader } from '../shared/config/manifest-loader.js';
16
18
  import { CloudflareServiceValidator } from '../shared/config/cloudflare-service-validator.js';
17
19
  import { DeploymentCredentialCollector } from '../shared/deployment/credential-collector.js';
18
20
  import { StandardOptions } from '../shared/utils/cli-options.js';
19
21
  import { ConfigLoader } from '../shared/utils/config-loader.js';
20
22
  import { DomainRouter } from '../shared/routing/domain-router.js';
21
- import { MultiDomainOrchestrator } from "../../orchestration/multi-domain-orchestrator.js";
23
+ import { MultiDomainOrchestrator } from '../../orchestration/multi-domain-orchestrator.js';
24
+
25
+ // Import modular helpers
26
+ import { detectExistingResources, displayDeploymentPlan } from './helpers/resource-detection.js';
27
+ import { confirmDeployment, displayDeploymentResults, displayNextSteps } from './helpers/deployment-ui.js';
28
+ import { runPostDeploymentVerification } from './helpers/deployment-verification.js';
29
+ import { handleDeploymentError } from './helpers/error-recovery.js';
22
30
  export function registerDeployCommand(program) {
23
31
  const command = program.command('deploy').description('Deploy a Clodo service with smart credential handling and domain selection')
24
32
  // Cloudflare-specific options
25
- .option('--token <token>', 'Cloudflare API token').option('--account-id <id>', 'Cloudflare account ID').option('--zone-id <id>', 'Cloudflare zone ID').option('--domain <domain>', 'Specific domain to deploy to (otherwise prompted if multiple exist)').option('--environment <env>', 'Target environment (development, staging, production)', 'production').option('--all-domains', 'Deploy to all configured domains (ignores --domain flag)').option('--dry-run', 'Simulate deployment without making changes').option('--service-path <path>', 'Path to service directory', '.');
33
+ .option('--token <token>', 'Cloudflare API token').option('--account-id <id>', 'Cloudflare account ID').option('--zone-id <id>', 'Cloudflare zone ID').option('--domain <domain>', 'Specific domain to deploy to (otherwise prompted if multiple exist)').option('--environment <env>', 'Target environment (development, staging, production)', 'production').option('--development', 'Deploy to development environment (shorthand for --environment development)').option('--staging', 'Deploy to staging environment (shorthand for --environment staging)').option('--production', 'Deploy to production environment (shorthand for --environment production)').option('--all-domains', 'Deploy to all configured domains (ignores --domain flag)').option('--dry-run', 'Simulate deployment without making changes').option('-y, --yes', 'Skip confirmation prompts (for CI/CD)').option('--service-path <path>', 'Path to service directory', '.');
26
34
 
27
35
  // Add standard options (--verbose, --quiet, --json, --no-color, --config-file)
28
36
  StandardOptions.define(command).action(async options => {
@@ -34,6 +42,15 @@ export function registerDeployCommand(program) {
34
42
  json: options.json
35
43
  });
36
44
 
45
+ // Handle shorthand environment flags
46
+ if (options.development) {
47
+ options.environment = 'development';
48
+ } else if (options.staging) {
49
+ options.environment = 'staging';
50
+ } else if (options.production) {
51
+ options.environment = 'production';
52
+ }
53
+
37
54
  // Load config from file if specified
38
55
  let configFileData = {};
39
56
  if (options.configFile) {
@@ -68,7 +85,7 @@ export function registerDeployCommand(program) {
68
85
  CloudflareServiceValidator.printValidationReport(serviceConfig.validationResult.validation);
69
86
  }
70
87
  ManifestLoader.printManifestInfo(serviceConfig.manifest);
71
- output.info(`Configuration loaded from: ${serviceConfig.foundAt}`);
88
+ console.log(chalk.blue(`ā„¹ļø Configuration loaded from: ${serviceConfig.foundAt}`));
72
89
 
73
90
  // Step 2: Smart credential gathering with interactive collection
74
91
  // Uses DeploymentCredentialCollector which:
@@ -121,20 +138,36 @@ export function registerDeployCommand(program) {
121
138
  }).filter(d => d !== null);
122
139
  }
123
140
 
124
- // If no domains in config, try to detect from environment
141
+ // If no domains in manifest but we have a selected zone from credentials, use that
142
+ if (detectedDomains.length === 0 && credentials.zoneName) {
143
+ detectedDomains = [credentials.zoneName];
144
+ if (!options.quiet) {
145
+ console.log(chalk.blue(`ā„¹ļø Using selected Cloudflare domain: ${credentials.zoneName}`));
146
+ }
147
+ }
148
+
149
+ // If still no domains and it's a detected CF service, use default
125
150
  if (detectedDomains.length === 0 && manifest._source === 'cloudflare-service-detected') {
126
151
  // For detected CF services, use default
127
152
  detectedDomains = ['workers.cloudflare.com'];
153
+ if (!options.quiet) {
154
+ console.log(chalk.blue(`ā„¹ļø No custom domains configured, using default: workers.cloudflare.com`));
155
+ }
156
+ } else if (detectedDomains.length > 0 && !options.quiet && !credentials.zoneName) {
157
+ console.log(chalk.blue(`ā„¹ļø Found ${detectedDomains.length} configured domain(s) in manifest`));
128
158
  }
129
159
 
130
160
  // Domain selection: check CLI flag first, then prompt user
131
161
  let selectedDomain = mergedOptions.domain;
162
+ if (selectedDomain && !options.quiet) {
163
+ console.log(chalk.blue(`ā„¹ļø Using domain from --domain flag: ${selectedDomain}`));
164
+ }
132
165
  if (!selectedDomain && detectedDomains.length > 0) {
133
166
  if (detectedDomains.length === 1) {
134
167
  // Only one domain, use it directly
135
168
  selectedDomain = detectedDomains[0];
136
169
  if (!options.quiet) {
137
- console.log(chalk.green(`āœ“ Selected domain: ${selectedDomain}`));
170
+ console.log(chalk.green(`āœ“ Auto-selected only available domain: ${selectedDomain}`));
138
171
  }
139
172
  } else {
140
173
  // Multiple domains available - let user choose
@@ -197,24 +230,58 @@ export function registerDeployCommand(program) {
197
230
  const serviceName = manifest.serviceName || 'unknown-service';
198
231
  const serviceType = manifest.serviceType || 'generic';
199
232
 
200
- // Display deployment plan
201
- console.log(chalk.cyan('\nšŸ“‹ Deployment Plan:'));
202
- console.log(chalk.gray('─'.repeat(60)));
203
- console.log(chalk.white(`Service: ${serviceName}`));
204
- console.log(chalk.white(`Type: ${serviceType}`));
205
- console.log(chalk.white(`Domain: ${selectedDomain}`));
206
- console.log(chalk.white(`Environment: ${mergedOptions.environment || 'production'}`));
207
- console.log(chalk.white(`Account: ${credentials.accountId.substring(0, 8)}...`));
208
- console.log(chalk.white(`Zone: ${credentials.zoneId.substring(0, 8)}...`));
209
- console.log(chalk.white(`Deployment Mode: ${options.dryRun ? 'DRY RUN' : 'LIVE'}`));
210
- console.log(chalk.gray('─'.repeat(60)));
211
- if (options.dryRun) {
212
- console.log(chalk.yellow('\nšŸ” DRY RUN MODE - No changes will be made\n'));
233
+ // Step 5: Detect existing resources and display deployment plan
234
+ const {
235
+ existingWorker,
236
+ existingDatabases,
237
+ resourceDetectionFailed
238
+ } = await detectExistingResources(serviceName, manifest, credentials, output, options.verbose);
239
+ displayDeploymentPlan({
240
+ serviceName,
241
+ serviceType,
242
+ selectedDomain,
243
+ environment: mergedOptions.environment,
244
+ credentials,
245
+ dryRun: options.dryRun,
246
+ existingWorker,
247
+ existingDatabases,
248
+ resourceDetectionFailed,
249
+ manifest
250
+ });
251
+
252
+ // Step 6: Get user confirmation
253
+ const confirmed = await confirmDeployment(options);
254
+ if (!confirmed) {
255
+ process.exit(0);
213
256
  }
214
257
 
215
258
  // Step 5: Initialize MultiDomainOrchestrator for deployment
216
259
  // REFACTORED (Task 3.2): Direct orchestrator integration instead of external deployer
217
260
  console.log(chalk.cyan('\nāš™ļø Initializing orchestration system...\n'));
261
+
262
+ // Determine wrangler config path based on selected domain/zone
263
+ // For multi-customer deployments, use customer-specific config if available
264
+ let wranglerConfigPath;
265
+ const configDir = join(servicePath, 'config');
266
+
267
+ // Map domain to config file (customize this mapping for your setup)
268
+ if (selectedDomain === 'clodo.dev' || credentials.cloudflareSettings?.zoneName === 'clodo.dev') {
269
+ // Use config/wrangler.toml for clodo.dev domain
270
+ const clodoConfigPath = join(configDir, 'wrangler.toml');
271
+ if (existsSync(clodoConfigPath)) {
272
+ wranglerConfigPath = clodoConfigPath;
273
+ console.log(chalk.green(`āœ“ Using clodo.dev config: ${clodoConfigPath}`));
274
+ }
275
+ }
276
+ // Add more domain mappings as needed:
277
+ // else if (selectedDomain === 'customer2.com') {
278
+ // wranglerConfigPath = path.join(configDir, 'customers', 'customer2-wrangler.toml');
279
+ // }
280
+
281
+ // If no specific config found, use default (root wrangler.toml)
282
+ if (!wranglerConfigPath) {
283
+ console.log(chalk.yellow(`ℹ Using default wrangler.toml from service root`));
284
+ }
218
285
  const orchestrator = new MultiDomainOrchestrator({
219
286
  domains: [selectedDomain],
220
287
  environment: mergedOptions.environment || 'production',
@@ -223,8 +290,12 @@ export function registerDeployCommand(program) {
223
290
  parallelDeployments: 1,
224
291
  // Single domain in this flow
225
292
  servicePath: servicePath,
226
- cloudflareToken: credentials.token,
227
- cloudflareAccountId: credentials.accountId,
293
+ serviceName: serviceName,
294
+ // Pass service name for custom domain construction
295
+ wranglerConfigPath: wranglerConfigPath,
296
+ // Pass custom config path if found
297
+ // Use cloudflareSettings object for complete zone-specific configuration
298
+ cloudflareSettings: credentials.cloudflareSettings,
228
299
  enablePersistence: !options.dryRun,
229
300
  rollbackEnabled: !options.dryRun,
230
301
  verbose: options.verbose
@@ -240,7 +311,7 @@ export function registerDeployCommand(program) {
240
311
  process.exit(1);
241
312
  }
242
313
 
243
- // Step 6: Execute deployment via orchestrator
314
+ // Step 7: Execute deployment via orchestrator
244
315
  console.log(chalk.cyan('šŸš€ Starting deployment via orchestrator...\n'));
245
316
  let result;
246
317
  try {
@@ -251,71 +322,32 @@ export function registerDeployCommand(program) {
251
322
  environment: mergedOptions.environment || 'production'
252
323
  });
253
324
  } catch (deployError) {
254
- console.error(chalk.red('\nāŒ Deployment failed during orchestration\n'));
255
- console.error(chalk.yellow(`Error: ${deployError.message}`));
256
-
257
- // Provide helpful error context
258
- if (deployError.message.includes('credentials') || deployError.message.includes('auth')) {
259
- console.error(chalk.yellow('\nšŸ’” Credential Issue:'));
260
- console.error(chalk.white(' Check your API token, account ID, and zone ID'));
261
- console.error(chalk.white(' Visit: https://dash.cloudflare.com/profile/api-tokens'));
262
- }
263
- if (deployError.message.includes('domain') || deployError.message.includes('zone')) {
264
- console.error(chalk.yellow('\nļæ½ Domain Issue:'));
265
- console.error(chalk.white(' Verify domain exists in Cloudflare'));
266
- console.error(chalk.white(' Check API token has zone:read permissions'));
267
- }
268
- if (process.env.DEBUG) {
269
- console.error(chalk.gray('\nFull Stack Trace:'));
270
- console.error(chalk.gray(deployError.stack));
271
- }
272
- process.exit(1);
325
+ await handleDeploymentError(deployError, command, options);
273
326
  }
274
327
 
275
- // Step 7: Display deployment results
276
- console.log(chalk.green('\nāœ… Deployment Completed Successfully!\n'));
277
- console.log(chalk.gray('─'.repeat(60)));
278
-
279
- // Display results from orchestrator
280
- if (result.url) {
281
- console.log(chalk.white(`🌐 Service URL: ${chalk.bold(result.url)}`));
282
- }
283
- console.log(chalk.white(`šŸ“¦ Service: ${serviceName}`));
284
- console.log(chalk.white(`šŸ”§ Type: ${serviceType}`));
285
- console.log(chalk.white(`šŸŒ Domain: ${selectedDomain}`));
286
- console.log(chalk.white(`šŸŒŽ Environment: ${mergedOptions.environment || 'production'}`));
287
- if (result.workerId) {
288
- console.log(chalk.white(`šŸ‘¤ Worker ID: ${result.workerId}`));
289
- }
290
- if (result.deploymentId) {
291
- console.log(chalk.white(`šŸ“‹ Deployment ID: ${result.deploymentId}`));
292
- }
293
- if (result.status) {
294
- const statusColor = result.status.toLowerCase().includes('success') ? chalk.green : chalk.yellow;
295
- console.log(chalk.white(`šŸ“Š Status: ${statusColor(result.status)}`));
296
- }
328
+ // Step 8: Display deployment results
329
+ displayDeploymentResults({
330
+ result,
331
+ serviceName,
332
+ serviceType,
333
+ selectedDomain,
334
+ environment: mergedOptions.environment
335
+ });
297
336
 
298
- // Display audit information if available
299
- if (result.auditLog) {
300
- console.log(chalk.cyan('\nšŸ“‹ Deployment Audit:'));
301
- console.log(chalk.gray(` Started: ${result.auditLog.startTime}`));
302
- console.log(chalk.gray(` Completed: ${result.auditLog.endTime}`));
303
- console.log(chalk.gray(` Duration: ${result.auditLog.duration}ms`));
304
- }
305
- console.log(chalk.gray('─'.repeat(60)));
337
+ // Step 9: Run post-deployment verification and health check
338
+ await runPostDeploymentVerification(serviceName, result, credentials, {
339
+ ...options,
340
+ serviceName,
341
+ customDomain: selectedDomain !== 'workers.cloudflare.com' ? selectedDomain : null
342
+ });
306
343
 
307
- // Display next steps
308
- if (!options.dryRun) {
309
- console.log(chalk.cyan('\nšŸ’” Next Steps:'));
310
- console.log(chalk.white(` • Test deployment: curl ${result.url || `https://${selectedDomain}`}`));
311
- console.log(chalk.white(` • View logs: wrangler tail ${serviceName}`));
312
- console.log(chalk.white(` • Monitor: https://dash.cloudflare.com`));
313
- console.log(chalk.white(` • Check audit logs: See deployment ID above\n`));
314
- } else {
315
- console.log(chalk.cyan('\nšŸ’” Dry Run Complete'));
316
- console.log(chalk.white(` • Review the plan above`));
317
- console.log(chalk.white(` • Remove --dry-run to execute deployment\n`));
318
- }
344
+ // Step 10: Display next steps
345
+ displayNextSteps({
346
+ result,
347
+ selectedDomain,
348
+ serviceName,
349
+ dryRun: options.dryRun
350
+ });
319
351
  if (process.env.DEBUG && result.details) {
320
352
  console.log(chalk.gray('šŸ“‹ Full Result:'));
321
353
  console.log(chalk.gray(JSON.stringify(result, null, 2)));
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Deployment UI Helpers
3
+ * Handles confirmation prompts and next steps display
4
+ */
5
+
6
+ import chalk from 'chalk';
7
+
8
+ /**
9
+ * Prompt user for deployment confirmation
10
+ * @param {Object} options - CLI options
11
+ * @returns {Promise<boolean>} Whether user confirmed
12
+ */
13
+ export async function confirmDeployment(options) {
14
+ // Skip confirmation if: --yes flag, --dry-run mode, or non-interactive terminal
15
+ if (options.dryRun) {
16
+ return true; // Dry run doesn't need confirmation
17
+ }
18
+ if (options.yes) {
19
+ console.log(chalk.gray('\n⚔ Auto-confirming deployment (--yes flag)\n'));
20
+ return true;
21
+ }
22
+ if (!process.stdin.isTTY) {
23
+ console.log(chalk.yellow('\nāš ļø Non-interactive mode: proceeding without confirmation'));
24
+ console.log(chalk.gray('šŸ’” Tip: Use --yes to suppress this warning\n'));
25
+ return true;
26
+ }
27
+
28
+ // Interactive confirmation
29
+ console.log(''); // Blank line for spacing
30
+
31
+ const {
32
+ createPromptModule
33
+ } = await import('inquirer');
34
+ const prompt = createPromptModule();
35
+ const {
36
+ confirmed
37
+ } = await prompt([{
38
+ type: 'confirm',
39
+ name: 'confirmed',
40
+ message: chalk.bold('Proceed with this deployment?'),
41
+ default: false
42
+ }]);
43
+ if (!confirmed) {
44
+ console.log(chalk.yellow('\nāŒ Deployment cancelled by user\n'));
45
+ console.log(chalk.gray('šŸ’” Tip: Use --dry-run to preview changes without deploying'));
46
+ return false;
47
+ }
48
+ console.log(''); // Blank line before starting deployment
49
+ return true;
50
+ }
51
+
52
+ /**
53
+ * Display deployment results summary
54
+ * @param {Object} resultData - Deployment result data
55
+ */
56
+ export function displayDeploymentResults(resultData) {
57
+ const {
58
+ result,
59
+ serviceName,
60
+ serviceType,
61
+ selectedDomain,
62
+ environment
63
+ } = resultData;
64
+ console.log(chalk.green('\nāœ… Deployment Completed Successfully!\n'));
65
+ console.log(chalk.gray('─'.repeat(60)));
66
+
67
+ // Display results from orchestrator
68
+ if (result.url) {
69
+ console.log(chalk.white(`🌐 Service URL: ${chalk.bold(result.url)}`));
70
+ }
71
+ console.log(chalk.white(`šŸ“¦ Service: ${serviceName}`));
72
+ console.log(chalk.white(`šŸ”§ Type: ${serviceType}`));
73
+ console.log(chalk.white(`šŸŒ Domain: ${selectedDomain}`));
74
+ console.log(chalk.white(`šŸŒŽ Environment: ${environment || 'production'}`));
75
+ if (result.workerId) {
76
+ console.log(chalk.white(`šŸ‘¤ Worker ID: ${result.workerId}`));
77
+ }
78
+ if (result.deploymentId) {
79
+ console.log(chalk.white(`šŸ“‹ Deployment ID: ${result.deploymentId}`));
80
+ }
81
+ if (result.status) {
82
+ const statusColor = result.status.toLowerCase().includes('success') ? chalk.green : chalk.yellow;
83
+ console.log(chalk.white(`šŸ“Š Status: ${statusColor(result.status)}`));
84
+ }
85
+
86
+ // Display audit information if available
87
+ if (result.auditLog) {
88
+ console.log(chalk.cyan('\nšŸ“‹ Deployment Audit:'));
89
+ console.log(chalk.gray(` Started: ${result.auditLog.startTime}`));
90
+ console.log(chalk.gray(` Completed: ${result.auditLog.endTime}`));
91
+ console.log(chalk.gray(` Duration: ${result.auditLog.duration}ms`));
92
+ }
93
+ console.log(chalk.gray('─'.repeat(60)));
94
+ }
95
+
96
+ /**
97
+ * Display next steps after deployment
98
+ * @param {Object} stepsData - Next steps data
99
+ */
100
+ export function displayNextSteps(stepsData) {
101
+ const {
102
+ result,
103
+ selectedDomain,
104
+ serviceName,
105
+ dryRun
106
+ } = stepsData;
107
+ if (dryRun) {
108
+ console.log(chalk.cyan('\nšŸ’” Dry Run Complete'));
109
+ console.log(chalk.white(` • Review the plan above`));
110
+ console.log(chalk.white(` • Remove --dry-run to execute deployment\n`));
111
+ return;
112
+ }
113
+ console.log(chalk.cyan('\nšŸ’” Next Steps:\n'));
114
+
115
+ // Show both URLs if worker deployed
116
+ if (result.url) {
117
+ console.log(chalk.white(` 🌐 Your service is live at:`));
118
+ console.log(chalk.green(` ${result.url}`));
119
+
120
+ // Show custom domain if different from workers.dev
121
+ if (selectedDomain !== 'workers.cloudflare.com' && !selectedDomain.includes('workers.dev')) {
122
+ console.log(chalk.white(`\n āš ļø Custom domain requires DNS setup:`));
123
+ console.log(chalk.yellow(` Domain: ${selectedDomain}`));
124
+ console.log(chalk.gray(` Add CNAME record: ${selectedDomain} → workers.dev`));
125
+ console.log(chalk.gray(` Or add route in Cloudflare Dashboard`));
126
+ }
127
+ }
128
+ console.log(chalk.white(`\n šŸ“ Testing:`));
129
+ console.log(chalk.gray(` curl ${result.url || `https://${selectedDomain}`}/health`));
130
+ console.log(chalk.white(`\n šŸ“Š Monitoring:`));
131
+ console.log(chalk.gray(` wrangler tail ${serviceName}`));
132
+ console.log(chalk.gray(` https://dash.cloudflare.com`));
133
+ if (result.deploymentId) {
134
+ console.log(chalk.white(`\n šŸ”„ Rollback (if needed):`));
135
+ console.log(chalk.gray(` clodo-service rollback ${result.deploymentId}`));
136
+ }
137
+ console.log(''); // Blank line at end
138
+ }