@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.
- package/LICENSE +21 -0
- package/README.md +287 -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,1201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Defines the Server API.
|
|
3
|
+
*
|
|
4
|
+
* @description Provides the public server interface for configuring,
|
|
5
|
+
* starting, monitoring, and stopping an application server.
|
|
6
|
+
*
|
|
7
|
+
* The Server manages the server lifecycle, middleware and route
|
|
8
|
+
* registration, request handling, and server events.
|
|
9
|
+
*
|
|
10
|
+
* @module Server
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
// ━━ IMPORT MODULES ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
14
|
+
// » IMPORT NATIVE NODEJS MODULES
|
|
15
|
+
|
|
16
|
+
// » IMPORT THIRD PARTY MODULES
|
|
17
|
+
|
|
18
|
+
// » IMPORT LOCAL MODULES
|
|
19
|
+
import Kernel from '#Kernel';
|
|
20
|
+
import ServerError from '#shared/errors/ServerError';
|
|
21
|
+
import { assertServerConfiguration } from '#shared/validations/Server/ServerConfiguration';
|
|
22
|
+
import { assertRouter } from '#shared/validations/Server/Router';
|
|
23
|
+
import { assertNotFoundHandler } from '#shared/validations/Server/NotFoundHandler';
|
|
24
|
+
import { assertSystemErrorHandler } from '#shared/validations/Server/SystemErrorHandler';
|
|
25
|
+
import { assertPathnamePattern } from '#shared/validations/PathnamePattern';
|
|
26
|
+
import { assertMiddlewares } from '#shared/validations/Middleware';
|
|
27
|
+
|
|
28
|
+
// ━━ TYPE DEFINITIONS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
29
|
+
/**
|
|
30
|
+
* Represents a single HTTP transaction.
|
|
31
|
+
*
|
|
32
|
+
* @typedef {import('#Exchange').default} Exchange
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* This error type provides identifiable failures related to middleware validation.
|
|
37
|
+
*
|
|
38
|
+
* @typedef {import('#shared/errors/MiddlewareError').default} MiddlewareError
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* This error type provides identifiable failures related to pathname pattern syntax and validation.
|
|
43
|
+
*
|
|
44
|
+
* @typedef {import('#shared/errors/PathnamePatternError').default} PathnamePatternError
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Represents a permitted server configuration identity.
|
|
49
|
+
*
|
|
50
|
+
* @typedef {import('#configurations/ServerConfiguration').ServerConfigurationIdentity} ServerConfigurationIdentity
|
|
51
|
+
*/
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Represents a server configuration constrained to a permitted identity.
|
|
55
|
+
*
|
|
56
|
+
* @typedef {import('#configurations/ServerConfiguration').default<ServerConfigurationIdentity>} ServerConfiguration
|
|
57
|
+
*/
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Represents a complete network endpoint.
|
|
61
|
+
*
|
|
62
|
+
* @typedef {import('#value-objects/Endpoint').default} Endpoint
|
|
63
|
+
*/
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Represents the network address of an HTTP server.
|
|
67
|
+
*
|
|
68
|
+
* @typedef {import('#value-objects/Address').default} Address
|
|
69
|
+
*/
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Represents a router instance.
|
|
73
|
+
*
|
|
74
|
+
* @typedef {import('#routing/Router').default} Router
|
|
75
|
+
*/
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Owns the IPC subsystem and its application-facing API.
|
|
79
|
+
*
|
|
80
|
+
* @typedef {import('#IPCMain').default} IPCMain
|
|
81
|
+
*/
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Provides information about an exchange when processing starts.
|
|
85
|
+
*
|
|
86
|
+
* @typedef {import('#Exchange').ExchangeStartInfo} ExchangeStartInfo
|
|
87
|
+
*/
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Provides information about an exchange when processing fails.
|
|
91
|
+
*
|
|
92
|
+
* @typedef {import('#Exchange').ExchangeErrorInfo} ExchangeErrorInfo
|
|
93
|
+
*/
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Provides information about an exchange when processing completes.
|
|
97
|
+
*
|
|
98
|
+
* @typedef {import('#Exchange').ExchangeEndInfo} ExchangeEndInfo
|
|
99
|
+
*/
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Represents the lifecycle states of the server.
|
|
103
|
+
*
|
|
104
|
+
* @typedef { 'idle' | 'starting' | 'listening' | 'stopping' | 'closed' | 'error' } ServerState
|
|
105
|
+
*/
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Represents a pathname pattern used to match incoming requests.
|
|
109
|
+
*
|
|
110
|
+
* @typedef {string} PathnamePattern
|
|
111
|
+
*/
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Represents a function that delegates execution to the next
|
|
115
|
+
* middleware layer.
|
|
116
|
+
*
|
|
117
|
+
* @callback NextFunction
|
|
118
|
+
* @returns {void|Promise<void>}
|
|
119
|
+
*/
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Represents an exchange middleware function.
|
|
123
|
+
*
|
|
124
|
+
* @callback MiddlewareFunction
|
|
125
|
+
* @param {Exchange} exchange - Current HTTP exchange.
|
|
126
|
+
* @param {NextFunction} next - Delegates execution to the next layer.
|
|
127
|
+
* @returns {void|Promise<void>}
|
|
128
|
+
*/
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Represents an event name supported by the server.
|
|
132
|
+
*
|
|
133
|
+
* @typedef {'listen'|'close'|'error'|'exchange:start'|'exchange:end'|'exchange:error'|symbol} EventName
|
|
134
|
+
*/
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Data emitted with the `listen` event.
|
|
138
|
+
*
|
|
139
|
+
* @typedef {object} ListenEventData
|
|
140
|
+
* @property {Endpoint} endpoint - Endpoint where the server is listening.
|
|
141
|
+
* @property {Address} address - Network address where the server is listening.
|
|
142
|
+
* @property {number} elapsed - Elapsed time in milliseconds.
|
|
143
|
+
*/
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Data emitted with the `close` event.
|
|
147
|
+
*
|
|
148
|
+
* @typedef {object} CloseEventData
|
|
149
|
+
* @property {number} elapsed - Elapsed time in milliseconds.
|
|
150
|
+
*/
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Listener registered for the `listen` event.
|
|
154
|
+
*
|
|
155
|
+
* @typedef {(data: ListenEventData) => void} ListenEventListener
|
|
156
|
+
*/
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Listener registered for the `close` event.
|
|
160
|
+
*
|
|
161
|
+
* @typedef {(data: CloseEventData) => void} CloseEventListener
|
|
162
|
+
*/
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Listener registered for the `error` event.
|
|
166
|
+
*
|
|
167
|
+
* @typedef {(error: Error) => void} ErrorEventListener
|
|
168
|
+
*/
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Listener registered for the `exchange:start` event.
|
|
172
|
+
*
|
|
173
|
+
* @typedef {(data: ExchangeStartInfo) => void} ExchangeStartEventListener
|
|
174
|
+
*/
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Listener registered for the `exchange:end` event.
|
|
178
|
+
*
|
|
179
|
+
* @typedef {(data: ExchangeEndInfo) => void} ExchangeEndEventListener
|
|
180
|
+
*/
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Listener registered for the `exchange:error` event.
|
|
184
|
+
*
|
|
185
|
+
* @typedef {(data: ExchangeErrorInfo) => void} ExchangeErrorEventListener
|
|
186
|
+
*/
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Represents a listener registered for a server event.
|
|
190
|
+
*
|
|
191
|
+
* @typedef {(data?: unknown) => void} EventListener
|
|
192
|
+
*/
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Represents a handler invoked when a request does not match any registered route.
|
|
196
|
+
*
|
|
197
|
+
* @typedef {(exchange: Exchange) => void|Promise<void>} NotFoundHandler
|
|
198
|
+
*/
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Represents a handler invoked when an error propagates during request processing.
|
|
202
|
+
*
|
|
203
|
+
* @typedef {(error: Error, exchange: Exchange) => void|Promise<void>} SystemErrorHandler
|
|
204
|
+
*/
|
|
205
|
+
|
|
206
|
+
// ━━ MODULE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
207
|
+
/**
|
|
208
|
+
* Provides the public interface for managing an application server.
|
|
209
|
+
*
|
|
210
|
+
* @classdesc Server is the central entry point for configuring and controlling
|
|
211
|
+
* the application server. It provides middleware and route registration,
|
|
212
|
+
* lifecycle management, request handling, error handling, and server
|
|
213
|
+
* event notifications.
|
|
214
|
+
*
|
|
215
|
+
* The server remains inactive until `listen()` is called and can be
|
|
216
|
+
* gracefully stopped with `close()`. Configuration and application
|
|
217
|
+
* handlers are registered before startup and remain fixed throughout
|
|
218
|
+
* the server lifecycle.
|
|
219
|
+
*/
|
|
220
|
+
class Server {
|
|
221
|
+
/**
|
|
222
|
+
* Application kernel instance.
|
|
223
|
+
*
|
|
224
|
+
* @type {Kernel}
|
|
225
|
+
*/
|
|
226
|
+
#kernel;
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Current server lifecycle state.
|
|
230
|
+
*
|
|
231
|
+
* @type {ServerState}
|
|
232
|
+
*/
|
|
233
|
+
#state = Server.#STATES.IDLE;
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Creates a server instance from the provided configuration.
|
|
237
|
+
*
|
|
238
|
+
* The configuration defines the transport protocol, listening options, and
|
|
239
|
+
* server behavior. The server is initialized in the `idle` state and remains
|
|
240
|
+
* inactive until `listen()` is called.
|
|
241
|
+
*
|
|
242
|
+
* @param {ServerConfiguration} configuration - Server configuration used to initialize the server.
|
|
243
|
+
* @throws {ServerError} If `configuration` does not implement the ServerConfiguration contract.
|
|
244
|
+
* @example
|
|
245
|
+
* ```js
|
|
246
|
+
* const configuration = new HttpServerConfiguration({
|
|
247
|
+
* connection: {
|
|
248
|
+
* requestTimeout: 300_000,
|
|
249
|
+
* headersTimeout: 60_000,
|
|
250
|
+
* keepAliveTimeout: 5_000,
|
|
251
|
+
* maxHeaderSize: 16_384,
|
|
252
|
+
* noDelay: true,
|
|
253
|
+
* },
|
|
254
|
+
* listen: {
|
|
255
|
+
* host: '127.0.0.1',
|
|
256
|
+
* port: 3000,
|
|
257
|
+
* backlog: 511,
|
|
258
|
+
* },
|
|
259
|
+
* request: {
|
|
260
|
+
* bodyLimit: 1_048_576,
|
|
261
|
+
* trustProxy: false,
|
|
262
|
+
* },
|
|
263
|
+
* response: {
|
|
264
|
+
* etag: true,
|
|
265
|
+
* defaultCharset: 'utf-8',
|
|
266
|
+
* },
|
|
267
|
+
* });
|
|
268
|
+
*
|
|
269
|
+
* const server = new Server(configuration);
|
|
270
|
+
* ```
|
|
271
|
+
*
|
|
272
|
+
* @example
|
|
273
|
+
* ```js
|
|
274
|
+
* const configuration = new HttpsServerConfiguration({
|
|
275
|
+
* connection: {
|
|
276
|
+
* requestTimeout: 300_000,
|
|
277
|
+
* headersTimeout: 60_000,
|
|
278
|
+
* keepAliveTimeout: 5_000,
|
|
279
|
+
* maxHeaderSize: 16_384,
|
|
280
|
+
* noDelay: true,
|
|
281
|
+
* key: await readFile('./certs/server.key'),
|
|
282
|
+
* cert: await readFile('./certs/server.crt'),
|
|
283
|
+
* ca: await readFile('./certs/ca.crt'),
|
|
284
|
+
* minVersion: 'TLSv1.2',
|
|
285
|
+
* maxVersion: 'TLSv1.3',
|
|
286
|
+
* requestCert: false,
|
|
287
|
+
* rejectUnauthorized: true,
|
|
288
|
+
* ALPNProtocols: ['h2', 'http/1.1'],
|
|
289
|
+
* },
|
|
290
|
+
* listen: {
|
|
291
|
+
* host: '127.0.0.1',
|
|
292
|
+
* port: 3000,
|
|
293
|
+
* backlog: 511,
|
|
294
|
+
* },
|
|
295
|
+
* request: {
|
|
296
|
+
* bodyLimit: 1_048_576,
|
|
297
|
+
* trustProxy: false,
|
|
298
|
+
* },
|
|
299
|
+
* response: {
|
|
300
|
+
* etag: true,
|
|
301
|
+
* defaultCharset: 'utf-8',
|
|
302
|
+
* },
|
|
303
|
+
* });
|
|
304
|
+
*
|
|
305
|
+
* const server = new Server(configuration);
|
|
306
|
+
* ```
|
|
307
|
+
*/
|
|
308
|
+
constructor(configuration) {
|
|
309
|
+
assertServerConfiguration(configuration);
|
|
310
|
+
|
|
311
|
+
this.#kernel = new Kernel(configuration);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Returns the current server lifecycle state.
|
|
316
|
+
*
|
|
317
|
+
* @readonly
|
|
318
|
+
* @type {ServerState}
|
|
319
|
+
*/
|
|
320
|
+
get state() {
|
|
321
|
+
return this.#state;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Returns whether the server is currently listening for requests.
|
|
326
|
+
*
|
|
327
|
+
* @readonly
|
|
328
|
+
* @type {boolean}
|
|
329
|
+
*/
|
|
330
|
+
get listening() {
|
|
331
|
+
return this.#kernel.listening;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* The IPC subsystem owned by the server.
|
|
336
|
+
*
|
|
337
|
+
* Available only while the server is listening.
|
|
338
|
+
*
|
|
339
|
+
* @readonly
|
|
340
|
+
* @type {IPCMain}
|
|
341
|
+
* @throws {ServerError} If the server is not currently listening.
|
|
342
|
+
*/
|
|
343
|
+
get ipc() {
|
|
344
|
+
if (!this.#kernel.listening) {
|
|
345
|
+
throw new ServerError('SERVER_NOT_LISTENING');
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
return this.#kernel.ipc;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Registers middleware for all HTTP methods.
|
|
353
|
+
*
|
|
354
|
+
* @param {PathnamePattern | MiddlewareFunction} pathnamePattern - The pathname pattern to match, or the first middleware function.
|
|
355
|
+
* @param {...MiddlewareFunction} middlewares - The middleware functions to execute for matching requests.
|
|
356
|
+
* @returns {Server} The server instance.
|
|
357
|
+
* @throws {ServerError} If the server is not in the idle state.
|
|
358
|
+
* @throws {PathnamePatternError} If the pathname pattern is not a string.
|
|
359
|
+
* @throws {PathnamePatternError} If the pathname pattern is empty.
|
|
360
|
+
* @throws {PathnamePatternError} If the pathname pattern exceeds the maximum length.
|
|
361
|
+
* @throws {PathnamePatternError} If the pathname pattern syntax is invalid.
|
|
362
|
+
* @throws {PathnamePatternError} If the pathname pattern has duplicate parameter names.
|
|
363
|
+
* @throws {MiddlewareError} If a middleware is not a function.
|
|
364
|
+
* @throws {MiddlewareError} If a middleware does not declare exactly two parameters.
|
|
365
|
+
* @example
|
|
366
|
+
* ```js
|
|
367
|
+
* server.use('/api', authenticate);
|
|
368
|
+
* server.use(logger);
|
|
369
|
+
* ```
|
|
370
|
+
*/
|
|
371
|
+
use(pathnamePattern, ...middlewares) {
|
|
372
|
+
this.#assertCurrentState(Server.#IDLE_STATE_ERRORS);
|
|
373
|
+
const routeEntry = this.#ensureRouteEntry(pathnamePattern, middlewares);
|
|
374
|
+
this.#kernel.registerRouteEntry(undefined, routeEntry.pathnamePattern, routeEntry.middlewares);
|
|
375
|
+
return this;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Registers middleware for GET requests.
|
|
380
|
+
*
|
|
381
|
+
* @param {PathnamePattern | MiddlewareFunction} pathnamePattern - The pathname pattern to match, or the first middleware function.
|
|
382
|
+
* @param {...MiddlewareFunction} middlewares - The middleware functions to execute for matching GET requests.
|
|
383
|
+
* @returns {Server} The server instance.
|
|
384
|
+
* @throws {ServerError} If the server is not in the idle state.
|
|
385
|
+
* @throws {PathnamePatternError} If the pathname pattern is not a string.
|
|
386
|
+
* @throws {PathnamePatternError} If the pathname pattern is empty.
|
|
387
|
+
* @throws {PathnamePatternError} If the pathname pattern exceeds the maximum length.
|
|
388
|
+
* @throws {PathnamePatternError} If the pathname pattern syntax is invalid.
|
|
389
|
+
* @throws {PathnamePatternError} If the pathname pattern has duplicate parameter names.
|
|
390
|
+
* @throws {MiddlewareError} If a middleware is not a function.
|
|
391
|
+
* @throws {MiddlewareError} If a middleware does not declare exactly two parameters.
|
|
392
|
+
* @example
|
|
393
|
+
* ```js
|
|
394
|
+
* server.get('/users', getUsers);
|
|
395
|
+
* ```
|
|
396
|
+
*/
|
|
397
|
+
get(pathnamePattern, ...middlewares) {
|
|
398
|
+
this.#assertCurrentState(Server.#IDLE_STATE_ERRORS);
|
|
399
|
+
const routeEntry = this.#ensureRouteEntry(pathnamePattern, middlewares);
|
|
400
|
+
|
|
401
|
+
this.#kernel.registerRouteEntry('GET', routeEntry.pathnamePattern, routeEntry.middlewares);
|
|
402
|
+
|
|
403
|
+
return this;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Registers middleware for QUERY requests.
|
|
408
|
+
*
|
|
409
|
+
* @param {PathnamePattern | MiddlewareFunction} pathnamePattern - The pathname pattern to match, or the first middleware function.
|
|
410
|
+
* @param {...MiddlewareFunction} middlewares - The middleware functions to execute for matching QUERY requests.
|
|
411
|
+
* @returns {Server} The server instance.
|
|
412
|
+
* @throws {ServerError} If the server is not in the idle state.
|
|
413
|
+
* @throws {PathnamePatternError} If the pathname pattern is not a string.
|
|
414
|
+
* @throws {PathnamePatternError} If the pathname pattern is empty.
|
|
415
|
+
* @throws {PathnamePatternError} If the pathname pattern exceeds the maximum length.
|
|
416
|
+
* @throws {PathnamePatternError} If the pathname pattern syntax is invalid.
|
|
417
|
+
* @throws {PathnamePatternError} If the pathname pattern has duplicate parameter names.
|
|
418
|
+
* @throws {MiddlewareError} If a middleware is not a function.
|
|
419
|
+
* @throws {MiddlewareError} If a middleware does not declare exactly two parameters.
|
|
420
|
+
* @example
|
|
421
|
+
* ```js
|
|
422
|
+
* server.query('/users', queryUsers);
|
|
423
|
+
* ```
|
|
424
|
+
*/
|
|
425
|
+
query(pathnamePattern, ...middlewares) {
|
|
426
|
+
this.#assertCurrentState(Server.#IDLE_STATE_ERRORS);
|
|
427
|
+
const routeEntry = this.#ensureRouteEntry(pathnamePattern, middlewares);
|
|
428
|
+
|
|
429
|
+
this.#kernel.registerRouteEntry('QUERY', routeEntry.pathnamePattern, routeEntry.middlewares);
|
|
430
|
+
|
|
431
|
+
return this;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* Registers middleware for POST requests.
|
|
436
|
+
*
|
|
437
|
+
* @param {PathnamePattern | MiddlewareFunction} pathnamePattern - The pathname pattern to match, or the first middleware function.
|
|
438
|
+
* @param {...MiddlewareFunction} middlewares - The middleware functions to execute for matching POST requests.
|
|
439
|
+
* @returns {Server} The server instance.
|
|
440
|
+
* @throws {ServerError} If the server is not in the idle state.
|
|
441
|
+
* @throws {PathnamePatternError} If the pathname pattern is not a string.
|
|
442
|
+
* @throws {PathnamePatternError} If the pathname pattern is empty.
|
|
443
|
+
* @throws {PathnamePatternError} If the pathname pattern exceeds the maximum length.
|
|
444
|
+
* @throws {PathnamePatternError} If the pathname pattern syntax is invalid.
|
|
445
|
+
* @throws {PathnamePatternError} If the pathname pattern has duplicate parameter names.
|
|
446
|
+
* @throws {MiddlewareError} If a middleware is not a function.
|
|
447
|
+
* @throws {MiddlewareError} If a middleware does not declare exactly two parameters.
|
|
448
|
+
* @example
|
|
449
|
+
* ```js
|
|
450
|
+
* server.post('/users', createUser);
|
|
451
|
+
* ```
|
|
452
|
+
*/
|
|
453
|
+
post(pathnamePattern, ...middlewares) {
|
|
454
|
+
this.#assertCurrentState(Server.#IDLE_STATE_ERRORS);
|
|
455
|
+
const routeEntry = this.#ensureRouteEntry(pathnamePattern, middlewares);
|
|
456
|
+
|
|
457
|
+
this.#kernel.registerRouteEntry('POST', routeEntry.pathnamePattern, routeEntry.middlewares);
|
|
458
|
+
|
|
459
|
+
return this;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Registers middleware for PUT requests.
|
|
464
|
+
*
|
|
465
|
+
* @param {PathnamePattern | MiddlewareFunction} pathnamePattern - The pathname pattern to match, or the first middleware function.
|
|
466
|
+
* @param {...MiddlewareFunction} middlewares - The middleware functions to execute for matching PUT requests.
|
|
467
|
+
* @returns {Server} The server instance.
|
|
468
|
+
* @throws {ServerError} If the server is not in the idle state.
|
|
469
|
+
* @throws {PathnamePatternError} If the pathname pattern is not a string.
|
|
470
|
+
* @throws {PathnamePatternError} If the pathname pattern is empty.
|
|
471
|
+
* @throws {PathnamePatternError} If the pathname pattern exceeds the maximum length.
|
|
472
|
+
* @throws {PathnamePatternError} If the pathname pattern syntax is invalid.
|
|
473
|
+
* @throws {PathnamePatternError} If the pathname pattern has duplicate parameter names.
|
|
474
|
+
* @throws {MiddlewareError} If a middleware is not a function.
|
|
475
|
+
* @throws {MiddlewareError} If a middleware does not declare exactly two parameters.
|
|
476
|
+
* @example
|
|
477
|
+
* ```js
|
|
478
|
+
* server.put('/users/:userId', updateUser);
|
|
479
|
+
* ```
|
|
480
|
+
*/
|
|
481
|
+
put(pathnamePattern, ...middlewares) {
|
|
482
|
+
this.#assertCurrentState(Server.#IDLE_STATE_ERRORS);
|
|
483
|
+
const routeEntry = this.#ensureRouteEntry(pathnamePattern, middlewares);
|
|
484
|
+
|
|
485
|
+
this.#kernel.registerRouteEntry('PUT', routeEntry.pathnamePattern, routeEntry.middlewares);
|
|
486
|
+
|
|
487
|
+
return this;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* Registers middleware for PATCH requests.
|
|
492
|
+
*
|
|
493
|
+
* @param {PathnamePattern | MiddlewareFunction} pathnamePattern - The pathname pattern to match, or the first middleware function.
|
|
494
|
+
* @param {...MiddlewareFunction} middlewares - The middleware functions to execute for matching PATCH requests.
|
|
495
|
+
* @returns {Server} The server instance.
|
|
496
|
+
* @throws {ServerError} If the server is not in the idle state.
|
|
497
|
+
* @throws {PathnamePatternError} If the pathname pattern is not a string.
|
|
498
|
+
* @throws {PathnamePatternError} If the pathname pattern is empty.
|
|
499
|
+
* @throws {PathnamePatternError} If the pathname pattern exceeds the maximum length.
|
|
500
|
+
* @throws {PathnamePatternError} If the pathname pattern syntax is invalid.
|
|
501
|
+
* @throws {PathnamePatternError} If the pathname pattern has duplicate parameter names.
|
|
502
|
+
* @throws {MiddlewareError} If a middleware is not a function.
|
|
503
|
+
* @throws {MiddlewareError} If a middleware does not declare exactly two parameters.
|
|
504
|
+
* @example
|
|
505
|
+
* ```js
|
|
506
|
+
* server.patch('/users/:userId', patchUser);
|
|
507
|
+
* ```
|
|
508
|
+
*/
|
|
509
|
+
patch(pathnamePattern, ...middlewares) {
|
|
510
|
+
this.#assertCurrentState(Server.#IDLE_STATE_ERRORS);
|
|
511
|
+
const routeEntry = this.#ensureRouteEntry(pathnamePattern, middlewares);
|
|
512
|
+
|
|
513
|
+
this.#kernel.registerRouteEntry('PATCH', routeEntry.pathnamePattern, routeEntry.middlewares);
|
|
514
|
+
|
|
515
|
+
return this;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* Registers middleware for DELETE requests.
|
|
520
|
+
*
|
|
521
|
+
* @param {PathnamePattern | MiddlewareFunction} pathnamePattern - The pathname pattern to match, or the first middleware function.
|
|
522
|
+
* @param {...MiddlewareFunction} middlewares - The middleware functions to execute for matching DELETE requests.
|
|
523
|
+
* @returns {Server} The server instance.
|
|
524
|
+
* @throws {ServerError} If the server is not in the idle state.
|
|
525
|
+
* @throws {PathnamePatternError} If the pathname pattern is not a string.
|
|
526
|
+
* @throws {PathnamePatternError} If the pathname pattern is empty.
|
|
527
|
+
* @throws {PathnamePatternError} If the pathname pattern exceeds the maximum length.
|
|
528
|
+
* @throws {PathnamePatternError} If the pathname pattern syntax is invalid.
|
|
529
|
+
* @throws {PathnamePatternError} If the pathname pattern has duplicate parameter names.
|
|
530
|
+
* @throws {MiddlewareError} If a middleware is not a function.
|
|
531
|
+
* @throws {MiddlewareError} If a middleware does not declare exactly two parameters.
|
|
532
|
+
* @example
|
|
533
|
+
* ```js
|
|
534
|
+
* server.delete('/users/:userId', deleteUser);
|
|
535
|
+
* ```
|
|
536
|
+
*/
|
|
537
|
+
delete(pathnamePattern, ...middlewares) {
|
|
538
|
+
this.#assertCurrentState(Server.#IDLE_STATE_ERRORS);
|
|
539
|
+
const routeEntry = this.#ensureRouteEntry(pathnamePattern, middlewares);
|
|
540
|
+
|
|
541
|
+
this.#kernel.registerRouteEntry('DELETE', routeEntry.pathnamePattern, routeEntry.middlewares);
|
|
542
|
+
|
|
543
|
+
return this;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* Registers middleware for HEAD requests.
|
|
548
|
+
*
|
|
549
|
+
* @param {PathnamePattern | MiddlewareFunction} pathnamePattern - The pathname pattern to match, or the first middleware function.
|
|
550
|
+
* @param {...MiddlewareFunction} middlewares - The middleware functions to execute for matching HEAD requests.
|
|
551
|
+
* @returns {Server} The server instance.
|
|
552
|
+
* @throws {ServerError} If the server is not in the idle state.
|
|
553
|
+
* @throws {PathnamePatternError} If the pathname pattern is not a string.
|
|
554
|
+
* @throws {PathnamePatternError} If the pathname pattern is empty.
|
|
555
|
+
* @throws {PathnamePatternError} If the pathname pattern exceeds the maximum length.
|
|
556
|
+
* @throws {PathnamePatternError} If the pathname pattern syntax is invalid.
|
|
557
|
+
* @throws {PathnamePatternError} If the pathname pattern has duplicate parameter names.
|
|
558
|
+
* @throws {MiddlewareError} If a middleware is not a function.
|
|
559
|
+
* @throws {MiddlewareError} If a middleware does not declare exactly two parameters.
|
|
560
|
+
* @example
|
|
561
|
+
* ```js
|
|
562
|
+
* server.head('/users', checkUsers);
|
|
563
|
+
* ```
|
|
564
|
+
*/
|
|
565
|
+
head(pathnamePattern, ...middlewares) {
|
|
566
|
+
this.#assertCurrentState(Server.#IDLE_STATE_ERRORS);
|
|
567
|
+
const routeEntry = this.#ensureRouteEntry(pathnamePattern, middlewares);
|
|
568
|
+
|
|
569
|
+
this.#kernel.registerRouteEntry('HEAD', routeEntry.pathnamePattern, routeEntry.middlewares);
|
|
570
|
+
|
|
571
|
+
return this;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
/**
|
|
575
|
+
* Registers middleware for TRACE requests.
|
|
576
|
+
*
|
|
577
|
+
* @param {PathnamePattern | MiddlewareFunction} pathnamePattern - The pathname pattern to match, or the first middleware function.
|
|
578
|
+
* @param {...MiddlewareFunction} middlewares - The middleware functions to execute for matching TRACE requests.
|
|
579
|
+
* @returns {Server} The server instance.
|
|
580
|
+
* @throws {ServerError} If the server is not in the idle state.
|
|
581
|
+
* @throws {PathnamePatternError} If the pathname pattern is not a string.
|
|
582
|
+
* @throws {PathnamePatternError} If the pathname pattern is empty.
|
|
583
|
+
* @throws {PathnamePatternError} If the pathname pattern exceeds the maximum length.
|
|
584
|
+
* @throws {PathnamePatternError} If the pathname pattern syntax is invalid.
|
|
585
|
+
* @throws {PathnamePatternError} If the pathname pattern has duplicate parameter names.
|
|
586
|
+
* @throws {MiddlewareError} If a middleware is not a function.
|
|
587
|
+
* @throws {MiddlewareError} If a middleware does not declare exactly two parameters.
|
|
588
|
+
* @example
|
|
589
|
+
* ```js
|
|
590
|
+
* server.trace('/debug', traceRequest);
|
|
591
|
+
* ```
|
|
592
|
+
*/
|
|
593
|
+
trace(pathnamePattern, ...middlewares) {
|
|
594
|
+
this.#assertCurrentState(Server.#IDLE_STATE_ERRORS);
|
|
595
|
+
const routeEntry = this.#ensureRouteEntry(pathnamePattern, middlewares);
|
|
596
|
+
|
|
597
|
+
this.#kernel.registerRouteEntry('TRACE', routeEntry.pathnamePattern, routeEntry.middlewares);
|
|
598
|
+
|
|
599
|
+
return this;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
/**
|
|
603
|
+
* Mounts a router instance at a specific pathname prefix.
|
|
604
|
+
*
|
|
605
|
+
* @param {PathnamePattern} pathnamePattern - Pathname prefix where the router is mounted.
|
|
606
|
+
* @param {Router} router - Router instance to mount.
|
|
607
|
+
* @returns {Server} The server instance.
|
|
608
|
+
* @throws {ServerError} If the server is not in the idle state.
|
|
609
|
+
* @throws {PathnamePatternError} If the pathname pattern is not a string.
|
|
610
|
+
* @throws {PathnamePatternError} If the pathname pattern is empty.
|
|
611
|
+
* @throws {PathnamePatternError} If the pathname pattern exceeds the maximum length.
|
|
612
|
+
* @throws {PathnamePatternError} If the pathname pattern syntax is invalid.
|
|
613
|
+
* @throws {PathnamePatternError} If the pathname pattern has duplicate parameter names.
|
|
614
|
+
* @example
|
|
615
|
+
* ```js
|
|
616
|
+
*
|
|
617
|
+
* const api = new Router();
|
|
618
|
+
* api.get('/users', getUsers);
|
|
619
|
+
* api.post('/users', createUser);
|
|
620
|
+
*
|
|
621
|
+
* server.mount('/api', api);
|
|
622
|
+
* ```
|
|
623
|
+
*/
|
|
624
|
+
mount(pathnamePattern, router) {
|
|
625
|
+
this.#assertCurrentState(Server.#IDLE_STATE_ERRORS);
|
|
626
|
+
assertPathnamePattern(pathnamePattern);
|
|
627
|
+
assertRouter(router);
|
|
628
|
+
this.#kernel.registerMountEntry(pathnamePattern, router);
|
|
629
|
+
return this;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* Registers a custom handler for requests that do not match any route (404 Not Found).
|
|
634
|
+
*
|
|
635
|
+
* @param {NotFoundHandler} notFoundHandler - The handler function executed on unmatched routes.
|
|
636
|
+
* @returns {Server} The server instance.
|
|
637
|
+
* @throws {ServerError} If called in an invalid state.
|
|
638
|
+
* @throws {ServerError} If the handler is not a function.
|
|
639
|
+
* @throws {ServerError} If the handler does not declare exactly one parameter.
|
|
640
|
+
* @example
|
|
641
|
+
* ```js
|
|
642
|
+
* server.notFound(exchange => {
|
|
643
|
+
* exchange.response.status(404).json({ error: 'Not Found' });
|
|
644
|
+
* });
|
|
645
|
+
* ```
|
|
646
|
+
*/
|
|
647
|
+
notFound(notFoundHandler) {
|
|
648
|
+
this.#assertCurrentState(Server.#IDLE_STATE_ERRORS);
|
|
649
|
+
assertNotFoundHandler(notFoundHandler);
|
|
650
|
+
this.#kernel.notFound(notFoundHandler);
|
|
651
|
+
return this;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
/**
|
|
655
|
+
* Registers a handler for errors raised during request processing.
|
|
656
|
+
*
|
|
657
|
+
* This handler is invoked when an error propagates through the exchange
|
|
658
|
+
* processing pipeline.
|
|
659
|
+
*
|
|
660
|
+
* @param {SystemErrorHandler} systemErrorHandler - The error handling function.
|
|
661
|
+
* @returns {Server} The server instance.
|
|
662
|
+
* @throws {ServerError} If called in an invalid state.
|
|
663
|
+
* @throws {ServerError} If the handler is not a function.
|
|
664
|
+
* @throws {ServerError} If the handler does not declare exactly two parameters.
|
|
665
|
+
* @example
|
|
666
|
+
* ```js
|
|
667
|
+
* server.systemError((error, exchange) => {
|
|
668
|
+
* console.error(error);
|
|
669
|
+
* exchange.response.status(500).json({ error: 'Internal Server Error' });
|
|
670
|
+
* });
|
|
671
|
+
* ```
|
|
672
|
+
*/
|
|
673
|
+
systemError(systemErrorHandler) {
|
|
674
|
+
this.#assertCurrentState(Server.#IDLE_STATE_ERRORS);
|
|
675
|
+
assertSystemErrorHandler(systemErrorHandler);
|
|
676
|
+
this.#kernel.systemError(systemErrorHandler);
|
|
677
|
+
return this;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
/**
|
|
681
|
+
* Starts listening for incoming requests.
|
|
682
|
+
*
|
|
683
|
+
* Transitions the server state from 'idle' to 'starting', and upon success, to 'listening'.
|
|
684
|
+
*
|
|
685
|
+
* @returns {Promise<void>}
|
|
686
|
+
* @throws {ServerError} If the server is not in the idle state, or if startup fails.
|
|
687
|
+
* @example
|
|
688
|
+
* ```js
|
|
689
|
+
* await server.listen();
|
|
690
|
+
* // Server is now listening.
|
|
691
|
+
* ```
|
|
692
|
+
*
|
|
693
|
+
* @example
|
|
694
|
+
* ```js
|
|
695
|
+
* server.onListen(({ endpoint, address, elapsed }) => {
|
|
696
|
+
* console.log(`Server listening at ${endpoint.displayUrl} in ${elapsed}ms`);
|
|
697
|
+
* console.log(`Bound to ${address} (${address.family})`);
|
|
698
|
+
* // Bound to [::1]:3000 (IPv6)
|
|
699
|
+
* });
|
|
700
|
+
*
|
|
701
|
+
* await server.listen();
|
|
702
|
+
* ```
|
|
703
|
+
*/
|
|
704
|
+
async listen() {
|
|
705
|
+
this.#assertCurrentState(Server.#LISTEN_STATE_ERRORS);
|
|
706
|
+
this.#transitionTo(Server.#STATES.STARTING);
|
|
707
|
+
|
|
708
|
+
try {
|
|
709
|
+
await this.#kernel.listen();
|
|
710
|
+
this.#transitionTo(Server.#STATES.LISTENING);
|
|
711
|
+
} catch (error) {
|
|
712
|
+
this.#transitionTo(Server.#STATES.ERROR);
|
|
713
|
+
throw error;
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
/**
|
|
718
|
+
* Stops the server and releases associated network resources.
|
|
719
|
+
*
|
|
720
|
+
* Transitions the server state to 'stopping' and then to 'closed'.
|
|
721
|
+
*
|
|
722
|
+
* @returns {Promise<void>}
|
|
723
|
+
* @throws {ServerError} If the server is not listening or shutdown fails.
|
|
724
|
+
* @example
|
|
725
|
+
* ```js
|
|
726
|
+
* // Graceful shutdown
|
|
727
|
+
* process.on('SIGTERM', async () => {
|
|
728
|
+
* await server.close();
|
|
729
|
+
* process.exit(0);
|
|
730
|
+
* });
|
|
731
|
+
* ```
|
|
732
|
+
*/
|
|
733
|
+
async close() {
|
|
734
|
+
this.#assertCurrentState(Server.#CLOSE_STATE_ERRORS);
|
|
735
|
+
this.#transitionTo(Server.#STATES.STOPPING);
|
|
736
|
+
|
|
737
|
+
try {
|
|
738
|
+
await this.#kernel.close();
|
|
739
|
+
this.#transitionTo(Server.#STATES.CLOSED);
|
|
740
|
+
} catch (error) {
|
|
741
|
+
this.#transitionTo(Server.#STATES.ERROR);
|
|
742
|
+
throw error;
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
/**
|
|
747
|
+
* @overload
|
|
748
|
+
* @param {'listen'} event - Event name.
|
|
749
|
+
* @param {ListenEventListener} listener - Function invoked when the server starts listening.
|
|
750
|
+
* @returns {Server} The server instance.
|
|
751
|
+
*/
|
|
752
|
+
/**
|
|
753
|
+
* @overload
|
|
754
|
+
* @param {'close'} event - Event name.
|
|
755
|
+
* @param {CloseEventListener} listener - Function invoked when the server closes.
|
|
756
|
+
* @returns {Server} The server instance.
|
|
757
|
+
*/
|
|
758
|
+
/**
|
|
759
|
+
* @overload
|
|
760
|
+
* @param {'error'} event - Event name.
|
|
761
|
+
* @param {ErrorEventListener} listener - Function invoked when a server-level error occurs.
|
|
762
|
+
* @returns {Server} The server instance.
|
|
763
|
+
*/
|
|
764
|
+
/**
|
|
765
|
+
* @overload
|
|
766
|
+
* @param {'exchange:start'} event - Event name.
|
|
767
|
+
* @param {ExchangeStartEventListener} listener - Function invoked during the exchange starts.
|
|
768
|
+
* @returns {Server} The server instance.
|
|
769
|
+
*/
|
|
770
|
+
/**
|
|
771
|
+
* @overload
|
|
772
|
+
* @param {'exchange:end'} event - Event name.
|
|
773
|
+
* @param {ExchangeEndEventListener} listener - Function invoked during the exchange ends.
|
|
774
|
+
* @returns {Server} The server instance.
|
|
775
|
+
*/
|
|
776
|
+
/**
|
|
777
|
+
* @overload
|
|
778
|
+
* @param {'exchange:error'} event - Event name.
|
|
779
|
+
* @param {ExchangeErrorEventListener} listener - Function invoked when an exchange fails.
|
|
780
|
+
* @returns {Server} The server instance.
|
|
781
|
+
*/
|
|
782
|
+
/**
|
|
783
|
+
* Registers a listener for a server event.
|
|
784
|
+
*
|
|
785
|
+
* @param {EventName} event - Event name.
|
|
786
|
+
* @param {EventListener} listener - Function invoked when the event is emitted.
|
|
787
|
+
* @returns {Server} The server instance.
|
|
788
|
+
*
|
|
789
|
+
* @example
|
|
790
|
+
* ```js
|
|
791
|
+
* server.on('listen', ({ endpoint, address, elapsed }) => {
|
|
792
|
+
* console.log(`Server listening at ${endpoint.displayUrl} in ${elapsed}ms`);
|
|
793
|
+
* console.log(`Bound to ${address} (${address.family})`);
|
|
794
|
+
* // Bound to [::1]:3000 (IPv6)
|
|
795
|
+
* });
|
|
796
|
+
* ```
|
|
797
|
+
*/
|
|
798
|
+
on(event, listener) {
|
|
799
|
+
this.#kernel.on(event, listener);
|
|
800
|
+
return this;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
/**
|
|
804
|
+
* @overload
|
|
805
|
+
* @param {'listen'} event - Event name.
|
|
806
|
+
* @param {ListenEventListener} listener - Function invoked when the server starts listening.
|
|
807
|
+
* @returns {Server} The server instance.
|
|
808
|
+
*/
|
|
809
|
+
/**
|
|
810
|
+
* @overload
|
|
811
|
+
* @param {'close'} event - Event name.
|
|
812
|
+
* @param {CloseEventListener} listener - Function invoked when the server closes.
|
|
813
|
+
* @returns {Server} The server instance.
|
|
814
|
+
*/
|
|
815
|
+
/**
|
|
816
|
+
* @overload
|
|
817
|
+
* @param {'error'} event - Event name.
|
|
818
|
+
* @param {ErrorEventListener} listener - Function invoked when a server-level error occurs.
|
|
819
|
+
* @returns {Server} The server instance.
|
|
820
|
+
*/
|
|
821
|
+
/**
|
|
822
|
+
* @overload
|
|
823
|
+
* @param {'exchange:start'} event - Event name.
|
|
824
|
+
* @param {ExchangeStartEventListener} listener - Function invoked during the exchange starts.
|
|
825
|
+
* @returns {Server} The server instance.
|
|
826
|
+
*/
|
|
827
|
+
/**
|
|
828
|
+
* @overload
|
|
829
|
+
* @param {'exchange:end'} event - Event name.
|
|
830
|
+
* @param {ExchangeEndEventListener} listener - Function invoked during the exchange ends.
|
|
831
|
+
* @returns {Server} The server instance.
|
|
832
|
+
*/
|
|
833
|
+
/**
|
|
834
|
+
* @overload
|
|
835
|
+
* @param {'exchange:error'} event - Event name.
|
|
836
|
+
* @param {ExchangeErrorEventListener} listener - Function invoked when an exchange fails.
|
|
837
|
+
* @returns {Server} The server instance.
|
|
838
|
+
*/
|
|
839
|
+
/**
|
|
840
|
+
* Registers a listener that is invoked only once for a server event.
|
|
841
|
+
*
|
|
842
|
+
* @param {EventName} event - Event name.
|
|
843
|
+
* @param {EventListener} listener - Function invoked when the event is emitted.
|
|
844
|
+
* @returns {Server} The server instance.
|
|
845
|
+
*
|
|
846
|
+
* @example
|
|
847
|
+
* ```js
|
|
848
|
+
* server.once('listen', ({ endpoint }) => {
|
|
849
|
+
* console.log(`Server started at ${endpoint.displayUrl}`);
|
|
850
|
+
* });
|
|
851
|
+
* ```
|
|
852
|
+
*/
|
|
853
|
+
once(event, listener) {
|
|
854
|
+
this.#kernel.once(event, listener);
|
|
855
|
+
return this;
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
/**
|
|
859
|
+
* @overload
|
|
860
|
+
* @param {'listen'} event - Event name.
|
|
861
|
+
* @param {ListenEventListener} listener - Function invoked when the server starts listening.
|
|
862
|
+
* @returns {Server} The server instance.
|
|
863
|
+
*/
|
|
864
|
+
/**
|
|
865
|
+
* @overload
|
|
866
|
+
* @param {'close'} event - Event name.
|
|
867
|
+
* @param {CloseEventListener} listener - Function invoked when the server closes.
|
|
868
|
+
* @returns {Server} The server instance.
|
|
869
|
+
*/
|
|
870
|
+
/**
|
|
871
|
+
* @overload
|
|
872
|
+
* @param {'error'} event - Event name.
|
|
873
|
+
* @param {ErrorEventListener} listener - Function invoked when a server-level error occurs.
|
|
874
|
+
* @returns {Server} The server instance.
|
|
875
|
+
*/
|
|
876
|
+
/**
|
|
877
|
+
* @overload
|
|
878
|
+
* @param {'exchange:start'} event - Event name.
|
|
879
|
+
* @param {ExchangeStartEventListener} listener - Function invoked during the exchange starts.
|
|
880
|
+
* @returns {Server} The server instance.
|
|
881
|
+
*/
|
|
882
|
+
/**
|
|
883
|
+
* @overload
|
|
884
|
+
* @param {'exchange:end'} event - Event name.
|
|
885
|
+
* @param {ExchangeEndEventListener} listener - Function invoked during the exchange ends.
|
|
886
|
+
* @returns {Server} The server instance.
|
|
887
|
+
*/
|
|
888
|
+
/**
|
|
889
|
+
* @overload
|
|
890
|
+
* @param {'exchange:error'} event - Event name.
|
|
891
|
+
* @param {ExchangeErrorEventListener} listener - Function invoked when an exchange fails.
|
|
892
|
+
* @returns {Server} The server instance.
|
|
893
|
+
*/
|
|
894
|
+
/**
|
|
895
|
+
* Removes a listener from a server event.
|
|
896
|
+
*
|
|
897
|
+
* @param {EventName} event - Event name.
|
|
898
|
+
* @param {EventListener} listener - Listener to remove.
|
|
899
|
+
* @returns {Server} The server instance.
|
|
900
|
+
*
|
|
901
|
+
* @example
|
|
902
|
+
* ```js
|
|
903
|
+
* const listener = () => {
|
|
904
|
+
* console.log('Server started');
|
|
905
|
+
* };
|
|
906
|
+
*
|
|
907
|
+
* server.on('listen', listener);
|
|
908
|
+
* server.off('listen', listener);
|
|
909
|
+
* ```
|
|
910
|
+
*/
|
|
911
|
+
off(event, listener) {
|
|
912
|
+
this.#kernel.off(event, listener);
|
|
913
|
+
return this;
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
/**
|
|
917
|
+
* Registers a listener for the `listen` event.
|
|
918
|
+
*
|
|
919
|
+
* @param {(data: ListenEventData) => void} listener - Invoked when the server starts listening.
|
|
920
|
+
* @returns {Server} The server instance.
|
|
921
|
+
*
|
|
922
|
+
* @example
|
|
923
|
+
* ```js
|
|
924
|
+
* server.onListen(({ endpoint, address, elapsed }) => {
|
|
925
|
+
* console.log(`Server listening at ${endpoint.displayUrl} in ${elapsed}ms`);
|
|
926
|
+
* console.log(`Bound to ${address} (${address.family})`);
|
|
927
|
+
* // Bound to [::1]:3000 (IPv6)
|
|
928
|
+
* });
|
|
929
|
+
* ```
|
|
930
|
+
*/
|
|
931
|
+
onListen(listener) {
|
|
932
|
+
this.#kernel.on('listen', listener);
|
|
933
|
+
return this;
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
/**
|
|
937
|
+
* Registers a listener for the `close` event.
|
|
938
|
+
*
|
|
939
|
+
* @param {(data: CloseEventData) => void} listener - Invoked when the server closes.
|
|
940
|
+
* @returns {Server} The server instance.
|
|
941
|
+
*
|
|
942
|
+
* @example
|
|
943
|
+
* ```js
|
|
944
|
+
* server.onClose(({ elapsed }) => {
|
|
945
|
+
* console.log(`Server closed in ${elapsed}ms`);
|
|
946
|
+
* });
|
|
947
|
+
* ```
|
|
948
|
+
*/
|
|
949
|
+
onClose(listener) {
|
|
950
|
+
this.#kernel.on('close', listener);
|
|
951
|
+
return this;
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
/**
|
|
955
|
+
* Registers a listener for the `error` event.
|
|
956
|
+
*
|
|
957
|
+
* @param {(error: Error) => void} listener - Invoked when a server-level error occurs.
|
|
958
|
+
* @returns {Server} The server instance.
|
|
959
|
+
*
|
|
960
|
+
* @example
|
|
961
|
+
* ```js
|
|
962
|
+
* server.onError(error => {
|
|
963
|
+
* console.error('Server error:', error);
|
|
964
|
+
* });
|
|
965
|
+
* ```
|
|
966
|
+
*/
|
|
967
|
+
onError(listener) {
|
|
968
|
+
this.#kernel.on('error', listener);
|
|
969
|
+
return this;
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
/**
|
|
973
|
+
* Registers a listener for the `exchange:start` event.
|
|
974
|
+
*
|
|
975
|
+
* @param {ExchangeStartEventListener} listener - Function invoked when an exchange starts.
|
|
976
|
+
* @returns {Server} The server instance.
|
|
977
|
+
*
|
|
978
|
+
* @example
|
|
979
|
+
* ```js
|
|
980
|
+
* server.onExchangeStart(information => {
|
|
981
|
+
* console.log(
|
|
982
|
+
* information.id,
|
|
983
|
+
* information.request.method,
|
|
984
|
+
* information.request.pathname,
|
|
985
|
+
* );
|
|
986
|
+
* });
|
|
987
|
+
* ```
|
|
988
|
+
*/
|
|
989
|
+
onExchangeStart(listener) {
|
|
990
|
+
this.#kernel.on('exchange:start', listener);
|
|
991
|
+
return this;
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
/**
|
|
995
|
+
* Registers a listener for the `exchange:end` event.
|
|
996
|
+
*
|
|
997
|
+
* @param {ExchangeEndEventListener} listener - Function invoked when exchange processing ends.
|
|
998
|
+
* @returns {Server} The server instance.
|
|
999
|
+
*
|
|
1000
|
+
* @example
|
|
1001
|
+
* ```js
|
|
1002
|
+
* server.onExchangeEnd(information => {
|
|
1003
|
+
* console.log(
|
|
1004
|
+
* information.outcome, // 'success' | 'error'
|
|
1005
|
+
* information.timing.duration, // number
|
|
1006
|
+
* );
|
|
1007
|
+
* });
|
|
1008
|
+
* ```
|
|
1009
|
+
*/
|
|
1010
|
+
onExchangeEnd(listener) {
|
|
1011
|
+
this.#kernel.on('exchange:end', listener);
|
|
1012
|
+
return this;
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
/**
|
|
1016
|
+
* Registers a listener for the `exchange:error` event.
|
|
1017
|
+
*
|
|
1018
|
+
* @param {ExchangeErrorEventListener} listener - Function invoked when an exchange fails.
|
|
1019
|
+
* @returns {Server} The server instance.
|
|
1020
|
+
*
|
|
1021
|
+
* @example
|
|
1022
|
+
* ```js
|
|
1023
|
+
* server.onExchangeError(information => {
|
|
1024
|
+
* console.error(
|
|
1025
|
+
* information.id,
|
|
1026
|
+
* information.error,
|
|
1027
|
+
* information.request.pathname,
|
|
1028
|
+
* );
|
|
1029
|
+
* });
|
|
1030
|
+
* ```
|
|
1031
|
+
*/
|
|
1032
|
+
onExchangeError(listener) {
|
|
1033
|
+
this.#kernel.on('exchange:error', listener);
|
|
1034
|
+
return this;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
/**
|
|
1038
|
+
* Asynchronously disposes of the server resources.
|
|
1039
|
+
*
|
|
1040
|
+
* Enables the use of the `await using` statement to automatically
|
|
1041
|
+
* close the server when it goes out of scope.
|
|
1042
|
+
*
|
|
1043
|
+
* @returns {Promise<void>}
|
|
1044
|
+
* @async
|
|
1045
|
+
* @example
|
|
1046
|
+
* ```js
|
|
1047
|
+
* async function main() {
|
|
1048
|
+
* await using server = new Server(configuration);
|
|
1049
|
+
* await server.listen();
|
|
1050
|
+
* // ... use server ...
|
|
1051
|
+
* } // ← `Symbol.asyncDispose` runs here.
|
|
1052
|
+
* ```
|
|
1053
|
+
*/
|
|
1054
|
+
async [Symbol.asyncDispose]() {
|
|
1055
|
+
if (this.#state === Server.#STATES.LISTENING || this.#state === Server.#STATES.STARTING) {
|
|
1056
|
+
await this.close();
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
/**
|
|
1061
|
+
* Validates that the current state allows an operation.
|
|
1062
|
+
*
|
|
1063
|
+
* @private
|
|
1064
|
+
* @param {Map<ServerState, string>} errorStates - Map containing invalid states and associated error codes.
|
|
1065
|
+
* @throws {ServerError} If the current state is restricted.
|
|
1066
|
+
*/
|
|
1067
|
+
#assertCurrentState(errorStates) {
|
|
1068
|
+
const identifier = errorStates.get(this.#state);
|
|
1069
|
+
if (identifier !== undefined) {
|
|
1070
|
+
throw new ServerError(identifier);
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
/**
|
|
1075
|
+
* Performs a safe state transition.
|
|
1076
|
+
*
|
|
1077
|
+
* @private
|
|
1078
|
+
* @param {ServerState} nextState - Target lifecycle state.
|
|
1079
|
+
*/
|
|
1080
|
+
#transitionTo(nextState) {
|
|
1081
|
+
this.#assertTransition(nextState);
|
|
1082
|
+
this.#state = nextState;
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
/**
|
|
1086
|
+
* Validates whether a state transition is permitted.
|
|
1087
|
+
*
|
|
1088
|
+
* @private
|
|
1089
|
+
* @param {ServerState} nextState - Target lifecycle state.
|
|
1090
|
+
* @throws {ServerError} If the transition is disallowed by the state machine.
|
|
1091
|
+
*/
|
|
1092
|
+
#assertTransition(nextState) {
|
|
1093
|
+
const transitions = Server.#TRANSITIONS.get(this.#state);
|
|
1094
|
+
|
|
1095
|
+
if (!transitions.has(nextState)) {
|
|
1096
|
+
throw new ServerError('SERVER_INVALID_STATE_TRANSITION', {
|
|
1097
|
+
values: {
|
|
1098
|
+
from: this.#state,
|
|
1099
|
+
to: nextState,
|
|
1100
|
+
},
|
|
1101
|
+
});
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
#ensureRouteEntry(pathnamePattern, middlewares) {
|
|
1106
|
+
if (typeof pathnamePattern === 'string') {
|
|
1107
|
+
assertPathnamePattern(pathnamePattern);
|
|
1108
|
+
assertMiddlewares(middlewares);
|
|
1109
|
+
|
|
1110
|
+
return {
|
|
1111
|
+
pathnamePattern,
|
|
1112
|
+
middlewares,
|
|
1113
|
+
};
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
const normalizedMiddlewares = [pathnamePattern, ...middlewares];
|
|
1117
|
+
|
|
1118
|
+
assertMiddlewares(normalizedMiddlewares);
|
|
1119
|
+
|
|
1120
|
+
return {
|
|
1121
|
+
pathnamePattern: undefined,
|
|
1122
|
+
middlewares: normalizedMiddlewares,
|
|
1123
|
+
};
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
/**
|
|
1127
|
+
* Enumeration of server lifecycle states.
|
|
1128
|
+
*
|
|
1129
|
+
* @private
|
|
1130
|
+
* @readonly
|
|
1131
|
+
* @enum {ServerState}
|
|
1132
|
+
*/
|
|
1133
|
+
static #STATES = Object.freeze({
|
|
1134
|
+
IDLE: 'idle',
|
|
1135
|
+
STARTING: 'starting',
|
|
1136
|
+
LISTENING: 'listening',
|
|
1137
|
+
STOPPING: 'stopping',
|
|
1138
|
+
CLOSED: 'closed',
|
|
1139
|
+
ERROR: 'error',
|
|
1140
|
+
});
|
|
1141
|
+
|
|
1142
|
+
/**
|
|
1143
|
+
* Allowed state transition rules map.
|
|
1144
|
+
*
|
|
1145
|
+
* @private
|
|
1146
|
+
* @type {Map<ServerState, Set<ServerState>>}
|
|
1147
|
+
*/
|
|
1148
|
+
static #TRANSITIONS = new Map([
|
|
1149
|
+
[Server.#STATES.IDLE, new Set([Server.#STATES.STARTING])],
|
|
1150
|
+
[Server.#STATES.STARTING, new Set([Server.#STATES.LISTENING, Server.#STATES.ERROR])],
|
|
1151
|
+
[Server.#STATES.LISTENING, new Set([Server.#STATES.STOPPING, Server.#STATES.ERROR])],
|
|
1152
|
+
[Server.#STATES.STOPPING, new Set([Server.#STATES.CLOSED, Server.#STATES.ERROR])],
|
|
1153
|
+
[Server.#STATES.CLOSED, new Set()],
|
|
1154
|
+
[Server.#STATES.ERROR, new Set()],
|
|
1155
|
+
]);
|
|
1156
|
+
|
|
1157
|
+
/**
|
|
1158
|
+
* Error mappings for configuration methods when server is busy or unready.
|
|
1159
|
+
*
|
|
1160
|
+
* @private
|
|
1161
|
+
* @type {Map<ServerState, string>}
|
|
1162
|
+
*/
|
|
1163
|
+
static #IDLE_STATE_ERRORS = new Map([
|
|
1164
|
+
[Server.#STATES.STARTING, 'SERVER_ALREADY_STARTING'],
|
|
1165
|
+
[Server.#STATES.LISTENING, 'SERVER_ALREADY_LISTENING'],
|
|
1166
|
+
[Server.#STATES.STOPPING, 'SERVER_STOPPING'],
|
|
1167
|
+
[Server.#STATES.CLOSED, 'SERVER_CLOSED'],
|
|
1168
|
+
[Server.#STATES.ERROR, 'SERVER_ERROR'],
|
|
1169
|
+
]);
|
|
1170
|
+
|
|
1171
|
+
/**
|
|
1172
|
+
* Error mappings when attempting to call listen() in an invalid state.
|
|
1173
|
+
*
|
|
1174
|
+
* @private
|
|
1175
|
+
* @type {Map<ServerState, string>}
|
|
1176
|
+
*/
|
|
1177
|
+
static #LISTEN_STATE_ERRORS = new Map([
|
|
1178
|
+
[Server.#STATES.STARTING, 'SERVER_ALREADY_STARTING'],
|
|
1179
|
+
[Server.#STATES.LISTENING, 'SERVER_ALREADY_LISTENING'],
|
|
1180
|
+
[Server.#STATES.STOPPING, 'SERVER_STOPPING'],
|
|
1181
|
+
[Server.#STATES.CLOSED, 'SERVER_CLOSED'],
|
|
1182
|
+
[Server.#STATES.ERROR, 'SERVER_ERROR'],
|
|
1183
|
+
]);
|
|
1184
|
+
|
|
1185
|
+
/**
|
|
1186
|
+
* Error mappings when attempting to call close() in an invalid state.
|
|
1187
|
+
*
|
|
1188
|
+
* @private
|
|
1189
|
+
* @type {Map<ServerState, string>}
|
|
1190
|
+
*/
|
|
1191
|
+
static #CLOSE_STATE_ERRORS = new Map([
|
|
1192
|
+
[Server.#STATES.IDLE, 'SERVER_NOT_LISTENING'],
|
|
1193
|
+
[Server.#STATES.STARTING, 'SERVER_NOT_LISTENING'],
|
|
1194
|
+
[Server.#STATES.STOPPING, 'SERVER_ALREADY_STOPPING'],
|
|
1195
|
+
[Server.#STATES.CLOSED, 'SERVER_CLOSED'],
|
|
1196
|
+
[Server.#STATES.ERROR, 'SERVER_ERROR'],
|
|
1197
|
+
]);
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
// ━━ EXPORT MODULE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
1201
|
+
export default Server;
|