@bool-ts/core 1.7.17 → 1.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) 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 +12 -0
  33. package/dist/entities/webSocketRoute.js +22 -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 +0 -39
  39. package/dist/hooks/factory.js +398 -63
  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 +7 -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 +35 -0
  70. package/src/entities/webSocketRouter.ts +64 -0
  71. package/src/entities/webSocketRouterGroup.ts +64 -0
  72. package/src/hooks/factory.ts +622 -95
  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/dist/entities/router.d.ts +0 -10
@@ -1,18 +1,18 @@
1
- import "colors";
2
1
  import "reflect-metadata";
3
2
  import Qs from "qs";
4
3
  import * as Zod from "zod";
5
4
  import { ETimeUnit, add as TimeAdd } from "@bool-ts/date-time";
6
- import { Router, RouterGroup } from "../entities";
5
+ import { HttpRouter, HttpRouterGroup, WebSocketRoute, WebSocketRouter, WebSocketRouterGroup } from "../entities";
7
6
  import { HttpClientError, HttpServerError, jsonErrorInfer } from "../http";
8
- import { argumentsKey, configKey, contextArgsKey, controllerHttpKey, controllerKey, moduleKey, paramArgsKey, paramsArgsKey, queryArgsKey, requestArgsKey, requestBodyArgsKey, requestHeaderArgsKey, requestHeadersArgsKey, responseBodyArgsKey, responseHeadersArgsKey, routeModelArgsKey } from "../keys";
7
+ import { argumentsKey, configKey, contextArgsKey, controllerHttpKey, controllerKey, moduleKey, paramArgsKey, paramsArgsKey, queryArgsKey, requestArgsKey, requestBodyArgsKey, requestHeaderArgsKey, requestHeadersArgsKey, responseBodyArgsKey, responseHeadersArgsKey, routeModelArgsKey, webSocketCloseCodeArgsKey, webSocketCloseReasonArgsKey, webSocketConnectionArgsKey, webSocketKey, webSocketMessageArgsKey, webSocketServerArgsKey } from "../keys";
8
+ import { ansiText, isWebSocketUpgrade } from "../ultils";
9
9
  import { Injector } from "./injector";
10
10
  const DEFAULT_STATIC_CACHE_TIME_IN_SECONDS = 900;
