@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
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* BaseGenerator - Abstract base class for all file generators
|
|
3
|
-
*
|
|
4
|
-
* Provides common functionality for loading templates, rendering content,
|
|
5
|
-
* and writing files. All concrete generators should extend this class.
|
|
6
|
-
*
|
|
7
|
-
* NOTE: This class uses Node.js filesystem APIs and is designed for
|
|
8
|
-
* build-time usage during service generation, not runtime in Cloudflare Workers.
|
|
9
|
-
*
|
|
10
|
-
* @abstract
|
|
11
|
-
*/
|
|
12
|
-
import { promises as fs } from 'fs';
|
|
13
|
-
import * as path from 'path';
|
|
14
|
-
export class BaseGenerator {
|
|
15
|
-
/**
|
|
16
|
-
* Create a new generator instance
|
|
17
|
-
* @param {Object} options - Generator configuration options
|
|
18
|
-
* @param {string} options.name - Generator name (for logging/debugging)
|
|
19
|
-
* @param {string} options.templatesPath - Path to templates directory
|
|
20
|
-
* @param {string} options.servicePath - Path to service being generated
|
|
21
|
-
*/
|
|
22
|
-
constructor(options = {}) {
|
|
23
|
-
if (new.target === BaseGenerator) {
|
|
24
|
-
throw new Error('BaseGenerator is abstract and cannot be instantiated directly');
|
|
25
|
-
}
|
|
26
|
-
this.name = options.name || this.constructor.name;
|
|
27
|
-
this.templatesPath = options.templatesPath || options.templatesDir || null;
|
|
28
|
-
this.servicePath = options.servicePath || null;
|
|
29
|
-
|
|
30
|
-
// Warn if running in Cloudflare Workers environment
|
|
31
|
-
if (typeof globalThis !== 'undefined' && globalThis.caches) {
|
|
32
|
-
console.warn(`⚠️ ${this.name}: Generators are designed for build-time usage, not runtime in Cloudflare Workers`);
|
|
33
|
-
}
|
|
34
|
-
this.context = {};
|
|
35
|
-
this.logger = options.logger || console;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Main generation method - must be implemented by concrete generators
|
|
40
|
-
* @abstract
|
|
41
|
-
* @param {Object} context - Generation context with service configuration
|
|
42
|
-
* @returns {Promise<void>}
|
|
43
|
-
*/
|
|
44
|
-
async generate(context) {
|
|
45
|
-
throw new Error(`generate() must be implemented by ${this.constructor.name}`);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Determine if this generator should run for the given context
|
|
50
|
-
* Override this to conditionally skip generation
|
|
51
|
-
* @param {Object} context - Generation context
|
|
52
|
-
* @returns {boolean} - True if generator should run
|
|
53
|
-
*/
|
|
54
|
-
shouldGenerate(context) {
|
|
55
|
-
return true;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Set the generation context
|
|
60
|
-
* @param {Object} context - Generation context with service configuration
|
|
61
|
-
*/
|
|
62
|
-
setContext(context) {
|
|
63
|
-
this.context = {
|
|
64
|
-
...context
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
// Update paths if provided in context
|
|
68
|
-
if (context.servicePath) {
|
|
69
|
-
this.servicePath = context.servicePath;
|
|
70
|
-
}
|
|
71
|
-
if (context.templatesPath) {
|
|
72
|
-
this.templatesPath = context.templatesPath;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Extract and normalize context into consistent format
|
|
78
|
-
* @param {Object} context - Generation context
|
|
79
|
-
* @returns {Object} - Normalized context with coreInputs, confirmedValues, servicePath
|
|
80
|
-
*/
|
|
81
|
-
extractContext(context) {
|
|
82
|
-
return {
|
|
83
|
-
coreInputs: context.coreInputs || {},
|
|
84
|
-
confirmedValues: context.confirmedValues || {},
|
|
85
|
-
servicePath: context.servicePath || this.servicePath || this.outputDir
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Get a value from the context
|
|
91
|
-
* @param {string} key - Context key (supports dot notation: 'config.name')
|
|
92
|
-
* @param {*} defaultValue - Default value if key not found
|
|
93
|
-
* @returns {*} - Context value or default
|
|
94
|
-
*/
|
|
95
|
-
getContext(key, defaultValue = undefined) {
|
|
96
|
-
if (!key) return this.context;
|
|
97
|
-
const keys = key.split('.');
|
|
98
|
-
let value = this.context;
|
|
99
|
-
for (const k of keys) {
|
|
100
|
-
if (value && typeof value === 'object' && k in value) {
|
|
101
|
-
value = value[k];
|
|
102
|
-
} else {
|
|
103
|
-
return defaultValue;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
return value;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Load a template file from the templates directory
|
|
111
|
-
* Subclasses can override this to implement custom template loading
|
|
112
|
-
* @param {string} templateName - Template filename or path relative to templatesPath
|
|
113
|
-
* @returns {Promise<string>} - Template content
|
|
114
|
-
*/
|
|
115
|
-
async loadTemplate(templateName) {
|
|
116
|
-
if (!this.templatesPath) {
|
|
117
|
-
throw new Error(`templatesPath not set for ${this.name}`);
|
|
118
|
-
}
|
|
119
|
-
const templatePath = path.join(this.templatesPath, templateName);
|
|
120
|
-
try {
|
|
121
|
-
const content = await fs.readFile(templatePath, 'utf8');
|
|
122
|
-
return content;
|
|
123
|
-
} catch (error) {
|
|
124
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
125
|
-
throw new Error(`Failed to load template '${templateName}' from '${templatePath}': ${errorMessage}`);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Render a template with variables
|
|
131
|
-
* Replaces {{variable}} placeholders with values from the variables object
|
|
132
|
-
* @param {string} template - Template string with {{placeholders}}
|
|
133
|
-
* @param {Object} variables - Variable values to replace
|
|
134
|
-
* @returns {string} - Rendered template
|
|
135
|
-
*/
|
|
136
|
-
renderTemplate(template, variables = {}) {
|
|
137
|
-
if (typeof template !== 'string') {
|
|
138
|
-
throw new Error('Template must be a string');
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// Merge context with provided variables (variables take precedence)
|
|
142
|
-
const mergedVars = {
|
|
143
|
-
...this.context,
|
|
144
|
-
...variables
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
// Replace {{variable}} placeholders
|
|
148
|
-
return template.replace(/\{\{([^}]+)\}\}/g, (match, key) => {
|
|
149
|
-
const trimmedKey = key.trim();
|
|
150
|
-
|
|
151
|
-
// Check provided variables first (priority), then context
|
|
152
|
-
let value;
|
|
153
|
-
if (trimmedKey in variables) {
|
|
154
|
-
value = variables[trimmedKey];
|
|
155
|
-
} else {
|
|
156
|
-
// Support dot notation for context: {{config.name}}
|
|
157
|
-
value = this.getContext(trimmedKey);
|
|
158
|
-
}
|
|
159
|
-
if (value === undefined || value === null) {
|
|
160
|
-
this.logger.warn(`Template variable '${trimmedKey}' is undefined in ${this.name}`);
|
|
161
|
-
return match; // Keep placeholder if variable not found
|
|
162
|
-
}
|
|
163
|
-
return String(value);
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* Write content to a file within the service directory
|
|
169
|
-
* Creates parent directories if they don't exist
|
|
170
|
-
* @param {string} relativePath - Path relative to servicePath
|
|
171
|
-
* @param {string} content - File content to write
|
|
172
|
-
* @param {Object} options - Write options
|
|
173
|
-
* @param {boolean} options.overwrite - Whether to overwrite existing files (default: true)
|
|
174
|
-
* @returns {Promise<void>}
|
|
175
|
-
*/
|
|
176
|
-
async writeFile(relativePath, content, options = {}) {
|
|
177
|
-
if (!this.servicePath) {
|
|
178
|
-
throw new Error(`servicePath not set for ${this.name}`);
|
|
179
|
-
}
|
|
180
|
-
const fullPath = path.join(this.servicePath, relativePath);
|
|
181
|
-
const overwrite = options.overwrite !== false; // Default to true
|
|
182
|
-
|
|
183
|
-
// Check if file exists and overwrite is disabled
|
|
184
|
-
try {
|
|
185
|
-
await fs.access(fullPath);
|
|
186
|
-
if (!overwrite) {
|
|
187
|
-
this.logger.info(`Skipping existing file: ${relativePath}`);
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
} catch {
|
|
191
|
-
// File doesn't exist, continue
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
// Ensure parent directory exists
|
|
195
|
-
const dir = path.dirname(fullPath);
|
|
196
|
-
await fs.mkdir(dir, {
|
|
197
|
-
recursive: true
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
// Write file
|
|
201
|
-
try {
|
|
202
|
-
await fs.writeFile(fullPath, content, 'utf8');
|
|
203
|
-
this.logger.info(`Generated: ${relativePath}`);
|
|
204
|
-
} catch (error) {
|
|
205
|
-
throw new Error(`Failed to write file '${relativePath}': ${error.message}`);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* Log a message at info level
|
|
211
|
-
* @param {string} message - Message to log
|
|
212
|
-
*/
|
|
213
|
-
log(message) {
|
|
214
|
-
this.logger.info(`[${this.name}] ${message}`);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* Log a warning message
|
|
219
|
-
* @param {string} message - Warning message
|
|
220
|
-
*/
|
|
221
|
-
warn(message) {
|
|
222
|
-
this.logger.warn(`[${this.name}] ${message}`);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
/**
|
|
226
|
-
* Log an error message
|
|
227
|
-
* @param {string} message - Error message
|
|
228
|
-
*/
|
|
229
|
-
error(message) {
|
|
230
|
-
this.logger.error(`[${this.name}] ${message}`);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
export default BaseGenerator;
|
|
@@ -1,254 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* GeneratorRegistry - Registry for managing and executing generators
|
|
3
|
-
*
|
|
4
|
-
* Provides a centralized registry for all generators, organized by category.
|
|
5
|
-
* Controls execution order and manages generator lifecycle.
|
|
6
|
-
*/
|
|
7
|
-
export class GeneratorRegistry {
|
|
8
|
-
/**
|
|
9
|
-
* Create a new generator registry
|
|
10
|
-
*/
|
|
11
|
-
constructor() {
|
|
12
|
-
this.categories = new Map();
|
|
13
|
-
this.executionOrder = ['core',
|
|
14
|
-
// Core configuration files (package.json, wrangler.toml, etc.)
|
|
15
|
-
'config',
|
|
16
|
-
// Environment and config files
|
|
17
|
-
'code',
|
|
18
|
-
// Source code (schemas, handlers, middleware, utils)
|
|
19
|
-
'scripts',
|
|
20
|
-
// Utility scripts (deploy, setup, health-check)
|
|
21
|
-
'tests',
|
|
22
|
-
// Test files and test configuration
|
|
23
|
-
'docs',
|
|
24
|
-
// Documentation files
|
|
25
|
-
'ci',
|
|
26
|
-
// CI/CD workflows
|
|
27
|
-
'service-types' // Service-type specific generation
|
|
28
|
-
];
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Register one or more generators in a category
|
|
33
|
-
* @param {string} category - Category name (e.g., 'core', 'config', 'code')
|
|
34
|
-
* @param {BaseGenerator|BaseGenerator[]} generators - Generator instance(s) to register
|
|
35
|
-
* @throws {Error} If category or generators are invalid
|
|
36
|
-
*/
|
|
37
|
-
register(category, generators) {
|
|
38
|
-
if (!category || typeof category !== 'string') {
|
|
39
|
-
throw new Error('Category must be a non-empty string');
|
|
40
|
-
}
|
|
41
|
-
if (!generators) {
|
|
42
|
-
throw new Error('Generators must be provided');
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Ensure generators is an array
|
|
46
|
-
const generatorArray = Array.isArray(generators) ? generators : [generators];
|
|
47
|
-
if (generatorArray.length === 0) {
|
|
48
|
-
throw new Error('At least one generator must be provided');
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// Validate all generators have a generate() method
|
|
52
|
-
for (const generator of generatorArray) {
|
|
53
|
-
if (!generator || typeof generator.generate !== 'function') {
|
|
54
|
-
throw new Error(`Invalid generator: must have a generate() method. Got: ${generator?.constructor?.name || typeof generator}`);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Get existing generators for this category or create new array
|
|
59
|
-
const existing = this.categories.get(category) || [];
|
|
60
|
-
|
|
61
|
-
// Add new generators
|
|
62
|
-
this.categories.set(category, [...existing, ...generatorArray]);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Unregister a specific generator from a category
|
|
67
|
-
* @param {string} category - Category name
|
|
68
|
-
* @param {string} generatorName - Name of the generator to remove
|
|
69
|
-
* @returns {boolean} - True if generator was found and removed
|
|
70
|
-
*/
|
|
71
|
-
unregister(category, generatorName) {
|
|
72
|
-
if (!this.categories.has(category)) {
|
|
73
|
-
return false;
|
|
74
|
-
}
|
|
75
|
-
const generators = this.categories.get(category);
|
|
76
|
-
const initialLength = generators.length;
|
|
77
|
-
const filtered = generators.filter(gen => gen.name !== generatorName);
|
|
78
|
-
if (filtered.length === 0) {
|
|
79
|
-
this.categories.delete(category);
|
|
80
|
-
} else {
|
|
81
|
-
this.categories.set(category, filtered);
|
|
82
|
-
}
|
|
83
|
-
return filtered.length < initialLength;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Get all generators for a specific category
|
|
88
|
-
* @param {string} category - Category name
|
|
89
|
-
* @returns {BaseGenerator[]} - Array of generators (empty if category not found)
|
|
90
|
-
*/
|
|
91
|
-
getGenerators(category) {
|
|
92
|
-
return this.categories.get(category) || [];
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Get all registered categories in execution order
|
|
97
|
-
* @returns {string[]} - Array of category names
|
|
98
|
-
*/
|
|
99
|
-
getCategories() {
|
|
100
|
-
const registeredCategories = Array.from(this.categories.keys());
|
|
101
|
-
|
|
102
|
-
// Return categories in execution order, followed by any unordered categories
|
|
103
|
-
const ordered = this.executionOrder.filter(cat => registeredCategories.includes(cat));
|
|
104
|
-
const unordered = registeredCategories.filter(cat => !this.executionOrder.includes(cat));
|
|
105
|
-
return [...ordered, ...unordered];
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Get total count of registered generators across all categories
|
|
110
|
-
* @returns {number} - Total generator count
|
|
111
|
-
*/
|
|
112
|
-
getCount() {
|
|
113
|
-
let count = 0;
|
|
114
|
-
for (const generators of this.categories.values()) {
|
|
115
|
-
count += generators.length;
|
|
116
|
-
}
|
|
117
|
-
return count;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Get count of generators in a specific category
|
|
122
|
-
* @param {string} category - Category name
|
|
123
|
-
* @returns {number} - Generator count for category
|
|
124
|
-
*/
|
|
125
|
-
getCategoryCount(category) {
|
|
126
|
-
return this.getGenerators(category).length;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Check if a category has any generators
|
|
131
|
-
* @param {string} category - Category name
|
|
132
|
-
* @returns {boolean} - True if category has generators
|
|
133
|
-
*/
|
|
134
|
-
hasCategory(category) {
|
|
135
|
-
return this.categories.has(category) && this.categories.get(category).length > 0;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Clear all generators from a category
|
|
140
|
-
* @param {string} category - Category name
|
|
141
|
-
* @returns {boolean} - True if category existed and was cleared
|
|
142
|
-
*/
|
|
143
|
-
clearCategory(category) {
|
|
144
|
-
return this.categories.delete(category);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Clear all generators from all categories
|
|
149
|
-
*/
|
|
150
|
-
clearAll() {
|
|
151
|
-
this.categories.clear();
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Execute all generators in order
|
|
156
|
-
* @param {Object} context - Generation context to pass to all generators
|
|
157
|
-
* @param {Object} options - Execution options
|
|
158
|
-
* @param {Function} options.logger - Logger for progress tracking
|
|
159
|
-
* @param {boolean} options.stopOnError - Whether to stop execution on first error (default: false)
|
|
160
|
-
* @returns {Promise<Object>} - Execution results { success, failed, skipped }
|
|
161
|
-
*/
|
|
162
|
-
async execute(context, options = {}) {
|
|
163
|
-
const logger = options.logger || console;
|
|
164
|
-
const stopOnError = options.stopOnError !== false; // Default to true for safety
|
|
165
|
-
|
|
166
|
-
const results = {
|
|
167
|
-
success: [],
|
|
168
|
-
failed: [],
|
|
169
|
-
skipped: []
|
|
170
|
-
};
|
|
171
|
-
const categories = this.getCategories();
|
|
172
|
-
logger.info(`Starting generator execution: ${this.getCount()} generators in ${categories.length} categories`);
|
|
173
|
-
for (const category of categories) {
|
|
174
|
-
const generators = this.getGenerators(category);
|
|
175
|
-
logger.info(`Executing category: ${category} (${generators.length} generators)`);
|
|
176
|
-
for (const generator of generators) {
|
|
177
|
-
const name = generator.name || generator.constructor.name;
|
|
178
|
-
try {
|
|
179
|
-
// Check if generator should run
|
|
180
|
-
if (generator.shouldGenerate && !generator.shouldGenerate(context)) {
|
|
181
|
-
logger.info(`Skipping ${name}: shouldGenerate() returned false`);
|
|
182
|
-
results.skipped.push({
|
|
183
|
-
name,
|
|
184
|
-
category,
|
|
185
|
-
reason: 'shouldGenerate() returned false'
|
|
186
|
-
});
|
|
187
|
-
continue;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Execute generator
|
|
191
|
-
logger.info(`Running ${name}...`);
|
|
192
|
-
await generator.generate(context);
|
|
193
|
-
results.success.push({
|
|
194
|
-
name,
|
|
195
|
-
category
|
|
196
|
-
});
|
|
197
|
-
logger.info(`✓ ${name} completed successfully`);
|
|
198
|
-
} catch (error) {
|
|
199
|
-
const errorInfo = {
|
|
200
|
-
name,
|
|
201
|
-
category,
|
|
202
|
-
error: error.message,
|
|
203
|
-
stack: error.stack
|
|
204
|
-
};
|
|
205
|
-
results.failed.push(errorInfo);
|
|
206
|
-
logger.error(`✗ ${name} failed: ${error.message}`);
|
|
207
|
-
if (stopOnError) {
|
|
208
|
-
logger.error('Stopping execution due to error (stopOnError=true)');
|
|
209
|
-
throw new Error(`Generator execution stopped: ${name} failed - ${error.message}`);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// Log summary
|
|
216
|
-
logger.info('\n=== Generator Execution Summary ===');
|
|
217
|
-
logger.info(`Total: ${this.getCount()} generators`);
|
|
218
|
-
logger.info(`✓ Success: ${results.success.length}`);
|
|
219
|
-
logger.info(`✗ Failed: ${results.failed.length}`);
|
|
220
|
-
logger.info(`⊘ Skipped: ${results.skipped.length}`);
|
|
221
|
-
if (results.failed.length > 0) {
|
|
222
|
-
logger.error('\nFailed generators:');
|
|
223
|
-
results.failed.forEach(({
|
|
224
|
-
name,
|
|
225
|
-
error
|
|
226
|
-
}) => {
|
|
227
|
-
logger.error(` - ${name}: ${error}`);
|
|
228
|
-
});
|
|
229
|
-
}
|
|
230
|
-
return results;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
/**
|
|
234
|
-
* Get a summary of all registered generators
|
|
235
|
-
* @returns {Object} - Summary with categories and generator counts
|
|
236
|
-
*/
|
|
237
|
-
getSummary() {
|
|
238
|
-
const categories = this.getCategories();
|
|
239
|
-
const summary = {
|
|
240
|
-
totalCategories: categories.length,
|
|
241
|
-
totalGenerators: this.getCount(),
|
|
242
|
-
categories: {}
|
|
243
|
-
};
|
|
244
|
-
for (const category of categories) {
|
|
245
|
-
const generators = this.getGenerators(category);
|
|
246
|
-
summary.categories[category] = {
|
|
247
|
-
count: generators.length,
|
|
248
|
-
generators: generators.map(g => g.name || g.constructor.name)
|
|
249
|
-
};
|
|
250
|
-
}
|
|
251
|
-
return summary;
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
export default GeneratorRegistry;
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { BaseGenerator } from '../BaseGenerator.js';
|
|
2
|
-
import { join } from 'path';
|
|
3
|
-
import { writeFileSync, mkdirSync } from 'fs';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* CI Workflow Generator
|
|
7
|
-
* Generates GitHub Actions CI workflow for automated testing
|
|
8
|
-
*/
|
|
9
|
-
export class CiWorkflowGenerator extends BaseGenerator {
|
|
10
|
-
/**
|
|
11
|
-
* Generate CI workflow
|
|
12
|
-
* @param {Object} context - Generation context
|
|
13
|
-
* @returns {Promise<string>} Path to generated CI workflow file
|
|
14
|
-
*/
|
|
15
|
-
async generate(context) {
|
|
16
|
-
const {
|
|
17
|
-
coreInputs,
|
|
18
|
-
confirmedValues,
|
|
19
|
-
servicePath
|
|
20
|
-
} = this.extractContext(context);
|
|
21
|
-
if (!this.shouldGenerate(context)) {
|
|
22
|
-
return null;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Ensure .github/workflows directory exists
|
|
26
|
-
const workflowsDir = join(servicePath, '.github', 'workflows');
|
|
27
|
-
mkdirSync(workflowsDir, {
|
|
28
|
-
recursive: true
|
|
29
|
-
});
|
|
30
|
-
const ciWorkflow = this._generateCiWorkflow(coreInputs, confirmedValues);
|
|
31
|
-
const filePath = join(workflowsDir, 'ci.yml');
|
|
32
|
-
writeFileSync(filePath, ciWorkflow, 'utf8');
|
|
33
|
-
return filePath;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Generate CI workflow content
|
|
38
|
-
* @private
|
|
39
|
-
*/
|
|
40
|
-
_generateCiWorkflow(coreInputs, confirmedValues) {
|
|
41
|
-
return `name: CI
|
|
42
|
-
|
|
43
|
-
on:
|
|
44
|
-
push:
|
|
45
|
-
branches: [ main, master ]
|
|
46
|
-
pull_request:
|
|
47
|
-
branches: [ main, master ]
|
|
48
|
-
|
|
49
|
-
jobs:
|
|
50
|
-
test:
|
|
51
|
-
runs-on: ubuntu-latest
|
|
52
|
-
|
|
53
|
-
steps:
|
|
54
|
-
- uses: actions/checkout@v4
|
|
55
|
-
|
|
56
|
-
- name: Setup Node.js
|
|
57
|
-
uses: actions/setup-node@v4
|
|
58
|
-
with:
|
|
59
|
-
node-version: '18'
|
|
60
|
-
cache: 'npm'
|
|
61
|
-
|
|
62
|
-
- name: Install dependencies
|
|
63
|
-
run: npm ci
|
|
64
|
-
|
|
65
|
-
- name: Lint code
|
|
66
|
-
run: npm run lint
|
|
67
|
-
|
|
68
|
-
- name: Run tests
|
|
69
|
-
run: npm test
|
|
70
|
-
|
|
71
|
-
- name: Build
|
|
72
|
-
run: npm run build
|
|
73
|
-
|
|
74
|
-
- name: Upload coverage reports
|
|
75
|
-
uses: codecov/codecov-action@v3
|
|
76
|
-
with:
|
|
77
|
-
file: ./coverage/lcov.info
|
|
78
|
-
`;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Determine if generator should run
|
|
83
|
-
*/
|
|
84
|
-
shouldGenerate(context) {
|
|
85
|
-
return true; // Always generate CI workflow
|
|
86
|
-
}
|
|
87
|
-
}
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import { BaseGenerator } from '../BaseGenerator.js';
|
|
2
|
-
import { join } from 'path';
|
|
3
|
-
import { writeFileSync, mkdirSync } from 'fs';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Deploy Workflow Generator
|
|
7
|
-
* Generates GitHub Actions deployment workflow for staging and production
|
|
8
|
-
*/
|
|
9
|
-
export class DeployWorkflowGenerator extends BaseGenerator {
|
|
10
|
-
/**
|
|
11
|
-
* Generate deployment workflow
|
|
12
|
-
* @param {Object} context - Generation context
|
|
13
|
-
* @returns {Promise<string>} Path to generated deploy workflow file
|
|
14
|
-
*/
|
|
15
|
-
async generate(context) {
|
|
16
|
-
const {
|
|
17
|
-
coreInputs,
|
|
18
|
-
confirmedValues,
|
|
19
|
-
servicePath
|
|
20
|
-
} = this.extractContext(context);
|
|
21
|
-
if (!this.shouldGenerate(context)) {
|
|
22
|
-
return null;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Ensure .github/workflows directory exists
|
|
26
|
-
const workflowsDir = join(servicePath, '.github', 'workflows');
|
|
27
|
-
mkdirSync(workflowsDir, {
|
|
28
|
-
recursive: true
|
|
29
|
-
});
|
|
30
|
-
const deployWorkflow = this._generateDeployWorkflow(coreInputs, confirmedValues);
|
|
31
|
-
const filePath = join(workflowsDir, 'deploy.yml');
|
|
32
|
-
writeFileSync(filePath, deployWorkflow, 'utf8');
|
|
33
|
-
return filePath;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Generate deployment workflow content
|
|
38
|
-
* @private
|
|
39
|
-
*/
|
|
40
|
-
_generateDeployWorkflow(coreInputs, confirmedValues) {
|
|
41
|
-
return `name: Deploy
|
|
42
|
-
|
|
43
|
-
on:
|
|
44
|
-
push:
|
|
45
|
-
branches: [ main, master ]
|
|
46
|
-
workflow_run:
|
|
47
|
-
workflows: ["CI"]
|
|
48
|
-
types:
|
|
49
|
-
- completed
|
|
50
|
-
|
|
51
|
-
jobs:
|
|
52
|
-
deploy-staging:
|
|
53
|
-
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master'
|
|
54
|
-
runs-on: ubuntu-latest
|
|
55
|
-
environment: staging
|
|
56
|
-
|
|
57
|
-
steps:
|
|
58
|
-
- uses: actions/checkout@v4
|
|
59
|
-
|
|
60
|
-
- name: Setup Node.js
|
|
61
|
-
uses: actions/setup-node@v4
|
|
62
|
-
with:
|
|
63
|
-
node-version: '18'
|
|
64
|
-
cache: 'npm'
|
|
65
|
-
|
|
66
|
-
- name: Install dependencies
|
|
67
|
-
run: npm ci
|
|
68
|
-
|
|
69
|
-
- name: Deploy to staging
|
|
70
|
-
run: npx wrangler deploy --env staging
|
|
71
|
-
env:
|
|
72
|
-
CLOUDFLARE_API_TOKEN: \${{ secrets.CLOUDFLARE_API_TOKEN }}
|
|
73
|
-
CLOUDFLARE_ACCOUNT_ID: \${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
|
74
|
-
|
|
75
|
-
deploy-production:
|
|
76
|
-
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master'
|
|
77
|
-
runs-on: ubuntu-latest
|
|
78
|
-
environment: production
|
|
79
|
-
|
|
80
|
-
steps:
|
|
81
|
-
- uses: actions/checkout@v4
|
|
82
|
-
|
|
83
|
-
- name: Setup Node.js
|
|
84
|
-
uses: actions/setup-node@v4
|
|
85
|
-
with:
|
|
86
|
-
node-version: '18'
|
|
87
|
-
cache: 'npm'
|
|
88
|
-
|
|
89
|
-
- name: Install dependencies
|
|
90
|
-
run: npm ci
|
|
91
|
-
|
|
92
|
-
- name: Deploy to production
|
|
93
|
-
run: npx wrangler deploy --env production
|
|
94
|
-
env:
|
|
95
|
-
CLOUDFLARE_API_TOKEN: \${{ secrets.CLOUDFLARE_API_TOKEN }}
|
|
96
|
-
CLOUDFLARE_ACCOUNT_ID: \${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
|
97
|
-
`;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Determine if generator should run
|
|
102
|
-
*/
|
|
103
|
-
shouldGenerate(context) {
|
|
104
|
-
return true; // Always generate deployment workflow
|
|
105
|
-
}
|
|
106
|
-
}
|