skyguard-js 1.0.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.
Files changed (142) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +237 -0
  3. package/dist/app.d.ts +123 -0
  4. package/dist/app.js +198 -0
  5. package/dist/container/container.d.ts +60 -0
  6. package/dist/container/container.js +71 -0
  7. package/dist/exceptions/baseException.d.ts +6 -0
  8. package/dist/exceptions/baseException.js +15 -0
  9. package/dist/exceptions/contentDispositionException.d.ts +4 -0
  10. package/dist/exceptions/contentDispositionException.js +11 -0
  11. package/dist/exceptions/contentParserException.d.ts +10 -0
  12. package/dist/exceptions/contentParserException.js +21 -0
  13. package/dist/exceptions/fileDownloadException.d.ts +4 -0
  14. package/dist/exceptions/fileDownloadException.js +11 -0
  15. package/dist/exceptions/fileExistsException.d.ts +4 -0
  16. package/dist/exceptions/fileExistsException.js +11 -0
  17. package/dist/exceptions/helperExceptions.d.ts +10 -0
  18. package/dist/exceptions/helperExceptions.js +25 -0
  19. package/dist/exceptions/httpNotFoundException.d.ts +7 -0
  20. package/dist/exceptions/httpNotFoundException.js +14 -0
  21. package/dist/exceptions/index.d.ts +9 -0
  22. package/dist/exceptions/index.js +25 -0
  23. package/dist/exceptions/invalidHttpStatusException.d.ts +4 -0
  24. package/dist/exceptions/invalidHttpStatusException.js +11 -0
  25. package/dist/exceptions/sessionException.d.ts +4 -0
  26. package/dist/exceptions/sessionException.js +11 -0
  27. package/dist/exceptions/validationException.d.ts +13 -0
  28. package/dist/exceptions/validationException.js +32 -0
  29. package/dist/helpers/app.d.ts +4 -0
  30. package/dist/helpers/app.js +12 -0
  31. package/dist/helpers/http.d.ts +59 -0
  32. package/dist/helpers/http.js +77 -0
  33. package/dist/helpers/index.d.ts +1 -0
  34. package/dist/helpers/index.js +9 -0
  35. package/dist/http/httpAdapter.d.ts +26 -0
  36. package/dist/http/httpAdapter.js +2 -0
  37. package/dist/http/httpMethods.d.ts +14 -0
  38. package/dist/http/httpMethods.js +18 -0
  39. package/dist/http/index.d.ts +6 -0
  40. package/dist/http/index.js +13 -0
  41. package/dist/http/logger.d.ts +8 -0
  42. package/dist/http/logger.js +36 -0
  43. package/dist/http/nodeNativeHttp.d.ts +41 -0
  44. package/dist/http/nodeNativeHttp.js +73 -0
  45. package/dist/http/request.d.ts +85 -0
  46. package/dist/http/request.js +127 -0
  47. package/dist/http/response.d.ts +118 -0
  48. package/dist/http/response.js +179 -0
  49. package/dist/http/statusCodes.d.ts +1 -0
  50. package/dist/http/statusCodes.js +38 -0
  51. package/dist/index.d.ts +4 -0
  52. package/dist/index.js +10 -0
  53. package/dist/middlewares/cors.d.ts +103 -0
  54. package/dist/middlewares/cors.js +91 -0
  55. package/dist/middlewares/session.d.ts +26 -0
  56. package/dist/middlewares/session.js +88 -0
  57. package/dist/parsers/contentParser.d.ts +27 -0
  58. package/dist/parsers/contentParser.js +2 -0
  59. package/dist/parsers/contentParserManager.d.ts +50 -0
  60. package/dist/parsers/contentParserManager.js +91 -0
  61. package/dist/parsers/index.d.ts +8 -0
  62. package/dist/parsers/index.js +30 -0
  63. package/dist/parsers/jsonParser.d.ts +10 -0
  64. package/dist/parsers/jsonParser.js +24 -0
  65. package/dist/parsers/multipartParser.d.ts +35 -0
  66. package/dist/parsers/multipartParser.js +120 -0
  67. package/dist/parsers/parserInterface.d.ts +37 -0
  68. package/dist/parsers/parserInterface.js +2 -0
  69. package/dist/parsers/textParser.d.ts +11 -0
  70. package/dist/parsers/textParser.js +19 -0
  71. package/dist/parsers/urlEncodedParser.d.ts +10 -0
  72. package/dist/parsers/urlEncodedParser.js +19 -0
  73. package/dist/parsers/xmlParser.d.ts +47 -0
  74. package/dist/parsers/xmlParser.js +158 -0
  75. package/dist/routing/index.d.ts +3 -0
  76. package/dist/routing/index.js +9 -0
  77. package/dist/routing/layer.d.ts +85 -0
  78. package/dist/routing/layer.js +117 -0
  79. package/dist/routing/router.d.ts +143 -0
  80. package/dist/routing/router.js +210 -0
  81. package/dist/routing/routerGroup.d.ts +79 -0
  82. package/dist/routing/routerGroup.js +103 -0
  83. package/dist/server/nodeNativeServer.d.ts +29 -0
  84. package/dist/server/nodeNativeServer.js +42 -0
  85. package/dist/sessions/cookieOptions.d.ts +72 -0
  86. package/dist/sessions/cookieOptions.js +2 -0
  87. package/dist/sessions/index.d.ts +4 -0
  88. package/dist/sessions/index.js +7 -0
  89. package/dist/sessions/memorySessionStorage.d.ts +112 -0
  90. package/dist/sessions/memorySessionStorage.js +170 -0
  91. package/dist/sessions/session.d.ts +80 -0
  92. package/dist/sessions/session.js +101 -0
  93. package/dist/sessions/sessionStorage.d.ts +105 -0
  94. package/dist/sessions/sessionStorage.js +2 -0
  95. package/dist/static/contentDisposition.d.ts +71 -0
  96. package/dist/static/contentDisposition.js +159 -0
  97. package/dist/static/fileDownload.d.ts +44 -0
  98. package/dist/static/fileDownload.js +88 -0
  99. package/dist/static/fileStaticHandler.d.ts +61 -0
  100. package/dist/static/fileStaticHandler.js +110 -0
  101. package/dist/static/index.d.ts +4 -0
  102. package/dist/static/index.js +11 -0
  103. package/dist/static/mimeTypes.d.ts +1 -0
  104. package/dist/static/mimeTypes.js +40 -0
  105. package/dist/tsconfig.tsbuildinfo +1 -0
  106. package/dist/types/index.d.ts +122 -0
  107. package/dist/types/index.js +2 -0
  108. package/dist/validators/index.d.ts +5 -0
  109. package/dist/validators/index.js +22 -0
  110. package/dist/validators/rules/booleanRule.d.ts +11 -0
  111. package/dist/validators/rules/booleanRule.js +22 -0
  112. package/dist/validators/rules/dateRule.d.ts +16 -0
  113. package/dist/validators/rules/dateRule.js +44 -0
  114. package/dist/validators/rules/emailRule.d.ts +12 -0
  115. package/dist/validators/rules/emailRule.js +24 -0
  116. package/dist/validators/rules/index.d.ts +6 -0
  117. package/dist/validators/rules/index.js +15 -0
  118. package/dist/validators/rules/numberRule.d.ts +17 -0
  119. package/dist/validators/rules/numberRule.js +30 -0
  120. package/dist/validators/rules/requiredRule.d.ts +11 -0
  121. package/dist/validators/rules/requiredRule.js +21 -0
  122. package/dist/validators/rules/stringRule.d.ts +18 -0
  123. package/dist/validators/rules/stringRule.js +32 -0
  124. package/dist/validators/types.d.ts +55 -0
  125. package/dist/validators/types.js +2 -0
  126. package/dist/validators/validationRule.d.ts +53 -0
  127. package/dist/validators/validationRule.js +37 -0
  128. package/dist/validators/validationSchema.d.ts +145 -0
  129. package/dist/validators/validationSchema.js +198 -0
  130. package/dist/validators/validator.d.ts +58 -0
  131. package/dist/validators/validator.js +91 -0
  132. package/dist/views/helpersTemplate.d.ts +104 -0
  133. package/dist/views/helpersTemplate.js +186 -0
  134. package/dist/views/index.d.ts +4 -0
  135. package/dist/views/index.js +9 -0
  136. package/dist/views/raptorEngine.d.ts +127 -0
  137. package/dist/views/raptorEngine.js +165 -0
  138. package/dist/views/templateEngine.d.ts +80 -0
  139. package/dist/views/templateEngine.js +204 -0
  140. package/dist/views/view.d.ts +55 -0
  141. package/dist/views/view.js +2 -0
  142. package/package.json +79 -0
