@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.
Files changed (68) hide show
  1. package/dist/core/config/config-sources.js +4 -0
  2. package/dist/core/config/config-sources.js.map +1 -1
  3. package/dist/core/config/config-validator.js +3 -0
  4. package/dist/core/config/config-validator.js.map +1 -1
  5. package/dist/core/config/file-loader.js +3 -1
  6. package/dist/core/config/file-loader.js.map +1 -1
  7. package/dist/core/config/schema.js +4 -1
  8. package/dist/core/config/schema.js.map +1 -1
  9. package/dist/core/events/event-bus.js +1 -1
  10. package/dist/core/events/event-bus.js.map +1 -1
  11. package/dist/core/framework.d.ts +1 -1
  12. package/dist/core/framework.js +13 -7
  13. package/dist/core/framework.js.map +1 -1
  14. package/dist/core/http/http-server.d.ts +55 -15
  15. package/dist/core/http/http-server.js +70 -146
  16. package/dist/core/http/http-server.js.map +1 -1
  17. package/dist/core/http/index.d.ts +1 -1
  18. package/dist/core/http/index.js +1 -1
  19. package/dist/core/http/index.js.map +1 -1
  20. package/dist/core/http/uws-http-server.d.ts +4 -22
  21. package/dist/core/http/uws-http-server.js +43 -208
  22. package/dist/core/http/uws-http-server.js.map +1 -1
  23. package/dist/core/networking/adapters/uws-adapter.d.ts +1 -1
  24. package/dist/core/networking/adapters/uws-adapter.js +1 -1
  25. package/dist/core/pooling/object-pool-manager.d.ts +140 -0
  26. package/dist/core/pooling/object-pool-manager.js +502 -0
  27. package/dist/core/pooling/object-pool-manager.js.map +1 -0
  28. package/dist/core/routing/app-integration.d.ts +12 -10
  29. package/dist/core/routing/app-integration.js +43 -74
  30. package/dist/core/routing/app-integration.js.map +1 -1
  31. package/dist/core/routing/index.d.ts +15 -29
  32. package/dist/core/routing/index.js +43 -390
  33. package/dist/core/routing/index.js.map +1 -1
  34. package/dist/core/routing/path-matcher.d.ts +67 -0
  35. package/dist/core/routing/path-matcher.js +182 -0
  36. package/dist/core/routing/path-matcher.js.map +1 -0
  37. package/dist/core/{http → routing}/router.d.ts +21 -9
  38. package/dist/core/routing/router.js +68 -0
  39. package/dist/core/routing/router.js.map +1 -0
  40. package/dist/core/routing/unified-router.d.ts +148 -0
  41. package/dist/core/routing/unified-router.js +684 -0
  42. package/dist/core/routing/unified-router.js.map +1 -0
  43. package/dist/moro.d.ts +10 -7
  44. package/dist/moro.js +90 -41
  45. package/dist/moro.js.map +1 -1
  46. package/dist/types/config.d.ts +3 -0
  47. package/package.json +1 -1
  48. package/src/core/config/config-sources.ts +4 -0
  49. package/src/core/config/config-validator.ts +3 -0
  50. package/src/core/config/file-loader.ts +4 -1
  51. package/src/core/config/schema.ts +4 -1
  52. package/src/core/events/event-bus.ts +1 -1
  53. package/src/core/framework.ts +14 -9
  54. package/src/core/http/http-server.ts +76 -161
  55. package/src/core/http/index.ts +1 -1
  56. package/src/core/http/uws-http-server.ts +43 -246
  57. package/src/core/networking/adapters/uws-adapter.ts +1 -1
  58. package/src/core/pooling/object-pool-manager.ts +630 -0
  59. package/src/core/routing/app-integration.ts +57 -109
  60. package/src/core/routing/index.ts +62 -473
  61. package/src/core/routing/path-matcher.ts +222 -0
  62. package/src/core/routing/router.ts +97 -0
  63. package/src/core/routing/unified-router.ts +870 -0
  64. package/src/moro.ts +107 -57
  65. package/src/types/config.ts +3 -0
  66. package/dist/core/http/router.js +0 -183
  67. package/dist/core/http/router.js.map +0 -1
  68. package/src/core/http/router.ts +0 -230
