@bool-ts/core 1.7.16 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/.prettierrc +1 -1
  2. package/__test/controller.ts +1 -1
  3. package/__test/index.ts +4 -1
  4. package/__test/module.ts +3 -1
  5. package/__test/tsconfig.json +109 -0
  6. package/__test/webSocket.ts +37 -0
  7. package/__test/webSocketClient.ts +23 -0
  8. package/dist/decorators/controller.d.ts +3 -3
  9. package/dist/decorators/controller.js +1 -2
  10. package/dist/decorators/dispatcher.d.ts +1 -1
  11. package/dist/decorators/http.d.ts +12 -12
  12. package/dist/decorators/http.js +1 -1
  13. package/dist/decorators/index.d.ts +5 -0
  14. package/dist/decorators/index.js +3 -0
  15. package/dist/decorators/module.d.ts +3 -1
  16. package/dist/decorators/module.js +9 -2
  17. package/dist/decorators/webSocket.d.ts +25 -0
  18. package/dist/decorators/webSocket.js +40 -0
  19. package/dist/decorators/webSocketArguments.d.ts +22 -0
  20. package/dist/decorators/webSocketArguments.js +49 -0
  21. package/dist/decorators/webSocketEvent.d.ts +15 -0
  22. package/dist/decorators/webSocketEvent.js +24 -0
  23. package/dist/decorators/zodSchema.js +3 -3
  24. package/dist/entities/{route.d.ts → httpRoute.d.ts} +12 -12
  25. package/dist/entities/{route.js → httpRoute.js} +27 -25
  26. package/dist/entities/httpRouter.d.ts +10 -0
  27. package/dist/entities/{router.js → httpRouter.js} +7 -5
  28. package/dist/entities/{routerGroup.d.ts → httpRouterGroup.d.ts} +4 -4
  29. package/dist/entities/{routerGroup.js → httpRouterGroup.js} +1 -1
  30. package/dist/entities/index.d.ts +7 -4
  31. package/dist/entities/index.js +6 -3
  32. package/dist/entities/webSocketRoute.d.ts +10 -0
  33. package/dist/entities/webSocketRoute.js +15 -0
  34. package/dist/entities/webSocketRouter.d.ts +31 -0
  35. package/dist/entities/webSocketRouter.js +54 -0
  36. package/dist/entities/webSocketRouterGroup.d.ts +25 -0
  37. package/dist/entities/webSocketRouterGroup.js +51 -0
  38. package/dist/hooks/factory.d.ts +1 -39
  39. package/dist/hooks/factory.js +450 -76
  40. package/dist/hooks/injector.js +2 -2
  41. package/dist/index.d.ts +1 -1
  42. package/dist/interfaces/index.d.ts +1 -0
  43. package/dist/interfaces/webSocket.d.ts +2 -0
  44. package/dist/interfaces/webSocket.js +1 -0
  45. package/dist/keys/index.d.ts +10 -1
  46. package/dist/keys/index.js +21 -12
  47. package/dist/ultils/colors.d.ts +30 -0
  48. package/dist/ultils/colors.js +41 -0
  49. package/dist/ultils/index.d.ts +2 -0
  50. package/dist/ultils/index.js +2 -0
  51. package/dist/ultils/socket.d.ts +1 -0
  52. package/dist/ultils/socket.js +7 -0
  53. package/package.json +8 -7
  54. package/src/decorators/controller.ts +5 -4
  55. package/src/decorators/dispatcher.ts +2 -1
  56. package/src/decorators/guard.ts +1 -0
  57. package/src/decorators/http.ts +3 -3
  58. package/src/decorators/index.ts +10 -0
  59. package/src/decorators/middleware.ts +1 -0
  60. package/src/decorators/module.ts +14 -3
  61. package/src/decorators/webSocket.ts +81 -0
  62. package/src/decorators/webSocketArguments.ts +144 -0
  63. package/src/decorators/webSocketEvent.ts +56 -0
  64. package/src/decorators/zodSchema.ts +5 -3
  65. package/src/entities/{route.ts → httpRoute.ts} +71 -57
  66. package/src/entities/{router.ts → httpRouter.ts} +8 -6
  67. package/src/entities/{routerGroup.ts → httpRouterGroup.ts} +4 -4
  68. package/src/entities/index.ts +7 -4
  69. package/src/entities/webSocketRoute.ts +27 -0
  70. package/src/entities/webSocketRouter.ts +64 -0
  71. package/src/entities/webSocketRouterGroup.ts +64 -0
  72. package/src/hooks/factory.ts +704 -112
  73. package/src/hooks/injector.ts +2 -2
  74. package/src/index.ts +1 -1
  75. package/src/interfaces/index.ts +1 -0
  76. package/src/interfaces/webSocket.ts +1 -0
  77. package/src/keys/index.ts +22 -12
  78. package/src/ultils/colors.ts +56 -0
  79. package/src/ultils/index.ts +3 -1
  80. package/src/ultils/socket.ts +9 -0
  81. package/test.ts +0 -0
  82. package/tsconfig.json +3 -2
  83. package/bun.lockb +0 -0
  84. package/dist/entities/router.d.ts +0 -10
@@ -1,15 +1,29 @@
1
- import type { TArgumentsMetadata, TControllerMetadata, THttpMetadata, TModuleMetadata } from "../decorators";
1
+ import type {
2
+ TArgumentsMetadata,
3
+ TControllerMetadata,
4
+ THttpMetadata,
5
+ TModuleMetadata,
6
+ TWebSocketEventHandlerMetadata,
7
+ TWebSocketMetadata
8
+ } from "../decorators";
9
+ import type { TWebSocketUpgradeData } from "../decorators/webSocket";
2
10
  import type { IContext, IGuard, IMiddleware } from "../interfaces";
3
11
  import type { IDispatcher } from "../interfaces/dispatcher";
4
12
 
5
- import "colors";
6
13
  import "reflect-metadata";
7
14
 
8
15
  import Qs from "qs";
9
16
  import * as Zod from "zod";
10
17
 
11
- import type { Server } from "bun";
12
- import { Router, RouterGroup } from "../entities";
18
+ import { ETimeUnit, add as TimeAdd } from "@bool-ts/date-time";
19
+ import type { BunFile, Server } from "bun";
20
+ import {
21
+ HttpRouter,
22
+ HttpRouterGroup,
23
+ WebSocketRoute,
24
+ WebSocketRouter,
25
+ WebSocketRouterGroup
26
+ } from "../entities";
13
27
  import { HttpClientError, HttpServerError, jsonErrorInfer, type THttpMethods } from "../http";
