@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.
- package/CHANGELOG.md +206 -62
- package/bin/clodo-service.js +32 -56
- package/bin/database/README.md +33 -0
- package/bin/database/deployment-db-manager.js +527 -0
- package/bin/database/enterprise-db-manager.js +736 -0
- package/bin/database/wrangler-d1-manager.js +775 -0
- package/bin/shared/cloudflare/domain-discovery.js +636 -0
- package/bin/shared/cloudflare/domain-manager.js +952 -0
- package/bin/shared/cloudflare/index.js +8 -0
- package/bin/shared/cloudflare/ops.js +359 -0
- package/bin/shared/config/index.js +1 -1
- package/bin/shared/database/connection-manager.js +374 -0
- package/bin/shared/database/index.js +7 -0
- package/bin/shared/database/orchestrator.js +726 -0
- package/bin/shared/deployment/auditor.js +969 -0
- package/bin/shared/deployment/index.js +10 -0
- package/bin/shared/deployment/rollback-manager.js +570 -0
- package/bin/shared/deployment/validator.js +779 -0
- package/bin/shared/index.js +32 -0
- package/bin/shared/monitoring/health-checker.js +484 -0
- package/bin/shared/monitoring/index.js +8 -0
- package/bin/shared/monitoring/memory-manager.js +387 -0
- package/bin/shared/monitoring/production-monitor.js +391 -0
- package/bin/shared/production-tester/api-tester.js +82 -0
- package/bin/shared/production-tester/auth-tester.js +132 -0
- package/bin/shared/production-tester/core.js +197 -0
- package/bin/shared/production-tester/database-tester.js +109 -0
- package/bin/shared/production-tester/index.js +77 -0
- package/bin/shared/production-tester/load-tester.js +131 -0
- package/bin/shared/production-tester/performance-tester.js +103 -0
- package/bin/shared/security/api-token-manager.js +312 -0
- package/bin/shared/security/index.js +8 -0
- package/bin/shared/security/secret-generator.js +937 -0
- package/bin/shared/security/secure-token-manager.js +398 -0
- package/bin/shared/utils/error-recovery.js +225 -0
- package/bin/shared/utils/graceful-shutdown-manager.js +390 -0
- package/bin/shared/utils/index.js +9 -0
- package/bin/shared/utils/interactive-prompts.js +146 -0
- package/bin/shared/utils/interactive-utils.js +530 -0
- package/bin/shared/utils/rate-limiter.js +246 -0
- package/dist/database/database-orchestrator.js +34 -12
- package/dist/deployment/index.js +2 -2
- package/dist/orchestration/multi-domain-orchestrator.js +8 -6
- package/dist/service-management/GenerationEngine.js +76 -28
- package/dist/service-management/ServiceInitializer.js +5 -3
- package/dist/shared/cloudflare/domain-manager.js +1 -1
- package/dist/shared/cloudflare/ops.js +27 -12
- package/dist/shared/config/index.js +1 -1
- package/dist/shared/deployment/index.js +2 -2
- package/dist/shared/security/secret-generator.js +4 -2
- package/dist/shared/utils/error-recovery.js +1 -1
- package/dist/shared/utils/graceful-shutdown-manager.js +4 -3
- package/dist/utils/deployment/secret-generator.js +19 -6
- package/package.json +7 -6
- package/bin/shared/config/customer-cli.js +0 -182
- 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('../../../
|
|
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
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
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": "
|
|
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/
|
|
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
|
|
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
|
-
});
|