@boo-labs/server 0.0.0-stage → 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/README.md +229 -2
- package/index.mjs +23 -0
- package/package.json +71 -4
- package/source/application/Kernel/index.mjs +1137 -0
- package/source/application/Server/index.mjs +1201 -0
- package/source/application/configurations/Http2CleartextServerConfiguration/index.mjs +168 -0
- package/source/application/configurations/Http2SecureServerConfiguration/index.mjs +172 -0
- package/source/application/configurations/HttpServerConfiguration/index.mjs +169 -0
- package/source/application/configurations/HttpsServerConfiguration/index.mjs +172 -0
- package/source/application/configurations/ServerConfiguration/Options/CORSOptions/CORSOptionsValue.mjs +158 -0
- package/source/application/configurations/ServerConfiguration/Options/CORSOptions/index.mjs +87 -0
- package/source/application/configurations/ServerConfiguration/Options/CSRFOptions/CSRFOptionsValue.mjs +178 -0
- package/source/application/configurations/ServerConfiguration/Options/CSRFOptions/index.mjs +80 -0
- package/source/application/configurations/ServerConfiguration/Options/CompressOptions/CompressOptionsValue.mjs +126 -0
- package/source/application/configurations/ServerConfiguration/Options/CompressOptions/index.mjs +81 -0
- package/source/application/configurations/ServerConfiguration/Options/CookieParserOptions/CookieParserOptionsValue.mjs +107 -0
- package/source/application/configurations/ServerConfiguration/Options/CookieParserOptions/index.mjs +82 -0
- package/source/application/configurations/ServerConfiguration/Options/CookieSessionOptions/CookieSessionOptionsValue.mjs +182 -0
- package/source/application/configurations/ServerConfiguration/Options/CookieSessionOptions/index.mjs +86 -0
- package/source/application/configurations/ServerConfiguration/Options/ListenOptions/ListenOptionsValue.mjs +95 -0
- package/source/application/configurations/ServerConfiguration/Options/ListenOptions/index.mjs +47 -0
- package/source/application/configurations/ServerConfiguration/Options/MiddlewareOption.mjs +102 -0
- package/source/application/configurations/ServerConfiguration/Options/Options.mjs +105 -0
- package/source/application/configurations/ServerConfiguration/Options/RateLimitOptions/RateLimitOptionsValue.mjs +164 -0
- package/source/application/configurations/ServerConfiguration/Options/RateLimitOptions/index.mjs +84 -0
- package/source/application/configurations/ServerConfiguration/Options/RequestOptions/RequestOptionsValue.mjs +108 -0
- package/source/application/configurations/ServerConfiguration/Options/RequestOptions/index.mjs +47 -0
- package/source/application/configurations/ServerConfiguration/Options/ResponseOptions/ResponseOptionsValue.mjs +101 -0
- package/source/application/configurations/ServerConfiguration/Options/ResponseOptions/index.mjs +47 -0
- package/source/application/configurations/ServerConfiguration/Options/SecurityHeadersOptions/SecurityHeadersOptionsValue.mjs +272 -0
- package/source/application/configurations/ServerConfiguration/Options/SecurityHeadersOptions/index.mjs +85 -0
- package/source/application/configurations/ServerConfiguration/Options/ServerOption.mjs +50 -0
- package/source/application/configurations/ServerConfiguration/Options/StaticOptions/StaticOptionsValue.mjs +164 -0
- package/source/application/configurations/ServerConfiguration/Options/StaticOptions/index.mjs +89 -0
- package/source/application/configurations/ServerConfiguration/index.mjs +781 -0
- package/source/application/resolvers/TransportResolver/index.mjs +119 -0
- package/source/application/use-cases/CloseServer/index.mjs +85 -0
- package/source/application/use-cases/ListenServer/index.mjs +98 -0
- package/source/core/EventSystem/index.mjs +110 -0
- package/source/core/Exchange/ExchangeContext.mjs +291 -0
- package/source/core/Exchange/Telemetry.mjs +193 -0
- package/source/core/Exchange/index.mjs +604 -0
- package/source/core/ExchangeLayerBuilder/index.mjs +133 -0
- package/source/core/IPCMain/IPCMain.mjs +507 -0
- package/source/core/IPCMain/IPCProtocol.mjs +441 -0
- package/source/core/IPCMain/IPCServerChannel.mjs +331 -0
- package/source/core/IPCMain/WebSocketAdapter.mjs +189 -0
- package/source/core/Request/BodyParser/BodyParser.mjs +197 -0
- package/source/core/Request/BodyParser/JSONParser.mjs +70 -0
- package/source/core/Request/BodyParser/MultipartParser.mjs +612 -0
- package/source/core/Request/BodyParser/URLEncodedParser.mjs +71 -0
- package/source/core/Request/RequestHeaders.mjs +177 -0
- package/source/core/Request/index.mjs +805 -0
- package/source/core/Response/ResponseHeaders.mjs +402 -0
- package/source/core/Response/index.mjs +1370 -0
- package/source/core/middlewares/CORSMiddleware/index.mjs +289 -0
- package/source/core/middlewares/CSRFMiddleware/index.mjs +284 -0
- package/source/core/middlewares/CompressMiddleware/index.mjs +460 -0
- package/source/core/middlewares/CookieParserMiddleware/index.mjs +194 -0
- package/source/core/middlewares/CookieSessionMiddleware/index.mjs +460 -0
- package/source/core/middlewares/RateLimitMiddleware/index.mjs +245 -0
- package/source/core/middlewares/SecurityHeadersMiddleware/index.mjs +151 -0
- package/source/core/middlewares/StaticMiddleware/index.mjs +628 -0
- package/source/core/routing/ExchangeLayer/ExchangeMatcher.mjs +127 -0
- package/source/core/routing/ExchangeLayer/index.mjs +254 -0
- package/source/core/routing/Pipeline/index.mjs +157 -0
- package/source/core/routing/Router/Route.mjs +184 -0
- package/source/core/routing/Router/index.mjs +523 -0
- package/source/core/routing/RouterRegister/OptionsMiddleware.mjs +147 -0
- package/source/core/routing/RouterRegister/index.mjs +150 -0
- package/source/core/routing/RouterSystem/index.mjs +225 -0
- package/source/core/value-objects/Address/index.mjs +281 -0
- package/source/core/value-objects/Endpoint/index.mjs +293 -0
- package/source/index.mjs +62 -0
- package/source/infrastructure/adapters/Http2Adapter/index.mjs +144 -0
- package/source/infrastructure/adapters/Http2CleartextAdapter/index.mjs +147 -0
- package/source/infrastructure/adapters/HttpAdapter/index.mjs +124 -0
- package/source/infrastructure/adapters/HttpsAdapter/index.mjs +124 -0
- package/source/infrastructure/adapters/TransportAdapter/createWebSocketOpenRequest.mjs +843 -0
- package/source/infrastructure/adapters/TransportAdapter/index.mjs +555 -0
- package/source/shared/Identifier/index.mjs +671 -0
- package/source/shared/constants/symbols/brands/index.mjs +45 -0
- package/source/shared/domain/UUIDV7/index.mjs +346 -0
- package/source/shared/errors/BaseError/index.mjs +157 -0
- package/source/shared/errors/IPCError/index.mjs +97 -0
- package/source/shared/errors/MiddlewareError/index.mjs +106 -0
- package/source/shared/errors/PathnamePatternError/index.mjs +103 -0
- package/source/shared/errors/RequestError/index.mjs +116 -0
- package/source/shared/errors/ResponseError/index.mjs +140 -0
- package/source/shared/errors/RouterError/index.mjs +90 -0
- package/source/shared/errors/ServerConfigurationError/index.mjs +551 -0
- package/source/shared/errors/ServerError/index.mjs +127 -0
- package/source/shared/errors/WebSocketError/index.mjs +58 -0
- package/source/shared/outcome/ErrorSchema.mjs +361 -0
- package/source/shared/outcome/Result/index.mjs +239 -0
- package/source/shared/outcome/Validation/index.mjs +208 -0
- package/source/shared/validations/Middleware/index.mjs +160 -0
- package/source/shared/validations/PathnamePattern/index.mjs +256 -0
- package/source/shared/validations/Server/NotFoundHandler/index.mjs +94 -0
- package/source/shared/validations/Server/Router/index.mjs +68 -0
- package/source/shared/validations/Server/ServerConfiguration/index.mjs +68 -0
- package/source/shared/validations/Server/SystemErrorHandler/index.mjs +94 -0
- package/source/shared/validations/ServerConfiguration/CORSOptions/index.mjs +310 -0
- package/source/shared/validations/ServerConfiguration/CSRFOptions/index.mjs +299 -0
- package/source/shared/validations/ServerConfiguration/CompressOptions/index.mjs +204 -0
- package/source/shared/validations/ServerConfiguration/CookieParserOptions/index.mjs +102 -0
- package/source/shared/validations/ServerConfiguration/CookieSessionOptions/index.mjs +332 -0
- package/source/shared/validations/ServerConfiguration/ListenOptions/index.mjs +178 -0
- package/source/shared/validations/ServerConfiguration/RateLimitOptions/index.mjs +229 -0
- package/source/shared/validations/ServerConfiguration/RequestOptions/index.mjs +132 -0
- package/source/shared/validations/ServerConfiguration/ResponseOptions/index.mjs +122 -0
- package/source/shared/validations/ServerConfiguration/SecurityHeadersOptions/index.mjs +137 -0
- package/source/shared/validations/ServerConfiguration/StaticOptions/index.mjs +248 -0
- package/types/index.d.ts +719 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
/**
|
|
3
|
+
* @file Defines the URL-encoded body parser.
|
|
4
|
+
*
|
|
5
|
+
* @description Provides the `URLEncodedParser` class for parsing
|
|
6
|
+
* `application/x-www-form-urlencoded` request bodies.
|
|
7
|
+
*
|
|
8
|
+
* @module URLEncodedParser
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// ━━ IMPORT MODULES ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
12
|
+
// » IMPORT LOCAL MODULES
|
|
13
|
+
import BodyParser from './BodyParser.mjs';
|
|
14
|
+
import RequestError from '#shared/errors/RequestError';
|
|
15
|
+
|
|
16
|
+
// ━━ TYPE DEFINITIONS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
17
|
+
/**
|
|
18
|
+
* Represents an incoming HTTP/1.1 or HTTPS/1.1 request message from Node.js.
|
|
19
|
+
*
|
|
20
|
+
* @typedef {import('node:http').IncomingMessage} HttpIncomingMessage
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Represents an incoming HTTP/2 request message from Node.js.
|
|
25
|
+
*
|
|
26
|
+
* @typedef {import('node:http2').Http2ServerRequest} Http2IncomingMessage
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Represents an incoming request message supported by the server.
|
|
31
|
+
*
|
|
32
|
+
* @typedef {HttpIncomingMessage|Http2IncomingMessage} IncomingRequest
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
// ━━ MODULE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
36
|
+
/**
|
|
37
|
+
* Parses `application/x-www-form-urlencoded` request bodies into
|
|
38
|
+
* `URLSearchParams`.
|
|
39
|
+
*
|
|
40
|
+
* @augments BodyParser
|
|
41
|
+
*/
|
|
42
|
+
class URLEncodedParser extends BodyParser {
|
|
43
|
+
/**
|
|
44
|
+
* Parses the incoming URL-encoded request body.
|
|
45
|
+
*
|
|
46
|
+
* @returns {Promise<URLSearchParams>} Parsed request body.
|
|
47
|
+
* @throws {RequestError} If the body cannot be parsed.
|
|
48
|
+
* @example
|
|
49
|
+
* ```js
|
|
50
|
+
* const body = await parser.parse();
|
|
51
|
+
*
|
|
52
|
+
* body.get('username'); // 'john'
|
|
53
|
+
* body.get('age'); // '30'
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
async parse() {
|
|
57
|
+
const buffer = await this.readBody();
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
return new URLSearchParams(buffer.toString('utf8'));
|
|
61
|
+
} catch (error) {
|
|
62
|
+
throw new RequestError('BODY_PARSE_FAILED', {
|
|
63
|
+
values: { reason: 'invalid URL-encoded body' },
|
|
64
|
+
cause: error instanceof Error ? error : new Error(String(error)),
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// ━━ EXPORT MODULE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
71
|
+
export default URLEncodedParser;
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
/**
|
|
3
|
+
* @file Defines the immutable request headers abstraction.
|
|
4
|
+
*
|
|
5
|
+
* @description `RequestHeaders` is an immutable, case-insensitive view of
|
|
6
|
+
* the headers received with an incoming HTTP message.
|
|
7
|
+
*
|
|
8
|
+
* HTTP/2 pseudo-headers (`:scheme`, `:authority`, `:method`, `:path`) are
|
|
9
|
+
* filtered out so that consumers see a uniform header map across HTTP/1.1
|
|
10
|
+
* and HTTP/2.
|
|
11
|
+
*
|
|
12
|
+
* Array values are copied on construction and on every read, so the internal
|
|
13
|
+
* snapshot cannot be mutated through the public API.
|
|
14
|
+
*
|
|
15
|
+
* No validation is performed: Node.js has already validated the incoming
|
|
16
|
+
* headers before they reach this abstraction.
|
|
17
|
+
*
|
|
18
|
+
* @module RequestHeaders
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
// ━━ TYPE DEFINITIONS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
22
|
+
/**
|
|
23
|
+
* Represents a single request header value.
|
|
24
|
+
*
|
|
25
|
+
* @typedef {string|string[]|undefined} RequestHeaderValue
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Represents an iterator over request header entries.
|
|
30
|
+
*
|
|
31
|
+
* @typedef {IterableIterator<[string, RequestHeaderValue]>} RequestHeadersIterator
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
// ━━ MODULE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
35
|
+
/**
|
|
36
|
+
* Immutable, case-insensitive view of incoming HTTP request headers.
|
|
37
|
+
*
|
|
38
|
+
* @classdesc Request headers are normalized to lowercase, pseudo-headers
|
|
39
|
+
* are removed, and array values are defensively copied. The internal
|
|
40
|
+
* snapshot is private and never exposed directly.
|
|
41
|
+
*/
|
|
42
|
+
class RequestHeaders {
|
|
43
|
+
/**
|
|
44
|
+
* Private snapshot of the normalized request headers.
|
|
45
|
+
*
|
|
46
|
+
* @type {Map<string, RequestHeaderValue>}
|
|
47
|
+
*/
|
|
48
|
+
#headers;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Creates a request headers instance from an incoming header map.
|
|
52
|
+
*
|
|
53
|
+
* @param {Record<string, string|string[]|undefined>} incomingHeaders - The incoming header map.
|
|
54
|
+
* @example
|
|
55
|
+
* ```js
|
|
56
|
+
* const headers = new RequestHeaders(incomingMessage.headers);
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
constructor(incomingHeaders) {
|
|
60
|
+
this.#headers = RequestHeaders.#buildSnapshot(incomingHeaders);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Returns the value of a request header.
|
|
65
|
+
*
|
|
66
|
+
* Header names are matched case-insensitively. Array values are copied
|
|
67
|
+
* so the caller cannot mutate the internal snapshot through the result.
|
|
68
|
+
*
|
|
69
|
+
* @param {string} name - The HTTP header name.
|
|
70
|
+
* @returns {RequestHeaderValue} The header value, or `undefined` when the header does not exist.
|
|
71
|
+
* @example
|
|
72
|
+
* ```js
|
|
73
|
+
* const contentType = headers.get('content-type');
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
get(name) {
|
|
77
|
+
const value = this.#headers.get(name.toLowerCase());
|
|
78
|
+
return Array.isArray(value) ? [...value] : value;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Checks whether a request header exists.
|
|
83
|
+
*
|
|
84
|
+
* @param {string} name - The HTTP header name.
|
|
85
|
+
* @returns {boolean} `true` when the header exists; otherwise, `false`.
|
|
86
|
+
* @example
|
|
87
|
+
* ```js
|
|
88
|
+
* if (headers.has('authorization')) { ... }
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
has(name) {
|
|
92
|
+
return this.#headers.has(name.toLowerCase());
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Returns the names of all request headers.
|
|
97
|
+
*
|
|
98
|
+
* The returned array serves as an index over the header collection and
|
|
99
|
+
* can be used to iterate headers by name when the value alone is not
|
|
100
|
+
* meaningful without its corresponding name.
|
|
101
|
+
*
|
|
102
|
+
* @returns {string[]} The normalized request header names.
|
|
103
|
+
* @example
|
|
104
|
+
* ```js
|
|
105
|
+
* const names = headers.getNames();
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
getNames() {
|
|
109
|
+
return [...this.#headers.keys()];
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Returns an iterator over the request headers as `[name, value]` pairs.
|
|
114
|
+
*
|
|
115
|
+
* Array values are copied so the caller cannot mutate the internal snapshot
|
|
116
|
+
* through the iterator.
|
|
117
|
+
*
|
|
118
|
+
* @yields {[string, RequestHeaderValue]} The request header entry.
|
|
119
|
+
* @returns {RequestHeadersIterator} The request header entries.
|
|
120
|
+
* @example
|
|
121
|
+
* ```js
|
|
122
|
+
* for (const [name, value] of headers.entries()) {
|
|
123
|
+
* console.log(name, value);
|
|
124
|
+
* }
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
*entries() {
|
|
128
|
+
for (const [name, value] of this.#headers) {
|
|
129
|
+
yield [name, Array.isArray(value) ? [...value] : value];
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Returns an iterator over the request headers as `[name, value]` pairs.
|
|
135
|
+
*
|
|
136
|
+
* Makes `RequestHeaders` directly iterable with `for...of`, spread, and
|
|
137
|
+
* `Object.fromEntries`.
|
|
138
|
+
*
|
|
139
|
+
* @returns {RequestHeadersIterator} The request header entries iterator.
|
|
140
|
+
* @example
|
|
141
|
+
* ```js
|
|
142
|
+
* for (const [name, value] of headers) {
|
|
143
|
+
* console.log(name, value);
|
|
144
|
+
* }
|
|
145
|
+
* ```
|
|
146
|
+
*/
|
|
147
|
+
[Symbol.iterator]() {
|
|
148
|
+
return this.entries();
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Builds the normalized header snapshot from the incoming header map.
|
|
153
|
+
*
|
|
154
|
+
* Pseudo-headers are filtered out, header names are normalized to
|
|
155
|
+
* lowercase, and array values are copied.
|
|
156
|
+
*
|
|
157
|
+
* @param {Record<string, string|string[]|undefined>} incomingHeaders - The incoming header map.
|
|
158
|
+
* @returns {Map<string, RequestHeaderValue>} The normalized header snapshot.
|
|
159
|
+
*/
|
|
160
|
+
static #buildSnapshot(incomingHeaders) {
|
|
161
|
+
/** @type {Map<string, RequestHeaderValue>} */
|
|
162
|
+
const snapshot = new Map();
|
|
163
|
+
|
|
164
|
+
for (const [name, value] of Object.entries(incomingHeaders)) {
|
|
165
|
+
if (name.startsWith(':')) {
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
snapshot.set(name.toLowerCase(), Array.isArray(value) ? [...value] : value);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return snapshot;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// ━━ EXPORT MODULE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
177
|
+
export default RequestHeaders;
|