14
28
  import {
15
29
  argumentsKey,
@@ -27,8 +41,15 @@ import {
27
41
  requestHeadersArgsKey,
28
42
  responseBodyArgsKey,
29
43
  responseHeadersArgsKey,
30
- routeModelArgsKey
44
+ routeModelArgsKey,
45
+ webSocketCloseCodeArgsKey,
46
+ webSocketCloseReasonArgsKey,
47
+ webSocketConnectionArgsKey,
48
+ webSocketKey,
49
+ webSocketMessageArgsKey,
50
+ webSocketServerArgsKey
31
51
  } from "../keys";
52
+ import { ansiText, isWebSocketUpgrade } from "../ultils";
32
53
  import { Injector } from "./injector";
33
54
 
34
55
  export type TGroupElementModel<
@@ -57,6 +78,7 @@ export type TBoolFactoryOptions = Required<{
57
78
  }> &
58
79
  Partial<{
59
80
  headers: Record<string, string>;
81
+ cacheTimeInSeconds: number;
60
82
  }>;
61
83
  cors: Partial<{
62
84
  credentials: boolean;
@@ -66,18 +88,25 @@ export type TBoolFactoryOptions = Required<{
66
88
  }>;
67
89
  }>;
68
90
 
69
- export const responseConverter = (response: Response) => {
91
+ const DEFAULT_STATIC_CACHE_TIME_IN_SECONDS = 900;
92
+
93
+ const responseConverter = (response: Response) => {
70
94
  response.headers.set("X-Powered-By", "Bool Typescript");
71
95
 
72
96
  return response;
73
97
  };
74
98
 
75
- export const controllerCreator = (
76
- controllerConstructor: new (...args: any[]) => unknown,
77
- group: RouterGroup,
78
- injector: Injector,
79
- prefix?: string
80
- ) => {
99
+ const controllerCreator = ({
100
+ controllerConstructor,
101
+ httpRouterGroup,
102
+ injector,
103
+ prefix
104
+ }: Readonly<{
105
+ controllerConstructor: new (...args: any[]) => unknown;
106
+ httpRouterGroup: HttpRouterGroup;
107
+ injector: Injector;
108
+ prefix?: string;
109
+ }>) => {
81
110
  if (!Reflect.getOwnMetadataKeys(controllerConstructor).includes(controllerKey)) {
82
111
  throw Error(`${controllerConstructor.name} is not a controller.`);
83
112
  }
@@ -88,12 +117,16 @@ export const controllerCreator = (
88
117
  throw Error("Can not initialize controller.");
89
118
  }
90
119
 
91
- const controllerMetadata: TControllerMetadata = Reflect.getOwnMetadata(controllerKey, controllerConstructor) || {
120
+ const controllerMetadata: TControllerMetadata = Reflect.getOwnMetadata(
121
+ controllerKey,
122
+ controllerConstructor
123
+ ) || {
92
124
  prefix: "/",
93
125
  httpMetadata: []
94
126
  };
95
- const routesMetadata = (Reflect.getOwnMetadata(controllerHttpKey, controllerConstructor) || []) as THttpMetadata;
96
- const router = new Router(`/${prefix || ""}/${controllerMetadata.prefix}`);
127
+ const routesMetadata = (Reflect.getOwnMetadata(controllerHttpKey, controllerConstructor) ||
128
+ []) as THttpMetadata;
129
+ const router = new HttpRouter(`/${prefix || ""}/${controllerMetadata.prefix}`);
97
130
 
98
131
  routesMetadata.forEach((routeMetadata) => {
99
132
  if (typeof routeMetadata.descriptor.value !== "function") {
@@ -124,10 +157,98 @@ export const controllerCreator = (
124
157
  }
125
158
  });
126
159
 
127
- return group.add(router);
160
+ return httpRouterGroup.add(router);
161
+ };
162
+
163
+ const webSocketCreator = ({
164
+ injector,
165
+ httpRouterGroup,
166
+ prefix,
167
+ webSocketRouterGroup,
168
+ webSocketConstructor
169
+ }: Readonly<{
170
+ webSocketConstructor: new (...args: any[]) => unknown;
171
+ httpRouterGroup: HttpRouterGroup;
172
+ webSocketRouterGroup: WebSocketRouterGroup;
173
+ injector: Injector;
174
+ prefix?: string;
175
+ }>): Readonly<{
176
+ httpRouterGroup: HttpRouterGroup;
177
+ webSocketRouterGroup: WebSocketRouterGroup;
178
+ }> => {
179
+ if (!Reflect.getOwnMetadataKeys(webSocketConstructor).includes(webSocketKey)) {
180
+ throw Error(`${webSocketConstructor.name} is not a controller.`);
181
+ }
182
+
183
+ const webSocket = injector.get(webSocketConstructor);
184
+
185
+ if (!webSocket) {
186
+ throw Error("Can not initialize webSocket.");
187
+ }
188
+
189
+ const webSocketMetadata: TWebSocketMetadata = Reflect.getOwnMetadata(
190
+ webSocketKey,
191
+ webSocketConstructor
192
+ ) || {
193
+ prefix: "/",
194
+ events: [],
195
+ http: []
196
+ };
197
+
198
+ const fullPrefix = `/${prefix || ""}/${webSocketMetadata.prefix}`;
199
+
200
+ //#region [HTTP ROUTER]
201
+ const router = new HttpRouter(fullPrefix);
202
+
203
+ for (const [_key, httpMetadata] of Object.entries(webSocketMetadata.http)) {
204
+ if (typeof httpMetadata.descriptor?.value !== "function") {
205
+ continue;
206
+ }
207
+
208
+ const route = router.route(httpMetadata.path);
209
+ const handler = httpMetadata.descriptor.value.bind(webSocket);
210
+ const routeArgument = Object.freeze({
211
+ class: webSocketConstructor,
212
+ funcName: httpMetadata.methodName,
213
+ func: handler
214
+ });
215
+
216
+ switch (httpMetadata.httpMethod) {
217
+ case "GET":
218
+ route.get(routeArgument);
219
+ break;
220
+ case "POST":
221
+ route.post(routeArgument);
222
+ break;
223
+ }
224
+ }
225
+
226
+ httpRouterGroup.add(router);
227
+ //#endregion
228
+
229
+ //#region [WEBSOCKET ROUTER]
230
+ const webSocketRouter = new WebSocketRouter(fullPrefix);
231
+
232
+ for (const [key, event] of Object.entries(webSocketMetadata.events)) {
233
+ const webSocketRoute = new WebSocketRoute({
234
+ eventName: key,
235
+ metadata: event
236
+ });
237
+
238
+ webSocketRouter.addRoutes(webSocketRoute);
239
+ }
240
+
241
+ webSocketRouter.bind(webSocket);
242
+ webSocketRouterGroup.addRouters(webSocketRouter);
243
+ //#endregion
244
+
245
+ return Object.freeze({
246
+ httpRouterGroup: httpRouterGroup,
247
+ webSocketRouterGroup: webSocketRouterGroup
248
+ });
128
249
  };
129
250
 
130
- export const argumentsResolution = async (
251
+ const argumentsResolution = async (
131
252
  data: unknown,
132
253
  zodSchema: Zod.Schema,
133
254
  argumentIndex: number,
@@ -166,7 +287,10 @@ export const argumentsResolution = async (
166
287
  }
167
288
  };
168
289
 
169
- export const moduleResolution = async (module: new (...args: any[]) => unknown, options: TBoolFactoryOptions) => {
290
+ const moduleResolution = async (
291
+ module: new (...args: any[]) => unknown,
292
+ options: TBoolFactoryOptions
293
+ ) => {
170
294
  if (!Reflect.getOwnMetadataKeys(module).includes(moduleKey)) {
171
295
  throw Error(`${module.name} is not a module.`);
172
296
  }
@@ -185,11 +309,14 @@ export const moduleResolution = async (module: new (...args: any[]) => unknown,
185
309
  dispatchers,
186
310
  controllers,
187
311
  dependencies,
312
+ webSockets,
188
313
  prefix: modulePrefix,
189
314
  config: moduleConfig
190
315
  } = moduleMetadata;
191
316
 
192
- // Configuration(s)
317
+ const fullPrefix = `${options.prefix || ""}/${modulePrefix || ""}`;
318
+
319
+ //#region [Configuration(s)]
193
320
  const { config } = Object.freeze({
194
321
  config: {
195
322
  ...(typeof options.config !== "function" ? options.config : await options.config()),
@@ -200,10 +327,13 @@ export const moduleResolution = async (module: new (...args: any[]) => unknown,
200
327
  : await moduleConfig())
201
328
  }
202
329
  });
330
+ //#endregion
203
331
 
204
- // Register config like an injection
332
+ //#region [Register config like an injection]
205
333
  injector.set(configKey, config);
334
+ //#endregion
206
335
 
336
+ //#region [Run loader(s)]
207
337
  if (loaders) {
208
338
  const loaderFunctions = [];
209
339
 
@@ -211,10 +341,24 @@ export const moduleResolution = async (module: new (...args: any[]) => unknown,
211
341
  loaderFunctions.push(async () => {
212
342
  try {
213
343
  const result = await func({ config });
214
- console.info(`INFO! Loader [${key}] initialized successfully.`);
344
+
345
+ console.info(
346
+ `${ansiText(" INFO ", {
347
+ color: "white",
348
+ backgroundColor: "blue",
349
+ bold: true
350
+ })} Loader [${key}] initialized successfully.`
351
+ );
352
+
215
353
  return result;
216
354
  } catch (error) {
217
- console.error(`WARNING! Loader [${key}] initialization failed.`);
355
+ console.error(
356
+ `${ansiText(" WARN ", {
357
+ color: "yellow",
358
+ backgroundColor: "red",
359
+ bold: true
360
+ })} Loader [${key}] initialization failed.`
361
+ );
218
362
  options.debug && console.error(error);
219
363
  throw error;
220
364
  }
@@ -228,22 +372,28 @@ export const moduleResolution = async (module: new (...args: any[]) => unknown,
228
372
  injector.set(key, value);
229
373
  }
230
374
  }
375
+ //#endregion
231
376
 
232
- // Dependencies
377
+ //#region [Dependencies]
233
378
  !dependencies || dependencies.map((dependency) => injector.get(dependency));
379
+ //#endregion
234
380
 
235
- // Middleware(s)
236
- const startMiddlewareGroup: Array<TGroupElementModel<"start", IMiddleware, NonNullable<IMiddleware["start"]>>> = [];
237
- const endMiddlewareGroup: Array<TGroupElementModel<"end", IMiddleware, NonNullable<IMiddleware["end"]>>> = [];
381
+ //#region [Middleware(s)]
382
+ const startMiddlewareGroup: Array<
383
+ TGroupElementModel<"start", IMiddleware, NonNullable<IMiddleware["start"]>>
384
+ > = [];
385
+ const endMiddlewareGroup: Array<
386
+ TGroupElementModel<"end", IMiddleware, NonNullable<IMiddleware["end"]>>
387
+ > = [];
238
388
 
239
- if (middlewares) {
240
- for (let i = 0; i < middlewares.length; i++) {
241
- const instance = injector.get<IMiddleware>(middlewares[i]);
389
+ middlewares &&
390
+ middlewares.forEach((middleware) => {
391
+ const instance = injector.get<IMiddleware>(middleware);
242
392
 
243
393
  if (instance.start && typeof instance.start === "function") {
244
394
  startMiddlewareGroup.push(
245
395
  Object.freeze({
246
- class: middlewares[i] as IMiddleware,
396
+ class: middleware as IMiddleware,
247
397
  funcName: "start",
248
398
  func: instance.start.bind(instance)
249
399
  })
@@ -253,16 +403,16 @@ export const moduleResolution = async (module: new (...args: any[]) => unknown,
253
403
  if (instance.end && typeof instance.end === "function") {
254
404
  endMiddlewareGroup.push(
255
405
  Object.freeze({
256
- class: middlewares[i] as IMiddleware,
406
+ class: middleware as IMiddleware,
257
407
  funcName: "end",
258
408
  func: instance.end.bind(instance)
259
409
  })
260
410
  );
261
411
  }
262
- }
263
- }
412
+ });
413
+ //#endregion
264
414
 
265
- // Guard(s)
415
+ //#region [Guard(s)]
266
416
  const guardGroup = !guards
267
417
  ? []
268
418
  : guards.map((guard) => {
@@ -274,19 +424,24 @@ export const moduleResolution = async (module: new (...args: any[]) => unknown,
274
424
  func: guardInstance.enforce.bind(guardInstance)
275
425
  });
276
426
  });
427
+ //#endregion
277
428
 
278
- // Before dispatcher(s)
279
- const openDispatcherGroup: Array<TGroupElementModel<"open", IDispatcher, NonNullable<IDispatcher["open"]>>> = [];
280
- const closeDispatcherGroup: Array<TGroupElementModel<"close", IDispatcher, NonNullable<IDispatcher["close"]>>> = [];
429
+ //#region [Before dispatcher(s)]
430
+ const openDispatcherGroup: Array<
431
+ TGroupElementModel<"open", IDispatcher, NonNullable<IDispatcher["open"]>>
432
+ > = [];
433
+ const closeDispatcherGroup: Array<
434
+ TGroupElementModel<"close", IDispatcher, NonNullable<IDispatcher["close"]>>
435
+ > = [];
281
436
 
282
- if (dispatchers) {
283
- for (let i = 0; i < dispatchers.length; i++) {
284
- const instance = injector.get<IDispatcher>(dispatchers[i]);
437
+ dispatchers &&
438
+ dispatchers.forEach((dispatcher) => {
439
+ const instance = injector.get<IDispatcher>(dispatcher);
285
440
 
286
441
  if (instance.open && typeof instance.open === "function") {
287
442
  openDispatcherGroup.push(
288
443
  Object.freeze({
289
- class: dispatchers[i] as IDispatcher,
444
+ class: dispatcher as IDispatcher,
290
445
  funcName: "open",
291
446
  func: instance.open.bind(instance)
292
447
  })
@@ -296,22 +451,44 @@ export const moduleResolution = async (module: new (...args: any[]) => unknown,
296
451
  if (instance.close && typeof instance.close === "function") {
297
452
  closeDispatcherGroup.push(
298
453
  Object.freeze({
299
- class: dispatchers[i] as IDispatcher,
454
+ class: dispatcher as IDispatcher,
300
455
  funcName: "close",
301
456
  func: instance.close.bind(instance)
302
457
  })
303
458
  );
304
459
  }
305
- }
306
- }
460
+ });
461
+ //#endregion
307
462
 
308
- // Controller(s)
309
- const routerGroup = new RouterGroup();
463
+ //#region [Controller(s)]
464
+ const controllerRouterGroup = new HttpRouterGroup();
310
465
 
311
466
  controllers &&
312
- controllers.map((controllerConstructor) =>
313
- controllerCreator(controllerConstructor, routerGroup, injector, `${options.prefix || ""}/${modulePrefix || ""}`)
467
+ controllers.forEach((controllerConstructor) =>
468
+ controllerCreator({
469
+ controllerConstructor,
470
+ httpRouterGroup: controllerRouterGroup,
471
+ injector: injector,
472
+ prefix: fullPrefix
473
+ })
474
+ );
475
+ //#endregion
476
+
477
+ //#region [WebSocket(s)]
478
+ const webSocketHttpRouterGroup = new HttpRouterGroup();
479
+ const webSocketRouterGroup = new WebSocketRouterGroup();
480
+
481
+ webSockets &&
482
+ webSockets.forEach((webSocket) =>
483
+ webSocketCreator({
484
+ webSocketConstructor: webSocket,
485
+ httpRouterGroup: webSocketHttpRouterGroup,
486
+ webSocketRouterGroup: webSocketRouterGroup,
487
+ injector,
488
+ prefix: fullPrefix
489
+ })
314
490
  );
491
+ //#endregion
315
492
 
316
493
  return Object.freeze({
317
494
  prefix: moduleMetadata.prefix,
@@ -321,11 +498,13 @@ export const moduleResolution = async (module: new (...args: any[]) => unknown,
321
498
  guardGroup,
322
499
  openDispatcherGroup,
323
500
  closeDispatcherGroup,
324
- routerGroup
501
+ controllerRouterGroup,
502
+ webSocketHttpRouterGroup,
503
+ webSocketRouterGroup
325
504
  });
326
505
  };
327
506
 
328
- const fetcher = async (
507
+ const webSocketFetcher = async (
329
508
  bun: Required<{
330
509
  request: Request;
331
510
  server: Server;
@@ -333,17 +512,82 @@ const fetcher = async (
333
512
  bool: Required<{
334
513
  responseHeaders: Headers;
335
514
  query: Record<string, unknown>;
336
- route: NonNullable<ReturnType<RouterGroup["find"]>>;
515
+ route: NonNullable<ReturnType<HttpRouterGroup["find"]>>;
337
516
  moduleResolution: NonNullable<Awaited<ReturnType<typeof moduleResolution>>>;
338
517
  }>
339
518
  ) => {
519
+ const { request, server } = bun;
340
520
  const {
341
521
  query,
342
522
  responseHeaders,
343
- route: { parameters, model },
344
- moduleResolution: { startMiddlewareGroup, endMiddlewareGroup, guardGroup, openDispatcherGroup, closeDispatcherGroup }
523
+ route: { model }
345
524
  } = bool;
525
+
526
+ // Execute controller action
527
+ const isUpgrade = await model.func(...[server, request, query]);
528
+
529
+ if (typeof isUpgrade !== "boolean") {
530
+ return responseConverter(
531
+ new Response(
532
+ JSON.stringify({
533
+ httpCode: 500,
534
+ message: "Can not detect webSocket upgrade result.",
535
+ data: undefined
536
+ }),
537
+ {
538
+ status: 500,
539
+ statusText: "Internal server error.",
540
+ headers: responseHeaders
541
+ }
542
+ )
543
+ );
544
+ }
545
+
546
+ if (!isUpgrade) {
547
+ return responseConverter(
548
+ new Response(
549
+ JSON.stringify({
550
+ httpCode: 500,
551
+ message: "Can not upgrade.",
552
+ data: undefined
553
+ }),
554
+ {
555
+ status: 500,
556
+ statusText: "Internal server error.",
557
+ headers: responseHeaders
558
+ }
559
+ )
560
+ );
561
+ }
562
+
563
+ return isUpgrade;
564
+ };
565
+
566
+ const httpFetcher = async (
567
+ bun: Required<{
568
+ request: Request;
569
+ server: Server;
570
+ }>,
571
+ bool: Required<{
572
+ responseHeaders: Headers;
573
+ query: Record<string, unknown>;
574
+ route: NonNullable<ReturnType<HttpRouterGroup["find"]>>;
575
+ moduleResolution: NonNullable<Awaited<ReturnType<typeof moduleResolution>>>;
576
+ }>
577
+ ) => {
346
578
  const { request, server: _server } = bun;
579
+ const {
580
+ query,
581
+ responseHeaders,
582
+ route: { parameters, model },
583
+ moduleResolution: {
584
+ startMiddlewareGroup,
585
+ endMiddlewareGroup,
586
+ guardGroup,
587
+ openDispatcherGroup,
588
+ closeDispatcherGroup
589
+ }
590
+ } = bool;
347
591
 
348
592
  const context: Record<symbol, any> = {
349
593
  [requestHeadersArgsKey]: request.headers,
@@ -397,7 +641,9 @@ const fetcher = async (
397
641
  );
398
642
  break;
399
643
  case contextArgsKey:
400
- args[argsMetadata.index] = !argsMetadata.key ? contextHook : contextHook.get(argsMetadata.key);
644
+ args[argsMetadata.index] = !argsMetadata.key
645
+ ? contextHook
646
+ : contextHook.get(argsMetadata.key);
401
647
  break;
402
648
  case requestHeadersArgsKey:
403
649
  args[argsMetadata.index] = !argsMetadata.zodSchema
@@ -441,7 +687,9 @@ const fetcher = async (
441
687
  ? undefined
442
688
  : context[argsMetadata.type]
443
689
  : await argumentsResolution(
444
- !(argsMetadata.type in context) ? undefined : context[argsMetadata.type],
690
+ !(argsMetadata.type in context)
691
+ ? undefined
692
+ : context[argsMetadata.type],
445
693
  argsMetadata.zodSchema,
446
694
  argsMetadata.index,
447
695
  collection.funcName
@@ -489,7 +737,9 @@ const fetcher = async (
489
737
  );
490
738
  break;
491
739
  case contextArgsKey:
492
- args[argsMetadata.index] = !argsMetadata.key ? contextHook : contextHook.get(argsMetadata.key);
740
+ args[argsMetadata.index] = !argsMetadata.key
741
+ ? contextHook
742
+ : contextHook.get(argsMetadata.key);
493
743
  break;
494
744
  case requestHeadersArgsKey:
495
745
  args[argsMetadata.index] = !argsMetadata.zodSchema
@@ -583,7 +833,9 @@ const fetcher = async (
583
833
  );
584
834
  break;
585
835
  case contextArgsKey:
586
- args[argsMetadata.index] = !argsMetadata.key ? contextHook : contextHook.get(argsMetadata.key);
836
+ args[argsMetadata.index] = !argsMetadata.key
837
+ ? contextHook
838
+ : contextHook.get(argsMetadata.key);
587
839
  break;
588
840
  case requestHeadersArgsKey:
589
841
  args[argsMetadata.index] = !argsMetadata.zodSchema
@@ -642,7 +894,11 @@ const fetcher = async (
642
894
  const controllerActionArguments: any[] = [];
643
895
  const controllerActionCollection = model;
644
896
  const controllerActionMetadata: Record<string, TArgumentsMetadata> =
645
- Reflect.getOwnMetadata(argumentsKey, controllerActionCollection.class, controllerActionCollection.funcName) || {};
897
+ Reflect.getOwnMetadata(
898
+ argumentsKey,
899
+ controllerActionCollection.class,
900
+ controllerActionCollection.funcName
901
+ ) || {};
646
902
 
647
903
  if (controllerActionMetadata) {
648
904
  for (const [_key, argsMetadata] of Object.entries(controllerActionMetadata)) {
@@ -722,7 +978,9 @@ const fetcher = async (
722
978
  }
723
979
  }
724
980
 
725
- context[responseBodyArgsKey] = await controllerActionCollection.func(...controllerActionArguments);
981
+ context[responseBodyArgsKey] = await controllerActionCollection.func(
982
+ ...controllerActionArguments
983
+ );
726
984
 
727
985
  // Execute close dispatcher(s)
728
986
  for (let i = 0; i < closeDispatcherGroup.length; i++) {
@@ -755,7 +1013,9 @@ const fetcher = async (
755
1013
  );
756
1014
  break;
757
1015
  case contextArgsKey:
758
- args[argsMetadata.index] = !argsMetadata.key ? contextHook : contextHook.get(argsMetadata.key);
1016
+ args[argsMetadata.index] = !argsMetadata.key
1017
+ ? contextHook
1018
+ : contextHook.get(argsMetadata.key);
759
1019
  break;
760
1020
  case requestHeadersArgsKey:
761
1021
  args[argsMetadata.index] = !argsMetadata.zodSchema
@@ -845,7 +1105,9 @@ const fetcher = async (
845
1105
  );
846
1106
  break;
847
1107
  case contextArgsKey:
848
- args[argsMetadata.index] = !argsMetadata.key ? contextHook : contextHook.get(argsMetadata.key);
1108
+ args[argsMetadata.index] = !argsMetadata.key
1109
+ ? contextHook
1110
+ : contextHook.get(argsMetadata.key);
849
1111
  break;
850
1112
  case requestHeadersArgsKey:
851
1113
  args[argsMetadata.index] = !argsMetadata.zodSchema
@@ -889,7 +1151,9 @@ const fetcher = async (
889
1151
  ? undefined
890
1152
  : context[argsMetadata.type]
891
1153
  : await argumentsResolution(
892
- !(argsMetadata.type in context) ? undefined : context[argsMetadata.type],
1154
+ !(argsMetadata.type in context)
1155
+ ? undefined
1156
+ : context[argsMetadata.type],
893
1157
  argsMetadata.zodSchema,
894
1158
  argsMetadata.index,
895
1159
  collection.funcName
@@ -924,10 +1188,29 @@ const fetcher = async (
924
1188
  );
925
1189
  };
926
1190
 
927
- export const BoolFactory = async (modules: Object | Array<Object>, options: TBoolFactoryOptions) => {
1191
+ export const BoolFactory = async (
1192
+ modules: Object | Array<Object>,
1193
+ options: TBoolFactoryOptions
1194
+ ) => {
928
1195
  try {
1196
+ const staticMap: Map<
1197
+ string,
1198
+ Readonly<{
1199
+ expiredAt: Date;
1200
+ file: BunFile;
1201
+ }>
1202
+ > = new Map();
1203
+
929
1204
  const modulesConverted = !Array.isArray(modules) ? [modules] : modules;
930
- const { allowLogsMethods, staticOption, allowOrigins, allowMethods, allowCredentials, allowHeaders } = Object.freeze({
1205
+
1206
+ const {
1207
+ allowLogsMethods,
1208
+ staticOption,
1209
+ allowOrigins,
1210
+ allowMethods,
1211
+ allowCredentials,
1212
+ allowHeaders
1213
+ } = Object.freeze({
931
1214
  allowLogsMethods: options?.log?.methods,
932
1215
  staticOption: options.static,
933
1216
  allowOrigins: !options.cors?.origins
@@ -937,9 +1220,19 @@ export const BoolFactory = async (modules: Object | Array<Object>, options: TBoo
937
1220
  ? ["*"]
938
1221
  : options.cors.origins
939
1222
  : [options.cors.origins !== "*" ? options.cors.origins : "*"],
940
- allowMethods: options.cors?.methods || ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"],
1223
+ allowMethods: options.cors?.methods || [
1224
+ "GET",
1225
+ "POST",
1226
+ "PUT",
1227
+ "PATCH",
1228
+ "DELETE",
1229
+ "OPTIONS"
1230
+ ],
941
1231
  allowCredentials: !options.cors?.credentials ? false : true,
942
- allowHeaders: !options.cors?.headers || options.cors.headers.includes("*") ? ["*"] : options.cors.headers
1232
+ allowHeaders:
1233
+ !options.cors?.headers || options.cors.headers.includes("*")
1234
+ ? ["*"]
1235
+ : options.cors.headers
943
1236
  });
944
1237
 
945
1238
  const moduleResolutions = await Promise.all(
@@ -951,14 +1244,28 @@ export const BoolFactory = async (modules: Object | Array<Object>, options: TBoo
951
1244
  );
952
1245
 
953
1246
  const prefixs = [
954
- ...new Set(availableModuleResolutions.map((availableModuleResolution) => availableModuleResolution.prefix))
1247
+ ...new Set(
1248
+ availableModuleResolutions.map(
1249
+ (availableModuleResolution) => availableModuleResolution.prefix
1250
+ )
1251
+ )
955
1252
  ];
956
1253
 
957
1254
  if (prefixs.length !== availableModuleResolutions.length) {
958
- throw Error(`Module prefix should be unique.`);
1255
+ throw Error("Module prefix should be unique.");
1256
+ }
1257
+
1258
+ const webSocketsMap = new Map<string, TWebSocketEventHandlerMetadata>();
1259
+
1260
+ for (const availableModuleResolution of availableModuleResolutions) {
1261
+ const webSocketMap = availableModuleResolution.webSocketRouterGroup.execute();
1262
+
1263
+ for (const [key, metadata] of webSocketMap.entries()) {
1264
+ webSocketsMap.set(key, metadata);
1265
+ }
959
1266
  }
960
1267
 
961
- Bun.serve({
1268
+ const server = Bun.serve<TWebSocketUpgradeData>({
962
1269
  port: options.port,
963
1270
  fetch: async (request, server) => {
964
1271
  const start = performance.now();
@@ -969,13 +1276,77 @@ export const BoolFactory = async (modules: Object | Array<Object>, options: TBoo
969
1276
  const responseHeaders = new Headers();
970
1277
 
971
1278
  try {
972
- allowCredentials && responseHeaders.set("Access-Control-Allow-Credentials", "true");
1279
+ const isUpgradable = isWebSocketUpgrade(request);
1280
+
1281
+ let collection:
1282
+ | undefined
1283
+ | Required<{
1284
+ route: NonNullable<ReturnType<HttpRouterGroup["find"]>>;
1285
+ resolution: NonNullable<Awaited<ReturnType<typeof moduleResolution>>>;
1286
+ }>;
1287
+
1288
+ if (isUpgradable) {
1289
+ for (const availableModuleResolution of availableModuleResolutions) {
1290
+ const routeResult =
1291
+ availableModuleResolution.webSocketHttpRouterGroup.find(
1292
+ url.pathname,
1293
+ request.method as keyof THttpMethods
1294
+ );
1295
+
1296
+ if (routeResult) {
1297
+ collection = Object.freeze({
1298
+ route: routeResult,
1299
+ resolution: availableModuleResolution
1300
+ });
1301
+ break;
1302
+ }
1303
+ }
1304
+
1305
+ if (!collection) {
1306
+ return responseConverter(
1307
+ new Response(
1308
+ JSON.stringify({
1309
+ httpCode: 404,
1310
+ message: "Route not found",
1311
+ data: undefined
1312
+ }),
1313
+ {
1314
+ status: 404,
1315
+ statusText: "Not found.",
1316
+ headers: responseHeaders
1317
+ }
1318
+ )
1319
+ );
1320
+ }
1321
+
1322
+ const upgradeResult = await webSocketFetcher(
1323
+ {
1324
+ request,
1325
+ server
1326
+ },
1327
+ {
1328
+ query: query,
1329
+ responseHeaders: responseHeaders,
1330
+ route: collection.route,
1331
+ moduleResolution: collection.resolution
1332
+ }
1333
+ );
1334
+
1335
+ return upgradeResult instanceof Response ? upgradeResult : undefined;
1336
+ }
1337
+
1338
+ allowCredentials &&
1339
+ responseHeaders.set("Access-Control-Allow-Credentials", "true");
973
1340
 
974
1341
  responseHeaders.set("Access-Control-Allow-Methods", allowMethods.join(", "));
975
1342
  responseHeaders.set("Access-Control-Allow-Headers", allowHeaders.join(", "));
976
1343
  responseHeaders.set(
977
1344
  "Access-Control-Allow-Origin",
978
- allowOrigins.includes("*") ? "*" : !allowOrigins.includes(origin) ? allowOrigins[0] : origin
1345
+ allowOrigins.includes("*")
1346
+ ? "*"
1347
+ : !allowOrigins.includes(origin)
1348
+ ? allowOrigins[0]
1349
+ : origin
979
1350
  );
980
1351
 
981
1352
  if (!allowMethods.includes(method)) {
@@ -1005,37 +1376,77 @@ export const BoolFactory = async (modules: Object | Array<Object>, options: TBoo
1005
1376
  }
1006
1377
 
1007
1378
  if (staticOption) {
1008
- const file = Bun.file(`${staticOption.path}/${url.pathname}`);
1009
- const isFileExists = await file.exists();
1010
-
1011
- if (isFileExists) {
1012
- if (staticOption.headers) {
1013
- for (const [key, value] of Object.entries(staticOption.headers)) {
1014
- responseHeaders.set(key, value);
1379
+ const { path, headers, cacheTimeInSeconds } = staticOption;
1380
+ const pathname = `${path}/${url.pathname}`;
1381
+ const cachedFile = staticMap.get(pathname);
1382
+
1383
+ if (!cachedFile) {
1384
+ const file = Bun.file(pathname);
1385
+ const isFileExists = await file.exists();
1386
+
1387
+ if (isFileExists) {
1388
+ if (headers) {
1389
+ for (const [key, value] of Object.entries(headers)) {
1390
+ responseHeaders.set(key, value);
1391
+ }
1015
1392
  }
1393
+
1394
+ responseHeaders.set("Content-Type", file.type);
1395
+
1396
+ return responseConverter(
1397
+ new Response(await file.arrayBuffer(), {
1398
+ status: 200,
1399
+ statusText: "SUCCESS",
1400
+ headers: responseHeaders
1401
+ })
1402
+ );
1016
1403
  }
1404
+ } else {
1405
+ const isExpired = new Date() > cachedFile.expiredAt;
1017
1406
 
1018
- responseHeaders.set("Content-Type", file.type);
1407
+ if (isExpired) {
1408
+ staticMap.delete(pathname);
1409
+ }
1019
1410
 
1020
- return responseConverter(
1021
- new Response(await file.arrayBuffer(), {
1022
- status: 200,
1023
- statusText: "SUCCESS",
1024
- headers: responseHeaders
1025
- })
1026
- );
1411
+ const file = !isExpired ? cachedFile.file : Bun.file(pathname);
1412
+ const isFileExists = await file.exists();
1413
+
1414
+ if (isFileExists) {
1415
+ staticMap.set(
1416
+ pathname,
1417
+ Object.freeze({
1418
+ expiredAt: TimeAdd(
1419
+ new Date(),
1420
+ typeof cacheTimeInSeconds !== "number"
1421
+ ? DEFAULT_STATIC_CACHE_TIME_IN_SECONDS
1422
+ : cacheTimeInSeconds,
1423
+ ETimeUnit.seconds
1424
+ ),
1425
+ file: file
1426
+ })
1427
+ );
1428
+
1429
+ if (headers) {
1430
+ for (const [key, value] of Object.entries(headers)) {
1431
+ responseHeaders.set(key, value);
1432
+ }
1433
+ }
1434
+
1435
+ responseHeaders.set("Content-Type", file.type);
1436
+
1437
+ return responseConverter(
1438
+ new Response(await file.arrayBuffer(), {
1439
+ status: 200,
1440
+ statusText: "SUCCESS",
1441
+ headers: responseHeaders
1442
+ })
1443
+ );
1444
+ }
1027
1445
  }
1028
1446
  }
1029
1447
 
1030
- let collection:
1031
- | undefined
1032
- | Required<{
1033
- route: NonNullable<ReturnType<RouterGroup["find"]>>;
1034
- resolution: NonNullable<Awaited<ReturnType<typeof moduleResolution>>>;
1035
- }>;
1036
-
1037
- for (let i = 0; i < availableModuleResolutions.length; i++) {
1038
- const routeResult = availableModuleResolutions[i].routerGroup.find(
1448
+ for (const availableModuleResolution of availableModuleResolutions) {
1449
+ const routeResult = availableModuleResolution.controllerRouterGroup.find(
1039
1450
  url.pathname,
1040
1451
  request.method as keyof THttpMethods
1041
1452
  );
@@ -1043,7 +1454,7 @@ export const BoolFactory = async (modules: Object | Array<Object>, options: TBoo
1043
1454
  if (routeResult) {
1044
1455
  collection = Object.freeze({
1045
1456
  route: routeResult,
1046
- resolution: availableModuleResolutions[i]
1457
+ resolution: availableModuleResolution
1047
1458
  });
1048
1459
  break;
1049
1460
  }
@@ -1056,12 +1467,17 @@ export const BoolFactory = async (modules: Object | Array<Object>, options: TBoo
1056
1467
  httpCode: 404,
1057
1468
  message: "Route not found",
1058
1469
  data: undefined
1059
- })
1470
+ }),
1471
+ {
1472
+ status: 404,
1473
+ statusText: "Not found.",
1474
+ headers: responseHeaders
1475
+ }
1060
1476
  )
1061
1477
  );
1062
1478
  }
1063
1479
 
1064
- return await fetcher(
1480
+ return await httpFetcher(
1065
1481
  {
1066
1482
  request,
1067
1483
  server
@@ -1080,24 +1496,200 @@ export const BoolFactory = async (modules: Object | Array<Object>, options: TBoo
1080
1496
  } finally {
1081
1497
  if (allowLogsMethods) {
1082
1498
  const end = performance.now();
1083
- const convertedPID = `${process.pid}`.yellow;
1084
- const convertedMethod = `${request.method.yellow}`.bgBlue;
1085
- const convertedReqIp = `${
1086
- request.headers.get("x-forwarded-for") ||
1087
- request.headers.get("x-real-ip") ||
1088
- server.requestIP(request)?.address ||
1089
- "<Unknown>"
1090
- }`.yellow;
1091
- const convertedTime = `${Math.round((end - start + Number.EPSILON) * 10 ** 2) / 10 ** 2}ms`.yellow;
1092
-
1093
- allowLogsMethods.includes(request.method.toUpperCase() as (typeof allowLogsMethods)[number]) &&
1499
+ const pathname = ansiText(url.pathname, { color: "blue" });
1500
+ const convertedPID = `${Bun.color("yellow", "ansi")}${process.pid}`;
1501
+ const convertedMethod = ansiText(request.method, {
1502
+ color: "yellow",
1503
+ backgroundColor: "blue"
1504
+ });
1505
+ const convertedReqIp = ansiText(
1506
+ `${
1507
+ request.headers.get("x-forwarded-for") ||
1508
+ request.headers.get("x-real-ip") ||
1509
+ server.requestIP(request)?.address ||
1510
+ "<Unknown>"
1511
+ }`,
1512
+ {
1513
+ color: "yellow"
1514
+ }
1515
+ );
1516
+ const convertedTime = ansiText(
1517
+ `${Math.round((end - start + Number.EPSILON) * 10 ** 2) / 10 ** 2}ms`,
1518
+ {
1519
+ color: "yellow",
1520
+ backgroundColor: "blue"
1521
+ }
1522
+ );
1523
+
1524
+ allowLogsMethods.includes(
1525
+ request.method.toUpperCase() as (typeof allowLogsMethods)[number]
1526
+ ) &&
1094
1527
  console.info(
1095
- `PID: ${convertedPID} - Method: ${convertedMethod} - IP: ${convertedReqIp} - ${
1096
- new URL(request.url).pathname.blue
1097
- } - Time: ${convertedTime}`
1528
+ `PID: ${convertedPID} - Method: ${convertedMethod} - IP: ${convertedReqIp} - ${pathname} - Time: ${convertedTime}`
1098
1529
  );
1099
1530
  }
1100
1531
  }
1532
+ },
1533
+ websocket: {
1534
+ open: (connection) => {
1535
+ const pathnameKey = `${connection.data.pathname}:::open`;
1536
+ const handlerMetadata = webSocketsMap.get(pathnameKey);
1537
+
1538
+ if (!handlerMetadata) {
1539
+ return;
1540
+ }
1541
+
1542
+ const argumentsMetadata = handlerMetadata.arguments || {};
1543
+ const args: Array<unknown> = [];
1544
+
1545
+ for (const [_key, argumentMetadata] of Object.entries(argumentsMetadata)) {
1546
+ switch (argumentMetadata.type) {
1547
+ case webSocketConnectionArgsKey:
1548
+ args[argumentMetadata.index] = connection;
1549
+ break;
1550
+ case webSocketServerArgsKey:
1551
+ args[argumentMetadata.index] = server;
1552
+ break;
1553
+ }
1554
+ }
1555
+
1556
+ handlerMetadata.descriptor.value(...args);
1557
+ },
1558
+ close: (connection, code: number, reason: string) => {
1559
+ const pathnameKey = `${connection.data.pathname}:::close`;
1560
+ const handlerMetadata = webSocketsMap.get(pathnameKey);
1561
+
1562
+ if (!handlerMetadata) {
1563
+ return;
1564
+ }
1565
+
1566
+ const argumentsMetadata = handlerMetadata.arguments || {};
1567
+ const args: Array<unknown> = [];
1568
+
1569
+ for (const [_key, argumentMetadata] of Object.entries(argumentsMetadata)) {
1570
+ switch (argumentMetadata.type) {
1571
+ case webSocketConnectionArgsKey:
1572
+ args[argumentMetadata.index] = connection;
1573
+ break;
1574
+ case webSocketServerArgsKey:
1575
+ args[argumentMetadata.index] = server;
1576
+ break;
1577
+ case webSocketCloseCodeArgsKey:
1578
+ args[argumentMetadata.index] = code;
1579
+ break;
1580
+ case webSocketCloseReasonArgsKey:
1581
+ args[argumentMetadata.index] = reason;
1582
+ break;
1583
+ }
1584
+ }
1585
+
1586
+ handlerMetadata.descriptor.value(...args);
1587
+ },
1588
+ message: (connection, message) => {
1589
+ const pathnameKey = `${connection.data.pathname}:::message`;
1590
+ const handlerMetadata = webSocketsMap.get(pathnameKey);
1591
+
1592
+ if (!handlerMetadata) {
1593
+ return;
1594
+ }
1595
+
1596
+ const argumentsMetadata = handlerMetadata.arguments || {};
1597
+ const args: Array<unknown> = [];
1598
+
1599
+ for (const [_key, argumentMetadata] of Object.entries(argumentsMetadata)) {
1600
+ switch (argumentMetadata.type) {
1601
+ case webSocketConnectionArgsKey:
1602
+ args[argumentMetadata.index] = connection;
1603
+ break;
1604
+ case webSocketMessageArgsKey:
1605
+ args[argumentMetadata.index] = message;
1606
+ break;
1607
+ case webSocketServerArgsKey:
1608
+ args[argumentMetadata.index] = server;
1609
+ break;
1610
+ }
1611
+ }
1612
+
1613
+ handlerMetadata.descriptor.value(...args);
1614
+ },
1615
+ drain: (connection) => {
1616
+ const pathnameKey = `${connection.data.pathname}:::drain`;
1617
+ const handlerMetadata = webSocketsMap.get(pathnameKey);
1618
+
1619
+ if (!handlerMetadata) {
1620
+ return;
1621
+ }
1622
+
1623
+ const argumentsMetadata = handlerMetadata.arguments || {};
1624
+ const args: Array<unknown> = [];
1625
+
1626
+ for (const [_key, argumentMetadata] of Object.entries(argumentsMetadata)) {
1627
+ switch (argumentMetadata.type) {
1628
+ case webSocketConnectionArgsKey:
1629
+ args[argumentMetadata.index] = connection;
1630
+ break;
1631
+ case webSocketServerArgsKey:
1632
+ args[argumentMetadata.index] = server;
1633
+ break;
1634
+ }
1635
+ }
1636
+
1637
+ handlerMetadata.descriptor.value(...args);
1638
+ },
1639
+ ping: (connection, data) => {
1640
+ const pathnameKey = `${connection.data.pathname}:::ping`;
1641
+ const handlerMetadata = webSocketsMap.get(pathnameKey);
1642
+
1643
+ if (!handlerMetadata) {
1644
+ return;
1645
+ }
1646
+
1647
+ const argumentsMetadata = handlerMetadata.arguments || {};
1648
+ const args: Array<unknown> = [];
1649
+
1650
+ for (const [_key, argumentMetadata] of Object.entries(argumentsMetadata)) {
1651
+ switch (argumentMetadata.type) {
1652
+ case webSocketConnectionArgsKey:
1653
+ args[argumentMetadata.index] = connection;
1654
+ break;
1655
+ case webSocketServerArgsKey:
1656
+ args[argumentMetadata.index] = server;
1657
+ break;
1658
+ case webSocketMessageArgsKey:
1659
+ args[argumentMetadata.index] = data;
1660
+ break;
1661
+ }
1662
+ }
1663
+
1664
+ handlerMetadata.descriptor.value(...args);
1665
+ },
1666
+ pong: (connection, data) => {
1667
+ const pathnameKey = `${connection.data.pathname}:::pong`;
1668
+ const handlerMetadata = webSocketsMap.get(pathnameKey);
1669
+
1670
+ if (!handlerMetadata) {
1671
+ return;
1672
+ }
1673
+
1674
+ const argumentsMetadata = handlerMetadata.arguments || {};
1675
+ const args: Array<unknown> = [];
1676
+
1677
+ for (const [_key, argumentMetadata] of Object.entries(argumentsMetadata)) {
1678
+ switch (argumentMetadata.type) {
1679
+ case webSocketConnectionArgsKey:
1680
+ args[argumentMetadata.index] = connection;
1681
+ break;
1682
+ case webSocketServerArgsKey:
1683
+ args[argumentMetadata.index] = server;
1684
+ break;
1685
+ case webSocketMessageArgsKey:
1686
+ args[argumentMetadata.index] = data;
1687
+ break;
1688
+ }
1689
+ }
1690
+
1691
+ handlerMetadata.descriptor.value(...args);
1692
+ }
1101
1693
  }
1102
1694
  });
1103
1695
  } catch (error) {