@twin.org/api-server-fastify 0.0.3-next.9 → 0.9.0-next.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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # TWIN API Server Fastify
2
2
 
3
- Use [Fastify](https://fastify.dev/) as the core web server for APIs.
3
+ This package provides Fastify web server integration for exposing API routes with consistent runtime behaviour. It builds on the Fastify framework to offer a predictable hosting layer for API services.
4
4
 
5
5
  ## Installation
6
6
 
@@ -1,6 +1,9 @@
1
1
  import fp from "fastify-plugin";
2
2
  import { Server } from "socket.io";
3
- // This is a clone of fastify-socket.io which runs with recent fastify versions.
3
+ /**
4
+ * Fastify plugin that attaches a Socket.IO server to the Fastify HTTP server.
5
+ * Cloned from fastify-socket.io to support recent Fastify versions.
6
+ */
4
7
  const fastifySocketIO = fp(async (fastify, opts) => {
5
8
  const ioServer = new Server(fastify.server, opts);
6
9
  fastify.decorate("io", ioServer);
@@ -1 +1 @@
1
- {"version":3,"file":"fastifySocketIo.js","sourceRoot":"","sources":["../../src/fastifySocketIo.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAChC,OAAO,EAAE,MAAM,EAAsB,MAAM,WAAW,CAAC;AAEvD,gFAAgF;AAChF,MAAM,eAAe,GAA+C,EAAE,CACrE,KAAK,EAAE,OAAwB,EAAE,IAA4B,EAAE,EAAE;IAChE,MAAM,QAAQ,GAAG,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAElD,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACjC,OAAO,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,EAAE;QAClC,QAAQ,CAAC,iBAAiB,EAAE,CAAC;QAC7B,QAAQ;aACN,KAAK,EAAE;YACR,wFAAwF;aACvF,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC;YACnB,wFAAwF;aACvF,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;AACJ,CAAC,EACD,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,CACzC,CAAC;AAEF,eAAe,eAAe,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { FastifyInstance, FastifyPluginAsync } from \"fastify\";\nimport fp from \"fastify-plugin\";\nimport { Server, type ServerOptions } from \"socket.io\";\n\n// This is a clone of fastify-socket.io which runs with recent fastify versions.\nconst fastifySocketIO: FastifyPluginAsync<Partial<ServerOptions>> = fp(\n\tasync (fastify: FastifyInstance, opts: Partial<ServerOptions>) => {\n\t\tconst ioServer = new Server(fastify.server, opts);\n\n\t\tfastify.decorate(\"io\", ioServer);\n\t\tfastify.addHook(\"preClose\", done => {\n\t\t\tioServer.disconnectSockets();\n\t\t\tioServer\n\t\t\t\t.close()\n\t\t\t\t// eslint-disable-next-line promise/prefer-await-to-then, promise/no-callback-in-promise\n\t\t\t\t.then(() => done())\n\t\t\t\t// eslint-disable-next-line promise/prefer-await-to-then, promise/no-callback-in-promise\n\t\t\t\t.catch(() => done());\n\t\t});\n\t},\n\t{ fastify: \">=5.x.x\", name: \"socket.io\" }\n);\n\nexport default fastifySocketIO;\n"]}
1
+ {"version":3,"file":"fastifySocketIo.js","sourceRoot":"","sources":["../../src/fastifySocketIo.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAChC,OAAO,EAAE,MAAM,EAAsB,MAAM,WAAW,CAAC;AAEvD;;;GAGG;AACH,MAAM,eAAe,GAA+C,EAAE,CACrE,KAAK,EAAE,OAAwB,EAAE,IAA4B,EAAE,EAAE;IAChE,MAAM,QAAQ,GAAG,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAElD,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACjC,OAAO,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,EAAE;QAClC,QAAQ,CAAC,iBAAiB,EAAE,CAAC;QAC7B,QAAQ;aACN,KAAK,EAAE;YACR,wFAAwF;aACvF,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC;YACnB,wFAAwF;aACvF,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;AACJ,CAAC,EACD,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,CACzC,CAAC;AAEF,eAAe,eAAe,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { FastifyInstance, FastifyPluginAsync } from \"fastify\";\nimport fp from \"fastify-plugin\";\nimport { Server, type ServerOptions } from \"socket.io\";\n\n/**\n * Fastify plugin that attaches a Socket.IO server to the Fastify HTTP server.\n * Cloned from fastify-socket.io to support recent Fastify versions.\n */\nconst fastifySocketIO: FastifyPluginAsync<Partial<ServerOptions>> = fp(\n\tasync (fastify: FastifyInstance, opts: Partial<ServerOptions>) => {\n\t\tconst ioServer = new Server(fastify.server, opts);\n\n\t\tfastify.decorate(\"io\", ioServer);\n\t\tfastify.addHook(\"preClose\", done => {\n\t\t\tioServer.disconnectSockets();\n\t\t\tioServer\n\t\t\t\t.close()\n\t\t\t\t// eslint-disable-next-line promise/prefer-await-to-then, promise/no-callback-in-promise\n\t\t\t\t.then(() => done())\n\t\t\t\t// eslint-disable-next-line promise/prefer-await-to-then, promise/no-callback-in-promise\n\t\t\t\t.catch(() => done());\n\t\t});\n\t},\n\t{ fastify: \">=5.x.x\", name: \"socket.io\" }\n);\n\nexport default fastifySocketIO;\n"]}
@@ -2,11 +2,11 @@
2
2
  // SPDX-License-Identifier: Apache-2.0.
3
3
  import FastifyCompress from "@fastify/compress";
4
4
  import FastifyCors from "@fastify/cors";
5
- import { HttpErrorHelper } from "@twin.org/api-models";
5
+ import { HttpContextIdKeys, HttpErrorHelper } from "@twin.org/api-models";
6
6
  import { JsonLdMimeTypeProcessor } from "@twin.org/api-processors";
7
7
  import { ContextIdStore } from "@twin.org/context";
8
- import { BaseError, ComponentFactory, GeneralError, Is, StringHelper } from "@twin.org/core";
9
- import { HeaderTypes, HttpMethod, HttpStatusCode } from "@twin.org/web";
8
+ import { BaseError, ComponentFactory, GeneralError, HealthStatus, Is, RandomHelper, StringHelper, Url } from "@twin.org/core";
9
+ import { HeaderTypes, HttpMethod, HttpStatusCode, HeaderHelper } from "@twin.org/web";
10
10
  import Fastify from "fastify";
11
11
  import FastifySocketIO from "./fastifySocketIo.js";
12
12
  /**
@@ -67,13 +67,23 @@ export class FastifyWebServer {
67
67
  * @internal
68
68
  */
69
69
  _includeErrorStack;
70
+ /**
71
+ * The public origin of the server, used for constructing the request URL and for CORS.
72
+ * @internal
73
+ */
74
+ _publicOrigin;
75
+ /**
76
+ * The local origin of the server, used for constructing the request URL and for CORS.
77
+ * @internal
78
+ */
79
+ _localOrigin;
70
80
  /**
71
81
  * Create a new instance of FastifyWebServer.
72
82
  * @param options The options for the server.
73
83
  */
74
84
  constructor(options) {
75
85
  this._loggingComponentType = options?.loggingComponentType;
76
- this._logging = ComponentFactory.getIfExists(options?.loggingComponentType ?? "logging");
86
+ this._logging = ComponentFactory.getIfExists(options?.loggingComponentType);
77
87
  this._fastify = Fastify({
78
88
  routerOptions: {
79
89
  maxParamLength: 2000
@@ -94,6 +104,13 @@ export class FastifyWebServer {
94
104
  }
95
105
  this._includeErrorStack = options?.config?.includeErrorStack ?? false;
96
106
  }
107
+ /**
108
+ * Returns the class name of the component.
109
+ * @returns The class name of the component.
110
+ */
111
+ className() {
112
+ return FastifyWebServer.CLASS_NAME;
113
+ }
97
114
  /**
98
115
  * Get the web server instance.
99
116
  * @returns The web server instance.
@@ -108,7 +125,7 @@ export class FastifyWebServer {
108
125
  * @param socketRouteProcessors The processors for incoming requests over Sockets.
109
126
  * @param socketRoutes The socket routes.
110
127
  * @param options Options for building the server.
111
- * @returns Nothing.
128
+ * @returns A promise that resolves when the server is fully built and ready to start.
112
129
  */
113
130
  async build(restRouteProcessors, restRoutes, socketRouteProcessors, socketRoutes, options) {
114
131
  if (Is.arrayValue(restRoutes) && !Is.arrayValue(restRouteProcessors)) {
@@ -123,6 +140,19 @@ export class FastifyWebServer {
123
140
  source: FastifyWebServer.CLASS_NAME,
124
141
  message: "building"
125
142
  });
143
+ this._localOrigin = `http://${options?.host ?? "localhost"}:${options?.port ?? 3000}`;
144
+ if (Is.stringValue(options?.publicOrigin)) {
145
+ const publicUrl = Url.tryParseExact(options.publicOrigin);
146
+ if (!Is.empty(publicUrl)) {
147
+ const urlParts = publicUrl.parts();
148
+ this._publicOrigin = `${urlParts.schema}://${urlParts.host}${Is.integer(urlParts.port) ? `:${urlParts.port}` : ""}`;
149
+ }
150
+ else {
151
+ throw new GeneralError(FastifyWebServer.CLASS_NAME, "invalidPublicOrigin", {
152
+ publicOrigin: options.publicOrigin
153
+ });
154
+ }
155
+ }
126
156
  this._options = options;
127
157
  await this._fastify.register(FastifyCompress);
128
158
  if (Is.arrayValue(socketRoutes)) {
@@ -178,7 +208,7 @@ export class FastifyWebServer {
178
208
  }
179
209
  /**
180
210
  * Start the server.
181
- * @returns Nothing.
211
+ * @returns A promise that resolves when the server is listening for connections.
182
212
  */
183
213
  async start() {
184
214
  const host = this._options?.host ?? FastifyWebServer._DEFAULT_HOST;
@@ -224,7 +254,7 @@ export class FastifyWebServer {
224
254
  }
225
255
  /**
226
256
  * Stop the server.
227
- * @returns Nothing.
257
+ * @returns A promise that resolves when the server has shut down all connections.
228
258
  */
229
259
  async stop() {
230
260
  if (this._started) {
@@ -238,6 +268,30 @@ export class FastifyWebServer {
238
268
  });
239
269
  }
240
270
  }
271
+ /**
272
+ * Perform a health check on the server by fetching its own root endpoint.
273
+ * @returns The health status of the server.
274
+ */
275
+ async health() {
276
+ let healthCheck;
277
+ if (this._fastify?.server?.listening) {
278
+ healthCheck = {
279
+ source: FastifyWebServer.CLASS_NAME,
280
+ status: HealthStatus.Ok,
281
+ description: "description",
282
+ message: "reachable"
283
+ };
284
+ }
285
+ else {
286
+ healthCheck = {
287
+ source: FastifyWebServer.CLASS_NAME,
288
+ status: HealthStatus.Error,
289
+ description: "description",
290
+ message: "unreachable"
291
+ };
292
+ }
293
+ return [healthCheck];
294
+ }
241
295
  /**
242
296
  * Add the REST routes to the server.
243
297
  * @param restRouteProcessors The processors for the incoming requests.
@@ -339,19 +393,34 @@ export class FastifyWebServer {
339
393
  * @param request The incoming request.
340
394
  * @param reply The outgoing response.
341
395
  * @param restRoute The REST route to handle.
396
+ * @returns The Fastify reply with the response.
342
397
  * @internal
343
398
  */
344
399
  async handleRequestRest(restRouteProcessors, request, reply, restRoute) {
400
+ const port = (request.port === 80 && request.protocol === "http") ||
401
+ (request.port === 443 && request.protocol === "https") ||
402
+ !Is.integer(request.port)
403
+ ? ""
404
+ : `:${request.port}`;
405
+ const requestOrigin = `${request.protocol}://${request.hostname}${port}`;
345
406
  const httpServerRequest = {
346
407
  method: request.method.toUpperCase(),
347
- url: `${request.protocol}://${request.hostname}${request.url}`,
408
+ url: `${requestOrigin}${request.url}`,
348
409
  body: request.body,
349
410
  query: request.query,
350
411
  pathParams: request.params,
351
412
  headers: request.headers
352
413
  };
353
414
  const httpResponse = {};
354
- const contextIds = {};
415
+ const contextIds = {
416
+ [HttpContextIdKeys.IpAddress]: HeaderHelper.extractClientIps(httpServerRequest.headers).join("|"),
417
+ [HttpContextIdKeys.UserAgent]: HeaderHelper.extractUserAgent(httpServerRequest.headers),
418
+ [HttpContextIdKeys.CorrelationId]: HeaderHelper.extractCorrelationId(httpServerRequest.headers),
419
+ [HttpContextIdKeys.RemoteRequest]: RandomHelper.generateUuidV7("compact"),
420
+ [HttpContextIdKeys.LocalOrigin]: this._localOrigin,
421
+ // This can be overridden by a processor if needed, for example a tenant processor
422
+ [HttpContextIdKeys.PublicOrigin]: this._publicOrigin ?? requestOrigin ?? this._localOrigin
423
+ };
355
424
  const processorState = restRoute?.processorData ?? {};
356
425
  if (Is.object(httpServerRequest.pathParams)) {
357
426
  for (const key of Object.keys(httpServerRequest.pathParams)) {
@@ -369,9 +438,7 @@ export class FastifyWebServer {
369
438
  reply.header(header, httpResponse.headers[header]);
370
439
  }
371
440
  }
372
- return reply
373
- .status((httpResponse.statusCode ?? HttpStatusCode.ok))
374
- .send(httpResponse.body);
441
+ return reply.status(httpResponse.statusCode ?? HttpStatusCode.ok).send(httpResponse.body);
375
442
  }
376
443
  /**
377
444
  * Run the REST processors for the route.
@@ -386,18 +453,29 @@ export class FastifyWebServer {
386
453
  let hasPreError = false;
387
454
  const filteredProcessors = this.filterRouteProcessors(restRoute, restRouteProcessors);
388
455
  try {
389
- for (const routeProcessor of filteredProcessors) {
390
- const pre = routeProcessor.pre?.bind(routeProcessor);
391
- if (Is.function(pre)) {
392
- await pre(httpServerRequest, httpResponse, restRoute, contextIds, processorState, this._loggingComponentType);
456
+ // Run inside ContextIdStore.run so pre-processors can do tenant-scoped storage lookups.
457
+ await ContextIdStore.run(contextIds, async () => {
458
+ for (const routeProcessor of filteredProcessors) {
459
+ const pre = routeProcessor.pre?.bind(routeProcessor);
460
+ if (Is.function(pre)) {
461
+ await pre(httpServerRequest, httpResponse, restRoute, contextIds, processorState, {
462
+ loggingComponentType: this._loggingComponentType
463
+ });
464
+ }
393
465
  }
394
- }
466
+ });
395
467
  }
396
468
  catch (err) {
397
469
  const { error, httpStatusCode } = HttpErrorHelper.processError(err, this._includeErrorStack);
398
470
  HttpErrorHelper.buildResponse(httpResponse, error, httpStatusCode);
399
471
  hasPreError = true;
400
472
  }
473
+ // A pre-processor may set an error response without throwing; treat that as halt.
474
+ if (!hasPreError &&
475
+ Is.integer(httpResponse.statusCode) &&
476
+ httpResponse.statusCode >= HttpStatusCode.badRequest) {
477
+ hasPreError = true;
478
+ }
401
479
  // Don't run the main processing if there was an error in the pre processing
402
480
  // As this is likely to perform tasks such as authentication which may have failed
403
481
  if (!hasPreError) {
@@ -408,7 +486,9 @@ export class FastifyWebServer {
408
486
  for (const routeProcessor of filteredProcessors) {
409
487
  const process = routeProcessor.process?.bind(routeProcessor);
410
488
  if (Is.function(process)) {
411
- await process(httpServerRequest, httpResponse, restRoute, processorState, this._loggingComponentType);
489
+ await process(httpServerRequest, httpResponse, restRoute, processorState, {
490
+ loggingComponentType: this._loggingComponentType
491
+ });
412
492
  }
413
493
  }
414
494
  });
@@ -416,18 +496,21 @@ export class FastifyWebServer {
416
496
  catch (err) {
417
497
  const { error, httpStatusCode } = HttpErrorHelper.processError(err, this._includeErrorStack);
418
498
  HttpErrorHelper.buildResponse(httpResponse, error, httpStatusCode);
419
- hasPreError = true;
420
499
  }
421
500
  }
422
501
  try {
423
502
  // Always run the post processors, even if there was an error earlier
424
503
  // as they may perform cleanup tasks, or logging etc
425
- for (const routeProcessor of filteredProcessors) {
426
- const post = routeProcessor.post?.bind(routeProcessor);
427
- if (Is.function(post)) {
428
- await post(httpServerRequest, httpResponse, restRoute, contextIds, processorState, this._loggingComponentType);
504
+ await ContextIdStore.run(contextIds, async () => {
505
+ for (const routeProcessor of filteredProcessors) {
506
+ const post = routeProcessor.post?.bind(routeProcessor);
507
+ if (Is.function(post)) {
508
+ await post(httpServerRequest, httpResponse, restRoute, contextIds, processorState, {
509
+ loggingComponentType: this._loggingComponentType
510
+ });
511
+ }
429
512
  }
430
- }
513
+ });
431
514
  }
432
515
  catch (err) {
433
516
  // Just log post processor errors
@@ -477,7 +560,7 @@ export class FastifyWebServer {
477
560
  * @param socket The socket to handle.
478
561
  * @param fullPath The full path of the socket route.
479
562
  * @param emitTopic The topic to emit the response on.
480
- * @param data The incoming data.
563
+ * @param request The incoming request.
481
564
  * @internal
482
565
  */
483
566
  async handleRequestSocket(socketRouteProcessors, socketRoute, socket, fullPath, emitTopic, request) {
@@ -500,7 +583,6 @@ export class FastifyWebServer {
500
583
  }
501
584
  /**
502
585
  * Run the socket processors for the route.
503
- * @param socketId The id of the socket.
504
586
  * @param socketRouteProcessors The processors to run.
505
587
  * @param socketRoute The route to process.
506
588
  * @param socketServerRequest The incoming request.
@@ -508,6 +590,7 @@ export class FastifyWebServer {
508
590
  * @param contextIds The context IDs of the request.
509
591
  * @param processorState The state handed through the processors.
510
592
  * @param requestTopic The topic of the request.
593
+ * @param responseEmitter The emitter to send the response on.
511
594
  * @internal
512
595
  */
513
596
  async runProcessorsSocket(socketRouteProcessors, socketRoute, socketServerRequest, httpResponse, contextIds, processorState, requestTopic, responseEmitter) {
@@ -520,7 +603,9 @@ export class FastifyWebServer {
520
603
  for (const postSocketRouteProcessor of filteredProcessors) {
521
604
  const post = postSocketRouteProcessor.post?.bind(postSocketRouteProcessor);
522
605
  if (Is.function(post)) {
523
- await post(socketServerRequest, response, socketRoute, contextIds, responseProcessorState, this._loggingComponentType);
606
+ await post(socketServerRequest, response, socketRoute, contextIds, responseProcessorState, {
607
+ loggingComponentType: this._loggingComponentType
608
+ });
524
609
  }
525
610
  }
526
611
  }
@@ -541,7 +626,9 @@ export class FastifyWebServer {
541
626
  for (const socketRouteProcessor of filteredProcessors) {
542
627
  const pre = socketRouteProcessor.pre?.bind(socketRouteProcessor);
543
628
  if (Is.function(pre)) {
544
- await pre(socketServerRequest, httpResponse, socketRoute, contextIds, processorState, this._loggingComponentType);
629
+ await pre(socketServerRequest, httpResponse, socketRoute, contextIds, processorState, {
630
+ loggingComponentType: this._loggingComponentType
631
+ });
545
632
  }
546
633
  }
547
634
  // We always call all the processors regardless of any response set by a previous processor.
@@ -1 +1 @@
1
- {"version":3,"file":"fastifyWebServer.js","sourceRoot":"","sources":["../../src/fastifyWebServer.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport FastifyCompress from \"@fastify/compress\";\nimport FastifyCors from \"@fastify/cors\";\nimport {\n\tHttpErrorHelper,\n\ttype IBaseRoute,\n\ttype IBaseRouteProcessor,\n\ttype IHttpRequest,\n\ttype IHttpRequestPathParams,\n\ttype IHttpRequestQuery,\n\ttype IHttpResponse,\n\ttype IHttpServerRequest,\n\ttype IMimeTypeProcessor,\n\ttype IRestRoute,\n\ttype IRestRouteProcessor,\n\ttype ISocketRoute,\n\ttype ISocketRouteProcessor,\n\ttype ISocketServerRequest,\n\ttype IWebServer,\n\ttype IWebServerOptions\n} from \"@twin.org/api-models\";\nimport { JsonLdMimeTypeProcessor } from \"@twin.org/api-processors\";\nimport { ContextIdStore, type IContextIds } from \"@twin.org/context\";\nimport {\n\tBaseError,\n\tComponentFactory,\n\tGeneralError,\n\ttype IError,\n\tIs,\n\tStringHelper\n} from \"@twin.org/core\";\nimport type { ILoggingComponent } from \"@twin.org/logging-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport { HeaderTypes, HttpMethod, HttpStatusCode, type IHttpHeaders } from \"@twin.org/web\";\nimport Fastify, {\n\ttype FastifyInstance,\n\ttype FastifyReply,\n\ttype FastifyRequest,\n\ttype FastifyServerOptions\n} from \"fastify\";\nimport type { Server, ServerOptions, Socket } from \"socket.io\";\nimport FastifySocketIO from \"./fastifySocketIo.js\";\nimport type { IFastifyWebServerConstructorOptions } from \"./models/IFastifyWebServerConstructorOptions.js\";\n\n/**\n * Implementation of the web server using Fastify.\n */\nexport class FastifyWebServer implements IWebServer<FastifyInstance> {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<FastifyWebServer>();\n\n\t/**\n\t * Default port for running the server.\n\t * @internal\n\t */\n\tprivate static readonly _DEFAULT_PORT: number = 3000;\n\n\t/**\n\t * Default host for running the server.\n\t * @internal\n\t */\n\tprivate static readonly _DEFAULT_HOST: string = \"localhost\";\n\n\t/**\n\t * The logging component type.\n\t * @internal\n\t */\n\tprivate readonly _loggingComponentType?: string;\n\n\t/**\n\t * The logging component.\n\t * @internal\n\t */\n\tprivate readonly _logging?: ILoggingComponent;\n\n\t/**\n\t * The options for the server.\n\t * @internal\n\t */\n\tprivate _options?: IWebServerOptions;\n\n\t/**\n\t * The Fastify instance.\n\t * @internal\n\t */\n\tprivate readonly _fastify: FastifyInstance;\n\n\t/**\n\t * The options for the socket server.\n\t * @internal\n\t */\n\tprivate readonly _socketConfig: Partial<ServerOptions>;\n\n\t/**\n\t * Whether the server has been started.\n\t * @internal\n\t */\n\tprivate _started: boolean;\n\n\t/**\n\t * The mime type processors.\n\t * @internal\n\t */\n\tprivate readonly _mimeTypeProcessors: IMimeTypeProcessor[];\n\n\t/**\n\t * Include the stack with errors.\n\t * @internal\n\t */\n\tprivate readonly _includeErrorStack: boolean;\n\n\t/**\n\t * Create a new instance of FastifyWebServer.\n\t * @param options The options for the server.\n\t */\n\tconstructor(options?: IFastifyWebServerConstructorOptions) {\n\t\tthis._loggingComponentType = options?.loggingComponentType;\n\t\tthis._logging = ComponentFactory.getIfExists(options?.loggingComponentType ?? \"logging\");\n\t\tthis._fastify = Fastify({\n\t\t\trouterOptions: {\n\t\t\t\tmaxParamLength: 2000\n\t\t\t},\n\t\t\t...options?.config?.web\n\t\t\t// Need this cast for now as maxParamLength has moved in to routerOptions\n\t\t\t// but the TS defs has not been updated yet\n\t\t} as unknown as FastifyServerOptions);\n\t\tthis._socketConfig = {\n\t\t\tpath: \"/socket\",\n\t\t\t...options?.config?.socket\n\t\t};\n\t\tthis._started = false;\n\n\t\tthis._mimeTypeProcessors = options?.mimeTypeProcessors ?? [];\n\n\t\tconst hasJsonLd = this._mimeTypeProcessors.find(\n\t\t\tprocessor => processor.className() === \"json-ld\"\n\t\t);\n\t\tif (!hasJsonLd) {\n\t\t\tthis._mimeTypeProcessors.push(new JsonLdMimeTypeProcessor());\n\t\t}\n\n\t\tthis._includeErrorStack = options?.config?.includeErrorStack ?? false;\n\t}\n\n\t/**\n\t * Get the web server instance.\n\t * @returns The web server instance.\n\t */\n\tpublic getInstance(): FastifyInstance {\n\t\treturn this._fastify;\n\t}\n\n\t/**\n\t * Build the server.\n\t * @param restRouteProcessors The processors for incoming requests over REST.\n\t * @param restRoutes The REST routes.\n\t * @param socketRouteProcessors The processors for incoming requests over Sockets.\n\t * @param socketRoutes The socket routes.\n\t * @param options Options for building the server.\n\t * @returns Nothing.\n\t */\n\tpublic async build(\n\t\trestRouteProcessors?: IRestRouteProcessor[],\n\t\trestRoutes?: IRestRoute[],\n\t\tsocketRouteProcessors?: ISocketRouteProcessor[],\n\t\tsocketRoutes?: ISocketRoute[],\n\t\toptions?: IWebServerOptions\n\t): Promise<void> {\n\t\tif (Is.arrayValue(restRoutes) && !Is.arrayValue(restRouteProcessors)) {\n\t\t\tthrow new GeneralError(FastifyWebServer.CLASS_NAME, \"noRestProcessors\");\n\t\t}\n\t\tif (Is.arrayValue(socketRoutes) && !Is.arrayValue(socketRouteProcessors)) {\n\t\t\tthrow new GeneralError(FastifyWebServer.CLASS_NAME, \"noSocketProcessors\");\n\t\t}\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tts: Date.now(),\n\t\t\tsource: FastifyWebServer.CLASS_NAME,\n\t\t\tmessage: \"building\"\n\t\t});\n\n\t\tthis._options = options;\n\n\t\tawait this._fastify.register(FastifyCompress);\n\n\t\tif (Is.arrayValue(socketRoutes)) {\n\t\t\tawait this._fastify.register(FastifySocketIO, this._socketConfig);\n\t\t}\n\n\t\tif (Is.arrayValue(this._mimeTypeProcessors)) {\n\t\t\tfor (const contentTypeHandler of this._mimeTypeProcessors) {\n\t\t\t\tthis._fastify.addContentTypeParser(\n\t\t\t\t\tcontentTypeHandler.getTypes(),\n\t\t\t\t\t{ parseAs: \"buffer\" },\n\t\t\t\t\t(request, body, done) => {\n\t\t\t\t\t\t// Fastify does not handle this method correctly if it is async\n\t\t\t\t\t\t// so we have to use the callback method\n\t\t\t\t\t\tcontentTypeHandler\n\t\t\t\t\t\t\t.handle(body as Buffer)\n\t\t\t\t\t\t\t// eslint-disable-next-line promise/prefer-await-to-then, promise/no-callback-in-promise\n\t\t\t\t\t\t\t.then(processed => done(null, processed))\n\t\t\t\t\t\t\t// eslint-disable-next-line promise/prefer-await-to-then, promise/no-callback-in-promise\n\t\t\t\t\t\t\t.catch(err => done(BaseError.fromError(err)));\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tawait this.initCors(options);\n\n\t\tthis._fastify.setNotFoundHandler({}, async (request, reply) =>\n\t\t\tthis.handleRequestRest(restRouteProcessors ?? [], request, reply)\n\t\t);\n\n\t\tthis._fastify.setErrorHandler(\n\t\t\tasync (\n\t\t\t\terror: Error & {\n\t\t\t\t\tcode?: number | string;\n\t\t\t\t\tstatusCode?: number | string;\n\t\t\t\t},\n\t\t\t\trequest,\n\t\t\t\treply\n\t\t\t) => {\n\t\t\t\t// If code property is set this is a fastify error\n\t\t\t\t// otherwise it's from our framework\n\t\t\t\tlet httpStatusCode: HttpStatusCode;\n\t\t\t\tlet err: IError;\n\t\t\t\tif (Is.number(error.code) || Is.string(error.code)) {\n\t\t\t\t\terr = {\n\t\t\t\t\t\tsource: FastifyWebServer.CLASS_NAME,\n\t\t\t\t\t\tname: error.name,\n\t\t\t\t\t\tmessage: `${error.code}: ${error.message}`\n\t\t\t\t\t};\n\t\t\t\t\thttpStatusCode = (error.statusCode as HttpStatusCode) ?? HttpStatusCode.badRequest;\n\t\t\t\t} else {\n\t\t\t\t\tconst errorAndCode = HttpErrorHelper.processError(error);\n\t\t\t\t\terr = errorAndCode.error;\n\t\t\t\t\thttpStatusCode = errorAndCode.httpStatusCode;\n\t\t\t\t}\n\n\t\t\t\tawait this._logging?.log({\n\t\t\t\t\tlevel: \"error\",\n\t\t\t\t\tts: Date.now(),\n\t\t\t\t\tsource: FastifyWebServer.CLASS_NAME,\n\t\t\t\t\tmessage: \"badRequest\",\n\t\t\t\t\terror: err\n\t\t\t\t});\n\n\t\t\t\treturn reply.status(httpStatusCode).send({\n\t\t\t\t\terror: err\n\t\t\t\t});\n\t\t\t}\n\t\t);\n\n\t\tawait this.addRoutesRest(restRouteProcessors, restRoutes);\n\t\tawait this.addRoutesSocket(socketRouteProcessors, socketRoutes);\n\t}\n\n\t/**\n\t * Start the server.\n\t * @returns Nothing.\n\t */\n\tpublic async start(): Promise<void> {\n\t\tconst host = this._options?.host ?? FastifyWebServer._DEFAULT_HOST;\n\t\tconst port = this._options?.port ?? FastifyWebServer._DEFAULT_PORT;\n\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tts: Date.now(),\n\t\t\tsource: FastifyWebServer.CLASS_NAME,\n\t\t\tmessage: \"starting\",\n\t\t\tdata: {\n\t\t\t\thost,\n\t\t\t\tport\n\t\t\t}\n\t\t});\n\n\t\tif (!this._started) {\n\t\t\ttry {\n\t\t\t\tawait this._fastify.listen({ port, host });\n\t\t\t\tconst addresses = this._fastify.addresses();\n\n\t\t\t\tconst protocol = Is.object(this._fastify.initialConfig.https) ? \"https://\" : \"http://\";\n\t\t\t\tawait this._logging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tts: Date.now(),\n\t\t\t\t\tsource: FastifyWebServer.CLASS_NAME,\n\t\t\t\t\tmessage: \"started\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\taddresses: addresses\n\t\t\t\t\t\t\t.map(\n\t\t\t\t\t\t\t\ta =>\n\t\t\t\t\t\t\t\t\t`${protocol}${a.family === \"IPv6\" ? \"[\" : \"\"}${a.address}${a.family === \"IPv6\" ? \"]\" : \"\"}:${a.port}`\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.join(\", \")\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tthis._started = true;\n\t\t\t} catch (err) {\n\t\t\t\tawait this._logging?.log({\n\t\t\t\t\tlevel: \"error\",\n\t\t\t\t\tts: Date.now(),\n\t\t\t\t\tsource: FastifyWebServer.CLASS_NAME,\n\t\t\t\t\tmessage: \"startFailed\",\n\t\t\t\t\terror: BaseError.fromError(err)\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Stop the server.\n\t * @returns Nothing.\n\t */\n\tpublic async stop(): Promise<void> {\n\t\tif (this._started) {\n\t\t\tthis._started = false;\n\n\t\t\tawait this._fastify.close();\n\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tts: Date.now(),\n\t\t\t\tsource: FastifyWebServer.CLASS_NAME,\n\t\t\t\tmessage: \"stopped\"\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Add the REST routes to the server.\n\t * @param restRouteProcessors The processors for the incoming requests.\n\t * @param restRoutes The REST routes to add.\n\t * @internal\n\t */\n\tprivate async addRoutesRest(\n\t\trestRouteProcessors?: IRestRouteProcessor[],\n\t\trestRoutes?: IRestRoute[]\n\t): Promise<void> {\n\t\tif (Is.arrayValue(restRouteProcessors) && Is.arrayValue(restRoutes)) {\n\t\t\tfor (const restRoute of restRoutes) {\n\t\t\t\tlet path = StringHelper.trimTrailingSlashes(restRoute.path);\n\t\t\t\tif (!path.startsWith(\"/\")) {\n\t\t\t\t\tpath = `/${path}`;\n\t\t\t\t}\n\t\t\t\tawait this._logging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tts: Date.now(),\n\t\t\t\t\tsource: FastifyWebServer.CLASS_NAME,\n\t\t\t\t\tmessage: \"restRouteAdded\",\n\t\t\t\t\tdata: { route: path, method: restRoute.method }\n\t\t\t\t});\n\t\t\t\tconst method = restRoute.method.toLowerCase() as\n\t\t\t\t\t| \"get\"\n\t\t\t\t\t| \"post\"\n\t\t\t\t\t| \"put\"\n\t\t\t\t\t| \"patch\"\n\t\t\t\t\t| \"delete\"\n\t\t\t\t\t| \"options\"\n\t\t\t\t\t| \"head\";\n\n\t\t\t\tthis._fastify[method](path, async (request, reply) =>\n\t\t\t\t\tthis.handleRequestRest(restRouteProcessors, request, reply, restRoute)\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Add the socket routes to the server.\n\t * @param socketRouteProcessors The processors for the incoming requests.\n\t * @param socketRoutes The socket routes to add.\n\t * @internal\n\t */\n\tprivate async addRoutesSocket(\n\t\tsocketRouteProcessors?: ISocketRouteProcessor[],\n\t\tsocketRoutes?: ISocketRoute[]\n\t): Promise<void> {\n\t\tif (Is.arrayValue(socketRouteProcessors) && Is.arrayValue(socketRoutes)) {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t\tconst io: Server = (this._fastify as any).io;\n\n\t\t\tfor (const socketRoute of socketRoutes) {\n\t\t\t\tconst path = StringHelper.trimLeadingSlashes(\n\t\t\t\t\tStringHelper.trimTrailingSlashes(socketRoute.path)\n\t\t\t\t);\n\t\t\t\tconst pathParts = path.split(\"/\");\n\n\t\t\t\tconst namespace = `/${pathParts[0]}`;\n\t\t\t\tconst topic = pathParts.slice(1).join(\"/\");\n\n\t\t\t\tawait this._logging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tts: Date.now(),\n\t\t\t\t\tsource: FastifyWebServer.CLASS_NAME,\n\t\t\t\t\tmessage: \"socketRouteAdded\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\thandshakePath: this._socketConfig.path,\n\t\t\t\t\t\tnamespace,\n\t\t\t\t\t\teventName: topic\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tconst socketNamespace = io.of(namespace);\n\n\t\t\t\tsocketNamespace.on(\"connection\", async socket => {\n\t\t\t\t\tconst socketServerRequest: ISocketServerRequest = {\n\t\t\t\t\t\tmethod: HttpMethod.GET,\n\t\t\t\t\t\turl: socket.handshake.url,\n\t\t\t\t\t\tquery: socket.handshake.query as IHttpRequestQuery,\n\t\t\t\t\t\theaders: socket.handshake.headers as IHttpHeaders,\n\t\t\t\t\t\tsocketId: socket.id\n\t\t\t\t\t};\n\n\t\t\t\t\t// Pass the connected information on to any processors\n\t\t\t\t\ttry {\n\t\t\t\t\t\tfor (const socketRouteProcessor of socketRouteProcessors) {\n\t\t\t\t\t\t\tif (socketRouteProcessor.connected) {\n\t\t\t\t\t\t\t\tawait socketRouteProcessor.connected(\n\t\t\t\t\t\t\t\t\tsocketServerRequest,\n\t\t\t\t\t\t\t\t\tsocketRoute,\n\t\t\t\t\t\t\t\t\tthis._loggingComponentType\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tconst { error, httpStatusCode } = HttpErrorHelper.processError(\n\t\t\t\t\t\t\terr,\n\t\t\t\t\t\t\tthis._includeErrorStack\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst response: IHttpResponse = {};\n\t\t\t\t\t\tHttpErrorHelper.buildResponse(response, error, httpStatusCode);\n\t\t\t\t\t\tsocket.emit(topic, response);\n\t\t\t\t\t}\n\n\t\t\t\t\tsocket.on(\"disconnect\", async () => {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t// The socket disconnected so notify any processors\n\t\t\t\t\t\t\tfor (const socketRouteProcessor of socketRouteProcessors) {\n\t\t\t\t\t\t\t\tif (socketRouteProcessor.disconnected) {\n\t\t\t\t\t\t\t\t\tawait socketRouteProcessor.disconnected(\n\t\t\t\t\t\t\t\t\t\tsocketServerRequest,\n\t\t\t\t\t\t\t\t\t\tsocketRoute,\n\t\t\t\t\t\t\t\t\t\tthis._loggingComponentType\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// If something fails on a disconnect there is not much we can do with it\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\t\t\t\t\t// Handle any incoming messages\n\t\t\t\t\tsocket.on(topic, async data => {\n\t\t\t\t\t\tawait this.handleRequestSocket(\n\t\t\t\t\t\t\tsocketRouteProcessors,\n\t\t\t\t\t\t\tsocketRoute,\n\t\t\t\t\t\t\tsocket,\n\t\t\t\t\t\t\t`/${pathParts.join(\"/\")}`,\n\t\t\t\t\t\t\ttopic,\n\t\t\t\t\t\t\tdata\n\t\t\t\t\t\t);\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Handle the incoming REST request.\n\t * @param restRouteProcessors The hooks to process the incoming requests.\n\t * @param request The incoming request.\n\t * @param reply The outgoing response.\n\t * @param restRoute The REST route to handle.\n\t * @internal\n\t */\n\tprivate async handleRequestRest(\n\t\trestRouteProcessors: IRestRouteProcessor[],\n\t\trequest: FastifyRequest,\n\t\treply: FastifyReply,\n\t\trestRoute?: IRestRoute\n\t): Promise<FastifyReply> {\n\t\tconst httpServerRequest: IHttpServerRequest = {\n\t\t\tmethod: request.method.toUpperCase() as HttpMethod,\n\t\t\turl: `${request.protocol}://${request.hostname}${request.url}`,\n\t\t\tbody: request.body,\n\t\t\tquery: request.query as IHttpRequestQuery,\n\t\t\tpathParams: request.params as IHttpRequestPathParams,\n\t\t\theaders: request.headers as IHttpHeaders\n\t\t};\n\t\tconst httpResponse: IHttpResponse = {};\n\t\tconst contextIds: IContextIds = {};\n\t\tconst processorState = restRoute?.processorData ?? {};\n\n\t\tif (Is.object(httpServerRequest.pathParams)) {\n\t\t\tfor (const key of Object.keys(httpServerRequest.pathParams)) {\n\t\t\t\thttpServerRequest.pathParams[key] = decodeURIComponent(httpServerRequest.pathParams[key]);\n\t\t\t}\n\t\t}\n\t\tif (Is.object(httpServerRequest.query)) {\n\t\t\tfor (const key of Object.keys(httpServerRequest.query)) {\n\t\t\t\thttpServerRequest.query[key] = decodeURIComponent(httpServerRequest.query[key]);\n\t\t\t}\n\t\t}\n\n\t\tawait this.runProcessorsRest(\n\t\t\trestRouteProcessors,\n\t\t\trestRoute,\n\t\t\thttpServerRequest,\n\t\t\thttpResponse,\n\t\t\tcontextIds,\n\t\t\tprocessorState\n\t\t);\n\n\t\tif (!Is.empty(httpResponse.headers)) {\n\t\t\tfor (const header of Object.keys(httpResponse.headers)) {\n\t\t\t\treply.header(header, httpResponse.headers[header]);\n\t\t\t}\n\t\t}\n\t\treturn reply\n\t\t\t.status((httpResponse.statusCode ?? HttpStatusCode.ok) as number)\n\t\t\t.send(httpResponse.body);\n\t}\n\n\t/**\n\t * Run the REST processors for the route.\n\t * @param restRouteProcessors The processors to run.\n\t * @param restRoute The route to process.\n\t * @param httpServerRequest The incoming request.\n\t * @param httpResponse The outgoing response.\n\t * @param contextIds The context IDs of the request.\n\t * @internal\n\t */\n\tprivate async runProcessorsRest(\n\t\trestRouteProcessors: IRestRouteProcessor[],\n\t\trestRoute: IRestRoute | undefined,\n\t\thttpServerRequest: IHttpServerRequest,\n\t\thttpResponse: IHttpResponse,\n\t\tcontextIds: IContextIds,\n\t\tprocessorState: {\n\t\t\t[id: string]: unknown;\n\t\t}\n\t): Promise<void> {\n\t\tlet hasPreError = false;\n\t\tconst filteredProcessors = this.filterRouteProcessors(restRoute, restRouteProcessors);\n\n\t\ttry {\n\t\t\tfor (const routeProcessor of filteredProcessors) {\n\t\t\t\tconst pre = routeProcessor.pre?.bind(routeProcessor);\n\t\t\t\tif (Is.function(pre)) {\n\t\t\t\t\tawait pre(\n\t\t\t\t\t\thttpServerRequest,\n\t\t\t\t\t\thttpResponse,\n\t\t\t\t\t\trestRoute,\n\t\t\t\t\t\tcontextIds,\n\t\t\t\t\t\tprocessorState,\n\t\t\t\t\t\tthis._loggingComponentType\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tconst { error, httpStatusCode } = HttpErrorHelper.processError(err, this._includeErrorStack);\n\t\t\tHttpErrorHelper.buildResponse(httpResponse, error, httpStatusCode);\n\t\t\thasPreError = true;\n\t\t}\n\n\t\t// Don't run the main processing if there was an error in the pre processing\n\t\t// As this is likely to perform tasks such as authentication which may have failed\n\t\tif (!hasPreError) {\n\t\t\ttry {\n\t\t\t\t// Run the processors within an async context\n\t\t\t\t// so that any services can access the context ids\n\t\t\t\tawait ContextIdStore.run(contextIds, async () => {\n\t\t\t\t\tfor (const routeProcessor of filteredProcessors) {\n\t\t\t\t\t\tconst process = routeProcessor.process?.bind(routeProcessor);\n\t\t\t\t\t\tif (Is.function(process)) {\n\t\t\t\t\t\t\tawait process(\n\t\t\t\t\t\t\t\thttpServerRequest,\n\t\t\t\t\t\t\t\thttpResponse,\n\t\t\t\t\t\t\t\trestRoute,\n\t\t\t\t\t\t\t\tprocessorState,\n\t\t\t\t\t\t\t\tthis._loggingComponentType\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t} catch (err) {\n\t\t\t\tconst { error, httpStatusCode } = HttpErrorHelper.processError(\n\t\t\t\t\terr,\n\t\t\t\t\tthis._includeErrorStack\n\t\t\t\t);\n\t\t\t\tHttpErrorHelper.buildResponse(httpResponse, error, httpStatusCode);\n\t\t\t\thasPreError = true;\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\t\t\t// Always run the post processors, even if there was an error earlier\n\t\t\t// as they may perform cleanup tasks, or logging etc\n\t\t\tfor (const routeProcessor of filteredProcessors) {\n\t\t\t\tconst post = routeProcessor.post?.bind(routeProcessor);\n\t\t\t\tif (Is.function(post)) {\n\t\t\t\t\tawait post(\n\t\t\t\t\t\thttpServerRequest,\n\t\t\t\t\t\thttpResponse,\n\t\t\t\t\t\trestRoute,\n\t\t\t\t\t\tcontextIds,\n\t\t\t\t\t\tprocessorState,\n\t\t\t\t\t\tthis._loggingComponentType\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (err) {\n\t\t\t// Just log post processor errors\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"error\",\n\t\t\t\tts: Date.now(),\n\t\t\t\tsource: FastifyWebServer.CLASS_NAME,\n\t\t\t\tmessage: \"postProcessorError\",\n\t\t\t\terror: BaseError.fromError(err),\n\t\t\t\tdata: {\n\t\t\t\t\troute: restRoute?.path ?? \"\"\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Filter the route processors based on the requested features.\n\t * @param route The route to process.\n\t * @param routeProcessors The processors to filter.\n\t * @returns The filtered list of route processor.\n\t * @internal\n\t */\n\tprivate filterRouteProcessors<T extends IBaseRouteProcessor>(\n\t\troute: IBaseRoute | undefined,\n\t\trouteProcessors: T[]\n\t): T[] {\n\t\tconst requestedFeatures = route?.processorFeatures ?? [];\n\n\t\tif (!Is.arrayValue(requestedFeatures)) {\n\t\t\t// If there are no requested features, we just return all the processors\n\t\t\treturn routeProcessors;\n\t\t}\n\n\t\t// Reduce the list of route processors to just those in the requested features list\n\t\tconst reducedProcessors = routeProcessors.filter(routeProcessor => {\n\t\t\t// Processors that do not define any features always get run\n\t\t\t// If the route processor has features defined, then we only run it\n\t\t\t// if the route has at least one of those features required\n\t\t\tlet runRouteProcessor = true;\n\t\t\tif (routeProcessor.features) {\n\t\t\t\tconst routeProcessorFeatures = routeProcessor.features();\n\t\t\t\trunRouteProcessor = routeProcessorFeatures.some(feature =>\n\t\t\t\t\trequestedFeatures.includes(feature)\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn runRouteProcessor;\n\t\t});\n\n\t\treturn reducedProcessors;\n\t}\n\n\t/**\n\t * Handle the incoming socket request.\n\t * @param socketRouteProcessors The hooks to process the incoming requests.\n\t * @param socketRoute The socket route to handle.\n\t * @param socket The socket to handle.\n\t * @param fullPath The full path of the socket route.\n\t * @param emitTopic The topic to emit the response on.\n\t * @param data The incoming data.\n\t * @internal\n\t */\n\tprivate async handleRequestSocket(\n\t\tsocketRouteProcessors: ISocketRouteProcessor[],\n\t\tsocketRoute: ISocketRoute,\n\t\tsocket: Socket,\n\t\tfullPath: string,\n\t\temitTopic: string,\n\t\trequest: IHttpRequest\n\t): Promise<void> {\n\t\tconst socketServerRequest: ISocketServerRequest = {\n\t\t\tmethod: HttpMethod.GET,\n\t\t\turl: fullPath,\n\t\t\tquery: socket.handshake.query as IHttpRequestQuery,\n\t\t\theaders: socket.handshake.headers as IHttpHeaders,\n\t\t\tbody: request.body,\n\t\t\tsocketId: socket.id\n\t\t};\n\t\tconst httpResponse: IHttpResponse = {};\n\t\tconst contextIds: IContextIds = {};\n\t\tconst processorState = {};\n\n\t\tdelete socketServerRequest.query?.EIO;\n\t\tdelete socketServerRequest.query?.transport;\n\n\t\tawait this.runProcessorsSocket(\n\t\t\tsocketRouteProcessors,\n\t\t\tsocketRoute,\n\t\t\tsocketServerRequest,\n\t\t\thttpResponse,\n\t\t\tcontextIds,\n\t\t\tprocessorState,\n\t\t\temitTopic,\n\t\t\tasync (topic, response) => {\n\t\t\t\tsocket.emit(topic, response);\n\t\t\t}\n\t\t);\n\t}\n\n\t/**\n\t * Run the socket processors for the route.\n\t * @param socketId The id of the socket.\n\t * @param socketRouteProcessors The processors to run.\n\t * @param socketRoute The route to process.\n\t * @param socketServerRequest The incoming request.\n\t * @param httpResponse The outgoing response.\n\t * @param contextIds The context IDs of the request.\n\t * @param processorState The state handed through the processors.\n\t * @param requestTopic The topic of the request.\n\t * @internal\n\t */\n\tprivate async runProcessorsSocket(\n\t\tsocketRouteProcessors: ISocketRouteProcessor[],\n\t\tsocketRoute: ISocketRoute,\n\t\tsocketServerRequest: ISocketServerRequest,\n\t\thttpResponse: IHttpResponse,\n\t\tcontextIds: IContextIds,\n\t\tprocessorState: {\n\t\t\t[id: string]: unknown;\n\t\t},\n\t\trequestTopic: string,\n\t\tresponseEmitter: (topic: string, response: IHttpResponse) => Promise<void>\n\t): Promise<void> {\n\t\tconst filteredProcessors = this.filterRouteProcessors(socketRoute, socketRouteProcessors);\n\n\t\t// Custom emit method which will also call the post processors\n\t\tconst postProcessEmit = async (\n\t\t\ttopic: string,\n\t\t\tresponse: IHttpResponse,\n\t\t\tresponseProcessorState: {\n\t\t\t\t[id: string]: unknown;\n\t\t\t}\n\t\t): Promise<void> => {\n\t\t\tawait responseEmitter(topic, response);\n\n\t\t\ttry {\n\t\t\t\t// The post processors are called after the response has been emitted\n\t\t\t\tfor (const postSocketRouteProcessor of filteredProcessors) {\n\t\t\t\t\tconst post = postSocketRouteProcessor.post?.bind(postSocketRouteProcessor);\n\t\t\t\t\tif (Is.function(post)) {\n\t\t\t\t\t\tawait post(\n\t\t\t\t\t\t\tsocketServerRequest,\n\t\t\t\t\t\t\tresponse,\n\t\t\t\t\t\t\tsocketRoute,\n\t\t\t\t\t\t\tcontextIds,\n\t\t\t\t\t\t\tresponseProcessorState,\n\t\t\t\t\t\t\tthis._loggingComponentType\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tawait this._logging?.log({\n\t\t\t\t\tlevel: \"error\",\n\t\t\t\t\tts: Date.now(),\n\t\t\t\t\tsource: FastifyWebServer.CLASS_NAME,\n\t\t\t\t\tmessage: \"postProcessorError\",\n\t\t\t\t\terror: BaseError.fromError(err),\n\t\t\t\t\tdata: {\n\t\t\t\t\t\troute: socketRoute.path\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t};\n\n\t\ttry {\n\t\t\tfor (const socketRouteProcessor of filteredProcessors) {\n\t\t\t\tconst pre = socketRouteProcessor.pre?.bind(socketRouteProcessor);\n\t\t\t\tif (Is.function(pre)) {\n\t\t\t\t\tawait pre(\n\t\t\t\t\t\tsocketServerRequest,\n\t\t\t\t\t\thttpResponse,\n\t\t\t\t\t\tsocketRoute,\n\t\t\t\t\t\tcontextIds,\n\t\t\t\t\t\tprocessorState,\n\t\t\t\t\t\tthis._loggingComponentType\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// We always call all the processors regardless of any response set by a previous processor.\n\t\t\t// But if a pre processor sets a status code, we will emit the response manually, as the pre\n\t\t\t// and post processors do not receive the emit method, they just populate the response object.\n\t\t\tif (!Is.empty(httpResponse.statusCode)) {\n\t\t\t\tawait postProcessEmit(requestTopic, httpResponse, processorState);\n\t\t\t}\n\n\t\t\tawait ContextIdStore.run(contextIds, async () => {\n\t\t\t\tfor (const socketRouteProcessor of filteredProcessors) {\n\t\t\t\t\tconst process = socketRouteProcessor.process?.bind(socketRouteProcessor);\n\t\t\t\t\tif (Is.function(process)) {\n\t\t\t\t\t\tawait process(\n\t\t\t\t\t\t\tsocketServerRequest,\n\t\t\t\t\t\t\thttpResponse,\n\t\t\t\t\t\t\tsocketRoute,\n\t\t\t\t\t\t\tprocessorState,\n\t\t\t\t\t\t\tasync (topic: string, processResponse: IHttpResponse) => {\n\t\t\t\t\t\t\t\tawait postProcessEmit(topic, processResponse, processorState);\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tthis._loggingComponentType\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// If the processors set the status to any kind of error then we should emit this manually\n\t\t\tif (\n\t\t\t\tIs.integer(httpResponse.statusCode) &&\n\t\t\t\thttpResponse.statusCode >= HttpStatusCode.badRequest\n\t\t\t) {\n\t\t\t\tawait postProcessEmit(requestTopic, httpResponse, processorState);\n\t\t\t}\n\t\t} catch (err) {\n\t\t\t// Emit any unhandled errors manually\n\t\t\tconst { error, httpStatusCode } = HttpErrorHelper.processError(err, this._includeErrorStack);\n\t\t\tHttpErrorHelper.buildResponse(httpResponse, error, httpStatusCode);\n\t\t\tawait postProcessEmit(requestTopic, httpResponse, processorState);\n\t\t}\n\t}\n\n\t/**\n\t * Initialize the cors options.\n\t * @param options The web server options.\n\t * @internal\n\t */\n\tprivate async initCors(options?: IWebServerOptions): Promise<void> {\n\t\tlet origins: string[] = [\"*\"];\n\n\t\tif (Is.arrayValue(options?.corsOrigins)) {\n\t\t\torigins = options?.corsOrigins;\n\t\t} else if (Is.stringValue(options?.corsOrigins)) {\n\t\t\torigins = [options?.corsOrigins];\n\t\t}\n\n\t\tconst hasWildcardOrigin = origins.includes(\"*\");\n\n\t\tconst methods = options?.methods ?? [\n\t\t\tHttpMethod.GET,\n\t\t\tHttpMethod.PUT,\n\t\t\tHttpMethod.POST,\n\t\t\tHttpMethod.DELETE,\n\t\t\tHttpMethod.OPTIONS\n\t\t];\n\t\tconst allowedHeaders = [\n\t\t\t\"Access-Control-Allow-Origin\",\n\t\t\t\"Content-Encoding\",\n\t\t\t\"Accept-Encoding\",\n\t\t\tHeaderTypes.ContentType,\n\t\t\tHeaderTypes.Authorization,\n\t\t\tHeaderTypes.Accept\n\t\t];\n\t\tconst exposedHeaders: string[] = [HeaderTypes.ContentDisposition, HeaderTypes.Location];\n\n\t\tif (Is.arrayValue(options?.allowedHeaders)) {\n\t\t\tallowedHeaders.push(...options.allowedHeaders);\n\t\t}\n\t\tif (Is.arrayValue(options?.exposedHeaders)) {\n\t\t\texposedHeaders.push(...options.exposedHeaders);\n\t\t}\n\n\t\tawait this._fastify.register(FastifyCors, {\n\t\t\torigin: (origin, callback) => {\n\t\t\t\tcallback(null, hasWildcardOrigin ? true : origins.includes(origin as string));\n\t\t\t},\n\t\t\tmethods,\n\t\t\tallowedHeaders,\n\t\t\texposedHeaders,\n\t\t\tcredentials: true\n\t\t});\n\t}\n}\n"]}
1
+ {"version":3,"file":"fastifyWebServer.js","sourceRoot":"","sources":["../../src/fastifyWebServer.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport FastifyCompress from \"@fastify/compress\";\nimport FastifyCors from \"@fastify/cors\";\nimport {\n\tHttpContextIdKeys,\n\tHttpErrorHelper,\n\ttype IBaseRoute,\n\ttype IBaseRouteProcessor,\n\ttype IHttpRequest,\n\ttype IHttpRequestPathParams,\n\ttype IHttpRequestQuery,\n\ttype IHttpResponse,\n\ttype IHttpServerRequest,\n\ttype IMimeTypeProcessor,\n\ttype IRestRoute,\n\ttype IRestRouteProcessor,\n\ttype ISocketRoute,\n\ttype ISocketRouteProcessor,\n\ttype ISocketServerRequest,\n\ttype IWebServer,\n\ttype IWebServerOptions\n} from \"@twin.org/api-models\";\nimport { JsonLdMimeTypeProcessor } from \"@twin.org/api-processors\";\nimport { ContextIdStore, type IContextIds } from \"@twin.org/context\";\nimport {\n\tBaseError,\n\tComponentFactory,\n\tGeneralError,\n\tHealthStatus,\n\ttype IError,\n\ttype IHealth,\n\tIs,\n\tRandomHelper,\n\tStringHelper,\n\tUrl\n} from \"@twin.org/core\";\nimport type { ILoggingComponent } from \"@twin.org/logging-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport {\n\tHeaderTypes,\n\tHttpMethod,\n\tHttpStatusCode,\n\ttype IHttpHeaders,\n\tHeaderHelper\n} from \"@twin.org/web\";\nimport Fastify, {\n\ttype FastifyInstance,\n\ttype FastifyReply,\n\ttype FastifyRequest,\n\ttype FastifyServerOptions\n} from \"fastify\";\nimport type { Server, ServerOptions, Socket } from \"socket.io\";\nimport FastifySocketIO from \"./fastifySocketIo.js\";\nimport type { IFastifyWebServerConstructorOptions } from \"./models/IFastifyWebServerConstructorOptions.js\";\n\n/**\n * Implementation of the web server using Fastify.\n */\nexport class FastifyWebServer implements IWebServer<FastifyInstance> {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<FastifyWebServer>();\n\n\t/**\n\t * Default port for running the server.\n\t * @internal\n\t */\n\tprivate static readonly _DEFAULT_PORT: number = 3000;\n\n\t/**\n\t * Default host for running the server.\n\t * @internal\n\t */\n\tprivate static readonly _DEFAULT_HOST: string = \"localhost\";\n\n\t/**\n\t * The logging component type.\n\t * @internal\n\t */\n\tprivate readonly _loggingComponentType?: string;\n\n\t/**\n\t * The logging component.\n\t * @internal\n\t */\n\tprivate readonly _logging?: ILoggingComponent;\n\n\t/**\n\t * The options for the server.\n\t * @internal\n\t */\n\tprivate _options?: IWebServerOptions;\n\n\t/**\n\t * The Fastify instance.\n\t * @internal\n\t */\n\tprivate readonly _fastify: FastifyInstance;\n\n\t/**\n\t * The options for the socket server.\n\t * @internal\n\t */\n\tprivate readonly _socketConfig: Partial<ServerOptions>;\n\n\t/**\n\t * Whether the server has been started.\n\t * @internal\n\t */\n\tprivate _started: boolean;\n\n\t/**\n\t * The mime type processors.\n\t * @internal\n\t */\n\tprivate readonly _mimeTypeProcessors: IMimeTypeProcessor[];\n\n\t/**\n\t * Include the stack with errors.\n\t * @internal\n\t */\n\tprivate readonly _includeErrorStack: boolean;\n\n\t/**\n\t * The public origin of the server, used for constructing the request URL and for CORS.\n\t * @internal\n\t */\n\tprivate _publicOrigin?: string;\n\n\t/**\n\t * The local origin of the server, used for constructing the request URL and for CORS.\n\t * @internal\n\t */\n\tprivate _localOrigin?: string;\n\n\t/**\n\t * Create a new instance of FastifyWebServer.\n\t * @param options The options for the server.\n\t */\n\tconstructor(options?: IFastifyWebServerConstructorOptions) {\n\t\tthis._loggingComponentType = options?.loggingComponentType;\n\t\tthis._logging = ComponentFactory.getIfExists(options?.loggingComponentType);\n\t\tthis._fastify = Fastify({\n\t\t\trouterOptions: {\n\t\t\t\tmaxParamLength: 2000\n\t\t\t},\n\t\t\t...options?.config?.web\n\t\t\t// Need this cast for now as maxParamLength has moved in to routerOptions\n\t\t\t// but the TS defs has not been updated yet\n\t\t} as unknown as FastifyServerOptions);\n\t\tthis._socketConfig = {\n\t\t\tpath: \"/socket\",\n\t\t\t...options?.config?.socket\n\t\t};\n\t\tthis._started = false;\n\n\t\tthis._mimeTypeProcessors = options?.mimeTypeProcessors ?? [];\n\n\t\tconst hasJsonLd = this._mimeTypeProcessors.find(\n\t\t\tprocessor => processor.className() === \"json-ld\"\n\t\t);\n\t\tif (!hasJsonLd) {\n\t\t\tthis._mimeTypeProcessors.push(new JsonLdMimeTypeProcessor());\n\t\t}\n\n\t\tthis._includeErrorStack = options?.config?.includeErrorStack ?? false;\n\t}\n\n\t/**\n\t * Returns the class name of the component.\n\t * @returns The class name of the component.\n\t */\n\tpublic className(): string {\n\t\treturn FastifyWebServer.CLASS_NAME;\n\t}\n\n\t/**\n\t * Get the web server instance.\n\t * @returns The web server instance.\n\t */\n\tpublic getInstance(): FastifyInstance {\n\t\treturn this._fastify;\n\t}\n\n\t/**\n\t * Build the server.\n\t * @param restRouteProcessors The processors for incoming requests over REST.\n\t * @param restRoutes The REST routes.\n\t * @param socketRouteProcessors The processors for incoming requests over Sockets.\n\t * @param socketRoutes The socket routes.\n\t * @param options Options for building the server.\n\t * @returns A promise that resolves when the server is fully built and ready to start.\n\t */\n\tpublic async build(\n\t\trestRouteProcessors?: IRestRouteProcessor[],\n\t\trestRoutes?: IRestRoute[],\n\t\tsocketRouteProcessors?: ISocketRouteProcessor[],\n\t\tsocketRoutes?: ISocketRoute[],\n\t\toptions?: IWebServerOptions\n\t): Promise<void> {\n\t\tif (Is.arrayValue(restRoutes) && !Is.arrayValue(restRouteProcessors)) {\n\t\t\tthrow new GeneralError(FastifyWebServer.CLASS_NAME, \"noRestProcessors\");\n\t\t}\n\t\tif (Is.arrayValue(socketRoutes) && !Is.arrayValue(socketRouteProcessors)) {\n\t\t\tthrow new GeneralError(FastifyWebServer.CLASS_NAME, \"noSocketProcessors\");\n\t\t}\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tts: Date.now(),\n\t\t\tsource: FastifyWebServer.CLASS_NAME,\n\t\t\tmessage: \"building\"\n\t\t});\n\n\t\tthis._localOrigin = `http://${options?.host ?? \"localhost\"}:${options?.port ?? 3000}`;\n\n\t\tif (Is.stringValue(options?.publicOrigin)) {\n\t\t\tconst publicUrl = Url.tryParseExact(options.publicOrigin);\n\t\t\tif (!Is.empty(publicUrl)) {\n\t\t\t\tconst urlParts = publicUrl.parts();\n\t\t\t\tthis._publicOrigin = `${urlParts.schema}://${urlParts.host}${Is.integer(urlParts.port) ? `:${urlParts.port}` : \"\"}`;\n\t\t\t} else {\n\t\t\t\tthrow new GeneralError(FastifyWebServer.CLASS_NAME, \"invalidPublicOrigin\", {\n\t\t\t\t\tpublicOrigin: options.publicOrigin\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tthis._options = options;\n\n\t\tawait this._fastify.register(FastifyCompress);\n\n\t\tif (Is.arrayValue(socketRoutes)) {\n\t\t\tawait this._fastify.register(FastifySocketIO, this._socketConfig);\n\t\t}\n\n\t\tif (Is.arrayValue(this._mimeTypeProcessors)) {\n\t\t\tfor (const contentTypeHandler of this._mimeTypeProcessors) {\n\t\t\t\tthis._fastify.addContentTypeParser(\n\t\t\t\t\tcontentTypeHandler.getTypes(),\n\t\t\t\t\t{ parseAs: \"buffer\" },\n\t\t\t\t\t(request, body, done) => {\n\t\t\t\t\t\t// Fastify does not handle this method correctly if it is async\n\t\t\t\t\t\t// so we have to use the callback method\n\t\t\t\t\t\tcontentTypeHandler\n\t\t\t\t\t\t\t.handle(body as Buffer)\n\t\t\t\t\t\t\t// eslint-disable-next-line promise/prefer-await-to-then, promise/no-callback-in-promise\n\t\t\t\t\t\t\t.then(processed => done(null, processed))\n\t\t\t\t\t\t\t// eslint-disable-next-line promise/prefer-await-to-then, promise/no-callback-in-promise\n\t\t\t\t\t\t\t.catch(err => done(BaseError.fromError(err)));\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tawait this.initCors(options);\n\n\t\tthis._fastify.setNotFoundHandler({}, async (request, reply) =>\n\t\t\tthis.handleRequestRest(restRouteProcessors ?? [], request, reply)\n\t\t);\n\n\t\tthis._fastify.setErrorHandler(\n\t\t\tasync (\n\t\t\t\terror: Error & {\n\t\t\t\t\tcode?: number | string;\n\t\t\t\t\tstatusCode?: number | string;\n\t\t\t\t},\n\t\t\t\trequest,\n\t\t\t\treply\n\t\t\t) => {\n\t\t\t\t// If code property is set this is a fastify error\n\t\t\t\t// otherwise it's from our framework\n\t\t\t\tlet httpStatusCode: HttpStatusCode;\n\t\t\t\tlet err: IError;\n\t\t\t\tif (Is.number(error.code) || Is.string(error.code)) {\n\t\t\t\t\terr = {\n\t\t\t\t\t\tsource: FastifyWebServer.CLASS_NAME,\n\t\t\t\t\t\tname: error.name,\n\t\t\t\t\t\tmessage: `${error.code}: ${error.message}`\n\t\t\t\t\t};\n\t\t\t\t\thttpStatusCode = (error.statusCode as HttpStatusCode) ?? HttpStatusCode.badRequest;\n\t\t\t\t} else {\n\t\t\t\t\tconst errorAndCode = HttpErrorHelper.processError(error);\n\t\t\t\t\terr = errorAndCode.error;\n\t\t\t\t\thttpStatusCode = errorAndCode.httpStatusCode;\n\t\t\t\t}\n\n\t\t\t\tawait this._logging?.log({\n\t\t\t\t\tlevel: \"error\",\n\t\t\t\t\tts: Date.now(),\n\t\t\t\t\tsource: FastifyWebServer.CLASS_NAME,\n\t\t\t\t\tmessage: \"badRequest\",\n\t\t\t\t\terror: err\n\t\t\t\t});\n\n\t\t\t\treturn reply.status(httpStatusCode).send({\n\t\t\t\t\terror: err\n\t\t\t\t});\n\t\t\t}\n\t\t);\n\n\t\tawait this.addRoutesRest(restRouteProcessors, restRoutes);\n\t\tawait this.addRoutesSocket(socketRouteProcessors, socketRoutes);\n\t}\n\n\t/**\n\t * Start the server.\n\t * @returns A promise that resolves when the server is listening for connections.\n\t */\n\tpublic async start(): Promise<void> {\n\t\tconst host = this._options?.host ?? FastifyWebServer._DEFAULT_HOST;\n\t\tconst port = this._options?.port ?? FastifyWebServer._DEFAULT_PORT;\n\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tts: Date.now(),\n\t\t\tsource: FastifyWebServer.CLASS_NAME,\n\t\t\tmessage: \"starting\",\n\t\t\tdata: {\n\t\t\t\thost,\n\t\t\t\tport\n\t\t\t}\n\t\t});\n\n\t\tif (!this._started) {\n\t\t\ttry {\n\t\t\t\tawait this._fastify.listen({ port, host });\n\t\t\t\tconst addresses = this._fastify.addresses();\n\n\t\t\t\tconst protocol = Is.object(this._fastify.initialConfig.https) ? \"https://\" : \"http://\";\n\t\t\t\tawait this._logging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tts: Date.now(),\n\t\t\t\t\tsource: FastifyWebServer.CLASS_NAME,\n\t\t\t\t\tmessage: \"started\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\taddresses: addresses\n\t\t\t\t\t\t\t.map(\n\t\t\t\t\t\t\t\ta =>\n\t\t\t\t\t\t\t\t\t`${protocol}${a.family === \"IPv6\" ? \"[\" : \"\"}${a.address}${a.family === \"IPv6\" ? \"]\" : \"\"}:${a.port}`\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.join(\", \")\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tthis._started = true;\n\t\t\t} catch (err) {\n\t\t\t\tawait this._logging?.log({\n\t\t\t\t\tlevel: \"error\",\n\t\t\t\t\tts: Date.now(),\n\t\t\t\t\tsource: FastifyWebServer.CLASS_NAME,\n\t\t\t\t\tmessage: \"startFailed\",\n\t\t\t\t\terror: BaseError.fromError(err)\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Stop the server.\n\t * @returns A promise that resolves when the server has shut down all connections.\n\t */\n\tpublic async stop(): Promise<void> {\n\t\tif (this._started) {\n\t\t\tthis._started = false;\n\n\t\t\tawait this._fastify.close();\n\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tts: Date.now(),\n\t\t\t\tsource: FastifyWebServer.CLASS_NAME,\n\t\t\t\tmessage: \"stopped\"\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Perform a health check on the server by fetching its own root endpoint.\n\t * @returns The health status of the server.\n\t */\n\tpublic async health(): Promise<IHealth[]> {\n\t\tlet healthCheck: IHealth | undefined;\n\t\tif (this._fastify?.server?.listening) {\n\t\t\thealthCheck = {\n\t\t\t\tsource: FastifyWebServer.CLASS_NAME,\n\t\t\t\tstatus: HealthStatus.Ok,\n\t\t\t\tdescription: \"description\",\n\t\t\t\tmessage: \"reachable\"\n\t\t\t};\n\t\t} else {\n\t\t\thealthCheck = {\n\t\t\t\tsource: FastifyWebServer.CLASS_NAME,\n\t\t\t\tstatus: HealthStatus.Error,\n\t\t\t\tdescription: \"description\",\n\t\t\t\tmessage: \"unreachable\"\n\t\t\t};\n\t\t}\n\n\t\treturn [healthCheck];\n\t}\n\n\t/**\n\t * Add the REST routes to the server.\n\t * @param restRouteProcessors The processors for the incoming requests.\n\t * @param restRoutes The REST routes to add.\n\t * @internal\n\t */\n\tprivate async addRoutesRest(\n\t\trestRouteProcessors?: IRestRouteProcessor[],\n\t\trestRoutes?: IRestRoute[]\n\t): Promise<void> {\n\t\tif (Is.arrayValue(restRouteProcessors) && Is.arrayValue(restRoutes)) {\n\t\t\tfor (const restRoute of restRoutes) {\n\t\t\t\tlet path = StringHelper.trimTrailingSlashes(restRoute.path);\n\t\t\t\tif (!path.startsWith(\"/\")) {\n\t\t\t\t\tpath = `/${path}`;\n\t\t\t\t}\n\t\t\t\tawait this._logging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tts: Date.now(),\n\t\t\t\t\tsource: FastifyWebServer.CLASS_NAME,\n\t\t\t\t\tmessage: \"restRouteAdded\",\n\t\t\t\t\tdata: { route: path, method: restRoute.method }\n\t\t\t\t});\n\t\t\t\tconst method = restRoute.method.toLowerCase() as\n\t\t\t\t\t| \"get\"\n\t\t\t\t\t| \"post\"\n\t\t\t\t\t| \"put\"\n\t\t\t\t\t| \"patch\"\n\t\t\t\t\t| \"delete\"\n\t\t\t\t\t| \"options\"\n\t\t\t\t\t| \"head\";\n\n\t\t\t\tthis._fastify[method](path, async (request, reply) =>\n\t\t\t\t\tthis.handleRequestRest(restRouteProcessors, request, reply, restRoute)\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Add the socket routes to the server.\n\t * @param socketRouteProcessors The processors for the incoming requests.\n\t * @param socketRoutes The socket routes to add.\n\t * @internal\n\t */\n\tprivate async addRoutesSocket(\n\t\tsocketRouteProcessors?: ISocketRouteProcessor[],\n\t\tsocketRoutes?: ISocketRoute[]\n\t): Promise<void> {\n\t\tif (Is.arrayValue(socketRouteProcessors) && Is.arrayValue(socketRoutes)) {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t\tconst io: Server = (this._fastify as any).io;\n\n\t\t\tfor (const socketRoute of socketRoutes) {\n\t\t\t\tconst path = StringHelper.trimLeadingSlashes(\n\t\t\t\t\tStringHelper.trimTrailingSlashes(socketRoute.path)\n\t\t\t\t);\n\t\t\t\tconst pathParts = path.split(\"/\");\n\n\t\t\t\tconst namespace = `/${pathParts[0]}`;\n\t\t\t\tconst topic = pathParts.slice(1).join(\"/\");\n\n\t\t\t\tawait this._logging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tts: Date.now(),\n\t\t\t\t\tsource: FastifyWebServer.CLASS_NAME,\n\t\t\t\t\tmessage: \"socketRouteAdded\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\thandshakePath: this._socketConfig.path,\n\t\t\t\t\t\tnamespace,\n\t\t\t\t\t\teventName: topic\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tconst socketNamespace = io.of(namespace);\n\n\t\t\t\tsocketNamespace.on(\"connection\", async socket => {\n\t\t\t\t\tconst socketServerRequest: ISocketServerRequest = {\n\t\t\t\t\t\tmethod: HttpMethod.GET,\n\t\t\t\t\t\turl: socket.handshake.url,\n\t\t\t\t\t\tquery: socket.handshake.query as IHttpRequestQuery,\n\t\t\t\t\t\theaders: socket.handshake.headers as IHttpHeaders,\n\t\t\t\t\t\tsocketId: socket.id\n\t\t\t\t\t};\n\n\t\t\t\t\t// Pass the connected information on to any processors\n\t\t\t\t\ttry {\n\t\t\t\t\t\tfor (const socketRouteProcessor of socketRouteProcessors) {\n\t\t\t\t\t\t\tif (socketRouteProcessor.connected) {\n\t\t\t\t\t\t\t\tawait socketRouteProcessor.connected(\n\t\t\t\t\t\t\t\t\tsocketServerRequest,\n\t\t\t\t\t\t\t\t\tsocketRoute,\n\t\t\t\t\t\t\t\t\tthis._loggingComponentType\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tconst { error, httpStatusCode } = HttpErrorHelper.processError(\n\t\t\t\t\t\t\terr,\n\t\t\t\t\t\t\tthis._includeErrorStack\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst response: IHttpResponse = {};\n\t\t\t\t\t\tHttpErrorHelper.buildResponse(response, error, httpStatusCode);\n\t\t\t\t\t\tsocket.emit(topic, response);\n\t\t\t\t\t}\n\n\t\t\t\t\tsocket.on(\"disconnect\", async () => {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t// The socket disconnected so notify any processors\n\t\t\t\t\t\t\tfor (const socketRouteProcessor of socketRouteProcessors) {\n\t\t\t\t\t\t\t\tif (socketRouteProcessor.disconnected) {\n\t\t\t\t\t\t\t\t\tawait socketRouteProcessor.disconnected(\n\t\t\t\t\t\t\t\t\t\tsocketServerRequest,\n\t\t\t\t\t\t\t\t\t\tsocketRoute,\n\t\t\t\t\t\t\t\t\t\tthis._loggingComponentType\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// If something fails on a disconnect there is not much we can do with it\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\t\t\t\t\t// Handle any incoming messages\n\t\t\t\t\tsocket.on(topic, async data => {\n\t\t\t\t\t\tawait this.handleRequestSocket(\n\t\t\t\t\t\t\tsocketRouteProcessors,\n\t\t\t\t\t\t\tsocketRoute,\n\t\t\t\t\t\t\tsocket,\n\t\t\t\t\t\t\t`/${pathParts.join(\"/\")}`,\n\t\t\t\t\t\t\ttopic,\n\t\t\t\t\t\t\tdata\n\t\t\t\t\t\t);\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Handle the incoming REST request.\n\t * @param restRouteProcessors The hooks to process the incoming requests.\n\t * @param request The incoming request.\n\t * @param reply The outgoing response.\n\t * @param restRoute The REST route to handle.\n\t * @returns The Fastify reply with the response.\n\t * @internal\n\t */\n\tprivate async handleRequestRest(\n\t\trestRouteProcessors: IRestRouteProcessor[],\n\t\trequest: FastifyRequest,\n\t\treply: FastifyReply,\n\t\trestRoute?: IRestRoute\n\t): Promise<FastifyReply> {\n\t\tconst port =\n\t\t\t(request.port === 80 && request.protocol === \"http\") ||\n\t\t\t(request.port === 443 && request.protocol === \"https\") ||\n\t\t\t!Is.integer(request.port)\n\t\t\t\t? \"\"\n\t\t\t\t: `:${request.port}`;\n\n\t\tconst requestOrigin = `${request.protocol}://${request.hostname}${port}`;\n\n\t\tconst httpServerRequest: IHttpServerRequest = {\n\t\t\tmethod: request.method.toUpperCase() as HttpMethod,\n\t\t\turl: `${requestOrigin}${request.url}`,\n\t\t\tbody: request.body,\n\t\t\tquery: request.query as IHttpRequestQuery,\n\t\t\tpathParams: request.params as IHttpRequestPathParams,\n\t\t\theaders: request.headers as IHttpHeaders\n\t\t};\n\n\t\tconst httpResponse: IHttpResponse = {};\n\t\tconst contextIds: IContextIds = {\n\t\t\t[HttpContextIdKeys.IpAddress]: HeaderHelper.extractClientIps(httpServerRequest.headers).join(\n\t\t\t\t\"|\"\n\t\t\t),\n\t\t\t[HttpContextIdKeys.UserAgent]: HeaderHelper.extractUserAgent(httpServerRequest.headers),\n\t\t\t[HttpContextIdKeys.CorrelationId]: HeaderHelper.extractCorrelationId(\n\t\t\t\thttpServerRequest.headers\n\t\t\t),\n\t\t\t[HttpContextIdKeys.RemoteRequest]: RandomHelper.generateUuidV7(\"compact\"),\n\t\t\t[HttpContextIdKeys.LocalOrigin]: this._localOrigin,\n\t\t\t// This can be overridden by a processor if needed, for example a tenant processor\n\t\t\t[HttpContextIdKeys.PublicOrigin]: this._publicOrigin ?? requestOrigin ?? this._localOrigin\n\t\t};\n\t\tconst processorState = restRoute?.processorData ?? {};\n\n\t\tif (Is.object(httpServerRequest.pathParams)) {\n\t\t\tfor (const key of Object.keys(httpServerRequest.pathParams)) {\n\t\t\t\thttpServerRequest.pathParams[key] = decodeURIComponent(httpServerRequest.pathParams[key]);\n\t\t\t}\n\t\t}\n\t\tif (Is.object(httpServerRequest.query)) {\n\t\t\tfor (const key of Object.keys(httpServerRequest.query)) {\n\t\t\t\thttpServerRequest.query[key] = decodeURIComponent(httpServerRequest.query[key]);\n\t\t\t}\n\t\t}\n\n\t\tawait this.runProcessorsRest(\n\t\t\trestRouteProcessors,\n\t\t\trestRoute,\n\t\t\thttpServerRequest,\n\t\t\thttpResponse,\n\t\t\tcontextIds,\n\t\t\tprocessorState\n\t\t);\n\n\t\tif (!Is.empty(httpResponse.headers)) {\n\t\t\tfor (const header of Object.keys(httpResponse.headers)) {\n\t\t\t\treply.header(header, httpResponse.headers[header]);\n\t\t\t}\n\t\t}\n\t\treturn reply.status(httpResponse.statusCode ?? HttpStatusCode.ok).send(httpResponse.body);\n\t}\n\n\t/**\n\t * Run the REST processors for the route.\n\t * @param restRouteProcessors The processors to run.\n\t * @param restRoute The route to process.\n\t * @param httpServerRequest The incoming request.\n\t * @param httpResponse The outgoing response.\n\t * @param contextIds The context IDs of the request.\n\t * @internal\n\t */\n\tprivate async runProcessorsRest(\n\t\trestRouteProcessors: IRestRouteProcessor[],\n\t\trestRoute: IRestRoute | undefined,\n\t\thttpServerRequest: IHttpServerRequest,\n\t\thttpResponse: IHttpResponse,\n\t\tcontextIds: IContextIds,\n\t\tprocessorState: {\n\t\t\t[id: string]: unknown;\n\t\t}\n\t): Promise<void> {\n\t\tlet hasPreError = false;\n\t\tconst filteredProcessors = this.filterRouteProcessors(restRoute, restRouteProcessors);\n\n\t\ttry {\n\t\t\t// Run inside ContextIdStore.run so pre-processors can do tenant-scoped storage lookups.\n\t\t\tawait ContextIdStore.run(contextIds, async () => {\n\t\t\t\tfor (const routeProcessor of filteredProcessors) {\n\t\t\t\t\tconst pre = routeProcessor.pre?.bind(routeProcessor);\n\t\t\t\t\tif (Is.function(pre)) {\n\t\t\t\t\t\tawait pre(httpServerRequest, httpResponse, restRoute, contextIds, processorState, {\n\t\t\t\t\t\t\tloggingComponentType: this._loggingComponentType\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t} catch (err) {\n\t\t\tconst { error, httpStatusCode } = HttpErrorHelper.processError(err, this._includeErrorStack);\n\t\t\tHttpErrorHelper.buildResponse(httpResponse, error, httpStatusCode);\n\t\t\thasPreError = true;\n\t\t}\n\n\t\t// A pre-processor may set an error response without throwing; treat that as halt.\n\t\tif (\n\t\t\t!hasPreError &&\n\t\t\tIs.integer(httpResponse.statusCode) &&\n\t\t\thttpResponse.statusCode >= HttpStatusCode.badRequest\n\t\t) {\n\t\t\thasPreError = true;\n\t\t}\n\n\t\t// Don't run the main processing if there was an error in the pre processing\n\t\t// As this is likely to perform tasks such as authentication which may have failed\n\t\tif (!hasPreError) {\n\t\t\ttry {\n\t\t\t\t// Run the processors within an async context\n\t\t\t\t// so that any services can access the context ids\n\t\t\t\tawait ContextIdStore.run(contextIds, async () => {\n\t\t\t\t\tfor (const routeProcessor of filteredProcessors) {\n\t\t\t\t\t\tconst process = routeProcessor.process?.bind(routeProcessor);\n\t\t\t\t\t\tif (Is.function(process)) {\n\t\t\t\t\t\t\tawait process(httpServerRequest, httpResponse, restRoute, processorState, {\n\t\t\t\t\t\t\t\tloggingComponentType: this._loggingComponentType\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t} catch (err) {\n\t\t\t\tconst { error, httpStatusCode } = HttpErrorHelper.processError(\n\t\t\t\t\terr,\n\t\t\t\t\tthis._includeErrorStack\n\t\t\t\t);\n\t\t\t\tHttpErrorHelper.buildResponse(httpResponse, error, httpStatusCode);\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\t\t\t// Always run the post processors, even if there was an error earlier\n\t\t\t// as they may perform cleanup tasks, or logging etc\n\t\t\tawait ContextIdStore.run(contextIds, async () => {\n\t\t\t\tfor (const routeProcessor of filteredProcessors) {\n\t\t\t\t\tconst post = routeProcessor.post?.bind(routeProcessor);\n\t\t\t\t\tif (Is.function(post)) {\n\t\t\t\t\t\tawait post(httpServerRequest, httpResponse, restRoute, contextIds, processorState, {\n\t\t\t\t\t\t\tloggingComponentType: this._loggingComponentType\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t} catch (err) {\n\t\t\t// Just log post processor errors\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"error\",\n\t\t\t\tts: Date.now(),\n\t\t\t\tsource: FastifyWebServer.CLASS_NAME,\n\t\t\t\tmessage: \"postProcessorError\",\n\t\t\t\terror: BaseError.fromError(err),\n\t\t\t\tdata: {\n\t\t\t\t\troute: restRoute?.path ?? \"\"\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Filter the route processors based on the requested features.\n\t * @param route The route to process.\n\t * @param routeProcessors The processors to filter.\n\t * @returns The filtered list of route processor.\n\t * @internal\n\t */\n\tprivate filterRouteProcessors<T extends IBaseRouteProcessor>(\n\t\troute: IBaseRoute | undefined,\n\t\trouteProcessors: T[]\n\t): T[] {\n\t\tconst requestedFeatures = route?.processorFeatures ?? [];\n\n\t\tif (!Is.arrayValue(requestedFeatures)) {\n\t\t\t// If there are no requested features, we just return all the processors\n\t\t\treturn routeProcessors;\n\t\t}\n\n\t\t// Reduce the list of route processors to just those in the requested features list\n\t\tconst reducedProcessors = routeProcessors.filter(routeProcessor => {\n\t\t\t// Processors that do not define any features always get run\n\t\t\t// If the route processor has features defined, then we only run it\n\t\t\t// if the route has at least one of those features required\n\t\t\tlet runRouteProcessor = true;\n\t\t\tif (routeProcessor.features) {\n\t\t\t\tconst routeProcessorFeatures = routeProcessor.features();\n\t\t\t\trunRouteProcessor = routeProcessorFeatures.some(feature =>\n\t\t\t\t\trequestedFeatures.includes(feature)\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn runRouteProcessor;\n\t\t});\n\n\t\treturn reducedProcessors;\n\t}\n\n\t/**\n\t * Handle the incoming socket request.\n\t * @param socketRouteProcessors The hooks to process the incoming requests.\n\t * @param socketRoute The socket route to handle.\n\t * @param socket The socket to handle.\n\t * @param fullPath The full path of the socket route.\n\t * @param emitTopic The topic to emit the response on.\n\t * @param request The incoming request.\n\t * @internal\n\t */\n\tprivate async handleRequestSocket(\n\t\tsocketRouteProcessors: ISocketRouteProcessor[],\n\t\tsocketRoute: ISocketRoute,\n\t\tsocket: Socket,\n\t\tfullPath: string,\n\t\temitTopic: string,\n\t\trequest: IHttpRequest\n\t): Promise<void> {\n\t\tconst socketServerRequest: ISocketServerRequest = {\n\t\t\tmethod: HttpMethod.GET,\n\t\t\turl: fullPath,\n\t\t\tquery: socket.handshake.query as IHttpRequestQuery,\n\t\t\theaders: socket.handshake.headers as IHttpHeaders,\n\t\t\tbody: request.body,\n\t\t\tsocketId: socket.id\n\t\t};\n\t\tconst httpResponse: IHttpResponse = {};\n\t\tconst contextIds: IContextIds = {};\n\t\tconst processorState = {};\n\n\t\tdelete socketServerRequest.query?.EIO;\n\t\tdelete socketServerRequest.query?.transport;\n\n\t\tawait this.runProcessorsSocket(\n\t\t\tsocketRouteProcessors,\n\t\t\tsocketRoute,\n\t\t\tsocketServerRequest,\n\t\t\thttpResponse,\n\t\t\tcontextIds,\n\t\t\tprocessorState,\n\t\t\temitTopic,\n\t\t\tasync (topic, response) => {\n\t\t\t\tsocket.emit(topic, response);\n\t\t\t}\n\t\t);\n\t}\n\n\t/**\n\t * Run the socket processors for the route.\n\t * @param socketRouteProcessors The processors to run.\n\t * @param socketRoute The route to process.\n\t * @param socketServerRequest The incoming request.\n\t * @param httpResponse The outgoing response.\n\t * @param contextIds The context IDs of the request.\n\t * @param processorState The state handed through the processors.\n\t * @param requestTopic The topic of the request.\n\t * @param responseEmitter The emitter to send the response on.\n\t * @internal\n\t */\n\tprivate async runProcessorsSocket(\n\t\tsocketRouteProcessors: ISocketRouteProcessor[],\n\t\tsocketRoute: ISocketRoute,\n\t\tsocketServerRequest: ISocketServerRequest,\n\t\thttpResponse: IHttpResponse,\n\t\tcontextIds: IContextIds,\n\t\tprocessorState: {\n\t\t\t[id: string]: unknown;\n\t\t},\n\t\trequestTopic: string,\n\t\tresponseEmitter: (topic: string, response: IHttpResponse) => Promise<void>\n\t): Promise<void> {\n\t\tconst filteredProcessors = this.filterRouteProcessors(socketRoute, socketRouteProcessors);\n\n\t\t// Custom emit method which will also call the post processors\n\t\tconst postProcessEmit = async (\n\t\t\ttopic: string,\n\t\t\tresponse: IHttpResponse,\n\t\t\tresponseProcessorState: {\n\t\t\t\t[id: string]: unknown;\n\t\t\t}\n\t\t): Promise<void> => {\n\t\t\tawait responseEmitter(topic, response);\n\n\t\t\ttry {\n\t\t\t\t// The post processors are called after the response has been emitted\n\t\t\t\tfor (const postSocketRouteProcessor of filteredProcessors) {\n\t\t\t\t\tconst post = postSocketRouteProcessor.post?.bind(postSocketRouteProcessor);\n\t\t\t\t\tif (Is.function(post)) {\n\t\t\t\t\t\tawait post(\n\t\t\t\t\t\t\tsocketServerRequest,\n\t\t\t\t\t\t\tresponse,\n\t\t\t\t\t\t\tsocketRoute,\n\t\t\t\t\t\t\tcontextIds,\n\t\t\t\t\t\t\tresponseProcessorState,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tloggingComponentType: this._loggingComponentType\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tawait this._logging?.log({\n\t\t\t\t\tlevel: \"error\",\n\t\t\t\t\tts: Date.now(),\n\t\t\t\t\tsource: FastifyWebServer.CLASS_NAME,\n\t\t\t\t\tmessage: \"postProcessorError\",\n\t\t\t\t\terror: BaseError.fromError(err),\n\t\t\t\t\tdata: {\n\t\t\t\t\t\troute: socketRoute.path\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t};\n\n\t\ttry {\n\t\t\tfor (const socketRouteProcessor of filteredProcessors) {\n\t\t\t\tconst pre = socketRouteProcessor.pre?.bind(socketRouteProcessor);\n\t\t\t\tif (Is.function(pre)) {\n\t\t\t\t\tawait pre(socketServerRequest, httpResponse, socketRoute, contextIds, processorState, {\n\t\t\t\t\t\tloggingComponentType: this._loggingComponentType\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// We always call all the processors regardless of any response set by a previous processor.\n\t\t\t// But if a pre processor sets a status code, we will emit the response manually, as the pre\n\t\t\t// and post processors do not receive the emit method, they just populate the response object.\n\t\t\tif (!Is.empty(httpResponse.statusCode)) {\n\t\t\t\tawait postProcessEmit(requestTopic, httpResponse, processorState);\n\t\t\t}\n\n\t\t\tawait ContextIdStore.run(contextIds, async () => {\n\t\t\t\tfor (const socketRouteProcessor of filteredProcessors) {\n\t\t\t\t\tconst process = socketRouteProcessor.process?.bind(socketRouteProcessor);\n\t\t\t\t\tif (Is.function(process)) {\n\t\t\t\t\t\tawait process(\n\t\t\t\t\t\t\tsocketServerRequest,\n\t\t\t\t\t\t\thttpResponse,\n\t\t\t\t\t\t\tsocketRoute,\n\t\t\t\t\t\t\tprocessorState,\n\t\t\t\t\t\t\tasync (topic: string, processResponse: IHttpResponse) => {\n\t\t\t\t\t\t\t\tawait postProcessEmit(topic, processResponse, processorState);\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tthis._loggingComponentType\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// If the processors set the status to any kind of error then we should emit this manually\n\t\t\tif (\n\t\t\t\tIs.integer(httpResponse.statusCode) &&\n\t\t\t\thttpResponse.statusCode >= HttpStatusCode.badRequest\n\t\t\t) {\n\t\t\t\tawait postProcessEmit(requestTopic, httpResponse, processorState);\n\t\t\t}\n\t\t} catch (err) {\n\t\t\t// Emit any unhandled errors manually\n\t\t\tconst { error, httpStatusCode } = HttpErrorHelper.processError(err, this._includeErrorStack);\n\t\t\tHttpErrorHelper.buildResponse(httpResponse, error, httpStatusCode);\n\t\t\tawait postProcessEmit(requestTopic, httpResponse, processorState);\n\t\t}\n\t}\n\n\t/**\n\t * Initialize the cors options.\n\t * @param options The web server options.\n\t * @internal\n\t */\n\tprivate async initCors(options?: IWebServerOptions): Promise<void> {\n\t\tlet origins: string[] = [\"*\"];\n\n\t\tif (Is.arrayValue(options?.corsOrigins)) {\n\t\t\torigins = options?.corsOrigins;\n\t\t} else if (Is.stringValue(options?.corsOrigins)) {\n\t\t\torigins = [options?.corsOrigins];\n\t\t}\n\n\t\tconst hasWildcardOrigin = origins.includes(\"*\");\n\n\t\tconst methods = options?.methods ?? [\n\t\t\tHttpMethod.GET,\n\t\t\tHttpMethod.PUT,\n\t\t\tHttpMethod.POST,\n\t\t\tHttpMethod.DELETE,\n\t\t\tHttpMethod.OPTIONS\n\t\t];\n\t\tconst allowedHeaders = [\n\t\t\t\"Access-Control-Allow-Origin\",\n\t\t\t\"Content-Encoding\",\n\t\t\t\"Accept-Encoding\",\n\t\t\tHeaderTypes.ContentType,\n\t\t\tHeaderTypes.Authorization,\n\t\t\tHeaderTypes.Accept\n\t\t];\n\t\tconst exposedHeaders: string[] = [HeaderTypes.ContentDisposition, HeaderTypes.Location];\n\n\t\tif (Is.arrayValue(options?.allowedHeaders)) {\n\t\t\tallowedHeaders.push(...options.allowedHeaders);\n\t\t}\n\t\tif (Is.arrayValue(options?.exposedHeaders)) {\n\t\t\texposedHeaders.push(...options.exposedHeaders);\n\t\t}\n\n\t\tawait this._fastify.register(FastifyCors, {\n\t\t\torigin: (origin, callback) => {\n\t\t\t\tcallback(null, hasWildcardOrigin ? true : origins.includes(origin as string));\n\t\t\t},\n\t\t\tmethods,\n\t\t\tallowedHeaders,\n\t\t\texposedHeaders,\n\t\t\tcredentials: true\n\t\t});\n\t}\n}\n"]}
@@ -1,4 +1,8 @@
1
1
  import type { FastifyPluginAsync } from "fastify";
2
2
  import { type ServerOptions } from "socket.io";
3
+ /**
4
+ * Fastify plugin that attaches a Socket.IO server to the Fastify HTTP server.
5
+ * Cloned from fastify-socket.io to support recent Fastify versions.
6
+ */
3
7
  declare const fastifySocketIO: FastifyPluginAsync<Partial<ServerOptions>>;
4
8
  export default fastifySocketIO;
@@ -1,4 +1,5 @@
1
1
  import { type IRestRoute, type IRestRouteProcessor, type ISocketRoute, type ISocketRouteProcessor, type IWebServer, type IWebServerOptions } from "@twin.org/api-models";
2
+ import { type IHealth } from "@twin.org/core";
2
3
  import { type FastifyInstance } from "fastify";
3
4
  import type { IFastifyWebServerConstructorOptions } from "./models/IFastifyWebServerConstructorOptions.js";
4
5
  /**
@@ -14,6 +15,11 @@ export declare class FastifyWebServer implements IWebServer<FastifyInstance> {
14
15
  * @param options The options for the server.
15
16
  */
16
17
  constructor(options?: IFastifyWebServerConstructorOptions);
18
+ /**
19
+ * Returns the class name of the component.
20
+ * @returns The class name of the component.
21
+ */
22
+ className(): string;
17
23
  /**
18
24
  * Get the web server instance.
19
25
  * @returns The web server instance.
@@ -26,17 +32,22 @@ export declare class FastifyWebServer implements IWebServer<FastifyInstance> {
26
32
  * @param socketRouteProcessors The processors for incoming requests over Sockets.
27
33
  * @param socketRoutes The socket routes.
28
34
  * @param options Options for building the server.
29
- * @returns Nothing.
35
+ * @returns A promise that resolves when the server is fully built and ready to start.
30
36
  */
31
37
  build(restRouteProcessors?: IRestRouteProcessor[], restRoutes?: IRestRoute[], socketRouteProcessors?: ISocketRouteProcessor[], socketRoutes?: ISocketRoute[], options?: IWebServerOptions): Promise<void>;
32
38
  /**
33
39
  * Start the server.
34
- * @returns Nothing.
40
+ * @returns A promise that resolves when the server is listening for connections.
35
41
  */
36
42
  start(): Promise<void>;
37
43
  /**
38
44
  * Stop the server.
39
- * @returns Nothing.
45
+ * @returns A promise that resolves when the server has shut down all connections.
40
46
  */
41
47
  stop(): Promise<void>;
48
+ /**
49
+ * Perform a health check on the server by fetching its own root endpoint.
50
+ * @returns The health status of the server.
51
+ */
52
+ health(): Promise<IHealth[]>;
42
53
  }