@lithia-js/core 1.0.0-canary.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.
- package/.turbo/turbo-build.log +4 -0
- package/CHANGELOG.md +13 -0
- package/LICENSE +21 -0
- package/README.md +60 -0
- package/dist/config.d.ts +101 -0
- package/dist/config.js +113 -0
- package/dist/config.js.map +1 -0
- package/dist/context/event-context.d.ts +53 -0
- package/dist/context/event-context.js +42 -0
- package/dist/context/event-context.js.map +1 -0
- package/dist/context/index.d.ts +16 -0
- package/dist/context/index.js +29 -0
- package/dist/context/index.js.map +1 -0
- package/dist/context/lithia-context.d.ts +47 -0
- package/dist/context/lithia-context.js +43 -0
- package/dist/context/lithia-context.js.map +1 -0
- package/dist/context/route-context.d.ts +74 -0
- package/dist/context/route-context.js +42 -0
- package/dist/context/route-context.js.map +1 -0
- package/dist/env.d.ts +1 -0
- package/dist/env.js +32 -0
- package/dist/env.js.map +1 -0
- package/dist/errors.d.ts +51 -0
- package/dist/errors.js +80 -0
- package/dist/errors.js.map +1 -0
- package/dist/hooks/dependency-hooks.d.ts +105 -0
- package/dist/hooks/dependency-hooks.js +96 -0
- package/dist/hooks/dependency-hooks.js.map +1 -0
- package/dist/hooks/event-hooks.d.ts +61 -0
- package/dist/hooks/event-hooks.js +70 -0
- package/dist/hooks/event-hooks.js.map +1 -0
- package/dist/hooks/index.d.ts +41 -0
- package/dist/hooks/index.js +59 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/route-hooks.d.ts +154 -0
- package/dist/hooks/route-hooks.js +174 -0
- package/dist/hooks/route-hooks.js.map +1 -0
- package/dist/lib.d.ts +10 -0
- package/dist/lib.js +30 -0
- package/dist/lib.js.map +1 -0
- package/dist/lithia.d.ts +447 -0
- package/dist/lithia.js +649 -0
- package/dist/lithia.js.map +1 -0
- package/dist/logger.d.ts +11 -0
- package/dist/logger.js +55 -0
- package/dist/logger.js.map +1 -0
- package/dist/module-loader.d.ts +12 -0
- package/dist/module-loader.js +78 -0
- package/dist/module-loader.js.map +1 -0
- package/dist/server/event-processor.d.ts +195 -0
- package/dist/server/event-processor.js +253 -0
- package/dist/server/event-processor.js.map +1 -0
- package/dist/server/http-server.d.ts +196 -0
- package/dist/server/http-server.js +295 -0
- package/dist/server/http-server.js.map +1 -0
- package/dist/server/middlewares/validation.d.ts +12 -0
- package/dist/server/middlewares/validation.js +34 -0
- package/dist/server/middlewares/validation.js.map +1 -0
- package/dist/server/request-processor.d.ts +400 -0
- package/dist/server/request-processor.js +652 -0
- package/dist/server/request-processor.js.map +1 -0
- package/dist/server/request.d.ts +73 -0
- package/dist/server/request.js +207 -0
- package/dist/server/request.js.map +1 -0
- package/dist/server/response.d.ts +69 -0
- package/dist/server/response.js +173 -0
- package/dist/server/response.js.map +1 -0
- package/package.json +46 -0
- package/src/config.ts +212 -0
- package/src/context/event-context.ts +66 -0
- package/src/context/index.ts +32 -0
- package/src/context/lithia-context.ts +59 -0
- package/src/context/route-context.ts +89 -0
- package/src/env.ts +31 -0
- package/src/errors.ts +96 -0
- package/src/hooks/dependency-hooks.ts +122 -0
- package/src/hooks/event-hooks.ts +69 -0
- package/src/hooks/index.ts +58 -0
- package/src/hooks/route-hooks.ts +177 -0
- package/src/lib.ts +27 -0
- package/src/lithia.ts +777 -0
- package/src/logger.ts +66 -0
- package/src/module-loader.ts +45 -0
- package/src/server/event-processor.ts +344 -0
- package/src/server/http-server.ts +371 -0
- package/src/server/middlewares/validation.ts +46 -0
- package/src/server/request-processor.ts +860 -0
- package/src/server/request.ts +247 -0
- package/src/server/response.ts +204 -0
- package/tsconfig.build.tsbuildinfo +1 -0
- package/tsconfig.json +8 -0
|
@@ -0,0 +1,652 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Request processor module for HTTP request handling.
|
|
4
|
+
*
|
|
5
|
+
* This module is the core of Lithia's request processing pipeline. It handles:
|
|
6
|
+
* - Route matching and parameter extraction
|
|
7
|
+
* - Static file serving
|
|
8
|
+
* - CORS preflight and headers
|
|
9
|
+
* - Middleware execution chain
|
|
10
|
+
* - Route handler invocation
|
|
11
|
+
* - Error handling and logging
|
|
12
|
+
*
|
|
13
|
+
* @module server/request-processor
|
|
14
|
+
*/
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.RequestProcessor = void 0;
|
|
17
|
+
const node_crypto_1 = require("node:crypto");
|
|
18
|
+
const node_fs_1 = require("node:fs");
|
|
19
|
+
const node_path_1 = require("node:path");
|
|
20
|
+
const utils_1 = require("@lithia-js/utils");
|
|
21
|
+
const route_context_1 = require("../context/route-context");
|
|
22
|
+
const errors_1 = require("../errors");
|
|
23
|
+
const logger_1 = require("../logger");
|
|
24
|
+
const module_loader_1 = require("../module-loader");
|
|
25
|
+
/**
|
|
26
|
+
* Request processor for the Lithia HTTP pipeline.
|
|
27
|
+
*
|
|
28
|
+
* This class orchestrates the entire request processing flow from receiving
|
|
29
|
+
* an HTTP request to sending a response. It manages:
|
|
30
|
+
*
|
|
31
|
+
* - **CORS handling**: Preflight requests and CORS headers
|
|
32
|
+
* - **Static files**: Serving files from configured static directories
|
|
33
|
+
* - **Route matching**: Finding the route that matches the request path
|
|
34
|
+
* - **Parameter extraction**: Extracting dynamic route parameters
|
|
35
|
+
* - **Middleware execution**: Running global and route-specific middlewares
|
|
36
|
+
* - **Handler invocation**: Executing the route handler function
|
|
37
|
+
* - **Error handling**: Converting exceptions to structured JSON responses
|
|
38
|
+
* - **Request logging**: Logging all requests with timing and status codes
|
|
39
|
+
*
|
|
40
|
+
* @remarks
|
|
41
|
+
* The processor uses AsyncLocalStorage to provide request context to hooks,
|
|
42
|
+
* allowing route handlers to access request/response without explicit parameters.
|
|
43
|
+
*
|
|
44
|
+
* In development mode, route modules are reloaded on each request (cache busting).
|
|
45
|
+
* In production, modules are cached for better performance.
|
|
46
|
+
*/
|
|
47
|
+
class RequestProcessor {
|
|
48
|
+
lithia;
|
|
49
|
+
httpServer;
|
|
50
|
+
/**
|
|
51
|
+
* Creates a new request processor.
|
|
52
|
+
*
|
|
53
|
+
* @param lithia - The Lithia application instance
|
|
54
|
+
*/
|
|
55
|
+
constructor(lithia, httpServer) {
|
|
56
|
+
this.lithia = lithia;
|
|
57
|
+
this.httpServer = httpServer;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Processes an incoming HTTP request through the complete pipeline.
|
|
61
|
+
*
|
|
62
|
+
* This is the main entry point for request processing. The method executes
|
|
63
|
+
* the following steps in order:
|
|
64
|
+
*
|
|
65
|
+
* 1. Initialize request context for hooks
|
|
66
|
+
* 2. Handle CORS preflight (OPTIONS) requests
|
|
67
|
+
* 3. Add standard response headers
|
|
68
|
+
* 4. Attempt to serve static files
|
|
69
|
+
* 5. Match request to a route
|
|
70
|
+
* 6. Extract dynamic route parameters
|
|
71
|
+
* 7. Load the route module
|
|
72
|
+
* 8. Execute global middlewares
|
|
73
|
+
* 9. Execute route-specific middlewares
|
|
74
|
+
* 10. Execute the route handler
|
|
75
|
+
* 11. Log the request with timing
|
|
76
|
+
*
|
|
77
|
+
* Any errors thrown during this process are caught and handled by
|
|
78
|
+
* {@link handleError}, which sends a structured error response.
|
|
79
|
+
*
|
|
80
|
+
* @param req - The incoming HTTP request
|
|
81
|
+
* @param res - The HTTP response object
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```typescript
|
|
85
|
+
* const processor = new RequestProcessor(lithia);
|
|
86
|
+
* await processor.processRequest(req, res);
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
async processRequest(req, res) {
|
|
90
|
+
const start = process.hrtime.bigint();
|
|
91
|
+
// Initialize context for hooks
|
|
92
|
+
const routeCtx = {
|
|
93
|
+
req,
|
|
94
|
+
res,
|
|
95
|
+
socketServer: this.httpServer.socketIO,
|
|
96
|
+
};
|
|
97
|
+
await this.lithia.runWithContext(async () => {
|
|
98
|
+
await route_context_1.routeContext.run(routeCtx, async () => {
|
|
99
|
+
try {
|
|
100
|
+
// Handle CORS
|
|
101
|
+
if (this.handleCors(req, res)) {
|
|
102
|
+
this.logRequest(req, res, start);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
// Add basic headers
|
|
106
|
+
res.addHeader("X-Powered-By", "Lithia");
|
|
107
|
+
// Serve static files
|
|
108
|
+
if (await this.serveStaticFile(req, res)) {
|
|
109
|
+
this.logRequest(req, res, start);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
// Find matching route
|
|
113
|
+
const route = this.findMatchingRoute(req.pathname, req.method);
|
|
114
|
+
if (!route) {
|
|
115
|
+
this.sendNotFound(req, res);
|
|
116
|
+
this.logRequest(req, res, start);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
// Update context with matched route
|
|
120
|
+
routeCtx.route = route;
|
|
121
|
+
// Extract params if dynamic route
|
|
122
|
+
if (route.dynamic) {
|
|
123
|
+
req.params = this.extractParams(req.pathname, route);
|
|
124
|
+
}
|
|
125
|
+
// Import route module
|
|
126
|
+
const module = await this.importRouteModule(route);
|
|
127
|
+
// Execute global middlewares
|
|
128
|
+
if (this.lithia.globalMiddlewares &&
|
|
129
|
+
this.lithia.globalMiddlewares.length > 0) {
|
|
130
|
+
const globalMiddlewareError = await this.executeMiddlewares(this.lithia.globalMiddlewares, req, res);
|
|
131
|
+
if (res._ended || globalMiddlewareError) {
|
|
132
|
+
if (globalMiddlewareError) {
|
|
133
|
+
throw globalMiddlewareError;
|
|
134
|
+
}
|
|
135
|
+
this.logRequest(req, res, start);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// Execute middlewares if present
|
|
140
|
+
if (module.middlewares && module.middlewares.length > 0) {
|
|
141
|
+
const middlewareError = await this.executeMiddlewares(module.middlewares, req, res);
|
|
142
|
+
// If middleware ended response or errored, stop processing
|
|
143
|
+
if (res._ended || middlewareError) {
|
|
144
|
+
if (middlewareError) {
|
|
145
|
+
throw middlewareError;
|
|
146
|
+
}
|
|
147
|
+
this.logRequest(req, res, start);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
// Execute route handler
|
|
152
|
+
if (module.default) {
|
|
153
|
+
await module.default(req, res);
|
|
154
|
+
}
|
|
155
|
+
// End response if not already ended
|
|
156
|
+
if (!res._ended) {
|
|
157
|
+
res.end();
|
|
158
|
+
}
|
|
159
|
+
this.logRequest(req, res, start);
|
|
160
|
+
}
|
|
161
|
+
catch (err) {
|
|
162
|
+
this.handleError(err, req, res, start);
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Executes an array of middlewares sequentially.
|
|
169
|
+
*
|
|
170
|
+
* Middlewares are executed in order. Each middleware must call `next()`
|
|
171
|
+
* to continue to the next middleware in the chain. If a middleware does
|
|
172
|
+
* not call `next()`, the chain stops and subsequent middlewares are not
|
|
173
|
+
* executed.
|
|
174
|
+
*
|
|
175
|
+
* If any middleware throws an error, execution stops immediately and the
|
|
176
|
+
* error is returned.
|
|
177
|
+
*
|
|
178
|
+
* @param middlewares - Array of middleware functions to execute
|
|
179
|
+
* @param req - The HTTP request object
|
|
180
|
+
* @param res - The HTTP response object
|
|
181
|
+
* @returns null if successful, or an Error if a middleware threw
|
|
182
|
+
*
|
|
183
|
+
* @private
|
|
184
|
+
*
|
|
185
|
+
* @example
|
|
186
|
+
* ```typescript
|
|
187
|
+
* const error = await this.executeMiddlewares(middlewares, req, res);
|
|
188
|
+
* if (error) {
|
|
189
|
+
* throw error;
|
|
190
|
+
* }
|
|
191
|
+
* ```
|
|
192
|
+
*/
|
|
193
|
+
async executeMiddlewares(middlewares, req, res) {
|
|
194
|
+
let currentIndex = 0;
|
|
195
|
+
const next = () => {
|
|
196
|
+
currentIndex++;
|
|
197
|
+
};
|
|
198
|
+
try {
|
|
199
|
+
for (let i = 0; i < middlewares.length; i++) {
|
|
200
|
+
currentIndex = i;
|
|
201
|
+
await middlewares[i](req, res, next);
|
|
202
|
+
// If response was ended by middleware, stop processing
|
|
203
|
+
if (res._ended) {
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
// If next() wasn't called, stop middleware chain
|
|
207
|
+
if (currentIndex === i) {
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
catch (err) {
|
|
214
|
+
return err instanceof Error ? err : new Error(String(err));
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Sends a structured 404 JSON response for unmatched routes.
|
|
219
|
+
*
|
|
220
|
+
* This method is called when no route matches the requested path.
|
|
221
|
+
* It sends a standardized error response with status 404.
|
|
222
|
+
*
|
|
223
|
+
* @param req - The HTTP request that didn't match any route
|
|
224
|
+
* @param res - The HTTP response object
|
|
225
|
+
*
|
|
226
|
+
* @private
|
|
227
|
+
*/
|
|
228
|
+
sendNotFound(req, res) {
|
|
229
|
+
const response = {
|
|
230
|
+
error: {
|
|
231
|
+
message: "The requested resource was not found",
|
|
232
|
+
statusCode: 404,
|
|
233
|
+
timestamp: new Date().toISOString(),
|
|
234
|
+
path: req.pathname,
|
|
235
|
+
method: req.method,
|
|
236
|
+
},
|
|
237
|
+
};
|
|
238
|
+
res.status(404).json(response);
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Centralized error handler for the request pipeline.
|
|
242
|
+
*
|
|
243
|
+
* This method handles all errors thrown during request processing:
|
|
244
|
+
*
|
|
245
|
+
* **Development mode:**
|
|
246
|
+
* - Returns detailed error messages
|
|
247
|
+
* - Includes full error stacks
|
|
248
|
+
* - Shows validation issues if present
|
|
249
|
+
*
|
|
250
|
+
* **Production mode:**
|
|
251
|
+
* - Returns generic error messages
|
|
252
|
+
* - Includes error digest for log correlation
|
|
253
|
+
* - Hides sensitive error details
|
|
254
|
+
*
|
|
255
|
+
* All server errors (5xx) are logged with the error digest for correlation
|
|
256
|
+
* between client responses and server logs.
|
|
257
|
+
*
|
|
258
|
+
* @param err - The error that was thrown
|
|
259
|
+
* @param req - The HTTP request that caused the error
|
|
260
|
+
* @param res - The HTTP response object
|
|
261
|
+
* @param start - High-resolution timestamp when request processing started
|
|
262
|
+
*
|
|
263
|
+
* @private
|
|
264
|
+
*/
|
|
265
|
+
handleError(err, req, res, start) {
|
|
266
|
+
const isDevelopment = this.lithia.getEnvironment() === "development";
|
|
267
|
+
// Don't send error response if already sent
|
|
268
|
+
if (res._ended) {
|
|
269
|
+
this.logRequest(req, res, start);
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
// Generate error digest (both dev and prod)
|
|
273
|
+
const digest = this.generateErrorDigest(err);
|
|
274
|
+
// Build error details
|
|
275
|
+
const errorMessage = err instanceof Error ? err.message : "Internal Server Error";
|
|
276
|
+
const errorStack = err instanceof Error ? err.stack : undefined;
|
|
277
|
+
let statusCode = 500;
|
|
278
|
+
let clientMessage = isDevelopment
|
|
279
|
+
? errorMessage
|
|
280
|
+
: "An internal server error occurred";
|
|
281
|
+
let issues;
|
|
282
|
+
if (err instanceof errors_1.ValidationError) {
|
|
283
|
+
statusCode = 400;
|
|
284
|
+
clientMessage = err.message;
|
|
285
|
+
issues = err.issues;
|
|
286
|
+
}
|
|
287
|
+
if (statusCode >= 500) {
|
|
288
|
+
// Log error with digest (same format for both environments)
|
|
289
|
+
logger_1.logger.error(`[Digest: ${(0, utils_1.red)(digest)}] ${errorStack}`);
|
|
290
|
+
}
|
|
291
|
+
// Build error response
|
|
292
|
+
const response = {
|
|
293
|
+
error: {
|
|
294
|
+
message: clientMessage,
|
|
295
|
+
statusCode,
|
|
296
|
+
timestamp: new Date().toISOString(),
|
|
297
|
+
path: req.pathname,
|
|
298
|
+
method: req.method,
|
|
299
|
+
digest: digest,
|
|
300
|
+
issues,
|
|
301
|
+
},
|
|
302
|
+
};
|
|
303
|
+
res.status(statusCode).json(response);
|
|
304
|
+
this.logRequest(req, res, start);
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Logs a completed request with color-coded status and timing.
|
|
308
|
+
*
|
|
309
|
+
* The log includes:
|
|
310
|
+
* - HTTP status code (color-coded by range)
|
|
311
|
+
* - HTTP method (GET, POST, etc.)
|
|
312
|
+
* - Request pathname
|
|
313
|
+
* - Processing duration in milliseconds
|
|
314
|
+
*
|
|
315
|
+
* Status colors:
|
|
316
|
+
* - 2xx: Green (success)
|
|
317
|
+
* - 3xx: Cyan (redirect)
|
|
318
|
+
* - 4xx: Yellow (client error)
|
|
319
|
+
* - 5xx: Red (server error)
|
|
320
|
+
*
|
|
321
|
+
* @param req - The HTTP request that was processed
|
|
322
|
+
* @param res - The HTTP response that was sent
|
|
323
|
+
* @param start - High-resolution timestamp when processing started
|
|
324
|
+
*
|
|
325
|
+
* @private
|
|
326
|
+
*/
|
|
327
|
+
/**
|
|
328
|
+
* Logs a completed request with color-coded status and timing.
|
|
329
|
+
*
|
|
330
|
+
* The log includes:
|
|
331
|
+
* - HTTP status code (color-coded by range)
|
|
332
|
+
* - HTTP method (GET, POST, etc.)
|
|
333
|
+
* - Request pathname
|
|
334
|
+
* - Processing duration in milliseconds
|
|
335
|
+
*
|
|
336
|
+
* Status colors:
|
|
337
|
+
* - 2xx: Green (success)
|
|
338
|
+
* - 3xx: Cyan (redirect)
|
|
339
|
+
* - 4xx: Yellow (client error)
|
|
340
|
+
* - 5xx: Red (server error)
|
|
341
|
+
*
|
|
342
|
+
* Respects the `logging.requests` configuration flag. Critical errors
|
|
343
|
+
* (5xx) are always logged regardless of the flag.
|
|
344
|
+
*
|
|
345
|
+
* @param req - The HTTP request that was processed
|
|
346
|
+
* @param res - The HTTP response that was sent
|
|
347
|
+
* @param start - High-resolution timestamp when processing started
|
|
348
|
+
*
|
|
349
|
+
* @private
|
|
350
|
+
*/
|
|
351
|
+
logRequest(req, res, start) {
|
|
352
|
+
const status = res.statusCode || 200;
|
|
353
|
+
// Always log critical errors (5xx), otherwise respect the logging.requests flag
|
|
354
|
+
const shouldLog = status >= 500 || this.lithia.options.logging?.requests !== false;
|
|
355
|
+
if (!shouldLog)
|
|
356
|
+
return;
|
|
357
|
+
const end = process.hrtime.bigint();
|
|
358
|
+
const duration = Number(end - start) / 1_000_000;
|
|
359
|
+
const durationStr = `${duration.toFixed(2)}ms`;
|
|
360
|
+
let statusStr = status.toString();
|
|
361
|
+
if (status >= 500) {
|
|
362
|
+
statusStr = (0, utils_1.red)(statusStr);
|
|
363
|
+
}
|
|
364
|
+
else if (status >= 400) {
|
|
365
|
+
statusStr = (0, utils_1.yellow)(statusStr);
|
|
366
|
+
}
|
|
367
|
+
else if (status >= 300) {
|
|
368
|
+
statusStr = (0, utils_1.cyan)(statusStr);
|
|
369
|
+
}
|
|
370
|
+
else {
|
|
371
|
+
statusStr = (0, utils_1.green)(statusStr);
|
|
372
|
+
}
|
|
373
|
+
logger_1.logger.info(`[${statusStr}] ${req.method} ${req.pathname} - ${durationStr}`);
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Generates a short hexadecimal digest for error correlation.
|
|
377
|
+
*
|
|
378
|
+
* The digest is used to correlate server-side error logs with client-facing
|
|
379
|
+
* error responses. This allows developers to find the detailed error in logs
|
|
380
|
+
* using the digest shown to the client.
|
|
381
|
+
*
|
|
382
|
+
* The digest is generated from:
|
|
383
|
+
* - Error message and stack
|
|
384
|
+
* - Current timestamp
|
|
385
|
+
* - Random factor for uniqueness
|
|
386
|
+
*
|
|
387
|
+
* @param err - The error to generate a digest for
|
|
388
|
+
* @returns An 8-character hexadecimal digest
|
|
389
|
+
*
|
|
390
|
+
* @private
|
|
391
|
+
*/
|
|
392
|
+
generateErrorDigest(err) {
|
|
393
|
+
// Create a unique digest based on error message, timestamp, and random factor
|
|
394
|
+
const errorString = err instanceof Error ? `${err.message}${err.stack}` : String(err);
|
|
395
|
+
const hash = (0, node_crypto_1.createHash)("sha256")
|
|
396
|
+
.update(`${errorString}${Date.now()}${Math.random()}`)
|
|
397
|
+
.digest("hex");
|
|
398
|
+
// Return first 8 characters (similar to Next.js)
|
|
399
|
+
return hash.substring(0, 8);
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Handles CORS preflight requests and applies CORS headers.
|
|
403
|
+
*
|
|
404
|
+
* This method:
|
|
405
|
+
* 1. Checks if the request origin is allowed based on CORS configuration
|
|
406
|
+
* 2. Adds appropriate CORS headers to the response
|
|
407
|
+
* 3. Handles OPTIONS preflight requests
|
|
408
|
+
*
|
|
409
|
+
* **CORS Headers Applied:**
|
|
410
|
+
* - `Access-Control-Allow-Origin`: Allowed origin
|
|
411
|
+
* - `Access-Control-Allow-Credentials`: If credentials are enabled
|
|
412
|
+
* - `Access-Control-Allow-Methods`: Allowed HTTP methods
|
|
413
|
+
* - `Access-Control-Allow-Headers`: Allowed request headers
|
|
414
|
+
* - `Access-Control-Max-Age`: Preflight cache duration
|
|
415
|
+
* - `Access-Control-Expose-Headers`: Headers exposed to client
|
|
416
|
+
*
|
|
417
|
+
* @param req - The HTTP request
|
|
418
|
+
* @param res - The HTTP response
|
|
419
|
+
* @returns true if the request was an OPTIONS preflight that was handled, false otherwise
|
|
420
|
+
*
|
|
421
|
+
* @private
|
|
422
|
+
*/
|
|
423
|
+
handleCors(req, res) {
|
|
424
|
+
const cors = this.lithia.options.http.cors;
|
|
425
|
+
if (!cors)
|
|
426
|
+
return false;
|
|
427
|
+
const origin = req.headers.origin;
|
|
428
|
+
// Check if origin is allowed
|
|
429
|
+
let allowedOrigin;
|
|
430
|
+
// Handle credentials with wildcard origin
|
|
431
|
+
if (cors.credentials && cors.origin?.includes("*")) {
|
|
432
|
+
allowedOrigin = origin;
|
|
433
|
+
}
|
|
434
|
+
else if (cors.origin?.includes("*")) {
|
|
435
|
+
allowedOrigin = "*";
|
|
436
|
+
}
|
|
437
|
+
else if (origin && cors.origin?.includes(origin)) {
|
|
438
|
+
allowedOrigin = origin;
|
|
439
|
+
}
|
|
440
|
+
if (allowedOrigin) {
|
|
441
|
+
res.addHeader("Access-Control-Allow-Origin", allowedOrigin);
|
|
442
|
+
res.addHeader("Vary", "Origin");
|
|
443
|
+
if (cors.credentials) {
|
|
444
|
+
res.addHeader("Access-Control-Allow-Credentials", "true");
|
|
445
|
+
}
|
|
446
|
+
if (req.method === "OPTIONS") {
|
|
447
|
+
if (cors.methods) {
|
|
448
|
+
res.addHeader("Access-Control-Allow-Methods", cors.methods.join(", "));
|
|
449
|
+
}
|
|
450
|
+
if (cors.allowedHeaders) {
|
|
451
|
+
res.addHeader("Access-Control-Allow-Headers", cors.allowedHeaders.join(", "));
|
|
452
|
+
}
|
|
453
|
+
if (cors.maxAge) {
|
|
454
|
+
res.addHeader("Access-Control-Max-Age", cors.maxAge.toString());
|
|
455
|
+
}
|
|
456
|
+
res.status(204).end();
|
|
457
|
+
return true;
|
|
458
|
+
}
|
|
459
|
+
if (cors.exposedHeaders) {
|
|
460
|
+
res.addHeader("Access-Control-Expose-Headers", cors.exposedHeaders.join(", "));
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
return false;
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* Attempts to serve a static file from the configured static directory.
|
|
467
|
+
*
|
|
468
|
+
* This method:
|
|
469
|
+
* 1. Checks if static file serving is enabled
|
|
470
|
+
* 2. Only serves for GET and HEAD requests
|
|
471
|
+
* 3. Strips configured prefix from the path
|
|
472
|
+
* 4. Prevents directory traversal attacks
|
|
473
|
+
* 5. Determines MIME type from file extension
|
|
474
|
+
* 6. Sends the file with appropriate Content-Type header
|
|
475
|
+
*
|
|
476
|
+
* @param req - The HTTP request
|
|
477
|
+
* @param res - The HTTP response
|
|
478
|
+
* @returns true if a static file was served, false otherwise
|
|
479
|
+
* @throws {StaticFileMimeMissingError} If file extension has no configured MIME type
|
|
480
|
+
*
|
|
481
|
+
* @private
|
|
482
|
+
*/
|
|
483
|
+
async serveStaticFile(req, res) {
|
|
484
|
+
const staticConfig = this.lithia.options.static;
|
|
485
|
+
if (!staticConfig || !staticConfig.root)
|
|
486
|
+
return false;
|
|
487
|
+
// Skip if method is not GET or HEAD
|
|
488
|
+
if (req.method !== "GET" && req.method !== "HEAD")
|
|
489
|
+
return false;
|
|
490
|
+
let filePath = req.pathname;
|
|
491
|
+
// Handle prefix stripping
|
|
492
|
+
if (staticConfig.prefix) {
|
|
493
|
+
if (!filePath.startsWith(staticConfig.prefix))
|
|
494
|
+
return false;
|
|
495
|
+
filePath = filePath.slice(staticConfig.prefix.length);
|
|
496
|
+
}
|
|
497
|
+
// Prevent directory traversal
|
|
498
|
+
const normalizedPath = (0, node_path_1.join)(staticConfig.root, filePath);
|
|
499
|
+
if (filePath.includes(".."))
|
|
500
|
+
return false;
|
|
501
|
+
try {
|
|
502
|
+
const stats = (0, node_fs_1.statSync)(normalizedPath);
|
|
503
|
+
if (stats.isFile()) {
|
|
504
|
+
const ext = (0, node_path_1.extname)(normalizedPath).toLowerCase();
|
|
505
|
+
const mime = this.lithia.options.http.mimeTypes?.[ext];
|
|
506
|
+
if (!mime) {
|
|
507
|
+
throw new errors_1.StaticFileMimeMissingError(ext, filePath);
|
|
508
|
+
}
|
|
509
|
+
res.addHeader("Content-Type", mime);
|
|
510
|
+
res.sendFile(normalizedPath);
|
|
511
|
+
return true;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
catch (e) {
|
|
515
|
+
if (e instanceof errors_1.LithiaError)
|
|
516
|
+
throw e;
|
|
517
|
+
// file not found or other error, fallback to routes
|
|
518
|
+
}
|
|
519
|
+
return false;
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* Finds a route matching the given pathname and HTTP method.
|
|
523
|
+
*
|
|
524
|
+
* Routes are matched in the order they were registered. The first route
|
|
525
|
+
* that matches both the path pattern (via regex) and HTTP method is returned.
|
|
526
|
+
*
|
|
527
|
+
* @param pathname - The request pathname to match
|
|
528
|
+
* @param method - The HTTP method (GET, POST, etc.)
|
|
529
|
+
* @returns The matched Route, or undefined if no match found
|
|
530
|
+
*
|
|
531
|
+
* @private
|
|
532
|
+
*/
|
|
533
|
+
findMatchingRoute(pathname, method) {
|
|
534
|
+
const routes = this.lithia.getRoutes();
|
|
535
|
+
return routes.find((route) => {
|
|
536
|
+
// Check method match
|
|
537
|
+
const methodMatches = !route.method || route.method.toUpperCase() === method.toUpperCase();
|
|
538
|
+
// Check path match using regex
|
|
539
|
+
const pathMatches = this.matchesPath(pathname, route);
|
|
540
|
+
return methodMatches && pathMatches;
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* Tests whether a pathname matches a route's regex pattern.
|
|
545
|
+
*
|
|
546
|
+
* @param pathname - The pathname to test
|
|
547
|
+
* @param route - The route with the regex pattern
|
|
548
|
+
* @returns true if the pathname matches the route's regex, false otherwise
|
|
549
|
+
*
|
|
550
|
+
* @private
|
|
551
|
+
*/
|
|
552
|
+
matchesPath(pathname, route) {
|
|
553
|
+
try {
|
|
554
|
+
const regex = new RegExp(route.regex);
|
|
555
|
+
return regex.test(pathname);
|
|
556
|
+
}
|
|
557
|
+
catch (err) {
|
|
558
|
+
logger_1.logger.error(`Invalid route regex for ${route.path}:`, err);
|
|
559
|
+
return false;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* Imports a route module from the file system.
|
|
564
|
+
*
|
|
565
|
+
* In **development mode**, uses cache-busting to reload the module on each
|
|
566
|
+
* request, enabling hot reloading without server restart.
|
|
567
|
+
*
|
|
568
|
+
* In **production mode**, uses standard dynamic imports with caching for
|
|
569
|
+
* better performance.
|
|
570
|
+
*
|
|
571
|
+
* The method also validates the module structure:
|
|
572
|
+
* - Must have a default export
|
|
573
|
+
* - Default export must be a function
|
|
574
|
+
* - Default export must be async
|
|
575
|
+
*
|
|
576
|
+
* @param route - The route whose module should be imported
|
|
577
|
+
* @returns The loaded and validated route module
|
|
578
|
+
* @throws {InvalidRouteModuleError} If the module structure is invalid
|
|
579
|
+
* @throws {Error} If the module fails to load
|
|
580
|
+
*
|
|
581
|
+
* @private
|
|
582
|
+
*/
|
|
583
|
+
async importRouteModule(route) {
|
|
584
|
+
try {
|
|
585
|
+
const isDevelopment = this.lithia.getEnvironment() === "development";
|
|
586
|
+
const mod = await (0, module_loader_1.coldImport)(route.filePath, isDevelopment);
|
|
587
|
+
if (!mod.default) {
|
|
588
|
+
throw new errors_1.InvalidRouteModuleError(route.filePath, "missing default export");
|
|
589
|
+
}
|
|
590
|
+
if (typeof mod.default !== "function") {
|
|
591
|
+
throw new errors_1.InvalidRouteModuleError(route.filePath, "default export is not a function");
|
|
592
|
+
}
|
|
593
|
+
if (!(0, module_loader_1.isAsyncFunction)(mod.default)) {
|
|
594
|
+
throw new errors_1.InvalidRouteModuleError(route.filePath, "default export is not an async function");
|
|
595
|
+
}
|
|
596
|
+
return mod;
|
|
597
|
+
}
|
|
598
|
+
catch (err) {
|
|
599
|
+
if (err instanceof errors_1.InvalidRouteModuleError) {
|
|
600
|
+
throw err;
|
|
601
|
+
}
|
|
602
|
+
throw new Error(`Failed to import route: ${route.path}`);
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
/**
|
|
606
|
+
* Extracts named route parameters from the pathname.
|
|
607
|
+
*
|
|
608
|
+
* For dynamic routes like `/users/:id/posts/:postId`, this method:
|
|
609
|
+
* 1. Matches the pathname against the route's regex
|
|
610
|
+
* 2. Extracts parameter names from the route path (e.g., "id", "postId")
|
|
611
|
+
* 3. Maps regex capture groups to parameter names
|
|
612
|
+
* 4. URL-decodes parameter values
|
|
613
|
+
*
|
|
614
|
+
* @param pathname - The request pathname
|
|
615
|
+
* @param route - The matched route with dynamic segments
|
|
616
|
+
* @returns Object mapping parameter names to their values
|
|
617
|
+
*
|
|
618
|
+
* @private
|
|
619
|
+
*
|
|
620
|
+
* @example
|
|
621
|
+
* ```typescript
|
|
622
|
+
* // Route: /users/:id/posts/:postId
|
|
623
|
+
* // Pathname: /users/123/posts/456
|
|
624
|
+
* // Returns: { id: '123', postId: '456' }
|
|
625
|
+
* ```
|
|
626
|
+
*/
|
|
627
|
+
extractParams(pathname, route) {
|
|
628
|
+
const params = {};
|
|
629
|
+
try {
|
|
630
|
+
const regex = new RegExp(route.regex);
|
|
631
|
+
const match = pathname.match(regex);
|
|
632
|
+
if (!match)
|
|
633
|
+
return params;
|
|
634
|
+
// Extract parameter names from the route path
|
|
635
|
+
const paramNames = (route.path.match(/:([^/]+)/g) || []).map((p) => p.slice(1));
|
|
636
|
+
// Match groups start at index 1 (index 0 is full match)
|
|
637
|
+
paramNames.forEach((name, idx) => {
|
|
638
|
+
const value = match[idx + 1];
|
|
639
|
+
if (value !== undefined) {
|
|
640
|
+
params[name] = decodeURIComponent(value);
|
|
641
|
+
}
|
|
642
|
+
});
|
|
643
|
+
return params;
|
|
644
|
+
}
|
|
645
|
+
catch (err) {
|
|
646
|
+
logger_1.logger.error(`Failed to extract params from ${pathname}:`, err);
|
|
647
|
+
return params;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
exports.RequestProcessor = RequestProcessor;
|
|
652
|
+
//# sourceMappingURL=request-processor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-processor.js","sourceRoot":"","sources":["../../src/server/request-processor.ts"],"names":[],"mappings":"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"}
|