skyguard-js 1.2.1 → 1.2.3

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 (64) hide show
  1. package/README.md +11 -680
  2. package/dist/app.d.ts +14 -9
  3. package/dist/app.js +37 -30
  4. package/dist/http/context.d.ts +115 -0
  5. package/dist/http/context.js +147 -0
  6. package/dist/http/httpAdapter.d.ts +4 -4
  7. package/dist/http/index.d.ts +3 -1
  8. package/dist/http/index.js +5 -1
  9. package/dist/http/logger.d.ts +9 -2
  10. package/dist/http/logger.js +49 -1
  11. package/dist/http/nodeNativeHttp.d.ts +4 -4
  12. package/dist/http/nodeNativeHttp.js +11 -4
  13. package/dist/http/request.d.ts +4 -0
  14. package/dist/http/request.js +8 -0
  15. package/dist/http/response.d.ts +21 -2
  16. package/dist/http/response.js +30 -2
  17. package/dist/http/webHttp.d.ts +19 -0
  18. package/dist/http/webHttp.js +95 -0
  19. package/dist/index.d.ts +2 -2
  20. package/dist/index.js +2 -2
  21. package/dist/middlewares/cors.d.ts +10 -4
  22. package/dist/middlewares/cors.js +35 -18
  23. package/dist/middlewares/csrf.js +33 -33
  24. package/dist/middlewares/index.d.ts +1 -1
  25. package/dist/middlewares/rateLimiter.d.ts +58 -6
  26. package/dist/middlewares/rateLimiter.js +149 -40
  27. package/dist/middlewares/session.js +4 -4
  28. package/dist/parsers/contentParserManager.d.ts +4 -2
  29. package/dist/parsers/contentParserManager.js +22 -3
  30. package/dist/routing/routeResolveFunc.d.ts +10 -0
  31. package/dist/routing/routeResolveFunc.js +21 -0
  32. package/dist/routing/router.d.ts +16 -10
  33. package/dist/routing/router.js +32 -25
  34. package/dist/routing/routerGroup.d.ts +10 -5
  35. package/dist/routing/routerGroup.js +11 -10
  36. package/dist/server/bunRuntimeServer.d.ts +7 -0
  37. package/dist/server/bunRuntimeServer.js +28 -0
  38. package/dist/server/createRuntimeServer.d.ts +4 -0
  39. package/dist/server/createRuntimeServer.js +23 -0
  40. package/dist/server/denoRuntimeServer.d.ts +7 -0
  41. package/dist/server/denoRuntimeServer.js +27 -0
  42. package/dist/server/index.d.ts +7 -0
  43. package/dist/server/index.js +19 -0
  44. package/dist/server/modulePath.d.ts +6 -0
  45. package/dist/server/modulePath.js +18 -0
  46. package/dist/server/nodeRuntimeServer.d.ts +7 -0
  47. package/dist/server/nodeRuntimeServer.js +21 -0
  48. package/dist/server/runtimeDetector.d.ts +4 -0
  49. package/dist/server/runtimeDetector.js +15 -0
  50. package/dist/server/types.d.ts +11 -0
  51. package/dist/server/types.js +2 -0
  52. package/dist/sessions/index.d.ts +2 -2
  53. package/dist/storage/storage.d.ts +3 -3
  54. package/dist/storage/storage.js +7 -7
  55. package/dist/storage/types.d.ts +5 -5
  56. package/dist/storage/uploader.d.ts +9 -9
  57. package/dist/storage/uploader.js +62 -62
  58. package/dist/types/index.d.ts +11 -10
  59. package/dist/validators/index.d.ts +2 -2
  60. package/dist/validators/rules/index.d.ts +5 -5
  61. package/dist/validators/validationSchema.js +8 -8
  62. package/package.json +2 -2
  63. package/dist/helpers/http.d.ts +0 -95
  64. package/dist/helpers/http.js +0 -112
