@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.
- package/CHANGELOG.md +9 -0
- package/README.md +53 -0
- package/dist/bin/clodo-service.js +47 -15
- package/dist/bin/commands/deploy.js +115 -83
- package/dist/bin/commands/helpers/deployment-ui.js +138 -0
- package/dist/bin/commands/helpers/deployment-verification.js +251 -0
- package/dist/bin/commands/helpers/error-recovery.js +80 -0
- package/dist/bin/commands/helpers/resource-detection.js +113 -0
- package/dist/bin/commands/validate.js +1 -1
- package/dist/bin/security/security-cli.js +1 -1
- package/dist/bin/shared/cache/configuration-cache.js +82 -0
- package/dist/bin/shared/cloudflare/domain-manager.js +1 -1
- package/dist/bin/shared/cloudflare/index.js +1 -1
- package/dist/bin/shared/cloudflare/ops.js +6 -4
- package/dist/bin/shared/config/ConfigurationManager.js +23 -1
- package/dist/bin/shared/config/command-config-manager.js +19 -3
- package/dist/bin/shared/config/index.js +1 -1
- package/dist/bin/shared/deployment/credential-collector.js +30 -7
- package/dist/bin/shared/deployment/index.js +2 -2
- package/dist/bin/shared/deployment/rollback-manager.js +4 -520
- package/dist/bin/shared/deployment/utilities/d1-error-recovery.js +177 -0
- package/dist/bin/shared/deployment/validator.js +40 -10
- package/dist/bin/shared/deployment/workflows/deployment-summary.js +214 -0
- package/dist/bin/shared/deployment/workflows/interactive-confirmation.js +188 -0
- package/dist/bin/shared/deployment/workflows/interactive-database-workflow.js +234 -0
- package/dist/bin/shared/deployment/workflows/interactive-domain-info-gatherer.js +240 -0
- package/dist/bin/shared/deployment/workflows/interactive-secret-workflow.js +228 -0
- package/dist/bin/shared/deployment/workflows/interactive-testing-workflow.js +235 -0
- package/dist/bin/shared/deployment/workflows/interactive-validation.js +218 -0
- package/dist/bin/shared/error-handling/error-classifier.js +46 -0
- package/dist/bin/shared/monitoring/health-checker.js +129 -1
- package/dist/bin/shared/monitoring/memory-manager.js +17 -6
- package/dist/bin/shared/routing/domain-router.js +1 -1
- package/dist/bin/shared/utils/deployment-validator.js +97 -0
- package/dist/bin/shared/utils/formatters.js +10 -0
- package/dist/bin/shared/utils/index.js +13 -1
- package/dist/bin/shared/utils/interactive-prompts.js +34 -18
- package/dist/bin/shared/utils/progress-manager.js +2 -2
- package/dist/bin/shared/utils/progress-spinner.js +53 -0
- package/dist/bin/shared/utils/sensitive-redactor.js +91 -0
- package/dist/bin/shared/validation/ValidationRegistry.js +1 -1
- package/dist/security/index.js +1 -1
- package/dist/security/patterns/insecure-patterns.js +1 -1
- package/dist/utils/constants.js +102 -0
- package/dist/utils/deployment/wrangler-config-manager.js +215 -48
- package/dist/utils/framework-config.js +2 -2
- package/dist/utils/interactive-prompts.js +10 -59
- package/package.json +16 -8
- package/dist/bin/clodo-service-old.js +0 -868
- package/dist/bin/clodo-service-test.js +0 -10
- package/dist/bin/commands/assess.js +0 -91
- package/dist/bin/commands/create.js +0 -77
- package/dist/bin/commands/diagnose.js +0 -83
- package/dist/bin/commands/helpers.js +0 -138
- package/dist/bin/commands/update.js +0 -75
- package/dist/bin/database/deployment-db-manager.js +0 -423
- package/dist/bin/database/enterprise-db-manager.js +0 -457
- package/dist/bin/database/wrangler-d1-manager.js +0 -685
- package/dist/bin/deployment/enterprise-deploy.js +0 -877
- package/dist/bin/deployment/master-deploy.js +0 -1376
- package/dist/bin/deployment/modular-enterprise-deploy.js +0 -466
- package/dist/bin/deployment/modules/DeploymentConfiguration.js +0 -395
- package/dist/bin/deployment/modules/DeploymentOrchestrator.js +0 -492
- package/dist/bin/deployment/modules/EnvironmentManager.js +0 -517
- package/dist/bin/deployment/modules/MonitoringIntegration.js +0 -560
- package/dist/bin/deployment/modules/ValidationManager.js +0 -342
- package/dist/bin/deployment/orchestration/BaseDeploymentOrchestrator.js +0 -426
- package/dist/bin/deployment/orchestration/EnterpriseOrchestrator.js +0 -401
- package/dist/bin/deployment/orchestration/PortfolioOrchestrator.js +0 -273
- package/dist/bin/deployment/orchestration/SingleServiceOrchestrator.js +0 -231
- package/dist/bin/deployment/orchestration/UnifiedDeploymentOrchestrator.js +0 -662
- package/dist/bin/deployment/test-interactive-utils.js +0 -66
- package/dist/bin/portfolio/portfolio-manager.js +0 -487
- package/dist/bin/service-management/create-service.js +0 -122
- package/dist/bin/service-management/init-service.js +0 -79
- package/dist/config/customers.js +0 -623
- package/dist/config/domains.js +0 -186
- package/dist/config/index.js +0 -6
- package/dist/database/database-orchestrator.js +0 -795
- package/dist/database/index.js +0 -4
- package/dist/deployment/index.js +0 -11
- package/dist/deployment/orchestration/BaseDeploymentOrchestrator.js +0 -426
- package/dist/deployment/orchestration/EnterpriseOrchestrator.js +0 -401
- package/dist/deployment/orchestration/PortfolioOrchestrator.js +0 -273
- package/dist/deployment/orchestration/SingleServiceOrchestrator.js +0 -231
- package/dist/deployment/orchestration/UnifiedDeploymentOrchestrator.js +0 -662
- package/dist/deployment/orchestration/index.js +0 -17
- package/dist/deployment/rollback-manager.js +0 -36
- package/dist/deployment/wrangler-deployer.js +0 -640
- package/dist/handlers/GenericRouteHandler.js +0 -532
- package/dist/migration/MigrationAdapters.js +0 -562
- package/dist/modules/ModuleManager.js +0 -668
- package/dist/modules/security.js +0 -96
- package/dist/orchestration/cross-domain-coordinator.js +0 -1083
- package/dist/orchestration/index.js +0 -5
- package/dist/orchestration/modules/DeploymentCoordinator.js +0 -368
- package/dist/orchestration/modules/DomainResolver.js +0 -198
- package/dist/orchestration/modules/StateManager.js +0 -332
- package/dist/orchestration/multi-domain-orchestrator.js +0 -724
- package/dist/routing/EnhancedRouter.js +0 -158
- package/dist/schema/SchemaManager.js +0 -778
- package/dist/service-management/ConfirmationEngine.js +0 -412
- package/dist/service-management/ErrorTracker.js +0 -299
- package/dist/service-management/GenerationEngine.js +0 -447
- package/dist/service-management/InputCollector.js +0 -619
- package/dist/service-management/ServiceCreator.js +0 -265
- package/dist/service-management/ServiceInitializer.js +0 -453
- package/dist/service-management/ServiceOrchestrator.js +0 -633
- package/dist/service-management/generators/BaseGenerator.js +0 -233
- package/dist/service-management/generators/GeneratorRegistry.js +0 -254
- package/dist/service-management/generators/cicd/CiWorkflowGenerator.js +0 -87
- package/dist/service-management/generators/cicd/DeployWorkflowGenerator.js +0 -106
- package/dist/service-management/generators/code/ServiceHandlersGenerator.js +0 -235
- package/dist/service-management/generators/code/ServiceMiddlewareGenerator.js +0 -116
- package/dist/service-management/generators/code/ServiceUtilsGenerator.js +0 -246
- package/dist/service-management/generators/code/WorkerIndexGenerator.js +0 -143
- package/dist/service-management/generators/config/DevelopmentEnvGenerator.js +0 -101
- package/dist/service-management/generators/config/DomainsConfigGenerator.js +0 -175
- package/dist/service-management/generators/config/EnvExampleGenerator.js +0 -178
- package/dist/service-management/generators/config/ProductionEnvGenerator.js +0 -97
- package/dist/service-management/generators/config/StagingEnvGenerator.js +0 -97
- package/dist/service-management/generators/config/WranglerTomlGenerator.js +0 -238
- package/dist/service-management/generators/core/PackageJsonGenerator.js +0 -243
- package/dist/service-management/generators/core/SiteConfigGenerator.js +0 -115
- package/dist/service-management/generators/documentation/ApiDocsGenerator.js +0 -331
- package/dist/service-management/generators/documentation/ConfigurationDocsGenerator.js +0 -294
- package/dist/service-management/generators/documentation/DeploymentDocsGenerator.js +0 -244
- package/dist/service-management/generators/documentation/ReadmeGenerator.js +0 -196
- package/dist/service-management/generators/schemas/ServiceSchemaGenerator.js +0 -190
- package/dist/service-management/generators/scripts/DeployScriptGenerator.js +0 -123
- package/dist/service-management/generators/scripts/HealthCheckScriptGenerator.js +0 -101
- package/dist/service-management/generators/scripts/SetupScriptGenerator.js +0 -88
- package/dist/service-management/generators/service-types/StaticSiteGenerator.js +0 -342
- package/dist/service-management/generators/testing/EslintConfigGenerator.js +0 -85
- package/dist/service-management/generators/testing/IntegrationTestsGenerator.js +0 -237
- package/dist/service-management/generators/testing/JestConfigGenerator.js +0 -72
- package/dist/service-management/generators/testing/UnitTestsGenerator.js +0 -277
- package/dist/service-management/generators/tooling/DockerComposeGenerator.js +0 -71
- package/dist/service-management/generators/tooling/GitignoreGenerator.js +0 -143
- package/dist/service-management/generators/utils/FileWriter.js +0 -179
- package/dist/service-management/generators/utils/PathResolver.js +0 -157
- package/dist/service-management/generators/utils/ServiceManifestGenerator.js +0 -111
- package/dist/service-management/generators/utils/TemplateEngine.js +0 -185
- package/dist/service-management/generators/utils/index.js +0 -18
- package/dist/service-management/handlers/ConfirmationHandler.js +0 -71
- package/dist/service-management/handlers/GenerationHandler.js +0 -80
- package/dist/service-management/handlers/InputHandler.js +0 -59
- package/dist/service-management/handlers/ValidationHandler.js +0 -203
- package/dist/service-management/index.js +0 -14
- package/dist/service-management/routing/DomainRouteMapper.js +0 -311
- package/dist/service-management/routing/RouteGenerator.js +0 -266
- package/dist/service-management/routing/WranglerRoutesBuilder.js +0 -273
- package/dist/service-management/routing/index.js +0 -14
- package/dist/service-management/services/DirectoryStructureService.js +0 -56
- package/dist/service-management/services/GenerationCoordinator.js +0 -208
- package/dist/service-management/services/GeneratorRegistry.js +0 -174
- package/dist/services/GenericDataService.js +0 -501
- package/dist/ui-structures/concepts/second-order-acquisition-strategy.md +0 -286
- package/dist/ui-structures/concepts/service-lifecycle-management.md +0 -150
- package/dist/ui-structures/concepts/service-manifest-guide.md +0 -309
- package/dist/ui-structures/concepts/three-tier-categorization-strategy.md +0 -231
- package/dist/ui-structures/creation/automated-generation-ui.json +0 -246
- package/dist/ui-structures/creation/core-inputs-ui.json +0 -217
- package/dist/ui-structures/creation/smart-confirmable-ui.json +0 -451
- package/dist/ui-structures/reference/absolutely-required-inputs.json +0 -315
- package/dist/ui-structures/reference/service-manifest-template.json +0 -342
- package/dist/version/VersionDetector.js +0 -723
- package/dist/worker/index.js +0 -4
- 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
|
-
//
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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(`ā
|
|
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
|
-
//
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
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
|
-
|
|
227
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
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
|
-
//
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
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
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
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
|
+
}
|