@morojs/moro 1.5.5 → 1.5.7

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 (70) hide show
  1. package/dist/core/config/config-manager.d.ts +44 -0
  2. package/dist/core/config/config-manager.js +114 -0
  3. package/dist/core/config/config-manager.js.map +1 -0
  4. package/dist/core/config/config-sources.d.ts +21 -0
  5. package/dist/core/config/config-sources.js +314 -0
  6. package/dist/core/config/config-sources.js.map +1 -0
  7. package/dist/core/config/config-validator.d.ts +21 -0
  8. package/dist/core/config/config-validator.js +744 -0
  9. package/dist/core/config/config-validator.js.map +1 -0
  10. package/dist/core/config/file-loader.d.ts +0 -5
  11. package/dist/core/config/file-loader.js +0 -171
  12. package/dist/core/config/file-loader.js.map +1 -1
  13. package/dist/core/config/index.d.ts +39 -10
  14. package/dist/core/config/index.js +66 -29
  15. package/dist/core/config/index.js.map +1 -1
  16. package/dist/core/config/schema.js +29 -31
  17. package/dist/core/config/schema.js.map +1 -1
  18. package/dist/core/config/utils.d.ts +9 -2
  19. package/dist/core/config/utils.js +19 -32
  20. package/dist/core/config/utils.js.map +1 -1
  21. package/dist/core/framework.d.ts +4 -7
  22. package/dist/core/framework.js +38 -12
  23. package/dist/core/framework.js.map +1 -1
  24. package/dist/core/http/http-server.d.ts +12 -0
  25. package/dist/core/http/http-server.js +56 -0
  26. package/dist/core/http/http-server.js.map +1 -1
  27. package/dist/core/http/router.d.ts +12 -0
  28. package/dist/core/http/router.js +114 -36
  29. package/dist/core/http/router.js.map +1 -1
  30. package/dist/core/logger/index.d.ts +1 -1
  31. package/dist/core/logger/index.js +2 -1
  32. package/dist/core/logger/index.js.map +1 -1
  33. package/dist/core/logger/logger.d.ts +9 -1
  34. package/dist/core/logger/logger.js +36 -3
  35. package/dist/core/logger/logger.js.map +1 -1
  36. package/dist/core/routing/index.d.ts +20 -0
  37. package/dist/core/routing/index.js +109 -11
  38. package/dist/core/routing/index.js.map +1 -1
  39. package/dist/moro.d.ts +7 -20
  40. package/dist/moro.js +115 -200
  41. package/dist/moro.js.map +1 -1
  42. package/dist/types/config.d.ts +46 -2
  43. package/dist/types/core.d.ts +22 -39
  44. package/dist/types/logger.d.ts +4 -0
  45. package/package.json +1 -1
  46. package/src/core/config/config-manager.ts +133 -0
  47. package/src/core/config/config-sources.ts +384 -0
  48. package/src/core/config/config-validator.ts +1042 -0
  49. package/src/core/config/file-loader.ts +0 -233
  50. package/src/core/config/index.ts +77 -32
  51. package/src/core/config/schema.ts +29 -31
  52. package/src/core/config/utils.ts +22 -29
  53. package/src/core/framework.ts +51 -18
  54. package/src/core/http/http-server.ts +66 -0
  55. package/src/core/http/router.ts +127 -38
  56. package/src/core/logger/index.ts +1 -0
  57. package/src/core/logger/logger.ts +43 -4
  58. package/src/core/routing/index.ts +116 -12
  59. package/src/moro.ts +127 -233
  60. package/src/types/config.ts +47 -2
  61. package/src/types/core.ts +32 -43
  62. package/src/types/logger.ts +6 -0
  63. package/dist/core/config/loader.d.ts +0 -7
  64. package/dist/core/config/loader.js +0 -269
  65. package/dist/core/config/loader.js.map +0 -1
  66. package/dist/core/config/validation.d.ts +0 -17
  67. package/dist/core/config/validation.js +0 -131
  68. package/dist/core/config/validation.js.map +0 -1
  69. package/src/core/config/loader.ts +0 -633
  70. package/src/core/config/validation.ts +0 -140
