@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.
Files changed (114) hide show
  1. package/README.md +229 -2
  2. package/index.mjs +23 -0
  3. package/package.json +71 -4
  4. package/source/application/Kernel/index.mjs +1137 -0
  5. package/source/application/Server/index.mjs +1201 -0
  6. package/source/application/configurations/Http2CleartextServerConfiguration/index.mjs +168 -0
  7. package/source/application/configurations/Http2SecureServerConfiguration/index.mjs +172 -0
  8. package/source/application/configurations/HttpServerConfiguration/index.mjs +169 -0
  9. package/source/application/configurations/HttpsServerConfiguration/index.mjs +172 -0
  10. package/source/application/configurations/ServerConfiguration/Options/CORSOptions/CORSOptionsValue.mjs +158 -0
  11. package/source/application/configurations/ServerConfiguration/Options/CORSOptions/index.mjs +87 -0
  12. package/source/application/configurations/ServerConfiguration/Options/CSRFOptions/CSRFOptionsValue.mjs +178 -0
  13. package/source/application/configurations/ServerConfiguration/Options/CSRFOptions/index.mjs +80 -0
  14. package/source/application/configurations/ServerConfiguration/Options/CompressOptions/CompressOptionsValue.mjs +126 -0
  15. package/source/application/configurations/ServerConfiguration/Options/CompressOptions/index.mjs +81 -0
  16. package/source/application/configurations/ServerConfiguration/Options/CookieParserOptions/CookieParserOptionsValue.mjs +107 -0
  17. package/source/application/configurations/ServerConfiguration/Options/CookieParserOptions/index.mjs +82 -0
  18. package/source/application/configurations/ServerConfiguration/Options/CookieSessionOptions/CookieSessionOptionsValue.mjs +182 -0
  19. package/source/application/configurations/ServerConfiguration/Options/CookieSessionOptions/index.mjs +86 -0
  20. package/source/application/configurations/ServerConfiguration/Options/ListenOptions/ListenOptionsValue.mjs +95 -0
  21. package/source/application/configurations/ServerConfiguration/Options/ListenOptions/index.mjs +47 -0
  22. package/source/application/configurations/ServerConfiguration/Options/MiddlewareOption.mjs +102 -0
  23. package/source/application/configurations/ServerConfiguration/Options/Options.mjs +105 -0
  24. package/source/application/configurations/ServerConfiguration/Options/RateLimitOptions/RateLimitOptionsValue.mjs +164 -0
  25. package/source/application/configurations/ServerConfiguration/Options/RateLimitOptions/index.mjs +84 -0
  26. package/source/application/configurations/ServerConfiguration/Options/RequestOptions/RequestOptionsValue.mjs +108 -0
  27. package/source/application/configurations/ServerConfiguration/Options/RequestOptions/index.mjs +47 -0
  28. package/source/application/configurations/ServerConfiguration/Options/ResponseOptions/ResponseOptionsValue.mjs +101 -0
  29. package/source/application/configurations/ServerConfiguration/Options/ResponseOptions/index.mjs +47 -0
  30. package/source/application/configurations/ServerConfiguration/Options/SecurityHeadersOptions/SecurityHeadersOptionsValue.mjs +272 -0
  31. package/source/application/configurations/ServerConfiguration/Options/SecurityHeadersOptions/index.mjs +85 -0
  32. package/source/application/configurations/ServerConfiguration/Options/ServerOption.mjs +50 -0
  33. package/source/application/configurations/ServerConfiguration/Options/StaticOptions/StaticOptionsValue.mjs +164 -0
  34. package/source/application/configurations/ServerConfiguration/Options/StaticOptions/index.mjs +89 -0
  35. package/source/application/configurations/ServerConfiguration/index.mjs +781 -0
  36. package/source/application/resolvers/TransportResolver/index.mjs +119 -0
  37. package/source/application/use-cases/CloseServer/index.mjs +85 -0
  38. package/source/application/use-cases/ListenServer/index.mjs +98 -0
  39. package/source/core/EventSystem/index.mjs +110 -0
  40. package/source/core/Exchange/ExchangeContext.mjs +291 -0
  41. package/source/core/Exchange/Telemetry.mjs +193 -0
  42. package/source/core/Exchange/index.mjs +604 -0
  43. package/source/core/ExchangeLayerBuilder/index.mjs +133 -0
  44. package/source/core/IPCMain/IPCMain.mjs +507 -0
  45. package/source/core/IPCMain/IPCProtocol.mjs +441 -0
  46. package/source/core/IPCMain/IPCServerChannel.mjs +331 -0
  47. package/source/core/IPCMain/WebSocketAdapter.mjs +189 -0
  48. package/source/core/Request/BodyParser/BodyParser.mjs +197 -0
  49. package/source/core/Request/BodyParser/JSONParser.mjs +70 -0
  50. package/source/core/Request/BodyParser/MultipartParser.mjs +612 -0
  51. package/source/core/Request/BodyParser/URLEncodedParser.mjs +71 -0
  52. package/source/core/Request/RequestHeaders.mjs +177 -0
  53. package/source/core/Request/index.mjs +805 -0
  54. package/source/core/Response/ResponseHeaders.mjs +402 -0
  55. package/source/core/Response/index.mjs +1370 -0
  56. package/source/core/middlewares/CORSMiddleware/index.mjs +289 -0
  57. package/source/core/middlewares/CSRFMiddleware/index.mjs +284 -0
  58. package/source/core/middlewares/CompressMiddleware/index.mjs +460 -0
  59. package/source/core/middlewares/CookieParserMiddleware/index.mjs +194 -0
  60. package/source/core/middlewares/CookieSessionMiddleware/index.mjs +460 -0
  61. package/source/core/middlewares/RateLimitMiddleware/index.mjs +245 -0
  62. package/source/core/middlewares/SecurityHeadersMiddleware/index.mjs +151 -0
  63. package/source/core/middlewares/StaticMiddleware/index.mjs +628 -0
  64. package/source/core/routing/ExchangeLayer/ExchangeMatcher.mjs +127 -0
  65. package/source/core/routing/ExchangeLayer/index.mjs +254 -0
  66. package/source/core/routing/Pipeline/index.mjs +157 -0
  67. package/source/core/routing/Router/Route.mjs +184 -0
  68. package/source/core/routing/Router/index.mjs +523 -0
  69. package/source/core/routing/RouterRegister/OptionsMiddleware.mjs +147 -0
  70. package/source/core/routing/RouterRegister/index.mjs +150 -0
  71. package/source/core/routing/RouterSystem/index.mjs +225 -0
  72. package/source/core/value-objects/Address/index.mjs +281 -0
  73. package/source/core/value-objects/Endpoint/index.mjs +293 -0
  74. package/source/index.mjs +62 -0
  75. package/source/infrastructure/adapters/Http2Adapter/index.mjs +144 -0
  76. package/source/infrastructure/adapters/Http2CleartextAdapter/index.mjs +147 -0
  77. package/source/infrastructure/adapters/HttpAdapter/index.mjs +124 -0
  78. package/source/infrastructure/adapters/HttpsAdapter/index.mjs +124 -0
  79. package/source/infrastructure/adapters/TransportAdapter/createWebSocketOpenRequest.mjs +843 -0
  80. package/source/infrastructure/adapters/TransportAdapter/index.mjs +555 -0
  81. package/source/shared/Identifier/index.mjs +671 -0
  82. package/source/shared/constants/symbols/brands/index.mjs +45 -0
  83. package/source/shared/domain/UUIDV7/index.mjs +346 -0
  84. package/source/shared/errors/BaseError/index.mjs +157 -0
  85. package/source/shared/errors/IPCError/index.mjs +97 -0
  86. package/source/shared/errors/MiddlewareError/index.mjs +106 -0
  87. package/source/shared/errors/PathnamePatternError/index.mjs +103 -0
  88. package/source/shared/errors/RequestError/index.mjs +116 -0
  89. package/source/shared/errors/ResponseError/index.mjs +140 -0
  90. package/source/shared/errors/RouterError/index.mjs +90 -0
  91. package/source/shared/errors/ServerConfigurationError/index.mjs +551 -0
  92. package/source/shared/errors/ServerError/index.mjs +127 -0
  93. package/source/shared/errors/WebSocketError/index.mjs +58 -0
  94. package/source/shared/outcome/ErrorSchema.mjs +361 -0
  95. package/source/shared/outcome/Result/index.mjs +239 -0
  96. package/source/shared/outcome/Validation/index.mjs +208 -0
  97. package/source/shared/validations/Middleware/index.mjs +160 -0
  98. package/source/shared/validations/PathnamePattern/index.mjs +256 -0
  99. package/source/shared/validations/Server/NotFoundHandler/index.mjs +94 -0
  100. package/source/shared/validations/Server/Router/index.mjs +68 -0
  101. package/source/shared/validations/Server/ServerConfiguration/index.mjs +68 -0
  102. package/source/shared/validations/Server/SystemErrorHandler/index.mjs +94 -0
  103. package/source/shared/validations/ServerConfiguration/CORSOptions/index.mjs +310 -0
  104. package/source/shared/validations/ServerConfiguration/CSRFOptions/index.mjs +299 -0
  105. package/source/shared/validations/ServerConfiguration/CompressOptions/index.mjs +204 -0
  106. package/source/shared/validations/ServerConfiguration/CookieParserOptions/index.mjs +102 -0
  107. package/source/shared/validations/ServerConfiguration/CookieSessionOptions/index.mjs +332 -0
  108. package/source/shared/validations/ServerConfiguration/ListenOptions/index.mjs +178 -0
  109. package/source/shared/validations/ServerConfiguration/RateLimitOptions/index.mjs +229 -0
  110. package/source/shared/validations/ServerConfiguration/RequestOptions/index.mjs +132 -0
  111. package/source/shared/validations/ServerConfiguration/ResponseOptions/index.mjs +122 -0
  112. package/source/shared/validations/ServerConfiguration/SecurityHeadersOptions/index.mjs +137 -0
  113. package/source/shared/validations/ServerConfiguration/StaticOptions/index.mjs +248 -0
  114. 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;