@tamyla/clodo-framework 3.2.5 → 4.0.1

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 CHANGED
@@ -1,3 +1,44 @@
1
+ ## [4.0.1](https://github.com/tamylaa/clodo-framework/compare/v4.0.0...v4.0.1) (2025-12-07)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * Export COMMON_FEATURES and autoConfigureFramework, update docs ([6cf9a7e](https://github.com/tamylaa/clodo-framework/commit/6cf9a7e13c5b0b6dc10b69624e5633429890f894))
7
+
8
+ # [4.0.0](https://github.com/tamylaa/clodo-framework/compare/v3.2.5...v4.0.0) (2025-12-07)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * resolve remaining 5 import path issues in dist files ([383a625](https://github.com/tamylaa/clodo-framework/commit/383a6257910546f4d9a9f1442f4005c0cc166704))
14
+
15
+
16
+ ### Code Refactoring
17
+
18
+ * replace band-aid import fixes with proper wrapper pattern ([5385ef2](https://github.com/tamylaa/clodo-framework/commit/5385ef23e9a9b8be26fce9d9fe6df2184667168c))
19
+
20
+
21
+ ### BREAKING CHANGES
22
+
23
+ * from previous approach:
24
+ - Removed post-build path manipulation that was fragile and hard to maintain
25
+ - Implemented proper wrapper re-export pattern consistent with existing codebase
26
+
27
+ Changes:
28
+ - Create lib/shared/utils/framework-config.js wrapper that re-exports from src/utils
29
+ - Update connection-manager.js to import from ../utils/framework-config.js wrapper
30
+ - Update secret-generator.js to import from ../utils/framework-config.js wrapper
31
+ - Update graceful-shutdown-manager.js to import from ./framework-config.js wrapper
32
+ - Replace complex import path fixes with single minimal transformation in fix-dist-imports.js
33
+ - Maintains all 23 exports working correctly
34
+
35
+ Benefits:
36
+ Clean, maintainable architecture following existing wrapper patterns
37
+ No circular dependencies
38
+ Imports work correctly in both source and compiled dist/
39
+ Easier to debug and understand import resolution
40
+ Scales better as codebase grows
41
+
1
42
  ## [3.2.5](https://github.com/tamylaa/clodo-framework/compare/v3.2.4...v3.2.5) (2025-12-06)
2
43
 
3
44
 
package/README.md CHANGED
@@ -135,14 +135,14 @@ await orchestrator.createService({
135
135
 
136
136
  #### Service Enhancement
137
137
  ```javascript
138
- import { ServiceEnhancer } from '@tamyla/clodo-framework';
139
-
140
- // Add custom handler to existing service
141
- const enhancer = new ServiceEnhancer('./path/to/service');
142
- await enhancer.addHandler('customHandler', {
143
- method: 'POST',
144
- path: '/custom',
145
- handler: customLogic
138
+ import { ServiceCreator } from '@tamyla/clodo-framework';
139
+
140
+ // Create and configure a new service
141
+ const creator = new ServiceCreator();
142
+ await creator.createService({
143
+ serviceName: 'my-api-service',
144
+ serviceType: 'data-service',
145
+ domain: 'mycompany.com'
146
146
  });
147
147
  ```
148
148
 
@@ -1,5 +1,24 @@
1
1
  // Simple inline logger to avoid circular dependency with index.js
2
- import { validateRequired, deepMerge } from '../utils/index.js';
2
+ // Import only pure JS utilities (no Node.js dependencies)
3
+ const deepMerge = (target, source) => {
4
+ const result = {
5
+ ...target
6
+ };
7
+ for (const key in source) {
8
+ if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {
9
+ result[key] = deepMerge(result[key] || {}, source[key]);
10
+ } else {
11
+ result[key] = source[key];
12
+ }
13
+ }
14
+ return result;
15
+ };
16
+ const validateRequired = (obj, requiredFields) => {
17
+ const missing = requiredFields.filter(field => !obj[field]);
18
+ if (missing.length > 0) {
19
+ throw new Error(`Missing required fields: ${missing.join(', ')}`);
20
+ }
21
+ };
3
22
  const logger = {
4
23
  info: (message, ...args) => console.log(`[DomainConfig] ${message}`, ...args),
5
24
  error: (message, ...args) => console.error(`[DomainConfig] ${message}`, ...args),
@@ -128,7 +128,7 @@ export class DatabaseOrchestrator {
128
128
  // Import framework config for consistent timing and database settings
129
129
  const {
130
130
  frameworkConfig
131
- } = await import('../utils/framework-config.js');
131
+ } = await import('../lib/shared/utils/framework-config.js');
132
132
  const timing = frameworkConfig.getTiming();
133
133
  const database = frameworkConfig.getDatabaseConfig();
134
134
  const configPaths = frameworkConfig.getPaths();
@@ -1,6 +1,10 @@
1
1
  // Deployment Module
2
2
  // Core deployment components for the Clodo Framework
3
3
 
4
+ // Validation and Auditing
5
+ export { DeploymentValidator } from './validator.js';
6
+ export { DeploymentAuditor } from './auditor.js';
7
+
4
8
  // NOTE: WranglerDeployer has lib/ dependencies not available in npm distribution
5
9
  // export { WranglerDeployer } from './wrangler-deployer.js';
6
10
 
@@ -19,7 +19,7 @@
19
19
  * @abstract
20
20
  */
21
21
 
22
- import { ErrorHandler } from '../../../lib/shared/utils/ErrorHandler.js';
22
+ import { ErrorHandler } from '../../lib/shared/utils/ErrorHandler.js';
23
23
 
24
24
  /**
25
25
  * Phase state and execution order
@@ -36,7 +36,7 @@
36
36
  import { BaseDeploymentOrchestrator } from './BaseDeploymentOrchestrator.js';
37
37
  import { SingleServiceOrchestrator } from './SingleServiceOrchestrator.js';
38
38
  import { PortfolioOrchestrator } from './PortfolioOrchestrator.js';
39
- import { ErrorHandler } from '../../../lib/shared/utils/ErrorHandler.js';
39
+ import { ErrorHandler } from '../../lib/shared/utils/ErrorHandler.js';
40
40
 
41
41
  /**
42
42
  * Capability descriptors - Defines what each capability provides
package/dist/index.js CHANGED
@@ -13,6 +13,7 @@ export { default as Clodo, createService, deploy, validate, initialize, getInfo
13
13
  export { FeatureFlagManager } from './config/features.js';
14
14
  export { createDomainConfigSchema, validateDomainConfig, createDefaultDomainConfig } from './utils/domain-config.js';
15
15
  export { initializeService } from './worker/integration.js';
16
+ export { autoConfigureFramework } from './version/VersionDetector.js';
16
17
 
17
18
  // Core data and schema components
18
19
  export * from './services/GenericDataService.js';
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import { executeSql } from '../cloudflare/ops.js';
7
- import { ErrorRecoveryManager } from '../utils/index.js';
7
+ import { ErrorRecoveryManager, frameworkConfig } from '../utils/index.js';
8
8
  export class DatabaseConnectionManager {
9
9
  constructor(options = {}) {
10
10
  this.options = options;
@@ -18,10 +18,7 @@ export class DatabaseConnectionManager {
18
18
  * Initialize with framework configuration
19
19
  */
20
20
  async initialize() {
21
- // Import framework config for consistent database connection settings
22
- const {
23
- frameworkConfig
24
- } = await import('../../utils/framework-config.js');
21
+ // Use framework config for consistent database connection settings
25
22
  const timing = frameworkConfig.getTiming();
26
23
  const database = frameworkConfig.getDatabaseConfig();
27
24
  this.config = {
@@ -36,9 +33,6 @@ export class DatabaseConnectionManager {
36
33
  };
37
34
 
38
35
  // Initialize error recovery with loaded config
39
- const {
40
- ErrorRecoveryManager
41
- } = await import('../utils/index.js');
42
36
  this.errorRecovery = new ErrorRecoveryManager({
43
37
  maxRetries: this.config.maxRetries,
44
38
  retryDelay: this.config.retryDelay,
@@ -13,6 +13,7 @@ import { join, dirname } from 'path';
13
13
  import { fileURLToPath } from 'url';
14
14
  import { promisify } from 'util';
15
15
  import { logger } from '../logging/Logger.js';
16
+ import { frameworkConfig } from '../utils/framework-config.js';
16
17
  const execAsync = promisify(exec);
17
18
  const __filename = fileURLToPath(import.meta.url);
18
19
  const __dirname = dirname(__filename);
@@ -108,10 +109,7 @@ export class DatabaseOrchestrator {
108
109
  * Initialize with framework configuration
109
110
  */
110
111
  async initialize() {
111
- // Import framework config for consistent timing and database settings
112
- const {
113
- frameworkConfig
114
- } = await import('../../utils/framework-config.js');
112
+ // Use framework config for consistent timing and database settings
115
113
  const timing = frameworkConfig.getTiming();
116
114
  const database = frameworkConfig.getDatabaseConfig();
117
115
  this.config = {
@@ -15,6 +15,7 @@ import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync, statSy
15
15
  import { join, dirname } from 'path';
16
16
  import { execSync } from 'child_process';
17
17
  import { fileURLToPath } from 'url';
18
+ import { frameworkConfig } from '../utils/framework-config.js';
18
19
  const __dirname = (() => {
19
20
  try {
20
21
  const filename = fileURLToPath(import.meta.url);
@@ -107,10 +108,7 @@ export class EnhancedSecretManager {
107
108
  * Initialize with framework configuration
108
109
  */
109
110
  async initialize() {
110
- // Import framework config for consistent timing and retry settings
111
- const {
112
- frameworkConfig
113
- } = await import('../../utils/framework-config.js');
111
+ // Use framework config for consistent timing and retry settings
114
112
  const timing = frameworkConfig.getTiming();
115
113
  const security = frameworkConfig.getSecurity();
116
114
  const configPaths = frameworkConfig.getPaths();
@@ -8,6 +8,7 @@ import { join } from 'path';
8
8
  import { exec } from 'child_process';
9
9
  import { promisify } from 'util';
10
10
  import crypto from 'crypto';
11
+ import { frameworkConfig } from '../utils/framework-config.js';
11
12
  const execAsync = promisify(exec);
12
13
  export class SecureTokenManager {
13
14
  constructor(options = {}) {
@@ -34,9 +35,6 @@ export class SecureTokenManager {
34
35
  async initialize() {
35
36
  try {
36
37
  // Load framework configuration
37
- const {
38
- frameworkConfig
39
- } = await import('../../utils/framework-config.js');
40
38
  this.frameworkConfig = frameworkConfig;
41
39
 
42
40
  // Update paths with framework config
@@ -11,6 +11,7 @@
11
11
  * This is the canonical version. All imports should use this version.
12
12
  */
13
13
 
14
+ import { frameworkConfig } from './framework-config.js';
14
15
  export class ErrorRecoveryManager {
15
16
  constructor(options = {}) {
16
17
  this.options = options;
@@ -23,11 +24,8 @@ export class ErrorRecoveryManager {
23
24
  * Initialize with framework configuration
24
25
  */
25
26
  async initialize() {
26
- // Import framework config for consistent timing and retry settings
27
+ // Use framework config for consistent timing and retry settings
27
28
  try {
28
- const {
29
- frameworkConfig
30
- } = await import('./framework-config.js');
31
29
  const timing = frameworkConfig.getTiming();
32
30
  this.config = {
33
31
  maxRetries: this.options.maxRetries || timing.retryAttempts,
@@ -0,0 +1,567 @@
1
+ /**
2
+ * Enhanced Configuration Manager
3
+ * Centralized configuration loading and management for the Clodo Framework
4
+ *
5
+ * Replaces hardcoded values throughout the codebase with configurable settings
6
+ * from validation-config.json and environment variables
7
+ */
8
+
9
+ import { join, dirname } from 'path';
10
+ import { fileURLToPath } from 'url';
11
+ import { FileManager } from './file-manager.js';
12
+ export class FrameworkConfig {
13
+ constructor(configPath = null) {
14
+ this.fileManager = new FileManager({
15
+ enableCache: true
16
+ });
17
+ this.configPath = configPath || this.findConfigFile();
18
+ this.config = this.loadConfig();
19
+ this.environment = process.env.ENVIRONMENT || 'development';
20
+
21
+ // Validate environment variables on initialization
22
+ this.validateEnvironmentVariables();
23
+ }
24
+
25
+ /**
26
+ * Find the configuration file in standard locations
27
+ *
28
+ * For a packaged framework, we should only look within the framework's own directory
29
+ * to maintain self-containment. Users can explicitly pass config paths if needed.
30
+ */
31
+ findConfigFile() {
32
+ let __filename, __dirname;
33
+
34
+ // Get the framework's directory (works in both source and packaged environments)
35
+ try {
36
+ __filename = fileURLToPath(import.meta.url);
37
+ __dirname = dirname(__filename);
38
+ } catch (error) {
39
+ // Fallback for environments where import.meta is not available
40
+ // This should not happen in modern Node.js environments
41
+ console.warn('⚠️ Unable to determine framework directory, using current directory');
42
+ __dirname = process.cwd();
43
+ }
44
+
45
+ // Only look for config files within the framework's package directory
46
+ // This ensures the framework is self-contained and doesn't depend on user project files
47
+ const frameworkRoot = join(__dirname, '..', '..');
48
+ const possiblePaths = [join(frameworkRoot, 'validation-config.json'), join(frameworkRoot, 'config', 'validation-config.json'),
49
+ // Allow explicit config path via environment variable (for advanced users)
50
+ process.env.CLODO_FRAMEWORK_CONFIG && join(process.cwd(), process.env.CLODO_FRAMEWORK_CONFIG)].filter(Boolean); // Remove falsy values
51
+
52
+ for (const path of possiblePaths) {
53
+ if (this.fileManager.exists(path)) {
54
+ return path;
55
+ }
56
+ }
57
+
58
+ // Return null instead of throwing - will use default config
59
+ // This is expected behavior - services don't need their own config
60
+ return null;
61
+ }
62
+
63
+ /**
64
+ * Load and parse the configuration file
65
+ */
66
+ loadConfig() {
67
+ // If no config file found, return default configuration
68
+ // This is normal - services use framework defaults unless they need custom settings
69
+ if (!this.configPath) {
70
+ return this.getDefaultConfig();
71
+ }
72
+ try {
73
+ const configContent = this.fileManager.readFile(this.configPath, 'utf8');
74
+ const config = JSON.parse(configContent);
75
+ console.log(`📋 Loaded configuration from: ${this.configPath}`);
76
+ return config;
77
+ } catch (error) {
78
+ console.warn(`⚠️ Failed to load configuration from ${this.configPath}: ${error.message}`);
79
+ console.log('📋 Falling back to default configuration');
80
+ return this.getDefaultConfig();
81
+ }
82
+ }
83
+
84
+ /**
85
+ * Get default configuration when validation-config.json is not available
86
+ */
87
+ getDefaultConfig() {
88
+ return {
89
+ // Timing configuration (all in milliseconds)
90
+ deploymentTimeout: 30000,
91
+ retryAttempts: 3,
92
+ retryDelay: 1000,
93
+ connectionTimeout: 5000,
94
+ heartbeatInterval: 5000,
95
+ shutdownTimeout: 10000,
96
+ backupTimeout: 15000,
97
+ restoreTimeout: 20000,
98
+ migrationTimeout: 25000,
99
+ validationTimeout: 8000,
100
+ rollbackTimeout: 12000,
101
+ healthCheckInterval: 30000,
102
+ auditInterval: 60000,
103
+ cleanupInterval: 300000,
104
+ monitoringInterval: 15000,
105
+ alertThrottle: 5000,
106
+ // Network configuration
107
+ networking: {
108
+ maxConcurrentConnections: 10,
109
+ connectionPoolSize: 5,
110
+ requestTimeout: 30000,
111
+ maxRetries: 3,
112
+ retryDelay: 1000
113
+ },
114
+ // Database configuration
115
+ database: {
116
+ connectionTimeout: 10000,
117
+ queryTimeout: 30000,
118
+ transactionTimeout: 60000,
119
+ poolMin: 2,
120
+ poolMax: 10,
121
+ acquireTimeoutMillis: 60000,
122
+ createTimeoutMillis: 30000,
123
+ destroyTimeoutMillis: 5000,
124
+ idleTimeoutMillis: 30000,
125
+ reapIntervalMillis: 1000,
126
+ createRetryIntervalMillis: 200
127
+ },
128
+ // Environment configuration
129
+ environments: {
130
+ development: {
131
+ logLevel: 'debug',
132
+ debugMode: true,
133
+ dryRun: false
134
+ },
135
+ staging: {
136
+ logLevel: 'info',
137
+ debugMode: false,
138
+ dryRun: false
139
+ },
140
+ production: {
141
+ logLevel: 'warn',
142
+ debugMode: false,
143
+ dryRun: false
144
+ }
145
+ },
146
+ // Path configuration - all generated files go under generated/
147
+ paths: {
148
+ // Base generated directory
149
+ generated: process.env.FRAMEWORK_GENERATED_DIR || 'generated',
150
+ // Specific generated subdirectories
151
+ logs: process.env.FRAMEWORK_LOGS_DIR || 'generated/logs',
152
+ auditLogs: process.env.FRAMEWORK_AUDIT_DIR || 'generated/audit/logs',
153
+ backups: process.env.FRAMEWORK_BACKUP_DIR || 'generated/backups',
154
+ configCache: process.env.FRAMEWORK_CONFIG_CACHE_DIR || 'generated/cache/config',
155
+ secureTokens: process.env.FRAMEWORK_TOKEN_DIR || 'generated/cache/tokens',
156
+ auditReports: process.env.FRAMEWORK_REPORTS_DIR || 'generated/audit/reports',
157
+ testResults: process.env.FRAMEWORK_TEST_RESULTS_DIR || 'generated/test-results',
158
+ services: process.env.FRAMEWORK_SERVICES_DIR || 'generated/services',
159
+ temp: process.env.FRAMEWORK_TEMP_DIR || 'generated/temp'
160
+ }
161
+ };
162
+ }
163
+
164
+ /**
165
+ * Reload the configuration from file (useful for testing)
166
+ */
167
+ reload() {
168
+ this.config = this.loadConfig();
169
+ }
170
+
171
+ /**
172
+ * Get timing configuration with environment variable overrides
173
+ */
174
+ getTiming() {
175
+ const timing = this.config.timing || {};
176
+ return {
177
+ deploymentTimeout: parseInt(process.env.DEPLOYMENT_TIMEOUT) || timing.deploymentTimeout || 300000,
178
+ discoveryTimeout: parseInt(process.env.DISCOVERY_TIMEOUT) || timing.discoveryTimeout || 30000,
179
+ healthCheckTimeout: parseInt(process.env.HEALTH_CHECK_TIMEOUT) || timing.healthCheckTimeout || 10000,
180
+ productionTestTimeout: parseInt(process.env.PRODUCTION_TEST_TIMEOUT) || timing.productionTestTimeout || 30000,
181
+ shutdownTimeout: parseInt(process.env.SHUTDOWN_TIMEOUT) || timing.shutdownTimeout || 30000,
182
+ forceShutdownTimeout: parseInt(process.env.FORCE_SHUTDOWN_TIMEOUT) || timing.forceShutdownTimeout || 5000,
183
+ retryDelay: parseInt(process.env.RETRY_DELAY) || timing.retryDelay || 1000,
184
+ retryAttempts: parseInt(process.env.RETRY_ATTEMPTS) || timing.retryAttempts || 3,
185
+ cacheTTL: parseInt(process.env.CACHE_TTL) || timing.cacheTTL || 3600000,
186
+ maxAge: parseInt(process.env.MAX_AGE) || timing.maxAge || 86400000,
187
+ rateLimitWindow: parseInt(process.env.RATE_LIMIT_WINDOW) || timing.rateLimitWindow || 60000,
188
+ circuitBreakerTimeout: parseInt(process.env.CIRCUIT_BREAKER_TIMEOUT) || timing.circuitBreakerTimeout || 60000,
189
+ circuitBreakerThreshold: parseInt(process.env.CIRCUIT_BREAKER_THRESHOLD) || timing.circuitBreakerThreshold || 5,
190
+ deploymentInterval: parseInt(process.env.DEPLOYMENT_INTERVAL) || timing.deploymentInterval || 5000,
191
+ endpointValidationTimeout: parseInt(process.env.ENDPOINT_VALIDATION_TIMEOUT) || timing.endpointValidationTimeout || 5000,
192
+ maxConcurrentDeployments: parseInt(process.env.MAX_CONCURRENT_DEPLOYMENTS) || timing.maxConcurrentDeployments || 3
193
+ };
194
+ }
195
+
196
+ /**
197
+ * Get networking configuration
198
+ */
199
+ getNetworking() {
200
+ const networking = this.config.networking || {};
201
+ return {
202
+ endpoints: networking.endpoints || {},
203
+ development: networking.development || {},
204
+ rateLimiting: {
205
+ defaultRequests: parseInt(process.env.RATE_LIMIT_REQUESTS) || networking.rateLimiting?.defaultRequests || 100,
206
+ defaultWindow: parseInt(process.env.RATE_LIMIT_WINDOW_MS) || networking.rateLimiting?.defaultWindow || 60000,
207
+ burstLimit: parseInt(process.env.RATE_LIMIT_BURST) || networking.rateLimiting?.burstLimit || 200,
208
+ strictMode: process.env.RATE_LIMIT_STRICT === 'true' || networking.rateLimiting?.strictMode || false
209
+ }
210
+ };
211
+ }
212
+
213
+ /**
214
+ * Get database naming configuration
215
+ */
216
+ getDatabaseConfig() {
217
+ const database = this.config.database || {};
218
+ const naming = database.namingConvention || {};
219
+ return {
220
+ naming: {
221
+ development: naming.development || '{service}-dev',
222
+ staging: naming.staging || '{service}-staging',
223
+ production: naming.production || '{service}'
224
+ },
225
+ migration: database.migration || {},
226
+ connection: {
227
+ timeout: parseInt(process.env.DB_TIMEOUT) || database.connection?.timeout || 30000,
228
+ retryAttempts: parseInt(process.env.DB_RETRY_ATTEMPTS) || database.connection?.retryAttempts || 3,
229
+ poolSize: parseInt(process.env.DB_POOL_SIZE) || database.connection?.poolSize || 10
230
+ }
231
+ };
232
+ }
233
+
234
+ /**
235
+ * Get development ports configuration
236
+ */
237
+ getDevelopmentPorts() {
238
+ const networking = this.config.networking || {};
239
+ const development = networking.development || {};
240
+ const defaultPorts = development.defaultPorts || {};
241
+ return {
242
+ frontend: parseInt(process.env.FRONTEND_PORT) || defaultPorts.frontend || 3000,
243
+ api: parseInt(process.env.API_PORT) || defaultPorts.api || 8787,
244
+ worker: parseInt(process.env.WORKER_PORT) || defaultPorts.worker || 8787,
245
+ preview: parseInt(process.env.PREVIEW_PORT) || defaultPorts.preview || 8788
246
+ };
247
+ }
248
+
249
+ /**
250
+ * Get caching configuration
251
+ */
252
+ getCaching() {
253
+ const caching = this.config.caching || {};
254
+ return {
255
+ maxCacheSize: parseInt(process.env.MAX_CACHE_SIZE) || caching.maxCacheSize || 52428800,
256
+ compressionThreshold: parseInt(process.env.COMPRESSION_THRESHOLD) || caching.compressionThreshold || 1024,
257
+ cleanupInterval: parseInt(process.env.CLEANUP_INTERVAL) || caching.cleanupInterval || 3600000,
258
+ enableCompression: process.env.ENABLE_COMPRESSION === 'true' || caching.enableCompression || true,
259
+ maxEntries: parseInt(process.env.MAX_CACHE_ENTRIES) || caching.maxEntries || 1000
260
+ };
261
+ }
262
+
263
+ /**
264
+ * Get monitoring configuration
265
+ */
266
+ getMonitoring() {
267
+ const monitoring = this.config.monitoring || {};
268
+ return {
269
+ healthCheck: monitoring.healthCheck || {},
270
+ metrics: monitoring.metrics || {},
271
+ logging: monitoring.logging || {}
272
+ };
273
+ }
274
+
275
+ /**
276
+ * Get security configuration
277
+ */
278
+ getSecurity() {
279
+ const security = this.config.security || {};
280
+ return {
281
+ requiredEnvironmentVars: security.requiredEnvironmentVars || [],
282
+ optionalEnvironmentVars: security.optionalEnvironmentVars || [],
283
+ secretsConfig: security.secretsConfig || {}
284
+ };
285
+ }
286
+
287
+ /**
288
+ * Get path configuration with environment variable overrides
289
+ * All generated files are organized under the generated/ folder by default
290
+ */
291
+ getPaths() {
292
+ const paths = this.config.paths || {};
293
+ return {
294
+ // Base generated directory
295
+ generated: process.env.FRAMEWORK_GENERATED_DIR || paths.generated || 'generated',
296
+ // Specific generated subdirectories
297
+ logs: process.env.FRAMEWORK_LOGS_DIR || paths.logs || 'generated/logs',
298
+ auditLogs: process.env.FRAMEWORK_AUDIT_DIR || paths.auditLogs || 'generated/audit/logs',
299
+ backups: process.env.FRAMEWORK_BACKUP_DIR || paths.backups || 'generated/backups',
300
+ configCache: process.env.FRAMEWORK_CONFIG_CACHE_DIR || paths.configCache || 'generated/cache/config',
301
+ secureTokens: process.env.FRAMEWORK_TOKEN_DIR || paths.secureTokens || 'generated/cache/tokens',
302
+ auditReports: process.env.FRAMEWORK_REPORTS_DIR || paths.auditReports || 'generated/audit/reports',
303
+ testResults: process.env.FRAMEWORK_TEST_RESULTS_DIR || paths.testResults || 'generated/test-results',
304
+ services: process.env.FRAMEWORK_SERVICES_DIR || paths.services || 'generated/services',
305
+ temp: process.env.FRAMEWORK_TEMP_DIR || paths.temp || 'generated/temp'
306
+ };
307
+ }
308
+
309
+ /**
310
+ * Get a clean command for removing all generated files
311
+ */
312
+ getCleanupCommand() {
313
+ const paths = this.getPaths();
314
+ return `rm -rf ${paths.generated}`;
315
+ }
316
+
317
+ /**
318
+ * Get environment configuration with validation
319
+ */
320
+ getEnvironmentConfig(environment = null) {
321
+ const env = environment || this.environment;
322
+ const environments = this.config.environments || {};
323
+ const envConfig = environments[env] || environments.development || {};
324
+ if (!envConfig || Object.keys(envConfig).length === 0) {
325
+ console.warn(`⚠️ No configuration found for environment: ${env}. Using development defaults.`);
326
+ return {
327
+ domainTemplate: process.env.DOMAIN_TEMPLATE || '{service}.{domain}',
328
+ workerSuffix: process.env.WORKER_SUFFIX || '',
329
+ databaseSuffix: process.env.DATABASE_SUFFIX || '',
330
+ logLevel: this.validateLogLevel(process.env.LOG_LEVEL) || 'info',
331
+ enableMetrics: process.env.ENABLE_METRICS === 'true' || true,
332
+ strictValidation: process.env.STRICT_VALIDATION === 'true' || false,
333
+ debugMode: env === 'development',
334
+ dryRun: false
335
+ };
336
+ }
337
+ return {
338
+ domainTemplate: process.env.DOMAIN_TEMPLATE || envConfig.domainTemplate || '{service}.{domain}',
339
+ workerSuffix: process.env.WORKER_SUFFIX || envConfig.workerSuffix || '',
340
+ databaseSuffix: process.env.DATABASE_SUFFIX || envConfig.databaseSuffix || '',
341
+ logLevel: this.validateLogLevel(process.env.LOG_LEVEL) || this.validateLogLevel(envConfig.logLevel) || 'info',
342
+ enableMetrics: process.env.ENABLE_METRICS === 'true' || envConfig.enableMetrics || true,
343
+ strictValidation: process.env.STRICT_VALIDATION === 'true' || envConfig.strictValidation || false,
344
+ debugMode: envConfig.debugMode || false,
345
+ dryRun: envConfig.dryRun || false
346
+ };
347
+ }
348
+
349
+ /**
350
+ * Validate LOG_LEVEL environment variable
351
+ */
352
+ validateLogLevel(level) {
353
+ const validLevels = ['error', 'warn', 'info', 'debug', 'trace'];
354
+ if (!level) return null;
355
+ const normalizedLevel = level.toLowerCase();
356
+ if (!validLevels.includes(normalizedLevel)) {
357
+ console.warn(`⚠️ Invalid LOG_LEVEL "${level}". Valid values: ${validLevels.join(', ')}. Using 'info'.`);
358
+ return 'info';
359
+ }
360
+ return normalizedLevel;
361
+ }
362
+
363
+ /**
364
+ * Validate required environment variables
365
+ */
366
+ validateEnvironmentVariables() {
367
+ const errors = [];
368
+ const warnings = [];
369
+
370
+ // Validate LOG_LEVEL if present
371
+ if (process.env.LOG_LEVEL) {
372
+ this.validateLogLevel(process.env.LOG_LEVEL);
373
+ }
374
+
375
+ // Validate ENVIRONMENT if present
376
+ if (process.env.ENVIRONMENT) {
377
+ const validEnvironments = ['development', 'staging', 'production'];
378
+ if (!validEnvironments.includes(process.env.ENVIRONMENT)) {
379
+ warnings.push(`Invalid ENVIRONMENT "${process.env.ENVIRONMENT}". Valid values: ${validEnvironments.join(', ')}`);
380
+ }
381
+ }
382
+
383
+ // Validate framework-specific environment variables
384
+ const frameworkEnvVars = ['FRAMEWORK_LOGS_DIR', 'FRAMEWORK_AUDIT_DIR', 'FRAMEWORK_BACKUP_DIR', 'FRAMEWORK_CONFIG_CACHE_DIR', 'FRAMEWORK_TOKEN_DIR', 'FRAMEWORK_REPORTS_DIR'];
385
+ frameworkEnvVars.forEach(varName => {
386
+ if (process.env[varName]) {
387
+ // Validate path doesn't contain dangerous characters
388
+ const value = process.env[varName];
389
+ if (value.includes('..') || value.includes('~')) {
390
+ warnings.push(`Environment variable ${varName} contains potentially dangerous path: ${value}`);
391
+ }
392
+ }
393
+ });
394
+
395
+ // Log validation results
396
+ if (warnings.length > 0) {
397
+ console.warn('⚠️ Environment variable validation warnings:');
398
+ warnings.forEach(warning => console.warn(` - ${warning}`));
399
+ }
400
+ if (errors.length > 0) {
401
+ console.error('❌ Environment variable validation errors:');
402
+ errors.forEach(error => console.error(` - ${error}`));
403
+ throw new Error('Environment variable validation failed');
404
+ }
405
+ if (warnings.length === 0 && errors.length === 0) {
406
+ console.log('✅ Environment variables validated successfully');
407
+ }
408
+ return {
409
+ errors,
410
+ warnings
411
+ };
412
+ }
413
+
414
+ /**
415
+ * Get testing configuration
416
+ */
417
+ getTesting() {
418
+ const testing = this.config.testing || {};
419
+ return {
420
+ production: {
421
+ enabled: process.env.PRODUCTION_TESTS === 'true' || testing.production?.enabled || true,
422
+ lightweight: process.env.LIGHTWEIGHT_TESTS === 'true' || testing.production?.lightweight || true,
423
+ skipHeavyTests: process.env.SKIP_HEAVY_TESTS === 'true' || testing.production?.skipHeavyTests || true,
424
+ generateReports: process.env.GENERATE_REPORTS === 'true' || testing.production?.generateReports || false,
425
+ testTimeout: parseInt(process.env.TEST_TIMEOUT) || testing.production?.testTimeout || 30000
426
+ },
427
+ integration: testing.integration || {}
428
+ };
429
+ }
430
+
431
+ /**
432
+ * Generate database name based on service and environment
433
+ */
434
+ generateDatabaseName(serviceName, environment = this.environment) {
435
+ const dbConfig = this.getDatabaseConfig();
436
+ const template = dbConfig.naming[environment] || dbConfig.naming.production || '{service}';
437
+ return template.replace('{service}', serviceName);
438
+ }
439
+
440
+ /**
441
+ * Generate development URLs based on service and configuration
442
+ */
443
+ generateDevelopmentUrls(serviceName) {
444
+ const ports = this.getDevelopmentPorts();
445
+ return {
446
+ frontend: `http://localhost:${ports.frontend}`,
447
+ api: `http://localhost:${ports.api}`,
448
+ worker: `http://localhost:${ports.worker}`,
449
+ preview: `http://localhost:${ports.preview}`
450
+ };
451
+ }
452
+
453
+ /**
454
+ * Validate environment variables
455
+ */
456
+ validateEnvironment() {
457
+ const security = this.getSecurity();
458
+ const missing = [];
459
+ for (const envVar of security.requiredEnvironmentVars) {
460
+ if (!process.env[envVar]) {
461
+ missing.push(envVar);
462
+ }
463
+ }
464
+ if (missing.length > 0) {
465
+ throw new Error(`Missing required environment variables: ${missing.join(', ')}`);
466
+ }
467
+ return true;
468
+ }
469
+
470
+ /**
471
+ * Get routing configuration
472
+ * Provides route generation settings from validation-config.json
473
+ */
474
+ getRoutingConfig() {
475
+ const routing = this.config.routing || {};
476
+ const templates = this.config.templates || {};
477
+ const workersDomain = templates.defaults?.WORKERS_DEV_DOMAIN || 'workers.dev';
478
+ return {
479
+ defaults: {
480
+ includeComments: routing.defaults?.includeComments !== false,
481
+ includeZoneId: routing.defaults?.includeZoneId !== false,
482
+ targetEnvironment: routing.defaults?.targetEnvironment || 'all',
483
+ orderStrategy: routing.defaults?.orderStrategy || 'most-specific-first'
484
+ },
485
+ domains: {
486
+ skipPatterns: routing.domains?.skipPatterns || [],
487
+ workersDomain,
488
+ // Reuse from templates.defaults.WORKERS_DEV_DOMAIN
489
+ complexTLDs: routing.domains?.complexTLDs || ['.co.uk', '.com.au', '.org.uk', '.gov.uk'],
490
+ subdomainMinParts: routing.domains?.subdomainMinParts || 3,
491
+ ignoreSubdomains: routing.domains?.ignoreSubdomains || ['www']
492
+ },
493
+ validation: {
494
+ zoneIdPattern: routing.validation?.zoneIdPattern || '^[a-f0-9]{32}$',
495
+ domainPattern: routing.validation?.domainPattern || '^[a-z0-9.-]+$',
496
+ strictMode: routing.validation?.strictMode !== false
497
+ },
498
+ comments: {
499
+ enabled: routing.comments?.enabled !== false,
500
+ templates: routing.comments?.templates || {
501
+ production: '# Production environment routes\n# Domain: {{domain}}',
502
+ staging: '# Staging environment routes\n# Domain: {{domain}}',
503
+ development: '# Development environment\n# Uses {{WORKERS_DEV_DOMAIN}} subdomain'
504
+ }
505
+ }
506
+ };
507
+ }
508
+
509
+ /**
510
+ * Get environment-specific routing configuration
511
+ * Combines global routing config with environment-specific settings
512
+ */
513
+ getEnvironmentRoutingConfig(environment = null) {
514
+ const env = environment || this.environment;
515
+ const environments = this.config.environments || {};
516
+ const envConfig = environments[env] || environments.development || {};
517
+ const routingConfig = envConfig.routing || {};
518
+
519
+ // Fallback defaults if not in config
520
+ const defaultPrefixes = {
521
+ development: '/dev-api',
522
+ staging: '/staging-api',
523
+ production: '/api'
524
+ };
525
+ return {
526
+ defaultPathPrefix: routingConfig.defaultPathPrefix || defaultPrefixes[env] || '/api',
527
+ wildcardPattern: routingConfig.wildcardPattern || '/*',
528
+ generateFallbackRoute: routingConfig.generateFallbackRoute !== false,
529
+ nestedInToml: env !== 'production' && routingConfig.nestedInToml !== false
530
+ };
531
+ }
532
+
533
+ /**
534
+ * Get all environment names from config
535
+ */
536
+ getEnvironmentNames() {
537
+ const environments = this.config.environments || {};
538
+ return Object.keys(environments).length > 0 ? Object.keys(environments) : ['development', 'staging', 'production'];
539
+ }
540
+
541
+ /**
542
+ * Get aggregated configuration for all needs
543
+ */
544
+ getAll() {
545
+ return {
546
+ timing: this.getTiming(),
547
+ networking: this.getNetworking(),
548
+ environment: this.getEnvironmentConfig(),
549
+ database: this.getDatabaseConfig(),
550
+ ports: this.getDevelopmentPorts(),
551
+ caching: this.getCaching(),
552
+ monitoring: this.getMonitoring(),
553
+ security: this.getSecurity(),
554
+ testing: this.getTesting(),
555
+ routing: this.getRoutingConfig()
556
+ };
557
+ }
558
+ }
559
+
560
+ // Export singleton instance for easy access
561
+ export const frameworkConfig = new FrameworkConfig();
562
+
563
+ // Export utility functions
564
+ export const getFrameworkConfig = (configPath = null) => {
565
+ return configPath ? new FrameworkConfig(configPath) : frameworkConfig;
566
+ };
567
+ export default FrameworkConfig;
@@ -3,6 +3,7 @@
3
3
  * Implements SIGTERM/SIGINT handlers and cleanup routines for CLI tools
4
4
  */
5
5
 
6
+ import { frameworkConfig } from './framework-config.js';
6
7
  export class GracefulShutdownManager {
7
8
  constructor(options = {}) {
8
9
  this.options = options;
@@ -17,10 +18,7 @@ export class GracefulShutdownManager {
17
18
  * Initialize with framework configuration
18
19
  */
19
20
  async initialize() {
20
- // Import framework config for consistent timing settings
21
- const {
22
- frameworkConfig
23
- } = await import('../../utils/framework-config.js');
21
+ // Use framework config for consistent timing settings
24
22
  const timing = frameworkConfig.getTiming();
25
23
  this.config = {
26
24
  shutdownTimeout: this.options.shutdownTimeout || timing.shutdownTimeout,
@@ -28,4 +28,7 @@ export { validateDeploymentPrerequisites, validateDeploymentInputs } from './dep
28
28
  export { redactSensitiveInfo, redactSensitiveObject } from './sensitive-redactor.js';
29
29
 
30
30
  // Configuration loading
31
- export { ConfigLoader } from './config-loader.js';
31
+ export { ConfigLoader } from './config-loader.js';
32
+
33
+ // Framework configuration
34
+ export { FrameworkConfig, frameworkConfig, getFrameworkConfig } from './framework-config.js';
@@ -6,11 +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 { SecurityCLI } from './SecurityCLI.js';
9
10
  // InteractiveDeploymentConfigurator removed - replaced by InputCollector
10
11
 
11
12
  export { ConfigurationValidator } from './ConfigurationValidator.js';
12
- // export { DeploymentManager } - DEPRECATED: Use MultiDomainOrchestrator instead
13
+ // export { DeploymentManager} - DEPRECATED: Use MultiDomainOrchestrator instead
13
14
  export { SecretGenerator } from './SecretGenerator.js';
15
+ export { SecurityCLI } from './SecurityCLI.js';
14
16
  // export { InteractiveDeploymentConfigurator } - DEPRECATED: Use InputCollector instead
15
17
 
16
18
  // Re-export patterns and rules for advanced usage
@@ -5,12 +5,49 @@
5
5
 
6
6
  import fs from 'fs/promises';
7
7
  import path from 'path';
8
+ import { FrameworkConfig } from '../../utils/framework-config.js';
8
9
  export class ValidationHandler {
9
10
  constructor(options = {}) {
10
11
  this.strict = options.strict || false;
11
12
  this.customConfig = options.customConfig || {};
13
+ this.configLoaded = false;
14
+ }
15
+
16
+ /**
17
+ * Load validation configuration from validation-config.json if it exists
18
+ */
19
+ loadValidationConfig(servicePath) {
20
+ // Skip if already loaded or custom config provided
21
+ if (this.configLoaded || Object.keys(this.customConfig).length > 0) {
22
+ return this.validationConfig;
23
+ }
24
+ try {
25
+ // Try to load validation-config.json from service directory
26
+ const configPath = path.join(servicePath, 'validation-config.json');
27
+ const frameworkConfig = new FrameworkConfig(configPath);
28
+ const config = frameworkConfig.config;
29
+
30
+ // Extract validation section from config
31
+ if (config && config.validation) {
32
+ // Log that we loaded the config
33
+ console.log(`📋 Loaded configuration from: ${configPath}`);
34
+ this.validationConfig = {
35
+ requiredFiles: config.validation.requiredFiles || ['package.json', 'src/config/domains.js', 'src/worker/index.js', 'wrangler.toml'],
36
+ optionalFiles: config.validation.optionalFiles || ['README.md', 'LICENSE', '.gitignore'],
37
+ requiredFields: config.validation.requiredFields || {
38
+ 'package.json': ['name', 'version', 'type', 'main'],
39
+ 'wrangler.toml': ['name', 'main', 'compatibility_date']
40
+ },
41
+ serviceTypes: config.validation.serviceTypes || ['data-service', 'auth-service', 'content-service', 'api-gateway', 'static-site', 'generic']
42
+ };
43
+ this.configLoaded = true;
44
+ return this.validationConfig;
45
+ }
46
+ } catch (error) {
47
+ // Config loading failed, use defaults silently
48
+ }
12
49
 
13
- // Use custom validation config if provided, otherwise use defaults
50
+ // Use custom config if provided, otherwise use defaults
14
51
  this.validationConfig = {
15
52
  requiredFiles: this.customConfig.requiredFiles || ['package.json', 'src/config/domains.js', 'src/worker/index.js', 'wrangler.toml'],
16
53
  optionalFiles: this.customConfig.optionalFiles || ['README.md', 'LICENSE', '.gitignore'],
@@ -20,12 +57,16 @@ export class ValidationHandler {
20
57
  },
21
58
  serviceTypes: this.customConfig.serviceTypes || ['data-service', 'auth-service', 'content-service', 'api-gateway', 'static-site', 'generic']
22
59
  };
60
+ this.configLoaded = true;
61
+ return this.validationConfig;
23
62
  }
24
63
 
25
64
  /**
26
65
  * Validate complete service configuration
27
66
  */
28
67
  async validateService(servicePath) {
68
+ // Load validation config from validation-config.json if it exists
69
+ this.loadValidationConfig(servicePath);
29
70
  const issues = [];
30
71
 
31
72
  // Check for required files using custom config
@@ -7,7 +7,7 @@
7
7
  * @module service-management/routing/DomainRouteMapper
8
8
  */
9
9
 
10
- import { frameworkConfig } from '../../utils/framework-config.js';
10
+ import { frameworkConfig } from '../../lib/shared/utils/framework-config.js';
11
11
  export class DomainRouteMapper {
12
12
  constructor(options = {}) {
13
13
  // Load environment-specific routing config
@@ -9,7 +9,7 @@
9
9
 
10
10
  import { DomainRouteMapper } from './DomainRouteMapper.js';
11
11
  import { WranglerRoutesBuilder } from './WranglerRoutesBuilder.js';
12
- import { frameworkConfig } from '../../utils/framework-config.js';
12
+ import { frameworkConfig } from '../../lib/shared/utils/framework-config.js';
13
13
  export class RouteGenerator {
14
14
  constructor(options = {}) {
15
15
  this.mapper = new DomainRouteMapper(options);
@@ -21,7 +21,7 @@ import { access, readFile, writeFile, mkdir, readdir, stat } from 'fs/promises';
21
21
  import { join, dirname } from 'path';
22
22
  import { promisify } from 'util';
23
23
  import { exec } from 'child_process';
24
- import { frameworkConfig } from '../framework-config.js';
24
+ import { frameworkConfig } from '../../lib/shared/utils/framework-config.js';
25
25
  import { NameFormatters } from '../formatters.js';
26
26
  const execAsync = promisify(exec);
27
27
  export class ConfigurationCacheManager {
@@ -5,4 +5,4 @@ export { ConfigurationCacheManager } from './config-cache.js';
5
5
  export { EnhancedSecretManager } from './secret-generator.js';
6
6
  export { UnifiedConfigManager, unifiedConfigManager } from '../config/unified-config-manager.js';
7
7
  export { askUser, askYesNo, askChoice, closePrompts } from '../interactive-prompts.js';
8
- export { DeploymentCredentialCollector } from '../../../lib/shared/deployment/credential-collector.js';
8
+ export { DeploymentCredentialCollector } from '../../lib/shared/deployment/credential-collector.js';
@@ -1,10 +1,10 @@
1
1
  /**
2
- * Enhanced Configuration Manager
3
- * Centralized configuration loading and management for the Clodo Framework
4
- *
5
- * Replaces hardcoded values throughout the codebase with configurable settings
6
- * from validation-config.json and environment variables
7
- */
2
+ * Enhanced Configuration Manager
3
+ * Centralized configuration loading and management for the Clodo Framework
4
+ *
5
+ * Replaces hardcoded values throughout the codebase with configurable settings
6
+ * from validation-config.json and environment variables
7
+ */
8
8
 
9
9
  import { join, dirname } from 'path';
10
10
  import { fileURLToPath } from 'url';
@@ -17,10 +17,10 @@ export class GracefulShutdownManager {
17
17
  * Initialize with framework configuration
18
18
  */
19
19
  async initialize() {
20
- // Import framework config for consistent timing
20
+ // Import framework config for consistent timing settings
21
21
  const {
22
22
  frameworkConfig
23
- } = await import('./framework-config.js');
23
+ } = await import('../lib/shared/utils/framework-config.js');
24
24
  const timing = frameworkConfig.getTiming();
25
25
  this.config = {
26
26
  shutdownTimeout: this.options.shutdownTimeout || timing.shutdownTimeout,
@@ -35,8 +35,8 @@ export * from './validation.js';
35
35
  // Health checking utilities
36
36
  export * from './health-checker.js';
37
37
 
38
- // Framework configuration
39
- export * from './framework-config.js';
38
+ // Framework configuration - re-export from canonical location
39
+ export { FrameworkConfig, frameworkConfig, getFrameworkConfig } from '../lib/shared/utils/framework-config.js';
40
40
 
41
41
  // Deployment utilities
42
42
  export * from './deployment/index.js';
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Common Feature Constants
3
+ * Worker-safe constants extracted from ConfigurationManager
4
+ * No Node.js dependencies (fs, path, etc.)
5
+ */
6
+
7
+ export const COMMON_FEATURES = {
8
+ // Schema Manager Features
9
+ ENABLE_ENHANCED_SCHEMA: true,
10
+ ENABLE_SCHEMA_CACHING: true,
11
+ ENABLE_COMPREHENSIVE_VALIDATION: true,
12
+ ENABLE_SQL_CACHING: true,
13
+ // Generic Data Service Features
14
+ ENABLE_QUERY_CACHING: true,
15
+ ENABLE_SECURITY_CONTROLS: true,
16
+ ENABLE_ADVANCED_PAGINATION: true,
17
+ ENABLE_RELATIONSHIP_LOADING: true,
18
+ // Module Manager Features
19
+ ENABLE_ENHANCED_HOOKS: true,
20
+ ENABLE_HOOK_TIMEOUT: true,
21
+ ENABLE_HOOK_METRICS: true,
22
+ ENABLE_PARALLEL_EXECUTION: true,
23
+ // Performance Features
24
+ ENABLE_PERFORMANCE_MONITORING: true,
25
+ ENABLE_CACHE_METRICS: true,
26
+ ENABLE_QUERY_OPTIMIZATION: true,
27
+ // Development Features
28
+ ENABLE_DEBUG_LOGGING: false,
29
+ ENABLE_DEVELOPMENT_MODE: false,
30
+ ENABLE_STRICT_VALIDATION: false,
31
+ // Migration Features
32
+ ENABLE_LEGACY_COMPATIBILITY: true,
33
+ ENABLE_DEPRECATION_WARNINGS: true,
34
+ ENABLE_MIGRATION_HELPERS: true,
35
+ // Domain-specific features
36
+ AUTHENTICATION: true,
37
+ AUTHORIZATION: true,
38
+ LOGGING: true,
39
+ MONITORING: true,
40
+ CACHING: true,
41
+ RATE_LIMITING: true,
42
+ FILE_STORAGE: true
43
+ };
@@ -1,13 +1,16 @@
1
1
  import { getDomainFromEnv, createEnvironmentConfig } from '../config/domains.js';
2
2
 
3
- // Import COMMON_FEATURES from ConfigurationManager
4
- import { COMMON_FEATURES } from '../../lib/shared/config/ConfigurationManager.js';
3
+ // Import COMMON_FEATURES from worker-safe constants (no Node.js dependencies)
4
+ import { COMMON_FEATURES } from './features.js';
5
+
6
+ // Re-export COMMON_FEATURES for use in worker templates
7
+ export { COMMON_FEATURES };
5
8
 
6
9
  // Simple feature manager interface (replaces ConfigurationManager dependency)
7
10
  export const configManager = {
8
11
  setDomain: () => {},
9
- getEnabledFeatures: () => Object.values(COMMON_FEATURES),
10
- isFeatureEnabled: feature => Object.values(COMMON_FEATURES).includes(feature)
12
+ getEnabledFeatures: () => Object.keys(COMMON_FEATURES).filter(key => COMMON_FEATURES[key]),
13
+ isFeatureEnabled: feature => COMMON_FEATURES[feature] === true
11
14
  };
12
15
 
13
16
  // Legacy featureManager compatibility interface
@@ -185,7 +188,7 @@ export const createRateLimitGuard = (options = {}) => {
185
188
  return handler => {
186
189
  return async (request, env, ctx) => {
187
190
  // Skip rate limiting if feature is disabled
188
- if (!featureManager.isEnabled(COMMON_FEATURES.RATE_LIMITING)) {
191
+ if (!featureManager.isEnabled('RATE_LIMITING')) {
189
192
  return handler(request, env, ctx);
190
193
  }
191
194
  const clientId = request.headers.get('CF-Connecting-IP') || 'anonymous';
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Worker Entry Point
3
+ * Minimal exports for Cloudflare Workers - excludes CLI/Node.js dependencies
4
+ *
5
+ * This is the entry point for wrangler.toml
6
+ * Only exports worker-compatible code (no fs, path, child_process, etc.)
7
+ */
8
+
9
+ // Worker integration (no Node.js dependencies)
10
+ export { initializeService, configManager } from './worker/integration.js';
11
+
12
+ // Domain configuration (pure JS, no fs dependencies)
13
+ export { getDomainFromEnv, createEnvironmentConfig } from './config/domains.js';
14
+
15
+ // Framework version
16
+ export const FRAMEWORK_VERSION = '1.0.0';
17
+
18
+ // Default export for module worker format
19
+ export default {
20
+ async fetch(request, env, ctx) {
21
+ return new Response('Clodo Framework Worker - Use initializeService() to set up your worker', {
22
+ status: 200,
23
+ headers: {
24
+ 'content-type': 'text/plain'
25
+ }
26
+ });
27
+ }
28
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tamyla/clodo-framework",
3
- "version": "3.2.5",
3
+ "version": "4.0.1",
4
4
  "description": "Reusable framework for Clodo-style software architecture on Cloudflare Workers + D1",
5
5
  "type": "module",
6
6
  "sideEffects": [
@@ -88,6 +88,8 @@
88
88
  "test:worker": "cross-env NODE_OPTIONS=--experimental-vm-modules jest test/worker/ --verbose",
89
89
  "test:integration": "cross-env NODE_OPTIONS=--experimental-vm-modules jest test/integration/ --verbose",
90
90
  "test:comprehensive": "cross-env NODE_OPTIONS=--experimental-vm-modules jest test/comprehensive-suite.spec.js --verbose",
91
+ "test:package": "node scripts/test-package.js",
92
+ "prepublishOnly": "npm run build:ci",
91
93
  "test:coverage:cli": "cross-env NODE_OPTIONS=--experimental-vm-modules jest test/cli-integration/ --coverage",
92
94
  "test:coverage:deployment": "cross-env NODE_OPTIONS=--experimental-vm-modules jest test/deployment/ test/deployment-security.spec.js --coverage",
93
95
  "test:coverage:services": "cross-env NODE_OPTIONS=--experimental-vm-modules jest test/service-management/ test/services/ --coverage",
@@ -101,7 +103,6 @@
101
103
  "analyze:bundle": "echo 'Bundle analysis not implemented yet'",
102
104
  "docs": "echo 'JSDoc documentation generation not configured yet'",
103
105
  "validate": "npm run check:all",
104
- "prepublishOnly": "npm run build:ci",
105
106
  "postpublish": "echo 'Published successfully to npm registry!'",
106
107
  "publish:beta": "npm publish --tag beta",
107
108
  "publish:latest": "npm publish --tag latest",