@@ -172,236 +172,3 @@ async function setupTypeScriptLoader(): Promise<void> {
172
172
  // the TypeScript transpilation is already handled by those tools.
173
173
  logger.debug('TypeScript config loading delegated to runtime environment');
174
174
  }
175
-
176
- /**
177
- * Convert a configuration object to environment variable mappings
178
- * This function flattens the config object and sets corresponding environment variables
179
- */
180
- export function applyConfigAsEnvironmentVariables(config: Partial<AppConfig>): void {
181
- if (!config || typeof config !== 'object') {
182
- return;
183
- }
184
-
185
- // Apply server configuration
186
- if (config.server) {
187
- setEnvIfNotSet('PORT', config.server.port?.toString());
188
- setEnvIfNotSet('HOST', config.server.host);
189
- setEnvIfNotSet('NODE_ENV', config.server.environment);
190
- setEnvIfNotSet('MAX_CONNECTIONS', config.server.maxConnections?.toString());
191
- setEnvIfNotSet('REQUEST_TIMEOUT', config.server.timeout?.toString());
192
- }
193
-
194
- // Apply database configuration
195
- if (config.database) {
196
- setEnvIfNotSet('DATABASE_URL', config.database.url);
197
-
198
- if (config.database.redis) {
199
- setEnvIfNotSet('REDIS_URL', config.database.redis.url);
200
- setEnvIfNotSet('REDIS_MAX_RETRIES', config.database.redis.maxRetries?.toString());
201
- setEnvIfNotSet('REDIS_RETRY_DELAY', config.database.redis.retryDelay?.toString());
202
- setEnvIfNotSet('REDIS_KEY_PREFIX', config.database.redis.keyPrefix);
203
- }
204
-
205
- if (config.database.mysql) {
206
- setEnvIfNotSet('MYSQL_HOST', config.database.mysql.host);
207
- setEnvIfNotSet('MYSQL_PORT', config.database.mysql.port?.toString());
208
- setEnvIfNotSet('MYSQL_DATABASE', config.database.mysql.database);
209
- setEnvIfNotSet('MYSQL_USERNAME', config.database.mysql.username);
210
- setEnvIfNotSet('MYSQL_PASSWORD', config.database.mysql.password);
211
- setEnvIfNotSet('MYSQL_CONNECTION_LIMIT', config.database.mysql.connectionLimit?.toString());
212
- setEnvIfNotSet('MYSQL_ACQUIRE_TIMEOUT', config.database.mysql.acquireTimeout?.toString());
213
- setEnvIfNotSet('MYSQL_TIMEOUT', config.database.mysql.timeout?.toString());
214
- }
215
- }
216
-
217
- // Apply service discovery configuration
218
- if (config.serviceDiscovery) {
219
- setEnvIfNotSet('SERVICE_DISCOVERY_ENABLED', config.serviceDiscovery.enabled?.toString());
220
- setEnvIfNotSet('DISCOVERY_TYPE', config.serviceDiscovery.type);
221
- setEnvIfNotSet('CONSUL_URL', config.serviceDiscovery.consulUrl);
222
- setEnvIfNotSet('K8S_NAMESPACE', config.serviceDiscovery.kubernetesNamespace);
223
- setEnvIfNotSet(
224
- 'HEALTH_CHECK_INTERVAL',
225
- config.serviceDiscovery.healthCheckInterval?.toString()
226
- );
227
- setEnvIfNotSet('DISCOVERY_RETRY_ATTEMPTS', config.serviceDiscovery.retryAttempts?.toString());
228
- }
229
-
230
- // Apply logging configuration
231
- if (config.logging) {
232
- setEnvIfNotSet('LOG_LEVEL', config.logging.level);
233
- setEnvIfNotSet('LOG_FORMAT', config.logging.format);
234
- setEnvIfNotSet('LOG_COLORS', config.logging.enableColors?.toString());
235
- setEnvIfNotSet('LOG_TIMESTAMP', config.logging.enableTimestamp?.toString());
236
- setEnvIfNotSet('LOG_CONTEXT', config.logging.enableContext?.toString());
237
-
238
- if (config.logging.outputs) {
239
- setEnvIfNotSet('LOG_CONSOLE', config.logging.outputs.console?.toString());
240
-
241
- if (config.logging.outputs.file) {
242
- setEnvIfNotSet('LOG_FILE_ENABLED', config.logging.outputs.file.enabled?.toString());
243
- setEnvIfNotSet('LOG_FILE_PATH', config.logging.outputs.file.path);
244
- setEnvIfNotSet('LOG_FILE_MAX_SIZE', config.logging.outputs.file.maxSize);
245
- setEnvIfNotSet('LOG_FILE_MAX_FILES', config.logging.outputs.file.maxFiles?.toString());
246
- }
247
-
248
- if (config.logging.outputs.webhook) {
249
- setEnvIfNotSet('LOG_WEBHOOK_ENABLED', config.logging.outputs.webhook.enabled?.toString());
250
- setEnvIfNotSet('LOG_WEBHOOK_URL', config.logging.outputs.webhook.url);
251
- if (config.logging.outputs.webhook.headers) {
252
- setEnvIfNotSet(
253
- 'LOG_WEBHOOK_HEADERS',
254
- JSON.stringify(config.logging.outputs.webhook.headers)
255
- );
256
- }
257
- }
258
- }
259
- }
260
-
261
- // Apply module defaults
262
- if (config.modules) {
263
- if (config.modules.cache) {
264
- setEnvIfNotSet('CACHE_ENABLED', config.modules.cache.enabled?.toString());
265
- setEnvIfNotSet('DEFAULT_CACHE_TTL', config.modules.cache.defaultTtl?.toString());
266
- setEnvIfNotSet('CACHE_MAX_SIZE', config.modules.cache.maxSize?.toString());
267
- setEnvIfNotSet('CACHE_STRATEGY', config.modules.cache.strategy);
268
- }
269
-
270
- if (config.modules.rateLimit) {
271
- setEnvIfNotSet('RATE_LIMIT_ENABLED', config.modules.rateLimit.enabled?.toString());
272
- setEnvIfNotSet(
273
- 'DEFAULT_RATE_LIMIT_REQUESTS',
274
- config.modules.rateLimit.defaultRequests?.toString()
275
- );
276
- setEnvIfNotSet(
277
- 'DEFAULT_RATE_LIMIT_WINDOW',
278
- config.modules.rateLimit.defaultWindow?.toString()
279
- );
280
- setEnvIfNotSet(
281
- 'RATE_LIMIT_SKIP_SUCCESS',
282
- config.modules.rateLimit.skipSuccessfulRequests?.toString()
283
- );
284
- setEnvIfNotSet(
285
- 'RATE_LIMIT_SKIP_FAILED',
286
- config.modules.rateLimit.skipFailedRequests?.toString()
287
- );
288
- }
289
-
290
- if (config.modules.validation) {
291
- setEnvIfNotSet('VALIDATION_ENABLED', config.modules.validation.enabled?.toString());
292
- setEnvIfNotSet(
293
- 'VALIDATION_STRIP_UNKNOWN',
294
- config.modules.validation.stripUnknown?.toString()
295
- );
296
- setEnvIfNotSet('VALIDATION_ABORT_EARLY', config.modules.validation.abortEarly?.toString());
297
- }
298
- }
299
-
300
- // Apply security configuration
301
- if (config.security) {
302
- if (config.security.cors) {
303
- setEnvIfNotSet('CORS_ENABLED', config.security.cors.enabled?.toString());
304
- if (typeof config.security.cors.origin === 'string') {
305
- setEnvIfNotSet('CORS_ORIGIN', config.security.cors.origin);
306
- } else if (Array.isArray(config.security.cors.origin)) {
307
- setEnvIfNotSet('CORS_ORIGIN', config.security.cors.origin.join(','));
308
- } else if (typeof config.security.cors.origin === 'boolean') {
309
- setEnvIfNotSet('CORS_ORIGIN', config.security.cors.origin.toString());
310
- }
311
- setEnvIfNotSet('CORS_METHODS', config.security.cors.methods?.join(','));
312
- setEnvIfNotSet('CORS_HEADERS', config.security.cors.allowedHeaders?.join(','));
313
- setEnvIfNotSet('CORS_CREDENTIALS', config.security.cors.credentials?.toString());
314
- }
315
-
316
- if (config.security.helmet) {
317
- setEnvIfNotSet('HELMET_ENABLED', config.security.helmet.enabled?.toString());
318
- setEnvIfNotSet('HELMET_CSP', config.security.helmet.contentSecurityPolicy?.toString());
319
- setEnvIfNotSet('HELMET_HSTS', config.security.helmet.hsts?.toString());
320
- setEnvIfNotSet('HELMET_NO_SNIFF', config.security.helmet.noSniff?.toString());
321
- setEnvIfNotSet('HELMET_FRAMEGUARD', config.security.helmet.frameguard?.toString());
322
- }
323
-
324
- if (config.security.rateLimit?.global) {
325
- setEnvIfNotSet(
326
- 'GLOBAL_RATE_LIMIT_ENABLED',
327
- config.security.rateLimit.global.enabled?.toString()
328
- );
329
- setEnvIfNotSet(
330
- 'GLOBAL_RATE_LIMIT_REQUESTS',
331
- config.security.rateLimit.global.requests?.toString()
332
- );
333
- setEnvIfNotSet(
334
- 'GLOBAL_RATE_LIMIT_WINDOW',
335
- config.security.rateLimit.global.window?.toString()
336
- );
337
- }
338
- }
339
-
340
- // Apply external services configuration
341
- if (config.external) {
342
- if (config.external.stripe) {
343
- setEnvIfNotSet('STRIPE_SECRET_KEY', config.external.stripe.secretKey);
344
- setEnvIfNotSet('STRIPE_PUBLISHABLE_KEY', config.external.stripe.publishableKey);
345
- setEnvIfNotSet('STRIPE_WEBHOOK_SECRET', config.external.stripe.webhookSecret);
346
- setEnvIfNotSet('STRIPE_API_VERSION', config.external.stripe.apiVersion);
347
- }
348
-
349
- if (config.external.paypal) {
350
- setEnvIfNotSet('PAYPAL_CLIENT_ID', config.external.paypal.clientId);
351
- setEnvIfNotSet('PAYPAL_CLIENT_SECRET', config.external.paypal.clientSecret);
352
- setEnvIfNotSet('PAYPAL_WEBHOOK_ID', config.external.paypal.webhookId);
353
- setEnvIfNotSet('PAYPAL_ENVIRONMENT', config.external.paypal.environment);
354
- }
355
-
356
- if (config.external.smtp) {
357
- setEnvIfNotSet('SMTP_HOST', config.external.smtp.host);
358
- setEnvIfNotSet('SMTP_PORT', config.external.smtp.port?.toString());
359
- setEnvIfNotSet('SMTP_SECURE', config.external.smtp.secure?.toString());
360
- setEnvIfNotSet('SMTP_USERNAME', config.external.smtp.username);
361
- setEnvIfNotSet('SMTP_PASSWORD', config.external.smtp.password);
362
- }
363
- }
364
-
365
- // Apply performance configuration
366
- if (config.performance) {
367
- if (config.performance.compression) {
368
- setEnvIfNotSet('COMPRESSION_ENABLED', config.performance.compression.enabled?.toString());
369
- setEnvIfNotSet('COMPRESSION_LEVEL', config.performance.compression.level?.toString());
370
- setEnvIfNotSet('COMPRESSION_THRESHOLD', config.performance.compression.threshold?.toString());
371
- }
372
-
373
- if (config.performance.circuitBreaker) {
374
- setEnvIfNotSet(
375
- 'CIRCUIT_BREAKER_ENABLED',
376
- config.performance.circuitBreaker.enabled?.toString()
377
- );
378
- setEnvIfNotSet(
379
- 'CIRCUIT_BREAKER_THRESHOLD',
380
- config.performance.circuitBreaker.failureThreshold?.toString()
381
- );
382
- setEnvIfNotSet(
383
- 'CIRCUIT_BREAKER_RESET',
384
- config.performance.circuitBreaker.resetTimeout?.toString()
385
- );
386
- setEnvIfNotSet(
387
- 'CIRCUIT_BREAKER_MONITOR',
388
- config.performance.circuitBreaker.monitoringPeriod?.toString()
389
- );
390
- }
391
-
392
- if (config.performance.clustering) {
393
- setEnvIfNotSet('CLUSTERING_ENABLED', config.performance.clustering.enabled?.toString());
394
- setEnvIfNotSet('CLUSTER_WORKERS', config.performance.clustering.workers?.toString());
395
- }
396
- }
397
- }
398
-
399
- /**
400
- * Set environment variable only if it's not already set
401
- * This ensures environment variables take precedence over config file values
402
- */
403
- function setEnvIfNotSet(key: string, value: string | undefined): void {
404
- if (value !== undefined && process.env[key] === undefined) {
405
- process.env[key] = value;
406
- }
407
- }
@@ -1,60 +1,105 @@
1
- // Configuration System - Main Exports and Utilities
1
+ /**
2
+ * Configuration System - Immutable Config with createApp Override Support
3
+ *
4
+ * This is the main entry point for the MoroJS configuration system.
5
+ * It provides a clean, immutable configuration that is locked at createApp() time.
6
+ *
7
+ * Key Features:
8
+ * - Immutable configuration after initialization
9
+ * - Clear precedence: Env Vars > createApp Options > Config File > Defaults
10
+ * - Type-safe validation
11
+ * - Single source of truth
12
+ */
13
+
14
+ // Export types and core components
2
15
  export * from './schema';
