@tamyla/clodo-framework 3.1.4 → 3.1.8
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 +29 -0
- package/bin/clodo-service.js +29 -989
- package/bin/database/enterprise-db-manager.js +7 -5
- package/bin/security/security-cli.js +0 -0
- package/bin/service-management/create-service.js +0 -0
- package/bin/service-management/init-service.js +0 -0
- package/bin/shared/cloudflare/domain-discovery.js +11 -10
- package/bin/shared/cloudflare/ops.js +1 -1
- package/bin/shared/config/ConfigurationManager.js +539 -0
- package/bin/shared/config/index.js +13 -1
- package/bin/shared/database/connection-manager.js +2 -2
- package/bin/shared/database/orchestrator.js +5 -4
- package/bin/shared/deployment/auditor.js +9 -8
- package/bin/shared/logging/Logger.js +214 -0
- package/bin/shared/monitoring/production-monitor.js +21 -9
- package/bin/shared/utils/ErrorHandler.js +675 -0
- package/bin/shared/utils/error-recovery.js +33 -13
- package/bin/shared/utils/file-manager.js +162 -0
- package/bin/shared/utils/formatters.js +247 -0
- package/bin/shared/utils/index.js +14 -4
- package/bin/shared/validation/ValidationRegistry.js +143 -0
- package/dist/deployment/auditor.js +23 -8
- package/dist/deployment/orchestration/BaseDeploymentOrchestrator.js +426 -0
- package/dist/deployment/orchestration/EnterpriseOrchestrator.js +401 -0
- package/dist/deployment/orchestration/PortfolioOrchestrator.js +273 -0
- package/dist/deployment/orchestration/SingleServiceOrchestrator.js +231 -0
- package/dist/deployment/orchestration/UnifiedDeploymentOrchestrator.js +662 -0
- package/dist/deployment/orchestration/index.js +17 -0
- package/dist/index.js +12 -0
- package/dist/orchestration/modules/DomainResolver.js +8 -6
- package/dist/orchestration/multi-domain-orchestrator.js +13 -1
- package/dist/security/index.js +2 -2
- package/dist/service-management/ConfirmationEngine.js +8 -7
- package/dist/service-management/ErrorTracker.js +7 -2
- package/dist/service-management/InputCollector.js +31 -16
- package/dist/service-management/ServiceCreator.js +22 -7
- package/dist/service-management/ServiceInitializer.js +12 -18
- package/dist/shared/cloudflare/domain-discovery.js +11 -10
- package/dist/shared/cloudflare/ops.js +1 -1
- package/dist/shared/config/ConfigurationManager.js +519 -0
- package/dist/shared/config/index.js +5 -1
- package/dist/shared/database/connection-manager.js +2 -2
- package/dist/shared/database/orchestrator.js +13 -4
- package/dist/shared/deployment/auditor.js +23 -8
- package/dist/shared/logging/Logger.js +209 -0
- package/dist/shared/monitoring/production-monitor.js +24 -8
- package/dist/{utils → shared/utils}/ErrorHandler.js +306 -28
- package/dist/shared/utils/error-recovery.js +33 -13
- package/dist/shared/utils/file-manager.js +155 -0
- package/dist/shared/utils/formatters.js +215 -0
- package/dist/shared/utils/index.js +14 -4
- package/dist/shared/validation/ValidationRegistry.js +126 -0
- package/dist/utils/config/unified-config-manager.js +14 -12
- package/dist/utils/deployment/config-cache.js +3 -1
- package/dist/utils/deployment/secret-generator.js +32 -29
- package/dist/utils/framework-config.js +6 -3
- package/dist/utils/ui-structures-loader.js +3 -0
- package/dist/worker/integration.js +11 -1
- package/package.json +31 -3
- package/dist/config/FeatureManager.js +0 -426
- package/dist/config/features.js +0 -230
- package/dist/utils/error-recovery.js +0 -240
|
@@ -63,12 +63,14 @@ export class DomainResolver {
|
|
|
63
63
|
warnings: []
|
|
64
64
|
};
|
|
65
65
|
try {
|
|
66
|
-
// Validate
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
66
|
+
// Validate Cloudflare token
|
|
67
|
+
if (!process.env.CLOUDFLARE_API_TOKEN) {
|
|
68
|
+
validation.warnings.push('CLOUDFLARE_API_TOKEN not yet configured (will be set during deployment)');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Validate Cloudflare account ID
|
|
72
|
+
if (!process.env.CLOUDFLARE_ACCOUNT_ID) {
|
|
73
|
+
validation.warnings.push('CLOUDFLARE_ACCOUNT_ID not yet configured (will be set during deployment)');
|
|
72
74
|
}
|
|
73
75
|
|
|
74
76
|
// Validate domain format
|
|
@@ -45,6 +45,14 @@ export class MultiDomainOrchestrator {
|
|
|
45
45
|
process.env.CLOUDFLARE_API_TOKEN = this.cloudflareToken;
|
|
46
46
|
console.log(`🔑 Configured wrangler to use API token authentication`);
|
|
47
47
|
}
|
|
48
|
+
if (this.cloudflareAccountId) {
|
|
49
|
+
process.env.CLOUDFLARE_ACCOUNT_ID = this.cloudflareAccountId;
|
|
50
|
+
console.log(`🔑 Configured wrangler to use account ID: ${this.cloudflareAccountId}`);
|
|
51
|
+
}
|
|
52
|
+
if (this.cloudflareAccountId) {
|
|
53
|
+
process.env.CLOUDFLARE_ACCOUNT_ID = this.cloudflareAccountId;
|
|
54
|
+
console.log(`🔑 Configured wrangler to use account ID: ${this.cloudflareAccountId}`);
|
|
55
|
+
}
|
|
48
56
|
|
|
49
57
|
// Initialize modular components
|
|
50
58
|
this.domainResolver = new DomainResolver({
|
|
@@ -161,14 +169,18 @@ export class MultiDomainOrchestrator {
|
|
|
161
169
|
/**
|
|
162
170
|
* Deploy to single domain using modular deployment coordinator
|
|
163
171
|
* @param {string} domain - Domain to deploy
|
|
172
|
+
* @param {Object} deploymentOptions - Deployment configuration options
|
|
164
173
|
* @returns {Promise<Object>} Deployment result
|
|
165
174
|
*/
|
|
166
|
-
async deploySingleDomain(domain) {
|
|
175
|
+
async deploySingleDomain(domain, deploymentOptions = {}) {
|
|
167
176
|
const domainState = this.portfolioState.domainStates.get(domain);
|
|
168
177
|
if (!domainState) {
|
|
169
178
|
throw new Error(`Domain ${domain} not found in portfolio`);
|
|
170
179
|
}
|
|
171
180
|
|
|
181
|
+
// Store deployment options in domain state for handlers to access
|
|
182
|
+
domainState.deploymentOptions = deploymentOptions;
|
|
183
|
+
|
|
172
184
|
// Create handlers that delegate to our legacy methods for backward compatibility
|
|
173
185
|
const handlers = {
|
|
174
186
|
validation: d => this.validateDomainPrerequisites(d),
|
package/dist/security/index.js
CHANGED
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
import { ConfigurationValidator } from './ConfigurationValidator.js';
|
|
7
7
|
// DeploymentManager removed - replaced by MultiDomainOrchestrator + WranglerConfigManager
|
|
8
8
|
import { SecretGenerator } from './SecretGenerator.js';
|
|
9
|
-
import { ErrorHandler } from '
|
|
9
|
+
import { ErrorHandler } from '../../bin/shared/utils/index.js';
|
|
10
10
|
// InteractiveDeploymentConfigurator removed - replaced by InputCollector
|
|
11
11
|
|
|
12
12
|
export { ConfigurationValidator } from './ConfigurationValidator.js';
|
|
13
13
|
// export { DeploymentManager } - DEPRECATED: Use MultiDomainOrchestrator instead
|
|
14
14
|
export { SecretGenerator } from './SecretGenerator.js';
|
|
15
|
-
export { ErrorHandler } from '
|
|
15
|
+
export { ErrorHandler } from '../../bin/shared/utils/index.js';
|
|
16
16
|
// export { InteractiveDeploymentConfigurator } - DEPRECATED: Use InputCollector instead
|
|
17
17
|
|
|
18
18
|
// Re-export patterns and rules for advanced usage
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
import { createInterface } from 'readline';
|
|
35
35
|
import chalk from 'chalk';
|
|
36
36
|
import { validateServiceName, validateDomainName } from '../utils/validation.js';
|
|
37
|
+
import { NameFormatters, UrlFormatters, ResourceFormatters } from '../../bin/shared/utils/Formatters.js';
|
|
37
38
|
export class ConfirmationEngine {
|
|
38
39
|
constructor(options = {}) {
|
|
39
40
|
this.interactive = options.interactive !== false;
|
|
@@ -82,17 +83,17 @@ export class ConfirmationEngine {
|
|
|
82
83
|
// 4. Author - Default framework author
|
|
83
84
|
author: 'Clodo Framework',
|
|
84
85
|
// 5-7. URLs - Derived from domain and service name
|
|
85
|
-
productionUrl:
|
|
86
|
-
stagingUrl:
|
|
87
|
-
developmentUrl:
|
|
86
|
+
productionUrl: UrlFormatters.buildProductionUrl(serviceName, domainName),
|
|
87
|
+
stagingUrl: UrlFormatters.buildStagingUrl(serviceName, domainName),
|
|
88
|
+
developmentUrl: UrlFormatters.buildDevUrl(serviceName, domainName),
|
|
88
89
|
// 8. Features - Based on service type
|
|
89
90
|
features: this.generateFeaturesForType(serviceType),
|
|
90
91
|
// 9. Database Name - Cloudflare D1 naming
|
|
91
|
-
databaseName:
|
|
92
|
+
databaseName: ResourceFormatters.databaseName(serviceName),
|
|
92
93
|
// 10. Worker Name - Cloudflare Worker naming
|
|
93
|
-
workerName:
|
|
94
|
+
workerName: ResourceFormatters.workerName(serviceName),
|
|
94
95
|
// 11. Package Name - NPM package naming
|
|
95
|
-
packageName:
|
|
96
|
+
packageName: ResourceFormatters.packageName(serviceName),
|
|
96
97
|
// 12. Git Repository URL - GitHub naming
|
|
97
98
|
gitRepositoryUrl: `https://github.com/tamylaa/${serviceName}`,
|
|
98
99
|
// 13. Documentation URL - Based on domain
|
|
@@ -319,7 +320,7 @@ export class ConfirmationEngine {
|
|
|
319
320
|
* Generate display name from service name
|
|
320
321
|
*/
|
|
321
322
|
generateDisplayName(serviceName) {
|
|
322
|
-
return
|
|
323
|
+
return NameFormatters.toDisplayName(serviceName);
|
|
323
324
|
}
|
|
324
325
|
|
|
325
326
|
/**
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import fs from 'fs/promises';
|
|
9
9
|
import path from 'path';
|
|
10
10
|
import chalk from 'chalk';
|
|
11
|
+
import { logger } from '../../bin/shared/logging/Logger.js';
|
|
11
12
|
export class ErrorTracker {
|
|
12
13
|
constructor() {
|
|
13
14
|
this.errors = [];
|
|
@@ -46,7 +47,9 @@ export class ErrorTracker {
|
|
|
46
47
|
|
|
47
48
|
// Log to file asynchronously (don't block)
|
|
48
49
|
this.logErrorToFile(errorEntry).catch(err => {
|
|
49
|
-
|
|
50
|
+
logger.warn('Failed to write error log', {
|
|
51
|
+
error: err.message
|
|
52
|
+
});
|
|
50
53
|
});
|
|
51
54
|
return errorEntry;
|
|
52
55
|
}
|
|
@@ -155,7 +158,9 @@ export class ErrorTracker {
|
|
|
155
158
|
await fs.appendFile(this.errorLogPath, logEntry);
|
|
156
159
|
} catch (error) {
|
|
157
160
|
// If we can't write to the log file, at least show a warning
|
|
158
|
-
|
|
161
|
+
logger.warn('Could not write to error log', {
|
|
162
|
+
error: error.message
|
|
163
|
+
});
|
|
159
164
|
}
|
|
160
165
|
}
|
|
161
166
|
|
|
@@ -15,6 +15,7 @@ import { createInterface } from 'readline';
|
|
|
15
15
|
import chalk from 'chalk';
|
|
16
16
|
import { validateServiceName, validateDomainName } from '../utils/validation.js';
|
|
17
17
|
import { uiStructuresLoader } from '../utils/ui-structures-loader.js';
|
|
18
|
+
import { NameFormatters, UrlFormatters, ResourceFormatters } from '../../bin/shared/utils/Formatters.js';
|
|
18
19
|
|
|
19
20
|
// Assessment capabilities moved to @tamyla/clodo-orchestration (professional edition)
|
|
20
21
|
|
|
@@ -122,12 +123,12 @@ export class InputCollector {
|
|
|
122
123
|
console.log(chalk.white('The following will be automatically generated from your inputs:\n'));
|
|
123
124
|
const autoTemplate = uiStructuresLoader.getAutomatedGenerationTemplate();
|
|
124
125
|
if (autoTemplate) {
|
|
125
|
-
console.log(chalk.gray(`📊 ${autoTemplate.
|
|
126
|
+
console.log(chalk.gray(`📊 ${autoTemplate.template.inputCount} configurations will be generated automatically`));
|
|
126
127
|
console.log(chalk.gray(`⏱️ Estimated time: ${autoTemplate.template.estimatedTime}`));
|
|
127
128
|
|
|
128
129
|
// Show some examples of what will be automated
|
|
129
130
|
result.automatedGenerations = {
|
|
130
|
-
count: autoTemplate.
|
|
131
|
+
count: autoTemplate.template.inputCount,
|
|
131
132
|
estimatedTime: autoTemplate.template.estimatedTime,
|
|
132
133
|
examples: ['Database connection strings', 'Environment variables', 'API endpoints', 'Security configurations', 'Deployment scripts']
|
|
133
134
|
};
|
|
@@ -148,12 +149,15 @@ export class InputCollector {
|
|
|
148
149
|
* Generate smart defaults based on core inputs
|
|
149
150
|
*/
|
|
150
151
|
generateSmartDefault(inputId, coreInputs) {
|
|
151
|
-
const serviceName = coreInputs.serviceName?.value || '';
|
|
152
|
-
const environment = coreInputs.environment?.value || 'development';
|
|
153
|
-
const domainName = coreInputs.domainName?.value || '';
|
|
152
|
+
const serviceName = coreInputs['service-name']?.value || coreInputs.serviceName?.value || '';
|
|
153
|
+
const environment = coreInputs['environment']?.value || coreInputs.environment?.value || 'development';
|
|
154
|
+
const domainName = coreInputs['domain-name']?.value || coreInputs.domainName?.value || '';
|
|
155
|
+
const serviceType = coreInputs['service-type']?.value || coreInputs.serviceType?.value || '';
|
|
156
|
+
const customerName = coreInputs['customer-name']?.value || coreInputs.customerName?.value || '';
|
|
157
|
+
const cloudflareToken = coreInputs['cloudflare-api-token']?.value || coreInputs.cloudflareApiToken?.value || '';
|
|
154
158
|
switch (inputId) {
|
|
155
159
|
case 'display-name':
|
|
156
|
-
return serviceName ?
|
|
160
|
+
return serviceName ? NameFormatters.toDisplayName(serviceName) : '';
|
|
157
161
|
case 'description':
|
|
158
162
|
return `A service built with CLODO Framework`;
|
|
159
163
|
case 'version':
|
|
@@ -161,19 +165,21 @@ export class InputCollector {
|
|
|
161
165
|
case 'author':
|
|
162
166
|
return 'CLODO Framework';
|
|
163
167
|
case 'production-url':
|
|
164
|
-
return domainName ?
|
|
168
|
+
return domainName && serviceName ? UrlFormatters.buildProductionUrl(serviceName, domainName) : '';
|
|
165
169
|
case 'staging-url':
|
|
166
|
-
return domainName && serviceName ?
|
|
170
|
+
return domainName && serviceName ? UrlFormatters.buildStagingUrl(serviceName, domainName) : '';
|
|
167
171
|
case 'development-url':
|
|
168
|
-
return domainName && serviceName ?
|
|
172
|
+
return domainName && serviceName ? UrlFormatters.buildDevUrl(serviceName, domainName) : '';
|
|
169
173
|
case 'service-directory':
|
|
170
174
|
return serviceName ? `./services/${serviceName}` : '';
|
|
171
175
|
case 'database-name':
|
|
172
|
-
return serviceName ?
|
|
176
|
+
return serviceName ? ResourceFormatters.databaseName(serviceName) : '';
|
|
173
177
|
case 'worker-name':
|
|
174
|
-
return serviceName ?
|
|
178
|
+
return serviceName ? ResourceFormatters.workerName(serviceName) : '';
|
|
175
179
|
case 'log-level':
|
|
176
180
|
return environment === 'production' ? 'warn' : environment === 'staging' ? 'info' : 'debug';
|
|
181
|
+
case 'cors-policy':
|
|
182
|
+
return domainName ? `https://${domainName}` : '*';
|
|
177
183
|
case 'env-prefix':
|
|
178
184
|
return environment === 'production' ? 'PROD_' : environment === 'staging' ? 'STAGING_' : 'DEV_';
|
|
179
185
|
default:
|
|
@@ -195,7 +201,7 @@ export class InputCollector {
|
|
|
195
201
|
* Format field names for display
|
|
196
202
|
*/
|
|
197
203
|
formatFieldName(inputId) {
|
|
198
|
-
return
|
|
204
|
+
return NameFormatters.toDisplayName(inputId);
|
|
199
205
|
}
|
|
200
206
|
|
|
201
207
|
/**
|
|
@@ -589,16 +595,25 @@ export class InputCollector {
|
|
|
589
595
|
}
|
|
590
596
|
|
|
591
597
|
/**
|
|
592
|
-
* Collect inputs and return
|
|
593
|
-
* Used by CLI for
|
|
598
|
+
* Collect inputs and return full three-tier result
|
|
599
|
+
* Used by CLI for comprehensive service operations
|
|
594
600
|
*/
|
|
595
601
|
async collect() {
|
|
596
602
|
const result = await this.collectInputsWithTransparency();
|
|
597
|
-
|
|
603
|
+
|
|
604
|
+
// For CLI compatibility, also provide flat coreInputs
|
|
598
605
|
const flatCoreInputs = {};
|
|
599
606
|
for (const [key, inputObj] of Object.entries(result.coreInputs)) {
|
|
600
607
|
flatCoreInputs[key] = inputObj.value;
|
|
601
608
|
}
|
|
602
|
-
|
|
609
|
+
|
|
610
|
+
// Merge smart confirmations into flat object
|
|
611
|
+
for (const [key, value] of Object.entries(result.smartConfirmations)) {
|
|
612
|
+
flatCoreInputs[key] = value;
|
|
613
|
+
}
|
|
614
|
+
return {
|
|
615
|
+
...result,
|
|
616
|
+
flatInputs: flatCoreInputs
|
|
617
|
+
};
|
|
603
618
|
}
|
|
604
619
|
}
|
|
@@ -3,13 +3,17 @@
|
|
|
3
3
|
* Programmatic API for creating services from templates
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { readdirSync, statSync, cpSync, rmSync } from 'fs';
|
|
7
7
|
import { join, dirname, resolve } from 'path';
|
|
8
8
|
import { fileURLToPath } from 'url';
|
|
9
9
|
import { FrameworkConfig } from '../utils/framework-config.js';
|
|
10
|
+
import { FileManager } from '../../bin/shared/utils/file-manager.js';
|
|
10
11
|
const SERVICE_TYPES = ['data-service', 'auth-service', 'content-service', 'api-gateway', 'generic'];
|
|
11
12
|
export class ServiceCreator {
|
|
12
13
|
constructor(options = {}) {
|
|
14
|
+
this.fileManager = new FileManager({
|
|
15
|
+
enableCache: true
|
|
16
|
+
});
|
|
13
17
|
const templatesDir = (() => {
|
|
14
18
|
try {
|
|
15
19
|
return join(dirname(fileURLToPath(import.meta.url)), '..', '..', 'templates');
|
|
@@ -80,9 +84,9 @@ export class ServiceCreator {
|
|
|
80
84
|
|
|
81
85
|
// Check if template exists, fall back to generic if not
|
|
82
86
|
let actualTemplateDir = templateDir;
|
|
83
|
-
if (!
|
|
87
|
+
if (!this.fileManager.exists(templateDir)) {
|
|
84
88
|
const genericTemplate = join(this.templatesDir, 'generic');
|
|
85
|
-
if (
|
|
89
|
+
if (this.fileManager.exists(genericTemplate)) {
|
|
86
90
|
console.log(`⚠️ Template for '${config.type}' not found, using 'generic' template as fallback`);
|
|
87
91
|
actualTemplateDir = genericTemplate;
|
|
88
92
|
} else {
|
|
@@ -91,10 +95,21 @@ export class ServiceCreator {
|
|
|
91
95
|
}
|
|
92
96
|
|
|
93
97
|
// Check if service directory already exists
|
|
94
|
-
if (
|
|
98
|
+
if (this.fileManager.exists(serviceDir) && !config.force) {
|
|
95
99
|
throw new Error(`Service directory already exists: ${serviceDir}. Use force option to overwrite.`);
|
|
96
100
|
}
|
|
97
101
|
|
|
102
|
+
// Create service directory and copy template
|
|
103
|
+
this.fileManager.ensureDir(dirname(serviceDir));
|
|
104
|
+
|
|
105
|
+
// If service directory exists (force mode), remove it first
|
|
106
|
+
if (this.fileManager.exists(serviceDir) && config.force) {
|
|
107
|
+
rmSync(serviceDir, {
|
|
108
|
+
recursive: true,
|
|
109
|
+
force: true
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
98
113
|
// Copy template to service directory
|
|
99
114
|
cpSync(actualTemplateDir, serviceDir, {
|
|
100
115
|
recursive: true
|
|
@@ -147,7 +162,7 @@ export class ServiceCreator {
|
|
|
147
162
|
const files = this.getAllFiles(dir);
|
|
148
163
|
for (const file of files) {
|
|
149
164
|
try {
|
|
150
|
-
let content =
|
|
165
|
+
let content = this.fileManager.readFile(file, 'utf8');
|
|
151
166
|
let modified = false;
|
|
152
167
|
for (const [placeholder, value] of Object.entries(variables)) {
|
|
153
168
|
if (content.includes(placeholder)) {
|
|
@@ -156,7 +171,7 @@ export class ServiceCreator {
|
|
|
156
171
|
}
|
|
157
172
|
}
|
|
158
173
|
if (modified) {
|
|
159
|
-
|
|
174
|
+
this.fileManager.writeFile(file, content, 'utf8');
|
|
160
175
|
}
|
|
161
176
|
} catch (error) {
|
|
162
177
|
// Skip binary files or files that can't be read
|
|
@@ -218,7 +233,7 @@ export class ServiceCreator {
|
|
|
218
233
|
*/
|
|
219
234
|
getFrameworkVersion() {
|
|
220
235
|
try {
|
|
221
|
-
const packageJson = JSON.parse(
|
|
236
|
+
const packageJson = JSON.parse(this.fileManager.readFile(join(dirname(fileURLToPath(import.meta.url)), '..', '..', 'package.json'), 'utf8'));
|
|
222
237
|
return packageJson.version;
|
|
223
238
|
} catch {
|
|
224
239
|
return '1.0.0';
|
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
* Programmatic API for initializing services with configurations
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { readdirSync } from 'fs';
|
|
7
7
|
import { join, dirname, resolve } from 'path';
|
|
8
8
|
import { fileURLToPath } from 'url';
|
|
9
|
+
import { FileManager } from '../../bin/shared/utils/file-manager.js';
|
|
9
10
|
|
|
10
11
|
// Get framework root - handle both ES module and CommonJS environments
|
|
11
12
|
const getFrameworkRoot = () => {
|
|
@@ -24,6 +25,9 @@ const TEMPLATES_DIR = join(FRAMEWORK_ROOT, 'templates');
|
|
|
24
25
|
const SERVICE_TYPES = ['generic', 'data-service', 'auth-service', 'content-service', 'api-gateway'];
|
|
25
26
|
export class ServiceInitializer {
|
|
26
27
|
constructor(options = {}) {
|
|
28
|
+
this.fileManager = new FileManager({
|
|
29
|
+
enableCache: true
|
|
30
|
+
});
|
|
27
31
|
this.frameworkRoot = options.frameworkRoot || FRAMEWORK_ROOT;
|
|
28
32
|
this.templatesDir = options.templatesDir || TEMPLATES_DIR;
|
|
29
33
|
this.serviceTypes = options.serviceTypes || SERVICE_TYPES;
|
|
@@ -403,26 +407,16 @@ ${domainInfo.domains.map(d => `- ${d.domain}`).join('\n')}
|
|
|
403
407
|
const serviceDir = join(servicesDir, serviceName);
|
|
404
408
|
|
|
405
409
|
// Create directories
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
recursive: true
|
|
411
|
-
});
|
|
412
|
-
mkdirSync(join(serviceDir, 'src', 'config'), {
|
|
413
|
-
recursive: true
|
|
414
|
-
});
|
|
415
|
-
mkdirSync(join(serviceDir, 'src', 'worker'), {
|
|
416
|
-
recursive: true
|
|
417
|
-
});
|
|
410
|
+
this.fileManager.ensureDir(servicesDir);
|
|
411
|
+
this.fileManager.ensureDir(serviceDir);
|
|
412
|
+
this.fileManager.ensureDir(join(serviceDir, 'src', 'config'));
|
|
413
|
+
this.fileManager.ensureDir(join(serviceDir, 'src', 'worker'));
|
|
418
414
|
|
|
419
415
|
// Write configuration files
|
|
420
416
|
for (const [filePath, content] of Object.entries(configs)) {
|
|
421
417
|
const fullPath = join(serviceDir, filePath);
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
});
|
|
425
|
-
writeFileSync(fullPath, content, 'utf8');
|
|
418
|
+
this.fileManager.ensureDir(dirname(fullPath));
|
|
419
|
+
this.fileManager.writeFile(fullPath, content, 'utf8');
|
|
426
420
|
}
|
|
427
421
|
|
|
428
422
|
// Create basic worker file
|
|
@@ -440,7 +434,7 @@ export default {
|
|
|
440
434
|
}
|
|
441
435
|
};
|
|
442
436
|
`;
|
|
443
|
-
|
|
437
|
+
this.fileManager.writeFile(join(serviceDir, 'src', 'worker', 'index.js'), workerContent, 'utf8');
|
|
444
438
|
}
|
|
445
439
|
|
|
446
440
|
/**
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync } from 'fs';
|
|
10
10
|
import { join, dirname } from 'path';
|
|
11
11
|
import { fileURLToPath } from 'url';
|
|
12
|
+
import { NameFormatters, UrlFormatters, ResourceFormatters, EnvironmentFormatters } from '../utils/Formatters.js';
|
|
12
13
|
const __filename = fileURLToPath(import.meta.url);
|
|
13
14
|
const __dirname = dirname(__filename);
|
|
14
15
|
|
|
@@ -185,7 +186,7 @@ export class DomainDiscovery {
|
|
|
185
186
|
const config = {
|
|
186
187
|
// Basic domain information
|
|
187
188
|
name: cleanDomainName,
|
|
188
|
-
displayName:
|
|
189
|
+
displayName: NameFormatters.toDisplayName(cleanDomainName),
|
|
189
190
|
fullDomain: domainName,
|
|
190
191
|
// Cloudflare infrastructure
|
|
191
192
|
accountId: account.id,
|
|
@@ -204,19 +205,19 @@ export class DomainDiscovery {
|
|
|
204
205
|
// Service URLs
|
|
205
206
|
services: {
|
|
206
207
|
frontend: {
|
|
207
|
-
production:
|
|
208
|
-
staging:
|
|
209
|
-
development:
|
|
208
|
+
production: UrlFormatters.buildProductionUrl('www', domainName),
|
|
209
|
+
staging: UrlFormatters.buildStagingUrl('www', domainName),
|
|
210
|
+
development: UrlFormatters.buildDevUrl('www', domainName)
|
|
210
211
|
},
|
|
211
212
|
api: {
|
|
212
|
-
production:
|
|
213
|
-
staging:
|
|
214
|
-
development:
|
|
213
|
+
production: UrlFormatters.buildProductionUrl('api', domainName),
|
|
214
|
+
staging: UrlFormatters.buildStagingUrl('api', domainName),
|
|
215
|
+
development: UrlFormatters.buildDevUrl('api', domainName)
|
|
215
216
|
},
|
|
216
217
|
auth: {
|
|
217
|
-
production:
|
|
218
|
-
staging:
|
|
219
|
-
development:
|
|
218
|
+
production: UrlFormatters.buildProductionUrl('auth', domainName),
|
|
219
|
+
staging: UrlFormatters.buildStagingUrl('auth', domainName),
|
|
220
|
+
development: UrlFormatters.buildDevUrl('auth', domainName)
|
|
220
221
|
}
|
|
221
222
|
},
|
|
222
223
|
// CORS configuration
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import { exec } from 'child_process';
|
|
9
9
|
import { promisify } from 'util';
|
|
10
10
|
import { executeWithRateLimit } from '../utils/rate-limiter.js';
|
|
11
|
-
import { ErrorRecoveryManager } from '../utils/
|
|
11
|
+
import { ErrorRecoveryManager } from '../utils/index.js';
|
|
12
12
|
import { SecureTokenManager } from '../security/secure-token-manager.js';
|
|
13
13
|
import { ProductionMonitor } from '../monitoring/production-monitor.js';
|
|
14
14
|
import { DatabaseConnectionManager } from '../database/connection-manager.js';
|