@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.
Files changed (169) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +53 -0
  3. package/dist/bin/clodo-service.js +47 -15
  4. package/dist/bin/commands/deploy.js +115 -83
  5. package/dist/bin/commands/helpers/deployment-ui.js +138 -0
  6. package/dist/bin/commands/helpers/deployment-verification.js +251 -0
  7. package/dist/bin/commands/helpers/error-recovery.js +80 -0
  8. package/dist/bin/commands/helpers/resource-detection.js +113 -0
  9. package/dist/bin/commands/validate.js +1 -1
  10. package/dist/bin/security/security-cli.js +1 -1
  11. package/dist/bin/shared/cache/configuration-cache.js +82 -0
  12. package/dist/bin/shared/cloudflare/domain-manager.js +1 -1
  13. package/dist/bin/shared/cloudflare/index.js +1 -1
  14. package/dist/bin/shared/cloudflare/ops.js +6 -4
  15. package/dist/bin/shared/config/ConfigurationManager.js +23 -1
  16. package/dist/bin/shared/config/command-config-manager.js +19 -3
  17. package/dist/bin/shared/config/index.js +1 -1
  18. package/dist/bin/shared/deployment/credential-collector.js +30 -7
  19. package/dist/bin/shared/deployment/index.js +2 -2
  20. package/dist/bin/shared/deployment/rollback-manager.js +4 -520
  21. package/dist/bin/shared/deployment/utilities/d1-error-recovery.js +177 -0
  22. package/dist/bin/shared/deployment/validator.js +40 -10
  23. package/dist/bin/shared/deployment/workflows/deployment-summary.js +214 -0
  24. package/dist/bin/shared/deployment/workflows/interactive-confirmation.js +188 -0
  25. package/dist/bin/shared/deployment/workflows/interactive-database-workflow.js +234 -0
  26. package/dist/bin/shared/deployment/workflows/interactive-domain-info-gatherer.js +240 -0
  27. package/dist/bin/shared/deployment/workflows/interactive-secret-workflow.js +228 -0
  28. package/dist/bin/shared/deployment/workflows/interactive-testing-workflow.js +235 -0
  29. package/dist/bin/shared/deployment/workflows/interactive-validation.js +218 -0
  30. package/dist/bin/shared/error-handling/error-classifier.js +46 -0
  31. package/dist/bin/shared/monitoring/health-checker.js +129 -1
  32. package/dist/bin/shared/monitoring/memory-manager.js +17 -6
  33. package/dist/bin/shared/routing/domain-router.js +1 -1
  34. package/dist/bin/shared/utils/deployment-validator.js +97 -0
  35. package/dist/bin/shared/utils/formatters.js +10 -0
  36. package/dist/bin/shared/utils/index.js +13 -1
  37. package/dist/bin/shared/utils/interactive-prompts.js +34 -18
  38. package/dist/bin/shared/utils/progress-manager.js +2 -2
  39. package/dist/bin/shared/utils/progress-spinner.js +53 -0
  40. package/dist/bin/shared/utils/sensitive-redactor.js +91 -0
  41. package/dist/bin/shared/validation/ValidationRegistry.js +1 -1
  42. package/dist/security/index.js +1 -1
  43. package/dist/security/patterns/insecure-patterns.js +1 -1
  44. package/dist/utils/constants.js +102 -0
  45. package/dist/utils/deployment/wrangler-config-manager.js +215 -48
  46. package/dist/utils/framework-config.js +2 -2
  47. package/dist/utils/interactive-prompts.js +10 -59
  48. package/package.json +16 -8
  49. package/dist/bin/clodo-service-old.js +0 -868
  50. package/dist/bin/clodo-service-test.js +0 -10
  51. package/dist/bin/commands/assess.js +0 -91
  52. package/dist/bin/commands/create.js +0 -77
  53. package/dist/bin/commands/diagnose.js +0 -83
  54. package/dist/bin/commands/helpers.js +0 -138
  55. package/dist/bin/commands/update.js +0 -75
  56. package/dist/bin/database/deployment-db-manager.js +0 -423
  57. package/dist/bin/database/enterprise-db-manager.js +0 -457
  58. package/dist/bin/database/wrangler-d1-manager.js +0 -685
  59. package/dist/bin/deployment/enterprise-deploy.js +0 -877
  60. package/dist/bin/deployment/master-deploy.js +0 -1376
  61. package/dist/bin/deployment/modular-enterprise-deploy.js +0 -466
  62. package/dist/bin/deployment/modules/DeploymentConfiguration.js +0 -395
  63. package/dist/bin/deployment/modules/DeploymentOrchestrator.js +0 -492
  64. package/dist/bin/deployment/modules/EnvironmentManager.js +0 -517
  65. package/dist/bin/deployment/modules/MonitoringIntegration.js +0 -560
  66. package/dist/bin/deployment/modules/ValidationManager.js +0 -342
  67. package/dist/bin/deployment/orchestration/BaseDeploymentOrchestrator.js +0 -426
  68. package/dist/bin/deployment/orchestration/EnterpriseOrchestrator.js +0 -401
  69. package/dist/bin/deployment/orchestration/PortfolioOrchestrator.js +0 -273
  70. package/dist/bin/deployment/orchestration/SingleServiceOrchestrator.js +0 -231
  71. package/dist/bin/deployment/orchestration/UnifiedDeploymentOrchestrator.js +0 -662
  72. package/dist/bin/deployment/test-interactive-utils.js +0 -66
  73. package/dist/bin/portfolio/portfolio-manager.js +0 -487
  74. package/dist/bin/service-management/create-service.js +0 -122
  75. package/dist/bin/service-management/init-service.js +0 -79
  76. package/dist/config/customers.js +0 -623
  77. package/dist/config/domains.js +0 -186
  78. package/dist/config/index.js +0 -6
  79. package/dist/database/database-orchestrator.js +0 -795
  80. package/dist/database/index.js +0 -4
  81. package/dist/deployment/index.js +0 -11
  82. package/dist/deployment/orchestration/BaseDeploymentOrchestrator.js +0 -426
  83. package/dist/deployment/orchestration/EnterpriseOrchestrator.js +0 -401
  84. package/dist/deployment/orchestration/PortfolioOrchestrator.js +0 -273
  85. package/dist/deployment/orchestration/SingleServiceOrchestrator.js +0 -231
  86. package/dist/deployment/orchestration/UnifiedDeploymentOrchestrator.js +0 -662
  87. package/dist/deployment/orchestration/index.js +0 -17
  88. package/dist/deployment/rollback-manager.js +0 -36
  89. package/dist/deployment/wrangler-deployer.js +0 -640
  90. package/dist/handlers/GenericRouteHandler.js +0 -532
  91. package/dist/migration/MigrationAdapters.js +0 -562
  92. package/dist/modules/ModuleManager.js +0 -668
  93. package/dist/modules/security.js +0 -96
  94. package/dist/orchestration/cross-domain-coordinator.js +0 -1083
  95. package/dist/orchestration/index.js +0 -5
  96. package/dist/orchestration/modules/DeploymentCoordinator.js +0 -368
  97. package/dist/orchestration/modules/DomainResolver.js +0 -198
  98. package/dist/orchestration/modules/StateManager.js +0 -332
  99. package/dist/orchestration/multi-domain-orchestrator.js +0 -724
  100. package/dist/routing/EnhancedRouter.js +0 -158
  101. package/dist/schema/SchemaManager.js +0 -778
  102. package/dist/service-management/ConfirmationEngine.js +0 -412
  103. package/dist/service-management/ErrorTracker.js +0 -299
  104. package/dist/service-management/GenerationEngine.js +0 -447
  105. package/dist/service-management/InputCollector.js +0 -619
  106. package/dist/service-management/ServiceCreator.js +0 -265
  107. package/dist/service-management/ServiceInitializer.js +0 -453
  108. package/dist/service-management/ServiceOrchestrator.js +0 -633
  109. package/dist/service-management/generators/BaseGenerator.js +0 -233
  110. package/dist/service-management/generators/GeneratorRegistry.js +0 -254
  111. package/dist/service-management/generators/cicd/CiWorkflowGenerator.js +0 -87
  112. package/dist/service-management/generators/cicd/DeployWorkflowGenerator.js +0 -106
  113. package/dist/service-management/generators/code/ServiceHandlersGenerator.js +0 -235
  114. package/dist/service-management/generators/code/ServiceMiddlewareGenerator.js +0 -116
  115. package/dist/service-management/generators/code/ServiceUtilsGenerator.js +0 -246
  116. package/dist/service-management/generators/code/WorkerIndexGenerator.js +0 -143
  117. package/dist/service-management/generators/config/DevelopmentEnvGenerator.js +0 -101
  118. package/dist/service-management/generators/config/DomainsConfigGenerator.js +0 -175
  119. package/dist/service-management/generators/config/EnvExampleGenerator.js +0 -178
  120. package/dist/service-management/generators/config/ProductionEnvGenerator.js +0 -97
  121. package/dist/service-management/generators/config/StagingEnvGenerator.js +0 -97
  122. package/dist/service-management/generators/config/WranglerTomlGenerator.js +0 -238
  123. package/dist/service-management/generators/core/PackageJsonGenerator.js +0 -243
  124. package/dist/service-management/generators/core/SiteConfigGenerator.js +0 -115
  125. package/dist/service-management/generators/documentation/ApiDocsGenerator.js +0 -331
  126. package/dist/service-management/generators/documentation/ConfigurationDocsGenerator.js +0 -294
  127. package/dist/service-management/generators/documentation/DeploymentDocsGenerator.js +0 -244
  128. package/dist/service-management/generators/documentation/ReadmeGenerator.js +0 -196
  129. package/dist/service-management/generators/schemas/ServiceSchemaGenerator.js +0 -190
  130. package/dist/service-management/generators/scripts/DeployScriptGenerator.js +0 -123
  131. package/dist/service-management/generators/scripts/HealthCheckScriptGenerator.js +0 -101
  132. package/dist/service-management/generators/scripts/SetupScriptGenerator.js +0 -88
  133. package/dist/service-management/generators/service-types/StaticSiteGenerator.js +0 -342
  134. package/dist/service-management/generators/testing/EslintConfigGenerator.js +0 -85
  135. package/dist/service-management/generators/testing/IntegrationTestsGenerator.js +0 -237
  136. package/dist/service-management/generators/testing/JestConfigGenerator.js +0 -72
  137. package/dist/service-management/generators/testing/UnitTestsGenerator.js +0 -277
  138. package/dist/service-management/generators/tooling/DockerComposeGenerator.js +0 -71
  139. package/dist/service-management/generators/tooling/GitignoreGenerator.js +0 -143
  140. package/dist/service-management/generators/utils/FileWriter.js +0 -179
  141. package/dist/service-management/generators/utils/PathResolver.js +0 -157
  142. package/dist/service-management/generators/utils/ServiceManifestGenerator.js +0 -111
  143. package/dist/service-management/generators/utils/TemplateEngine.js +0 -185
  144. package/dist/service-management/generators/utils/index.js +0 -18
  145. package/dist/service-management/handlers/ConfirmationHandler.js +0 -71
  146. package/dist/service-management/handlers/GenerationHandler.js +0 -80
  147. package/dist/service-management/handlers/InputHandler.js +0 -59
  148. package/dist/service-management/handlers/ValidationHandler.js +0 -203
  149. package/dist/service-management/index.js +0 -14
  150. package/dist/service-management/routing/DomainRouteMapper.js +0 -311
  151. package/dist/service-management/routing/RouteGenerator.js +0 -266
  152. package/dist/service-management/routing/WranglerRoutesBuilder.js +0 -273
  153. package/dist/service-management/routing/index.js +0 -14
  154. package/dist/service-management/services/DirectoryStructureService.js +0 -56
  155. package/dist/service-management/services/GenerationCoordinator.js +0 -208
  156. package/dist/service-management/services/GeneratorRegistry.js +0 -174
  157. package/dist/services/GenericDataService.js +0 -501
  158. package/dist/ui-structures/concepts/second-order-acquisition-strategy.md +0 -286
  159. package/dist/ui-structures/concepts/service-lifecycle-management.md +0 -150
  160. package/dist/ui-structures/concepts/service-manifest-guide.md +0 -309
  161. package/dist/ui-structures/concepts/three-tier-categorization-strategy.md +0 -231
  162. package/dist/ui-structures/creation/automated-generation-ui.json +0 -246
  163. package/dist/ui-structures/creation/core-inputs-ui.json +0 -217
  164. package/dist/ui-structures/creation/smart-confirmable-ui.json +0 -451
  165. package/dist/ui-structures/reference/absolutely-required-inputs.json +0 -315
  166. package/dist/ui-structures/reference/service-manifest-template.json +0 -342
  167. package/dist/version/VersionDetector.js +0 -723
  168. package/dist/worker/index.js +0 -4
  169. package/dist/worker/integration.js +0 -351