3
- export * from './loader';
4
- export * from './utils';
16
+ export * from './config-sources';
17
+ export * from './config-validator';
5
18
  export * from './file-loader';
6
19
 
7
- // Main configuration loading function
8
- import { loadConfig } from './loader';
9
- import type { AppConfig } from './schema';
10
- import { setConfig } from './utils';
20
+ // Export specific functions from config-manager to avoid conflicts
21
+ export { initializeAndLockConfig, isConfigLocked, resetConfigForTesting } from './config-manager';
22
+
23
+ // Export utilities for backward compatibility
24
+ export * from './utils';
25
+
26
+ import { MoroOptions } from '../../types/core';
27
+ import { AppConfig } from '../../types/config';
28
+ import { loadConfigFromAllSources } from './config-sources';
29
+ import {
30
+ initializeAndLockConfig,
31
+ getGlobalConfig as getConfig,
32
+ isConfigLocked,
33
+ resetConfigForTesting,
34
+ } from './config-manager';
35
+ import { createFrameworkLogger } from '../logger';
11
36
 
12
- // Global configuration instance
13
- let globalConfig: AppConfig | null = null;
37
+ const logger = createFrameworkLogger('ConfigSystem');
14
38
 
15
39
  /**
16
- * Initialize and load the global application configuration
17
- * This should be called once at application startup
40
+ * Initialize configuration system with createApp options
41
+ * This is the main entry point called by createApp()
42
+ *
43
+ * @param options - createApp options that can override config file and defaults
44
+ * @returns Immutable, validated configuration object
18
45
  */
