@tamyla/clodo-framework 2.0.19 → 3.0.2

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 (56) hide show
  1. package/CHANGELOG.md +206 -62
  2. package/bin/clodo-service.js +32 -56
  3. package/bin/database/README.md +33 -0
  4. package/bin/database/deployment-db-manager.js +527 -0
  5. package/bin/database/enterprise-db-manager.js +736 -0
  6. package/bin/database/wrangler-d1-manager.js +775 -0
  7. package/bin/shared/cloudflare/domain-discovery.js +636 -0
  8. package/bin/shared/cloudflare/domain-manager.js +952 -0
  9. package/bin/shared/cloudflare/index.js +8 -0
  10. package/bin/shared/cloudflare/ops.js +359 -0
  11. package/bin/shared/config/index.js +1 -1
  12. package/bin/shared/database/connection-manager.js +374 -0
  13. package/bin/shared/database/index.js +7 -0
  14. package/bin/shared/database/orchestrator.js +726 -0
  15. package/bin/shared/deployment/auditor.js +969 -0
  16. package/bin/shared/deployment/index.js +10 -0
  17. package/bin/shared/deployment/rollback-manager.js +570 -0
  18. package/bin/shared/deployment/validator.js +779 -0
  19. package/bin/shared/index.js +32 -0
  20. package/bin/shared/monitoring/health-checker.js +484 -0
  21. package/bin/shared/monitoring/index.js +8 -0
  22. package/bin/shared/monitoring/memory-manager.js +387 -0
  23. package/bin/shared/monitoring/production-monitor.js +391 -0
  24. package/bin/shared/production-tester/api-tester.js +82 -0
  25. package/bin/shared/production-tester/auth-tester.js +132 -0
  26. package/bin/shared/production-tester/core.js +197 -0
  27. package/bin/shared/production-tester/database-tester.js +109 -0
  28. package/bin/shared/production-tester/index.js +77 -0
  29. package/bin/shared/production-tester/load-tester.js +131 -0
  30. package/bin/shared/production-tester/performance-tester.js +103 -0
  31. package/bin/shared/security/api-token-manager.js +312 -0
  32. package/bin/shared/security/index.js +8 -0
  33. package/bin/shared/security/secret-generator.js +937 -0
  34. package/bin/shared/security/secure-token-manager.js +398 -0
  35. package/bin/shared/utils/error-recovery.js +225 -0
  36. package/bin/shared/utils/graceful-shutdown-manager.js +390 -0
  37. package/bin/shared/utils/index.js +9 -0
  38. package/bin/shared/utils/interactive-prompts.js +146 -0
  39. package/bin/shared/utils/interactive-utils.js +530 -0
  40. package/bin/shared/utils/rate-limiter.js +246 -0
  41. package/dist/database/database-orchestrator.js +34 -12
  42. package/dist/deployment/index.js +2 -2
  43. package/dist/orchestration/multi-domain-orchestrator.js +8 -6
  44. package/dist/service-management/GenerationEngine.js +76 -28
  45. package/dist/service-management/ServiceInitializer.js +5 -3
  46. package/dist/shared/cloudflare/domain-manager.js +1 -1
  47. package/dist/shared/cloudflare/ops.js +27 -12
  48. package/dist/shared/config/index.js +1 -1
  49. package/dist/shared/deployment/index.js +2 -2
  50. package/dist/shared/security/secret-generator.js +4 -2
  51. package/dist/shared/utils/error-recovery.js +1 -1
  52. package/dist/shared/utils/graceful-shutdown-manager.js +4 -3
  53. package/dist/utils/deployment/secret-generator.js +19 -6
  54. package/package.json +7 -6
  55. package/bin/shared/config/customer-cli.js +0 -182
  56. package/dist/shared/config/customer-cli.js +0 -175
@@ -20,7 +20,7 @@ export class GracefulShutdownManager {
20
20
  // Import framework config for consistent timing
21
21
  const {
22
22
  frameworkConfig
23
- } = await import('../../../src/utils/framework-config.js');
23
+ } = await import('../../../dist/utils/framework-config.js');
24
24
  const timing = frameworkConfig.getTiming();
