@morojs/moro 1.5.4 → 1.5.6

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 +737 -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 +22 -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 +2 -7
  22. package/dist/core/framework.js +12 -5
  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 +10 -1
  34. package/dist/core/logger/logger.js +99 -37
  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 +22 -0
  40. package/dist/moro.js +134 -98
  41. package/dist/moro.js.map +1 -1
  42. package/dist/types/config.d.ts +39 -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 +1035 -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 +22 -31
  52. package/src/core/config/utils.ts +22 -29
  53. package/src/core/framework.ts +18 -11
  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 +109 -36
  58. package/src/core/routing/index.ts +116 -12
  59. package/src/moro.ts +159 -107
  60. package/src/types/config.ts +40 -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,12 +2,11 @@
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,
13
12
  },
@@ -19,30 +18,23 @@ export const DEFAULT_CONFIG: AppConfig = {
19
18
  healthCheckInterval: 30000,
20
19
  retryAttempts: 3,
21
20
  },
22
- database: {
23
- redis: {
24
- url: 'redis://localhost:6379',
25
- maxRetries: 3,
26
- retryDelay: 1000,
27
- keyPrefix: 'moro:',
28
- },
29
- },
21
+ database: {},
30
22
  modules: {
31
23
  cache: {
32
- enabled: true,
24
+ enabled: false, // Opt-in for better performance
33
25
  defaultTtl: 300,
34
26
  maxSize: 1000,
35
27
  strategy: 'lru',
36
28
  },
37
29
  rateLimit: {
38
- enabled: true,
30
+ enabled: false, // Opt-in to avoid unnecessary overhead
39
31
  defaultRequests: 100,
40
32
  defaultWindow: 60000,
41
33
  skipSuccessfulRequests: false,
42
34
  skipFailedRequests: false,
43
35
  },
44
36
  validation: {
45
- enabled: true,
37
+ enabled: false,
46
38
  stripUnknown: true,
47
39
  abortEarly: false,
48
40
  },
@@ -69,14 +61,14 @@ export const DEFAULT_CONFIG: AppConfig = {
69
61
  },
70
62
  security: {
71
63
  cors: {
72
- enabled: true,
64
+ enabled: false, // Opt-in for better performance
73
65
  origin: '*',
74
66
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
75
67
  allowedHeaders: ['Content-Type', 'Authorization'],
76
68
  credentials: false,
77
69
  },
78
70
  helmet: {
79
- enabled: true,
71
+ enabled: false, // Opt-in for better performance
80
72
  contentSecurityPolicy: true,
81
73
  hsts: true,
82
74
  noSniff: true,
@@ -90,26 +82,15 @@ export const DEFAULT_CONFIG: AppConfig = {
90
82
  },
91
83
  },
92
84
  },
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
- },
85
+ external: {},
105
86
  performance: {
106
87
  compression: {
107
- enabled: true,
88
+ enabled: false, // Opt-in to avoid overhead
108
89
  level: 6,
109
90
  threshold: 1024,
110
91
  },
111
92
  circuitBreaker: {
112
- enabled: true,
93
+ enabled: false, // Opt-in to avoid overhead
113
94
  failureThreshold: 5,
114
95
  resetTimeout: 60000,
115
96
  monitoringPeriod: 10000,
@@ -117,13 +98,23 @@ export const DEFAULT_CONFIG: AppConfig = {
117
98
  clustering: {
118
99
  enabled: false,
119
100
  workers: 1,
101
+ memoryPerWorkerGB: undefined,
120
102
  },
121
103
  },
104
+ websocket: {
105
+ enabled: false, // Opt-in - user must explicitly enable WebSockets
106
+ },
122
107
  };
123
108
 
124
- // Simple compatibility export - just return the config as-is
109
+ // Schema validation is now handled by config-validator.ts
110
+ // This export is kept for backward compatibility only
111
+ // Note: For actual validation, use validateConfig() from config-validator.ts directly
125
112
  export const ConfigSchema = {
126
- parse: (data: any): AppConfig => data as AppConfig,
113
+ parse: (data: any): AppConfig => {
114
+ // Simple pass-through for backward compatibility
115
+ // Real validation happens in the config loading pipeline
116
+ return data as AppConfig;
117
+ },
127
118
  };
128
119
 
129
120
  // 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
  }
@@ -15,19 +15,17 @@ import { MoroEventBus } from './events';
15
15
  import { createFrameworkLogger, logger as globalLogger } from './logger';
16
16
  import { ModuleConfig, InternalRouteDefinition } from '../types/module';
17
17
  import { LogLevel, LoggerOptions } from '../types/logger';
18
+ import { MoroOptions as CoreMoroOptions } from '../types/core';
18
19
  import { WebSocketAdapter, WebSocketAdapterOptions } from './networking/websocket-adapter';
19
20
 
20
- export interface MoroOptions {
21
+ // Extended MoroOptions that includes both core options and framework-specific options
22
+ export interface MoroOptions extends CoreMoroOptions {
21
23
  http2?: boolean;
22
24
  https?: {
23
25
  key: string | Buffer;
24
26
  cert: string | Buffer;
25
27
  ca?: string | Buffer;
26
28
  };
27
- compression?: {
28
- enabled?: boolean;
29
- threshold?: number;
30
- };
31
29
  websocket?:
32
30
  | {
33
31
  enabled?: boolean;
@@ -37,7 +35,6 @@ export interface MoroOptions {
37
35
  options?: WebSocketAdapterOptions;
38
36
  }
39
37
  | false;
40
- logger?: LoggerOptions | boolean;
41
38
  }
42
39
 
43
40
  export class Moro extends EventEmitter {
@@ -131,12 +128,22 @@ export class Moro extends EventEmitter {
131
128
  }
132
129
 
133
130
  private setupCore() {
134
- // Security middleware
135
- this.httpServer.use(middleware.helmet());
136
- this.httpServer.use(middleware.cors());
131
+ // PERFORMANCE FIX: Only apply middleware if enabled in options
132
+
133
+ // Security middleware - only if enabled (default to enabled for backward compatibility)
134
+ if (this.options.helmet !== false) {
135
+ this.httpServer.use(middleware.helmet());
136
+ }
137
+
138
+ if (this.options.cors !== false) {
139
+ this.httpServer.use(middleware.cors());
140
+ }
141
+
142
+ // Performance middleware - only if enabled (default to enabled for backward compatibility)
143
+ if (this.options.compression !== false) {
144
+ this.httpServer.use(middleware.compression());
145
+ }
137
146
 
138
- // Performance middleware
139
- this.httpServer.use(middleware.compression());
140
147
  this.httpServer.use(middleware.bodySize({ limit: '10mb' }));
141
148
 
142
149
  // Request tracking middleware