19
- export function initializeConfig(): AppConfig {
20
- if (globalConfig) {
21
- return globalConfig;
46
+ export function initializeConfig(options?: MoroOptions): Readonly<AppConfig> {
47
+ if (isConfigLocked()) {
48
+ logger.debug('Configuration already locked, returning existing config');
49
+ return getConfig();
22
50
  }
23
51
 
24
- globalConfig = loadConfig();
52
+ logger.debug('Initializing configuration system');
53
+
54
+ // Load configuration from all sources with proper precedence
55
+ const config = loadConfigFromAllSources(options);
25
56
 
26
- // Also set the config for utils functions
27
- setConfig(globalConfig);
57
+ // Lock the configuration to prevent further changes
58
+ initializeAndLockConfig(config);
28
59
 
29
- return globalConfig;
60
+ logger.info(
61
+ `Configuration system initialized and locked: ${process.env.NODE_ENV || 'development'}:${config.server.port} (sources: env + file + options + defaults)`
62
+ );
63
+
64
+ return config;
65
+ }
66
+
67
+ /**
68
+ * Load configuration without locking (for testing and utilities)
69
+ * This maintains backward compatibility with existing code
70
+ */
71
+ export function loadConfig(): AppConfig {
72
+ return loadConfigFromAllSources();
73
+ }
74
+
75
+ /**
76
+ * Load configuration with createApp options (for testing and utilities)
77
+ * This maintains backward compatibility with existing code
78
+ */
79
+ export function loadConfigWithOptions(options: MoroOptions): AppConfig {
80
+ return loadConfigFromAllSources(options);
30
81
  }
31
82
 
32
83
  /**
33
84
  * Get the current global configuration
34
- * Throws if configuration hasn't been initialized
85
+ * Alias for getGlobalConfig() for backward compatibility
35
86
  */
36
- export function getGlobalConfig(): AppConfig {
37
- if (!globalConfig) {
38
- throw new Error('Configuration not initialized. Call initializeConfig() first.');
39
- }
40
- return globalConfig;
87
+ export function getGlobalConfig(): Readonly<AppConfig> {
88
+ return getConfig();
41
89
  }
42
90
 
43
91
  /**
44
- * Check if configuration has been initialized
92
+ * Check if configuration has been initialized and locked
93
+ * Alias for isConfigLocked() for backward compatibility
45
94
  */
46
95
  export function isConfigInitialized(): boolean {
47
- return globalConfig !== null;
96
+ return isConfigLocked();
48
97
  }
49
98
 
50
99
  /**
51
- * Reset the global configuration state (for testing purposes)
100
+ * Reset configuration state (for testing only)
52
101
  * @internal
53
102
  */
54
103
  export function resetConfig(): void {
55
- globalConfig = null;
56
-
57
- // Also reset the utils config (by setting it to null via direct access)
58
- const { setConfig } = require('./utils');
59
- setConfig(null as any);
104
+ resetConfigForTesting();
60
105
  }
@@ -2,14 +2,20 @@
2
2
 
3
3
  import { AppConfig } from '../../types/config';
4
4
 
5
- // Default configuration values
5
+ // Minimal default configuration - performance-focused, most things opt-in
6
6
  export const DEFAULT_CONFIG: AppConfig = {
7
7
  server: {
8
8
  port: 3001,
9
9
  host: 'localhost',
10
- environment: 'development',
11
10
  maxConnections: 1000,
12
11
  timeout: 30000,
12
+ bodySizeLimit: '10mb',
13
+ requestTracking: {
14
+ enabled: true, // Enable by default for debugging
15
+ },
16
+ errorBoundary: {
17
+ enabled: true, // Always enabled for safety
18
+ },
13
19
  },
14
20
  serviceDiscovery: {
15
21
  enabled: false,
@@ -19,30 +25,23 @@ export const DEFAULT_CONFIG: AppConfig = {
19
25
  healthCheckInterval: 30000,
20
26
  retryAttempts: 3,
21
27
  },
22
- database: {
23
- redis: {
24
- url: 'redis://localhost:6379',
25
- maxRetries: 3,
26
- retryDelay: 1000,
27
- keyPrefix: 'moro:',
28
- },
29
- },
28
+ database: {},
30
29
  modules: {
31
30
  cache: {
32
- enabled: true,
31
+ enabled: false, // Opt-in for better performance
33
32
  defaultTtl: 300,
34
33
  maxSize: 1000,
35
34
  strategy: 'lru',
36
35
  },
37
36
  rateLimit: {
38
- enabled: true,
37
+ enabled: false, // Opt-in to avoid unnecessary overhead
39
38
  defaultRequests: 100,
40
39
  defaultWindow: 60000,
41
40
  skipSuccessfulRequests: false,
42
41
  skipFailedRequests: false,
43
42
  },
44
43
  validation: {
45
- enabled: true,
44
+ enabled: false,
46
45
  stripUnknown: true,
47
46
  abortEarly: false,
48
47
  },
@@ -69,14 +68,14 @@ export const DEFAULT_CONFIG: AppConfig = {
69
68
  },
70
69
  security: {
71
70
  cors: {
72
- enabled: true,
71
+ enabled: false, // Opt-in for better performance
73
72
  origin: '*',
74
73
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
75
74
  allowedHeaders: ['Content-Type', 'Authorization'],
76
75
  credentials: false,
77
76
  },
78
77
  helmet: {
79
- enabled: true,
78
+ enabled: false, // Opt-in for better performance
80
79
  contentSecurityPolicy: true,
81
80
  hsts: true,
82
81
  noSniff: true,
@@ -90,26 +89,15 @@ export const DEFAULT_CONFIG: AppConfig = {
90
89
  },
91
90
  },
92
91
  },
93
- external: {
94
- stripe: {
95
- apiVersion: '2023-10-16',
96
- },
97
- paypal: {
98
- environment: 'sandbox',
99
- },
100
- smtp: {
101
- port: 587,
102
- secure: false,
103
- },
104
- },
92
+ external: {},
105
93
  performance: {
106
94
  compression: {
107
- enabled: true,
95
+ enabled: false, // Opt-in to avoid overhead
108
96
  level: 6,
109
97
  threshold: 1024,
110
98
  },
111
99
  circuitBreaker: {
112
- enabled: true,
100
+ enabled: false, // Opt-in to avoid overhead
113
101
  failureThreshold: 5,
114
102
  resetTimeout: 60000,
115
103
  monitoringPeriod: 10000,
@@ -117,13 +105,23 @@ export const DEFAULT_CONFIG: AppConfig = {
117
105
  clustering: {
118
106
  enabled: false,
119
107
  workers: 1,
108
+ memoryPerWorkerGB: undefined,
120
109
  },
121
110
  },
111
+ websocket: {
112
+ enabled: false, // Opt-in - user must explicitly enable WebSockets
113
+ },
122
114
  };
123
115
 
124
- // Simple compatibility export - just return the config as-is
116
+ // Schema validation is now handled by config-validator.ts
117
+ // This export is kept for backward compatibility only
118
+ // Note: For actual validation, use validateConfig() from config-validator.ts directly
125
119
  export const ConfigSchema = {
126
- parse: (data: any): AppConfig => data as AppConfig,
120
+ parse: (data: any): AppConfig => {
121
+ // Simple pass-through for backward compatibility
122
+ // Real validation happens in the config loading pipeline
123
+ return data as AppConfig;
124
+ },
127
125
  };
128
126
 
129
127
  // Re-export types for backward compatibility
@@ -1,28 +1,26 @@
1
1
  // Configuration Utilities for Modules and Environment Handling
2
2
  import { AppConfig } from './schema';
3
3
  import { createFrameworkLogger } from '../logger';
4
+ import { getGlobalConfig } from './config-manager';
4
5
 
5
6
  const logger = createFrameworkLogger('ConfigUtils');
6
7
 
7
- // Global configuration store
8
- let appConfig: AppConfig | null = null;
9
-
10
8
  /**
11
- * Set the global configuration (used by framework initialization)
9
+ * Set the global configuration (deprecated - for backward compatibility only)
10
+ * @deprecated Use the new immutable config system instead
12
11
  */
13
- export function setConfig(config: AppConfig): void {
14
- appConfig = config;
15
- logger.debug('Global configuration updated');
12
+ export function setConfig(_config: AppConfig): void {
13
+ logger.warn(
14
+ 'setConfig() is deprecated. Configuration is now immutable after createApp() initialization.'
15
+ );
16
16
  }
17
17
 
18
18
  /**
19
19
  * Get the global configuration
20
+ * This now delegates to the new config manager
20
21
  */
21
22
  export function getConfig(): AppConfig {
22
- if (!appConfig) {
23
- throw new Error('Configuration not initialized. Call loadConfig() first.');
24
- }
25
- return appConfig;
23
+ return getGlobalConfig();
26
24
  }
27
25
 
28
26
  /**
@@ -63,6 +61,7 @@ function coerceEnvironmentValue(value: string): any {
63
61
 
64
62
  /**
65
63
  * Create module-specific configuration with environment override support
64
+ * This now uses the new immutable config system
66
65
  */
67
66
  export function createModuleConfig<T>(
68
67
  schema: { parse: (data: any) => T },
@@ -72,10 +71,12 @@ export function createModuleConfig<T>(
72
71
  // Try to get global config, but don't fail if not initialized
73
72
  let globalConfig = {};
74
73
  try {
75
- const { getGlobalConfig } = require('./index');
76
74
  globalConfig = getGlobalConfig();
77
75
  } catch {
78
76
  // Global config not initialized - use empty object (module config can still work independently)
77
+ logger.debug(
78
+ `Global config not available for module config with prefix ${envPrefix}, using defaults only`
79
+ );
79
80
  globalConfig = {};
80
81
  }
81
82
 
@@ -104,7 +105,7 @@ export function createModuleConfig<T>(
104
105
  // Priority: environment variables > global config > default config
105
106
  const mergedConfig = {
106
107
  ...defaultConfig,
107
- ...globalConfig, // Now actually using global config!
108
+ ...globalConfig, // Now uses the new immutable config system
108
109
  ...envConfig,
109
110
  };
110
111
 
@@ -208,9 +209,10 @@ export function envVar(prefix: string, name: string): string {
208
209
 
209
210
  /**
210
211
  * Get configuration value with dot notation
212
+ * This now delegates to the new config manager
211
213
  */
212
214
  export function getConfigValue(path: string): any {
213
- const config = getConfig();
215
+ const config = getGlobalConfig();
214
216
 
215
217
  return path.split('.').reduce((obj, key) => {
216
218
  return obj && obj[key] !== undefined ? obj[key] : undefined;
@@ -219,33 +221,24 @@ export function getConfigValue(path: string): any {
219
221
 
220
222
  /**
221
223
  * Check if we're in development environment
224
+ * Now reads NODE_ENV directly for consistency with Node.js ecosystem
222
225
  */
223
226
  export function isDevelopment(): boolean {
224
- try {
225
- return getConfig().server.environment === 'development';
226
- } catch {
227
- return process.env.NODE_ENV === 'development';
228
- }
227
+ return process.env.NODE_ENV === 'development';
229
228
  }
230
229
 
231
230
  /**
232
231
  * Check if we're in production environment
232
+ * Now reads NODE_ENV directly for consistency with Node.js ecosystem
233
233
  */
234
234
  export function isProduction(): boolean {
235
- try {
236
- return getConfig().server.environment === 'production';
237
- } catch {
238
- return process.env.NODE_ENV === 'production';
239
- }
235
+ return process.env.NODE_ENV === 'production';
240
236
  }
241
237
 
242
238
  /**
243
239
  * Check if we're in staging environment
240
+ * Now reads NODE_ENV directly for consistency with Node.js ecosystem
244
241
  */
245
242
  export function isStaging(): boolean {
246
- try {
247
- return getConfig().server.environment === 'staging';
248
- } catch {
249
- return process.env.NODE_ENV === 'staging';
250
- }
243
+ return process.env.NODE_ENV === 'staging';
251
244
  }