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.
- package/LICENSE +21 -0
- package/README.md +237 -0
- package/dist/app.d.ts +123 -0
- package/dist/app.js +198 -0
- package/dist/container/container.d.ts +60 -0
- package/dist/container/container.js +71 -0
- package/dist/exceptions/baseException.d.ts +6 -0
- package/dist/exceptions/baseException.js +15 -0
- package/dist/exceptions/contentDispositionException.d.ts +4 -0
- package/dist/exceptions/contentDispositionException.js +11 -0
- package/dist/exceptions/contentParserException.d.ts +10 -0
- package/dist/exceptions/contentParserException.js +21 -0
- package/dist/exceptions/fileDownloadException.d.ts +4 -0
- package/dist/exceptions/fileDownloadException.js +11 -0
- package/dist/exceptions/fileExistsException.d.ts +4 -0
- package/dist/exceptions/fileExistsException.js +11 -0
- package/dist/exceptions/helperExceptions.d.ts +10 -0
- package/dist/exceptions/helperExceptions.js +25 -0
- package/dist/exceptions/httpNotFoundException.d.ts +7 -0
- package/dist/exceptions/httpNotFoundException.js +14 -0
- package/dist/exceptions/index.d.ts +9 -0
- package/dist/exceptions/index.js +25 -0
- package/dist/exceptions/invalidHttpStatusException.d.ts +4 -0
- package/dist/exceptions/invalidHttpStatusException.js +11 -0
- package/dist/exceptions/sessionException.d.ts +4 -0
- package/dist/exceptions/sessionException.js +11 -0
- package/dist/exceptions/validationException.d.ts +13 -0
- package/dist/exceptions/validationException.js +32 -0
- package/dist/helpers/app.d.ts +4 -0
- package/dist/helpers/app.js +12 -0
- package/dist/helpers/http.d.ts +59 -0
- package/dist/helpers/http.js +77 -0
- package/dist/helpers/index.d.ts +1 -0
- package/dist/helpers/index.js +9 -0
- package/dist/http/httpAdapter.d.ts +26 -0
- package/dist/http/httpAdapter.js +2 -0
- package/dist/http/httpMethods.d.ts +14 -0
- package/dist/http/httpMethods.js +18 -0
- package/dist/http/index.d.ts +6 -0
- package/dist/http/index.js +13 -0
- package/dist/http/logger.d.ts +8 -0
- package/dist/http/logger.js +36 -0
- package/dist/http/nodeNativeHttp.d.ts +41 -0
- package/dist/http/nodeNativeHttp.js +73 -0
- package/dist/http/request.d.ts +85 -0
- package/dist/http/request.js +127 -0
- package/dist/http/response.d.ts +118 -0
- package/dist/http/response.js +179 -0
- package/dist/http/statusCodes.d.ts +1 -0
- package/dist/http/statusCodes.js +38 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +10 -0
- package/dist/middlewares/cors.d.ts +103 -0
- package/dist/middlewares/cors.js +91 -0
- package/dist/middlewares/session.d.ts +26 -0
- package/dist/middlewares/session.js +88 -0
- package/dist/parsers/contentParser.d.ts +27 -0
- package/dist/parsers/contentParser.js +2 -0
- package/dist/parsers/contentParserManager.d.ts +50 -0
- package/dist/parsers/contentParserManager.js +91 -0
- package/dist/parsers/index.d.ts +8 -0
- package/dist/parsers/index.js +30 -0
- package/dist/parsers/jsonParser.d.ts +10 -0
- package/dist/parsers/jsonParser.js +24 -0
- package/dist/parsers/multipartParser.d.ts +35 -0
- package/dist/parsers/multipartParser.js +120 -0
- package/dist/parsers/parserInterface.d.ts +37 -0
- package/dist/parsers/parserInterface.js +2 -0
- package/dist/parsers/textParser.d.ts +11 -0
- package/dist/parsers/textParser.js +19 -0
- package/dist/parsers/urlEncodedParser.d.ts +10 -0
- package/dist/parsers/urlEncodedParser.js +19 -0
- package/dist/parsers/xmlParser.d.ts +47 -0
- package/dist/parsers/xmlParser.js +158 -0
- package/dist/routing/index.d.ts +3 -0
- package/dist/routing/index.js +9 -0
- package/dist/routing/layer.d.ts +85 -0
- package/dist/routing/layer.js +117 -0
- package/dist/routing/router.d.ts +143 -0
- package/dist/routing/router.js +210 -0
- package/dist/routing/routerGroup.d.ts +79 -0
- package/dist/routing/routerGroup.js +103 -0
- package/dist/server/nodeNativeServer.d.ts +29 -0
- package/dist/server/nodeNativeServer.js +42 -0
- package/dist/sessions/cookieOptions.d.ts +72 -0
- package/dist/sessions/cookieOptions.js +2 -0
- package/dist/sessions/index.d.ts +4 -0
- package/dist/sessions/index.js +7 -0
- package/dist/sessions/memorySessionStorage.d.ts +112 -0
- package/dist/sessions/memorySessionStorage.js +170 -0
- package/dist/sessions/session.d.ts +80 -0
- package/dist/sessions/session.js +101 -0
- package/dist/sessions/sessionStorage.d.ts +105 -0
- package/dist/sessions/sessionStorage.js +2 -0
- package/dist/static/contentDisposition.d.ts +71 -0
- package/dist/static/contentDisposition.js +159 -0
- package/dist/static/fileDownload.d.ts +44 -0
- package/dist/static/fileDownload.js +88 -0
- package/dist/static/fileStaticHandler.d.ts +61 -0
- package/dist/static/fileStaticHandler.js +110 -0
- package/dist/static/index.d.ts +4 -0
- package/dist/static/index.js +11 -0
- package/dist/static/mimeTypes.d.ts +1 -0
- package/dist/static/mimeTypes.js +40 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/types/index.d.ts +122 -0
- package/dist/types/index.js +2 -0
- package/dist/validators/index.d.ts +5 -0
- package/dist/validators/index.js +22 -0
- package/dist/validators/rules/booleanRule.d.ts +11 -0
- package/dist/validators/rules/booleanRule.js +22 -0
- package/dist/validators/rules/dateRule.d.ts +16 -0
- package/dist/validators/rules/dateRule.js +44 -0
- package/dist/validators/rules/emailRule.d.ts +12 -0
- package/dist/validators/rules/emailRule.js +24 -0
- package/dist/validators/rules/index.d.ts +6 -0
- package/dist/validators/rules/index.js +15 -0
- package/dist/validators/rules/numberRule.d.ts +17 -0
- package/dist/validators/rules/numberRule.js +30 -0
- package/dist/validators/rules/requiredRule.d.ts +11 -0
- package/dist/validators/rules/requiredRule.js +21 -0
- package/dist/validators/rules/stringRule.d.ts +18 -0
- package/dist/validators/rules/stringRule.js +32 -0
- package/dist/validators/types.d.ts +55 -0
- package/dist/validators/types.js +2 -0
- package/dist/validators/validationRule.d.ts +53 -0
- package/dist/validators/validationRule.js +37 -0
- package/dist/validators/validationSchema.d.ts +145 -0
- package/dist/validators/validationSchema.js +198 -0
- package/dist/validators/validator.d.ts +58 -0
- package/dist/validators/validator.js +91 -0
- package/dist/views/helpersTemplate.d.ts +104 -0
- package/dist/views/helpersTemplate.js +186 -0
- package/dist/views/index.d.ts +4 -0
- package/dist/views/index.js +9 -0
- package/dist/views/raptorEngine.d.ts +127 -0
- package/dist/views/raptorEngine.js +165 -0
- package/dist/views/templateEngine.d.ts +80 -0
- package/dist/views/templateEngine.js +204 -0
- package/dist/views/view.d.ts +55 -0
- package/dist/views/view.js +2 -0
- 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,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
|
+
}
|