@@ -1,8 +1,9 @@
1
1
  // uWebSockets.js HTTP Server Implementation for Moro Framework
2
- // Provides ultra-high-performance HTTP and WebSocket server using uWebSockets.js
2
+ // Provides high-performance HTTP and WebSocket server using uWebSockets.js
3
3
 
4
4
  import cluster from 'cluster';
5
5
  import { createFrameworkLogger } from '../logger/index.js';
6
+ import { ObjectPoolManager } from '../pooling/object-pool-manager.js';
6
7
  import {
7
8
  HttpRequest,
8
9
  HttpResponse,
@@ -19,24 +20,18 @@ export class UWebSocketsHttpServer {
19
20
  private app: any; // uWebSockets app instance
20
21
  private uws: any; // uWebSockets module reference (stored to avoid re-importing)
21
22
  private listenSocket: any; // uWebSockets listen socket
22
- private routes: RouteEntry[] = [];
23
23
  private globalMiddleware: Middleware[] = [];
24
24
  private logger = createFrameworkLogger('UWSHttpServer');
25
25
  private hookManager: any;
26
26
  private requestCounter = 0;
27
+ private requestTrackingEnabled = true; // Generate request IDs
27
28
  private isListening = false;
28
29
  private port?: number;
29
30
  private host?: string;
30
31
  private initPromise: Promise<void>;
31
32
 
32
- // Route caching for performance
33
- private staticRoutes = new Map<string, RouteEntry>();
34
- private dynamicRoutes: RouteEntry[] = [];
35
-
36
- // Performance optimizations - object pooling
37
- private paramObjectPool: Record<string, string>[] = [];
38
- private queryObjectPool: Record<string, string>[] = [];
39
- private readonly maxPoolSize = 100;
33
+ // Performance optimizations - shared object pooling
34
+ private poolManager = ObjectPoolManager.getInstance();
40
35
 
41
36
  // String interning for common values
42
37
  private static readonly INTERNED_METHODS = new Map([
@@ -102,118 +97,24 @@ export class UWebSocketsHttpServer {
102
97
  }
103
98
 
104
99
  private setupRouteHandlers(): void {
105
- // Handle all HTTP methods through catchall for proper routing
100
+ // Handle all HTTP methods through catchall
101
+ // All requests go through middleware chain (includes UnifiedRouter)
106
102
  this.app.any('/*', (res: any, req: any) => {
107
- // Try fast synchronous path first
108
- const method = req.getMethod().toUpperCase();
109
- const path = req.getUrl();
110
-
111
- // Fast path: No body, no global middleware
112
- if (this.globalMiddleware.length === 0 && method === 'GET') {
113
- const route = this.findRoute(method, path);
114
- if (route && (!route.middleware || route.middleware.length === 0)) {
115
- this.handleRequestSync(req, res, route, method, path);
116
- return;
117
- }
118
- }
119
-
120
- // Slow path: Has middleware or body or other complexity
121
103
  this.handleRequest(req, res);
122
104
  });
123
105
  }
124
106
 
125
- // Fast synchronous handler for simple GET requests
126
- private handleRequestSync(
127
- req: any,
128
- res: any,
129
- route: RouteEntry,
130
- method: string,
131
- path: string
132
- ): void {
133
- this.requestCounter++;
134
- let httpReq: any;
135
-
136
- try {
137
- httpReq = this.createMoroRequest(req, res);
138
- const httpRes = this.createMoroResponse(req, res);
139
-
140
- // Extract params if needed
141
- if (route.paramNames.length > 0) {
142
- const matches = path.match(route.pattern);
143
- if (matches) {
144
- httpReq.params = this.acquireParamObject();
145
- route.paramNames.forEach((name: string, index: number) => {
146
- httpReq.params![name] = matches[index + 1];
147
- });
148
- (httpReq as any)._pooledParams = httpReq.params;
149
- }
150
- }
151
-
152
- // Execute handler synchronously
153
- const result = route.handler(httpReq, httpRes);
154
-
155
- // Handle return value
156
- if (result && typeof result.then === 'function') {
157
- // Oops, handler is async - handle it
158
- result
159
- .then((data: any) => {
160
- if (data !== undefined && data !== null && !httpRes.headersSent) {
161
- httpRes.json(data);
162
- }
163
- })
164
- .catch(() => {
165
- if (!res.aborted) {
166
- res.cork(() => {
167
- res.writeStatus('500 Internal Server Error');
168
- res.end('{"success":false,"error":"Internal server error"}');
169
- });
170
- }
171
- });
172
- } else if (result !== undefined && result !== null && !httpRes.headersSent) {
173
- httpRes.json(result);
174
- }
175
- } finally {
176
- const pooledParams = (httpReq as any)?._pooledParams;
177
- if (pooledParams) this.releaseParamObject(pooledParams);
178
-
179
- const pooledQuery = (httpReq as any)?._pooledQuery;
180
- if (pooledQuery) this.releaseQueryObject(pooledQuery);
181
- }
182
- }
183
-
184
- // Object pooling methods for performance
185
- private acquireParamObject(): Record<string, string> {
186
- return this.paramObjectPool.pop() || {};
187
- }
188
-
189
- private releaseParamObject(obj: Record<string, string>): void {
190
- if (this.paramObjectPool.length < this.maxPoolSize) {
191
- for (const key in obj) delete obj[key];
192
- this.paramObjectPool.push(obj);
193
- }
194
- }
195
-
196
- private acquireQueryObject(): Record<string, string> {
197
- return this.queryObjectPool.pop() || {};
198
- }
199
-
200
- private releaseQueryObject(obj: Record<string, string>): void {
201
- if (this.queryObjectPool.length < this.maxPoolSize) {
202
- for (const key in obj) delete obj[key];
203
- this.queryObjectPool.push(obj);
204
- }
205
- }
206
-
207
107
  private async handleRequest(req: any, res: any): Promise<void> {
208
108
  this.requestCounter++;
209
109
 
210
110
  // Declare outside try block for cleanup in finally
211
111
  let httpReq: any;
112
+ let httpRes: any;
212
113
 
213
114
  try {
214
115
  // Create Moro-compatible request object
215
116
  httpReq = this.createMoroRequest(req, res);
216
- const httpRes = this.createMoroResponse(req, res);
117
+ httpRes = this.createMoroResponse(req, res);
217
118
 
218
119
  // Parse body only if there's actually a body (check content-length)
219
120
  const method = req.getMethod().toUpperCase();
@@ -234,47 +135,17 @@ export class UWebSocketsHttpServer {
234
135
  });
235
136
  }
236
137
 
237
- // Find route first (before middleware)
238
- const route = this.findRoute(httpReq.method!, httpReq.path);
239
-
240
- if (!route) {
241
- // 404 Not Found - fast path
138
+ // Execute middleware chain (includes UnifiedRouter for routing)
139
+ // The UnifiedRouter will handle route matching, params extraction, and handler execution
140
+ if (this.globalMiddleware.length > 0) {
141
+ await this.executeMiddleware(this.globalMiddleware, httpReq, httpRes);
142
+ } else {
143
+ // No middleware - send 404 (router middleware should be present)
242
144
  if (!httpRes.headersSent) {
243
145
  httpRes.statusCode = 404;
244
146
  httpRes.setHeader('Content-Type', 'application/json');
245
147
  httpRes.end('{"success":false,"error":"Not found"}');
246
148
  }
247
- return;
248
- }
249
-
250
- // Extract path parameters early - use pooled object
251
- const matches = httpReq.path.match(route.pattern);
252
- if (matches) {
253
- httpReq.params = this.acquireParamObject();
254
- route.paramNames.forEach((name: string, index: number) => {
255
- httpReq.params![name] = matches[index + 1];
256
- });
257
- // Store for cleanup
258
- (httpReq as any)._pooledParams = httpReq.params;
259
- }
260
-
261
- // Execute ALL middleware in one pass (global + route)
262
- if (this.globalMiddleware.length > 0 || (route.middleware && route.middleware.length > 0)) {
263
- const allMiddleware =
264
- route.middleware && route.middleware.length > 0
265
- ? [...this.globalMiddleware, ...route.middleware]
266
- : this.globalMiddleware;
267
-
268
- await this.executeMiddleware(allMiddleware, httpReq, httpRes);
269
- if (httpRes.headersSent) return;
270
- }
271
-
272
- // Execute route handler
273
- const result = await route.handler(httpReq, httpRes);
274
-
275
- // If handler returns data and response hasn't been sent, send it
276
- if (result !== undefined && result !== null && !httpRes.headersSent) {
277
- httpRes.json(result);
278
149
  }
279
150
  } catch (error) {
280
151
  this.logger.error(
@@ -295,15 +166,18 @@ export class UWebSocketsHttpServer {
295
166
  }
296
167
  }
297
168
  } finally {
298
- // Cleanup: Release pooled objects back to pool for reuse
299
- const pooledParams = (httpReq as any)._pooledParams;
300
- if (pooledParams) {
301
- this.releaseParamObject(pooledParams);
302
- }
169
+ // CRITICAL: Release pooled objects back to pool
170
+ if (httpReq) {
171
+ const pooledQuery = (httpReq as any)._pooledQuery;
172
+ const pooledHeaders = (httpReq as any)._pooledHeaders;
173
+
174
+ if (pooledQuery && Object.keys(pooledQuery).length > 0) {
175
+ this.poolManager.releaseQuery(pooledQuery);
176
+ }
303
177
 
304
- const pooledQuery = (httpReq as any)._pooledQuery;
305
- if (pooledQuery) {
306
- this.releaseQueryObject(pooledQuery);
178
+ if (pooledHeaders && Object.keys(pooledHeaders).length > 0) {
179
+ this.poolManager.releaseHeaders(pooledHeaders);
180
+ }
307
181
  }
308
182
  }
309
183
  }
@@ -316,11 +190,11 @@ export class UWebSocketsHttpServer {
316
190
  // Use interned method string if available
317
191
  const method = UWebSocketsHttpServer.INTERNED_METHODS.get(methodRaw) || methodRaw.toUpperCase();
318
192
 
319
- // Lazy query parsing - use pooled object
320
- let queryParams: Record<string, string> | undefined;
193
+ // Optimized query parsing with pooled object
194
+ let queryParams: Record<string, string>;
321
195
  if (queryString) {
322
- queryParams = this.acquireQueryObject();
323
- // Fast query parsing without URLSearchParams overhead
196
+ queryParams = this.poolManager.acquireQuery();
197
+ // Query parsing without URLSearchParams overhead
324
198
  const pairs = queryString.split('&');
325
199
  for (let i = 0; i < pairs.length; i++) {
326
200
  const pair = pairs[i];
@@ -331,10 +205,12 @@ export class UWebSocketsHttpServer {
331
205
  queryParams[decodeURIComponent(key)] = decodeURIComponent(value);
332
206
  }
333
207
  }
208
+ } else {
209
+ queryParams = {};
334
210
  }
335
211
 
336
- // Lazy header parsing - only parse headers that exist
337
- const headers: Record<string, string> = {};
212
+ // Optimized header parsing with pooled object
213
+ const headers = this.poolManager.acquireHeaders();
338
214
  req.forEach((key: string, value: string) => {
339
215
  const lowerKey = key.toLowerCase();
340
216
  headers[lowerKey] = value;
@@ -344,16 +220,17 @@ export class UWebSocketsHttpServer {
344
220
  method,
345
221
  path: url,
346
222
  url: url,
347
- query: queryParams || {},
223
+ query: queryParams,
348
224
  params: {}, // Will be filled by route matching
349
225
  headers,
350
226
  body: null,
351
227
  ip: '', // Lazy - only compute if accessed
352
- requestId: '', // Lazy - only generate if accessed
228
+ requestId: this.requestTrackingEnabled ? this.poolManager.generateRequestId() : '', // ID generation (if enabled)
353
229
  } as HttpRequest;
354
230
 
355
- // Store original query object for cleanup
231
+ // Store pooled objects for cleanup
356
232
  (httpReq as any)._pooledQuery = queryParams;
233
+ (httpReq as any)._pooledHeaders = headers;
357
234
 
358
235
  return httpReq;
359
236
  }
@@ -599,99 +476,19 @@ export class UWebSocketsHttpServer {
599
476
  }
600
477
  }
601
478
 
602
- private findRoute(method: string, path: string): RouteEntry | null {
603
- // Fast path: static route lookup
604
- const staticKey = `${method}:${path}`;
605
- const staticRoute = this.staticRoutes.get(staticKey);
606
- if (staticRoute) return staticRoute;
607
-
608
- // Dynamic route matching
609
- for (const route of this.dynamicRoutes) {
610
- if (route.method === method && route.pattern.test(path)) {
611
- return route;
612
- }
613
- }
614
-
615
- return null;
616
- }
617
-
618
479
  // Public API - matches MoroHttpServer interface
619
480
 
620
481
  use(middleware: Middleware): void {
621
482
  this.globalMiddleware.push(middleware);
622
483
  }
623
484
 
624
- get(path: string, handler: HttpHandler, middleware?: Middleware[]): void {
625
- this.addRoute('GET', path, handler, middleware);
626
- }
627
-
628
- post(path: string, handler: HttpHandler, middleware?: Middleware[]): void {
629
- this.addRoute('POST', path, handler, middleware);
485
+ // Configure request tracking (ID generation)
486
+ setRequestTracking(enabled: boolean): void {
487
+ this.requestTrackingEnabled = enabled;
630
488
  }
631
489
 
632
- put(path: string, handler: HttpHandler, middleware?: Middleware[]): void {
633
- this.addRoute('PUT', path, handler, middleware);
634
- }
635
-
636
- delete(path: string, handler: HttpHandler, middleware?: Middleware[]): void {
637
- this.addRoute('DELETE', path, handler, middleware);
638
- }
639
-
640
- patch(path: string, handler: HttpHandler, middleware?: Middleware[]): void {
641
- this.addRoute('PATCH', path, handler, middleware);
642
- }
643
-
644
- options(path: string, handler: HttpHandler, middleware?: Middleware[]): void {
645
- this.addRoute('OPTIONS', path, handler, middleware);
646
- }
647
-
648
- head(path: string, handler: HttpHandler, middleware?: Middleware[]): void {
649
- this.addRoute('HEAD', path, handler, middleware);
650
- }
651
-
652
- private addRoute(
653
- method: string,
654
- path: string,
655
- handler: HttpHandler,
656
- middleware?: Middleware[]
657
- ): void {
658
- const { pattern, paramNames } = this.pathToRegex(path);
659
-
660
- const route: RouteEntry = {
661
- method,
662
- path,
663
- pattern,
664
- paramNames,
665
- handler,
666
- middleware: middleware || [],
667
- };
668
-
669
- this.routes.push(route);
670
-
671
- // Optimize route lookup
672
- if (paramNames.length === 0) {
673
- // Static route
674
- this.staticRoutes.set(`${method}:${path}`, route);
675
- } else {
676
- // Dynamic route
677
- this.dynamicRoutes.push(route);
678
- }
679
-
680
- this.logger.debug(`Route registered: ${method} ${path}`, 'RouteRegistration');
681
- }
682
-
683
- private pathToRegex(path: string): { pattern: RegExp; paramNames: string[] } {
684
- const paramNames: string[] = [];
685
- const regexPath = path.replace(/\//g, '\\/').replace(/:([^/]+)/g, (match, paramName) => {
686
- paramNames.push(paramName);
687
- return '([^/]+)';
688
- });
689
-
690
- return {
691
- pattern: new RegExp(`^${regexPath}$`),
692
- paramNames,
693
- };
694
- }
490
+ // Note: Route registration methods (get, post, etc.) are not used by uWebSockets adapter
491
+ // All routing is handled by UnifiedRouter through the middleware chain
695
492
 
696
493
  setHookManager(hookManager: any): void {
697
494
  this.hookManager = hookManager;
@@ -15,7 +15,7 @@ import { createFrameworkLogger } from '../../logger/index.js';
15
15
 
16
16
  /**
17
17
  * uWebSockets adapter implementation
18
- * Provides ultra-high-performance WebSocket support using uWebSockets.js
18
+ * Provides high-performance WebSocket support using uWebSockets.js
19
19
  */
20
20
  export class UWebSocketsAdapter implements WebSocketAdapter {
21
21
  private app: any; // uWebSockets app instance