11
- export const responseConverter = (response) => {
11
+ const responseConverter = (response) => {
12
12
  response.headers.set("X-Powered-By", "Bool Typescript");
13
13
  return response;
14
14
  };
15
- export const controllerCreator = (controllerConstructor, group, injector, prefix) => {
15
+ const controllerCreator = ({ controllerConstructor, httpRouterGroup, injector, prefix }) => {
16
16
  if (!Reflect.getOwnMetadataKeys(controllerConstructor).includes(controllerKey)) {
17
17
  throw Error(`${controllerConstructor.name} is not a controller.`);
18
18
  }
@@ -24,8 +24,9 @@ export const controllerCreator = (controllerConstructor, group, injector, prefix
24
24
  prefix: "/",
25
25
  httpMetadata: []
26
26
  };
27
- const routesMetadata = (Reflect.getOwnMetadata(controllerHttpKey, controllerConstructor) || []);
28
- const router = new Router(`/${prefix || ""}/${controllerMetadata.prefix}`);
27
+ const routesMetadata = (Reflect.getOwnMetadata(controllerHttpKey, controllerConstructor) ||
28
+ []);
29
+ const router = new HttpRouter(`/${prefix || ""}/${controllerMetadata.prefix}`);
29
30
  routesMetadata.forEach((routeMetadata) => {
30
31
  if (typeof routeMetadata.descriptor.value !== "function") {
31
32
  return;
@@ -52,9 +53,64 @@ export const controllerCreator = (controllerConstructor, group, injector, prefix
52
53
  return route.options(routeArgument);
53
54
  }
54
55
  });
55
- return group.add(router);
56
+ return httpRouterGroup.add(router);
56
57
  };
57
- export const argumentsResolution = async (data, zodSchema, argumentIndex, funcName) => {
58
+ const webSocketCreator = ({ injector, httpRouterGroup, prefix, webSocketRouterGroup, webSocketConstructor }) => {
59
+ if (!Reflect.getOwnMetadataKeys(webSocketConstructor).includes(webSocketKey)) {
60
+ throw Error(`${webSocketConstructor.name} is not a controller.`);
61
+ }
62
+ const webSocket = injector.get(webSocketConstructor);
63
+ if (!webSocket) {
64
+ throw Error("Can not initialize webSocket.");
65
+ }
66
+ const webSocketMetadata = Reflect.getOwnMetadata(webSocketKey, webSocketConstructor) || {
67
+ prefix: "/",
68
+ events: [],
69
+ http: []
70
+ };
71
+ const fullPrefix = `/${prefix || ""}/${webSocketMetadata.prefix}`;
72
+ //#region [HTTP ROUTER]
73
+ const router = new HttpRouter(fullPrefix);
74
+ for (const [_key, httpMetadata] of Object.entries(webSocketMetadata.http)) {
75
+ if (typeof httpMetadata.descriptor?.value !== "function") {
76
+ continue;
77
+ }
78
+ const route = router.route(httpMetadata.path);
79
+ const handler = httpMetadata.descriptor.value.bind(webSocket);
80
+ const routeArgument = Object.freeze({
81
+ class: webSocketConstructor,
82
+ funcName: httpMetadata.methodName,
83
+ func: handler
84
+ });
85
+ switch (httpMetadata.httpMethod) {
86
+ case "GET":
87
+ route.get(routeArgument);
88
+ break;
89
+ case "POST":
90
+ route.post(routeArgument);
91
+ break;
92
+ }
93
+ }
94
+ httpRouterGroup.add(router);
95
+ //#endregion
96
+ //#region [WEBSOCKET ROUTER]
97
+ const webSocketRouter = new WebSocketRouter(fullPrefix);
98
+ for (const [key, event] of Object.entries(webSocketMetadata.events)) {
99
+ const webSocketRoute = new WebSocketRoute({
100
+ eventName: key,
101
+ metadata: event
102
+ });
103
+ webSocketRouter.addRoutes(webSocketRoute);
104
+ }
105
+ webSocketRouter.bind(webSocket);
106
+ webSocketRouterGroup.addRouters(webSocketRouter);
107
+ //#endregion
108
+ return Object.freeze({
109
+ httpRouterGroup: httpRouterGroup,
110
+ webSocketRouterGroup: webSocketRouterGroup
111
+ });
112
+ };
113
+ const argumentsResolution = async (data, zodSchema, argumentIndex, funcName) => {
58
114
  try {
59
115
  const validation = await zodSchema.safeParseAsync(data);
60
116
  if (!validation.success) {
@@ -85,7 +141,7 @@ export const argumentsResolution = async (data, zodSchema, argumentIndex, funcNa
85
141
  });
86
142
  }
87
143
  };
88
- export const moduleResolution = async (module, options) => {
144
+ const moduleResolution = async (module, options) => {
89
145
  if (!Reflect.getOwnMetadataKeys(module).includes(moduleKey)) {
90
146
  throw Error(`${module.name} is not a module.`);
91
147
  }
@@ -94,8 +150,9 @@ export const moduleResolution = async (module, options) => {
94
150
  if (!moduleMetadata) {
95
151
  return;
96
152
  }
97
- const { loaders, middlewares, guards, dispatchers, controllers, dependencies, prefix: modulePrefix, config: moduleConfig } = moduleMetadata;
98
- // Configuration(s)
153
+ const { loaders, middlewares, guards, dispatchers, controllers, dependencies, webSockets, prefix: modulePrefix, config: moduleConfig } = moduleMetadata;
154
+ const fullPrefix = `${options.prefix || ""}/${modulePrefix || ""}`;
155
+ //#region [Configuration(s)]
99
156
  const { config } = Object.freeze({
100
157
  config: {
101
158
  ...(typeof options.config !== "function" ? options.config : await options.config()),
@@ -106,19 +163,30 @@ export const moduleResolution = async (module, options) => {
106
163
  : await moduleConfig())
107
164
  }
108
165
  });
109
- // Register config like an injection
166
+ //#endregion
167
+ //#region [Register config like an injection]
110
168
  injector.set(configKey, config);
169
+ //#endregion
170
+ //#region [Run loader(s)]
111
171
  if (loaders) {
112
172
  const loaderFunctions = [];
113
173
  for (const [key, func] of Object.entries(loaders)) {
114
174
  loaderFunctions.push(async () => {
115
175
  try {
116
176
  const result = await func({ config });
117
- console.info(`INFO! Loader [${key}] initialized successfully.`);
177
+ console.info(`${ansiText(" INFO ", {
178
+ color: "white",
179
+ backgroundColor: "blue",
180
+ bold: true
181
+ })} Loader [${key}] initialized successfully.`);
118
182
  return result;
119
183
  }
120
184
  catch (error) {
121
- console.error(`WARNING! Loader [${key}] initialization failed.`);
185
+ console.error(`${ansiText(" WARN ", {
186
+ color: "yellow",
187
+ backgroundColor: "red",
188
+ bold: true
189
+ })} Loader [${key}] initialization failed.`);
122
190
  options.debug && console.error(error);
123
191
  throw error;
124
192
  }
@@ -130,31 +198,33 @@ export const moduleResolution = async (module, options) => {
130
198
  injector.set(key, value);
131
199
  }
132
200
  }
133
- // Dependencies
201
+ //#endregion
202
+ //#region [Dependencies]
134
203
  !dependencies || dependencies.map((dependency) => injector.get(dependency));
135
- // Middleware(s)
204
+ //#endregion
205
+ //#region [Middleware(s)]
136
206
  const startMiddlewareGroup = [];
137
207
  const endMiddlewareGroup = [];
138
- if (middlewares) {
139
- for (let i = 0; i < middlewares.length; i++) {
140
- const instance = injector.get(middlewares[i]);
208
+ middlewares &&
209
+ middlewares.forEach((middleware) => {
210
+ const instance = injector.get(middleware);
141
211
  if (instance.start && typeof instance.start === "function") {
142
212
  startMiddlewareGroup.push(Object.freeze({
143
- class: middlewares[i],
213
+ class: middleware,
144
214
  funcName: "start",
145
215
  func: instance.start.bind(instance)
146
216
  }));
147
217
  }
148
218
  if (instance.end && typeof instance.end === "function") {
149
219
  endMiddlewareGroup.push(Object.freeze({
150
- class: middlewares[i],
220
+ class: middleware,
151
221
  funcName: "end",
152
222
  func: instance.end.bind(instance)
153
223
  }));
154
224
  }
155
- }
156
- }
157
- // Guard(s)
225
+ });
226
+ //#endregion
227
+ //#region [Guard(s)]
158
228
  const guardGroup = !guards
159
229
  ? []
160
230
  : guards.map((guard) => {
@@ -165,32 +235,51 @@ export const moduleResolution = async (module, options) => {
165
235
  func: guardInstance.enforce.bind(guardInstance)
166
236
  });
167
237
  });
168
- // Before dispatcher(s)
238
+ //#endregion
239
+ //#region [Before dispatcher(s)]
169
240
  const openDispatcherGroup = [];
170
241
  const closeDispatcherGroup = [];
171
- if (dispatchers) {
172
- for (let i = 0; i < dispatchers.length; i++) {
173
- const instance = injector.get(dispatchers[i]);
242
+ dispatchers &&
243
+ dispatchers.forEach((dispatcher) => {
244
+ const instance = injector.get(dispatcher);
174
245
  if (instance.open && typeof instance.open === "function") {
175
246
  openDispatcherGroup.push(Object.freeze({
176
- class: dispatchers[i],
247
+ class: dispatcher,
177
248
  funcName: "open",
178
249
  func: instance.open.bind(instance)
179
250
  }));
180
251
  }
181
252
  if (instance.close && typeof instance.close === "function") {
182
253
  closeDispatcherGroup.push(Object.freeze({
183
- class: dispatchers[i],
254
+ class: dispatcher,
184
255
  funcName: "close",
185
256
  func: instance.close.bind(instance)
186
257
  }));
187
258
  }
188
- }
189
- }
190
- // Controller(s)
191
- const routerGroup = new RouterGroup();
259
+ });
260
+ //#endregion
261
+ //#region [Controller(s)]
262
+ const controllerRouterGroup = new HttpRouterGroup();
192
263
  controllers &&
193
- controllers.map((controllerConstructor) => controllerCreator(controllerConstructor, routerGroup, injector, `${options.prefix || ""}/${modulePrefix || ""}`));
264
+ controllers.forEach((controllerConstructor) => controllerCreator({
265
+ controllerConstructor,
266
+ httpRouterGroup: controllerRouterGroup,
267
+ injector: injector,
268
+ prefix: fullPrefix
269
+ }));
270
+ //#endregion
271
+ //#region [WebSocket(s)]
272
+ const webSocketHttpRouterGroup = new HttpRouterGroup();
273
+ const webSocketRouterGroup = new WebSocketRouterGroup();
274
+ webSockets &&
275
+ webSockets.forEach((webSocket) => webSocketCreator({
276
+ webSocketConstructor: webSocket,
277
+ httpRouterGroup: webSocketHttpRouterGroup,
278
+ webSocketRouterGroup: webSocketRouterGroup,
279
+ injector,
280
+ prefix: fullPrefix
281
+ }));
282
+ //#endregion
194
283
  return Object.freeze({
195
284
  prefix: moduleMetadata.prefix,
196
285
  injector: injector,
@@ -199,12 +288,43 @@ export const moduleResolution = async (module, options) => {
199
288
  guardGroup,
200
289
  openDispatcherGroup,
201
290
  closeDispatcherGroup,
202
- routerGroup
291
+ controllerRouterGroup,
292
+ webSocketHttpRouterGroup,
293
+ webSocketRouterGroup
203
294
  });
204
295
  };
205
- const fetcher = async (bun, bool) => {
206
- const { query, responseHeaders, route: { parameters, model }, moduleResolution: { startMiddlewareGroup, endMiddlewareGroup, guardGroup, openDispatcherGroup, closeDispatcherGroup } } = bool;
296
+ const webSocketFetcher = async (bun, bool) => {
297
+ const { request, server } = bun;
298
+ const { query, responseHeaders, route: { model } } = bool;
299
+ // Execute controller action
300
+ const isUpgrade = await model.func(...[server, request, query]);
301
+ if (typeof isUpgrade !== "boolean") {
302
+ return responseConverter(new Response(JSON.stringify({
303
+ httpCode: 500,
304
+ message: "Can not detect webSocket upgrade result.",
305
+ data: undefined
306
+ }), {
307
+ status: 500,
308
+ statusText: "Internal server error.",
309
+ headers: responseHeaders
310
+ }));
311
+ }
312
+ if (!isUpgrade) {
313
+ return responseConverter(new Response(JSON.stringify({
314
+ httpCode: 500,
315
+ message: "Can not upgrade.",
316
+ data: undefined
317
+ }), {
318
+ status: 500,
319
+ statusText: "Internal server error.",
320
+ headers: responseHeaders
321
+ }));
322
+ }
323
+ return isUpgrade;
324
+ };
325
+ const httpFetcher = async (bun, bool) => {
207
326
  const { request, server: _server } = bun;
327
+ const { query, responseHeaders, route: { parameters, model }, moduleResolution: { startMiddlewareGroup, endMiddlewareGroup, guardGroup, openDispatcherGroup, closeDispatcherGroup } } = bool;
208
328
  const context = {
209
329
  [requestHeadersArgsKey]: request.headers,
210
330
  [responseHeadersArgsKey]: responseHeaders,
@@ -242,7 +362,9 @@ const fetcher = async (bun, bool) => {
242
362
  : await argumentsResolution(await request[argsMetadata.parser || "json"](), argsMetadata.zodSchema, argsMetadata.index, collection.funcName);
243
363
  break;
244
364
  case contextArgsKey:
245
- args[argsMetadata.index] = !argsMetadata.key ? contextHook : contextHook.get(argsMetadata.key);
365
+ args[argsMetadata.index] = !argsMetadata.key
366
+ ? contextHook
367
+ : contextHook.get(argsMetadata.key);
246
368
  break;
247
369
  case requestHeadersArgsKey:
248
370
  args[argsMetadata.index] = !argsMetadata.zodSchema
@@ -270,7 +392,9 @@ const fetcher = async (bun, bool) => {
270
392
  ? !(argsMetadata.type in context)
271
393
  ? undefined
272
394
  : context[argsMetadata.type]
273
- : await argumentsResolution(!(argsMetadata.type in context) ? undefined : context[argsMetadata.type], argsMetadata.zodSchema, argsMetadata.index, collection.funcName);
395
+ : await argumentsResolution(!(argsMetadata.type in context)
396
+ ? undefined
397
+ : context[argsMetadata.type], argsMetadata.zodSchema, argsMetadata.index, collection.funcName);
274
398
  break;
275
399
  }
276
400
  }
@@ -299,7 +423,9 @@ const fetcher = async (bun, bool) => {
299
423
  : await argumentsResolution(await request[argsMetadata.parser || "json"](), argsMetadata.zodSchema, argsMetadata.index, collection.funcName);
300
424
  break;
301
425
  case contextArgsKey:
302
- args[argsMetadata.index] = !argsMetadata.key ? contextHook : contextHook.get(argsMetadata.key);
426
+ args[argsMetadata.index] = !argsMetadata.key
427
+ ? contextHook
428
+ : contextHook.get(argsMetadata.key);
303
429
  break;
304
430
  case requestHeadersArgsKey:
305
431
  args[argsMetadata.index] = !argsMetadata.zodSchema
@@ -358,7 +484,9 @@ const fetcher = async (bun, bool) => {
358
484
  : await argumentsResolution(await request[argsMetadata.parser || "json"](), argsMetadata.zodSchema, argsMetadata.index, collection.funcName);
359
485
  break;
360
486
  case contextArgsKey:
361
- args[argsMetadata.index] = !argsMetadata.key ? contextHook : contextHook.get(argsMetadata.key);
487
+ args[argsMetadata.index] = !argsMetadata.key
488
+ ? contextHook
489
+ : contextHook.get(argsMetadata.key);
362
490
  break;
363
491
  case requestHeadersArgsKey:
364
492
  args[argsMetadata.index] = !argsMetadata.zodSchema
@@ -462,7 +590,9 @@ const fetcher = async (bun, bool) => {
462
590
  : await argumentsResolution(await request[argsMetadata.parser || "json"](), argsMetadata.zodSchema, argsMetadata.index, collection.funcName);
463
591
  break;
464
592
  case contextArgsKey:
465
- args[argsMetadata.index] = !argsMetadata.key ? contextHook : contextHook.get(argsMetadata.key);
593
+ args[argsMetadata.index] = !argsMetadata.key
594
+ ? contextHook
595
+ : contextHook.get(argsMetadata.key);
466
596
  break;
467
597
  case requestHeadersArgsKey:
468
598
  args[argsMetadata.index] = !argsMetadata.zodSchema
@@ -517,7 +647,9 @@ const fetcher = async (bun, bool) => {
517
647
  : await argumentsResolution(await request[argsMetadata.parser || "json"](), argsMetadata.zodSchema, argsMetadata.index, collection.funcName);
518
648
  break;
519
649
  case contextArgsKey:
520
- args[argsMetadata.index] = !argsMetadata.key ? contextHook : contextHook.get(argsMetadata.key);
650
+ args[argsMetadata.index] = !argsMetadata.key
651
+ ? contextHook
652
+ : contextHook.get(argsMetadata.key);
521
653
  break;
522
654
  case requestHeadersArgsKey:
523
655
  args[argsMetadata.index] = !argsMetadata.zodSchema
@@ -545,7 +677,9 @@ const fetcher = async (bun, bool) => {
545
677
  ? !(argsMetadata.type in context)
546
678
  ? undefined
547
679
  : context[argsMetadata.type]
548
- : await argumentsResolution(!(argsMetadata.type in context) ? undefined : context[argsMetadata.type], argsMetadata.zodSchema, argsMetadata.index, collection.funcName);
680
+ : await argumentsResolution(!(argsMetadata.type in context)
681
+ ? undefined
682
+ : context[argsMetadata.type], argsMetadata.zodSchema, argsMetadata.index, collection.funcName);
549
683
  break;
550
684
  }
551
685
  }
@@ -581,9 +715,18 @@ export const BoolFactory = async (modules, options) => {
581
715
  ? ["*"]
582
716
  : options.cors.origins
583
717
  : [options.cors.origins !== "*" ? options.cors.origins : "*"],
584
- allowMethods: options.cors?.methods || ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"],
718
+ allowMethods: options.cors?.methods || [
719
+ "GET",
720
+ "POST",
721
+ "PUT",
722
+ "PATCH",
723
+ "DELETE",
724
+ "OPTIONS"
725
+ ],
585
726
  allowCredentials: !options.cors?.credentials ? false : true,
586
- allowHeaders: !options.cors?.headers || options.cors.headers.includes("*") ? ["*"] : options.cors.headers
727
+ allowHeaders: !options.cors?.headers || options.cors.headers.includes("*")
728
+ ? ["*"]
729
+ : options.cors.headers
587
730
  });
588
731
  const moduleResolutions = await Promise.all(modulesConverted.map((moduleConverted) => moduleResolution(moduleConverted, options)));
589
732
  const availableModuleResolutions = moduleResolutions.filter((moduleResolution) => typeof moduleResolution !== "undefined");
@@ -591,9 +734,16 @@ export const BoolFactory = async (modules, options) => {
591
734
  ...new Set(availableModuleResolutions.map((availableModuleResolution) => availableModuleResolution.prefix))
592
735
  ];
593
736
  if (prefixs.length !== availableModuleResolutions.length) {
594
- throw Error(`Module prefix should be unique.`);
737
+ throw Error("Module prefix should be unique.");
738
+ }
739
+ const webSocketsMap = new Map();
740
+ for (const availableModuleResolution of availableModuleResolutions) {
741
+ const webSocketMap = availableModuleResolution.webSocketRouterGroup.execute();
742
+ for (const [key, metadata] of webSocketMap.entries()) {
743
+ webSocketsMap.set(key, metadata);
744
+ }
595
745
  }
596
- Bun.serve({
746
+ const server = Bun.serve({
597
747
  port: options.port,
598
748
  fetch: async (request, server) => {
599
749
  const start = performance.now();
@@ -603,10 +753,50 @@ export const BoolFactory = async (modules, options) => {
603
753
  const method = request.method.toUpperCase();
604
754
  const responseHeaders = new Headers();
605
755
  try {
606
- allowCredentials && responseHeaders.set("Access-Control-Allow-Credentials", "true");
756
+ const isUpgradable = isWebSocketUpgrade(request);
757
+ let collection;
758
+ if (isUpgradable) {
759
+ for (const availableModuleResolution of availableModuleResolutions) {
760
+ const routeResult = availableModuleResolution.webSocketHttpRouterGroup.find(url.pathname, request.method);
761
+ if (routeResult) {
762
+ collection = Object.freeze({
763
+ route: routeResult,
764
+ resolution: availableModuleResolution
765
+ });
766
+ break;
767
+ }
768
+ }
769
+ if (!collection) {
770
+ return responseConverter(new Response(JSON.stringify({
771
+ httpCode: 404,
772
+ message: "Route not found",
773
+ data: undefined
774
+ }), {
775
+ status: 404,
776
+ statusText: "Not found.",
777
+ headers: responseHeaders
778
+ }));
779
+ }
780
+ const upgradeResult = await webSocketFetcher({
781
+ request,
782
+ server
783
+ }, {
784
+ query: query,
785
+ responseHeaders: responseHeaders,
786
+ route: collection.route,
787
+ moduleResolution: collection.resolution
788
+ });
789
+ return upgradeResult instanceof Response ? upgradeResult : undefined;
790
+ }
791
+ allowCredentials &&
792
+ responseHeaders.set("Access-Control-Allow-Credentials", "true");
607
793
  responseHeaders.set("Access-Control-Allow-Methods", allowMethods.join(", "));
608
794
  responseHeaders.set("Access-Control-Allow-Headers", allowHeaders.join(", "));
609
- responseHeaders.set("Access-Control-Allow-Origin", allowOrigins.includes("*") ? "*" : !allowOrigins.includes(origin) ? allowOrigins[0] : origin);
795
+ responseHeaders.set("Access-Control-Allow-Origin", allowOrigins.includes("*")
796
+ ? "*"
797
+ : !allowOrigins.includes(origin)
798
+ ? allowOrigins[0]
799
+ : origin);
610
800
  if (!allowMethods.includes(method)) {
611
801
  return responseConverter(new Response(undefined, {
612
802
  status: 405,
@@ -676,13 +866,12 @@ export const BoolFactory = async (modules, options) => {
676
866
  }
677
867
  }
678
868
  }
679
- let collection;
680
- for (let i = 0; i < availableModuleResolutions.length; i++) {
681
- const routeResult = availableModuleResolutions[i].routerGroup.find(url.pathname, request.method);
869
+ for (const availableModuleResolution of availableModuleResolutions) {
870
+ const routeResult = availableModuleResolution.controllerRouterGroup.find(url.pathname, request.method);
682
871
  if (routeResult) {
683
872
  collection = Object.freeze({
684
873
  route: routeResult,
685
- resolution: availableModuleResolutions[i]
874
+ resolution: availableModuleResolution
686
875
  });
687
876
  break;
688
877
  }
@@ -698,7 +887,7 @@ export const BoolFactory = async (modules, options) => {
698
887
  headers: responseHeaders
699
888
  }));
700
889
  }
701
- return await fetcher({
890
+ return await httpFetcher({
702
891
  request,
703
892
  server
704
893
  }, {
@@ -715,16 +904,162 @@ export const BoolFactory = async (modules, options) => {
715
904
  finally {
716
905
  if (allowLogsMethods) {
717
906
  const end = performance.now();
718
- const convertedPID = `${process.pid}`.yellow;
719
- const convertedMethod = `${request.method.yellow}`.bgBlue;
720
- const convertedReqIp = `${request.headers.get("x-forwarded-for") ||
907
+ const pathname = ansiText(url.pathname, { color: "blue" });
908
+ const convertedPID = `${Bun.color("yellow", "ansi")}${process.pid}`;
909
+ const convertedMethod = ansiText(request.method, {
910
+ color: "yellow",
911
+ backgroundColor: "blue"
912
+ });
913
+ const convertedReqIp = ansiText(`${request.headers.get("x-forwarded-for") ||
721
914
  request.headers.get("x-real-ip") ||
722
915
  server.requestIP(request)?.address ||
723
- "<Unknown>"}`.yellow;
724
- const convertedTime = `${Math.round((end - start + Number.EPSILON) * 10 ** 2) / 10 ** 2}ms`.yellow;
916
+ "<Unknown>"}`, {
917
+ color: "yellow"
918
+ });
919
+ const convertedTime = ansiText(`${Math.round((end - start + Number.EPSILON) * 10 ** 2) / 10 ** 2}ms`, {
920
+ color: "yellow",
921
+ backgroundColor: "blue"
922
+ });
725
923
  allowLogsMethods.includes(request.method.toUpperCase()) &&
726
- console.info(`PID: ${convertedPID} - Method: ${convertedMethod} - IP: ${convertedReqIp} - ${new URL(request.url).pathname.blue} - Time: ${convertedTime}`);
924
+ console.info(`PID: ${convertedPID} - Method: ${convertedMethod} - IP: ${convertedReqIp} - ${pathname} - Time: ${convertedTime}`);
925
+ }
926
+ }
927
+ },
928
+ websocket: {
929
+ open: (connection) => {
930
+ const pathnameKey = `${connection.data.pathname}:::open`;
931
+ const handlerMetadata = webSocketsMap.get(pathnameKey);
932
+ if (!handlerMetadata) {
933
+ return;
934
+ }
935
+ const argumentsMetadata = handlerMetadata.arguments || {};
936
+ const args = [];
937
+ for (const [_key, argumentMetadata] of Object.entries(argumentsMetadata)) {
938
+ switch (argumentMetadata.type) {
939
+ case webSocketConnectionArgsKey:
940
+ args[argumentMetadata.index] = connection;
941
+ break;
942
+ case webSocketServerArgsKey:
943
+ args[argumentMetadata.index] = server;
944
+ break;
945
+ }
946
+ }
947
+ handlerMetadata.descriptor.value(...args);
948
+ },
949
+ close: (connection, code, reason) => {
950
+ const pathnameKey = `${connection.data.pathname}:::close`;
951
+ const handlerMetadata = webSocketsMap.get(pathnameKey);
952
+ if (!handlerMetadata) {
953
+ return;
954
+ }
955
+ const argumentsMetadata = handlerMetadata.arguments || {};
956
+ const args = [];
957
+ for (const [_key, argumentMetadata] of Object.entries(argumentsMetadata)) {
958
+ switch (argumentMetadata.type) {
959
+ case webSocketConnectionArgsKey:
960
+ args[argumentMetadata.index] = connection;
961
+ break;
962
+ case webSocketServerArgsKey:
963
+ args[argumentMetadata.index] = server;
964
+ break;
965
+ case webSocketCloseCodeArgsKey:
966
+ args[argumentMetadata.index] = code;
967
+ break;
968
+ case webSocketCloseReasonArgsKey:
969
+ args[argumentMetadata.index] = reason;
970
+ break;
971
+ }
972
+ }
973
+ handlerMetadata.descriptor.value(...args);
974
+ },
975
+ message: (connection, message) => {
976
+ const pathnameKey = `${connection.data.pathname}:::message`;
977
+ const handlerMetadata = webSocketsMap.get(pathnameKey);
978
+ if (!handlerMetadata) {
979
+ return;
980
+ }
981
+ const argumentsMetadata = handlerMetadata.arguments || {};
982
+ const args = [];
983
+ for (const [_key, argumentMetadata] of Object.entries(argumentsMetadata)) {
984
+ switch (argumentMetadata.type) {
985
+ case webSocketConnectionArgsKey:
986
+ args[argumentMetadata.index] = connection;
987
+ break;
988
+ case webSocketMessageArgsKey:
989
+ args[argumentMetadata.index] = message;
990
+ break;
991
+ case webSocketServerArgsKey:
992
+ args[argumentMetadata.index] = server;
993
+ break;
994
+ }
995
+ }
996
+ handlerMetadata.descriptor.value(...args);
997
+ },
998
+ drain: (connection) => {
999
+ const pathnameKey = `${connection.data.pathname}:::drain`;
1000
+ const handlerMetadata = webSocketsMap.get(pathnameKey);
1001
+ if (!handlerMetadata) {
1002
+ return;
1003
+ }
1004
+ const argumentsMetadata = handlerMetadata.arguments || {};
1005
+ const args = [];
1006
+ for (const [_key, argumentMetadata] of Object.entries(argumentsMetadata)) {
1007
+ switch (argumentMetadata.type) {
1008
+ case webSocketConnectionArgsKey:
1009
+ args[argumentMetadata.index] = connection;
1010
+ break;
1011
+ case webSocketServerArgsKey:
1012
+ args[argumentMetadata.index] = server;
1013
+ break;
1014
+ }
1015
+ }
1016
+ handlerMetadata.descriptor.value(...args);
1017
+ },
1018
+ ping: (connection, data) => {
1019
+ const pathnameKey = `${connection.data.pathname}:::ping`;
1020
+ const handlerMetadata = webSocketsMap.get(pathnameKey);
1021
+ if (!handlerMetadata) {
1022
+ return;
1023
+ }
1024
+ const argumentsMetadata = handlerMetadata.arguments || {};
1025
+ const args = [];
1026
+ for (const [_key, argumentMetadata] of Object.entries(argumentsMetadata)) {
1027
+ switch (argumentMetadata.type) {
1028
+ case webSocketConnectionArgsKey:
1029
+ args[argumentMetadata.index] = connection;
1030
+ break;
1031
+ case webSocketServerArgsKey:
1032
+ args[argumentMetadata.index] = server;
1033
+ break;
1034
+ case webSocketMessageArgsKey:
1035
+ args[argumentMetadata.index] = data;
1036
+ break;
1037
+ }
1038
+ }
1039
+ handlerMetadata.descriptor.value(...args);
1040
+ },
1041
+ pong: (connection, data) => {
1042
+ const pathnameKey = `${connection.data.pathname}:::pong`;
1043
+ const handlerMetadata = webSocketsMap.get(pathnameKey);
1044
+ if (!handlerMetadata) {
1045
+ return;
1046
+ }
1047
+ const argumentsMetadata = handlerMetadata.arguments || {};
1048
+ const args = [];
1049
+ for (const [_key, argumentMetadata] of Object.entries(argumentsMetadata)) {
1050
+ switch (argumentMetadata.type) {
1051
+ case webSocketConnectionArgsKey:
1052
+ args[argumentMetadata.index] = connection;
1053
+ break;
1054
+ case webSocketServerArgsKey:
1055
+ args[argumentMetadata.index] = server;
1056
+ break;
1057
+ case webSocketMessageArgsKey:
1058
+ args[argumentMetadata.index] = data;
1059
+ break;
1060
+ }
727
1061
  }
1062
+ handlerMetadata.descriptor.value(...args);
728
1063
  }
729
1064
  }
730
1065
  });