@morojs/moro 1.5.16 → 1.5.17
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/framework.d.ts +2 -0
- package/dist/core/framework.js +32 -4
- package/dist/core/framework.js.map +1 -1
- package/dist/core/http/http-server.js +2 -147
- package/dist/core/http/http-server.js.map +1 -1
- package/dist/core/middleware/built-in/auth.js +46 -35
- package/dist/core/middleware/built-in/auth.js.map +1 -1
- package/dist/core/middleware/built-in/jwt-helpers.d.ts +26 -1
- package/dist/core/middleware/built-in/jwt-helpers.js +26 -1
- package/dist/core/middleware/built-in/jwt-helpers.js.map +1 -1
- package/dist/moro.d.ts +17 -0
- package/dist/moro.js +134 -28
- package/dist/moro.js.map +1 -1
- package/package.json +1 -1
- package/src/core/framework.ts +42 -5
- package/src/core/http/http-server.ts +2 -150
- package/src/core/middleware/built-in/auth.ts +60 -37
- package/src/core/middleware/built-in/jwt-helpers.ts +26 -1
- package/src/moro.ts +163 -28
package/src/moro.ts
CHANGED
|
@@ -27,6 +27,9 @@ export class Moro extends EventEmitter {
|
|
|
27
27
|
private lazyModules = new Map<string, ModuleConfig>();
|
|
28
28
|
private routeHandlers: Record<string, Function> = {};
|
|
29
29
|
private moduleDiscovery?: any; // Store for cleanup
|
|
30
|
+
private autoDiscoveryOptions: MoroOptions | null = null;
|
|
31
|
+
private autoDiscoveryInitialized = false;
|
|
32
|
+
private autoDiscoveryPromise: Promise<void> | null = null;
|
|
30
33
|
// Enterprise event system integration
|
|
31
34
|
private eventBus: MoroEventBus;
|
|
32
35
|
// Application logger
|
|
@@ -118,15 +121,10 @@ export class Moro extends EventEmitter {
|
|
|
118
121
|
...options,
|
|
119
122
|
});
|
|
120
123
|
|
|
121
|
-
//
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
this.logger.error('Auto-discovery initialization failed', 'Framework', {
|
|
126
|
-
error: error instanceof Error ? error.message : String(error),
|
|
127
|
-
});
|
|
128
|
-
});
|
|
129
|
-
}
|
|
124
|
+
// Store auto-discovery options for later initialization
|
|
125
|
+
// IMPORTANT: Auto-discovery is deferred to ensure user middleware (like auth)
|
|
126
|
+
// is registered before module middleware that might bypass it
|
|
127
|
+
this.autoDiscoveryOptions = options.autoDiscover !== false ? options : null;
|
|
130
128
|
|
|
131
129
|
// Emit initialization event through enterprise event bus
|
|
132
130
|
this.eventBus.emit('framework:initialized', {
|
|
@@ -355,6 +353,13 @@ export class Moro extends EventEmitter {
|
|
|
355
353
|
version: moduleOrPath.version || '1.0.0',
|
|
356
354
|
});
|
|
357
355
|
}
|
|
356
|
+
|
|
357
|
+
// IMPORTANT: If modules are loaded manually after auto-discovery,
|
|
358
|
+
// ensure the final module handler is set up to maintain middleware order
|
|
359
|
+
if (this.autoDiscoveryInitialized) {
|
|
360
|
+
this.coreFramework.setupFinalModuleHandler();
|
|
361
|
+
}
|
|
362
|
+
|
|
358
363
|
return this;
|
|
359
364
|
}
|
|
360
365
|
|
|
@@ -496,35 +501,162 @@ export class Moro extends EventEmitter {
|
|
|
496
501
|
this.registerDirectRoutes();
|
|
497
502
|
}
|
|
498
503
|
|
|
499
|
-
const
|
|
500
|
-
const
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
this.
|
|
506
|
-
|
|
507
|
-
|
|
504
|
+
const startServer = () => {
|
|
505
|
+
const actualCallback = () => {
|
|
506
|
+
const displayHost = host || 'localhost';
|
|
507
|
+
this.logger.info('Moro Server Started', 'Server');
|
|
508
|
+
this.logger.info(`Runtime: ${this.runtimeType}`, 'Server');
|
|
509
|
+
this.logger.info(`HTTP API: http://${displayHost}:${port}`, 'Server');
|
|
510
|
+
if (this.config.websocket.enabled) {
|
|
511
|
+
this.logger.info(`WebSocket: ws://${displayHost}:${port}`, 'Server');
|
|
512
|
+
}
|
|
513
|
+
this.logger.info('Learn more at https://morojs.com', 'Server');
|
|
514
|
+
|
|
515
|
+
// Log intelligent routes info
|
|
516
|
+
const intelligentRoutes = this.intelligentRouting.getIntelligentRoutes();
|
|
517
|
+
if (intelligentRoutes.length > 0) {
|
|
518
|
+
this.logger.info(`Intelligent Routes: ${intelligentRoutes.length} registered`, 'Server');
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
this.eventBus.emit('server:started', { port, runtime: this.runtimeType });
|
|
522
|
+
if (callback) callback();
|
|
523
|
+
};
|
|
508
524
|
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
this.
|
|
525
|
+
if (host && typeof host === 'string') {
|
|
526
|
+
this.coreFramework.listen(port, host, actualCallback);
|
|
527
|
+
} else {
|
|
528
|
+
this.coreFramework.listen(port, actualCallback);
|
|
513
529
|
}
|
|
530
|
+
};
|
|
514
531
|
|
|
515
|
-
|
|
516
|
-
|
|
532
|
+
// Ensure auto-discovery is complete before starting server
|
|
533
|
+
this.ensureAutoDiscoveryComplete()
|
|
534
|
+
.then(() => {
|
|
535
|
+
startServer();
|
|
536
|
+
})
|
|
537
|
+
.catch(error => {
|
|
538
|
+
this.logger.error('Auto-discovery initialization failed during server start', 'Framework', {
|
|
539
|
+
error: error instanceof Error ? error.message : String(error),
|
|
540
|
+
});
|
|
541
|
+
// Start server anyway - auto-discovery failure shouldn't prevent startup
|
|
542
|
+
startServer();
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// Public method to manually initialize auto-discovery
|
|
547
|
+
// Useful for ensuring auth middleware is registered before auto-discovery
|
|
548
|
+
async initializeAutoDiscoveryNow(): Promise<void> {
|
|
549
|
+
return this.ensureAutoDiscoveryComplete();
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// Public API: Initialize modules explicitly after middleware setup
|
|
553
|
+
// This provides users with explicit control over module loading timing
|
|
554
|
+
// IMPORTANT: This forces module loading even if autoDiscovery.enabled is false
|
|
555
|
+
// Usage: app.initModules() or app.initModules({ paths: ['./my-modules'] })
|
|
556
|
+
initModules(options?: {
|
|
557
|
+
paths?: string[];
|
|
558
|
+
patterns?: string[];
|
|
559
|
+
recursive?: boolean;
|
|
560
|
+
loadingStrategy?: 'eager' | 'lazy' | 'conditional';
|
|
561
|
+
watchForChanges?: boolean;
|
|
562
|
+
ignorePatterns?: string[];
|
|
563
|
+
loadOrder?: 'alphabetical' | 'dependency' | 'custom';
|
|
564
|
+
failOnError?: boolean;
|
|
565
|
+
maxDepth?: number;
|
|
566
|
+
}): void {
|
|
567
|
+
this.logger.info('User-requested module initialization', 'ModuleSystem');
|
|
568
|
+
|
|
569
|
+
// If already initialized, do nothing
|
|
570
|
+
if (this.autoDiscoveryInitialized) {
|
|
571
|
+
this.logger.debug('Auto-discovery already completed, skipping', 'ModuleSystem');
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
// Store the options and mark that we want to force initialization
|
|
576
|
+
this.autoDiscoveryOptions = {
|
|
577
|
+
autoDiscover: {
|
|
578
|
+
enabled: true, // Force enabled regardless of original config
|
|
579
|
+
paths: options?.paths || ['./modules', './src/modules'],
|
|
580
|
+
patterns: options?.patterns || [
|
|
581
|
+
'**/*.module.{ts,js}',
|
|
582
|
+
'**/index.{ts,js}',
|
|
583
|
+
'**/*.config.{ts,js}',
|
|
584
|
+
],
|
|
585
|
+
recursive: options?.recursive ?? true,
|
|
586
|
+
loadingStrategy: options?.loadingStrategy || ('eager' as const),
|
|
587
|
+
watchForChanges: options?.watchForChanges ?? false,
|
|
588
|
+
ignorePatterns: options?.ignorePatterns || [
|
|
589
|
+
'**/*.test.{ts,js}',
|
|
590
|
+
'**/*.spec.{ts,js}',
|
|
591
|
+
'**/node_modules/**',
|
|
592
|
+
],
|
|
593
|
+
loadOrder: options?.loadOrder || ('dependency' as const),
|
|
594
|
+
failOnError: options?.failOnError ?? false,
|
|
595
|
+
maxDepth: options?.maxDepth ?? 5,
|
|
596
|
+
},
|
|
517
597
|
};
|
|
518
598
|
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
599
|
+
this.logger.debug(
|
|
600
|
+
'Module initialization options stored, will execute on next listen/getHandler call',
|
|
601
|
+
'ModuleSystem'
|
|
602
|
+
);
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
// Robust method to ensure auto-discovery is complete, handling race conditions
|
|
606
|
+
private async ensureAutoDiscoveryComplete(): Promise<void> {
|
|
607
|
+
// If already initialized, nothing to do
|
|
608
|
+
if (this.autoDiscoveryInitialized) {
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
// If auto-discovery is disabled, mark as initialized
|
|
613
|
+
if (!this.autoDiscoveryOptions) {
|
|
614
|
+
this.autoDiscoveryInitialized = true;
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
// If already in progress, wait for it to complete
|
|
619
|
+
if (this.autoDiscoveryPromise) {
|
|
620
|
+
return this.autoDiscoveryPromise;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
// Start auto-discovery
|
|
624
|
+
this.autoDiscoveryPromise = this.performAutoDiscovery();
|
|
625
|
+
|
|
626
|
+
try {
|
|
627
|
+
await this.autoDiscoveryPromise;
|
|
628
|
+
this.autoDiscoveryInitialized = true;
|
|
629
|
+
} catch (error) {
|
|
630
|
+
// Reset promise on error so it can be retried
|
|
631
|
+
this.autoDiscoveryPromise = null;
|
|
632
|
+
throw error;
|
|
633
|
+
} finally {
|
|
634
|
+
this.autoDiscoveryOptions = null; // Clear after attempt
|
|
523
635
|
}
|
|
524
636
|
}
|
|
525
637
|
|
|
638
|
+
// Perform the actual auto-discovery work
|
|
639
|
+
private async performAutoDiscovery(optionsOverride?: MoroOptions): Promise<void> {
|
|
640
|
+
const optionsToUse = optionsOverride || this.autoDiscoveryOptions;
|
|
641
|
+
if (!optionsToUse) return;
|
|
642
|
+
|
|
643
|
+
this.logger.debug('Starting auto-discovery initialization', 'AutoDiscovery');
|
|
644
|
+
|
|
645
|
+
await this.initializeAutoDiscovery(optionsToUse);
|
|
646
|
+
|
|
647
|
+
this.logger.debug('Auto-discovery initialization completed', 'AutoDiscovery');
|
|
648
|
+
}
|
|
649
|
+
|
|
526
650
|
// Get handler for non-Node.js runtimes
|
|
527
651
|
getHandler() {
|
|
652
|
+
// Ensure auto-discovery is complete for non-Node.js runtimes
|
|
653
|
+
// This handles the case where users call getHandler() immediately after createApp()
|
|
654
|
+
this.ensureAutoDiscoveryComplete().catch(error => {
|
|
655
|
+
this.logger.error('Auto-discovery initialization failed for runtime handler', 'Framework', {
|
|
656
|
+
error: error instanceof Error ? error.message : String(error),
|
|
657
|
+
});
|
|
658
|
+
});
|
|
659
|
+
|
|
528
660
|
// Create a unified request handler that works with the runtime adapter
|
|
529
661
|
const handler = async (req: HttpRequest, res: HttpResponse) => {
|
|
530
662
|
// Add documentation middleware first (if enabled)
|
|
@@ -902,6 +1034,9 @@ export class Moro extends EventEmitter {
|
|
|
902
1034
|
// Load modules based on strategy
|
|
903
1035
|
await this.loadDiscoveredModules(modules, autoDiscoveryConfig);
|
|
904
1036
|
|
|
1037
|
+
// Setup final module handler to run after user middleware (like auth)
|
|
1038
|
+
this.coreFramework.setupFinalModuleHandler();
|
|
1039
|
+
|
|
905
1040
|
// Setup file watching if enabled
|
|
906
1041
|
if (autoDiscoveryConfig.watchForChanges) {
|
|
907
1042
|
this.moduleDiscovery.watchModulesAdvanced(
|