@@ -1,311 +0,0 @@
1
- /**
2
- * DomainRouteMapper - Maps domain configurations to route patterns
3
- *
4
- * Handles the business logic of converting domain metadata into
5
- * Cloudflare Workers route patterns with proper specificity ordering.
6
- *
7
- * @module service-management/routing/DomainRouteMapper
8
- */
9
-
10
- import { frameworkConfig } from '../../utils/framework-config.js';
11
- export class DomainRouteMapper {
12
- constructor(options = {}) {
13
- // Load environment-specific routing config
14
- this.frameworkConfig = frameworkConfig;
15
- this.options = options;
16
- }
17
-
18
- /**
19
- * Map domain configuration to route patterns
20
- *
21
- * @param {Object} domainConfig - Domain configuration object
22
- * @param {Object} domainConfig.domains - Domain URLs by environment
23
- * @param {string} domainConfig.zoneId - Cloudflare zone ID
24
- * @param {string} domainConfig.apiBasePath - API base path (optional)
25
- * @param {string} environment - Target environment (production|staging|development)
26
- *
27
- * @returns {Object} Route mapping with patterns and zone_id
28
- * @returns {Array<string>} returns.patterns - Route patterns (ordered by specificity)
29
- * @returns {string} returns.zoneId - Cloudflare zone ID
30
- * @returns {string} returns.environment - Environment name
31
- *
32
- * @example
33
- * const mapper = new DomainRouteMapper();
34
- * const routes = mapper.mapDomainToRoutes(
35
- * {
36
- * domains: { production: 'api.example.com' },
37
- * zoneId: 'xyz789...',
38
- * apiBasePath: '/api'
39
- * },
40
- * 'production'
41
- * );
42
- * // Returns:
43
- * // {
44
- * // patterns: ['api.example.com/*', 'example.com/api/*'],
45
- * // zoneId: 'xyz789...',
46
- * // environment: 'production'
47
- * // }
48
- */
49
- mapDomainToRoutes(domainConfig, environment) {
50
- const domainUrl = domainConfig.domains[environment];
51
- if (!domainUrl) {
52
- return {
53
- patterns: [],
54
- zoneId: domainConfig.zoneId,
55
- environment
56
- };
57
- }
58
-
59
- // Skip workers.dev subdomains (no routes needed)
60
- const routingConfig = this.frameworkConfig.getRoutingConfig();
61
- const workersDomain = routingConfig.domains.workersDomain;
62
- if (domainUrl.includes(workersDomain)) {
63
- return {
64
- patterns: [],
65
- zoneId: domainConfig.zoneId,
66
- environment
67
- };
68
- }
69
-
70
- // Generate route patterns based on environment
71
- let patterns;
72
- switch (environment) {
73
- case 'production':
74
- patterns = this.generateProductionRoutes(domainUrl, domainConfig);
75
- break;
76
- case 'staging':
77
- patterns = this.generateStagingRoutes(domainUrl, domainConfig);
78
- break;
79
- case 'development':
80
- patterns = this.generateDevelopmentRoutes(domainUrl, domainConfig);
81
- break;
82
- default:
83
- patterns = this._generateGenericRoutes(domainUrl, domainConfig);
84
- }
85
- return {
86
- patterns,
87
- zoneId: domainConfig.zoneId,
88
- environment
89
- };
90
- }
91
-
92
- /**
93
- * Generate production environment routes
94
- *
95
- * Creates subdomain pattern and root domain fallback
96
- *
97
- * @param {string} domain - Domain URL (e.g., api.example.com)
98
- * @param {Object} config - Domain configuration
99
- * @returns {Array<string>} Route patterns (ordered by specificity)
100
- *
101
- * @example
102
- * mapper.generateProductionRoutes('api.example.com', { apiBasePath: '/api' })
103
- * // Returns: ['api.example.com/*', 'example.com/api/*']
104
- */
105
- generateProductionRoutes(domain, config = {}) {
106
- const patterns = [];
107
-
108
- // Check if it's a subdomain
109
- const isSubdomain = this._isSubdomain(domain);
110
- if (isSubdomain) {
111
- // 1. Subdomain wildcard (most specific)
112
- patterns.push(`${domain}/*`);
113
-
114
- // 2. Root domain with path fallback
115
- const rootDomain = this._getRootDomain(domain);
116
- const pathPrefix = config.apiBasePath || this._getSubdomainPrefix(domain);
117
- patterns.push(`${rootDomain}${pathPrefix}/*`);
118
- } else {
119
- // Root domain only
120
- const envRouting = this.frameworkConfig.getEnvironmentRoutingConfig('production');
121
- const pathPrefix = config.apiBasePath || envRouting.defaultPathPrefix;
122
- patterns.push(`${domain}${pathPrefix}/*`);
123
- }
124
- return patterns;
125
- }
126
-
127
- /**
128
- * Generate staging environment routes
129
- *
130
- * Similar to production but with staging-specific patterns
131
- *
132
- * @param {string} domain - Domain URL (e.g., staging-api.example.com)
133
- * @param {Object} config - Domain configuration
134
- * @returns {Array<string>} Route patterns (ordered by specificity)
135
- */
136
- generateStagingRoutes(domain, config = {}) {
137
- const patterns = [];
138
-
139
- // Check if it's a subdomain
140
- const isSubdomain = this._isSubdomain(domain);
141
- if (isSubdomain) {
142
- // 1. Staging subdomain wildcard
143
- patterns.push(`${domain}/*`);
144
-
145
- // 2. Root domain with staging path fallback
146
- const rootDomain = this._getRootDomain(domain);
147
- const pathPrefix = config.apiBasePath || this._getSubdomainPrefix(domain);
148
- patterns.push(`${rootDomain}${pathPrefix}/*`);
149
- } else {
150
- // Root domain only
151
- const envRouting = this.frameworkConfig.getEnvironmentRoutingConfig('staging');
152
- const pathPrefix = config.apiBasePath || envRouting.defaultPathPrefix;
153
- patterns.push(`${domain}${pathPrefix}/*`);
154
- }
155
- return patterns;
156
- }
157
-
158
- /**
159
- * Generate development environment routes
160
- *
161
- * Development typically uses workers.dev subdomain (no routes needed)
162
- * Only generate routes if custom domain explicitly specified
163
- *
164
- * @param {string} domain - Domain URL
165
- * @param {Object} config - Domain configuration
166
- * @returns {Array<string>} Route patterns (usually empty)
167
- */
168
- generateDevelopmentRoutes(domain, config = {}) {
169
- // Development typically uses *.workers.dev (no routes needed)
170
- const routingConfig = this.frameworkConfig.getRoutingConfig();
171
- const workersDomain = routingConfig.domains.workersDomain;
172
- if (!domain || domain.includes(workersDomain)) {
173
- return [];
174
- }
175
-
176
- // If custom domain specified for development, generate routes
177
- const patterns = [];
178
- const isSubdomain = this._isSubdomain(domain);
179
- if (isSubdomain) {
180
- patterns.push(`${domain}/*`);
181
- const rootDomain = this._getRootDomain(domain);
182
- const pathPrefix = config.apiBasePath || this._getSubdomainPrefix(domain);
183
- patterns.push(`${rootDomain}${pathPrefix}/*`);
184
- } else {
185
- const envRouting = this.frameworkConfig.getEnvironmentRoutingConfig('development');
186
- const pathPrefix = config.apiBasePath || envRouting.defaultPathPrefix;
187
- patterns.push(`${domain}${pathPrefix}/*`);
188
- }
189
- return patterns;
190
- }
191
-
192
- /**
193
- * Generate generic routes (for any environment)
194
- * @private
195
- */
196
- _generateGenericRoutes(domain, config = {}) {
197
- const patterns = [];
198
- const isSubdomain = this._isSubdomain(domain);
199
- if (isSubdomain) {
200
- patterns.push(`${domain}/*`);
201
- const rootDomain = this._getRootDomain(domain);
202
- const pathPrefix = config.apiBasePath || this._getSubdomainPrefix(domain);
203
- patterns.push(`${rootDomain}${pathPrefix}/*`);
204
- } else {
205
- const envRouting = this.frameworkConfig.getEnvironmentRoutingConfig('production');
206
- const pathPrefix = config.apiBasePath || envRouting.defaultPathPrefix;
207
- patterns.push(`${domain}${pathPrefix}/*`);
208
- }
209
- return patterns;
210
- }
211
-
212
- /**
213
- * Check if domain is a subdomain
214
- * @private
215
- *
216
- * @param {string} domain - Domain name
217
- * @returns {boolean} True if subdomain, false if root domain
218
- *
219
- * @example
220
- * _isSubdomain('api.example.com') // true
221
- * _isSubdomain('example.com') // false
222
- * _isSubdomain('www.example.com') // true
223
- */
224
- _isSubdomain(domain) {
225
- if (!domain) return false;
226
- const parts = domain.split('.');
227
-
228
- // At least 3 parts = subdomain (e.g., api.example.com)
229
- // 2 parts = root domain (e.g., example.com)
230
- // Account for TLDs like .co.uk (4+ parts)
231
- return parts.length >= 3;
232
- }
233
-
234
- /**
235
- * Extract root domain from subdomain
236
- * @private
237
- *
238
- * @param {string} domain - Full domain (e.g., api.example.com)
239
- * @returns {string} Root domain (e.g., example.com)
240
- *
241
- * @example
242
- * _getRootDomain('api.example.com') // 'example.com'
243
- * _getRootDomain('staging-api.example.com') // 'example.com'
244
- * _getRootDomain('example.com') // 'example.com'
245
- */
246
- _getRootDomain(domain) {
247
- if (!domain) return '';
248
- const parts = domain.split('.');
249
-
250
- // Handle different TLD formats
251
- if (parts.length <= 2) {
252
- // Already root domain
253
- return domain;
254
- }
255
-
256
- // Extract last 2 parts (handles .com, .org, etc.)
257
- // TODO: Handle complex TLDs like .co.uk (requires TLD database)
258
- return parts.slice(-2).join('.');
259
- }
260
-
261
- /**
262
- * Extract subdomain prefix and convert to path
263
- * @private
264
- *
265
- * @param {string} domain - Full domain (e.g., api.example.com)
266
- * @returns {string} Path prefix (e.g., /api)
267
- *
268
- * @example
269
- * _getSubdomainPrefix('api.example.com') // '/api'
270
- * _getSubdomainPrefix('staging-api.example.com') // '/staging-api'
271
- * _getSubdomainPrefix('www.example.com') // '/www'
272
- */
273
- _getSubdomainPrefix(domain) {
274
- if (!domain) return '';
275
- const parts = domain.split('.');
276
- if (parts.length < 3) {
277
- // Not a subdomain
278
- return '';
279
- }
280
-
281
- // Get first part (subdomain)
282
- const subdomain = parts[0];
283
-
284
- // Convert to path (add leading slash)
285
- return `/${subdomain}`;
286
- }
287
-
288
- /**
289
- * Get zone ID for domain
290
- *
291
- * Extracts zone_id from coreInputs with validation
292
- *
293
- * @param {string} domain - Domain name
294
- * @param {Object} coreInputs - Core service inputs
295
- * @returns {string} Cloudflare zone ID
296
- * @throws {Error} If zone_id missing or invalid format
297
- */
298
- getZoneIdForDomain(domain, coreInputs) {
299
- if (!coreInputs || !coreInputs.cloudflareZoneId) {
300
- throw new Error(`cloudflareZoneId is required for domain "${domain}" route generation`);
301
- }
302
- const zoneId = coreInputs.cloudflareZoneId;
303
-
304
- // Validate zone_id format (32 hex characters)
305
- const zoneIdPattern = /^[a-f0-9]{32}$/;
306
- if (!zoneIdPattern.test(zoneId)) {
307
- throw new Error(`Invalid zone_id format for domain "${domain}". ` + `Expected 32 hex characters, received: "${zoneId}"`);
308
- }
309
- return zoneId;
310
- }
311
- }
@@ -1,266 +0,0 @@
1
- /**
2
- * RouteGenerator - Main orchestrator for route generation
3
- *
4
- * Generates Cloudflare Workers [[routes]] configuration from domain metadata.
5
- * This is a CORE IDENTITY feature that completes multi-domain orchestration.
6
- *
7
- * @module service-management/routing/RouteGenerator
8
- */
9
-
10
- import { DomainRouteMapper } from './DomainRouteMapper.js';
11
- import { WranglerRoutesBuilder } from './WranglerRoutesBuilder.js';
12
- import { frameworkConfig } from '../../utils/framework-config.js';
13
- export class RouteGenerator {
14
- constructor(options = {}) {
15
- this.mapper = new DomainRouteMapper(options);
16
- this.builder = new WranglerRoutesBuilder(options);
17
-
18
- // Load routing configuration from validation-config.json
19
- const routingConfig = frameworkConfig.getRoutingConfig();
20
- const templateDefaults = frameworkConfig.config.templates?.defaults || {};
21
- this.options = {
22
- // Routing defaults from config
23
- includeComments: routingConfig.defaults.includeComments,
24
- includeZoneId: routingConfig.defaults.includeZoneId,
25
- environment: routingConfig.defaults.targetEnvironment,
26
- // Map targetEnvironment -> environment
27
- orderStrategy: routingConfig.defaults.orderStrategy,
28
- // Domain configuration
29
- workersDomain: templateDefaults.WORKERS_DEV_DOMAIN || 'workers.dev',
30
- skipPatterns: routingConfig.domains.skipPatterns,
31
- // Allow runtime overrides
32
- ...options
33
- };
34
- }
35
-
36
- /**
37
- * Generate routes configuration for wrangler.toml
38
- *
39
- * @param {Object} coreInputs - Core service inputs (6 values)
40
- * @param {string} coreInputs.serviceName - Service name
41
- * @param {string} coreInputs.serviceType - Service type
42
- * @param {string} coreInputs.domainName - Domain name
43
- * @param {string} coreInputs.cloudflareAccountId - Cloudflare account ID
44
- * @param {string} coreInputs.cloudflareZoneId - Cloudflare zone ID (32 hex chars)
45
- * @param {string} coreInputs.environment - Environment (production|staging|development)
46
- *
47
- * @param {Object} confirmedValues - Confirmed configuration values (15 values)
48
- * @param {string} confirmedValues.productionUrl - Production URL (e.g., api.example.com)
49
- * @param {string} confirmedValues.stagingUrl - Staging URL (e.g., staging-api.example.com)
50
- * @param {string} confirmedValues.developmentUrl - Development URL (optional, defaults to workers.dev)
51
- * @param {string} confirmedValues.apiBasePath - API base path (e.g., /api)
52
- * @param {string} confirmedValues.workerName - Worker name
53
- *
54
- * @param {Object} options - Generation options
55
- * @param {boolean} options.includeComments - Include explanatory comments (default: true)
56
- * @param {boolean} options.includeZoneId - Include zone_id in routes (default: true)
57
- * @param {string} options.environment - Target environment filter (default: 'all')
58
- *
59
- * @returns {string} TOML-formatted routes configuration
60
- *
61
- * @throws {Error} If domain configuration is invalid or incomplete
62
- *
63
- * @example
64
- * const routeGenerator = new RouteGenerator();
65
- * const routesConfig = routeGenerator.generateRoutes(
66
- * {
67
- * serviceName: 'my-api',
68
- * domainName: 'example.com',
69
- * cloudflareZoneId: 'abc123...',
70
- * // ... other core inputs
71
- * },
72
- * {
73
- * productionUrl: 'api.example.com',
74
- * stagingUrl: 'staging-api.example.com',
75
- * apiBasePath: '/api',
76
- * // ... other confirmed values
77
- * }
78
- * );
79
- */
80
- generateRoutes(coreInputs, confirmedValues, options = {}) {
81
- // Merge options
82
- const opts = {
83
- ...this.options,
84
- ...options
85
- };
86
-
87
- // Validate inputs
88
- this.validateDomainConfig(coreInputs, confirmedValues);
89
-
90
- // Build domain configuration
91
- const domainConfig = {
92
- domains: {
93
- production: confirmedValues.productionUrl,
94
- staging: confirmedValues.stagingUrl,
95
- development: confirmedValues.developmentUrl
96
- },
97
- zoneId: coreInputs.cloudflareZoneId,
98
- apiBasePath: confirmedValues.apiBasePath,
99
- serviceName: coreInputs.serviceName,
100
- workerName: confirmedValues.workerName
101
- };
102
-
103
- // Generate routes for each environment
104
- const productionRoutes = this._generateEnvironmentRoutes(domainConfig, 'production', opts);
105
- const stagingRoutes = this._generateEnvironmentRoutes(domainConfig, 'staging', opts);
106
- const developmentRoutes = this._generateEnvironmentRoutes(domainConfig, 'development', opts);
107
-
108
- // Build complete routes section
109
- let routesSection = '';
110
-
111
- // Add header comment
112
- if (opts.includeComments) {
113
- routesSection += `# Routes configuration for ${domainConfig.serviceName}\n`;
114
- routesSection += `# Generated by Clodo Framework RouteGenerator\n`;
115
- routesSection += `# Generated: ${new Date().toISOString()}\n\n`;
116
- }
117
-
118
- // Add production routes (top-level)
119
- if (productionRoutes && (opts.environment === 'all' || opts.environment === 'production')) {
120
- routesSection += productionRoutes;
121
- }
122
-
123
- // Add staging routes
124
- if (stagingRoutes && (opts.environment === 'all' || opts.environment === 'staging')) {
125
- if (routesSection && !routesSection.endsWith('\n\n')) {
126
- routesSection += '\n';
127
- }
128
- routesSection += stagingRoutes;
129
- }
130
-
131
- // Add development routes (usually none - workers.dev)
132
- if (developmentRoutes && (opts.environment === 'all' || opts.environment === 'development')) {
133
- if (routesSection && !routesSection.endsWith('\n\n')) {
134
- routesSection += '\n';
135
- }
136
- routesSection += developmentRoutes;
137
- }
138
- return routesSection.trim() + '\n';
139
- }
140
-
141
- /**
142
- * Generate routes for a specific environment
143
- * @private
144
- */
145
- _generateEnvironmentRoutes(domainConfig, environment, options) {
146
- const domainUrl = domainConfig.domains[environment];
147
-
148
- // Skip if no domain configured or matches skip patterns
149
- if (!domainUrl || this._shouldSkipDomain(domainUrl)) {
150
- // workers.dev subdomain - no routes needed
151
- if (environment === 'development' && options.includeComments) {
152
- return this.builder.generateDevComment(domainConfig.workerName);
153
- }
154
- return '';
155
- }
156
-
157
- // Map domain to route patterns
158
- const routeMapping = this.mapper.mapDomainToRoutes(domainConfig, environment);
159
-
160
- // Build TOML routes section
161
- return this.builder.buildRoutesSection(routeMapping.patterns, environment, {
162
- zoneId: options.includeZoneId ? routeMapping.zoneId : null,
163
- includeComments: options.includeComments,
164
- domain: domainUrl,
165
- serviceName: domainConfig.serviceName
166
- });
167
- }
168
-
169
- /**
170
- * Validate domain configuration completeness
171
- *
172
- * @param {Object} coreInputs - Core service inputs
173
- * @param {Object} confirmedValues - Confirmed configuration values
174
- * @throws {Error} If validation fails
175
- */
176
- validateDomainConfig(coreInputs, confirmedValues) {
177
- // Check required coreInputs
178
- if (!coreInputs) {
179
- throw new Error('coreInputs is required for route generation');
180
- }
181
- if (!coreInputs.serviceName) {
182
- throw new Error('coreInputs.serviceName is required for route generation');
183
- }
184
- if (!coreInputs.cloudflareZoneId) {
185
- throw new Error('coreInputs.cloudflareZoneId is required for route generation');
186
- }
187
-
188
- // Validate zone_id format (32 hex characters)
189
- const zoneIdPattern = /^[a-f0-9]{32}$/;
190
- if (!zoneIdPattern.test(coreInputs.cloudflareZoneId)) {
191
- throw new Error('coreInputs.cloudflareZoneId must be a valid Cloudflare zone ID (32 hex characters). ' + `Received: "${coreInputs.cloudflareZoneId}"`);
192
- }
193
-
194
- // Check required confirmedValues
195
- if (!confirmedValues) {
196
- throw new Error('confirmedValues is required for route generation');
197
- }
198
- if (!confirmedValues.productionUrl) {
199
- throw new Error('confirmedValues.productionUrl is required for route generation');
200
- }
201
-
202
- // Validate production URL format
203
- if (!this._isValidDomain(confirmedValues.productionUrl)) {
204
- throw new Error('confirmedValues.productionUrl must be a valid domain name. ' + `Received: "${confirmedValues.productionUrl}"`);
205
- }
206
- }
207
-
208
- /**
209
- * Check if a string is a valid domain name
210
- * @private
211
- */
212
- _isValidDomain(domain) {
213
- if (!domain || typeof domain !== 'string') {
214
- return false;
215
- }
216
-
217
- // Basic domain validation
218
- const domainPattern = /^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?(\.[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/i;
219
- return domainPattern.test(domain);
220
- }
221
-
222
- /**
223
- * Get route patterns for a specific domain and environment
224
- *
225
- * @param {string} domain - Domain name (e.g., api.example.com)
226
- * @param {string} environment - Environment (production|staging|development)
227
- * @param {Object} options - Additional options
228
- * @returns {Array<string>} Array of route patterns
229
- *
230
- * @example
231
- * const patterns = routeGenerator.getRoutePatterns('api.example.com', 'production');
232
- * // Returns: ['api.example.com/*', 'example.com/api/*']
233
- */
234
- getRoutePatterns(domain, environment, options = {}) {
235
- const domainConfig = {
236
- domains: {
237
- [environment]: domain
238
- },
239
- zoneId: options.zoneId || 'placeholder',
240
- apiBasePath: options.apiBasePath,
241
- serviceName: options.serviceName || 'service'
242
- };
243
- const routeMapping = this.mapper.mapDomainToRoutes(domainConfig, environment);
244
- return routeMapping.patterns;
245
- }
246
-
247
- /**
248
- * Check if a domain should be skipped for route generation
249
- * @private
250
- *
251
- * @param {string} domain - Domain to check
252
- * @returns {boolean} True if domain should be skipped
253
- */
254
- _shouldSkipDomain(domain) {
255
- if (!domain) return true;
256
-
257
- // Check workers.dev domain
258
- if (domain.includes(this.options.workersDomain)) {
259
- return true;
260
- }
261
-
262
- // Check configured skip patterns
263
- const skipPatterns = this.options.skipPatterns || [];
264
- return skipPatterns.some(pattern => domain.includes(pattern));
265
- }
266
- }