@boo-labs/server 0.0.0-stage → 1.0.1

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 (115) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +287 -2
  3. package/index.mjs +23 -0
  4. package/package.json +71 -4
  5. package/source/application/Kernel/index.mjs +1137 -0
  6. package/source/application/Server/index.mjs +1201 -0
  7. package/source/application/configurations/Http2CleartextServerConfiguration/index.mjs +168 -0
  8. package/source/application/configurations/Http2SecureServerConfiguration/index.mjs +172 -0
  9. package/source/application/configurations/HttpServerConfiguration/index.mjs +169 -0
  10. package/source/application/configurations/HttpsServerConfiguration/index.mjs +172 -0
  11. package/source/application/configurations/ServerConfiguration/Options/CORSOptions/CORSOptionsValue.mjs +158 -0
  12. package/source/application/configurations/ServerConfiguration/Options/CORSOptions/index.mjs +87 -0
  13. package/source/application/configurations/ServerConfiguration/Options/CSRFOptions/CSRFOptionsValue.mjs +178 -0
  14. package/source/application/configurations/ServerConfiguration/Options/CSRFOptions/index.mjs +80 -0
  15. package/source/application/configurations/ServerConfiguration/Options/CompressOptions/CompressOptionsValue.mjs +126 -0
  16. package/source/application/configurations/ServerConfiguration/Options/CompressOptions/index.mjs +81 -0
  17. package/source/application/configurations/ServerConfiguration/Options/CookieParserOptions/CookieParserOptionsValue.mjs +107 -0
  18. package/source/application/configurations/ServerConfiguration/Options/CookieParserOptions/index.mjs +82 -0
  19. package/source/application/configurations/ServerConfiguration/Options/CookieSessionOptions/CookieSessionOptionsValue.mjs +182 -0
  20. package/source/application/configurations/ServerConfiguration/Options/CookieSessionOptions/index.mjs +86 -0
  21. package/source/application/configurations/ServerConfiguration/Options/ListenOptions/ListenOptionsValue.mjs +95 -0
  22. package/source/application/configurations/ServerConfiguration/Options/ListenOptions/index.mjs +47 -0
  23. package/source/application/configurations/ServerConfiguration/Options/MiddlewareOption.mjs +102 -0
  24. package/source/application/configurations/ServerConfiguration/Options/Options.mjs +105 -0
  25. package/source/application/configurations/ServerConfiguration/Options/RateLimitOptions/RateLimitOptionsValue.mjs +164 -0
  26. package/source/application/configurations/ServerConfiguration/Options/RateLimitOptions/index.mjs +84 -0
  27. package/source/application/configurations/ServerConfiguration/Options/RequestOptions/RequestOptionsValue.mjs +108 -0
  28. package/source/application/configurations/ServerConfiguration/Options/RequestOptions/index.mjs +47 -0
  29. package/source/application/configurations/ServerConfiguration/Options/ResponseOptions/ResponseOptionsValue.mjs +101 -0
  30. package/source/application/configurations/ServerConfiguration/Options/ResponseOptions/index.mjs +47 -0
  31. package/source/application/configurations/ServerConfiguration/Options/SecurityHeadersOptions/SecurityHeadersOptionsValue.mjs +272 -0
  32. package/source/application/configurations/ServerConfiguration/Options/SecurityHeadersOptions/index.mjs +85 -0
  33. package/source/application/configurations/ServerConfiguration/Options/ServerOption.mjs +50 -0
  34. package/source/application/configurations/ServerConfiguration/Options/StaticOptions/StaticOptionsValue.mjs +164 -0
  35. package/source/application/configurations/ServerConfiguration/Options/StaticOptions/index.mjs +89 -0
  36. package/source/application/configurations/ServerConfiguration/index.mjs +781 -0
  37. package/source/application/resolvers/TransportResolver/index.mjs +119 -0
  38. package/source/application/use-cases/CloseServer/index.mjs +85 -0
  39. package/source/application/use-cases/ListenServer/index.mjs +98 -0
  40. package/source/core/EventSystem/index.mjs +110 -0
  41. package/source/core/Exchange/ExchangeContext.mjs +291 -0
  42. package/source/core/Exchange/Telemetry.mjs +193 -0
  43. package/source/core/Exchange/index.mjs +604 -0
  44. package/source/core/ExchangeLayerBuilder/index.mjs +133 -0
  45. package/source/core/IPCMain/IPCMain.mjs +507 -0
  46. package/source/core/IPCMain/IPCProtocol.mjs +441 -0
  47. package/source/core/IPCMain/IPCServerChannel.mjs +331 -0
  48. package/source/core/IPCMain/WebSocketAdapter.mjs +189 -0
  49. package/source/core/Request/BodyParser/BodyParser.mjs +197 -0
  50. package/source/core/Request/BodyParser/JSONParser.mjs +70 -0
  51. package/source/core/Request/BodyParser/MultipartParser.mjs +612 -0
  52. package/source/core/Request/BodyParser/URLEncodedParser.mjs +71 -0
  53. package/source/core/Request/RequestHeaders.mjs +177 -0
  54. package/source/core/Request/index.mjs +805 -0
  55. package/source/core/Response/ResponseHeaders.mjs +402 -0
  56. package/source/core/Response/index.mjs +1370 -0
  57. package/source/core/middlewares/CORSMiddleware/index.mjs +289 -0
  58. package/source/core/middlewares/CSRFMiddleware/index.mjs +284 -0
  59. package/source/core/middlewares/CompressMiddleware/index.mjs +460 -0
  60. package/source/core/middlewares/CookieParserMiddleware/index.mjs +194 -0
  61. package/source/core/middlewares/CookieSessionMiddleware/index.mjs +460 -0
  62. package/source/core/middlewares/RateLimitMiddleware/index.mjs +245 -0
  63. package/source/core/middlewares/SecurityHeadersMiddleware/index.mjs +151 -0
  64. package/source/core/middlewares/StaticMiddleware/index.mjs +628 -0
  65. package/source/core/routing/ExchangeLayer/ExchangeMatcher.mjs +127 -0
  66. package/source/core/routing/ExchangeLayer/index.mjs +254 -0
  67. package/source/core/routing/Pipeline/index.mjs +157 -0
  68. package/source/core/routing/Router/Route.mjs +184 -0
  69. package/source/core/routing/Router/index.mjs +523 -0
  70. package/source/core/routing/RouterRegister/OptionsMiddleware.mjs +147 -0
  71. package/source/core/routing/RouterRegister/index.mjs +150 -0
  72. package/source/core/routing/RouterSystem/index.mjs +225 -0
  73. package/source/core/value-objects/Address/index.mjs +281 -0
  74. package/source/core/value-objects/Endpoint/index.mjs +293 -0
  75. package/source/index.mjs +62 -0
  76. package/source/infrastructure/adapters/Http2Adapter/index.mjs +144 -0
  77. package/source/infrastructure/adapters/Http2CleartextAdapter/index.mjs +147 -0
  78. package/source/infrastructure/adapters/HttpAdapter/index.mjs +124 -0
  79. package/source/infrastructure/adapters/HttpsAdapter/index.mjs +124 -0
  80. package/source/infrastructure/adapters/TransportAdapter/createWebSocketOpenRequest.mjs +843 -0
  81. package/source/infrastructure/adapters/TransportAdapter/index.mjs +555 -0
  82. package/source/shared/Identifier/index.mjs +671 -0
  83. package/source/shared/constants/symbols/brands/index.mjs +45 -0
  84. package/source/shared/domain/UUIDV7/index.mjs +346 -0
  85. package/source/shared/errors/BaseError/index.mjs +157 -0
  86. package/source/shared/errors/IPCError/index.mjs +97 -0
  87. package/source/shared/errors/MiddlewareError/index.mjs +106 -0
  88. package/source/shared/errors/PathnamePatternError/index.mjs +103 -0
  89. package/source/shared/errors/RequestError/index.mjs +116 -0
  90. package/source/shared/errors/ResponseError/index.mjs +140 -0
  91. package/source/shared/errors/RouterError/index.mjs +90 -0
  92. package/source/shared/errors/ServerConfigurationError/index.mjs +551 -0
  93. package/source/shared/errors/ServerError/index.mjs +127 -0
  94. package/source/shared/errors/WebSocketError/index.mjs +58 -0
  95. package/source/shared/outcome/ErrorSchema.mjs +361 -0
  96. package/source/shared/outcome/Result/index.mjs +239 -0
  97. package/source/shared/outcome/Validation/index.mjs +208 -0
  98. package/source/shared/validations/Middleware/index.mjs +160 -0
  99. package/source/shared/validations/PathnamePattern/index.mjs +256 -0
  100. package/source/shared/validations/Server/NotFoundHandler/index.mjs +94 -0
  101. package/source/shared/validations/Server/Router/index.mjs +68 -0
  102. package/source/shared/validations/Server/ServerConfiguration/index.mjs +68 -0
  103. package/source/shared/validations/Server/SystemErrorHandler/index.mjs +94 -0
  104. package/source/shared/validations/ServerConfiguration/CORSOptions/index.mjs +310 -0
  105. package/source/shared/validations/ServerConfiguration/CSRFOptions/index.mjs +299 -0
  106. package/source/shared/validations/ServerConfiguration/CompressOptions/index.mjs +204 -0
  107. package/source/shared/validations/ServerConfiguration/CookieParserOptions/index.mjs +102 -0
  108. package/source/shared/validations/ServerConfiguration/CookieSessionOptions/index.mjs +332 -0
  109. package/source/shared/validations/ServerConfiguration/ListenOptions/index.mjs +178 -0
  110. package/source/shared/validations/ServerConfiguration/RateLimitOptions/index.mjs +229 -0
  111. package/source/shared/validations/ServerConfiguration/RequestOptions/index.mjs +132 -0
  112. package/source/shared/validations/ServerConfiguration/ResponseOptions/index.mjs +122 -0
  113. package/source/shared/validations/ServerConfiguration/SecurityHeadersOptions/index.mjs +137 -0
  114. package/source/shared/validations/ServerConfiguration/StaticOptions/index.mjs +248 -0
  115. package/types/index.d.ts +719 -0
