@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,147 @@
1
+ // @ts-check
2
+ /**
3
+ * @file Defines the middleware for handling automatic OPTIONS requests.
4
+ *
5
+ * @description Provides automatic OPTIONS responses for routes by exposing the
6
+ * HTTP methods registered for each pathname pattern.
7
+ *
8
+ * @module OptionsMiddleware
9
+ */
10
+
11
+ // ━━ TYPE DEFINITIONS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
12
+ /**
13
+ * Represents a single HTTP transaction.
14
+ *
15
+ * @typedef {import('#Exchange').default} Exchange
16
+ */
17
+
18
+ /**
19
+ * Represents an HTTP method supported by the routing layer.
20
+ *
21
+ * @typedef {import('#routing/ExchangeLayer').HTTPMethod} HTTPMethod
22
+ */
23
+
24
+ // ━━ MODULE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
25
+ /**
26
+ * Handles automatic OPTIONS responses for a route.
27
+ *
28
+ * @classdesc `OptionsMiddleware` generates an OPTIONS response containing the
29
+ * HTTP methods registered for a pathname pattern.
30
+ */
31
+ class OptionsMiddleware {
32
+ /**
33
+ * The HTTP methods registered for the route.
34
+ *
35
+ * `undefined` represents all methods during registration and is removed when
36
+ * the methods are resolved.
37
+ *
38
+ * @type {Set<HTTPMethod|undefined>}
39
+ */
40
+ #methods = new Set();
41
+
42
+ /**
43
+ * The cached resolved HTTP methods string.
44
+ *
45
+ * @type {string|null}
46
+ */
47
+ #methodsCache = null;
48
+
49
+ /**
50
+ * Creates an instance of OptionsMiddleware.
51
+ *
52
+ * @example
53
+ * ```js
54
+ * const middleware = new OptionsMiddleware();
55
+ * ```
56
+ */
57
+ constructor() {
58
+ this.handle = this.handle.bind(this);
59
+ }
60
+
61
+ /**
62
+ * The resolved HTTP methods string.
63
+ *
64
+ * @type {string}
65
+ */
66
+ get methods() {
67
+ if (this.#methodsCache !== null) {
68
+ return this.#methodsCache;
69
+ }
70
+
71
+ const methods = new Set(this.#methods);
72
+ methods.delete(undefined);
73
+
74
+ if (methods.size === 0) {
75
+ this.#methodsCache = OptionsMiddleware.#METHODS.join(', ');
76
+ } else {
77
+ methods.add('OPTIONS');
78
+ this.#methodsCache = [...methods].join(', ');
79
+ }
80
+
81
+ return this.#methodsCache;
82
+ }
83
+
84
+ /**
85
+ * Adds an HTTP method to the allowed methods.
86
+ *
87
+ * `undefined` represents all methods during registration.
88
+ *
89
+ * @param {HTTPMethod|undefined} method - The HTTP method to allow.
90
+ * @example
91
+ * ```js
92
+ * middleware.add('GET');
93
+ * middleware.add('POST');
94
+ * ```
95
+ */
96
+ add(method) {
97
+ this.#methods.add(method);
98
+ this.#methodsCache = null;
99
+ }
100
+
101
+ /**
102
+ * Handles an OPTIONS request and terminates the exchange.
103
+ *
104
+ * @param {Exchange} exchange - The current exchange.
105
+ * @param {Function} _next - The unused continuation function.
106
+ * @example
107
+ * ```js
108
+ * const middleware = new OptionsMiddleware();
109
+ * middleware.add('GET');
110
+ * middleware.add('POST');
111
+ * middleware.handle(exchange, next);
112
+ *
113
+ * // Response:
114
+ * // 204 No Content
115
+ * // Allow: GET, POST
116
+ * // Access-Control-Allow-Methods: GET, POST
117
+ * ```
118
+ */
119
+ handle(exchange, _next) {
120
+ exchange.response
121
+ .status(204)
122
+ .setHeader('Allow', this.methods)
123
+ .setHeader('Access-Control-Allow-Methods', this.methods)
124
+ .setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization')
125
+ .end();
126
+ }
127
+
128
+ /**
129
+ * The HTTP methods supported by the server.
130
+ *
131
+ * @type {Readonly<Array<HTTPMethod>>}
132
+ */
133
+ static #METHODS = Object.freeze([
134
+ 'GET',
135
+ 'HEAD',
136
+ 'POST',
137
+ 'PUT',
138
+ 'PATCH',
139
+ 'DELETE',
140
+ 'OPTIONS',
141
+ 'QUERY',
142
+ 'TRACE',
143
+ ]);
144
+ }
145
+
146
+ // ━━ EXPORT MODULE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
147
+ export default OptionsMiddleware;
@@ -0,0 +1,150 @@
1
+ // @ts-check
2
+ /**
3
+ * @file Defines the route register.
4
+ *
5
+ * @description Maintains route registrations and builds automatic OPTIONS
6
+ * middleware for each pathname pattern.
7
+ *
8
+ * @module RouteRegister
9
+ */
10
+
11
+ // ━━ IMPORT MODULES ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
12
+ // » IMPORT LOCAL MODULES
13
+ import OptionsMiddleware from './OptionsMiddleware.mjs';
14
+
15
+ // ━━ TYPE DEFINITIONS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
16
+ /**
17
+ * Represents a single HTTP transaction.
18
+ *
19
+ * @typedef {import('#Exchange').default} Exchange
20
+ */
21
+
22
+ /**
23
+ * Represents an HTTP method supported by the routing layer.
24
+ *
25
+ * @typedef {import('#routing/ExchangeLayer').HTTPMethod} HTTPMethod
26
+ */
27
+
28
+ /**
29
+ * Represents an exchange middleware function.
30
+ *
31
+ * @typedef {import('#routing/ExchangeLayer').MiddlewareFunction} MiddlewareFunction
32
+ */
33
+
34
+ /**
35
+ * Route registration containing an optional HTTP method and pathname pattern.
36
+ *
37
+ * @typedef {[HTTPMethod|undefined, string|undefined]} RouteRegistration
38
+ */
39
+
40
+ /**
41
+ * Collection of route registrations.
42
+ *
43
+ * @typedef {RouteRegistration[]} RouteRegistrations
44
+ */
45
+
46
+ /**
47
+ * Represents the options used to create an exchange layer.
48
+ *
49
+ * @typedef {object} ExchangeLayerOptions
50
+ * @property {'OPTIONS'} method - HTTP method to match for the automatic OPTIONS layer.
51
+ * @property {string} pathnamePattern - URL pathname pattern to match.
52
+ * @property {MiddlewareFunction} middleware - Middleware executed when the exchange matches the layer criteria.
53
+ */
54
+
55
+ // ━━ MODULE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
56
+ /**
57
+ * Maintains registered routes and their automatic OPTIONS middleware.
58
+ *
59
+ * @classdesc `RouteRegister` groups registered HTTP methods by pathname pattern
60
+ * and creates an OPTIONS route for each new pathname pattern.
61
+ */
62
+ class RouteRegister {
63
+ /**
64
+ * OPTIONS middleware keyed by pathname pattern.
65
+ *
66
+ * @type {Map<string, OptionsMiddleware>}
67
+ */
68
+ #middlewares = new Map();
69
+
70
+ /**
71
+ * Registers a route by its HTTP method and pathname pattern.
72
+ *
73
+ * On the first registration of a pathname pattern, creates an
74
+ * `OptionsMiddleware` and returns the OPTIONS layer options. On later
75
+ * registrations of the same pattern, only adds the method to the existing
76
+ * middleware and returns `undefined`.
77
+ *
78
+ * @param {RouteRegistration} registration - The route registration to add.
79
+ * @returns {ExchangeLayerOptions|undefined} The OPTIONS layer options when the pathname pattern is new; otherwise `undefined`.
80
+ * @example
81
+ * ```js
82
+ * register(['GET', '/users']);
83
+ * // → { method: 'OPTIONS', pathnamePattern: '/users', middleware: handle }
84
+ *
85
+ * register(['POST', '/users']);
86
+ * // → undefined (methods updated)
87
+ * ```
88
+ */
89
+ register([method, pathnamePattern]) {
90
+ if (pathnamePattern === undefined) {
91
+ return undefined;
92
+ }
93
+
94
+ const optionsMiddleware = this.#middlewares.get(pathnamePattern);
95
+
96
+ if (optionsMiddleware !== undefined) {
97
+ optionsMiddleware.add(method);
98
+ return undefined;
99
+ }
100
+
101
+ const middleware = new OptionsMiddleware();
102
+ middleware.add(method);
103
+ this.#middlewares.set(pathnamePattern, middleware);
104
+ return {
105
+ method: 'OPTIONS',
106
+ pathnamePattern,
107
+ middleware: middleware.handle,
108
+ };
109
+ }
110
+
111
+ /**
112
+ * Registers multiple routes.
113
+ *
114
+ * Only the first registration of each pathname pattern contributes an OPTIONS
115
+ * layer. Later registrations for the same pattern update the existing
116
+ * middleware and are omitted from the result.
117
+ *
118
+ * @param {RouteRegistrations} registrations - The route registrations to add.
119
+ * @returns {ExchangeLayerOptions[]} The new OPTIONS layer options.
120
+ * @example
121
+ * ```js
122
+ * registerBatch([
123
+ * ['GET', '/users'],
124
+ * ['POST', '/users'],
125
+ * ['GET', '/posts'],
126
+ * ]);
127
+ * // → [
128
+ * // { method: 'OPTIONS', pathnamePattern: '/users', middleware: handle },
129
+ * // { method: 'OPTIONS', pathnamePattern: '/posts', middleware: handle },
130
+ * // ]
131
+ * ```
132
+ */
133
+ registerBatch(registrations) {
134
+ /** @type {ExchangeLayerOptions[]} */
135
+ const options = [];
136
+
137
+ for (const registration of registrations) {
138
+ const layerOptions = this.register(registration);
139
+
140
+ if (layerOptions !== undefined) {
141
+ options.push(layerOptions);
142
+ }
143
+ }
144
+
145
+ return options;
146
+ }
147
+ }
148
+
149
+ // ━━ EXPORT MODULE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
150
+ export default RouteRegister;
@@ -0,0 +1,225 @@
1
+ // @ts-check
2
+ /**
3
+ * @file Provides the routing system for route registration and execution.
4
+ *
5
+ * @module RouterSystem
6
+ */
7
+
8
+ // ━━ IMPORT MODULES ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
9
+ // » IMPORT LOCAL MODULES
10
+ import Pipeline from '#routing/Pipeline';
11
+ import RouteRegister from '#routing/RouterRegister';
12
+ import ExchangeLayer from '#routing/ExchangeLayer';
13
+
14
+ // ━━ TYPE DEFINITIONS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
15
+ /**
16
+ * Represents a single HTTP transaction.
17
+ *
18
+ * @typedef {import('#Exchange').default} Exchange
19
+ */
20
+
21
+ /**
22
+ * Defines HTTP middleware pipelines by pathname pattern and method.
23
+ *
24
+ * @typedef {import('#routing/Router').default} Router
25
+ */
26
+
27
+ /**
28
+ * Represents an exchange middleware function.
29
+ *
30
+ * @typedef {import('#routing/ExchangeLayer').MiddlewareFunction} MiddlewareFunction
31
+ */
32
+
33
+ /**
34
+ * Represents the fallback handler invoked when no layer resolves the exchange.
35
+ *
36
+ * @typedef {import('#routing/Pipeline').NotFoundHandler} NotFoundHandler
37
+ */
38
+
39
+ /**
40
+ * Collection of route registrations.
41
+ *
42
+ * @typedef {import('#routing/RouterRegister').RouteRegistrations} RouteRegistrations
43
+ */
44
+
45
+ /**
46
+ * Defines the criteria and middleware used by an exchange layer.
47
+ *
48
+ * @typedef {import('#routing/ExchangeLayer').ExchangeLayerOptions} ExchangeLayerOptions
49
+ */
50
+
51
+ /**
52
+ * Represents an HTTP method supported by the routing layer.
53
+ *
54
+ * @typedef {import('#routing/ExchangeLayer').HTTPMethod} HTTPMethod
55
+ */
56
+
57
+ /**
58
+ * Collection of layer options.
59
+ *
60
+ * @typedef {ExchangeLayerOptions[]} ExchangeLayersOptions
61
+ */
62
+
63
+ // ━━ MODULE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
64
+ /**
65
+ * Coordinates route registration and layer execution.
66
+ *
67
+ * @classdesc `RouterSystem` maintains the routing pipeline and translates
68
+ * route registrations and layer options into executable exchange layers.
69
+ */
70
+ class RouterSystem {
71
+ /**
72
+ * Pipeline containing the executable exchange layers.
73
+ *
74
+ * @type {Pipeline}
75
+ */
76
+ #pipeline = new Pipeline();
77
+
78
+ /**
79
+ * Route register used to maintain registered routes and compose automatic
80
+ * OPTIONS layer options.
81
+ *
82
+ * @type {RouteRegister}
83
+ */
84
+
85
+ #routes = new RouteRegister();
86
+ /**
87
+ * Registers multiple exchange layers from layer options.
88
+ *
89
+ * @param {ExchangeLayersOptions} layersOptions - The layer options used to create
90
+ * executable exchange layers.
91
+ * @example
92
+ * ```js
93
+ * routerSystem.registerLayerOptionsBatch([
94
+ * { method: undefined, pathnamePattern: '/api', middleware: middleware },
95
+ * ]);
96
+ * ```
97
+ */
98
+ registerLayerOptionsBatch(layersOptions) {
99
+ this.#registerLayerBatch(layersOptions);
100
+ }
101
+
102
+ /**
103
+ * Registers a route entry by transforming method, pathname pattern, and middlewares
104
+ * into executable exchange layers and route registrations.
105
+ *
106
+ * @param {HTTPMethod|undefined} method - The HTTP method to match.
107
+ * @param {string|undefined} pathnamePattern - The URL pathname pattern to match.
108
+ * @param {MiddlewareFunction[]} middlewares - The middleware functions to execute.
109
+ * @example
110
+ * ```js
111
+ * routerSystem.registerRouteEntry('GET', '/users', [authenticate, getUsers]);
112
+ * ```
113
+ */
114
+ registerRouteEntry(method, pathnamePattern, middlewares) {
115
+ const layersOptions = middlewares.map(middleware => ({
116
+ method,
117
+ pathnamePattern,
118
+ middleware,
119
+ }));
120
+
121
+ /** @type {RouteRegistrations} */
122
+ const routes = layersOptions.map(layerOptions => [
123
+ layerOptions.method,
124
+ layerOptions.pathnamePattern,
125
+ ]);
126
+
127
+ this.#registerRouteBatch(routes);
128
+ this.#registerLayerBatch(layersOptions);
129
+ }
130
+
131
+ /**
132
+ * Registers a mounted router by prefixing its routes and middlewares with a base pathname pattern.
133
+ *
134
+ * @param {string} basePathnamePattern - The base URL pathname pattern to prefix.
135
+ * @param {Router} router - The router instance to mount (must implement a `compose()` method).
136
+ * @example
137
+ * ```js
138
+ * const userRouter = new Router();
139
+ * userRouter.get('/', getUsers);
140
+ * routerSystem.registerMountEntry('/api/users', userRouter);
141
+ * ```
142
+ */
143
+ registerMountEntry(basePathnamePattern, router) {
144
+ const { middlewares, layersOptions } = router.compose();
145
+
146
+ const options = [
147
+ ...middlewares.map(middleware => ({
148
+ method: undefined,
149
+ pathnamePattern: basePathnamePattern,
150
+ middleware,
151
+ })),
152
+ ...layersOptions.map(({ method, pathnamePattern, middleware }) => ({
153
+ method,
154
+ pathnamePattern: `${basePathnamePattern}${pathnamePattern}`,
155
+ middleware,
156
+ })),
157
+ ];
158
+
159
+ /** @type {RouteRegistrations} */
160
+ const routes = options.map(({ method, pathnamePattern }) => [method, pathnamePattern]);
161
+
162
+ this.#registerRouteBatch(routes);
163
+ this.#registerLayerBatch(options);
164
+ }
165
+
166
+ /**
167
+ * Executes the routing pipeline for an exchange.
168
+ *
169
+ * @param {Exchange} exchange - The exchange to process.
170
+ * @param {NotFoundHandler} notFoundHandler - The fallback async function to execute if no layer resolves the exchange.
171
+ * @returns {Promise<void>} A promise fulfilled when routing execution completes.
172
+ * @example
173
+ * ```js
174
+ * await routerSystem.executePipeline(exchange, async (exc) => {
175
+ * exc.response.status(404).json({ error: 'Not Found' });
176
+ * });
177
+ * ```
178
+ */
179
+ executePipeline(exchange, notFoundHandler) {
180
+ return this.#pipeline.execute(exchange, notFoundHandler);
181
+ }
182
+
183
+ /**
184
+ * Registers multiple routes and adds their automatic OPTIONS layers to
185
+ * the routing pipeline.
186
+ *
187
+ * @param {RouteRegistrations} routes - The route registrations to add.
188
+ * @example
189
+ * ```js
190
+ * routerSystem.registerRouteBatch([
191
+ * ['GET', '/users'],
192
+ * ['POST', '/users'],
193
+ * ]);
194
+ * ```
195
+ */
196
+ #registerRouteBatch(routes) {
197
+ const layersOptions = this.#routes.registerBatch(routes);
198
+
199
+ const layers = layersOptions.map(layerOptions => new ExchangeLayer(layerOptions));
200
+
201
+ this.#pipeline.addBatch(layers);
202
+ }
203
+
204
+ /**
205
+ * Registers multiple `ExchangeLayer` instances created from the provided layer
206
+ * options and adds them to the routing pipeline.
207
+ *
208
+ * @param {ExchangeLayersOptions} layersOptions - The layer options used to create the `ExchangeLayer` instances.
209
+ * @example
210
+ * ```js
211
+ * routerSystem.registerLayerBatch([
212
+ * { method: 'GET', pathnamePattern: '/users', middleware: getUsers },
213
+ * { method: 'POST', pathnamePattern: '/users', middleware: createUser },
214
+ * ]);
215
+ * ```
216
+ */
217
+ #registerLayerBatch(layersOptions) {
218
+ const layers = layersOptions.map(layerOptions => new ExchangeLayer(layerOptions));
219
+
220
+ this.#pipeline.addBatch(layers);
221
+ }
222
+ }
223
+
224
+ // ━━ EXPORT MODULE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
225
+ export default RouterSystem;