@morojs/moro 1.2.1 → 1.4.0

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 (92) hide show
  1. package/LICENSE +2 -2
  2. package/README.md +61 -7
  3. package/dist/core/config/file-loader.js +31 -25
  4. package/dist/core/config/file-loader.js.map +1 -1
  5. package/dist/core/config/schema.d.ts +2 -2
  6. package/dist/core/config/schema.js +1 -1
  7. package/dist/core/config/schema.js.map +1 -1
  8. package/dist/core/config/types.d.ts +147 -0
  9. package/dist/core/config/types.js +124 -0
  10. package/dist/core/config/types.js.map +1 -0
  11. package/dist/core/config/typescript-loader.d.ts +6 -0
  12. package/dist/core/config/typescript-loader.js +268 -0
  13. package/dist/core/config/typescript-loader.js.map +1 -0
  14. package/dist/core/config/validation.d.ts +18 -0
  15. package/dist/core/config/validation.js +134 -0
  16. package/dist/core/config/validation.js.map +1 -0
  17. package/dist/core/docs/openapi-generator.js +6 -6
  18. package/dist/core/docs/openapi-generator.js.map +1 -1
  19. package/dist/core/docs/schema-to-openapi.d.ts +7 -0
  20. package/dist/core/docs/schema-to-openapi.js +124 -0
  21. package/dist/core/docs/schema-to-openapi.js.map +1 -0
  22. package/dist/core/docs/zod-to-openapi.d.ts +2 -0
  23. package/dist/core/docs/zod-to-openapi.js.map +1 -1
  24. package/dist/core/events/event-bus.js +4 -0
  25. package/dist/core/events/event-bus.js.map +1 -1
  26. package/dist/core/framework.d.ts +29 -6
  27. package/dist/core/framework.js +117 -18
  28. package/dist/core/framework.js.map +1 -1
  29. package/dist/core/http/http-server.d.ts +33 -0
  30. package/dist/core/http/http-server.js +329 -28
  31. package/dist/core/http/http-server.js.map +1 -1
  32. package/dist/core/networking/adapters/index.d.ts +3 -0
  33. package/dist/core/networking/adapters/index.js +10 -0
  34. package/dist/core/networking/adapters/index.js.map +1 -0
  35. package/dist/core/networking/adapters/socketio-adapter.d.ts +16 -0
  36. package/dist/core/networking/adapters/socketio-adapter.js +244 -0
  37. package/dist/core/networking/adapters/socketio-adapter.js.map +1 -0
  38. package/dist/core/networking/adapters/ws-adapter.d.ts +54 -0
  39. package/dist/core/networking/adapters/ws-adapter.js +383 -0
  40. package/dist/core/networking/adapters/ws-adapter.js.map +1 -0
  41. package/dist/core/networking/websocket-adapter.d.ts +171 -0
  42. package/dist/core/networking/websocket-adapter.js +5 -0
  43. package/dist/core/networking/websocket-adapter.js.map +1 -0
  44. package/dist/core/networking/websocket-manager.d.ts +53 -17
  45. package/dist/core/networking/websocket-manager.js +166 -108
  46. package/dist/core/networking/websocket-manager.js.map +1 -1
  47. package/dist/core/routing/index.d.ts +13 -13
  48. package/dist/core/routing/index.js.map +1 -1
  49. package/dist/core/utilities/container.d.ts +1 -0
  50. package/dist/core/utilities/container.js +11 -1
  51. package/dist/core/utilities/container.js.map +1 -1
  52. package/dist/core/validation/adapters.d.ts +51 -0
  53. package/dist/core/validation/adapters.js +135 -0
  54. package/dist/core/validation/adapters.js.map +1 -0
  55. package/dist/core/validation/index.d.ts +14 -11
  56. package/dist/core/validation/index.js +37 -26
  57. package/dist/core/validation/index.js.map +1 -1
  58. package/dist/core/validation/schema-interface.d.ts +36 -0
  59. package/dist/core/validation/schema-interface.js +68 -0
  60. package/dist/core/validation/schema-interface.js.map +1 -0
  61. package/dist/index.d.ts +6 -1
  62. package/dist/index.js +14 -3
  63. package/dist/index.js.map +1 -1
  64. package/dist/moro.d.ts +8 -0
  65. package/dist/moro.js +339 -14
  66. package/dist/moro.js.map +1 -1
  67. package/dist/types/core.d.ts +17 -0
  68. package/package.json +42 -14
  69. package/src/core/config/file-loader.ts +34 -25
  70. package/src/core/config/schema.ts +1 -1
  71. package/src/core/config/types.ts +277 -0
  72. package/src/core/config/typescript-loader.ts +571 -0
  73. package/src/core/config/validation.ts +145 -0
  74. package/src/core/docs/openapi-generator.ts +7 -6
  75. package/src/core/docs/schema-to-openapi.ts +148 -0
  76. package/src/core/docs/zod-to-openapi.ts +2 -0
  77. package/src/core/events/event-bus.ts +5 -0
  78. package/src/core/framework.ts +121 -28
  79. package/src/core/http/http-server.ts +377 -28
  80. package/src/core/networking/adapters/index.ts +16 -0
  81. package/src/core/networking/adapters/socketio-adapter.ts +252 -0
  82. package/src/core/networking/adapters/ws-adapter.ts +425 -0
  83. package/src/core/networking/websocket-adapter.ts +217 -0
  84. package/src/core/networking/websocket-manager.ts +185 -127
  85. package/src/core/routing/index.ts +13 -13
  86. package/src/core/utilities/container.ts +14 -1
  87. package/src/core/validation/adapters.ts +147 -0
  88. package/src/core/validation/index.ts +60 -38
  89. package/src/core/validation/schema-interface.ts +100 -0
  90. package/src/index.ts +25 -2
  91. package/src/moro.ts +405 -15
  92. package/src/types/core.ts +18 -0