@@ -0,0 +1,103 @@
1
+ import { HttpMethods } from "../http";
2
+ import type { Middleware } from "../types";
3
+ /**
4
+ * CORS origin matcher type.
5
+ *
6
+ * Controls how the middleware determines the value of
7
+ * `Access-Control-Allow-Origin` for a given request.
8
+ *
9
+ * Supported forms:
10
+ * - `string`: a single allowed origin (e.g. `"https://example.com"`) or `"*"` for public access
11
+ * - `string[]`: a whitelist of allowed origins
12
+ * - `function`: a custom resolver that receives the request Origin and decides what to allow
13
+ *
14
+ * Notes:
15
+ * - If `credentials: true` is enabled, `"*"` cannot be used as the final
16
+ * `Access-Control-Allow-Origin` value. In that case this middleware will
17
+ * reflect the request origin when allowed.
18
+ */
19
+ type CorsOrigin = string | string[] | ((origin: string | undefined) => string);
20
+ /**
21
+ * CORS middleware configuration options.
22
+ *
23
+ * These options map to standard CORS response headers and preflight behavior.
24
+ */
25
+ interface CorsOptions {
26
+ /**
27
+ * Allowed origin(s) for cross-origin requests.
28
+ *
29
+ * - `"*"` allows any origin (public).
30
+ * - A specific origin (string) restricts access to that origin.
31
+ * - An array provides a whitelist.
32
+ * - A function can implement custom allow/deny logic.
33
+ *
34
+ * Affects: `Access-Control-Allow-Origin`.
35
+ */
36
+ origin?: CorsOrigin;
37
+ /**
38
+ * HTTP methods allowed for cross-origin requests.
39
+ *
40
+ * Used in preflight responses.
41
+ *
42
+ * Affects: `Access-Control-Allow-Methods`.
43
+ */
44
+ methods?: HttpMethods[];
45
+ /**
46
+ * Request headers the browser is allowed to send in cross-origin requests.
47
+ *
48
+ * Used in preflight responses (especially when the client sends custom headers
49
+ * such as `Authorization`).
50
+ *
51
+ * Affects: `Access-Control-Allow-Headers`.
52
+ */
53
+ allowedHeaders?: string[];
54
+ /**
55
+ * Response headers that should be exposed to browser JavaScript.
56
+ *
57
+ * By default, browsers do not allow JS to read non-safelisted headers.
58
+ *
59
+ * Affects: `Access-Control-Expose-Headers`.
60
+ */
61
+ exposedHeaders?: string[];
62
+ /**
63
+ * Whether the response can be exposed when credentials are included.
64
+ *
65
+ * Enables sending/receiving cookies and authenticated requests across origins.
66
+ *
67
+ * Affects: `Access-Control-Allow-Credentials`.
68
+ *
69
+ * Important:
70
+ * - When enabled, the final `Access-Control-Allow-Origin` value must not be `"*"`.
71
+ */
72
+ credentials?: boolean;
73
+ /**
74
+ * How long (in seconds) the browser may cache a successful preflight response.
75
+ *
76
+ * Improves performance by reducing repeated OPTIONS requests.
77
+ *
78
+ * Affects: `Access-Control-Max-Age`.
79
+ */
80
+ maxAge?: number;
81
+ /**
82
+ * If `false` (default), the middleware ends OPTIONS requests immediately with 204.
83
+ * If `true`, the request continues down the middleware/handler chain after setting
84
+ * the preflight headers.
85
+ */
86
+ preflightContinue?: boolean;
87
+ }
88
+ /**
89
+ * Native CORS middleware.
90
+ *
91
+ * Behavior overview:
92
+ * - Resolves the allowed origin from the request `Origin` header using `resolveOrigin`.
93
+ * - Sets `Access-Control-Allow-Origin` (and `Vary: Origin` when not `"*"`).
94
+ * - Optionally sets `Access-Control-Allow-Credentials` and `Access-Control-Expose-Headers`.
95
+ * - For OPTIONS requests, returns a 204 response (unless `preflightContinue` is enabled),
96
+ * including `Access-Control-Allow-Methods`, `Access-Control-Allow-Headers`, and
97
+ * `Access-Control-Max-Age`.
98
+ *
99
+ * @param options - CORS configuration.
100
+ * @returns A `Middleware` function that applies CORS headers to the response.
101
+ */
102
+ export declare const cors: (options?: CorsOptions) => Middleware;
103
+ export {};
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.cors = void 0;
4
+ const http_1 = require("../http");
5
+ /**
6
+ * Resolves the effective `Access-Control-Allow-Origin` value for a request.
7
+ *
8
+ * @param requestOrigin - The `Origin` header value from the incoming request.
9
+ * @returns The origin to allow:
10
+ * - `"*"` for public access when credentials are disabled
11
+ * - the request origin when it is allowed (whitelist or custom resolver)
12
+ * - `null` if the origin is not allowed (no CORS headers will be applied)
13
+ */
14
+ function resolveOrigin(requestOrigin, config) {
15
+ if (!requestOrigin)
16
+ return null;
17
+ if (typeof config.origin === "function") {
18
+ const out = config.origin(requestOrigin);
19
+ return out ? requestOrigin : null;
20
+ }
21
+ if (Array.isArray(config.origin))
22
+ return config.origin.includes(requestOrigin) ? requestOrigin : null;
23
+ if (config.origin === "*")
24
+ return config.credentials ? requestOrigin : "*";
25
+ return config.origin;
26
+ }
27
+ /**
28
+ * Native CORS middleware.
29
+ *
30
+ * Behavior overview:
31
+ * - Resolves the allowed origin from the request `Origin` header using `resolveOrigin`.
32
+ * - Sets `Access-Control-Allow-Origin` (and `Vary: Origin` when not `"*"`).
33
+ * - Optionally sets `Access-Control-Allow-Credentials` and `Access-Control-Expose-Headers`.
34
+ * - For OPTIONS requests, returns a 204 response (unless `preflightContinue` is enabled),
35
+ * including `Access-Control-Allow-Methods`, `Access-Control-Allow-Headers`, and
36
+ * `Access-Control-Max-Age`.
37
+ *
38
+ * @param options - CORS configuration.
39
+ * @returns A `Middleware` function that applies CORS headers to the response.
40
+ */
41
+ const cors = (options = {}) => {
42
+ const config = {
43
+ origin: options.origin ?? "*",
44
+ methods: options.methods ?? [
45
+ http_1.HttpMethods.get,
46
+ http_1.HttpMethods.post,
47
+ http_1.HttpMethods.put,
48
+ http_1.HttpMethods.patch,
49
+ http_1.HttpMethods.delete,
50
+ http_1.HttpMethods.options,
51
+ ],
52
+ allowedHeaders: options.allowedHeaders ?? ["Content-Type", "Authorization"],
53
+ exposedHeaders: options.exposedHeaders ?? [],
54
+ credentials: options.credentials ?? false,
55
+ maxAge: options.maxAge ?? 86400,
56
+ preflightContinue: options.preflightContinue ?? false,
57
+ };
58
+ return async (request, next) => {
59
+ const allowedOrigin = resolveOrigin(request.getHeaders.origin, config);
60
+ const corsHeaders = {};
61
+ if (allowedOrigin) {
62
+ corsHeaders["Access-Control-Allow-Origin"] = allowedOrigin;
63
+ if (allowedOrigin !== "*")
64
+ corsHeaders["Vary"] = "Origin";
65
+ }
66
+ if (config.credentials)
67
+ corsHeaders["Access-Control-Allow-Credentials"] = "true";
68
+ if (config.exposedHeaders.length) {
69
+ corsHeaders["Access-Control-Expose-Headers"] =
70
+ config.exposedHeaders.join(", ");
71
+ }
72
+ if (request.getMethod === http_1.HttpMethods.options) {
73
+ corsHeaders["Access-Control-Allow-Methods"] = config.methods.join(", ");
74
+ corsHeaders["Access-Control-Allow-Headers"] =
75
+ config.allowedHeaders.join(", ");
76
+ corsHeaders["Access-Control-Max-Age"] = String(config.maxAge);
77
+ if (!config.preflightContinue) {
78
+ return new http_1.Response()
79
+ .setStatus(204)
80
+ .setContent(null)
81
+ .setHeaders(corsHeaders);
82
+ }
83
+ }
84
+ const response = await next(request);
85
+ for (const [key, value] of Object.entries(corsHeaders)) {
86
+ response.setHeader(key, value);
87
+ }
88
+ return response;
89
+ };
90
+ };
91
+ exports.cors = cors;
@@ -0,0 +1,26 @@
1
+ import { type SessionStorage, type CookieOptions } from "../sessions";
2
+ import type { Middleware } from "../types";
3
+ /**
4
+ * Constructor type for `SessionStorage` implementations.
5
+ *
6
+ * Allows injecting different session storage strategies
7
+ * (memory, file, redis, etc.).
8
+ */
9
+ type SessionStorageConstructor<T extends SessionStorage = SessionStorage> = new (...args: any[]) => T;
10
+ /**
11
+ * Session lifecycle middleware implementation.
12
+ *
13
+ * @param StorageClass - `SessionStorage` implementation
14
+ * @param options - Session cookie configuration
15
+ * @returns Session middleware
16
+ *
17
+ * @example
18
+ * app.middlewares([
19
+ * sessionMiddleware(MemorySessionStorage, {
20
+ * cookieName: "sid",
21
+ * maxAge: 86400,
22
+ * }),
23
+ * ]);
24
+ */
25
+ export declare const sessions: (StorageClass: SessionStorageConstructor, options?: CookieOptions) => Middleware;
26
+ export {};
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sessions = void 0;
4
+ const sessions_1 = require("../sessions");
5
+ /**
6
+ * Parses the `Cookie` header into a key/value object.
7
+ *
8
+ * @param cookieHeader - Raw `Cookie` header value
9
+ * @returns Parsed cookies
10
+ *
11
+ * @example
12
+ * parseCookies("foo=bar; session_id=abc123");
13
+ * // { foo: "bar", session_id: "abc123" }
14
+ */
15
+ function parseCookies(cookieHeader) {
16
+ if (!cookieHeader)
17
+ return {};
18
+ return Object.fromEntries(cookieHeader.split(";").map((cookie) => {
19
+ const [key, ...value] = cookie.trim().split("=");
20
+ return [key, decodeURIComponent(value.join("="))];
21
+ }));
22
+ }
23
+ /**
24
+ * Builds the `Set-Cookie` header value for the session.
25
+ *
26
+ * @param sessionId - Session identifier
27
+ * @param config - Fully resolved cookie configuration
28
+ * @returns Value ready to be used in `Set-Cookie`
29
+ *
30
+ * @example
31
+ * buildSessionCookie("abc123", config);
32
+ * // "session_id=abc123; Max-Age=86400; Path=/; SameSite=Lax; HttpOnly"
33
+ */
34
+ function buildSessionCookie(sessionId, config) {
35
+ const parts = [
36
+ `${config.cookieName}=${encodeURIComponent(sessionId)}`,
37
+ `Max-Age=${config.maxAge}`,
38
+ `Path=${config.path}`,
39
+ `SameSite=${config.sameSite}`,
40
+ ];
41
+ if (config.httpOnly)
42
+ parts.push("HttpOnly");
43
+ if (config.secure)
44
+ parts.push("Secure");
45
+ return parts.join("; ");
46
+ }
47
+ /**
48
+ * Session lifecycle middleware implementation.
49
+ *
50
+ * @param StorageClass - `SessionStorage` implementation
51
+ * @param options - Session cookie configuration
52
+ * @returns Session middleware
53
+ *
54
+ * @example
55
+ * app.middlewares([
56
+ * sessionMiddleware(MemorySessionStorage, {
57
+ * cookieName: "sid",
58
+ * maxAge: 86400,
59
+ * }),
60
+ * ]);
61
+ */
62
+ const sessions = (StorageClass, options = {}) => {
63
+ const timeMaxAge = 86400;
64
+ const config = {
65
+ cookieName: options.cookieName ?? "session_id",
66
+ maxAge: options.maxAge ?? timeMaxAge,
67
+ httpOnly: options.httpOnly ?? true,
68
+ secure: options.secure ?? false,
69
+ sameSite: options.sameSite ?? "Lax",
70
+ path: options.path ?? "/",
71
+ };
72
+ return async (request, next) => {
73
+ const cookies = parseCookies(request.getHeaders["cookie"] || "");
74
+ const sessionId = cookies[config.cookieName];
75
+ const storage = new StorageClass(options.maxAge || timeMaxAge);
76
+ if (sessionId)
77
+ storage.load(sessionId);
78
+ const session = new sessions_1.Session(storage);
79
+ request.setSession(session);
80
+ const response = await next(request);
81
+ if (storage.id() !== null) {
82
+ const cookieValue = buildSessionCookie(storage.id(), config);
83
+ response.setHeader("Set-Cookie", cookieValue);
84
+ }
85
+ return response;
86
+ };
87
+ };
88
+ exports.sessions = sessions;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Contract for classes responsible for parsing HTTP request bodies.
3
+ *
4
+ * Implementations decide whether they can handle a given `Content-Type`
5
+ * and transform the raw body into a usable structure.
6
+ */
7
+ export interface ContentParser {
8
+ /**
9
+ * Determines whether this parser can handle the given content type.
10
+ *
11
+ * @param contentType - Full `Content-Type` header value
12
+ * @returns `true` if the content type can be parsed by this parser
13
+ */
14
+ canParse(contentType: string): boolean;
15
+ /**
16
+ * Parses the raw request body.
17
+ *
18
+ * If the content cannot be parsed, implementations may return
19
+ * the original body.
20
+ *
21
+ * @param body - Raw request body
22
+ * @param contentType - Full `Content-Type` header value
23
+ * (may include charset, boundary, etc.)
24
+ * @returns Parsed content or the original body
25
+ */
26
+ parse(body: Buffer | string, contentType: string): unknown;
27
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,50 @@
1
+ import { IncomingMessage } from "node:http";
2
+ import type { ContentParser } from "./contentParser";
3
+ /**
4
+ * Main request body parsing manager.
5
+ *
6
+ * Coordinates multiple {@link ContentParser} implementations and
7
+ * selects the appropriate one based on the request `Content-Type`.
8
+ */
9
+ export declare class ContentParserManager {
10
+ private parsers;
11
+ constructor();
12
+ /**
13
+ * Registers a custom content parser.
14
+ *
15
+ * Parsers registered later take priority over existing ones.
16
+ *
17
+ * @param parser - Content parser implementation
18
+ *
19
+ * @example
20
+ * contentParserManager.registerParser(new CustomParser());
21
+ */
22
+ registerParser(parser: ContentParser): void;
23
+ /**
24
+ * Parses the request body using the appropriate parser.
25
+ *
26
+ * The parser is selected based on the `Content-Type` header.
27
+ * If no parser matches, the raw body is returned.
28
+ *
29
+ * @param req - Native incoming HTTP request
30
+ * @returns Parsed body content or raw body
31
+ *
32
+ * @example
33
+ * const data = await contentParserManager.parse(req);
34
+ */
35
+ parse(req: IncomingMessage): Promise<unknown>;
36
+ /**
37
+ * Reads the raw request body.
38
+ *
39
+ * @param req - Native incoming HTTP request
40
+ * @returns A promise that resolves to the full body buffer
41
+ */
42
+ private readBody;
43
+ /**
44
+ * Finds a parser capable of handling the given content type.
45
+ *
46
+ * @param contentType - Request `Content-Type` header
47
+ * @returns Matching parser or `null` if none is found
48
+ */
49
+ private findParser;
50
+ }
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ContentParserManager = void 0;
4
+ const jsonParser_1 = require("./jsonParser");
5
+ const multipartParser_1 = require("./multipartParser");
6
+ const textParser_1 = require("./textParser");
7
+ const urlEncodedParser_1 = require("./urlEncodedParser");
8
+ const xmlParser_1 = require("./xmlParser");
9
+ const contentParserException_1 = require("../exceptions/contentParserException");
10
+ /**
11
+ * Main request body parsing manager.
12
+ *
13
+ * Coordinates multiple {@link ContentParser} implementations and
14
+ * selects the appropriate one based on the request `Content-Type`.
15
+ */
16
+ class ContentParserManager {
17
+ parsers = [];
18
+ constructor() {
19
+ this.registerParser(new jsonParser_1.JsonParser());
20
+ this.registerParser(new multipartParser_1.MultipartParser());
21
+ this.registerParser(new urlEncodedParser_1.UrlEncodedParser());
22
+ this.registerParser(new textParser_1.TextParser());
23
+ this.registerParser(new xmlParser_1.XmlParser());
24
+ }
25
+ /**
26
+ * Registers a custom content parser.
27
+ *
28
+ * Parsers registered later take priority over existing ones.
29
+ *
30
+ * @param parser - Content parser implementation
31
+ *
32
+ * @example
33
+ * contentParserManager.registerParser(new CustomParser());
34
+ */
35
+ registerParser(parser) {
36
+ // Insert at the beginning to give higher priority
37
+ this.parsers.unshift(parser);
38
+ }
39
+ /**
40
+ * Parses the request body using the appropriate parser.
41
+ *
42
+ * The parser is selected based on the `Content-Type` header.
43
+ * If no parser matches, the raw body is returned.
44
+ *
45
+ * @param req - Native incoming HTTP request
46
+ * @returns Parsed body content or raw body
47
+ *
48
+ * @example
49
+ * const data = await contentParserManager.parse(req);
50
+ */
51
+ async parse(req) {
52
+ const body = await this.readBody(req);
53
+ if (body.length <= 0)
54
+ return {};
55
+ const contentType = req.headers["content-type"] || "text/plain";
56
+ const parser = this.findParser(contentType);
57
+ if (!parser)
58
+ return Buffer.isBuffer(body) ? body : Buffer.from(body);
59
+ return parser.parse(body, contentType);
60
+ }
61
+ /**
62
+ * Reads the raw request body.
63
+ *
64
+ * @param req - Native incoming HTTP request
65
+ * @returns A promise that resolves to the full body buffer
66
+ */
67
+ readBody(req) {
68
+ return new Promise((resolve, reject) => {
69
+ const chunks = [];
70
+ req.on("data", (chunk) => {
71
+ chunks.push(chunk);
72
+ });
73
+ req.on("end", () => {
74
+ resolve(Buffer.concat(chunks));
75
+ });
76
+ req.on("error", () => {
77
+ reject(new contentParserException_1.ReadBodyException());
78
+ });
79
+ });
80
+ }
81
+ /**
82
+ * Finds a parser capable of handling the given content type.
83
+ *
84
+ * @param contentType - Request `Content-Type` header
85
+ * @returns Matching parser or `null` if none is found
86
+ */
87
+ findParser(contentType) {
88
+ return this.parsers.find((parser) => parser.canParse(contentType)) || null;
89
+ }
90
+ }
91
+ exports.ContentParserManager = ContentParserManager;
@@ -0,0 +1,8 @@
1
+ export { ContentParserManager } from "./contentParserManager";
2
+ export { ContentParser } from "./contentParser";
3
+ export { JsonParser } from "./jsonParser";
4
+ export { MultipartParser } from "./multipartParser";
5
+ export { TextParser } from "./textParser";
6
+ export { UrlEncodedParser } from "./urlEncodedParser";
7
+ export { XmlParser } from "./xmlParser";
8
+ export * from "./parserInterface";
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.XmlParser = exports.UrlEncodedParser = exports.TextParser = exports.MultipartParser = exports.JsonParser = exports.ContentParserManager = void 0;
18
+ var contentParserManager_1 = require("./contentParserManager");
19
+ Object.defineProperty(exports, "ContentParserManager", { enumerable: true, get: function () { return contentParserManager_1.ContentParserManager; } });
20
+ var jsonParser_1 = require("./jsonParser");
21
+ Object.defineProperty(exports, "JsonParser", { enumerable: true, get: function () { return jsonParser_1.JsonParser; } });
22
+ var multipartParser_1 = require("./multipartParser");
23
+ Object.defineProperty(exports, "MultipartParser", { enumerable: true, get: function () { return multipartParser_1.MultipartParser; } });
24
+ var textParser_1 = require("./textParser");
25
+ Object.defineProperty(exports, "TextParser", { enumerable: true, get: function () { return textParser_1.TextParser; } });
26
+ var urlEncodedParser_1 = require("./urlEncodedParser");
27
+ Object.defineProperty(exports, "UrlEncodedParser", { enumerable: true, get: function () { return urlEncodedParser_1.UrlEncodedParser; } });
28
+ var xmlParser_1 = require("./xmlParser");
29
+ Object.defineProperty(exports, "XmlParser", { enumerable: true, get: function () { return xmlParser_1.XmlParser; } });
30
+ __exportStar(require("./parserInterface"), exports);
@@ -0,0 +1,10 @@
1
+ import type { ContentParser } from "./contentParser";
2
+ /**
3
+ * JSON content parser.
4
+ *
5
+ * Handles `application/json` and `application/*+json` content types.
6
+ */
7
+ export declare class JsonParser implements ContentParser {
8
+ canParse(contentType: string): boolean;
9
+ parse(body: Buffer | string): unknown;
10
+ }
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.JsonParser = void 0;
4
+ const contentParserException_1 = require("../exceptions/contentParserException");
5
+ /**
6
+ * JSON content parser.
7
+ *
8
+ * Handles `application/json` and `application/*+json` content types.
9
+ */
10
+ class JsonParser {
11
+ canParse(contentType) {
12
+ return (contentType.includes("application/json") || contentType.includes("+json"));
13
+ }
14
+ parse(body) {
15
+ try {
16
+ const text = Buffer.isBuffer(body) ? body.toString("utf-8") : body;
17
+ return JSON.parse(text);
18
+ }
19
+ catch {
20
+ throw new contentParserException_1.ContentParserException("Invalid JSON content");
21
+ }
22
+ }
23
+ }
24
+ exports.JsonParser = JsonParser;
@@ -0,0 +1,35 @@
1
+ import type { ContentParser } from "./contentParser";
2
+ import type { MultipartData } from "./parserInterface";
3
+ /**
4
+ * `multipart/form-data` content parser.
5
+ *
6
+ * Parses multipart payloads into fields and files.
7
+ */
8
+ export declare class MultipartParser implements ContentParser {
9
+ /**
10
+ * Checks whether the given content type is `multipart/form-data`.
11
+ *
12
+ * @param contentType - Raw `Content-Type` header value
13
+ * @returns `true` if the content type is multipart
14
+ */
15
+ canParse(contentType: string): boolean;
16
+ /**
17
+ * Parses a `multipart/form-data` body into a typed structure.
18
+ *
19
+ * @param body - Raw request body
20
+ * @param contentType - Full `Content-Type` header value
21
+ * @returns Parsed multipart data (fields and files)
22
+ * @throws {ContentParserException} If the multipart boundary is missing
23
+ *
24
+ * @example
25
+ * // Typically called through ContentParserManager based on Content-Type:
26
+ * const parsed = parser.parse(body, "multipart/form-data; boundary=---123");
27
+ * // parsed.fields / parsed.files
28
+ */
29
+ parse(body: Buffer | string, contentType: string): MultipartData;
30
+ private extractBoundary;
31
+ private parseMultipart;
32
+ private splitBuffer;
33
+ private parsePart;
34
+ private parseHeaders;
35
+ }