25
25
  this.config = {
26
26
  shutdownTimeout: this.options.shutdownTimeout || timing.shutdownTimeout,
@@ -32,8 +32,9 @@ export class GracefulShutdownManager {
32
32
 
33
33
  /**
34
34
  * Register the shutdown manager
35
+ * @param {boolean} silent - Suppress registration message (for interactive modes)
35
36
  */
36
- register() {
37
+ register(silent = false) {
37
38
  if (this.registered) return;
38
39
  this.registered = true;
39
40
 
@@ -50,7 +51,7 @@ export class GracefulShutdownManager {
50
51
  console.error('šŸ’„ Unhandled rejection at:', promise, 'reason:', reason);
51
52
  this.initiateShutdown('unhandledRejection', reason);
52
53
  });
53
- if (this.config.enableLogging) {
54
+ if (this.config.enableLogging && !silent) {
54
55
  console.log('šŸ›‘ Graceful shutdown manager registered');
55
56
  }
56
57
  }
@@ -138,17 +138,25 @@ export class EnhancedSecretManager {
138
138
  * Initialize enhanced secret manager
139
139
  */
140
140
  initializeSecretManager() {
141
- console.log('šŸ” Enhanced Secret Manager v2.0');
142
- console.log('===============================');
143
- console.log(`šŸ“ Secret Root: ${this.secretPaths.root}`);
144
- console.log(`šŸ” Mode: ${this.dryRun ? 'DRY RUN' : 'LIVE OPERATIONS'}`);
145
- console.log(`šŸ“Š Formats: ${Object.keys(this.outputFormats).join(', ')}`);
146
- console.log('');
141
+ // Skip console output and file logging in test/CI environments
142
+ const isTestEnv = process.env.NODE_ENV === 'test' || process.env.CI === 'true';
143
+ if (!isTestEnv) {
144
+ console.log('šŸ” Enhanced Secret Manager v2.0');
145
+ console.log('===============================');
146
+ console.log(`šŸ“ Secret Root: ${this.secretPaths.root}`);
147
+ console.log(`šŸ” Mode: ${this.dryRun ? 'DRY RUN' : 'LIVE OPERATIONS'}`);
148
+ console.log(`šŸ“Š Formats: ${Object.keys(this.outputFormats).join(', ')}`);
149
+ console.log('');
150
+ }
147
151
 
148
152
  // Create directories
149
153
  Object.values(this.secretPaths).forEach(path => {
150
154
  if (!path.endsWith('.log')) {
151
155
  this.ensureDirectory(path);
156
+ } else {
157
+ // For log files, ensure parent directory exists
158
+ const logDir = dirname(path);
159
+ this.ensureDirectory(logDir);
152
160
  }
153
161
  });
154
162
  this.logSecretEvent('MANAGER_INITIALIZED', 'SYSTEM', {
@@ -697,6 +705,11 @@ ${Object.entries(SECRET_CONFIGS).map(([key, config]) => `- **${key}**: ${config.
697
705
  }
698
706
  }
699
707
  logSecretEvent(event, domain, details = {}) {
708
+ // Skip file logging in test/CI environments
709
+ const isTestEnv = process.env.NODE_ENV === 'test' || process.env.CI === 'true';
710
+ if (isTestEnv) {
711
+ return; // Silent in tests - no file I/O or warnings
712
+ }
700
713
  const logEntry = {
701
714
  timestamp: new Date().toISOString(),
702
715
  event,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tamyla/clodo-framework",
3
- "version": "2.0.19",
3
+ "version": "3.0.2",
4
4
  "description": "Reusable framework for Clodo-style software architecture on Cloudflare Workers + D1",
5
5
  "type": "module",
6
6
  "sideEffects": [
@@ -20,7 +20,8 @@
20
20
  "./handlers": "./dist/handlers/GenericRouteHandler.js",
21
21
  "./config": "./dist/config/index.js",
22
22
  "./config/discovery": "./dist/config/discovery/domain-discovery.js",
23
- "./config/customer-loader": "./dist/config/customer-config-loader.js",
23
+ "./config/customers": "./dist/config/customers.js",
24
+ "./utils/config": "./dist/utils/config/unified-config-manager.js",
24
25
  "./worker": "./dist/worker/index.js",
25
26
  "./utils": "./dist/utils/index.js",
26
27
  "./utils/deployment": "./dist/utils/deployment/index.js",
@@ -38,15 +39,13 @@
38
39
  "./service-management": "./dist/service-management/index.js",
39
40
  "./service-management/create": "./dist/service-management/ServiceCreator.js",
40
41
  "./service-management/init": "./dist/service-management/ServiceInitializer.js",
41
- "./config/cli": "./dist/config/CustomerConfigCLI.js",
42
42
  "./modules/security": "./dist/modules/security.js"
43
43
  },
44
44
  "bin": {
45
45
  "clodo-service": "./bin/clodo-service.js",
46
46
  "clodo-create-service": "./bin/service-management/create-service.js",
47
47
  "clodo-init-service": "./bin/service-management/init-service.js",
48
- "clodo-security": "./bin/security/security-cli.js",
49
- "clodo-customer-config": "./bin/shared/config/customer-cli.js"
48
+ "clodo-security": "./bin/security/security-cli.js"
50
49
  },
51
50
  "publishConfig": {
52
51
  "access": "public"
@@ -57,7 +56,8 @@
57
56
  "bin/clodo-service.js",
58
57
  "bin/service-management",
59
58
  "bin/security",
60
- "bin/shared/config",
59
+ "bin/shared",
60
+ "bin/database",
61
61
  "templates",
62
62
  "docs/README.md",
63
63
  "docs/overview.md",
@@ -117,6 +117,7 @@
117
117
  "@iarna/toml": "^2.2.5",
118
118
  "chalk": "^5.3.0",
119
119
  "commander": "^11.0.0",
120
+ "uuid": "^13.0.0",
120
121
  "wrangler": ">=3.0.0"
121
122
  },
122
123
  "devDependencies": {
@@ -1,182 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Customer Configuration Management CLI
5
- * Manages multi-environment, multi-customer configuration structure
6
- * Integrates with Clodo Framework domain and feature flag systems
7
- */
8
-
9
- import { CustomerConfigCLI } from '../../../dist/config/CustomerConfigCLI.js';
10
- import { resolve } from 'path';
11
-
12
- // Parse command line arguments
13
- const argv = process.argv.slice(2);
14
- let configDir = null;
15
- let command = null;
16
- let args = [];
17
-
18
- // Extract --config-dir parameter if present
19
- for (let i = 0; i < argv.length; i++) {
20
- if (argv[i] === '--config-dir' && i + 1 < argv.length) {
21
- configDir = resolve(argv[i + 1]);
22
- i++; // Skip the next argument (the path)
23
- } else if (!command) {
24
- command = argv[i];
25
- } else {
26
- args.push(argv[i]);
27
- }
28
- }
29
-
30
- // Default to current working directory if not specified
31
- if (!configDir) {
32
- configDir = resolve(process.cwd(), 'config');
33
- }
34
-
35
- async function main() {
36
- const cli = new CustomerConfigCLI({ configDir });
37
- await cli.initialize();
38
-
39
- try {
40
- switch (command) {
41
- case 'create-customer':
42
- const [customerName, domain] = args;
43
- const result = await cli.createCustomer(customerName, domain);
44
- if (result.success) {
45
- console.log(`\nšŸŽ‰ Customer ${customerName} configuration created successfully!`);
46
- console.log(`\nšŸ“‹ Customer Details:`);
47
- console.log(` Name: ${result.customer.name}`);
48
- console.log(` Domain: ${result.customer.domain || 'Not specified'}`);
49
- console.log(` Config Path: ${result.customer.configPath}`);
50
- console.log(` Environments: ${result.customer.environments.join(', ')}`);
51
- console.log(`\nšŸ“‹ Next steps:`);
52
- console.log(`1. Review generated configs in: config/customers/${customerName}/`);
53
- console.log(`2. Update domain-specific URLs if needed`);
54
- console.log(`3. Generate production secrets: npm run security:generate-key ${customerName}`);
55
- console.log(`4. Set production secrets: wrangler secret put KEY_NAME --env production`);
56
- } else {
57
- console.error(`āŒ Failed to create customer: ${result.error}`);
58
- process.exit(1);
59
- }
60
- break;
61
-
62
- case 'validate':
63
- const validateResult = await cli.validateConfigurations();
64
- if (validateResult.valid) {
65
- console.log('āœ… All customer configurations are valid');
66
- } else {
67
- console.log('āŒ Configuration validation failed');
68
- validateResult.errors.forEach(error => console.log(` - ${error}`));
69
- process.exit(1);
70
- }
71
- break;
72
-
73
- case 'show':
74
- const [customerNameShow, environment] = args;
75
- const showResult = cli.showConfiguration(customerNameShow, environment);
76
- if (showResult.success) {
77
- console.log(`šŸ” Effective configuration: ${customerNameShow}/${environment}\n`);
78
- if (showResult.config.variables?.base) {
79
- console.log('šŸ“‹ Base variables:');
80
- Object.entries(showResult.config.variables.base).slice(0, 10).forEach(([key, value]) => {
81
- console.log(` ${key}=${value}`);
82
- });
83
- if (Object.keys(showResult.config.variables.base).length > 10) {
84
- console.log(' ...');
85
- }
86
- console.log('');
87
- }
88
- if (showResult.config.variables?.customer) {
89
- console.log(`šŸ“‹ Customer ${environment} variables:`);
90
- Object.entries(showResult.config.variables.customer).slice(0, 15).forEach(([key, value]) => {
91
- console.log(` ${key}=${value}`);
92
- });
93
- if (Object.keys(showResult.config.variables.customer).length > 15) {
94
- console.log(' ...');
95
- }
96
- console.log('');
97
- }
98
- if (showResult.config.features && Object.keys(showResult.config.features).length > 0) {
99
- console.log('🚩 Customer features:');
100
- Object.entries(showResult.config.features).forEach(([feature, enabled]) => {
101
- console.log(` ${feature}: ${enabled ? 'āœ…' : 'āŒ'}`);
102
- });
103
- }
104
- } else {
105
- console.error(`āŒ Failed to show configuration: ${showResult.error}`);
106
- process.exit(1);
107
- }
108
- break;
109
-
110
- case 'deploy-command':
111
- const [customerNameDeploy, environmentDeploy] = args;
112
- const deployResult = cli.getDeployCommand(customerNameDeploy, environmentDeploy);
113
- if (deployResult.success) {
114
- console.log(`šŸ“‹ Deploy command for ${customerNameDeploy}/${environmentDeploy}:`);
115
- console.log(` ${deployResult.command}`);
116
- console.log(`\nšŸ’” Ensure customer config is loaded: ${deployResult.configPath}`);
117
- } else {
118
- console.error(`āŒ Failed to get deploy command: ${deployResult.error}`);
119
- process.exit(1);
120
- }
121
- break;
122
-
123
- case 'list':
124
- const listResult = cli.listCustomers();
125
- if (listResult.success && listResult.customers.length > 0) {
126
- console.log('šŸ“‹ Configured customers:\n');
127
- listResult.customers.forEach(customer => {
128
- console.log(`šŸ¢ ${customer.name}`);
129
- console.log(` Domain: ${customer.customerDomain || customer.domain || 'Not configured'}`);
130
- console.log(` Account ID: ${customer.accountId ? `${customer.accountId.substring(0, 8)}...${customer.accountId.substring(24)}` : 'Not configured'}`);
131
- console.log(` Zone ID: ${customer.zoneId ? `${customer.zoneId.substring(0, 8)}...` : 'Not configured'}`);
132
- if (customer.databaseId) {
133
- console.log(` Database: ${customer.databaseName || 'Unnamed'} (${customer.databaseId.substring(0, 8)}...)`);
134
- }
135
- console.log(` Secrets: ${customer.hasSecrets ? 'āœ… Managed via wrangler secret commands' : 'āŒ Not configured'}`);
136
- console.log(` Environments: ${customer.environments.join(', ')}`);
137
- console.log(` Config Path: config/customers/${customer.name}/`);
138
- console.log('');
139
- });
140
- } else if (listResult.success) {
141
- console.log('šŸ“‹ No customers configured');
142
- console.log('\nšŸ’” Tip: Run "clodo-customer-config create-customer <name>" to create your first customer');
143
- } else {
144
- console.error(`āŒ Failed to list customers: ${listResult.error}`);
145
- process.exit(1);
146
- }
147
- break;
148
-
149
- default:
150
- console.log('Customer Configuration Management Tool\n');
151
- console.log('Usage:');
152
- console.log(' clodo-customer-config [--config-dir <path>] <command> [args]\n');
153
- console.log('Options:');
154
- console.log(' --config-dir <path> - Path to config directory (default: ./config)\n');
155
- console.log('Available commands:');
156
- console.log(' create-customer <name> [domain] - Create new customer config from template');
157
- console.log(' validate - Validate configuration structure');
158
- console.log(' show <customer> <environment> - Show effective configuration');
159
- console.log(' deploy-command <customer> <env> - Get deployment command');
160
- console.log(' list - List all configured customers');
161
- console.log('\nExamples:');
162
- console.log(' clodo-customer-config create-customer acmecorp acmecorp.com');
163
- console.log(' clodo-customer-config validate');
164
- console.log(' clodo-customer-config show acmecorp production');
165
- console.log(' clodo-customer-config list');
166
- console.log(' clodo-customer-config --config-dir /path/to/service/config validate');
167
- console.log('\nIntegration:');
168
- console.log(' This tool integrates with Clodo Framework domain and feature flag systems.');
169
- console.log(' Customer configurations are automatically registered as domains.');
170
- console.log(' When run from a service directory, it uses ./config by default.');
171
- break;
172
- }
173
- } catch (error) {
174
- console.error(`āŒ Error: ${error.message}`);
175
- process.exit(1);
176
- }
177
- }
178
-
179
- main().catch(error => {
180
- console.error(`āŒ Unexpected error: ${error.message}`);
181
- process.exit(1);
182
- });
@@ -1,175 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Customer Configuration Management CLI
5
- * Manages multi-environment, multi-customer configuration structure
6
- * Integrates with Clodo Framework domain and feature flag systems
7
- */
8
- import { CustomerConfigCLI } from '../../../dist/config/CustomerConfigCLI.js';
9
- import { resolve } from 'path';
10
-
11
- // Parse command line arguments
12
- const argv = process.argv.slice(2);
13
- let configDir = null;
14
- let command = null;
15
- let args = [];
16
-
17
- // Extract --config-dir parameter if present
18
- for (let i = 0; i < argv.length; i++) {
19
- if (argv[i] === '--config-dir' && i + 1 < argv.length) {
20
- configDir = resolve(argv[i + 1]);
21
- i++; // Skip the next argument (the path)
22
- } else if (!command) {
23
- command = argv[i];
24
- } else {
25
- args.push(argv[i]);
26
- }
27
- }
28
-
29
- // Default to current working directory if not specified
30
- if (!configDir) {
31
- configDir = resolve(process.cwd(), 'config');
32
- }
33
- async function main() {
34
- const cli = new CustomerConfigCLI({
35
- configDir
36
- });
37
- await cli.initialize();
38
- try {
39
- switch (command) {
40
- case 'create-customer':
41
- const [customerName, domain] = args;
42
- const result = await cli.createCustomer(customerName, domain);
43
- if (result.success) {
44
- console.log(`\nšŸŽ‰ Customer ${customerName} configuration created successfully!`);
45
- console.log(`\nšŸ“‹ Customer Details:`);
46
- console.log(` Name: ${result.customer.name}`);
47
- console.log(` Domain: ${result.customer.domain || 'Not specified'}`);
48
- console.log(` Config Path: ${result.customer.configPath}`);
49
- console.log(` Environments: ${result.customer.environments.join(', ')}`);
50
- console.log(`\nšŸ“‹ Next steps:`);
51
- console.log(`1. Review generated configs in: config/customers/${customerName}/`);
52
- console.log(`2. Update domain-specific URLs if needed`);
53
- console.log(`3. Generate production secrets: npm run security:generate-key ${customerName}`);
54
- console.log(`4. Set production secrets: wrangler secret put KEY_NAME --env production`);
55
- } else {
56
- console.error(`āŒ Failed to create customer: ${result.error}`);
57
- process.exit(1);
58
- }
59
- break;
60
- case 'validate':
61
- const validateResult = await cli.validateConfigurations();
62
- if (validateResult.valid) {
63
- console.log('āœ… All customer configurations are valid');
64
- } else {
65
- console.log('āŒ Configuration validation failed');
66
- validateResult.errors.forEach(error => console.log(` - ${error}`));
67
- process.exit(1);
68
- }
69
- break;
70
- case 'show':
71
- const [customerNameShow, environment] = args;
72
- const showResult = cli.showConfiguration(customerNameShow, environment);
73
- if (showResult.success) {
74
- console.log(`šŸ” Effective configuration: ${customerNameShow}/${environment}\n`);
75
- if (showResult.config.variables?.base) {
76
- console.log('šŸ“‹ Base variables:');
77
- Object.entries(showResult.config.variables.base).slice(0, 10).forEach(([key, value]) => {
78
- console.log(` ${key}=${value}`);
79
- });
80
- if (Object.keys(showResult.config.variables.base).length > 10) {
81
- console.log(' ...');
82
- }
83
- console.log('');
84
- }
85
- if (showResult.config.variables?.customer) {
86
- console.log(`šŸ“‹ Customer ${environment} variables:`);
87
- Object.entries(showResult.config.variables.customer).slice(0, 15).forEach(([key, value]) => {
88
- console.log(` ${key}=${value}`);
89
- });
90
- if (Object.keys(showResult.config.variables.customer).length > 15) {
91
- console.log(' ...');
92
- }
93
- console.log('');
94
- }
95
- if (showResult.config.features && Object.keys(showResult.config.features).length > 0) {
96
- console.log('🚩 Customer features:');
97
- Object.entries(showResult.config.features).forEach(([feature, enabled]) => {
98
- console.log(` ${feature}: ${enabled ? 'āœ…' : 'āŒ'}`);
99
- });
100
- }
101
- } else {
102
- console.error(`āŒ Failed to show configuration: ${showResult.error}`);
103
- process.exit(1);
104
- }
105
- break;
106
- case 'deploy-command':
107
- const [customerNameDeploy, environmentDeploy] = args;
108
- const deployResult = cli.getDeployCommand(customerNameDeploy, environmentDeploy);
109
- if (deployResult.success) {
110
- console.log(`šŸ“‹ Deploy command for ${customerNameDeploy}/${environmentDeploy}:`);
111
- console.log(` ${deployResult.command}`);
112
- console.log(`\nšŸ’” Ensure customer config is loaded: ${deployResult.configPath}`);
113
- } else {
114
- console.error(`āŒ Failed to get deploy command: ${deployResult.error}`);
115
- process.exit(1);
116
- }
117
- break;
118
- case 'list':
119
- const listResult = cli.listCustomers();
120
- if (listResult.success && listResult.customers.length > 0) {
121
- console.log('šŸ“‹ Configured customers:\n');
122
- listResult.customers.forEach(customer => {
123
- console.log(`šŸ¢ ${customer.name}`);
124
- console.log(` Domain: ${customer.customerDomain || customer.domain || 'Not configured'}`);
125
- console.log(` Account ID: ${customer.accountId ? `${customer.accountId.substring(0, 8)}...${customer.accountId.substring(24)}` : 'Not configured'}`);
126
- console.log(` Zone ID: ${customer.zoneId ? `${customer.zoneId.substring(0, 8)}...` : 'Not configured'}`);
127
- if (customer.databaseId) {
128
- console.log(` Database: ${customer.databaseName || 'Unnamed'} (${customer.databaseId.substring(0, 8)}...)`);
129
- }
130
- console.log(` Secrets: ${customer.hasSecrets ? 'āœ… Managed via wrangler secret commands' : 'āŒ Not configured'}`);
131
- console.log(` Environments: ${customer.environments.join(', ')}`);
132
- console.log(` Config Path: config/customers/${customer.name}/`);
133
- console.log('');
134
- });
135
- } else if (listResult.success) {
136
- console.log('šŸ“‹ No customers configured');
137
- console.log('\nšŸ’” Tip: Run "clodo-customer-config create-customer <name>" to create your first customer');
138
- } else {
139
- console.error(`āŒ Failed to list customers: ${listResult.error}`);
140
- process.exit(1);
141
- }
142
- break;
143
- default:
144
- console.log('Customer Configuration Management Tool\n');
145
- console.log('Usage:');
146
- console.log(' clodo-customer-config [--config-dir <path>] <command> [args]\n');
147
- console.log('Options:');
148
- console.log(' --config-dir <path> - Path to config directory (default: ./config)\n');
149
- console.log('Available commands:');
150
- console.log(' create-customer <name> [domain] - Create new customer config from template');
151
- console.log(' validate - Validate configuration structure');
152
- console.log(' show <customer> <environment> - Show effective configuration');
153
- console.log(' deploy-command <customer> <env> - Get deployment command');
154
- console.log(' list - List all configured customers');
155
- console.log('\nExamples:');
156
- console.log(' clodo-customer-config create-customer acmecorp acmecorp.com');
157
- console.log(' clodo-customer-config validate');
158
- console.log(' clodo-customer-config show acmecorp production');
159
- console.log(' clodo-customer-config list');
160
- console.log(' clodo-customer-config --config-dir /path/to/service/config validate');
161
- console.log('\nIntegration:');
162
- console.log(' This tool integrates with Clodo Framework domain and feature flag systems.');
163
- console.log(' Customer configurations are automatically registered as domains.');
164
- console.log(' When run from a service directory, it uses ./config by default.');
165
- break;
166
- }
167
- } catch (error) {
168
- console.error(`āŒ Error: ${error.message}`);
169
- process.exit(1);
170
- }
171
- }
172
- main().catch(error => {
173
- console.error(`āŒ Unexpected error: ${error.message}`);
174
- process.exit(1);
175
- });