package/dist/app.d.ts CHANGED
@@ -109,7 +109,7 @@ declare class App {
109
109
  *
110
110
  * @param port - TCP port to listen on
111
111
  */
112
- run(port: number, callback: VoidFunction, hostname?: string): void;
112
+ run(port?: number, callback?: VoidFunction, hostname?: string): void;
113
113
  /**
114
114
  * Configures HTTP request logger output format and optional file output.
115
115
  *
@@ -136,24 +136,29 @@ declare class App {
136
136
  */
137
137
  setPrefix(prefix: string): void;
138
138
  /** Registers a GET route */
139
- get(path: string, action: RouteHandler, middlewares?: Middleware[]): void;
139
+ get(path: string, action: RouteHandler): void;
140
+ get(path: string, middlewares: Middleware[], action: RouteHandler): void;
140
141
  /** Registers a POST route */
141
- post(path: string, action: RouteHandler, middlewares?: Middleware[]): void;
142
+ post(path: string, action: RouteHandler): void;
143
+ post(path: string, middlewares: Middleware[], action: RouteHandler): void;
142
144
  /** Registers a PUT route */
143
- put(path: string, action: RouteHandler, middlewares?: Middleware[]): void;
145
+ put(path: string, action: RouteHandler): void;
146
+ put(path: string, middlewares: Middleware[], action: RouteHandler): void;
144
147
  /** Registers a PATCH route */
145
- patch(path: string, action: RouteHandler, middlewares?: Middleware[]): void;
148
+ patch(path: string, action: RouteHandler): void;
149
+ patch(path: string, middlewares: Middleware[], action: RouteHandler): void;
146
150
  /** Registers a DELETE route */
147
- delete(path: string, action: RouteHandler, middlewares?: Middleware[]): void;
151
+ delete(path: string, action: RouteHandler): void;
152
+ delete(path: string, middlewares: Middleware[], action: RouteHandler): void;
148
153
  /**
149
154
  * Registers global middlewares.
150
155
  *
151
156
  * These are executed for every route.
152
157
  *
153
158
  * @example
154
- * const auth = async (request, next) => {
155
- * console.log(request.header);
156
- * return await next(request);
159
+ * const auth = async (context, next) => {
160
+ * console.log(context.headers);
161
+ * return await next(context);
157
162
  * }
158
163
  *
159
164
  * app.middlewares(auth);
package/dist/app.js CHANGED
@@ -2,15 +2,16 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createApp = void 0;
4
4
  const routing_1 = require("./routing");
5
+ const routeResolveFunc_1 = require("./routing/routeResolveFunc");
5
6
  const http_1 = require("./http");
6
7
  const validationException_1 = require("./exceptions/validationException");
7
8
  const node_path_1 = require("node:path");
8
9
  const node_fs_1 = require("node:fs");
9
10
  const fileStaticHandler_1 = require("./static/fileStaticHandler");
10
- const node_http_1 = require("node:http");
11
11
  const httpExceptions_1 = require("./exceptions/httpExceptions");
12
12
  const engineTemplate_1 = require("./views/engineTemplate");
13
13
  const container_1 = require("./container/container");
14
+ const createRuntimeServer_1 = require("./server/createRuntimeServer");
14
15
  /**
15
16
  * The `App` class acts as the **execution kernel** and **lifecycle orchestrator**
16
17
  * of the framework.
@@ -71,15 +72,15 @@ class App {
71
72
  */
72
73
  async handle(adapter) {
73
74
  try {
74
- const request = await adapter.getRequest();
75
- if (this.staticFileHandler && request.method === http_1.HttpMethods.get) {
76
- const staticResponse = await this.staticFileHandler.tryServeFile(request.url);
75
+ const context = await adapter.getContext();
76
+ if (this.staticFileHandler && context.req.method === http_1.HttpMethods.get) {
77
+ const staticResponse = await this.staticFileHandler.tryServeFile(context.req.url);
77
78
  if (staticResponse) {
78
79
  adapter.sendResponse(staticResponse);
79
80
  return;
80
81
  }
81
82
  }
82
- const response = await this.router.resolve(request);
83
+ const response = await this.router.resolve(context);
83
84
  adapter.sendResponse(response);
84
85
  }
85
86
  catch (error) {
@@ -147,12 +148,17 @@ class App {
147
148
  *
148
149
  * @param port - TCP port to listen on
149
150
  */
150
- run(port, callback, hostname = "127.0.0.1") {
151
- (0, node_http_1.createServer)((req, res) => {
152
- const adapter = new http_1.NodeHttpAdapter(req, res, this.loggerOptions);
153
- void this.handle(adapter);
154
- }).listen(port, hostname, () => {
155
- callback();
151
+ run(port = 3000, callback, hostname) {
152
+ const runtimeServer = (0, createRuntimeServer_1.createRuntimeServer)(this.loggerOptions);
153
+ runtimeServer.listen(async (adapter) => {
154
+ await this.handle(adapter);
155
+ }, {
156
+ port,
157
+ hostname,
158
+ callback: () => {
159
+ if (callback)
160
+ callback();
161
+ },
156
162
  });
157
163
  }
158
164
  /**
@@ -169,7 +175,7 @@ class App {
169
175
  * app.logger("common");
170
176
  * app.logger("combined", "./logs/http.log");
171
177
  */
172
- logger(format = "dev", filePath) {
178
+ logger(format, filePath) {
173
179
  this.loggerOptions = {
174
180
  ...this.loggerOptions,
175
181
  format,
@@ -192,25 +198,25 @@ class App {
192
198
  setPrefix(prefix) {
193
199
  this.router.setPrefix(prefix);
194
200
  }
195
- /** Registers a GET route */
196
- get(path, action, middlewares) {
197
- this.router.get(path, action, middlewares);
201
+ get(path, handlerOrMiddlewares, handler) {
202
+ const { action, middlewares } = (0, routeResolveFunc_1.normalizeRouteArgs)(handlerOrMiddlewares, handler);
203
+ this.router.get(path, middlewares, action);
198
204
  }
199
- /** Registers a POST route */
200
- post(path, action, middlewares) {
201
- this.router.post(path, action, middlewares);
205
+ post(path, handlerOrMiddlewares, handler) {
206
+ const { action, middlewares } = (0, routeResolveFunc_1.normalizeRouteArgs)(handlerOrMiddlewares, handler);
207
+ this.router.post(path, middlewares, action);
202
208
  }
203
- /** Registers a PUT route */
204
- put(path, action, middlewares) {
205
- this.router.put(path, action, middlewares);
209
+ put(path, handlerOrMiddlewares, handler) {
210
+ const { action, middlewares } = (0, routeResolveFunc_1.normalizeRouteArgs)(handlerOrMiddlewares, handler);
211
+ this.router.put(path, middlewares, action);
206
212
  }
207
- /** Registers a PATCH route */
208
- patch(path, action, middlewares) {
209
- this.router.patch(path, action, middlewares);
213
+ patch(path, handlerOrMiddlewares, handler) {
214
+ const { action, middlewares } = (0, routeResolveFunc_1.normalizeRouteArgs)(handlerOrMiddlewares, handler);
215
+ this.router.patch(path, middlewares, action);
210
216
  }
211
- /** Registers a DELETE route */
212
- delete(path, action, middlewares) {
213
- this.router.delete(path, action, middlewares);
217
+ delete(path, handlerOrMiddlewares, handler) {
218
+ const { action, middlewares } = (0, routeResolveFunc_1.normalizeRouteArgs)(handlerOrMiddlewares, handler);
219
+ this.router.delete(path, middlewares, action);
214
220
  }
215
221
  /**
216
222
  * Registers global middlewares.
@@ -218,9 +224,9 @@ class App {
218
224
  * These are executed for every route.
219
225
  *
220
226
  * @example
221
- * const auth = async (request, next) => {
222
- * console.log(request.header);
223
- * return await next(request);
227
+ * const auth = async (context, next) => {
228
+ * console.log(context.headers);
229
+ * return await next(context);
224
230
  * }
225
231
  *
226
232
  * app.middlewares(auth);
@@ -252,6 +258,7 @@ class App {
252
258
  }
253
259
  if (error instanceof validationException_1.ValidationException) {
254
260
  adapter.sendResponse(http_1.Response.json({
261
+ message: "Validation Error",
255
262
  errors: error.getErrorsByField(),
256
263
  }).setStatusCode(400));
257
264
  return;
@@ -0,0 +1,115 @@
1
+ import { IncomingHttpHeaders } from "node:http";
2
+ import { Request } from "./request";
3
+ import { Response } from "./response";
4
+ import { Readable } from "node:stream";
5
+ import { Session } from "../sessions";
6
+ /**
7
+ * Unified HTTP context shared by middleware and route handlers.
8
+ *
9
+ * This object wraps the current {@link Request} and exposes convenient
10
+ * read-only accessors (`headers`, `body`, `params`, etc.) plus response
11
+ * builder helpers (`json`, `text`, `redirect`, `stream`, `download`).
12
+ *
13
+ * @example
14
+ * app.get("/users/{id}", context => {
15
+ * return context.json({
16
+ * id: context.params.id,
17
+ * ip: context.remoteAddress,
18
+ * });
19
+ * });
20
+ */
21
+ export declare class Context {
22
+ private readonly _req;
23
+ /**
24
+ * @param _req - Current request wrapper instance.
25
+ */
26
+ constructor(_req: Request);
27
+ /**
28
+ * Returns a new empty response instance.
29
+ *
30
+ * Useful when constructing a response manually.
31
+ */
32
+ get res(): Response;
33
+ /**
34
+ * Returns the underlying request object.
35
+ */
36
+ get req(): Request;
37
+ /**
38
+ * Returns incoming request headers.
39
+ */
40
+ get headers(): IncomingHttpHeaders;
41
+ /**
42
+ * Returns the socket peer IP address when available.
43
+ */
44
+ get remoteAddress(): string | undefined;
45
+ /**
46
+ * Returns parsed request body.
47
+ */
48
+ get body(): Record<string, any>;
49
+ /**
50
+ * Returns route path parameters.
51
+ */
52
+ get params(): Record<string, any>;
53
+ /**
54
+ * Returns parsed query string values.
55
+ */
56
+ get query(): Record<string, any>;
57
+ /**
58
+ * Returns parsed request cookies.
59
+ */
60
+ get cookies(): Record<string, string>;
61
+ /**
62
+ * Returns request session wrapper.
63
+ */
64
+ get session(): Session;
65
+ /**
66
+ * Creates a JSON response.
67
+ *
68
+ * @param data - Serializable payload.
69
+ */
70
+ json(data: unknown): Response;
71
+ /**
72
+ * Creates a plain-text response.
73
+ *
74
+ * @param data - Text payload.
75
+ */
76
+ text(data: string): Response;
77
+ /**
78
+ * Creates an HTTP redirect response (302 by default).
79
+ *
80
+ * @param url - Redirect target URL.
81
+ */
82
+ redirect(url: string): Response;
83
+ /**
84
+ * Creates a streaming response.
85
+ *
86
+ * @param stream - Readable stream body.
87
+ * @param headers - Optional extra headers.
88
+ */
89
+ stream(stream: Readable, headers?: Record<string, string>): Response;
90
+ /**
91
+ * Creates a download response from a filesystem path.
92
+ *
93
+ * @param path - File path.
94
+ * @param filename - Optional download filename.
95
+ * @param headers - Optional additional headers.
96
+ */
97
+ download(path: string, filename?: string, headers?: Record<string, string>): Promise<Response>;
98
+ /**
99
+ * Renders a configured template with optional params.
100
+ *
101
+ * @param data - Template source or identifier depending on view engine setup.
102
+ * @param params - Template context values.
103
+ */
104
+ render(data: string, params?: Record<string, unknown>): Promise<Response>;
105
+ /**
106
+ * Sends a file for inline display.
107
+ *
108
+ * @param filePath - File path to send.
109
+ * @param options - Optional root and headers.
110
+ */
111
+ sendFile(filePath: string, options: {
112
+ headers?: Record<string, string>;
113
+ root?: string;
114
+ }): Promise<Response>;
115
+ }
@@ -0,0 +1,147 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Context = void 0;
4
+ const response_1 = require("./response");
5
+ /**
6
+ * Unified HTTP context shared by middleware and route handlers.
7
+ *
8
+ * This object wraps the current {@link Request} and exposes convenient
9
+ * read-only accessors (`headers`, `body`, `params`, etc.) plus response
10
+ * builder helpers (`json`, `text`, `redirect`, `stream`, `download`).
11
+ *
12
+ * @example
13
+ * app.get("/users/{id}", context => {
14
+ * return context.json({
15
+ * id: context.params.id,
16
+ * ip: context.remoteAddress,
17
+ * });
18
+ * });
19
+ */
20
+ class Context {
21
+ _req;
22
+ /**
23
+ * @param _req - Current request wrapper instance.
24
+ */
25
+ constructor(_req) {
26
+ this._req = _req;
27
+ this._req = _req;
28
+ }
29
+ /**
30
+ * Returns a new empty response instance.
31
+ *
32
+ * Useful when constructing a response manually.
33
+ */
34
+ get res() {
35
+ return new response_1.Response();
36
+ }
37
+ /**
38
+ * Returns the underlying request object.
39
+ */
40
+ get req() {
41
+ return this._req;
42
+ }
43
+ /**
44
+ * Returns incoming request headers.
45
+ */
46
+ get headers() {
47
+ return this._req.headers;
48
+ }
49
+ /**
50
+ * Returns the socket peer IP address when available.
51
+ */
52
+ get remoteAddress() {
53
+ return this._req.remoteAddress;
54
+ }
55
+ /**
56
+ * Returns parsed request body.
57
+ */
58
+ get body() {
59
+ return this._req.body;
60
+ }
61
+ /**
62
+ * Returns route path parameters.
63
+ */
64
+ get params() {
65
+ return this._req.params;
66
+ }
67
+ /**
68
+ * Returns parsed query string values.
69
+ */
70
+ get query() {
71
+ return this._req.query;
72
+ }
73
+ /**
74
+ * Returns parsed request cookies.
75
+ */
76
+ get cookies() {
77
+ return this._req.cookies;
78
+ }
79
+ /**
80
+ * Returns request session wrapper.
81
+ */
82
+ get session() {
83
+ return this._req.session;
84
+ }
85
+ /**
86
+ * Creates a JSON response.
87
+ *
88
+ * @param data - Serializable payload.
89
+ */
90
+ json(data) {
91
+ return response_1.Response.json(data);
92
+ }
93
+ /**
94
+ * Creates a plain-text response.
95
+ *
96
+ * @param data - Text payload.
97
+ */
98
+ text(data) {
99
+ return response_1.Response.text(data);
100
+ }
101
+ /**
102
+ * Creates an HTTP redirect response (302 by default).
103
+ *
104
+ * @param url - Redirect target URL.
105
+ */
106
+ redirect(url) {
107
+ return response_1.Response.redirect(url);
108
+ }
109
+ /**
110
+ * Creates a streaming response.
111
+ *
112
+ * @param stream - Readable stream body.
113
+ * @param headers - Optional extra headers.
114
+ */
115
+ stream(stream, headers) {
116
+ return response_1.Response.stream(stream, headers);
117
+ }
118
+ /**
119
+ * Creates a download response from a filesystem path.
120
+ *
121
+ * @param path - File path.
122
+ * @param filename - Optional download filename.
123
+ * @param headers - Optional additional headers.
124
+ */
125
+ async download(path, filename, headers) {
126
+ return await response_1.Response.download(path, filename, headers);
127
+ }
128
+ /**
129
+ * Renders a configured template with optional params.
130
+ *
131
+ * @param data - Template source or identifier depending on view engine setup.
132
+ * @param params - Template context values.
133
+ */
134
+ async render(data, params) {
135
+ return await response_1.Response.render(data, params);
136
+ }
137
+ /**
138
+ * Sends a file for inline display.
139
+ *
140
+ * @param filePath - File path to send.
141
+ * @param options - Optional root and headers.
142
+ */
143
+ async sendFile(filePath, options) {
144
+ return await response_1.Response.sendFile(filePath, options);
145
+ }
146
+ }
147
+ exports.Context = Context;
@@ -1,4 +1,4 @@
1
- import { Request } from "./request";
1
+ import { Context } from "./context";
2
2
  import { Response } from "./response";
3
3
  /**
4
4
  * High-level contract that defines the framework entry port
@@ -9,12 +9,12 @@ import { Response } from "./response";
9
9
  */
10
10
  export interface HttpAdapter {
11
11
  /**
12
- * Builds and returns a {@link Request} instance from
12
+ * Builds and returns a {@link Context} instance from
13
13
  * the current connection context.
14
14
  *
15
- * @returns A promise that resolves to a {@link Request} object
15
+ * @returns A promise that resolves to a {@link Context} object
16
16
  */
17
- getRequest(): Promise<Request>;
17
+ getContext(): Promise<Context>;
18
18
  /**
19
19
  * Sends a {@link Response} to the client, mapping its status,
20
20
  * headers, and body to the underlying runtime protocol.
@@ -1,7 +1,9 @@
1
1
  export { Response } from "./response";
2
2
  export { Request } from "./request";
3
+ export { Context } from "./context";
3
4
  export { NodeHttpAdapter } from "./nodeNativeHttp";
5
+ export { WebHttpAdapter } from "./webHttp";
4
6
  export { HttpMethods } from "./httpMethods";
5
- export { HttpAdapter } from "./httpAdapter";
7
+ export type { HttpAdapter } from "./httpAdapter";
6
8
  export { Logger } from "./logger";
7
9
  export type { LogFormat, LoggerOptions } from "./logger";
@@ -1,12 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Logger = exports.HttpMethods = exports.NodeHttpAdapter = exports.Request = exports.Response = void 0;
3
+ exports.Logger = exports.HttpMethods = exports.WebHttpAdapter = exports.NodeHttpAdapter = exports.Context = exports.Request = exports.Response = void 0;
4
4
  var response_1 = require("./response");
5
5
  Object.defineProperty(exports, "Response", { enumerable: true, get: function () { return response_1.Response; } });
6
6
  var request_1 = require("./request");
7
7
  Object.defineProperty(exports, "Request", { enumerable: true, get: function () { return request_1.Request; } });
8
+ var context_1 = require("./context");
9
+ Object.defineProperty(exports, "Context", { enumerable: true, get: function () { return context_1.Context; } });
8
10
  var nodeNativeHttp_1 = require("./nodeNativeHttp");
9
11
  Object.defineProperty(exports, "NodeHttpAdapter", { enumerable: true, get: function () { return nodeNativeHttp_1.NodeHttpAdapter; } });
12
+ var webHttp_1 = require("./webHttp");
13
+ Object.defineProperty(exports, "WebHttpAdapter", { enumerable: true, get: function () { return webHttp_1.WebHttpAdapter; } });
10
14
  var httpMethods_1 = require("./httpMethods");
11
15
  Object.defineProperty(exports, "HttpMethods", { enumerable: true, get: function () { return httpMethods_1.HttpMethods; } });
12
16
  var logger_1 = require("./logger");
@@ -2,8 +2,12 @@ import { IncomingMessage, ServerResponse } from "node:http";
2
2
  export type LogFormat = "combined" | "common" | "dev" | "short" | "tiny";
3
3
  export type LoggerOptions = {
4
4
  format?: LogFormat;
5
- stream?: NodeJS.WritableStream;
6
- fileStream?: NodeJS.WritableStream;
5
+ stream?: {
6
+ write(chunk: string): unknown;
7
+ };
8
+ fileStream?: {
9
+ write(chunk: string): unknown;
10
+ };
7
11
  };
8
12
  /**
9
13
  * Minimal HTTP request logger.
@@ -45,7 +49,9 @@ export declare class Logger {
45
49
  * @param startTime - High-resolution timestamp captured at request start using `process.hrtime.bigint()`.
46
50
  */
47
51
  log(req: IncomingMessage, res: ServerResponse, startTime: bigint): void;
52
+ logWeb(req: globalThis.Request, res: globalThis.Response, startTimeMs: number): void;
48
53
  private buildLogLine;
54
+ private buildWebLogLine;
49
55
  /**
50
56
  * Applies ANSI color codes to an HTTP status code for terminal output.
51
57
  *
@@ -60,4 +66,5 @@ export declare class Logger {
60
66
  * @returns Colorized status code string suitable for terminal output.
61
67
  */
62
68
  private colorizeStatus;
69
+ private getDefaultStream;
63
70
  }
@@ -22,7 +22,7 @@ class Logger {
22
22
  fileStream;
23
23
  format;
24
24
  constructor(options = {}) {
25
- this.stream = options.stream || process.stdout;
25
+ this.stream = options.stream || this.getDefaultStream();
26
26
  this.fileStream = options.fileStream;
27
27
  this.format = options.format || "dev";
28
28
  }
@@ -54,6 +54,15 @@ class Logger {
54
54
  this.fileStream.write(fileLine + "\n");
55
55
  }
56
56
  }
57
+ logWeb(req, res, startTimeMs) {
58
+ const responseTime = (performance.now() - startTimeMs).toFixed(3);
59
+ const consoleLine = this.buildWebLogLine(req, res, responseTime, true);
60
+ const fileLine = this.buildWebLogLine(req, res, responseTime, false);
61
+ this.stream.write(consoleLine + "\n");
62
+ if (this.fileStream) {
63
+ this.fileStream.write(fileLine + "\n");
64
+ }
65
+ }
57
66
  buildLogLine(req, res, responseTime, useColor) {
58
67
  const method = req.method || "-";
59
68
  const url = req.url || "-";
@@ -86,6 +95,32 @@ class Logger {
86
95
  }
87
96
  return `${method} ${url} ${statusCode} ${responseTime} ms - ${contentLength}`;
88
97
  }
98
+ buildWebLogLine(req, res, responseTime, useColor) {
99
+ const method = req.method || "-";
100
+ const url = new URL(req.url).pathname || "-";
101
+ const statusCode = useColor
102
+ ? this.colorizeStatus(res.status)
103
+ : String(res.status);
104
+ const contentLength = res.headers.get("content-length") || "-";
105
+ const remoteAddr = req.headers.get("x-forwarded-for") || "-";
106
+ const httpVersion = "1.1";
107
+ const referrer = req.headers.get("referer") || req.headers.get("referrer") || "-";
108
+ const userAgent = req.headers.get("user-agent") || "-";
109
+ const date = new Date().toUTCString();
110
+ if (this.format === "tiny") {
111
+ return `${method} ${url} ${statusCode} ${contentLength} - ${responseTime} ms`;
112
+ }
113
+ if (this.format === "short") {
114
+ return `${remoteAddr} ${method} ${url} ${statusCode} ${contentLength} - ${responseTime} ms`;
115
+ }
116
+ if (this.format === "common") {
117
+ return `${remoteAddr} - - [${date}] "${method} ${url} HTTP/${httpVersion}" ${statusCode} ${contentLength}`;
118
+ }
119
+ if (this.format === "combined") {
120
+ return `${remoteAddr} - - [${date}] "${method} ${url} HTTP/${httpVersion}" ${statusCode} ${contentLength} "${referrer}" "${userAgent}"`;
121
+ }
122
+ return `${method} ${url} ${statusCode} ${responseTime} ms - ${contentLength}`;
123
+ }
89
124
  /**
90
125
  * Applies ANSI color codes to an HTTP status code for terminal output.
91
126
  *
@@ -115,5 +150,18 @@ class Logger {
115
150
  }
116
151
  return statusStr;
117
152
  }
153
+ getDefaultStream() {
154
+ const maybeProcess = globalThis;
155
+ if (maybeProcess.process?.stdout?.write) {
156
+ return maybeProcess.process.stdout;
157
+ }
158
+ return {
159
+ write: (chunk) => {
160
+ // Use console fallback on runtimes without Node process/stdout.
161
+ // eslint-disable-next-line no-console
162
+ console.log(chunk.trimEnd());
163
+ },
164
+ };
165
+ }
118
166
  }
119
167
  exports.Logger = Logger;
@@ -1,7 +1,7 @@
1
1
  import { IncomingMessage, ServerResponse } from "node:http";
2
2
  import type { HttpAdapter } from "./httpAdapter";
3
3
  import { Response } from "./response";
4
- import { Request } from "./request";
4
+ import { Context } from "./context";
5
5
  import { type LoggerOptions } from "./logger";
6
6
  /**
7
7
  * Node.js HTTP adapter.
@@ -26,12 +26,12 @@ export declare class NodeHttpAdapter implements HttpAdapter {
26
26
  */
27
27
  constructor(req: IncomingMessage, res: ServerResponse, loggerOptions?: LoggerOptions);
28
28
  /**
29
- * Builds and returns a {@link Request} instance from
29
+ * Builds and returns a {@link Context} instance from
30
30
  * the incoming Node.js request.
31
31
  *
32
- * @returns A fully constructed {@link Request} instance
32
+ * @returns A fully constructed {@link Context} instance
33
33
  */
34
- getRequest(): Promise<Request>;
34
+ getContext(): Promise<Context>;
35
35
  /**
36
36
  * Sends a framework {@link Response} to the client by mapping it
37
37
  * to the native Node.js {@link ServerResponse}.
@@ -3,8 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.NodeHttpAdapter = void 0;
4
4
  const httpMethods_1 = require("./httpMethods");
5
5
  const request_1 = require("./request");
6
+ const context_1 = require("./context");
6
7
  const contentParserManager_1 = require("../parsers/contentParserManager");
7
8
  const logger_1 = require("./logger");
9
+ const node_stream_1 = require("node:stream");
8
10
  /**
9
11
  * Node.js HTTP adapter.
10
12
  *
@@ -34,24 +36,25 @@ class NodeHttpAdapter {
34
36
  this.contentParser = new contentParserManager_1.ContentParserManager();
35
37
  }
36
38
  /**
37
- * Builds and returns a {@link Request} instance from
39
+ * Builds and returns a {@link Context} instance from
38
40
  * the incoming Node.js request.
39
41
  *
40
- * @returns A fully constructed {@link Request} instance
42
+ * @returns A fully constructed {@link Context} instance
41
43
  */
42
- async getRequest() {
44
+ async getContext() {
43
45
  const url = new URL(this.req.url || "", `http://${this.req.headers.host}`);
44
46
  const request = new request_1.Request(url.pathname);
45
47
  request.setMethod(this.req.method || httpMethods_1.HttpMethods.get);
46
48
  request.setQuery(Object.fromEntries(url.searchParams.entries()));
47
49
  request.setHeaders(this.req.headers);
50
+ request.setRemoteAddress(this.req.socket?.remoteAddress);
48
51
  if (request.method === httpMethods_1.HttpMethods.post ||
49
52
  request.method === httpMethods_1.HttpMethods.put ||
50
53
  request.method === httpMethods_1.HttpMethods.patch) {
51
54
  const parsedData = await this.contentParser.parse(this.req);
52
55
  request.setBody(parsedData);
53
56
  }
54
- return request;
57
+ return new context_1.Context(request);
55
58
  }
56
59
  /**
57
60
  * Sends a framework {@link Response} to the client by mapping it
@@ -72,6 +75,10 @@ class NodeHttpAdapter {
72
75
  if (!response.content)
73
76
  this.res.removeHeader("Content-Type");
74
77
  this.logger.log(this.req, this.res, this.startTime);
78
+ if (response.content instanceof node_stream_1.Readable) {
79
+ response.content.pipe(this.res);
80
+ return;
81
+ }
75
82
  this.res.end(response.content);
76
83
  }
77
84
  }