@morojs/moro 1.6.0 → 1.6.2
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 +4 -0
- package/dist/core/config/config-sources.js.map +1 -1
- package/dist/core/config/config-validator.js +3 -0
- package/dist/core/config/config-validator.js.map +1 -1
- package/dist/core/config/file-loader.js +3 -1
- package/dist/core/config/file-loader.js.map +1 -1
- package/dist/core/config/schema.js +4 -1
- package/dist/core/config/schema.js.map +1 -1
- package/dist/core/events/event-bus.js +1 -1
- package/dist/core/events/event-bus.js.map +1 -1
- package/dist/core/framework.d.ts +1 -1
- package/dist/core/framework.js +13 -7
- package/dist/core/framework.js.map +1 -1
- package/dist/core/http/http-server.d.ts +55 -15
- package/dist/core/http/http-server.js +70 -146
- package/dist/core/http/http-server.js.map +1 -1
- package/dist/core/http/index.d.ts +1 -1
- package/dist/core/http/index.js +1 -1
- package/dist/core/http/index.js.map +1 -1
- package/dist/core/http/uws-http-server.d.ts +4 -22
- package/dist/core/http/uws-http-server.js +43 -208
- package/dist/core/http/uws-http-server.js.map +1 -1
- package/dist/core/networking/adapters/uws-adapter.d.ts +1 -1
- package/dist/core/networking/adapters/uws-adapter.js +1 -1
- package/dist/core/pooling/object-pool-manager.d.ts +140 -0
- package/dist/core/pooling/object-pool-manager.js +502 -0
- package/dist/core/pooling/object-pool-manager.js.map +1 -0
- package/dist/core/routing/app-integration.d.ts +12 -10
- package/dist/core/routing/app-integration.js +43 -74
- package/dist/core/routing/app-integration.js.map +1 -1
- package/dist/core/routing/index.d.ts +15 -29
- package/dist/core/routing/index.js +43 -390
- package/dist/core/routing/index.js.map +1 -1
- package/dist/core/routing/path-matcher.d.ts +67 -0
- package/dist/core/routing/path-matcher.js +182 -0
- package/dist/core/routing/path-matcher.js.map +1 -0
- package/dist/core/{http → routing}/router.d.ts +21 -9
- package/dist/core/routing/router.js +68 -0
- package/dist/core/routing/router.js.map +1 -0
- package/dist/core/routing/unified-router.d.ts +148 -0
- package/dist/core/routing/unified-router.js +684 -0
- package/dist/core/routing/unified-router.js.map +1 -0
- package/dist/moro.d.ts +10 -7
- package/dist/moro.js +90 -41
- package/dist/moro.js.map +1 -1
- package/dist/types/config.d.ts +3 -0
- package/package.json +1 -1
- package/src/core/config/config-sources.ts +4 -0
- package/src/core/config/config-validator.ts +3 -0
- package/src/core/config/file-loader.ts +4 -1
- package/src/core/config/schema.ts +4 -1
- package/src/core/events/event-bus.ts +1 -1
- package/src/core/framework.ts +14 -9
- package/src/core/http/http-server.ts +76 -161
- package/src/core/http/index.ts +1 -1
- package/src/core/http/uws-http-server.ts +43 -246
- package/src/core/networking/adapters/uws-adapter.ts +1 -1
- package/src/core/pooling/object-pool-manager.ts +630 -0
- package/src/core/routing/app-integration.ts +57 -109
- package/src/core/routing/index.ts +62 -473
- package/src/core/routing/path-matcher.ts +222 -0
- package/src/core/routing/router.ts +97 -0
- package/src/core/routing/unified-router.ts +870 -0
- package/src/moro.ts +107 -57
- package/src/types/config.ts +3 -0
- package/dist/core/http/router.js +0 -183
- package/dist/core/http/router.js.map +0 -1
- package/src/core/http/router.ts +0 -230
package/src/moro.ts
CHANGED
|
@@ -11,7 +11,11 @@ import { createFrameworkLogger, applyLoggingConfiguration } from './core/logger/
|
|
|
11
11
|
import { Logger } from './types/logger.js';
|
|
12
12
|
import { MiddlewareManager } from './core/middleware/index.js';
|
|
13
13
|
import { IntelligentRoutingManager } from './core/routing/app-integration.js';
|
|
14
|
-
import {
|
|
14
|
+
import { RouteSchema } from './core/routing/index.js';
|
|
15
|
+
import {
|
|
16
|
+
UnifiedRouter,
|
|
17
|
+
RouteBuilder as UnifiedRouteBuilder,
|
|
18
|
+
} from './core/routing/unified-router.js';
|
|
15
19
|
import { AppDocumentationManager, DocsConfig } from './core/docs/index.js';
|
|
16
20
|
import { EventEmitter } from 'events';
|
|
17
21
|
import cluster from 'cluster';
|
|
@@ -37,12 +41,16 @@ export class Moro extends EventEmitter {
|
|
|
37
41
|
private eventBus!: MoroEventBus;
|
|
38
42
|
// Application logger
|
|
39
43
|
private logger!: Logger;
|
|
40
|
-
//
|
|
41
|
-
private
|
|
44
|
+
// Unified routing system (singleton - shared across all routers)
|
|
45
|
+
private unifiedRouter!: UnifiedRouter;
|
|
46
|
+
// Legacy intelligent routing (kept for backward compatibility, now a facade)
|
|
47
|
+
private intelligentRouting!: IntelligentRoutingManager;
|
|
42
48
|
// Documentation system
|
|
43
49
|
private documentation = new AppDocumentationManager();
|
|
44
50
|
// Configuration system
|
|
45
51
|
private config!: AppConfig;
|
|
52
|
+
// Track if user explicitly set logger options (for worker log level handling)
|
|
53
|
+
private userSetLogger = false;
|
|
46
54
|
// Runtime system
|
|
47
55
|
private runtimeAdapter!: RuntimeAdapter;
|
|
48
56
|
private runtimeType!: RuntimeType;
|
|
@@ -58,6 +66,9 @@ export class Moro extends EventEmitter {
|
|
|
58
66
|
constructor(options: MoroOptions = {}) {
|
|
59
67
|
super(); // Call EventEmitter constructor
|
|
60
68
|
|
|
69
|
+
// Track if user explicitly set logger/logging options
|
|
70
|
+
this.userSetLogger = !!(options.logger || options.logging);
|
|
71
|
+
|
|
61
72
|
// Apply logging configuration BEFORE config loading to avoid DEBUG spam
|
|
62
73
|
// 1. Environment variables (base level)
|
|
63
74
|
const envLogLevel = process.env.LOG_LEVEL || process.env.MORO_LOG_LEVEL;
|
|
@@ -76,13 +87,18 @@ export class Moro extends EventEmitter {
|
|
|
76
87
|
// Use simplified global configuration system
|
|
77
88
|
this.config = initializeConfig(options);
|
|
78
89
|
|
|
79
|
-
// Apply config
|
|
80
|
-
|
|
90
|
+
// Apply final config logging (this includes normalized logger → logging conversion)
|
|
91
|
+
// Always apply this as it's the authoritative merged config
|
|
92
|
+
if (this.config.logging) {
|
|
81
93
|
applyLoggingConfiguration(this.config.logging, undefined);
|
|
82
94
|
// Recreate logger with updated config
|
|
83
95
|
this.logger = createFrameworkLogger('App');
|
|
84
96
|
}
|
|
85
97
|
|
|
98
|
+
// NOW initialize routing systems AFTER logger is configured
|
|
99
|
+
this.unifiedRouter = UnifiedRouter.getInstance();
|
|
100
|
+
this.intelligentRouting = new IntelligentRoutingManager();
|
|
101
|
+
|
|
86
102
|
this.logger.info(
|
|
87
103
|
`Configuration system initialized: ${process.env.NODE_ENV || 'development'}:${this.config.server.port}`
|
|
88
104
|
);
|
|
@@ -181,84 +197,85 @@ export class Moro extends EventEmitter {
|
|
|
181
197
|
|
|
182
198
|
// Intelligent route methods - chainable with automatic middleware ordering
|
|
183
199
|
// Overloads for better TypeScript inference
|
|
184
|
-
get(path: string):
|
|
200
|
+
get(path: string): UnifiedRouteBuilder;
|
|
185
201
|
get(path: string, handler: (req: HttpRequest, res: HttpResponse) => any, options?: any): this;
|
|
186
202
|
get(
|
|
187
203
|
path: string,
|
|
188
204
|
handler?: (req: HttpRequest, res: HttpResponse) => any,
|
|
189
205
|
options?: any
|
|
190
|
-
):
|
|
206
|
+
): UnifiedRouteBuilder | this {
|
|
191
207
|
if (handler) {
|
|
192
208
|
// Direct route registration
|
|
193
209
|
return this.addRoute('GET', path, handler, options);
|
|
194
210
|
}
|
|
195
|
-
//
|
|
196
|
-
return this.
|
|
211
|
+
// Use unified router for chainable API
|
|
212
|
+
return this.unifiedRouter.get(path);
|
|
197
213
|
}
|
|
198
214
|
|
|
199
|
-
post(path: string):
|
|
215
|
+
post(path: string): UnifiedRouteBuilder;
|
|
200
216
|
post(path: string, handler: (req: HttpRequest, res: HttpResponse) => any, options?: any): this;
|
|
201
217
|
post(
|
|
202
218
|
path: string,
|
|
203
219
|
handler?: (req: HttpRequest, res: HttpResponse) => any,
|
|
204
220
|
options?: any
|
|
205
|
-
):
|
|
221
|
+
): UnifiedRouteBuilder | this {
|
|
206
222
|
if (handler) {
|
|
207
223
|
// Direct route registration
|
|
208
224
|
return this.addRoute('POST', path, handler, options);
|
|
209
225
|
}
|
|
210
|
-
//
|
|
211
|
-
return this.
|
|
226
|
+
// Use unified router for chainable API
|
|
227
|
+
return this.unifiedRouter.post(path);
|
|
212
228
|
}
|
|
213
229
|
|
|
214
|
-
put(path: string):
|
|
230
|
+
put(path: string): UnifiedRouteBuilder;
|
|
215
231
|
put(path: string, handler: (req: HttpRequest, res: HttpResponse) => any, options?: any): this;
|
|
216
232
|
put(
|
|
217
233
|
path: string,
|
|
218
234
|
handler?: (req: HttpRequest, res: HttpResponse) => any,
|
|
219
235
|
options?: any
|
|
220
|
-
):
|
|
236
|
+
): UnifiedRouteBuilder | this {
|
|
221
237
|
if (handler) {
|
|
222
238
|
// Direct route registration
|
|
223
239
|
return this.addRoute('PUT', path, handler, options);
|
|
224
240
|
}
|
|
225
|
-
//
|
|
226
|
-
return this.
|
|
241
|
+
// Use unified router for chainable API
|
|
242
|
+
return this.unifiedRouter.put(path);
|
|
227
243
|
}
|
|
228
244
|
|
|
229
|
-
delete(path: string):
|
|
245
|
+
delete(path: string): UnifiedRouteBuilder;
|
|
230
246
|
delete(path: string, handler: (req: HttpRequest, res: HttpResponse) => any, options?: any): this;
|
|
231
247
|
delete(
|
|
232
248
|
path: string,
|
|
233
249
|
handler?: (req: HttpRequest, res: HttpResponse) => any,
|
|
234
250
|
options?: any
|
|
235
|
-
):
|
|
251
|
+
): UnifiedRouteBuilder | this {
|
|
236
252
|
if (handler) {
|
|
237
253
|
// Direct route registration
|
|
238
254
|
return this.addRoute('DELETE', path, handler, options);
|
|
239
255
|
}
|
|
240
|
-
//
|
|
241
|
-
return this.
|
|
256
|
+
// Use unified router for chainable API
|
|
257
|
+
return this.unifiedRouter.delete(path);
|
|
242
258
|
}
|
|
243
259
|
|
|
244
|
-
patch(path: string):
|
|
260
|
+
patch(path: string): UnifiedRouteBuilder;
|
|
245
261
|
patch(path: string, handler: (req: HttpRequest, res: HttpResponse) => any, options?: any): this;
|
|
246
262
|
patch(
|
|
247
263
|
path: string,
|
|
248
264
|
handler?: (req: HttpRequest, res: HttpResponse) => any,
|
|
249
265
|
options?: any
|
|
250
|
-
):
|
|
266
|
+
): UnifiedRouteBuilder | this {
|
|
251
267
|
if (handler) {
|
|
252
268
|
// Direct route registration
|
|
253
269
|
return this.addRoute('PATCH', path, handler, options);
|
|
254
270
|
}
|
|
255
|
-
//
|
|
256
|
-
return this.
|
|
271
|
+
// Use unified router for chainable API
|
|
272
|
+
return this.unifiedRouter.patch(path);
|
|
257
273
|
}
|
|
258
274
|
|
|
259
275
|
// Schema-first route method
|
|
260
|
-
route(schema: RouteSchema):
|
|
261
|
-
|
|
276
|
+
route(schema: RouteSchema): void {
|
|
277
|
+
// Use unified router for schema-first registration
|
|
278
|
+
this.unifiedRouter.route(schema);
|
|
262
279
|
}
|
|
263
280
|
|
|
264
281
|
// Enable automatic API documentation
|
|
@@ -554,18 +571,31 @@ export class Moro extends EventEmitter {
|
|
|
554
571
|
this.logger.debug('Documentation not enabled', 'Documentation');
|
|
555
572
|
}
|
|
556
573
|
|
|
557
|
-
// Add
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
574
|
+
// Add unified routing middleware (handles both chainable and direct routes)
|
|
575
|
+
// Optimized: call router without extra async wrapper when possible
|
|
576
|
+
this.coreFramework.addMiddleware((req: HttpRequest, res: HttpResponse, next: () => void) => {
|
|
577
|
+
// Try unified router first (handles all route types)
|
|
578
|
+
const handled = this.unifiedRouter.handleRequest(req, res);
|
|
579
|
+
|
|
580
|
+
// Check if it's a promise (async route) or sync
|
|
581
|
+
if (handled && typeof (handled as any).then === 'function') {
|
|
582
|
+
// Async - await the result
|
|
583
|
+
(handled as Promise<boolean>)
|
|
584
|
+
.then(isHandled => {
|
|
585
|
+
if (!isHandled) {
|
|
586
|
+
next(); // Fall back to legacy routes if any
|
|
587
|
+
}
|
|
588
|
+
})
|
|
589
|
+
.catch(() => next());
|
|
590
|
+
} else {
|
|
591
|
+
// Sync - check immediately
|
|
592
|
+
if (!(handled as boolean)) {
|
|
593
|
+
next();
|
|
564
594
|
}
|
|
565
595
|
}
|
|
566
|
-
);
|
|
596
|
+
});
|
|
567
597
|
|
|
568
|
-
// Register direct routes with the HTTP server
|
|
598
|
+
// Register legacy direct routes with the HTTP server (for backward compatibility)
|
|
569
599
|
if (this.routes.length > 0) {
|
|
570
600
|
this.registerDirectRoutes();
|
|
571
601
|
}
|
|
@@ -581,10 +611,12 @@ export class Moro extends EventEmitter {
|
|
|
581
611
|
}
|
|
582
612
|
this.logger.info('Learn more at https://morojs.com', 'Server');
|
|
583
613
|
|
|
584
|
-
// Log
|
|
585
|
-
const
|
|
586
|
-
if (
|
|
587
|
-
this.logger.info(`
|
|
614
|
+
// Log unified router stats
|
|
615
|
+
const routeCount = this.unifiedRouter.getRouteCount();
|
|
616
|
+
if (routeCount > 0) {
|
|
617
|
+
this.logger.info(`Unified Router: ${routeCount} routes registered`, 'Server');
|
|
618
|
+
// Log performance stats
|
|
619
|
+
this.unifiedRouter.logPerformanceStats();
|
|
588
620
|
}
|
|
589
621
|
|
|
590
622
|
this.eventBus.emit('server:started', { port, runtime: this.runtimeType });
|
|
@@ -744,11 +776,11 @@ export class Moro extends EventEmitter {
|
|
|
744
776
|
// Documentation not enabled, that's fine
|
|
745
777
|
}
|
|
746
778
|
|
|
747
|
-
// Try
|
|
748
|
-
const handled = await this.
|
|
779
|
+
// Try unified router first (handles all routes)
|
|
780
|
+
const handled = await this.unifiedRouter.handleRequest(req, res);
|
|
749
781
|
if (handled) return;
|
|
750
782
|
|
|
751
|
-
// Handle direct routes
|
|
783
|
+
// Handle legacy direct routes (backward compatibility)
|
|
752
784
|
if (this.routes.length > 0) {
|
|
753
785
|
await this.handleDirectRoutes(req, res);
|
|
754
786
|
}
|
|
@@ -915,8 +947,11 @@ export class Moro extends EventEmitter {
|
|
|
915
947
|
|
|
916
948
|
// Private methods
|
|
917
949
|
private addRoute(method: string, path: string, handler: Function, options: any = {}) {
|
|
918
|
-
|
|
950
|
+
// Register with unified router (primary routing system)
|
|
951
|
+
this.unifiedRouter.addRoute(method as any, path, handler as any, options.middleware || []);
|
|
919
952
|
|
|
953
|
+
// Also store in legacy routes array for backward compatibility
|
|
954
|
+
const handlerName = `handler_${this.routes.length}`;
|
|
920
955
|
const route = {
|
|
921
956
|
method: method as any,
|
|
922
957
|
path,
|
|
@@ -929,10 +964,10 @@ export class Moro extends EventEmitter {
|
|
|
929
964
|
|
|
930
965
|
this.routes.push(route);
|
|
931
966
|
|
|
932
|
-
// Organize routes for optimal lookup
|
|
967
|
+
// Organize routes for optimal lookup (legacy)
|
|
933
968
|
this.organizeRouteForLookup(route);
|
|
934
969
|
|
|
935
|
-
// Store handler for later module creation
|
|
970
|
+
// Store handler for later module creation (legacy)
|
|
936
971
|
this.routeHandlers[handlerName] = handler;
|
|
937
972
|
|
|
938
973
|
return this;
|
|
@@ -1440,8 +1475,9 @@ export class Moro extends EventEmitter {
|
|
|
1440
1475
|
|
|
1441
1476
|
// Reduce logging contention in workers (major bottleneck)
|
|
1442
1477
|
// Multiple workers writing to same log files creates I/O contention
|
|
1443
|
-
if
|
|
1444
|
-
|
|
1478
|
+
// ONLY reduce log level if user didn't explicitly set one
|
|
1479
|
+
if (!this.userSetLogger) {
|
|
1480
|
+
// Workers log less frequently to reduce I/O contention (only if not explicitly configured)
|
|
1445
1481
|
applyLoggingConfiguration(undefined, { level: 'warn' }); // Only warnings and errors
|
|
1446
1482
|
}
|
|
1447
1483
|
|
|
@@ -1462,9 +1498,9 @@ export class Moro extends EventEmitter {
|
|
|
1462
1498
|
'Worker'
|
|
1463
1499
|
);
|
|
1464
1500
|
|
|
1465
|
-
// Optimize V8 flags for better performance
|
|
1501
|
+
// Optimize V8 flags for better performance
|
|
1466
1502
|
if (process.env.NODE_ENV === 'production') {
|
|
1467
|
-
//
|
|
1503
|
+
// Aggressive V8 optimizations for maximum performance
|
|
1468
1504
|
const v8Flags = [
|
|
1469
1505
|
'--optimize-for-size', // Trade memory for speed
|
|
1470
1506
|
'--always-opt', // Always optimize functions
|
|
@@ -1523,17 +1559,31 @@ export class Moro extends EventEmitter {
|
|
|
1523
1559
|
// Documentation not enabled, that's fine
|
|
1524
1560
|
}
|
|
1525
1561
|
|
|
1526
|
-
// Add
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1562
|
+
// Add unified routing middleware (handles both chainable and direct routes)
|
|
1563
|
+
// Optimized: call router without extra async wrapper when possible
|
|
1564
|
+
this.coreFramework.addMiddleware((req: HttpRequest, res: HttpResponse, next: () => void) => {
|
|
1565
|
+
// Try unified router first (handles all route types)
|
|
1566
|
+
const handled = this.unifiedRouter.handleRequest(req, res);
|
|
1567
|
+
|
|
1568
|
+
// Check if it's a promise (async route) or sync
|
|
1569
|
+
if (handled && typeof (handled as any).then === 'function') {
|
|
1570
|
+
// Async - await the result
|
|
1571
|
+
(handled as Promise<boolean>)
|
|
1572
|
+
.then(isHandled => {
|
|
1573
|
+
if (!isHandled) {
|
|
1574
|
+
next(); // Fall back to legacy routes if any
|
|
1575
|
+
}
|
|
1576
|
+
})
|
|
1577
|
+
.catch(() => next());
|
|
1578
|
+
} else {
|
|
1579
|
+
// Sync - check immediately
|
|
1580
|
+
if (!(handled as boolean)) {
|
|
1531
1581
|
next();
|
|
1532
1582
|
}
|
|
1533
1583
|
}
|
|
1534
|
-
);
|
|
1584
|
+
});
|
|
1535
1585
|
|
|
1536
|
-
// Register direct routes
|
|
1586
|
+
// Register legacy direct routes with the HTTP server (for backward compatibility)
|
|
1537
1587
|
if (this.routes.length > 0) {
|
|
1538
1588
|
this.registerDirectRoutes();
|
|
1539
1589
|
}
|
package/src/types/config.ts
CHANGED
package/dist/core/http/router.js
DELETED
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
import { createFrameworkLogger } from '../logger/index.js';
|
|
2
|
-
export class Router {
|
|
3
|
-
routes = [];
|
|
4
|
-
logger = createFrameworkLogger('Router');
|
|
5
|
-
// Performance optimizations - O(1) static route lookup
|
|
6
|
-
staticRoutes = new Map(); // "GET:/api/users" -> route
|
|
7
|
-
dynamicRoutes = []; // Routes with parameters
|
|
8
|
-
// Object pooling for parameters to reduce GC pressure
|
|
9
|
-
paramObjectPool = [];
|
|
10
|
-
maxPoolSize = 50;
|
|
11
|
-
get(path, ...handlers) {
|
|
12
|
-
this.addRoute('GET', path, handlers);
|
|
13
|
-
}
|
|
14
|
-
post(path, ...handlers) {
|
|
15
|
-
this.addRoute('POST', path, handlers);
|
|
16
|
-
}
|
|
17
|
-
put(path, ...handlers) {
|
|
18
|
-
this.addRoute('PUT', path, handlers);
|
|
19
|
-
}
|
|
20
|
-
delete(path, ...handlers) {
|
|
21
|
-
this.addRoute('DELETE', path, handlers);
|
|
22
|
-
}
|
|
23
|
-
patch(path, ...handlers) {
|
|
24
|
-
this.addRoute('PATCH', path, handlers);
|
|
25
|
-
}
|
|
26
|
-
addRoute(method, path, handlers) {
|
|
27
|
-
const { pattern, paramNames } = this.pathToRegex(path);
|
|
28
|
-
const handler = handlers.pop();
|
|
29
|
-
const middleware = handlers;
|
|
30
|
-
const route = {
|
|
31
|
-
method,
|
|
32
|
-
path,
|
|
33
|
-
pattern,
|
|
34
|
-
paramNames,
|
|
35
|
-
handler,
|
|
36
|
-
middleware,
|
|
37
|
-
};
|
|
38
|
-
// Add to routes array (maintain compatibility)
|
|
39
|
-
this.routes.push(route);
|
|
40
|
-
// Performance optimization: separate static and dynamic routes
|
|
41
|
-
const isStatic = !path.includes(':') && !path.includes('*');
|
|
42
|
-
if (isStatic && middleware.length === 0) {
|
|
43
|
-
// Static route with no middleware - use O(1) lookup
|
|
44
|
-
const routeKey = `${method}:${path}`;
|
|
45
|
-
this.staticRoutes.set(routeKey, route);
|
|
46
|
-
this.logger.debug(`Added static route: ${routeKey}`, 'FastRoute');
|
|
47
|
-
}
|
|
48
|
-
else {
|
|
49
|
-
// Dynamic route or has middleware - needs regex matching
|
|
50
|
-
this.dynamicRoutes.push(route);
|
|
51
|
-
this.logger.debug(`Added dynamic route: ${method} ${path}`, 'DynamicRoute');
|
|
52
|
-
}
|
|
53
|
-
// Initialize object pool on first route
|
|
54
|
-
if (this.paramObjectPool.length === 0) {
|
|
55
|
-
for (let i = 0; i < this.maxPoolSize; i++) {
|
|
56
|
-
this.paramObjectPool.push({});
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
pathToRegex(path) {
|
|
61
|
-
const paramNames = [];
|
|
62
|
-
// Convert parameterized routes to regex
|
|
63
|
-
const regexPattern = path
|
|
64
|
-
.replace(/\/:([^/]+)/g, (match, paramName) => {
|
|
65
|
-
paramNames.push(paramName);
|
|
66
|
-
return '/([^/]+)';
|
|
67
|
-
})
|
|
68
|
-
.replace(/\//g, '\\/');
|
|
69
|
-
return {
|
|
70
|
-
pattern: new RegExp(`^${regexPattern}$`),
|
|
71
|
-
paramNames,
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
async handle(req, res, basePath = '') {
|
|
75
|
-
let path = req.path.startsWith(basePath) ? req.path.substring(basePath.length) : req.path;
|
|
76
|
-
// If removing basePath results in empty string, default to '/'
|
|
77
|
-
if (path === '' || path === undefined) {
|
|
78
|
-
path = '/';
|
|
79
|
-
}
|
|
80
|
-
this.logger.debug(`Router processing: originalPath="${req.path}", basePath="${basePath}", processedPath="${path}"`, 'Processing');
|
|
81
|
-
// PERFORMANCE OPTIMIZATION: Fast path - O(1) static route lookup first
|
|
82
|
-
const routeKey = `${req.method}:${path}`;
|
|
83
|
-
const staticRoute = this.staticRoutes.get(routeKey);
|
|
84
|
-
if (staticRoute) {
|
|
85
|
-
this.logger.debug(`Fast route match: ${routeKey}`, 'FastRoute');
|
|
86
|
-
// Static route with no middleware - execute handler directly
|
|
87
|
-
req.params = {}; // No params for static routes
|
|
88
|
-
const result = await staticRoute.handler(req, res);
|
|
89
|
-
// If handler returns data and response hasn't been sent, send it
|
|
90
|
-
if (result !== undefined && result !== null && !res.headersSent) {
|
|
91
|
-
res.json(result);
|
|
92
|
-
}
|
|
93
|
-
return true;
|
|
94
|
-
}
|
|
95
|
-
// Fallback: Dynamic route matching (with middleware support)
|
|
96
|
-
const route = this.dynamicRoutes.find(r => r.method === req.method && r.pattern.test(path));
|
|
97
|
-
this.logger.debug(`Found dynamic route: ${!!route}${route ? ` ${route.method} ${route.path}` : ' none'}`, 'RouteMatch');
|
|
98
|
-
if (!route) {
|
|
99
|
-
return false; // Route not found
|
|
100
|
-
}
|
|
101
|
-
// Extract path parameters using object pooling
|
|
102
|
-
const matches = path.match(route.pattern);
|
|
103
|
-
if (matches) {
|
|
104
|
-
req.params = this.acquireParamObject();
|
|
105
|
-
route.paramNames.forEach((name, index) => {
|
|
106
|
-
req.params[name] = matches[index + 1];
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
try {
|
|
110
|
-
// Execute middleware
|
|
111
|
-
for (const mw of route.middleware) {
|
|
112
|
-
await new Promise((resolve, reject) => {
|
|
113
|
-
let nextCalled = false;
|
|
114
|
-
const next = () => {
|
|
115
|
-
if (nextCalled)
|
|
116
|
-
return;
|
|
117
|
-
nextCalled = true;
|
|
118
|
-
resolve();
|
|
119
|
-
};
|
|
120
|
-
try {
|
|
121
|
-
const result = mw(req, res, next);
|
|
122
|
-
if (result instanceof Promise) {
|
|
123
|
-
result
|
|
124
|
-
.then(() => {
|
|
125
|
-
if (!nextCalled)
|
|
126
|
-
next();
|
|
127
|
-
})
|
|
128
|
-
.catch(reject);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
catch (error) {
|
|
132
|
-
reject(error);
|
|
133
|
-
}
|
|
134
|
-
});
|
|
135
|
-
if (res.headersSent)
|
|
136
|
-
break; // Early exit if response sent
|
|
137
|
-
}
|
|
138
|
-
// Execute handler
|
|
139
|
-
const result = await route.handler(req, res);
|
|
140
|
-
// If handler returns data and response hasn't been sent, send it
|
|
141
|
-
if (result !== undefined && result !== null && !res.headersSent) {
|
|
142
|
-
res.json(result);
|
|
143
|
-
}
|
|
144
|
-
return true;
|
|
145
|
-
}
|
|
146
|
-
finally {
|
|
147
|
-
// Release parameter object back to pool
|
|
148
|
-
if (req.params && matches) {
|
|
149
|
-
this.releaseParamObject(req.params);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
getRoutes() {
|
|
154
|
-
return [...this.routes];
|
|
155
|
-
}
|
|
156
|
-
// Object pooling methods for performance optimization
|
|
157
|
-
acquireParamObject() {
|
|
158
|
-
const obj = this.paramObjectPool.pop();
|
|
159
|
-
if (obj) {
|
|
160
|
-
// Clear the object
|
|
161
|
-
for (const key in obj) {
|
|
162
|
-
delete obj[key];
|
|
163
|
-
}
|
|
164
|
-
return obj;
|
|
165
|
-
}
|
|
166
|
-
return {};
|
|
167
|
-
}
|
|
168
|
-
releaseParamObject(obj) {
|
|
169
|
-
if (this.paramObjectPool.length < this.maxPoolSize) {
|
|
170
|
-
this.paramObjectPool.push(obj);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
// Performance statistics for monitoring
|
|
174
|
-
getPerformanceStats() {
|
|
175
|
-
return {
|
|
176
|
-
totalRoutes: this.routes.length,
|
|
177
|
-
staticRoutes: this.staticRoutes.size,
|
|
178
|
-
dynamicRoutes: this.dynamicRoutes.length,
|
|
179
|
-
paramObjectPoolSize: this.paramObjectPool.length,
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
//# sourceMappingURL=router.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"router.js","sourceRoot":"","sources":["../../../src/core/http/router.ts"],"names":[],"mappings":"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"}
|