@morojs/moro 1.5.5 → 1.5.6
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-manager.d.ts +44 -0
- package/dist/core/config/config-manager.js +114 -0
- package/dist/core/config/config-manager.js.map +1 -0
- package/dist/core/config/config-sources.d.ts +21 -0
- package/dist/core/config/config-sources.js +314 -0
- package/dist/core/config/config-sources.js.map +1 -0
- package/dist/core/config/config-validator.d.ts +21 -0
- package/dist/core/config/config-validator.js +737 -0
- package/dist/core/config/config-validator.js.map +1 -0
- package/dist/core/config/file-loader.d.ts +0 -5
- package/dist/core/config/file-loader.js +0 -171
- package/dist/core/config/file-loader.js.map +1 -1
- package/dist/core/config/index.d.ts +39 -10
- package/dist/core/config/index.js +66 -29
- package/dist/core/config/index.js.map +1 -1
- package/dist/core/config/schema.js +22 -31
- package/dist/core/config/schema.js.map +1 -1
- package/dist/core/config/utils.d.ts +9 -2
- package/dist/core/config/utils.js +19 -32
- package/dist/core/config/utils.js.map +1 -1
- package/dist/core/framework.d.ts +2 -7
- package/dist/core/framework.js +12 -5
- package/dist/core/framework.js.map +1 -1
- package/dist/core/http/http-server.d.ts +12 -0
- package/dist/core/http/http-server.js +56 -0
- package/dist/core/http/http-server.js.map +1 -1
- package/dist/core/http/router.d.ts +12 -0
- package/dist/core/http/router.js +114 -36
- package/dist/core/http/router.js.map +1 -1
- package/dist/core/logger/index.d.ts +1 -1
- package/dist/core/logger/index.js +2 -1
- package/dist/core/logger/index.js.map +1 -1
- package/dist/core/logger/logger.d.ts +9 -1
- package/dist/core/logger/logger.js +36 -3
- package/dist/core/logger/logger.js.map +1 -1
- package/dist/core/routing/index.d.ts +20 -0
- package/dist/core/routing/index.js +109 -11
- package/dist/core/routing/index.js.map +1 -1
- package/dist/moro.d.ts +7 -20
- package/dist/moro.js +97 -192
- package/dist/moro.js.map +1 -1
- package/dist/types/config.d.ts +39 -2
- package/dist/types/core.d.ts +22 -39
- package/dist/types/logger.d.ts +4 -0
- package/package.json +1 -1
- package/src/core/config/config-manager.ts +133 -0
- package/src/core/config/config-sources.ts +384 -0
- package/src/core/config/config-validator.ts +1035 -0
- package/src/core/config/file-loader.ts +0 -233
- package/src/core/config/index.ts +77 -32
- package/src/core/config/schema.ts +22 -31
- package/src/core/config/utils.ts +22 -29
- package/src/core/framework.ts +18 -11
- package/src/core/http/http-server.ts +66 -0
- package/src/core/http/router.ts +127 -38
- package/src/core/logger/index.ts +1 -0
- package/src/core/logger/logger.ts +43 -4
- package/src/core/routing/index.ts +116 -12
- package/src/moro.ts +105 -225
- package/src/types/config.ts +40 -2
- package/src/types/core.ts +32 -43
- package/src/types/logger.ts +6 -0
- package/dist/core/config/loader.d.ts +0 -7
- package/dist/core/config/loader.js +0 -269
- package/dist/core/config/loader.js.map +0 -1
- package/dist/core/config/validation.d.ts +0 -17
- package/dist/core/config/validation.js +0 -131
- package/dist/core/config/validation.js.map +0 -1
- package/src/core/config/loader.ts +0 -633
- package/src/core/config/validation.ts +0 -140
|
@@ -26,6 +26,11 @@ export class MoroHttpServer {
|
|
|
26
26
|
// Request handler pooling to avoid function creation overhead
|
|
27
27
|
private middlewareExecutionCache = new Map<string, Function>();
|
|
28
28
|
|
|
29
|
+
// Response caching for ultra-fast common responses
|
|
30
|
+
private responseCache = new Map<string, Buffer>();
|
|
31
|
+
private responseCacheHits = 0;
|
|
32
|
+
private responseCacheMisses = 0;
|
|
33
|
+
|
|
29
34
|
// String interning for common values (massive memory savings)
|
|
30
35
|
private static readonly INTERNED_METHODS = new Map([
|
|
31
36
|
['GET', 'GET'],
|
|
@@ -492,6 +497,20 @@ export class MoroHttpServer {
|
|
|
492
497
|
httpRes.json = async (data: any) => {
|
|
493
498
|
if (httpRes.headersSent) return;
|
|
494
499
|
|
|
500
|
+
// PERFORMANCE OPTIMIZATION: Check response cache for common patterns
|
|
501
|
+
const cacheKey = this.getResponseCacheKey(data);
|
|
502
|
+
if (cacheKey) {
|
|
503
|
+
const cachedBuffer = this.responseCache.get(cacheKey);
|
|
504
|
+
if (cachedBuffer) {
|
|
505
|
+
this.responseCacheHits++;
|
|
506
|
+
httpRes.setHeader('Content-Type', 'application/json; charset=utf-8');
|
|
507
|
+
httpRes.setHeader('Content-Length', cachedBuffer.length);
|
|
508
|
+
httpRes.end(cachedBuffer);
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
this.responseCacheMisses++;
|
|
512
|
+
}
|
|
513
|
+
|
|
495
514
|
// Ultra-fast JSON serialization with zero-copy buffers
|
|
496
515
|
let jsonString: string;
|
|
497
516
|
|
|
@@ -578,6 +597,12 @@ export class MoroHttpServer {
|
|
|
578
597
|
});
|
|
579
598
|
|
|
580
599
|
httpRes.end(finalBuffer);
|
|
600
|
+
|
|
601
|
+
// PERFORMANCE OPTIMIZATION: Cache small, common responses
|
|
602
|
+
if (cacheKey && finalBuffer.length < 1024 && this.responseCache.size < 100) {
|
|
603
|
+
this.responseCache.set(cacheKey, Buffer.from(finalBuffer));
|
|
604
|
+
}
|
|
605
|
+
|
|
581
606
|
// Return buffer to pool after response (zero-copy achievement!)
|
|
582
607
|
process.nextTick(() => MoroHttpServer.returnBuffer(buffer));
|
|
583
608
|
};
|
|
@@ -953,6 +978,47 @@ export class MoroHttpServer {
|
|
|
953
978
|
getServer(): Server {
|
|
954
979
|
return this.server;
|
|
955
980
|
}
|
|
981
|
+
|
|
982
|
+
// PERFORMANCE OPTIMIZATION: Generate cache key for common response patterns
|
|
983
|
+
private getResponseCacheKey(data: any): string | null {
|
|
984
|
+
// Only cache simple, common responses
|
|
985
|
+
if (!data || typeof data !== 'object') {
|
|
986
|
+
// Simple primitives or strings - generate key
|
|
987
|
+
const key = JSON.stringify(data);
|
|
988
|
+
return key.length < 100 ? key : null;
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
// Common API response patterns
|
|
992
|
+
if ('hello' in data && Object.keys(data).length <= 2) {
|
|
993
|
+
// Hello world type responses
|
|
994
|
+
return `hello:${JSON.stringify(data)}`;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
if ('status' in data && Object.keys(data).length <= 3) {
|
|
998
|
+
// Status responses like {status: "ok", version: "1.0.0"}
|
|
999
|
+
return `status:${JSON.stringify(data)}`;
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
if ('success' in data && 'message' in data && Object.keys(data).length <= 3) {
|
|
1003
|
+
// Simple success/error responses
|
|
1004
|
+
return `msg:${data.success}:${data.message}`;
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
// Don't cache complex objects
|
|
1008
|
+
return null;
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
// Performance statistics
|
|
1012
|
+
getPerformanceStats() {
|
|
1013
|
+
return {
|
|
1014
|
+
responseCacheHits: this.responseCacheHits,
|
|
1015
|
+
responseCacheMisses: this.responseCacheMisses,
|
|
1016
|
+
responseCacheSize: this.responseCache.size,
|
|
1017
|
+
paramObjectPoolSize: this.paramObjectPool.length,
|
|
1018
|
+
bufferPoolSize: this.bufferPool.length,
|
|
1019
|
+
middlewareExecutionCacheSize: this.middlewareExecutionCache.size,
|
|
1020
|
+
};
|
|
1021
|
+
}
|
|
956
1022
|
}
|
|
957
1023
|
|
|
958
1024
|
// Built-in middleware
|
package/src/core/http/router.ts
CHANGED
|
@@ -12,6 +12,14 @@ export class Router {
|
|
|
12
12
|
private routes: RouteDefinition[] = [];
|
|
13
13
|
private logger = createFrameworkLogger('Router');
|
|
14
14
|
|
|
15
|
+
// Performance optimizations - O(1) static route lookup
|
|
16
|
+
private staticRoutes = new Map<string, RouteDefinition>(); // "GET:/api/users" -> route
|
|
17
|
+
private dynamicRoutes: RouteDefinition[] = []; // Routes with parameters
|
|
18
|
+
|
|
19
|
+
// Object pooling for parameters to reduce GC pressure
|
|
20
|
+
private paramObjectPool: Record<string, string>[] = [];
|
|
21
|
+
private readonly maxPoolSize = 50;
|
|
22
|
+
|
|
15
23
|
get(path: string, ...handlers: (Middleware | HttpHandler)[]): void {
|
|
16
24
|
this.addRoute('GET', path, handlers);
|
|
17
25
|
}
|
|
@@ -37,14 +45,37 @@ export class Router {
|
|
|
37
45
|
const handler = handlers.pop() as HttpHandler;
|
|
38
46
|
const middleware = handlers as Middleware[];
|
|
39
47
|
|
|
40
|
-
|
|
48
|
+
const route: RouteDefinition = {
|
|
41
49
|
method,
|
|
42
50
|
path,
|
|
43
51
|
pattern,
|
|
44
52
|
paramNames,
|
|
45
53
|
handler,
|
|
46
54
|
middleware,
|
|
47
|
-
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// Add to routes array (maintain compatibility)
|
|
58
|
+
this.routes.push(route);
|
|
59
|
+
|
|
60
|
+
// Performance optimization: separate static and dynamic routes
|
|
61
|
+
const isStatic = !path.includes(':') && !path.includes('*');
|
|
62
|
+
if (isStatic && middleware.length === 0) {
|
|
63
|
+
// Static route with no middleware - use O(1) lookup
|
|
64
|
+
const routeKey = `${method}:${path}`;
|
|
65
|
+
this.staticRoutes.set(routeKey, route);
|
|
66
|
+
this.logger.debug(`Added static route: ${routeKey}`, 'FastRoute');
|
|
67
|
+
} else {
|
|
68
|
+
// Dynamic route or has middleware - needs regex matching
|
|
69
|
+
this.dynamicRoutes.push(route);
|
|
70
|
+
this.logger.debug(`Added dynamic route: ${method} ${path}`, 'DynamicRoute');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Initialize object pool on first route
|
|
74
|
+
if (this.paramObjectPool.length === 0) {
|
|
75
|
+
for (let i = 0; i < this.maxPoolSize; i++) {
|
|
76
|
+
this.paramObjectPool.push({});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
48
79
|
}
|
|
49
80
|
|
|
50
81
|
private pathToRegex(path: string): { pattern: RegExp; paramNames: string[] } {
|
|
@@ -77,10 +108,30 @@ export class Router {
|
|
|
77
108
|
'Processing'
|
|
78
109
|
);
|
|
79
110
|
|
|
80
|
-
|
|
111
|
+
// PERFORMANCE OPTIMIZATION: Fast path - O(1) static route lookup first
|
|
112
|
+
const routeKey = `${req.method}:${path}`;
|
|
113
|
+
const staticRoute = this.staticRoutes.get(routeKey);
|
|
114
|
+
|
|
115
|
+
if (staticRoute) {
|
|
116
|
+
this.logger.debug(`Fast route match: ${routeKey}`, 'FastRoute');
|
|
117
|
+
|
|
118
|
+
// Static route with no middleware - execute handler directly
|
|
119
|
+
req.params = {}; // No params for static routes
|
|
120
|
+
const result = await staticRoute.handler(req, res);
|
|
121
|
+
|
|
122
|
+
// If handler returns data and response hasn't been sent, send it
|
|
123
|
+
if (result !== undefined && result !== null && !res.headersSent) {
|
|
124
|
+
res.json(result);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Fallback: Dynamic route matching (with middleware support)
|
|
131
|
+
const route = this.dynamicRoutes.find(r => r.method === req.method && r.pattern.test(path));
|
|
81
132
|
|
|
82
133
|
this.logger.debug(
|
|
83
|
-
`Found route: ${!!route}${route ? ` ${route.method} ${route.path}` : ' none'}`,
|
|
134
|
+
`Found dynamic route: ${!!route}${route ? ` ${route.method} ${route.path}` : ' none'}`,
|
|
84
135
|
'RouteMatch'
|
|
85
136
|
);
|
|
86
137
|
|
|
@@ -88,54 +139,92 @@ export class Router {
|
|
|
88
139
|
return false; // Route not found
|
|
89
140
|
}
|
|
90
141
|
|
|
91
|
-
// Extract path parameters
|
|
142
|
+
// Extract path parameters using object pooling
|
|
92
143
|
const matches = path.match(route.pattern);
|
|
93
144
|
if (matches) {
|
|
94
|
-
req.params =
|
|
145
|
+
req.params = this.acquireParamObject();
|
|
95
146
|
route.paramNames.forEach((name, index) => {
|
|
96
147
|
req.params[name] = matches[index + 1];
|
|
97
148
|
});
|
|
98
149
|
}
|
|
99
150
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
result
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
151
|
+
try {
|
|
152
|
+
// Execute middleware
|
|
153
|
+
for (const mw of route.middleware) {
|
|
154
|
+
await new Promise<void>((resolve, reject) => {
|
|
155
|
+
let nextCalled = false;
|
|
156
|
+
|
|
157
|
+
const next = () => {
|
|
158
|
+
if (nextCalled) return;
|
|
159
|
+
nextCalled = true;
|
|
160
|
+
resolve();
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
try {
|
|
164
|
+
const result = mw(req, res, next);
|
|
165
|
+
|
|
166
|
+
if (result instanceof Promise) {
|
|
167
|
+
result
|
|
168
|
+
.then(() => {
|
|
169
|
+
if (!nextCalled) next();
|
|
170
|
+
})
|
|
171
|
+
.catch(reject);
|
|
172
|
+
}
|
|
173
|
+
} catch (error) {
|
|
174
|
+
reject(error);
|
|
120
175
|
}
|
|
121
|
-
}
|
|
122
|
-
reject(error);
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
}
|
|
176
|
+
});
|
|
126
177
|
|
|
127
|
-
|
|
128
|
-
|
|
178
|
+
if (res.headersSent) break; // Early exit if response sent
|
|
179
|
+
}
|
|
129
180
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
res.json(result);
|
|
133
|
-
}
|
|
181
|
+
// Execute handler
|
|
182
|
+
const result = await route.handler(req, res);
|
|
134
183
|
|
|
135
|
-
|
|
184
|
+
// If handler returns data and response hasn't been sent, send it
|
|
185
|
+
if (result !== undefined && result !== null && !res.headersSent) {
|
|
186
|
+
res.json(result);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return true;
|
|
190
|
+
} finally {
|
|
191
|
+
// Release parameter object back to pool
|
|
192
|
+
if (req.params && matches) {
|
|
193
|
+
this.releaseParamObject(req.params);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
136
196
|
}
|
|
137
197
|
|
|
138
198
|
getRoutes(): RouteDefinition[] {
|
|
139
199
|
return [...this.routes];
|
|
140
200
|
}
|
|
201
|
+
|
|
202
|
+
// Object pooling methods for performance optimization
|
|
203
|
+
private acquireParamObject(): Record<string, string> {
|
|
204
|
+
const obj = this.paramObjectPool.pop();
|
|
205
|
+
if (obj) {
|
|
206
|
+
// Clear the object
|
|
207
|
+
for (const key in obj) {
|
|
208
|
+
delete obj[key];
|
|
209
|
+
}
|
|
210
|
+
return obj;
|
|
211
|
+
}
|
|
212
|
+
return {};
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
private releaseParamObject(obj: Record<string, string>): void {
|
|
216
|
+
if (this.paramObjectPool.length < this.maxPoolSize) {
|
|
217
|
+
this.paramObjectPool.push(obj);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Performance statistics for monitoring
|
|
222
|
+
getPerformanceStats() {
|
|
223
|
+
return {
|
|
224
|
+
totalRoutes: this.routes.length,
|
|
225
|
+
staticRoutes: this.staticRoutes.size,
|
|
226
|
+
dynamicRoutes: this.dynamicRoutes.length,
|
|
227
|
+
paramObjectPoolSize: this.paramObjectPool.length,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
141
230
|
}
|
package/src/core/logger/index.ts
CHANGED
|
@@ -60,6 +60,7 @@ export class MoroLogger implements Logger {
|
|
|
60
60
|
// Buffer overflow protection
|
|
61
61
|
private bufferOverflowThreshold: number;
|
|
62
62
|
private emergencyFlushInProgress = false;
|
|
63
|
+
private isDestroyed = false;
|
|
63
64
|
|
|
64
65
|
// High-performance output methods
|
|
65
66
|
|
|
@@ -226,7 +227,9 @@ export class MoroLogger implements Logger {
|
|
|
226
227
|
}
|
|
227
228
|
|
|
228
229
|
child(context: string, metadata?: Record<string, any>): Logger {
|
|
229
|
-
|
|
230
|
+
// Create child logger with current parent level (not original options level)
|
|
231
|
+
const childOptions = { ...this.options, level: this.level };
|
|
232
|
+
const childLogger = new MoroLogger(childOptions);
|
|
230
233
|
childLogger.contextPrefix = this.contextPrefix ? `${this.contextPrefix}:${context}` : context;
|
|
231
234
|
childLogger.contextMetadata = { ...this.contextMetadata, ...metadata };
|
|
232
235
|
childLogger.outputs = this.outputs;
|
|
@@ -242,6 +245,10 @@ export class MoroLogger implements Logger {
|
|
|
242
245
|
this.level = level;
|
|
243
246
|
}
|
|
244
247
|
|
|
248
|
+
getLevel(): LogLevel {
|
|
249
|
+
return this.level;
|
|
250
|
+
}
|
|
251
|
+
|
|
245
252
|
addOutput(output: LogOutput): void {
|
|
246
253
|
this.outputs.set(output.name, output);
|
|
247
254
|
}
|
|
@@ -725,8 +732,8 @@ export class MoroLogger implements Logger {
|
|
|
725
732
|
}
|
|
726
733
|
|
|
727
734
|
private scheduleFlush(): void {
|
|
728
|
-
if (this.flushTimeout) {
|
|
729
|
-
return; // Already scheduled
|
|
735
|
+
if (this.flushTimeout || this.isDestroyed) {
|
|
736
|
+
return; // Already scheduled or destroyed
|
|
730
737
|
}
|
|
731
738
|
|
|
732
739
|
this.flushTimeout = setTimeout(() => {
|
|
@@ -734,7 +741,7 @@ export class MoroLogger implements Logger {
|
|
|
734
741
|
}, this.flushInterval);
|
|
735
742
|
}
|
|
736
743
|
|
|
737
|
-
|
|
744
|
+
public flushBuffer(): void {
|
|
738
745
|
if (this.outputBuffer.length === 0) {
|
|
739
746
|
return;
|
|
740
747
|
}
|
|
@@ -916,6 +923,30 @@ export class MoroLogger implements Logger {
|
|
|
916
923
|
// Ignore flush errors
|
|
917
924
|
}
|
|
918
925
|
}
|
|
926
|
+
|
|
927
|
+
// Destroy logger and clean up all resources (for testing)
|
|
928
|
+
public destroy(): void {
|
|
929
|
+
// Mark as destroyed to prevent new timeouts
|
|
930
|
+
this.isDestroyed = true;
|
|
931
|
+
|
|
932
|
+
// Clear any remaining timeouts
|
|
933
|
+
if (this.flushTimeout) {
|
|
934
|
+
clearTimeout(this.flushTimeout);
|
|
935
|
+
this.flushTimeout = null;
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
// Flush any remaining buffer
|
|
939
|
+
this.flushBuffer();
|
|
940
|
+
|
|
941
|
+
// Clear outputs and filters
|
|
942
|
+
this.outputs.clear();
|
|
943
|
+
this.filters.clear();
|
|
944
|
+
|
|
945
|
+
// Clear history
|
|
946
|
+
this.history.length = 0;
|
|
947
|
+
this.historyIndex = 0;
|
|
948
|
+
this.historySize = 0;
|
|
949
|
+
}
|
|
919
950
|
}
|
|
920
951
|
|
|
921
952
|
// Global logger instance
|
|
@@ -942,6 +973,14 @@ export function configureGlobalLogger(options: Partial<LoggerOptions>): void {
|
|
|
942
973
|
// For now, focusing on level which is the most critical
|
|
943
974
|
}
|
|
944
975
|
|
|
976
|
+
/**
|
|
977
|
+
* Destroy the global logger and clean up resources (for testing)
|
|
978
|
+
* @internal
|
|
979
|
+
*/
|
|
980
|
+
export function destroyGlobalLogger(): void {
|
|
981
|
+
logger.destroy();
|
|
982
|
+
}
|
|
983
|
+
|
|
945
984
|
/**
|
|
946
985
|
* Apply logging configuration from the config system and/or createApp options
|
|
947
986
|
*/
|
|
@@ -256,20 +256,91 @@ export class IntelligentRouteBuilder implements RouteBuilder {
|
|
|
256
256
|
|
|
257
257
|
// Executable route with intelligent middleware ordering
|
|
258
258
|
export class ExecutableRoute implements CompiledRoute {
|
|
259
|
-
|
|
259
|
+
// PERFORMANCE OPTIMIZATION: Pre-analyze route requirements
|
|
260
|
+
private readonly requiresAuth: boolean;
|
|
261
|
+
private readonly requiresValidation: boolean;
|
|
262
|
+
private readonly requiresRateLimit: boolean;
|
|
263
|
+
private readonly requiresCache: boolean;
|
|
264
|
+
private readonly hasBeforeMiddleware: boolean;
|
|
265
|
+
private readonly hasAfterMiddleware: boolean;
|
|
266
|
+
private readonly hasTransformMiddleware: boolean;
|
|
267
|
+
private readonly isFastPath: boolean;
|
|
268
|
+
|
|
269
|
+
constructor(public readonly schema: RouteSchema) {
|
|
270
|
+
// Pre-calculate what this route actually needs
|
|
271
|
+
this.requiresAuth = !!this.schema.auth;
|
|
272
|
+
this.requiresValidation = !!this.schema.validation;
|
|
273
|
+
this.requiresRateLimit = !!this.schema.rateLimit;
|
|
274
|
+
this.requiresCache = !!this.schema.cache;
|
|
275
|
+
this.hasBeforeMiddleware = !!this.schema.middleware?.before?.length;
|
|
276
|
+
this.hasAfterMiddleware = !!this.schema.middleware?.after?.length;
|
|
277
|
+
this.hasTransformMiddleware = !!this.schema.middleware?.transform?.length;
|
|
278
|
+
|
|
279
|
+
// Fast path: no middleware, no auth, no validation, no rate limiting
|
|
280
|
+
this.isFastPath =
|
|
281
|
+
!this.requiresAuth &&
|
|
282
|
+
!this.requiresValidation &&
|
|
283
|
+
!this.requiresRateLimit &&
|
|
284
|
+
!this.requiresCache &&
|
|
285
|
+
!this.hasBeforeMiddleware &&
|
|
286
|
+
!this.hasAfterMiddleware &&
|
|
287
|
+
!this.hasTransformMiddleware;
|
|
288
|
+
|
|
289
|
+
// Log fast path routes for monitoring
|
|
290
|
+
if (this.isFastPath) {
|
|
291
|
+
logger.debug(`Fast path route: ${this.schema.method} ${this.schema.path}`, 'FastPath');
|
|
292
|
+
}
|
|
293
|
+
}
|
|
260
294
|
|
|
261
295
|
async execute(req: HttpRequest, res: HttpResponse): Promise<void> {
|
|
262
296
|
const validatedReq = req as ValidatedRequest;
|
|
263
297
|
|
|
264
298
|
try {
|
|
265
|
-
//
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
299
|
+
// PERFORMANCE OPTIMIZATION: Fast path for simple routes
|
|
300
|
+
if (this.isFastPath) {
|
|
301
|
+
// Skip all middleware - execute handler directly
|
|
302
|
+
const result = await this.schema.handler(validatedReq, res);
|
|
303
|
+
if (result !== undefined && !res.headersSent) {
|
|
304
|
+
res.json(result);
|
|
305
|
+
}
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Optimized middleware execution - only run what's needed
|
|
310
|
+
if (this.hasBeforeMiddleware) {
|
|
311
|
+
await this.executePhase('before', validatedReq, res);
|
|
312
|
+
if (res.headersSent) return;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (this.requiresRateLimit) {
|
|
316
|
+
await this.executePhase('rateLimit', validatedReq, res);
|
|
317
|
+
if (res.headersSent) return;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if (this.requiresAuth) {
|
|
321
|
+
await this.executePhase('auth', validatedReq, res);
|
|
322
|
+
if (res.headersSent) return;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (this.requiresValidation) {
|
|
326
|
+
await this.executePhase('validation', validatedReq, res);
|
|
327
|
+
if (res.headersSent) return;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
if (this.hasTransformMiddleware) {
|
|
331
|
+
await this.executePhase('transform', validatedReq, res);
|
|
332
|
+
if (res.headersSent) return;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if (this.requiresCache) {
|
|
336
|
+
await this.executePhase('cache', validatedReq, res);
|
|
337
|
+
if (res.headersSent) return;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (this.hasAfterMiddleware) {
|
|
341
|
+
await this.executePhase('after', validatedReq, res);
|
|
342
|
+
if (res.headersSent) return;
|
|
343
|
+
}
|
|
273
344
|
|
|
274
345
|
// Execute handler last
|
|
275
346
|
if (!res.headersSent) {
|
|
@@ -361,15 +432,32 @@ export class ExecutableRoute implements CompiledRoute {
|
|
|
361
432
|
req: HttpRequest,
|
|
362
433
|
res: HttpResponse
|
|
363
434
|
): Promise<void> {
|
|
435
|
+
// PERFORMANCE OPTIMIZATION: Reduce Promise overhead
|
|
364
436
|
return new Promise((resolve, reject) => {
|
|
437
|
+
let resolved = false;
|
|
438
|
+
|
|
439
|
+
const next = () => {
|
|
440
|
+
if (!resolved) {
|
|
441
|
+
resolved = true;
|
|
442
|
+
resolve();
|
|
443
|
+
}
|
|
444
|
+
};
|
|
445
|
+
|
|
365
446
|
try {
|
|
366
|
-
const next = () => resolve();
|
|
367
447
|
const result = middleware(req, res, next);
|
|
368
448
|
if (result instanceof Promise) {
|
|
369
|
-
result.then(() =>
|
|
449
|
+
result.then(() => !resolved && next()).catch(reject);
|
|
450
|
+
} else {
|
|
451
|
+
// Synchronous middleware - call next immediately if not called
|
|
452
|
+
if (!resolved) {
|
|
453
|
+
next();
|
|
454
|
+
}
|
|
370
455
|
}
|
|
371
456
|
} catch (error) {
|
|
372
|
-
|
|
457
|
+
if (!resolved) {
|
|
458
|
+
resolved = true;
|
|
459
|
+
reject(error);
|
|
460
|
+
}
|
|
373
461
|
}
|
|
374
462
|
});
|
|
375
463
|
}
|
|
@@ -475,6 +563,22 @@ export class ExecutableRoute implements CompiledRoute {
|
|
|
475
563
|
config: this.schema.cache,
|
|
476
564
|
});
|
|
477
565
|
}
|
|
566
|
+
|
|
567
|
+
// Performance monitoring
|
|
568
|
+
getPerformanceInfo() {
|
|
569
|
+
return {
|
|
570
|
+
path: this.schema.path,
|
|
571
|
+
method: this.schema.method,
|
|
572
|
+
isFastPath: this.isFastPath,
|
|
573
|
+
requiresAuth: this.requiresAuth,
|
|
574
|
+
requiresValidation: this.requiresValidation,
|
|
575
|
+
requiresRateLimit: this.requiresRateLimit,
|
|
576
|
+
requiresCache: this.requiresCache,
|
|
577
|
+
hasBeforeMiddleware: this.hasBeforeMiddleware,
|
|
578
|
+
hasAfterMiddleware: this.hasAfterMiddleware,
|
|
579
|
+
hasTransformMiddleware: this.hasTransformMiddleware,
|
|
580
|
+
};
|
|
581
|
+
}
|
|
478
582
|
}
|
|
479
583
|
|
|
480
584
|
// Factory functions for creating routes
|