@@ -0,0 +1,781 @@
1
+ // @ts-check
2
+ /**
3
+ * @file Defines the ServerConfiguration abstraction.
4
+ *
5
+ * @description Provides the base configuration for a server.
6
+ *
7
+ * ServerConfiguration defines the common configuration shared by server
8
+ * implementations and is extended by transport-specific configuration classes.
9
+ *
10
+ * @module ServerConfiguration
11
+ */
12
+
13
+ // ━━ IMPORT MODULES ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
14
+ // » IMPORT NATIVE NODEJS MODULES
15
+ import { inspect } from 'node:util';
16
+
17
+ // » IMPORT LOCAL MODULES
18
+ import { SERVER_CONFIGURATION_BRAND } from '#shared/constants/symbols/brands';
19
+ import ListenOptions from '#ServerOptions/ListenOptions';
20
+ import RequestOptions from '#ServerOptions/RequestOptions';
21
+ import ResponseOptions from '#ServerOptions/ResponseOptions';
22
+ import StaticOptions from '#ServerOptions/StaticOptions';
23
+ import CORSOptions from '#ServerOptions/CORSOptions';
24
+ import SecurityHeadersOptions from '#ServerOptions/SecurityHeadersOptions';
25
+ import RateLimitOptions from '#ServerOptions/RateLimitOptions';
26
+ import CookieParserOptions from '#ServerOptions/CookieParserOptions';
27
+ import CookieSessionOptions from '#ServerOptions/CookieSessionOptions';
28
+ import CSRFOptions from '#ServerOptions/CSRFOptions';
29
+ import CompressOptions from '#ServerOptions/CompressOptions';
30
+
31
+ // ━━ TYPE DEFINITIONS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
32
+ /**
33
+ * HTTP server connection options.
34
+ *
35
+ * @typedef {import('node:http').ServerOptions} HttpConnectionOptions
36
+ */
37
+
38
+ /**
39
+ * HTTPS server connection options.
40
+ *
41
+ * @typedef {import('node:https').ServerOptions} HttpsConnectionOptions
42
+ */
43
+
44
+ /**
45
+ * HTTP/2 cleartext server connection options.
46
+ *
47
+ * @typedef {import('node:http2').ServerOptions} Http2ConnectionOptions
48
+ */
49
+
50
+ /**
51
+ * HTTP/2 secure server connection options.
52
+ *
53
+ * @typedef {import('node:http2').SecureServerOptions} Http2SecureConnectionOptions
54
+ */
55
+
56
+ /**
57
+ * Identity for a plain HTTP server configuration.
58
+ *
59
+ * @typedef {object} HttpServerConfigurationIdentity
60
+ * @property {'http'} protocol - Application-level protocol.
61
+ * @property {'h1'} transport - Transport identifier for HTTP/1.1 cleartext.
62
+ * @property {HttpConnectionOptions} [connection] - HTTP server options forwarded to the adapter.
63
+ */
64
+
65
+ /**
66
+ * Identity for a secure HTTPS server configuration.
67
+ *
68
+ * @typedef {object} HttpsServerConfigurationIdentity
69
+ * @property {'https'} protocol - Application-level protocol.
70
+ * @property {'h1s'} transport - Transport identifier for HTTP/1.1 over TLS.
71
+ * @property {HttpsConnectionOptions} [connection] - HTTPS server options forwarded to the adapter.
72
+ */
73
+
74
+ /**
75
+ * Identity for a cleartext HTTP/2 server configuration.
76
+ *
77
+ * @typedef {object} Http2ServerConfigurationIdentity
78
+ * @property {'http'} protocol - Application-level protocol.
79
+ * @property {'h2c'} transport - Transport identifier for HTTP/2 cleartext.
80
+ * @property {Http2ConnectionOptions} [connection] - HTTP/2 cleartext server options forwarded to the adapter.
81
+ */
82
+
83
+ /**
84
+ * Identity for a secure HTTP/2 server configuration.
85
+ *
86
+ * @typedef {object} Http2SecureServerConfigurationIdentity
87
+ * @property {'https'} protocol - Application-level protocol.
88
+ * @property {'h2'} transport - Transport identifier for HTTP/2 over TLS.
89
+ * @property {Http2SecureConnectionOptions} [connection] - HTTP/2 secure server options forwarded to the adapter.
90
+ */
91
+
92
+ /**
93
+ * Represents a permitted server configuration identity.
94
+ *
95
+ * @typedef {HttpServerConfigurationIdentity | HttpsServerConfigurationIdentity | Http2ServerConfigurationIdentity | Http2SecureServerConfigurationIdentity } ServerConfigurationIdentity
96
+ */
97
+
98
+ /**
99
+ * Represents an HTTP method supported by the routing layer.
100
+ *
101
+ * @typedef {'GET'|'HEAD'|'POST'|'PUT'|'PATCH'|'DELETE'|'OPTIONS'|'QUERY'|'TRACE'} HTTPMethod
102
+ */
103
+
104
+ /**
105
+ * Represents the listen options accepted by the server configuration.
106
+ *
107
+ * @typedef {import('#ServerOptions/ListenOptions').ListenOptionsInput} ListenOptionsInput
108
+ */
109
+
110
+ /**
111
+ * Represents the request options accepted by the server configuration.
112
+ *
113
+ * @typedef {import('#ServerOptions/RequestOptions').RequestOptionsInput} RequestOptionsInput
114
+ */
115
+
116
+ /**
117
+ * Represents the response options accepted by the server configuration.
118
+ *
119
+ * @typedef {import('#ServerOptions/ResponseOptions').ResponseOptionsInput} ResponseOptionsInput
120
+ */
121
+
122
+ /**
123
+ * Represents the static options accepted by the server configuration.
124
+ *
125
+ * @typedef {import('#ServerOptions/StaticOptions').StaticOptionsInput} StaticOptionsInput
126
+ */
127
+
128
+ /**
129
+ * Represents the CORS options accepted by the server configuration.
130
+ *
131
+ * @typedef {import('#ServerOptions/CORSOptions').CORSOptionsInput} CORSOptionsInput
132
+ */
133
+
134
+ /**
135
+ * Represents the security headers options accepted by the server configuration.
136
+ *
137
+ * @typedef {import('#ServerOptions/SecurityHeadersOptions').SecurityHeadersOptionsInput} SecurityHeadersOptionsInput
138
+ */
139
+
140
+ /**
141
+ * Represents the rate limit options accepted by the server configuration.
142
+ *
143
+ * @typedef {import('#ServerOptions/RateLimitOptions').RateLimitOptionsInput} RateLimitOptionsInput
144
+ */
145
+
146
+ /**
147
+ * Represents the listen configuration.
148
+ *
149
+ * @typedef {import('#ServerOptions/ListenOptions').ListenOptionsData} ListenOptionsData
150
+ */
151
+
152
+ /**
153
+ * Represents the request configuration.
154
+ *
155
+ * @typedef {import('#ServerOptions/RequestOptions').RequestOptionsData} RequestOptionsData
156
+ */
157
+
158
+ /**
159
+ * Represents the response configuration.
160
+ *
161
+ * @typedef {import('#ServerOptions/ResponseOptions').ResponseOptionsData} ResponseOptionsData
162
+ */
163
+
164
+ /**
165
+ * Represents the static files configuration.
166
+ *
167
+ * @typedef {import('#ServerOptions/StaticOptions').StaticOptionsData} StaticOptionsData
168
+ */
169
+
170
+ /**
171
+ * Represents the CORS configuration.
172
+ *
173
+ * @typedef {import('#ServerOptions/CORSOptions').CORSOptionsData} CORSOptionsData
174
+ */
175
+
176
+ /**
177
+ * Represents the security headers configuration.
178
+ *
179
+ * @typedef {import('#ServerOptions/SecurityHeadersOptions').SecurityHeadersOptionsData} SecurityHeadersOptionsData
180
+ */
181
+
182
+ /**
183
+ * Represents the rate limit configuration.
184
+ *
185
+ * @typedef {import('#ServerOptions/RateLimitOptions').RateLimitOptionsData} RateLimitOptionsData
186
+ */
187
+
188
+ /**
189
+ * Represents the normalized cookie parser options.
190
+ *
191
+ * @typedef {import('#ServerOptions/CookieParserOptions').CookieParserOptionsData} CookieParserOptionsData
192
+ */
193
+
194
+ /**
195
+ * Represents the cookie parser options accepted by the server configuration.
196
+ *
197
+ * @typedef {import('#ServerOptions/CookieParserOptions').CookieParserOptionsInput} CookieParserOptionsInput
198
+ */
199
+ /**
200
+ * Represents the cookie session options accepted by the server configuration.
201
+ *
202
+ * @typedef {import('#ServerOptions/CookieSessionOptions').CookieSessionOptionsInput} CookieSessionOptionsInput
203
+ */
204
+
205
+ /**
206
+ * Represents the normalized cookie session options.
207
+ *
208
+ * @typedef {import('#ServerOptions/CookieSessionOptions').CookieSessionOptionsData} CookieSessionOptionsData
209
+ */
210
+
211
+ /**
212
+ * Represents the CSRF options accepted by the server configuration.
213
+ *
214
+ * @typedef {import('#ServerOptions/CSRFOptions').CSRFOptionsInput} CSRFOptionsInput
215
+ */
216
+
217
+ /**
218
+ * Represents the normalized CSRF options.
219
+ *
220
+ * @typedef {import('#ServerOptions/CSRFOptions').CSRFOptionsData} CSRFOptionsData
221
+ */
222
+
223
+ /**
224
+ * Represents the compression options accepted by the server configuration.
225
+ *
226
+ * @typedef {import('#ServerOptions/CompressOptions').CompressOptionsInput} CompressOptionsInput
227
+ */
228
+
229
+ /**
230
+ * Represents the normalized compression options.
231
+ *
232
+ * @typedef {import('#ServerOptions/CompressOptions').CompressOptionsData} CompressOptionsData
233
+ */
234
+
235
+ /**
236
+ * Represents the cookie middleware options accepted by the server configuration.
237
+ *
238
+ * @typedef {object} CookieOptionsInput
239
+ * @property {CookieParserOptionsInput} [parser] - Cookie parser configuration.
240
+ * @property {CookieSessionOptionsInput} [session] - Cookie session configuration.
241
+ */
242
+
243
+ /**
244
+ * Represents the normalized cookie options.
245
+ *
246
+ * `session` is only present when a cookie session is configured. Since a
247
+ * cookie session requires a cookie parser, `parser` is always present when
248
+ * `cookie` is defined.
249
+ *
250
+ * @typedef {object} CookieOptionsData
251
+ * @property {CookieParserOptionsData} parser - Normalized cookie parser options.
252
+ * @property {CookieSessionOptionsData} [session] - Normalized cookie session options.
253
+ */
254
+
255
+ /**
256
+ * Options common to every server configuration.
257
+ *
258
+ * @typedef {object} ServerConfigurationOptionsInputBase
259
+ * @property {ListenOptionsInput} [listen] - Server listening configuration.
260
+ * @property {RequestOptionsInput} [request] - Request configuration.
261
+ * @property {ResponseOptionsInput} [response] - Response configuration.
262
+ * @property {StaticOptionsInput} [static] - Static files middleware configuration.
263
+ * @property {CORSOptionsInput} [cors] - CORS middleware configuration.
264
+ * @property {SecurityHeadersOptionsInput} [securityHeaders] - Security headers middleware configuration.
265
+ * @property {RateLimitOptionsInput} [rateLimit] - Rate limit middleware configuration.
266
+ * @property {CookieOptionsInput} [cookie] - Cookie middleware configuration.
267
+ * @property {CSRFOptionsInput} [csrf] - CSRF middleware configuration.
268
+ * @property {CompressOptionsInput} [compress] - Compression middleware configuration.
269
+ */
270
+
271
+ /**
272
+ * Represents the server-specific options consumed by the kernel.
273
+ *
274
+ * @template {ServerConfigurationIdentity} TIdentity
275
+ * @typedef {object} ServerOptions
276
+ * @property {TIdentity['transport']} transport - Transport identifier.
277
+ * @property {TIdentity['protocol']} protocol - Application-level protocol.
278
+ * @property {ListenOptionsData|undefined} listen - Listen configuration.
279
+ * @property {RequestOptionsData|undefined} request - Request configuration.
280
+ * @property {ResponseOptionsData|undefined} response - Response configuration.
281
+ * @property {TIdentity['connection']} connection - Connection options forwarded to the adapter.
282
+ */
283
+
284
+ /**
285
+ * Represents one middleware configuration consumed by the exchange layer builder.
286
+ *
287
+ * @typedef {object} MiddlewareConfiguration
288
+ * @property {string} name - Middleware name.
289
+ * @property {unknown} options - Middleware configuration options.
290
+ * @property {string|undefined} pathnamePattern - URL pathname pattern to match.
291
+ * @property {HTTPMethod|undefined} method - HTTP method to match.
292
+ */
293
+
294
+ /**
295
+ * Represents the composed server configuration.
296
+ *
297
+ * @template {ServerConfigurationIdentity} TIdentity
298
+ * @typedef {object} ComposedConfiguration
299
+ * @property {ServerOptions<TIdentity>} serverOptions - Server options forwarded to the kernel.
300
+ * @property {MiddlewareConfiguration[]} middlewareOptions - Middleware configurations forwarded to the exchange layer builder.
301
+ */
302
+
303
+ /**
304
+ * Represents the private state associated with a ServerConfiguration instance.
305
+ *
306
+ * @template {ServerConfigurationIdentity} TIdentity
307
+ * @typedef {object} ServerConfigurationData
308
+ * @property {() => ComposedConfiguration<TIdentity>} compose - Composes the configuration into server and middleware options.
309
+ */
310
+
311
+ /**
312
+ * Represents the plain object projection of a ServerConfiguration instance.
313
+ *
314
+ * Every property is optional because only configured options are included.
315
+ *
316
+ * @typedef {object} ServerConfigurationObject
317
+ * @property {unknown} [connection] - Connection options forwarded to the adapter.
318
+ * @property {ListenOptionsData} [listen] - Normalized listen options.
319
+ * @property {RequestOptionsData} [request] - Normalized request options.
320
+ * @property {ResponseOptionsData} [response] - Normalized response options.
321
+ * @property {StaticOptionsData} [static] - Normalized static options.
322
+ * @property {CORSOptionsData} [cors] - Normalized CORS options.
323
+ * @property {SecurityHeadersOptionsData} [securityHeaders] - Normalized security headers options.
324
+ * @property {RateLimitOptionsData} [rateLimit] - Normalized rate limit options.
325
+ * @property {CookieOptionsData} [cookie] - Normalized cookie options.
326
+ * @property {CSRFOptionsData} [csrf] - Normalized CSRF configuration.
327
+ * @property {CompressOptionsData} [compress] - Normalized compression configuration.
328
+ */
329
+ // ━━ CONSTANTS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
330
+ /**
331
+ * Stores private ServerConfiguration data for each {@link ServerConfiguration} instance.
332
+ *
333
+ * @private
334
+ * @type {WeakMap<ServerConfiguration<any>, ServerConfigurationData<any>>}
335
+ */
336
+ const SERVER_CONFIGURATION_PRIVATE = new WeakMap();
337
+
338
+ // ━━ FUNCTIONS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
339
+ /**
340
+ * Returns the private state associated with a {@link ServerConfiguration} instance.
341
+ *
342
+ * @private
343
+ * @template {ServerConfigurationIdentity} TIdentity
344
+ * @param {ServerConfiguration<TIdentity>} instance - ServerConfiguration instance whose private state is requested.
345
+ * @returns {ServerConfigurationData<TIdentity>} The private state associated with the instance.
346
+ * @throws {TypeError} If the instance has no associated private state.
347
+ */
348
+ function getServerConfigurationData(instance) {
349
+ const data = SERVER_CONFIGURATION_PRIVATE.get(instance);
350
+
351
+ if (!data) {
352
+ throw new TypeError('Invalid ServerConfiguration instance.');
353
+ }
354
+
355
+ return data;
356
+ }
357
+
358
+ /**
359
+ * Composes a server configuration into its server-specific and middleware
360
+ * options.
361
+ *
362
+ * @private
363
+ * @template {ServerConfigurationIdentity} TIdentity
364
+ * @param {ServerConfiguration<TIdentity>} configuration - Server configuration to compose.
365
+ * @returns {ComposedConfiguration<TIdentity>} Composed server and middleware options.
366
+ * @throws {TypeError} If the value is not a ServerConfiguration instance.
367
+ */
368
+ function composeConfiguration(configuration) {
369
+ if (!(configuration instanceof ServerConfiguration)) {
370
+ throw new TypeError('Expected a ServerConfiguration instance.');
371
+ }
372
+
373
+ const data = getServerConfigurationData(configuration);
374
+
375
+ return data.compose();
376
+ }
377
+
378
+ // ━━ MODULE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
379
+ /**
380
+ * Defines the common server configuration.
381
+ *
382
+ * @template {ServerConfigurationIdentity} TIdentity
383
+ *
384
+ * @classdesc ServerConfiguration is the base class for server configuration
385
+ * types. It cannot be instantiated directly and is extended by concrete server
386
+ * configuration classes.
387
+ */
388
+ class ServerConfiguration {
389
+ /**
390
+ * Transport identifier used by this ServerConfiguration.
391
+ *
392
+ * @type {TIdentity['transport']}
393
+ */
394
+ #transport;
395
+
396
+ /**
397
+ * Protocol identifier used by this ServerConfiguration.
398
+ *
399
+ * @type {TIdentity['protocol']}
400
+ */
401
+ #protocol;
402
+
403
+ /**
404
+ * Connection options used by this ServerConfiguration.
405
+ *
406
+ * @type {TIdentity['connection']}
407
+ */
408
+ #connection;
409
+
410
+ /**
411
+ * Listen options used by this ServerConfiguration.
412
+ *
413
+ * @type {ListenOptions}
414
+ */
415
+ #listen;
416
+
417
+ /**
418
+ * Request options used by this ServerConfiguration.
419
+ *
420
+ * @type {RequestOptions}
421
+ */
422
+ #request;
423
+
424
+ /**
425
+ * Response options used by this ServerConfiguration.
426
+ *
427
+ * @type {ResponseOptions}
428
+ */
429
+ #response;
430
+
431
+ /**
432
+ * Static files middleware configuration.
433
+ *
434
+ * @type {StaticOptions}
435
+ */
436
+ #static;
437
+
438
+ /**
439
+ * CORS middleware configuration.
440
+ *
441
+ * @type {CORSOptions}
442
+ */
443
+ #cors;
444
+
445
+ /**
446
+ * Security headers middleware configuration.
447
+ *
448
+ * @type {SecurityHeadersOptions}
449
+ */
450
+ #securityHeaders;
451
+
452
+ /**
453
+ * Rate limit middleware configuration.
454
+ *
455
+ * @type {RateLimitOptions}
456
+ */
457
+ #rateLimit;
458
+
459
+ /**
460
+ * Cookie parser middleware configuration.
461
+ *
462
+ * @type {CookieParserOptions}
463
+ */
464
+ #cookieParser;
465
+
466
+ /**
467
+ * Cookie session middleware configuration.
468
+ *
469
+ * @type {CookieSessionOptions}
470
+ */
471
+ #cookieSession;
472
+
473
+ /**
474
+ * CSRF middleware configuration.
475
+ *
476
+ * @type {CSRFOptions}
477
+ */
478
+ #csrf;
479
+
480
+ /**
481
+ * Compression middleware configuration.
482
+ *
483
+ * @type {CompressOptions}
484
+ */
485
+ #compress;
486
+
487
+ /**
488
+ * Creates a server configuration.
489
+ *
490
+ * @abstract
491
+ * @param {ServerConfigurationOptionsInputBase & TIdentity} options - Server configuration options.
492
+ * @throws {TypeError} When ServerConfiguration is instantiated directly.
493
+ */
494
+ constructor(options) {
495
+ if (new.target === ServerConfiguration) {
496
+ throw new TypeError('ServerConfiguration is an abstract class and cannot be instantiated');
497
+ }
498
+
499
+ // Identity & connection
500
+ this.#transport = options.transport;
501
+ this.#protocol = options.protocol;
502
+ this.#connection = options.connection;
503
+
504
+ // Server options
505
+ this.#listen = new ListenOptions(options.listen);
506
+ this.#request = new RequestOptions(options.request);
507
+ this.#response = new ResponseOptions(options.response);
508
+
509
+ // Middleware options
510
+ this.#static = new StaticOptions(options.static);
511
+ this.#cors = new CORSOptions(options.cors);
512
+ this.#securityHeaders = new SecurityHeadersOptions(options.securityHeaders);
513
+ this.#rateLimit = new RateLimitOptions(options.rateLimit);
514
+ this.#cookieParser = new CookieParserOptions(options.cookie?.parser);
515
+ this.#cookieSession = new CookieSessionOptions(
516
+ options.cookie?.session,
517
+ options.cookie?.parser !== undefined,
518
+ );
519
+ this.#csrf = new CSRFOptions(options.csrf);
520
+ this.#compress = new CompressOptions(options.compress);
521
+
522
+ SERVER_CONFIGURATION_PRIVATE.set(this, {
523
+ compose: () => this.#compose(),
524
+ });
525
+ }
526
+
527
+ /**
528
+ * The transport identifier.
529
+ *
530
+ * @readonly
531
+ * @type {TIdentity['transport']}
532
+ */
533
+ get transport() {
534
+ return this.#transport;
535
+ }
536
+
537
+ /**
538
+ * The application-level protocol.
539
+ *
540
+ * @readonly
541
+ * @type {TIdentity['protocol']}
542
+ */
543
+ get protocol() {
544
+ return this.#protocol;
545
+ }
546
+
547
+ /**
548
+ * The connection configuration.
549
+ *
550
+ * @readonly
551
+ * @type {TIdentity['connection']}
552
+ */
553
+ get connection() {
554
+ return this.#connection;
555
+ }
556
+
557
+ /**
558
+ * The request configuration.
559
+ *
560
+ * @readonly
561
+ * @type {RequestOptionsData|undefined}
562
+ */
563
+ get request() {
564
+ return this.#request.value;
565
+ }
566
+
567
+ /**
568
+ * The response configuration.
569
+ *
570
+ * @readonly
571
+ * @type {ResponseOptionsData|undefined}
572
+ */
573
+ get response() {
574
+ return this.#response.value;
575
+ }
576
+
577
+ /**
578
+ * The server listening configuration.
579
+ *
580
+ * @readonly
581
+ * @type {ListenOptionsData|undefined}
582
+ */
583
+ get listen() {
584
+ return this.#listen.value;
585
+ }
586
+
587
+ /**
588
+ * The static files configuration.
589
+ *
590
+ * @readonly
591
+ * @type {StaticOptionsData|undefined}
592
+ */
593
+ get static() {
594
+ return this.#static.value;
595
+ }
596
+
597
+ /**
598
+ * The CORS configuration.
599
+ *
600
+ * @readonly
601
+ * @type {CORSOptionsData|undefined}
602
+ */
603
+ get cors() {
604
+ return this.#cors.value;
605
+ }
606
+
607
+ /**
608
+ * The security headers configuration.
609
+ *
610
+ * @readonly
611
+ * @type {SecurityHeadersOptionsData|undefined}
612
+ */
613
+ get securityHeaders() {
614
+ return this.#securityHeaders.value;
615
+ }
616
+
617
+ /**
618
+ * The rate limit configuration.
619
+ *
620
+ * @readonly
621
+ * @type {RateLimitOptionsData|undefined}
622
+ */
623
+ get rateLimit() {
624
+ return this.#rateLimit.value;
625
+ }
626
+
627
+ /**
628
+ * The cookie middleware configuration.
629
+ *
630
+ * @readonly
631
+ * @type {CookieOptionsData|undefined}
632
+ */
633
+ get cookie() {
634
+ const parser = this.#cookieParser.value;
635
+ const session = this.#cookieSession.value;
636
+
637
+ if (parser === undefined) {
638
+ return undefined;
639
+ }
640
+
641
+ if (session === undefined) {
642
+ return { parser };
643
+ }
644
+
645
+ return {
646
+ parser,
647
+ session,
648
+ };
649
+ }
650
+
651
+ /**
652
+ * The CSRF configuration.
653
+ *
654
+ * @readonly
655
+ * @type {CSRFOptionsData|undefined}
656
+ */
657
+ get csrf() {
658
+ return this.#csrf.value;
659
+ }
660
+
661
+ /**
662
+ * The compression configuration.
663
+ *
664
+ * @readonly
665
+ * @type {CompressOptionsData|undefined}
666
+ */
667
+ get compress() {
668
+ return this.#compress.value;
669
+ }
670
+
671
+ /**
672
+ * Custom string tag for better type identification.
673
+ *
674
+ * @readonly
675
+ * @type {string}
676
+ */
677
+ get [Symbol.toStringTag]() {
678
+ return this.constructor.name;
679
+ }
680
+
681
+ /**
682
+ * Indicates whether this object implements the server configuration contract.
683
+ *
684
+ * @readonly
685
+ * @type {boolean}
686
+ */
687
+ get [SERVER_CONFIGURATION_BRAND]() {
688
+ return true;
689
+ }
690
+
691
+ /**
692
+ * Returns a plain object representation of the server configuration.
693
+ *
694
+ * @returns {ServerConfigurationObject} A plain object representation of the configuration.
695
+ *
696
+ * @example
697
+ * ```js
698
+ * const configuration = new HttpServerConfiguration({
699
+ * listen: { port: 3000 },
700
+ * cors: { origin: '*' },
701
+ * });
702
+ *
703
+ * configuration.toObject();
704
+ * // => { listen: { port: 3000 }, cors: { origin: '*' } }
705
+ * ```
706
+ */
707
+ toObject() {
708
+ return this.#createObject();
709
+ }
710
+
711
+ /**
712
+ * Custom inspect implementation for Node.js `util.inspect()`.
713
+ *
714
+ * @returns {string} Custom string representation for debugging.
715
+ */
716
+ [inspect.custom]() {
717
+ return `${this.constructor.name} ${inspect(this.toObject(), { colors: true })}`;
718
+ }
719
+
720
+ /**
721
+ * Builds the plain object representation shared by public projections.
722
+ *
723
+ * @returns {Record<string, unknown>} A plain object representation of the configuration.
724
+ */
725
+ #createObject() {
726
+ return {
727
+ ...(this.connection !== undefined && { connection: this.connection }),
728
+ ...(this.listen !== undefined && { listen: this.listen }),
729
+ ...(this.request !== undefined && { request: this.request }),
730
+ ...(this.response !== undefined && { response: this.response }),
731
+ ...(this.static !== undefined && { static: this.static }),
732
+ ...(this.cors !== undefined && { cors: this.cors }),
733
+ ...(this.securityHeaders !== undefined && {
734
+ securityHeaders: this.securityHeaders,
735
+ }),
736
+ ...(this.rateLimit !== undefined && { rateLimit: this.rateLimit }),
737
+ ...(this.cookie !== undefined && { cookie: this.cookie }),
738
+ ...(this.csrf !== undefined && { csrf: this.csrf }),
739
+ ...(this.compress !== undefined && { compress: this.compress }),
740
+ };
741
+ }
742
+
743
+ /**
744
+ * Composes the configuration into server-specific and middleware options.
745
+ *
746
+ * @returns {ComposedConfiguration<TIdentity>} Composed server and middleware options.
747
+ */
748
+ #compose() {
749
+ /** @type {ServerOptions<TIdentity>} */
750
+ const serverOptions = {
751
+ transport: this.#transport,
752
+ protocol: this.#protocol,
753
+ listen: this.listen,
754
+ request: this.request,
755
+ response: this.response,
756
+ connection: this.connection,
757
+ };
758
+
759
+ const middlewareOptions = [
760
+ this.#cookieParser,
761
+ this.#cookieSession,
762
+ this.#csrf,
763
+ this.#static,
764
+ this.#cors,
765
+ this.#securityHeaders,
766
+ this.#rateLimit,
767
+ this.#compress,
768
+ ]
769
+ .filter(option => option.value !== undefined)
770
+ .map(option => option.compose());
771
+
772
+ return {
773
+ serverOptions,
774
+ middlewareOptions,
775
+ };
776
+ }
777
+ }
778
+
779
+ // ━━ EXPORT MODULE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
780
+ export default ServerConfiguration;
781
+ export { composeConfiguration };