@morojs/moro 1.5.14 → 1.5.16
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/dist/core/config/config-sources.js +188 -0
- package/dist/core/config/config-sources.js.map +1 -1
- package/dist/core/config/config-validator.js +21 -0
- package/dist/core/config/config-validator.js.map +1 -1
- package/dist/core/config/schema.js +12 -0
- package/dist/core/config/schema.js.map +1 -1
- package/dist/core/modules/auto-discovery.d.ts +17 -0
- package/dist/core/modules/auto-discovery.js +366 -11
- package/dist/core/modules/auto-discovery.js.map +1 -1
- package/dist/moro.d.ts +9 -0
- package/dist/moro.js +178 -22
- package/dist/moro.js.map +1 -1
- package/dist/types/config.d.ts +12 -0
- package/dist/types/core.d.ts +12 -1
- package/package.json +1 -1
- package/src/core/config/config-sources.ts +212 -0
- package/src/core/config/config-validator.ts +36 -0
- package/src/core/config/schema.ts +12 -0
- package/src/core/modules/auto-discovery.ts +474 -11
- package/src/moro.ts +224 -37
- package/src/types/config.ts +12 -0
- package/src/types/core.ts +15 -2
|
@@ -206,6 +206,189 @@ function loadEnvironmentConfig(): Partial<AppConfig> {
|
|
|
206
206
|
config.external = externalConfig;
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
+
// Module configuration
|
|
210
|
+
const moduleEnvVars = [
|
|
211
|
+
// Cache
|
|
212
|
+
'CACHE_ENABLED',
|
|
213
|
+
'MORO_CACHE_ENABLED',
|
|
214
|
+
'DEFAULT_CACHE_TTL',
|
|
215
|
+
'MORO_CACHE_TTL',
|
|
216
|
+
'CACHE_MAX_SIZE',
|
|
217
|
+
'MORO_CACHE_SIZE',
|
|
218
|
+
'CACHE_STRATEGY',
|
|
219
|
+
'MORO_CACHE_STRATEGY',
|
|
220
|
+
// Rate Limit
|
|
221
|
+
'RATE_LIMIT_ENABLED',
|
|
222
|
+
'MORO_RATE_LIMIT_ENABLED',
|
|
223
|
+
'DEFAULT_RATE_LIMIT_REQUESTS',
|
|
224
|
+
'MORO_RATE_LIMIT_REQUESTS',
|
|
225
|
+
'DEFAULT_RATE_LIMIT_WINDOW',
|
|
226
|
+
'MORO_RATE_LIMIT_WINDOW',
|
|
227
|
+
// Validation
|
|
228
|
+
'VALIDATION_ENABLED',
|
|
229
|
+
'MORO_VALIDATION_ENABLED',
|
|
230
|
+
// Auto-Discovery
|
|
231
|
+
'AUTO_DISCOVERY_ENABLED',
|
|
232
|
+
'MORO_AUTO_DISCOVERY_ENABLED',
|
|
233
|
+
'AUTO_DISCOVERY_PATHS',
|
|
234
|
+
'MORO_AUTO_DISCOVERY_PATHS',
|
|
235
|
+
'AUTO_DISCOVERY_PATTERNS',
|
|
236
|
+
'MORO_AUTO_DISCOVERY_PATTERNS',
|
|
237
|
+
'AUTO_DISCOVERY_LOADING_STRATEGY',
|
|
238
|
+
'MORO_AUTO_DISCOVERY_LOADING_STRATEGY',
|
|
239
|
+
'AUTO_DISCOVERY_WATCH_FOR_CHANGES',
|
|
240
|
+
'MORO_AUTO_DISCOVERY_WATCH_FOR_CHANGES',
|
|
241
|
+
'AUTO_DISCOVERY_LOAD_ORDER',
|
|
242
|
+
'MORO_AUTO_DISCOVERY_LOAD_ORDER',
|
|
243
|
+
'AUTO_DISCOVERY_FAIL_ON_ERROR',
|
|
244
|
+
'MORO_AUTO_DISCOVERY_FAIL_ON_ERROR',
|
|
245
|
+
'AUTO_DISCOVERY_MAX_DEPTH',
|
|
246
|
+
'MORO_AUTO_DISCOVERY_MAX_DEPTH',
|
|
247
|
+
];
|
|
248
|
+
|
|
249
|
+
if (moduleEnvVars.some(envVar => process.env[envVar])) {
|
|
250
|
+
if (!config.modules) config.modules = {} as any;
|
|
251
|
+
|
|
252
|
+
// Cache configuration
|
|
253
|
+
if (process.env.CACHE_ENABLED || process.env.MORO_CACHE_ENABLED) {
|
|
254
|
+
if (!config.modules!.cache) config.modules!.cache = {} as any;
|
|
255
|
+
config.modules!.cache!.enabled =
|
|
256
|
+
(process.env.CACHE_ENABLED || process.env.MORO_CACHE_ENABLED) === 'true';
|
|
257
|
+
}
|
|
258
|
+
if (process.env.DEFAULT_CACHE_TTL || process.env.MORO_CACHE_TTL) {
|
|
259
|
+
if (!config.modules!.cache) config.modules!.cache = {} as any;
|
|
260
|
+
config.modules!.cache!.defaultTtl = parseInt(
|
|
261
|
+
process.env.DEFAULT_CACHE_TTL || process.env.MORO_CACHE_TTL || '300',
|
|
262
|
+
10
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
if (process.env.CACHE_MAX_SIZE || process.env.MORO_CACHE_SIZE) {
|
|
266
|
+
if (!config.modules!.cache) config.modules!.cache = {} as any;
|
|
267
|
+
config.modules!.cache!.maxSize = parseInt(
|
|
268
|
+
process.env.CACHE_MAX_SIZE || process.env.MORO_CACHE_SIZE || '1000',
|
|
269
|
+
10
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
if (process.env.CACHE_STRATEGY || process.env.MORO_CACHE_STRATEGY) {
|
|
273
|
+
if (!config.modules!.cache) config.modules!.cache = {} as any;
|
|
274
|
+
const strategy = process.env.CACHE_STRATEGY || process.env.MORO_CACHE_STRATEGY;
|
|
275
|
+
if (['lru', 'lfu', 'fifo'].includes(strategy || '')) {
|
|
276
|
+
config.modules!.cache!.strategy = strategy as 'lru' | 'lfu' | 'fifo';
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Rate limit configuration
|
|
281
|
+
if (process.env.RATE_LIMIT_ENABLED || process.env.MORO_RATE_LIMIT_ENABLED) {
|
|
282
|
+
if (!config.modules!.rateLimit) config.modules!.rateLimit = {} as any;
|
|
283
|
+
config.modules!.rateLimit!.enabled =
|
|
284
|
+
(process.env.RATE_LIMIT_ENABLED || process.env.MORO_RATE_LIMIT_ENABLED) === 'true';
|
|
285
|
+
}
|
|
286
|
+
if (process.env.DEFAULT_RATE_LIMIT_REQUESTS || process.env.MORO_RATE_LIMIT_REQUESTS) {
|
|
287
|
+
if (!config.modules!.rateLimit) config.modules!.rateLimit = {} as any;
|
|
288
|
+
config.modules!.rateLimit!.defaultRequests = parseInt(
|
|
289
|
+
process.env.DEFAULT_RATE_LIMIT_REQUESTS || process.env.MORO_RATE_LIMIT_REQUESTS || '100',
|
|
290
|
+
10
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
if (process.env.DEFAULT_RATE_LIMIT_WINDOW || process.env.MORO_RATE_LIMIT_WINDOW) {
|
|
294
|
+
if (!config.modules!.rateLimit) config.modules!.rateLimit = {} as any;
|
|
295
|
+
config.modules!.rateLimit!.defaultWindow = parseInt(
|
|
296
|
+
process.env.DEFAULT_RATE_LIMIT_WINDOW || process.env.MORO_RATE_LIMIT_WINDOW || '60000',
|
|
297
|
+
10
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Validation configuration
|
|
302
|
+
if (process.env.VALIDATION_ENABLED || process.env.MORO_VALIDATION_ENABLED) {
|
|
303
|
+
if (!config.modules!.validation) config.modules!.validation = {} as any;
|
|
304
|
+
config.modules!.validation!.enabled =
|
|
305
|
+
(process.env.VALIDATION_ENABLED || process.env.MORO_VALIDATION_ENABLED) === 'true';
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Auto-Discovery configuration
|
|
309
|
+
if (process.env.AUTO_DISCOVERY_ENABLED || process.env.MORO_AUTO_DISCOVERY_ENABLED) {
|
|
310
|
+
if (!config.modules!.autoDiscovery) config.modules!.autoDiscovery = {} as any;
|
|
311
|
+
config.modules!.autoDiscovery!.enabled =
|
|
312
|
+
(process.env.AUTO_DISCOVERY_ENABLED || process.env.MORO_AUTO_DISCOVERY_ENABLED) === 'true';
|
|
313
|
+
}
|
|
314
|
+
if (process.env.AUTO_DISCOVERY_PATHS || process.env.MORO_AUTO_DISCOVERY_PATHS) {
|
|
315
|
+
if (!config.modules!.autoDiscovery) config.modules!.autoDiscovery = {} as any;
|
|
316
|
+
const paths = (
|
|
317
|
+
process.env.AUTO_DISCOVERY_PATHS ||
|
|
318
|
+
process.env.MORO_AUTO_DISCOVERY_PATHS ||
|
|
319
|
+
''
|
|
320
|
+
)
|
|
321
|
+
.split(',')
|
|
322
|
+
.map(p => p.trim())
|
|
323
|
+
.filter(Boolean);
|
|
324
|
+
if (paths.length > 0) {
|
|
325
|
+
config.modules!.autoDiscovery!.paths = paths;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
if (process.env.AUTO_DISCOVERY_PATTERNS || process.env.MORO_AUTO_DISCOVERY_PATTERNS) {
|
|
329
|
+
if (!config.modules!.autoDiscovery) config.modules!.autoDiscovery = {} as any;
|
|
330
|
+
const patterns = (
|
|
331
|
+
process.env.AUTO_DISCOVERY_PATTERNS ||
|
|
332
|
+
process.env.MORO_AUTO_DISCOVERY_PATTERNS ||
|
|
333
|
+
''
|
|
334
|
+
)
|
|
335
|
+
.split(',')
|
|
336
|
+
.map(p => p.trim())
|
|
337
|
+
.filter(Boolean);
|
|
338
|
+
if (patterns.length > 0) {
|
|
339
|
+
config.modules!.autoDiscovery!.patterns = patterns;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
if (
|
|
343
|
+
process.env.AUTO_DISCOVERY_LOADING_STRATEGY ||
|
|
344
|
+
process.env.MORO_AUTO_DISCOVERY_LOADING_STRATEGY
|
|
345
|
+
) {
|
|
346
|
+
if (!config.modules!.autoDiscovery) config.modules!.autoDiscovery = {} as any;
|
|
347
|
+
const strategy =
|
|
348
|
+
process.env.AUTO_DISCOVERY_LOADING_STRATEGY ||
|
|
349
|
+
process.env.MORO_AUTO_DISCOVERY_LOADING_STRATEGY;
|
|
350
|
+
if (['eager', 'lazy', 'conditional'].includes(strategy || '')) {
|
|
351
|
+
config.modules!.autoDiscovery!.loadingStrategy = strategy as
|
|
352
|
+
| 'eager'
|
|
353
|
+
| 'lazy'
|
|
354
|
+
| 'conditional';
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
if (
|
|
358
|
+
process.env.AUTO_DISCOVERY_WATCH_FOR_CHANGES ||
|
|
359
|
+
process.env.MORO_AUTO_DISCOVERY_WATCH_FOR_CHANGES
|
|
360
|
+
) {
|
|
361
|
+
if (!config.modules!.autoDiscovery) config.modules!.autoDiscovery = {} as any;
|
|
362
|
+
config.modules!.autoDiscovery!.watchForChanges =
|
|
363
|
+
(process.env.AUTO_DISCOVERY_WATCH_FOR_CHANGES ||
|
|
364
|
+
process.env.MORO_AUTO_DISCOVERY_WATCH_FOR_CHANGES) === 'true';
|
|
365
|
+
}
|
|
366
|
+
if (process.env.AUTO_DISCOVERY_LOAD_ORDER || process.env.MORO_AUTO_DISCOVERY_LOAD_ORDER) {
|
|
367
|
+
if (!config.modules!.autoDiscovery) config.modules!.autoDiscovery = {} as any;
|
|
368
|
+
const loadOrder =
|
|
369
|
+
process.env.AUTO_DISCOVERY_LOAD_ORDER || process.env.MORO_AUTO_DISCOVERY_LOAD_ORDER;
|
|
370
|
+
if (['alphabetical', 'dependency', 'custom'].includes(loadOrder || '')) {
|
|
371
|
+
config.modules!.autoDiscovery!.loadOrder = loadOrder as
|
|
372
|
+
| 'alphabetical'
|
|
373
|
+
| 'dependency'
|
|
374
|
+
| 'custom';
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
if (process.env.AUTO_DISCOVERY_FAIL_ON_ERROR || process.env.MORO_AUTO_DISCOVERY_FAIL_ON_ERROR) {
|
|
378
|
+
if (!config.modules!.autoDiscovery) config.modules!.autoDiscovery = {} as any;
|
|
379
|
+
config.modules!.autoDiscovery!.failOnError =
|
|
380
|
+
(process.env.AUTO_DISCOVERY_FAIL_ON_ERROR ||
|
|
381
|
+
process.env.MORO_AUTO_DISCOVERY_FAIL_ON_ERROR) === 'true';
|
|
382
|
+
}
|
|
383
|
+
if (process.env.AUTO_DISCOVERY_MAX_DEPTH || process.env.MORO_AUTO_DISCOVERY_MAX_DEPTH) {
|
|
384
|
+
if (!config.modules!.autoDiscovery) config.modules!.autoDiscovery = {} as any;
|
|
385
|
+
config.modules!.autoDiscovery!.maxDepth = parseInt(
|
|
386
|
+
process.env.AUTO_DISCOVERY_MAX_DEPTH || process.env.MORO_AUTO_DISCOVERY_MAX_DEPTH || '5',
|
|
387
|
+
10
|
|
388
|
+
);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
209
392
|
return config;
|
|
210
393
|
}
|
|
211
394
|
|
|
@@ -226,6 +409,35 @@ function normalizeCreateAppOptions(options: MoroOptions): Partial<AppConfig> {
|
|
|
226
409
|
if (options.modules) {
|
|
227
410
|
config.modules = { ...config.modules, ...options.modules } as any;
|
|
228
411
|
}
|
|
412
|
+
|
|
413
|
+
// Handle autoDiscover option (maps to modules.autoDiscovery)
|
|
414
|
+
if (options.autoDiscover !== undefined) {
|
|
415
|
+
const autoDiscoveryConfig =
|
|
416
|
+
typeof options.autoDiscover === 'boolean'
|
|
417
|
+
? { enabled: options.autoDiscover }
|
|
418
|
+
: options.autoDiscover;
|
|
419
|
+
|
|
420
|
+
config.modules = {
|
|
421
|
+
...config.modules,
|
|
422
|
+
autoDiscovery: {
|
|
423
|
+
...DEFAULT_CONFIG.modules.autoDiscovery,
|
|
424
|
+
...autoDiscoveryConfig,
|
|
425
|
+
},
|
|
426
|
+
} as any;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// Handle legacy modulesPath option (maps to modules.autoDiscovery.paths)
|
|
430
|
+
if (options.modulesPath) {
|
|
431
|
+
config.modules = {
|
|
432
|
+
...config.modules,
|
|
433
|
+
autoDiscovery: {
|
|
434
|
+
...DEFAULT_CONFIG.modules.autoDiscovery,
|
|
435
|
+
...(config.modules as any)?.autoDiscovery,
|
|
436
|
+
enabled: true,
|
|
437
|
+
paths: [options.modulesPath],
|
|
438
|
+
},
|
|
439
|
+
} as any;
|
|
440
|
+
}
|
|
229
441
|
if (options.logging) {
|
|
230
442
|
config.logging = { ...config.logging, ...options.logging } as any;
|
|
231
443
|
}
|
|
@@ -338,6 +338,42 @@ function validateModuleDefaultsConfig(config: any, path: string) {
|
|
|
338
338
|
cache: validateCacheConfig(config.cache, `${path}.cache`),
|
|
339
339
|
rateLimit: validateRateLimitConfig(config.rateLimit, `${path}.rateLimit`),
|
|
340
340
|
validation: validateValidationConfig(config.validation, `${path}.validation`),
|
|
341
|
+
autoDiscovery: validateAutoDiscoveryConfig(config.autoDiscovery, `${path}.autoDiscovery`),
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Validate auto-discovery configuration
|
|
347
|
+
*/
|
|
348
|
+
function validateAutoDiscoveryConfig(config: any, path: string) {
|
|
349
|
+
if (!config || typeof config !== 'object') {
|
|
350
|
+
throw new ConfigValidationError(
|
|
351
|
+
path,
|
|
352
|
+
config,
|
|
353
|
+
'object',
|
|
354
|
+
'Auto-discovery configuration must be an object'
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
return {
|
|
359
|
+
enabled: validateBoolean(config.enabled, `${path}.enabled`),
|
|
360
|
+
paths: validateStringArray(config.paths, `${path}.paths`),
|
|
361
|
+
patterns: validateStringArray(config.patterns, `${path}.patterns`),
|
|
362
|
+
recursive: validateBoolean(config.recursive, `${path}.recursive`),
|
|
363
|
+
loadingStrategy: validateEnum(
|
|
364
|
+
config.loadingStrategy,
|
|
365
|
+
['eager', 'lazy', 'conditional'],
|
|
366
|
+
`${path}.loadingStrategy`
|
|
367
|
+
),
|
|
368
|
+
watchForChanges: validateBoolean(config.watchForChanges, `${path}.watchForChanges`),
|
|
369
|
+
ignorePatterns: validateStringArray(config.ignorePatterns, `${path}.ignorePatterns`),
|
|
370
|
+
loadOrder: validateEnum(
|
|
371
|
+
config.loadOrder,
|
|
372
|
+
['alphabetical', 'dependency', 'custom'],
|
|
373
|
+
`${path}.loadOrder`
|
|
374
|
+
),
|
|
375
|
+
failOnError: validateBoolean(config.failOnError, `${path}.failOnError`),
|
|
376
|
+
maxDepth: validateNumber(config.maxDepth, `${path}.maxDepth`),
|
|
341
377
|
};
|
|
342
378
|
}
|
|
343
379
|
|
|
@@ -45,6 +45,18 @@ export const DEFAULT_CONFIG: AppConfig = {
|
|
|
45
45
|
stripUnknown: true,
|
|
46
46
|
abortEarly: false,
|
|
47
47
|
},
|
|
48
|
+
autoDiscovery: {
|
|
49
|
+
enabled: true, // Enable by default for better DX
|
|
50
|
+
paths: ['./modules', './src/modules'],
|
|
51
|
+
patterns: ['**/*.module.{ts,js}', '**/index.{ts,js}', '**/*.config.{ts,js}'],
|
|
52
|
+
recursive: true,
|
|
53
|
+
loadingStrategy: 'eager',
|
|
54
|
+
watchForChanges: false, // Opt-in for development
|
|
55
|
+
ignorePatterns: ['**/*.test.{ts,js}', '**/*.spec.{ts,js}', '**/node_modules/**'],
|
|
56
|
+
loadOrder: 'dependency',
|
|
57
|
+
failOnError: false, // Graceful degradation
|
|
58
|
+
maxDepth: 5,
|
|
59
|
+
},
|
|
48
60
|
},
|
|
49
61
|
logging: {
|
|
50
62
|
level: 'info',
|