package/src/moro.ts CHANGED
@@ -73,6 +73,28 @@ export class Moro extends EventEmitter {
73
73
  applyLoggingConfiguration(undefined, options.logger);
74
74
  }
75
75
 
76
+ // Apply performance configuration from createApp options (takes precedence)
77
+ if (options.performance) {
78
+ if (options.performance.clustering) {
79
+ this.config.performance.clustering = {
80
+ ...this.config.performance.clustering,
81
+ ...options.performance.clustering,
82
+ };
83
+ }
84
+ if (options.performance.compression) {
85
+ this.config.performance.compression = {
86
+ ...this.config.performance.compression,
87
+ ...options.performance.compression,
88
+ };
89
+ }
90
+ if (options.performance.circuitBreaker) {
91
+ this.config.performance.circuitBreaker = {
92
+ ...this.config.performance.circuitBreaker,
93
+ ...options.performance.circuitBreaker,
94
+ };
95
+ }
96
+ }
97
+
76
98
  this.logger.info(
77
99
  `Configuration system initialized: ${this.config.server.environment}:${this.config.server.port}`
78
100
  );
@@ -83,7 +105,13 @@ export class Moro extends EventEmitter {
83
105
 
84
106
  this.logger.info(`Runtime system initialized: ${this.runtimeType}`, 'Runtime');
85
107
 
86
- this.coreFramework = new MoroCore();
108
+ // Pass logging configuration from config to framework
109
+ const frameworkOptions: any = {
110
+ ...options,
111
+ logger: this.config.logging,
112
+ };
113
+
114
+ this.coreFramework = new MoroCore(frameworkOptions);
87
115
 
88
116
  // Initialize middleware system
89
117
  this.middlewareManager = new MiddlewareManager();
@@ -94,6 +122,15 @@ export class Moro extends EventEmitter {
94
122
  httpServer.setHookManager((this.middlewareManager as any).hooks);
95
123
  }
96
124
 
125
+ // Configure HTTP server performance based on config
126
+ if (httpServer && httpServer.configurePerformance) {
127
+ const performanceConfig = this.config.performance;
128
+ httpServer.configurePerformance({
129
+ compression: performanceConfig?.compression || { enabled: true },
130
+ minimal: performanceConfig?.compression?.enabled === false, // Enable minimal mode if compression disabled
131
+ });
132
+ }
133
+
97
134
  // Access enterprise event bus from core framework
98
135
  this.eventBus = (this.coreFramework as any).eventBus;
99
136
 
@@ -350,10 +387,19 @@ export class Moro extends EventEmitter {
350
387
 
351
388
  // WebSocket helper with events
352
389
  websocket(namespace: string, handlers: Record<string, Function>) {
390
+ const adapter = this.coreFramework.getWebSocketAdapter();
391
+ if (!adapter) {
392
+ throw new Error(
393
+ 'WebSocket features require a WebSocket adapter. Install socket.io or configure an adapter:\n' +
394
+ 'npm install socket.io\n' +
395
+ 'or\n' +
396
+ 'new Moro({ websocket: { adapter: new SocketIOAdapter() } })'
397
+ );
398
+ }
399
+
353
400
  this.emit('websocket:registering', { namespace, handlers });
354
401
 
355
- const io = this.coreFramework.getIOServer();
356
- const ns = io.of(namespace);
402
+ const ns = adapter.createNamespace(namespace);
357
403
 
358
404
  Object.entries(handlers).forEach(([event, handler]) => {
359
405
  ns.on('connection', socket => {
@@ -383,9 +429,14 @@ export class Moro extends EventEmitter {
383
429
  }
384
430
 
385
431
  // Start server with events (Node.js only)
432
+ listen(callback?: () => void): void;
386
433
  listen(port: number, callback?: () => void): void;
387
434
  listen(port: number, host: string, callback?: () => void): void;
388
- listen(port: number, host?: string | (() => void), callback?: () => void) {
435
+ listen(
436
+ portOrCallback?: number | (() => void),
437
+ hostOrCallback?: string | (() => void),
438
+ callback?: () => void
439
+ ) {
389
440
  // Only available for Node.js runtime
390
441
  if (this.runtimeType !== 'node') {
391
442
  throw new Error(
@@ -393,10 +444,46 @@ export class Moro extends EventEmitter {
393
444
  );
394
445
  }
395
446
 
396
- // Handle overloaded parameters (port, callback) or (port, host, callback)
397
- if (typeof host === 'function') {
398
- callback = host;
399
- host = undefined;
447
+ // Handle overloaded parameters - supports:
448
+ // listen(callback)
449
+ // listen(port, callback)
450
+ // listen(port, host, callback)
451
+ let port: number;
452
+ let host: string | undefined;
453
+
454
+ if (typeof portOrCallback === 'function') {
455
+ // listen(callback) - use port from config
456
+ callback = portOrCallback;
457
+ port = this.config.server.port;
458
+ host = this.config.server.host;
459
+ } else if (typeof portOrCallback === 'number') {
460
+ // listen(port, ...) variants
461
+ port = portOrCallback;
462
+ if (typeof hostOrCallback === 'function') {
463
+ // listen(port, callback)
464
+ callback = hostOrCallback;
465
+ host = undefined;
466
+ } else {
467
+ // listen(port, host, callback)
468
+ host = hostOrCallback;
469
+ }
470
+ } else {
471
+ // listen() - use config defaults
472
+ port = this.config.server.port;
473
+ host = this.config.server.host;
474
+ }
475
+
476
+ // Validate that we have a valid port
477
+ if (!port || typeof port !== 'number') {
478
+ throw new Error(
479
+ 'Port not specified and not found in configuration. Please provide a port number or configure it in moro.config.js/ts'
480
+ );
481
+ }
482
+
483
+ // Check if clustering is enabled for massive performance gains
484
+ if (this.config.performance?.clustering?.enabled) {
485
+ this.startWithClustering(port, host as string, callback);
486
+ return;
400
487
  }
401
488
  this.eventBus.emit('server:starting', { port, runtime: this.runtimeType });
402
489
 
@@ -493,7 +580,7 @@ export class Moro extends EventEmitter {
493
580
  const matches = req.path.match(route.pattern);
494
581
  if (matches) {
495
582
  req.params = {};
496
- route.paramNames.forEach((name, index) => {
583
+ route.paramNames.forEach((name: string, index: number) => {
497
584
  req.params[name] = matches[index + 1];
498
585
  });
499
586
  }
@@ -557,11 +644,38 @@ export class Moro extends EventEmitter {
557
644
  }
558
645
  }
559
646
 
560
- // Find matching route
647
+ // Advanced route matching with caching and optimization
648
+ private routeCache = new Map<string, { pattern: RegExp; paramNames: string[] }>();
649
+ private staticRouteMap = new Map<string, any>();
650
+ private dynamicRoutesBySegments = new Map<number, any[]>();
651
+
561
652
  private findMatchingRoute(method: string, path: string) {
562
- for (const route of this.routes) {
653
+ // Phase 1: O(1) static route lookup
654
+ const staticKey = `${method}:${path}`;
655
+ const staticRoute = this.staticRouteMap.get(staticKey);
656
+ if (staticRoute) {
657
+ return {
658
+ ...staticRoute,
659
+ pattern: /^.*$/, // Dummy pattern for static routes
660
+ paramNames: [],
661
+ };
662
+ }
663
+
664
+ // Phase 2: Optimized dynamic route matching by segment count
665
+ const segments = path.split('/').filter(s => s.length > 0);
666
+ const segmentCount = segments.length;
667
+ const candidateRoutes = this.dynamicRoutesBySegments.get(segmentCount) || [];
668
+
669
+ for (const route of candidateRoutes) {
563
670
  if (route.method === method) {
564
- const pattern = this.pathToRegex(route.path);
671
+ const cacheKey = `${method}:${route.path}`;
672
+ let pattern = this.routeCache.get(cacheKey);
673
+
674
+ if (!pattern) {
675
+ pattern = this.pathToRegex(route.path);
676
+ this.routeCache.set(cacheKey, pattern);
677
+ }
678
+
565
679
  if (pattern.pattern.test(path)) {
566
680
  return {
567
681
  ...route,
@@ -571,6 +685,7 @@ export class Moro extends EventEmitter {
571
685
  }
572
686
  }
573
687
  }
688
+
574
689
  return null;
575
690
  }
576
691
 
@@ -602,7 +717,7 @@ export class Moro extends EventEmitter {
602
717
  private addRoute(method: string, path: string, handler: Function, options: any = {}) {
603
718
  const handlerName = `handler_${this.routes.length}`;
604
719
 
605
- this.routes.push({
720
+ const route = {
606
721
  method: method as any,
607
722
  path,
608
723
  handler: handlerName,
@@ -610,7 +725,12 @@ export class Moro extends EventEmitter {
610
725
  rateLimit: options.rateLimit,
611
726
  cache: options.cache,
612
727
  middleware: options.middleware,
613
- });
728
+ };
729
+
730
+ this.routes.push(route);
731
+
732
+ // Organize routes for optimal lookup
733
+ this.organizeRouteForLookup(route);
614
734
 
615
735
  // Store handler for later module creation
616
736
  this.routeHandlers[handlerName] = handler;
@@ -618,6 +738,23 @@ export class Moro extends EventEmitter {
618
738
  return this;
619
739
  }
620
740
 
741
+ private organizeRouteForLookup(route: any): void {
742
+ if (!route.path.includes(':')) {
743
+ // Static route - add to static map for O(1) lookup
744
+ const staticKey = `${route.method}:${route.path}`;
745
+ this.staticRouteMap.set(staticKey, route);
746
+ } else {
747
+ // Dynamic route - organize by segment count
748
+ const segments = route.path.split('/').filter((s: string) => s.length > 0);
749
+ const segmentCount = segments.length;
750
+
751
+ if (!this.dynamicRoutesBySegments.has(segmentCount)) {
752
+ this.dynamicRoutesBySegments.set(segmentCount, []);
753
+ }
754
+ this.dynamicRoutesBySegments.get(segmentCount)!.push(route);
755
+ }
756
+ }
757
+
621
758
  private registerDirectRoutes() {
622
759
  // Register routes directly with the HTTP server for optimal performance
623
760
  // This provides the intuitive developer experience users expect
@@ -766,11 +903,264 @@ export class Moro extends EventEmitter {
766
903
  const module = await import(modulePath);
767
904
  return module.default || module;
768
905
  }
906
+
907
+ // Clustering support for massive performance gains with proper cleanup
908
+ private clusterWorkers = new Map<number, any>();
909
+ private startWithClustering(port: number, host?: string, callback?: () => void): void {
910
+ const cluster = require('cluster');
911
+ const os = require('os');
912
+
913
+ // Smart worker count calculation based on actual bottlenecks
914
+ let workerCount = this.config.performance?.clustering?.workers || os.cpus().length;
915
+
916
+ // Auto-optimize worker count based on system characteristics
917
+ if (workerCount === 'auto' || workerCount > 8) {
918
+ // For high-core machines, limit workers to prevent IPC/memory bottlenecks
919
+ const cpuCount = os.cpus().length;
920
+ const totalMemoryGB = os.totalmem() / (1024 * 1024 * 1024);
921
+
922
+ // Optimal worker count formula based on research
923
+ if (cpuCount >= 16) {
924
+ // High-core machines: focus on memory/IPC efficiency
925
+ workerCount = Math.min(Math.ceil(totalMemoryGB / 2), 4); // 2GB per worker max, cap at 4
926
+ } else if (cpuCount >= 8) {
927
+ // Mid-range machines: balanced approach
928
+ workerCount = Math.min(cpuCount / 2, 4);
929
+ } else {
930
+ // Low-core machines: use all cores
931
+ workerCount = cpuCount;
932
+ }
933
+
934
+ this.logger.info(
935
+ `Auto-optimized workers: ${workerCount} (CPU: ${cpuCount}, RAM: ${totalMemoryGB.toFixed(1)}GB)`,
936
+ 'Cluster'
937
+ );
938
+ }
939
+
940
+ if (cluster.isPrimary) {
941
+ this.logger.info(`🚀 Starting ${workerCount} workers for maximum performance`, 'Cluster');
942
+
943
+ // Optimize cluster scheduling for high concurrency
944
+ cluster.schedulingPolicy = cluster.SCHED_RR; // Round-robin scheduling
945
+
946
+ // Set cluster settings for better performance
947
+ cluster.setupMaster({
948
+ exec: process.argv[1],
949
+ args: process.argv.slice(2),
950
+ silent: false,
951
+ });
952
+
953
+ // Optimize IPC to reduce communication overhead
954
+ process.env.NODE_CLUSTER_SCHED_POLICY = 'rr'; // Ensure round-robin
955
+ process.env.NODE_DISABLE_COLORS = '1'; // Reduce IPC message size
956
+
957
+ // Graceful shutdown handler
958
+ const gracefulShutdown = () => {
959
+ this.logger.info('Gracefully shutting down cluster...', 'Cluster');
960
+
961
+ // Clean up all workers
962
+ for (const [pid, worker] of this.clusterWorkers) {
963
+ worker.removeAllListeners();
964
+ worker.kill('SIGTERM');
965
+ }
966
+
967
+ // Clean up cluster listeners
968
+ cluster.removeAllListeners();
969
+ process.exit(0);
970
+ };
971
+
972
+ // Handle process signals for graceful shutdown
973
+ process.on('SIGINT', gracefulShutdown);
974
+ process.on('SIGTERM', gracefulShutdown);
975
+
976
+ // Fork workers with proper tracking and CPU affinity
977
+ for (let i = 0; i < workerCount; i++) {
978
+ const worker = cluster.fork({
979
+ WORKER_ID: i,
980
+ WORKER_CPU_AFFINITY: i % os.cpus().length, // Distribute workers across CPUs
981
+ });
982
+ this.clusterWorkers.set(worker.process.pid!, worker);
983
+ this.logger.info(
984
+ `Worker ${worker.process.pid} started (CPU ${i % os.cpus().length})`,
985
+ 'Cluster'
986
+ );
987
+
988
+ // Handle individual worker messages (reuse handler)
989
+ worker.on('message', this.handleWorkerMessage.bind(this));
990
+ }
991
+
992
+ // Handle worker exits with cleanup
993
+ cluster.on('exit', (worker: any, code: number, signal: string) => {
994
+ // Clean up worker tracking
995
+ this.clusterWorkers.delete(worker.process.pid);
996
+
997
+ this.logger.warn(
998
+ `Worker ${worker.process.pid} died (${signal || code}). Restarting...`,
999
+ 'Cluster'
1000
+ );
1001
+
1002
+ // Restart worker with proper tracking
1003
+ const newWorker = cluster.fork();
1004
+ this.clusterWorkers.set(newWorker.process.pid!, newWorker);
1005
+ newWorker.on('message', this.handleWorkerMessage.bind(this));
1006
+ this.logger.info(`Worker ${newWorker.process.pid} started`, 'Cluster');
1007
+ });
1008
+
1009
+ // Master process callback
1010
+ if (callback) callback();
1011
+ } else {
1012
+ // Worker process - start the actual server with proper cleanup
1013
+ this.logger.info(`Worker ${process.pid} initializing`, 'Worker');
1014
+
1015
+ // Worker-specific optimizations for high concurrency
1016
+ process.env.UV_THREADPOOL_SIZE = '64';
1017
+
1018
+ // Reduce logging contention in workers (major bottleneck)
1019
+ if (this.config.logging) {
1020
+ // Workers log less frequently to reduce I/O contention
1021
+ this.config.logging.level = 'warn'; // Only warnings and errors
1022
+ }
1023
+
1024
+ // Memory optimization for workers
1025
+ process.env.NODE_OPTIONS = '--max-old-space-size=1024'; // Limit memory per worker
1026
+
1027
+ // Optimize V8 flags for better performance (Rust-level optimizations)
1028
+ if (process.env.NODE_ENV === 'production') {
1029
+ // Ultra-aggressive V8 optimizations for maximum performance
1030
+ const v8Flags = [
1031
+ '--optimize-for-size', // Trade memory for speed
1032
+ '--always-opt', // Always optimize functions
1033
+ '--turbo-fast-api-calls', // Optimize API calls
1034
+ '--turbo-escape-analysis', // Escape analysis optimization
1035
+ '--turbo-inline-api-calls', // Inline API calls
1036
+ '--max-old-space-size=1024', // Limit memory to prevent GC pressure
1037
+ ];
1038
+ process.env.NODE_OPTIONS = (process.env.NODE_OPTIONS || '') + ' ' + v8Flags.join(' ');
1039
+ }
1040
+
1041
+ // Optimize garbage collection for workers
1042
+ // eslint-disable-next-line no-undef
1043
+ if ((global as any).gc) {
1044
+ setInterval(() => {
1045
+ // eslint-disable-next-line no-undef
1046
+ if ((global as any).gc) (global as any).gc();
1047
+ }, 60000); // GC every 60 seconds (less frequent)
1048
+ }
1049
+
1050
+ // Graceful shutdown for worker
1051
+ const workerShutdown = () => {
1052
+ this.logger.info(`Worker ${process.pid} shutting down gracefully...`, 'Worker');
1053
+
1054
+ // Clean up event listeners
1055
+ this.eventBus.removeAllListeners();
1056
+ this.removeAllListeners();
1057
+
1058
+ // Close server gracefully
1059
+ if (this.coreFramework) {
1060
+ const server = (this.coreFramework as any).server;
1061
+ if (server) {
1062
+ server.close(() => {
1063
+ process.exit(0);
1064
+ });
1065
+ }
1066
+ }
1067
+ };
1068
+
1069
+ // Handle worker shutdown signals
1070
+ process.on('SIGTERM', workerShutdown);
1071
+ process.on('SIGINT', workerShutdown);
1072
+
1073
+ // Continue with normal server startup for this worker
1074
+ this.eventBus.emit('server:starting', {
1075
+ port,
1076
+ runtime: this.runtimeType,
1077
+ worker: process.pid,
1078
+ });
1079
+
1080
+ // Add documentation middleware first (if enabled)
1081
+ try {
1082
+ const docsMiddleware = this.documentation.getDocsMiddleware();
1083
+ this.coreFramework.addMiddleware(docsMiddleware);
1084
+ } catch (error) {
1085
+ // Documentation not enabled, that's fine
1086
+ }
1087
+
1088
+ // Add intelligent routing middleware
1089
+ this.coreFramework.addMiddleware(
1090
+ async (req: HttpRequest, res: HttpResponse, next: () => void) => {
1091
+ const handled = await this.intelligentRouting.handleIntelligentRoute(req, res);
1092
+ if (!handled) {
1093
+ next();
1094
+ }
1095
+ }
1096
+ );
1097
+
1098
+ // Register direct routes
1099
+ if (this.routes.length > 0) {
1100
+ this.registerDirectRoutes();
1101
+ }
1102
+
1103
+ const workerCallback = () => {
1104
+ const displayHost = host || 'localhost';
1105
+ this.logger.info(`Worker ${process.pid} ready on ${displayHost}:${port}`, 'Worker');
1106
+ this.eventBus.emit('server:started', {
1107
+ port,
1108
+ runtime: this.runtimeType,
1109
+ worker: process.pid,
1110
+ });
1111
+ };
1112
+
1113
+ if (host) {
1114
+ this.coreFramework.listen(port, host, workerCallback);
1115
+ } else {
1116
+ this.coreFramework.listen(port, workerCallback);
1117
+ }
1118
+ }
1119
+ }
1120
+
1121
+ // Reusable worker message handler (avoids creating new functions)
1122
+ private handleWorkerMessage(message: any): void {
1123
+ // Handle inter-worker communication if needed
1124
+ if (message.type === 'health-check') {
1125
+ // Worker health check response
1126
+ return;
1127
+ }
1128
+
1129
+ // Log other worker messages
1130
+ this.logger.debug(`Worker message: ${JSON.stringify(message)}`, 'Cluster');
1131
+ }
769
1132
  }
770
1133
 
771
1134
  // Export convenience function
772
1135
  export function createApp(options?: MoroOptions): Moro {
773
- return new Moro(options);
1136
+ // Load global config from moro.config.js and merge with passed options
1137
+ const globalConfig = initializeConfig();
1138
+
1139
+ // Convert global config to MoroOptions format for createApp
1140
+ const configAsOptions: Partial<MoroOptions> = {
1141
+ performance: globalConfig.performance,
1142
+ logger: globalConfig.logging
1143
+ ? {
1144
+ level: globalConfig.logging.level,
1145
+ enableColors: globalConfig.logging.enableColors,
1146
+ enableTimestamp: globalConfig.logging.enableTimestamp,
1147
+ }
1148
+ : undefined,
1149
+ // Add other relevant config mappings as needed
1150
+ };
1151
+
1152
+ // Merge config file options with passed options (passed options take precedence)
1153
+ const mergedOptions = {
1154
+ ...configAsOptions,
1155
+ ...options,
1156
+ // Deep merge performance settings
1157
+ performance: {
1158
+ ...configAsOptions.performance,
1159
+ ...options?.performance,
1160
+ },
1161
+ };
1162
+
1163
+ return new Moro(mergedOptions);
774
1164
  }
775
1165
 
776
1166
  // Runtime-specific convenience functions
package/src/types/core.ts CHANGED
@@ -14,4 +14,22 @@ export interface MoroOptions {
14
14
  runtime?: RuntimeConfig;
15
15
  // Logger configuration
16
16
  logger?: LoggerOptions | boolean;
17
+ // Performance configuration
18
+ performance?: {
19
+ clustering?: {
20
+ enabled?: boolean;
21
+ workers?: number | 'auto';
22
+ };
23
+ compression?: {
24
+ enabled?: boolean;
25
+ level?: number;
26
+ threshold?: number;
27
+ };
28
+ circuitBreaker?: {
29
+ enabled?: boolean;
30
+ failureThreshold?: number;
31
+ resetTimeout?: number;
32
+ monitoringPeriod?: number;
33
+ };
34
+ };
17
35
  }