@bool-ts/core 1.9.28 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/decorators/arguments.d.ts +19 -20
  2. package/dist/decorators/container.d.ts +10 -11
  3. package/dist/decorators/http.d.ts +11 -11
  4. package/dist/decorators/index.d.ts +1 -2
  5. package/dist/entities/application.d.ts +111 -0
  6. package/dist/entities/context.d.ts +14 -0
  7. package/dist/entities/httpRoute.d.ts +18 -9
  8. package/dist/entities/httpRouter.d.ts +13 -0
  9. package/dist/entities/httpRouterGroup.d.ts +6 -0
  10. package/dist/entities/index.d.ts +2 -0
  11. package/dist/entities/injector.d.ts +29 -0
  12. package/dist/entities/validationFailed.d.ts +5 -0
  13. package/dist/entities/webSocketRoute.d.ts +1 -0
  14. package/dist/entities/webSocketRouter.d.ts +1 -0
  15. package/dist/entities/webSocketRouterGroup.d.ts +1 -0
  16. package/dist/index.d.ts +1 -0
  17. package/dist/index.js +6 -6
  18. package/dist/index.js.map +22 -21
  19. package/dist/interfaces/customValidator.d.ts +4 -0
  20. package/dist/interfaces/index.d.ts +1 -0
  21. package/dist/producers/factory.d.ts +3 -1
  22. package/dist/producers/index.d.ts +1 -1
  23. package/package.json +2 -2
  24. package/src/decorators/arguments.ts +44 -39
  25. package/src/decorators/container.ts +12 -12
  26. package/src/decorators/http.ts +8 -8
  27. package/src/decorators/index.ts +1 -2
  28. package/src/entities/application.ts +2236 -0
  29. package/src/{producers → entities}/context.ts +2 -0
  30. package/src/entities/httpRoute.ts +18 -9
  31. package/src/entities/httpRouter.ts +13 -0
  32. package/src/entities/httpRouterGroup.ts +10 -4
  33. package/src/entities/index.ts +2 -0
  34. package/src/entities/validationFailed.ts +5 -0
  35. package/src/entities/webSocketRoute.ts +2 -0
  36. package/src/entities/webSocketRouter.ts +2 -0
  37. package/src/entities/webSocketRouterGroup.ts +2 -0
  38. package/src/index.ts +1 -0
  39. package/src/interfaces/customValidator.ts +10 -0
  40. package/src/interfaces/index.ts +1 -0
  41. package/src/producers/factory.ts +7 -2037
  42. package/src/producers/index.ts +1 -1
  43. package/src/decorators/zodSchema.ts +0 -21
  44. /package/src/{producers → entities}/injector.ts +0 -0
@@ -1,59 +1,11 @@
1
- import type { BunFile, Server } from "bun";
2
- import type {
3
- TContainerMetadata,
4
- TControllerMetadata,
5
- TModuleMetadata,
6
- TWebSocketEventHandlerMetadata,
7
- TWebSocketMetadata
8
- } from "../decorators";
9
1
  import type { TArgumentsMetadataCollection } from "../decorators/arguments";
10
- import type { TWebSocketUpgradeData } from "../decorators/webSocket";
11
- import type { IGuard, IInterceptor, IMiddleware } from "../interfaces";
2
+ import type { TConstructor } from "../ultils";
12
3
 
13
4
  import "reflect-metadata";
14
5
 
15
6
  import Qs from "qs";
16
- import * as Zod from "zod";
17
7
 
18
- import { ETimeUnit, add as TimeAdd } from "@bool-ts/date-time";
19
- import {
20
- HttpRouter,
21
- HttpRouterGroup,
22
- WebSocketRoute,
23
- WebSocketRouter,
24
- WebSocketRouterGroup
25
- } from "../entities";
26
- import { HttpClientError, HttpServerError, jsonErrorInfer, type THttpMethods } from "../http";
27
- import {
28
- argumentsKey,
29
- configKey,
30
- containerKey,
31
- contextArgsKey,
32
- controllerKey,
33
- httpServerArgsKey,
34
- moduleKey,
35
- paramArgsKey,
36
- paramsArgsKey,
37
- queryArgsKey,
38
- requestArgsKey,
39
- requestBodyArgsKey,
40
- requestHeaderArgsKey,
41
- requestHeadersArgsKey,
42
- responseBodyArgsKey,
43
- responseHeadersArgsKey,
44
- responseStatusArgsKey,
45
- responseStatusTextArgsKey,
46
- routeModelArgsKey,
47
- webSocketCloseCodeArgsKey,
48
- webSocketCloseReasonArgsKey,
49
- webSocketConnectionArgsKey,
50
- webSocketKey,
51
- webSocketMessageArgsKey,
52
- webSocketServerArgsKey
53
- } from "../keys";
54
- import { ansiText, isWebSocketUpgrade } from "../ultils";
55
- import { Context } from "./context";
56
- import { Injector } from "./injector";
8
+ import { Application } from "../entities";
57
9
 
58
10
  export type TParamsType = Record<string, string>;
59
11
 
@@ -94,1998 +46,16 @@ export type TBoolFactoryOptions = Required<{
94
46
  }>;
95
47
  }>;
96
48
 
97
- const DEFAULT_STATIC_CACHE_TIME_IN_SECONDS = 900;
98
-
99
- const responseConverter = (response: Response) => {
100
- response.headers.set("X-Powered-By", "Bool Typescript");
101
-
102
- return response;
103
- };
104
-
105
- const responseSerialize = ({
106
- status,
107
- statusText,
108
- headers,
109
- data
110
- }: {
111
- status?: number;
112
- statusText?: string;
113
- headers: Headers;
114
- data: unknown;
115
- }): Response => {
116
- const contentType = headers.get("Content-Type") || "text/plain";
117
-
118
- if (contentType.includes("application/json")) {
119
- return responseConverter(
120
- new Response(data instanceof ReadableStream ? data : JSON.stringify(data), {
121
- status: status,
122
- statusText: statusText,
123
- headers: headers
124
- })
125
- );
126
- }
127
-
128
- if (contentType.includes("text/plain") || contentType.includes("text/html")) {
129
- return responseConverter(
130
- new Response(data instanceof ReadableStream ? data : String(data), {
131
- status: status,
132
- statusText: statusText,
133
- headers: headers
134
- })
135
- );
136
- }
137
-
138
- if (contentType.includes("application/octet-stream")) {
139
- if (
140
- data instanceof Uint8Array ||
141
- data instanceof ArrayBuffer ||
142
- data instanceof Blob ||
143
- data instanceof ReadableStream
144
- ) {
145
- return responseConverter(
146
- new Response(data, { status: status, statusText: statusText, headers: headers })
147
- );
148
- }
149
-
150
- throw new Error("Invalid data type for application/octet-stream");
151
- }
152
-
153
- if (contentType.includes("multipart/form-data")) {
154
- if (data instanceof FormData) {
155
- return responseConverter(
156
- new Response(data, { status: status, statusText: statusText, headers: headers })
157
- );
158
- }
159
-
160
- throw new Error("multipart/form-data requires FormData object");
161
- }
162
-
163
- return responseConverter(
164
- new Response(String(data), { status: status, statusText: statusText, headers: headers })
165
- );
166
- };
167
-
168
- const controllerCreator = ({
169
- controllerConstructor,
170
- httpRouterGroup,
171
- injector,
172
- prefix
173
- }: Readonly<{
174
- controllerConstructor: new (...args: any[]) => unknown;
175
- httpRouterGroup: HttpRouterGroup;
176
- injector: Injector;
177
- prefix?: string;
178
- }>) => {
179
- if (!Reflect.getOwnMetadataKeys(controllerConstructor).includes(controllerKey)) {
180
- throw Error(`${controllerConstructor.name} is not a controller.`);
181
- }
182
-
183
- const controller = injector.get(controllerConstructor);
184
-
185
- if (!controller) {
186
- throw Error("Can not initialize controller.");
187
- }
188
-
189
- const controllerMetadata: TControllerMetadata = Reflect.getOwnMetadata(
190
- controllerKey,
191
- controllerConstructor
192
- ) || {
193
- prefix: "/",
194
- httpMetadata: []
195
- };
196
-
197
- const router = new HttpRouter(`/${prefix || ""}/${controllerMetadata.prefix}`);
198
-
199
- controllerMetadata.httpMetadata.forEach((routeMetadata) => {
200
- if (typeof routeMetadata.descriptor.value !== "function") {
201
- return;
202
- }
203
-
204
- const route = router.route(routeMetadata.path);
205
- const handler = routeMetadata.descriptor.value.bind(controller);
206
- const routeArgument = Object.freeze({
207
- class: controllerConstructor,
208
- funcName: routeMetadata.methodName,
209
- func: handler,
210
- argumentsMetadata: routeMetadata.argumentsMetadata
211
- });
212
-
213
- switch (routeMetadata.httpMethod) {
214
- case "GET":
215
- return route.get(routeArgument);
216
- case "POST":
217
- return route.post(routeArgument);
218
- case "PUT":
219
- return route.put(routeArgument);
220
- case "PATCH":
221
- return route.patch(routeArgument);
222
- case "DELETE":
223
- return route.delete(routeArgument);
224
- case "OPTIONS":
225
- return route.options(routeArgument);
226
- }
227
- });
228
-
229
- return httpRouterGroup.add(router);
230
- };
231
-
232
- const webSocketCreator = ({
233
- injector,
234
- httpRouterGroup,
235
- prefix,
236
- webSocketRouterGroup,
237
- webSocketConstructor
238
- }: Readonly<{
239
- webSocketConstructor: new (...args: any[]) => unknown;
240
- httpRouterGroup: HttpRouterGroup;
241
- webSocketRouterGroup: WebSocketRouterGroup;
242
- injector: Injector;
243
- prefix?: string;
244
- }>): Readonly<{
245
- httpRouterGroup: HttpRouterGroup;
246
- webSocketRouterGroup: WebSocketRouterGroup;
247
- }> => {
248
- if (!Reflect.getOwnMetadataKeys(webSocketConstructor).includes(webSocketKey)) {
249
- throw Error(`${webSocketConstructor.name} is not a websocket route.`);
250
- }
251
-
252
- const webSocket = injector.get(webSocketConstructor);
253
-
254
- if (!webSocket) {
255
- throw Error("Can not initialize webSocket.");
256
- }
257
-
258
- const webSocketMetadata: TWebSocketMetadata = Reflect.getOwnMetadata(
259
- webSocketKey,
260
- webSocketConstructor
261
- ) || {
262
- prefix: "/",
263
- events: [],
264
- http: []
265
- };
266
-
267
- const fullPrefix = `/${prefix || ""}/${webSocketMetadata.prefix}`;
268
-
269
- //#region [HTTP ROUTER]
270
- const router = new HttpRouter(fullPrefix);
271
-
272
- for (const [_key, httpMetadata] of Object.entries(webSocketMetadata.http)) {
273
- if (typeof httpMetadata.descriptor?.value !== "function") {
274
- continue;
275
- }
276
-
277
- const route = router.route(httpMetadata.path);
278
- const handler = httpMetadata.descriptor.value.bind(webSocket);
279
- const routeArgument = Object.freeze({
280
- class: webSocketConstructor,
281
- funcName: httpMetadata.methodName,
282
- func: handler,
283
- argumentsMetadata: httpMetadata.argumentsMetadata
284
- });
285
-
286
- switch (httpMetadata.httpMethod) {
287
- case "GET":
288
- route.get(routeArgument);
289
- break;
290
- case "POST":
291
- route.post(routeArgument);
292
- break;
293
- }
294
- }
295
-
296
- httpRouterGroup.add(router);
297
- //#endregion
298
-
299
- //#region [WEBSOCKET ROUTER]
300
- const webSocketRouter = new WebSocketRouter(fullPrefix);
301
-
302
- for (const [key, event] of Object.entries(webSocketMetadata.events)) {
303
- const webSocketRoute = new WebSocketRoute({
304
- eventName: key,
305
- metadata: event
306
- });
307
-
308
- webSocketRouter.addRoutes(webSocketRoute);
309
- }
310
-
311
- webSocketRouter.bind(webSocket);
312
- webSocketRouterGroup.addRouters(webSocketRouter);
313
- //#endregion
314
-
315
- return Object.freeze({
316
- httpRouterGroup: httpRouterGroup,
317
- webSocketRouterGroup: webSocketRouterGroup
318
- });
319
- };
320
-
321
- const argumentsResolution = async (
322
- data: unknown,
323
- zodSchema: Zod.Schema,
324
- argumentIndex: number,
325
- funcName: string | symbol
326
- ) => {
327
- try {
328
- const validation = await zodSchema.safeParseAsync(data);
329
-
330
- if (!validation.success) {
331
- throw new HttpClientError({
332
- httpCode: 400,
333
- message: `Validation at the [${funcName.toString()}] method fails at positional argument [${argumentIndex}].`,
334
- data: validation.error.issues
335
- });
336
- }
337
-
338
- return validation.data;
339
- } catch (error) {
340
- if (error instanceof HttpClientError) {
341
- throw error;
342
- }
343
-
344
- throw new HttpServerError({
345
- httpCode: 500,
346
- message: `Validation at the [${funcName.toString()}] method error at positional argument [${argumentIndex}].`,
347
- data: !(error instanceof Error)
348
- ? error
349
- : [
350
- {
351
- message: error.message,
352
- code: error.name,
353
- cause: error.cause
354
- }
355
- ]
356
- });
357
- }
358
- };
359
-
360
- const containerResolution = async ({
361
- containerClass,
362
- options,
363
- extendInjector
364
- }: {
365
- containerClass: new (...args: any[]) => unknown;
366
- options: TBoolFactoryOptions;
367
- extendInjector: Injector;
368
- }) => {
369
- if (!Reflect.getOwnMetadataKeys(containerClass).includes(containerKey)) {
370
- throw Error(`${containerClass.name} is not a container.`);
371
- }
372
-
373
- const injector = new Injector(extendInjector);
374
- const containerMetadata: TContainerMetadata = Reflect.getOwnMetadata(
375
- containerKey,
376
- containerClass
377
- );
378
-
379
- const {
380
- loaders,
381
- middlewares,
382
- guards,
383
- dependencies,
384
- config: containerConfig
385
- } = containerMetadata || {};
386
-
387
- //#region [Configuration(s)]
388
- const { config } = Object.freeze({
389
- config: {
390
- ...(typeof options.config !== "function" ? options.config : await options.config()),
391
- ...(typeof containerConfig !== "function"
392
- ? typeof containerConfig !== "object"
393
- ? undefined
394
- : "key" in containerConfig &&
395
- "value" in containerConfig &&
396
- typeof containerConfig.key === "symbol"
397
- ? typeof containerConfig.value !== "function"
398
- ? containerConfig.value
399
- : await containerConfig.value()
400
- : containerConfig
401
- : await containerConfig())
402
- }
403
- });
404
- //#endregion
405
-
406
- //#region [Register config like an injection]
407
- injector.set(
408
- containerConfig &&
409
- "key" in containerConfig &&
410
- "value" in containerConfig &&
411
- typeof containerConfig.key === "symbol"
412
- ? containerConfig.key
413
- : configKey,
414
- config
415
- );
416
- //#endregion
417
-
418
- //#region [Run loader(s)]
419
- if (loaders) {
420
- const loaderFunctions = [];
421
-
422
- for (const [key, func] of Object.entries(loaders)) {
423
- loaderFunctions.push(async () => {
424
- try {
425
- const result = await func({ config });
426
-
427
- console.info(
428
- `${ansiText(" INFO ", {
429
- color: "white",
430
- backgroundColor: "blue",
431
- bold: true
432
- })} Loader [${key}] initialized successfully.`
433
- );
434
-
435
- return result;
436
- } catch (error) {
437
- console.error(
438
- `${ansiText(" WARN ", {
439
- color: "yellow",
440
- backgroundColor: "red",
441
- bold: true
442
- })} Loader [${key}] initialization failed.`
443
- );
444
- options.debug && console.error(error);
445
- throw error;
446
- }
447
- });
448
- }
449
-
450
- const results = await Promise.all(loaderFunctions.map((func) => func()));
451
-
452
- for (let i = 0; i < results.length; i++) {
453
- const [key, value] = results[i];
454
- injector.set(key, value);
455
- }
456
- }
457
- //#endregion
458
-
459
- //#region [Dependencies]
460
- !dependencies || dependencies.map((dependency) => injector.get(dependency));
461
- //#endregion
462
-
463
- //#region [Middleware(s)]
464
- const startMiddlewareGroup: Array<
465
- TGroupElementModel<"start", IMiddleware, NonNullable<IMiddleware["start"]>>
466
- > = [];
467
- const endMiddlewareGroup: Array<
468
- TGroupElementModel<"end", IMiddleware, NonNullable<IMiddleware["end"]>>
469
- > = [];
470
-
471
- !middlewares ||
472
- middlewares.forEach((middleware) => {
473
- const instance = injector.get<IMiddleware>(middleware);
474
-
475
- if (instance.start && typeof instance.start === "function") {
476
- const argumentsMetadata: TArgumentsMetadataCollection =
477
- Reflect.getOwnMetadata(argumentsKey, middleware, "start") || {};
478
-
479
- startMiddlewareGroup.push(
480
- Object.freeze({
481
- class: middleware as IMiddleware,
482
- funcName: "start",
483
- func: instance.start.bind(instance),
484
- argumentsMetadata: argumentsMetadata
485
- })
486
- );
487
- }
488
-
489
- if (instance.end && typeof instance.end === "function") {
490
- const argumentsMetadata: TArgumentsMetadataCollection =
491
- Reflect.getOwnMetadata(argumentsKey, middleware, "end") || {};
492
-
493
- endMiddlewareGroup.push(
494
- Object.freeze({
495
- class: middleware as IMiddleware,
496
- funcName: "end",
497
- func: instance.end.bind(instance),
498
- argumentsMetadata: argumentsMetadata
499
- })
500
- );
501
- }
502
- });
503
- //#endregion
504
-
505
- //#region [Guard(s)]
506
- const guardGroup: Array<TGroupElementModel<"enforce", IGuard, NonNullable<IGuard["enforce"]>>> =
507
- !guards
508
- ? []
509
- : guards.map((guard) => {
510
- const guardInstance = injector.get<IGuard>(guard);
511
- const argumentsMetadata: TArgumentsMetadataCollection =
512
- Reflect.getOwnMetadata(argumentsKey, guard, "enforce") || {};
513
-
514
- return Object.freeze({
515
- class: guard as unknown as IGuard,
516
- funcName: "enforce",
517
- func: guardInstance.enforce.bind(guardInstance),
518
- argumentsMetadata: argumentsMetadata
519
- });
520
- });
521
- //#endregion
522
-
523
- return Object.freeze({
524
- injector,
525
- startMiddlewareGroup,
526
- endMiddlewareGroup,
527
- guardGroup
528
- });
529
- };
530
-
531
- const moduleResolution = async ({
532
- moduleClass,
533
- options,
534
- extendInjector
535
- }: {
536
- moduleClass: new (...args: any[]) => unknown;
537
- options: TBoolFactoryOptions;
538
- extendInjector: Injector;
539
- }) => {
540
- if (!Reflect.getOwnMetadataKeys(moduleClass).includes(moduleKey)) {
541
- throw Error(`${moduleClass.name} is not a module.`);
542
- }
543
-
544
- const injector = new Injector(extendInjector);
545
- const moduleMetadata: TModuleMetadata = Reflect.getOwnMetadata(moduleKey, moduleClass);
546
-
547
- const {
548
- loaders,
549
- middlewares,
550
- guards,
551
- interceptors,
552
- controllers,
553
- dependencies,
554
- webSockets,
555
- prefix: modulePrefix,
556
- config: moduleConfig
557
- } = moduleMetadata || {};
558
-
559
- const fullPrefix = `${options.prefix || ""}/${modulePrefix || ""}`;
560
-
561
- //#region [Configuration(s)]
562
- const { config } = Object.freeze({
563
- config: {
564
- ...(typeof options.config !== "function" ? options.config : await options.config()),
565
- ...(typeof moduleConfig !== "function"
566
- ? typeof moduleConfig !== "object"
567
- ? undefined
568
- : "key" in moduleConfig &&
569
- "value" in moduleConfig &&
570
- typeof moduleConfig.key === "symbol"
571
- ? typeof moduleConfig.value !== "function"
572
- ? moduleConfig.value
573
- : await moduleConfig.value()
574
- : moduleConfig
575
- : await moduleConfig())
576
- }
577
- });
578
- //#endregion
579
-
580
- //#region [Register config like an injection]
581
- injector.set(
582
- moduleConfig &&
583
- "key" in moduleConfig &&
584
- "value" in moduleConfig &&
585
- typeof moduleConfig.key === "symbol"
586
- ? moduleConfig.key
587
- : configKey,
588
- config
589
- );
590
- //#endregion
591
-
592
- //#region [Run loader(s)]
593
- if (loaders) {
594
- const loaderFunctions = [];
595
-
596
- for (const [key, func] of Object.entries(loaders)) {
597
- loaderFunctions.push(async () => {
598
- try {
599
- const result = await func({ config });
600
-
601
- console.info(
602
- `${ansiText(" INFO ", {
603
- color: "white",
604
- backgroundColor: "blue",
605
- bold: true
606
- })} Loader [${key}] initialized successfully.`
607
- );
608
-
609
- return result;
610
- } catch (error) {
611
- console.error(
612
- `${ansiText(" WARN ", {
613
- color: "yellow",
614
- backgroundColor: "red",
615
- bold: true
616
- })} Loader [${key}] initialization failed.`
617
- );
618
- options.debug && console.error(error);
619
- throw error;
620
- }
621
- });
622
- }
623
-
624
- const results = await Promise.all(loaderFunctions.map((func) => func()));
625
-
626
- for (let i = 0; i < results.length; i++) {
627
- const [key, value] = results[i];
628
- injector.set(key, value);
629
- }
630
- }
631
- //#endregion
632
-
633
- //#region [Dependencies]
634
- !dependencies || dependencies.map((dependency) => injector.get(dependency));
635
- //#endregion
636
-
637
- //#region [Middleware(s)]
638
- const startMiddlewareGroup: Array<
639
- TGroupElementModel<"start", IMiddleware, NonNullable<IMiddleware["start"]>>
640
- > = [];
641
- const endMiddlewareGroup: Array<
642
- TGroupElementModel<"end", IMiddleware, NonNullable<IMiddleware["end"]>>
643
- > = [];
644
-
645
- !middlewares ||
646
- middlewares.forEach((middleware) => {
647
- const instance = injector.get<IMiddleware>(middleware);
648
-
649
- if (instance.start && typeof instance.start === "function") {
650
- const argumentsMetadata: TArgumentsMetadataCollection =
651
- Reflect.getOwnMetadata(argumentsKey, middleware, "start") || {};
652
-
653
- startMiddlewareGroup.push(
654
- Object.freeze({
655
- class: middleware as IMiddleware,
656
- funcName: "start",
657
- func: instance.start.bind(instance),
658
- argumentsMetadata: argumentsMetadata
659
- })
660
- );
661
- }
662
-
663
- if (instance.end && typeof instance.end === "function") {
664
- const argumentsMetadata: TArgumentsMetadataCollection =
665
- Reflect.getOwnMetadata(argumentsKey, middleware, "end") || {};
666
-
667
- endMiddlewareGroup.push(
668
- Object.freeze({
669
- class: middleware as IMiddleware,
670
- funcName: "end",
671
- func: instance.end.bind(instance),
672
- argumentsMetadata: argumentsMetadata
673
- })
674
- );
675
- }
676
- });
677
- //#endregion
678
-
679
- //#region [Guard(s)]
680
- const guardGroup: Array<TGroupElementModel<"enforce", IGuard, NonNullable<IGuard["enforce"]>>> =
681
- !guards
682
- ? []
683
- : guards.map((guard) => {
684
- const guardInstance = injector.get<IGuard>(guard);
685
- const argumentsMetadata: TArgumentsMetadataCollection =
686
- Reflect.getOwnMetadata(argumentsKey, guard, "enforce") || {};
687
-
688
- return Object.freeze({
689
- class: guard as unknown as IGuard,
690
- funcName: "enforce",
691
- func: guardInstance.enforce.bind(guardInstance),
692
- argumentsMetadata: argumentsMetadata
693
- });
694
- });
695
- //#endregion
696
-
697
- //#region [Before interceptor(s)]
698
- const openInterceptorGroup: Array<
699
- TGroupElementModel<"open", IInterceptor, NonNullable<IInterceptor["open"]>>
700
- > = [];
701
- const closeInterceptorGroup: Array<
702
- TGroupElementModel<"close", IInterceptor, NonNullable<IInterceptor["close"]>>
703
- > = [];
704
-
705
- !interceptors ||
706
- interceptors.forEach((interceptor) => {
707
- const instance = injector.get<IInterceptor>(interceptor);
708
-
709
- if (instance.open && typeof instance.open === "function") {
710
- const argumentsMetadata: TArgumentsMetadataCollection =
711
- Reflect.getOwnMetadata(argumentsKey, interceptor, "open") || {};
712
-
713
- openInterceptorGroup.push(
714
- Object.freeze({
715
- class: interceptor as IInterceptor,
716
- funcName: "open",
717
- func: instance.open.bind(instance),
718
- argumentsMetadata: argumentsMetadata
719
- })
720
- );
721
- }
722
-
723
- if (instance.close && typeof instance.close === "function") {
724
- const argumentsMetadata: TArgumentsMetadataCollection =
725
- Reflect.getOwnMetadata(argumentsKey, interceptor, "close") || {};
726
-
727
- closeInterceptorGroup.push(
728
- Object.freeze({
729
- class: interceptor as IInterceptor,
730
- funcName: "close",
731
- func: instance.close.bind(instance),
732
- argumentsMetadata: argumentsMetadata
733
- })
734
- );
735
- }
736
- });
737
- //#endregion
738
-
739
- //#region [Controller(s)]
740
- const controllerRouterGroup = new HttpRouterGroup();
741
-
742
- !controllers ||
743
- controllers.forEach((controllerConstructor) =>
744
- controllerCreator({
745
- controllerConstructor,
746
- httpRouterGroup: controllerRouterGroup,
747
- injector: injector,
748
- prefix: fullPrefix
749
- })
750
- );
751
- //#endregion
752
-
753
- //#region [WebSocket(s)]
754
- const webSocketHttpRouterGroup = new HttpRouterGroup();
755
- const webSocketRouterGroup = new WebSocketRouterGroup();
756
-
757
- webSockets &&
758
- webSockets.forEach((webSocket) =>
759
- webSocketCreator({
760
- webSocketConstructor: webSocket,
761
- httpRouterGroup: webSocketHttpRouterGroup,
762
- webSocketRouterGroup: webSocketRouterGroup,
763
- injector: injector,
764
- prefix: fullPrefix
765
- })
766
- );
767
- //#endregion
768
-
769
- return Object.freeze({
770
- prefix: modulePrefix || "",
771
- injector: injector,
772
- startMiddlewareGroup: startMiddlewareGroup,
773
- endMiddlewareGroup: endMiddlewareGroup,
774
- guardGroup: guardGroup,
775
- openInterceptorGroup: openInterceptorGroup,
776
- closeInterceptorGroup: closeInterceptorGroup,
777
- controllerRouterGroup: controllerRouterGroup,
778
- webSocketHttpRouterGroup: webSocketHttpRouterGroup,
779
- webSocketRouterGroup: webSocketRouterGroup
780
- });
781
- };
782
-
783
- const webSocketFetcher = async (
784
- bun: Required<{
785
- request: Request;
786
- server: Server;
787
- }>,
788
- bool: Required<{
789
- responseHeaders: Headers;
790
- query: Record<string, unknown>;
791
- route: NonNullable<ReturnType<HttpRouterGroup["find"]>>;
792
- moduleResolution: NonNullable<Awaited<ReturnType<typeof moduleResolution>>>;
793
- }>
794
- ) => {
795
- const { request, server } = bun;
796
- const {
797
- query,
798
- responseHeaders,
799
- route: { model }
800
- } = bool;
801
-
802
- // Execute controller action
803
- const isUpgrade = await model.func(...[server, request, query]);
804
-
805
- if (typeof isUpgrade !== "boolean") {
806
- return responseConverter(
807
- new Response(
808
- JSON.stringify({
809
- httpCode: 500,
810
- message: "Can not detect webSocket upgrade result.",
811
- data: undefined
812
- }),
813
- {
814
- status: 500,
815
- statusText: "Internal server error.",
816
- headers: responseHeaders
817
- }
818
- )
819
- );
820
- }
821
-
822
- if (!isUpgrade) {
823
- return responseConverter(
824
- new Response(
825
- JSON.stringify({
826
- httpCode: 500,
827
- message: "Can not upgrade.",
828
- data: undefined
829
- }),
830
- {
831
- status: 500,
832
- statusText: "Internal server error.",
833
- headers: responseHeaders
834
- }
835
- )
836
- );
837
- }
838
-
839
- return isUpgrade;
840
- };
841
-
842
- const httpFetcher = async ({
843
- context: outerContext,
844
- route,
845
- options,
846
- resolutedMap
847
- }: Partial<{
848
- route: NonNullable<ReturnType<HttpRouterGroup["find"]>>;
849
- resolutedMap:
850
- | Partial<NonNullable<Awaited<ReturnType<typeof containerResolution>>>>
851
- | Partial<NonNullable<Awaited<ReturnType<typeof moduleResolution>>>>;
852
- context: Context;
853
- options: Partial<{
854
- isContainer: boolean;
855
- }>;
856
- }>) => {
857
- const contextOptions = { isStatic: true };
858
- const context = (!outerContext ? new Context() : new Context(outerContext)).setOptions(
859
- contextOptions
860
- );
861
-
862
- if (route) {
863
- context.set(paramsArgsKey, route.parameters).set(routeModelArgsKey, route.model);
864
- }
865
-
866
- const httpServer =
867
- context.get<Server | null | undefined>(httpServerArgsKey, contextOptions) || undefined,
868
- request =
869
- context.get<Request | null | undefined>(requestArgsKey, contextOptions) || undefined,
870
- requestHeaders =
871
- context.get<Headers | null | undefined>(requestHeaderArgsKey, contextOptions) ||
872
- undefined,
873
- responseHeaders =
874
- context.get<Headers | null | undefined>(responseHeadersArgsKey, contextOptions) ||
875
- undefined,
876
- parameters =
877
- context.get<TParamsType | null | undefined>(paramsArgsKey, contextOptions) || undefined,
878
- routeModel =
879
- context.get<
880
- NonNullable<ReturnType<HttpRouterGroup["find"]>>["model"] | null | undefined
881
- >(routeModelArgsKey, contextOptions) || undefined;
882
-
883
- if (resolutedMap) {
884
- const { startMiddlewareGroup, guardGroup } = resolutedMap;
885
-
886
- // Execute start middleware(s)
887
- if (startMiddlewareGroup) {
888
- for (let i = 0; i < startMiddlewareGroup.length; i++) {
889
- const args = [];
890
- const {
891
- func: handler,
892
- funcName: functionName,
893
- argumentsMetadata
894
- } = startMiddlewareGroup[i];
895
-
896
- for (const [_key, argMetadata] of Object.entries(argumentsMetadata)) {
897
- switch (argMetadata.type) {
898
- case contextArgsKey:
899
- args[argMetadata.index] = !argMetadata.key
900
- ? context
901
- : context.get(argMetadata.key, contextOptions);
902
- break;
903
- case requestArgsKey:
904
- args[argMetadata.index] = !argMetadata.zodSchema
905
- ? request
906
- : await argumentsResolution(
907
- request,
908
- argMetadata.zodSchema,
909
- argMetadata.index,
910
- functionName
911
- );
912
- break;
913
- case requestBodyArgsKey:
914
- args[argMetadata.index] = !argMetadata.zodSchema
915
- ? await request?.[argMetadata.parser || "json"]()
916
- : await argumentsResolution(
917
- await request?.[argMetadata.parser || "json"](),
918
- argMetadata.zodSchema,
919
- argMetadata.index,
920
- functionName
921
- );
922
- break;
923
- case requestHeadersArgsKey:
924
- args[argMetadata.index] = !argMetadata.zodSchema
925
- ? requestHeaders
926
- : await argumentsResolution(
927
- requestHeaders?.toJSON(),
928
- argMetadata.zodSchema,
929
- argMetadata.index,
930
- functionName
931
- );
932
- break;
933
- case requestHeaderArgsKey:
934
- args[argMetadata.index] = !argMetadata.zodSchema
935
- ? requestHeaders?.get(argMetadata.key) || undefined
936
- : await argumentsResolution(
937
- requestHeaders?.get(argMetadata.key) || undefined,
938
- argMetadata.zodSchema,
939
- argMetadata.index,
940
- functionName
941
- );
942
- break;
943
- case paramArgsKey:
944
- args[argMetadata.index] = !argMetadata.zodSchema
945
- ? parameters?.[argMetadata.key] || undefined
946
- : await argumentsResolution(
947
- parameters?.[argMetadata.key] || undefined,
948
- argMetadata.zodSchema,
949
- argMetadata.index,
950
- functionName
951
- );
952
- break;
953
- case routeModelArgsKey:
954
- args[argMetadata.index] = routeModel;
955
- break;
956
- case responseHeadersArgsKey:
957
- args[argMetadata.index] = responseHeaders;
958
- break;
959
- case httpServerArgsKey:
960
- args[argMetadata.index] = httpServer;
961
- break;
962
- default:
963
- args[argMetadata.index] = !argMetadata.zodSchema
964
- ? !context.has(argMetadata.type, contextOptions)
965
- ? undefined
966
- : context.get(argMetadata.type, contextOptions)
967
- : await argumentsResolution(
968
- !(argMetadata.type in context)
969
- ? undefined
970
- : context.get(argMetadata.type, contextOptions),
971
- argMetadata.zodSchema,
972
- argMetadata.index,
973
- functionName
974
- );
975
- break;
976
- }
977
- }
978
-
979
- await handler(...args);
980
- }
981
- }
982
-
983
- // Execute guard(s)
984
- if (guardGroup) {
985
- for (let i = 0; i < guardGroup.length; i++) {
986
- const args = [];
987
- const { func: handler, funcName: functionName, argumentsMetadata } = guardGroup[i];
988
-
989
- for (const [_key, argMetadata] of Object.entries(argumentsMetadata)) {
990
- switch (argMetadata.type) {
991
- case requestArgsKey:
992
- args[argMetadata.index] = !argMetadata.zodSchema
993
- ? request
994
- : await argumentsResolution(
995
- request,
996
- argMetadata.zodSchema,
997
- argMetadata.index,
998
- functionName
999
- );
1000
- break;
1001
- case requestBodyArgsKey:
1002
- args[argMetadata.index] = !argMetadata.zodSchema
1003
- ? await request?.[argMetadata.parser || "json"]()
1004
- : await argumentsResolution(
1005
- await request?.[argMetadata.parser || "json"](),
1006
- argMetadata.zodSchema,
1007
- argMetadata.index,
1008
- functionName
1009
- );
1010
- break;
1011
- case contextArgsKey:
1012
- args[argMetadata.index] = !argMetadata.key
1013
- ? context
1014
- : context.get(argMetadata.key);
1015
- break;
1016
- case requestHeadersArgsKey:
1017
- args[argMetadata.index] = !argMetadata.zodSchema
1018
- ? requestHeaders
1019
- : await argumentsResolution(
1020
- requestHeaders?.toJSON(),
1021
- argMetadata.zodSchema,
1022
- argMetadata.index,
1023
- functionName
1024
- );
1025
- break;
1026
- case responseHeadersArgsKey:
1027
- args[argMetadata.index] = responseHeaders;
1028
- break;
1029
- case requestHeaderArgsKey:
1030
- args[argMetadata.index] = !argMetadata.zodSchema
1031
- ? requestHeaders?.get(argMetadata.key) || undefined
1032
- : await argumentsResolution(
1033
- requestHeaders?.get(argMetadata.key) || undefined,
1034
- argMetadata.zodSchema,
1035
- argMetadata.index,
1036
- functionName
1037
- );
1038
- break;
1039
- case paramArgsKey:
1040
- args[argMetadata.index] = !argMetadata.zodSchema
1041
- ? parameters?.[argMetadata.key] || undefined
1042
- : await argumentsResolution(
1043
- parameters?.[argMetadata.key],
1044
- argMetadata.zodSchema,
1045
- argMetadata.index,
1046
- functionName
1047
- );
1048
- break;
1049
- case routeModelArgsKey:
1050
- args[argMetadata.index] = routeModel;
1051
- break;
1052
- case httpServerArgsKey:
1053
- args[argMetadata.index] = httpServer;
1054
- break;
1055
- default:
1056
- args[argMetadata.index] = !argMetadata.zodSchema
1057
- ? !context.has(argMetadata.type)
1058
- ? undefined
1059
- : context.get(argMetadata.type)
1060
- : await argumentsResolution(
1061
- context.get(argMetadata.type),
1062
- argMetadata.zodSchema,
1063
- argMetadata.index,
1064
- functionName
1065
- );
1066
- break;
1067
- }
1068
- }
1069
-
1070
- const guardResult = await handler(...args);
1071
-
1072
- if (typeof guardResult !== "boolean" || !guardResult) {
1073
- throw new HttpClientError({
1074
- httpCode: 401,
1075
- message: "Unauthorization.",
1076
- data: undefined
1077
- });
1078
- }
1079
- }
1080
- }
1081
- }
1082
-
1083
- if (routeModel && !options?.isContainer) {
1084
- if (
1085
- resolutedMap &&
1086
- "openInterceptorGroup" in resolutedMap &&
1087
- resolutedMap.openInterceptorGroup
1088
- ) {
1089
- const { openInterceptorGroup } = resolutedMap;
1090
-
1091
- // Execute open interceptor(s)
1092
- for (let i = 0; i < openInterceptorGroup.length; i++) {
1093
- const args = [];
1094
- const {
1095
- func: handler,
1096
- funcName: functionName,
1097
- argumentsMetadata
1098
- } = openInterceptorGroup[i];
1099
-
1100
- for (const [_key, argMetadata] of Object.entries(argumentsMetadata)) {
1101
- switch (argMetadata.type) {
1102
- case requestArgsKey:
1103
- args[argMetadata.index] = !argMetadata.zodSchema
1104
- ? request
1105
- : await argumentsResolution(
1106
- request,
1107
- argMetadata.zodSchema,
1108
- argMetadata.index,
1109
- functionName
1110
- );
1111
- break;
1112
- case requestBodyArgsKey:
1113
- args[argMetadata.index] = !argMetadata.zodSchema
1114
- ? await request?.[argMetadata.parser || "json"]()
1115
- : await argumentsResolution(
1116
- await request?.[argMetadata.parser || "json"](),
1117
- argMetadata.zodSchema,
1118
- argMetadata.index,
1119
- functionName
1120
- );
1121
- break;
1122
- case contextArgsKey:
1123
- args[argMetadata.index] = !argMetadata.key
1124
- ? context
1125
- : context.get(argMetadata.key);
1126
- break;
1127
- case requestHeadersArgsKey:
1128
- args[argMetadata.index] = !argMetadata.zodSchema
1129
- ? requestHeaders
1130
- : await argumentsResolution(
1131
- requestHeaders?.toJSON(),
1132
- argMetadata.zodSchema,
1133
- argMetadata.index,
1134
- functionName
1135
- );
1136
- break;
1137
- case requestHeaderArgsKey:
1138
- args[argMetadata.index] = !argMetadata.zodSchema
1139
- ? requestHeaders?.get(argMetadata.key) || undefined
1140
- : await argumentsResolution(
1141
- requestHeaders?.get(argMetadata.key) || undefined,
1142
- argMetadata.zodSchema,
1143
- argMetadata.index,
1144
- functionName
1145
- );
1146
- break;
1147
- case responseHeadersArgsKey:
1148
- args[argMetadata.index] = responseHeaders;
1149
- break;
1150
- case paramArgsKey:
1151
- args[argMetadata.index] = !argMetadata.zodSchema
1152
- ? parameters?.[argMetadata.key] || undefined
1153
- : await argumentsResolution(
1154
- parameters?.[argMetadata.key] || undefined,
1155
- argMetadata.zodSchema,
1156
- argMetadata.index,
1157
- functionName
1158
- );
1159
- break;
1160
- case routeModelArgsKey:
1161
- args[argMetadata.index] = routeModel;
1162
- break;
1163
- case httpServerArgsKey:
1164
- args[argMetadata.index] = httpServer;
1165
- break;
1166
- default:
1167
- args[argMetadata.index] = !argMetadata.zodSchema
1168
- ? !context.has(argMetadata.type)
1169
- ? undefined
1170
- : context.get(argMetadata.type)
1171
- : await argumentsResolution(
1172
- context.get(argMetadata.type),
1173
- argMetadata.zodSchema,
1174
- argMetadata.index,
1175
- functionName
1176
- );
1177
- break;
1178
- }
1179
- }
1180
-
1181
- await handler(...args);
1182
- }
1183
- }
1184
-
1185
- // Execute controller action
1186
- const controllerActionArguments: any[] = [];
1187
- const {
1188
- func: controllerAction,
1189
- funcName: controllerActionName,
1190
- argumentsMetadata: controllerActionArgumentsMetadata
1191
- } = routeModel;
1192
-
1193
- for (const [_key, argMetadata] of Object.entries(controllerActionArgumentsMetadata)) {
1194
- switch (argMetadata.type) {
1195
- case requestArgsKey:
1196
- controllerActionArguments[argMetadata.index] = !argMetadata.zodSchema
1197
- ? request
1198
- : await argumentsResolution(
1199
- request,
1200
- argMetadata.zodSchema,
1201
- argMetadata.index,
1202
- controllerActionName
1203
- );
1204
- break;
1205
- case requestBodyArgsKey:
1206
- controllerActionArguments[argMetadata.index] = !argMetadata.zodSchema
1207
- ? await request?.[argMetadata.parser || "json"]()
1208
- : await argumentsResolution(
1209
- await request?.[argMetadata.parser || "json"](),
1210
- argMetadata.zodSchema,
1211
- argMetadata.index,
1212
- controllerActionName
1213
- );
1214
- break;
1215
- case contextArgsKey:
1216
- controllerActionArguments[argMetadata.index] = !argMetadata.key
1217
- ? context
1218
- : context.get(argMetadata.key);
1219
- break;
1220
- case requestHeadersArgsKey:
1221
- controllerActionArguments[argMetadata.index] = !argMetadata.zodSchema
1222
- ? requestHeaders
1223
- : await argumentsResolution(
1224
- requestHeaders?.toJSON(),
1225
- argMetadata.zodSchema,
1226
- argMetadata.index,
1227
- controllerActionName
1228
- );
1229
- break;
1230
- case requestHeaderArgsKey:
1231
- controllerActionArguments[argMetadata.index] = !argMetadata.zodSchema
1232
- ? requestHeaders?.get(argMetadata.key) || undefined
1233
- : await argumentsResolution(
1234
- requestHeaders?.get(argMetadata.key) || undefined,
1235
- argMetadata.zodSchema,
1236
- argMetadata.index,
1237
- controllerActionName
1238
- );
1239
- break;
1240
- case responseHeadersArgsKey:
1241
- controllerActionArguments[argMetadata.index] = responseHeaders;
1242
- break;
1243
- case paramArgsKey:
1244
- controllerActionArguments[argMetadata.index] = !argMetadata.zodSchema
1245
- ? parameters?.[argMetadata.key] || undefined
1246
- : await argumentsResolution(
1247
- parameters?.[argMetadata.key] || undefined,
1248
- argMetadata.zodSchema,
1249
- argMetadata.index,
1250
- controllerActionName
1251
- );
1252
- break;
1253
- case routeModelArgsKey:
1254
- controllerActionArguments[argMetadata.index] = routeModel;
1255
- break;
1256
- case httpServerArgsKey:
1257
- controllerActionArguments[argMetadata.index] = httpServer;
1258
- break;
1259
- default:
1260
- controllerActionArguments[argMetadata.index] = !argMetadata.zodSchema
1261
- ? !context.has(argMetadata.type)
1262
- ? undefined
1263
- : context.get(argMetadata.type)
1264
- : await argumentsResolution(
1265
- context.get(argMetadata.type),
1266
- argMetadata.zodSchema,
1267
- argMetadata.index,
1268
- controllerActionName
1269
- );
1270
- break;
1271
- }
1272
- }
1273
-
1274
- context.set(responseBodyArgsKey, await controllerAction(...controllerActionArguments), {
1275
- isStatic: false
1276
- });
1277
-
1278
- if (
1279
- resolutedMap &&
1280
- "closeInterceptorGroup" in resolutedMap &&
1281
- resolutedMap.closeInterceptorGroup
1282
- ) {
1283
- const { closeInterceptorGroup } = resolutedMap;
1284
-
1285
- // Execute close interceptor(s)
1286
- for (let i = 0; i < closeInterceptorGroup.length; i++) {
1287
- const args = [];
1288
- const {
1289
- func: handler,
1290
- funcName: functionName,
1291
- argumentsMetadata
1292
- } = closeInterceptorGroup[i];
1293
-
1294
- for (const [_key, argMetadata] of Object.entries(argumentsMetadata)) {
1295
- switch (argMetadata.type) {
1296
- case requestArgsKey:
1297
- args[argMetadata.index] = !argMetadata.zodSchema
1298
- ? request
1299
- : await argumentsResolution(
1300
- request,
1301
- argMetadata.zodSchema,
1302
- argMetadata.index,
1303
- functionName
1304
- );
1305
- break;
1306
- case requestBodyArgsKey:
1307
- args[argMetadata.index] = !argMetadata.zodSchema
1308
- ? await request?.[argMetadata.parser || "json"]()
1309
- : await argumentsResolution(
1310
- await request?.[argMetadata.parser || "json"](),
1311
- argMetadata.zodSchema,
1312
- argMetadata.index,
1313
- functionName
1314
- );
1315
- break;
1316
- case contextArgsKey:
1317
- args[argMetadata.index] = !argMetadata.key
1318
- ? context
1319
- : context.get(argMetadata.key);
1320
- break;
1321
- case requestHeadersArgsKey:
1322
- args[argMetadata.index] = !argMetadata.zodSchema
1323
- ? requestHeaders
1324
- : await argumentsResolution(
1325
- requestHeaders?.toJSON(),
1326
- argMetadata.zodSchema,
1327
- argMetadata.index,
1328
- functionName
1329
- );
1330
- break;
1331
- case responseHeadersArgsKey:
1332
- args[argMetadata.index] = context.get(argMetadata.type);
1333
- break;
1334
- case requestHeaderArgsKey:
1335
- args[argMetadata.index] = !argMetadata.zodSchema
1336
- ? requestHeaders?.get(argMetadata.key) || undefined
1337
- : await argumentsResolution(
1338
- requestHeaders?.get(argMetadata.key) || undefined,
1339
- argMetadata.zodSchema,
1340
- argMetadata.index,
1341
- functionName
1342
- );
1343
- break;
1344
- case paramArgsKey:
1345
- args[argMetadata.index] = !argMetadata.zodSchema
1346
- ? parameters?.[argMetadata.key] || undefined
1347
- : await argumentsResolution(
1348
- parameters?.[argMetadata.key] || undefined,
1349
- argMetadata.zodSchema,
1350
- argMetadata.index,
1351
- functionName
1352
- );
1353
- break;
1354
- case routeModelArgsKey:
1355
- args[argMetadata.index] = routeModel;
1356
- break;
1357
- case httpServerArgsKey:
1358
- args[argMetadata.index] = httpServer;
1359
- break;
1360
- default:
1361
- args[argMetadata.index] = !argMetadata.zodSchema
1362
- ? !context.has(argMetadata.type)
1363
- ? undefined
1364
- : context.get(argMetadata.type)
1365
- : await argumentsResolution(
1366
- context.get(argMetadata.type),
1367
- argMetadata.zodSchema,
1368
- argMetadata.index,
1369
- functionName
1370
- );
1371
- break;
1372
- }
1373
- }
1374
-
1375
- await handler(...args);
1376
- }
1377
- }
1378
- }
1379
-
1380
- if (resolutedMap) {
1381
- const { endMiddlewareGroup } = resolutedMap;
1382
-
1383
- // Execute end middleware(s)
1384
- if (endMiddlewareGroup) {
1385
- for (let i = 0; i < endMiddlewareGroup.length; i++) {
1386
- const args = [];
1387
- const {
1388
- func: handler,
1389
- funcName: functionName,
1390
- argumentsMetadata
1391
- } = endMiddlewareGroup[i];
1392
-
1393
- for (const [_key, argMetadata] of Object.entries(argumentsMetadata)) {
1394
- switch (argMetadata.type) {
1395
- case requestArgsKey:
1396
- args[argMetadata.index] = !argMetadata.zodSchema
1397
- ? request
1398
- : await argumentsResolution(
1399
- request,
1400
- argMetadata.zodSchema,
1401
- argMetadata.index,
1402
- functionName
1403
- );
1404
- break;
1405
- case requestBodyArgsKey:
1406
- args[argMetadata.index] = !argMetadata.zodSchema
1407
- ? await request?.[argMetadata.parser || "json"]()
1408
- : await argumentsResolution(
1409
- await request?.[argMetadata.parser || "json"](),
1410
- argMetadata.zodSchema,
1411
- argMetadata.index,
1412
- functionName
1413
- );
1414
- break;
1415
- case contextArgsKey:
1416
- args[argMetadata.index] = !argMetadata.key
1417
- ? context
1418
- : context.get(argMetadata.key);
1419
- break;
1420
- case requestHeadersArgsKey:
1421
- args[argMetadata.index] = !argMetadata.zodSchema
1422
- ? requestHeaders
1423
- : await argumentsResolution(
1424
- requestHeaders?.toJSON(),
1425
- argMetadata.zodSchema,
1426
- argMetadata.index,
1427
- functionName
1428
- );
1429
- break;
1430
- case responseHeadersArgsKey:
1431
- args[argMetadata.index] = context.get(argMetadata.type);
1432
- break;
1433
- case requestHeaderArgsKey:
1434
- args[argMetadata.index] = !argMetadata.zodSchema
1435
- ? requestHeaders?.get(argMetadata.key) || undefined
1436
- : await argumentsResolution(
1437
- requestHeaders?.get(argMetadata.key) || undefined,
1438
- argMetadata.zodSchema,
1439
- argMetadata.index,
1440
- functionName
1441
- );
1442
- break;
1443
- case paramArgsKey:
1444
- args[argMetadata.index] = !argMetadata.zodSchema
1445
- ? parameters?.[argMetadata.key] || undefined
1446
- : await argumentsResolution(
1447
- parameters?.[argMetadata.key] || undefined,
1448
- argMetadata.zodSchema,
1449
- argMetadata.index,
1450
- functionName
1451
- );
1452
- break;
1453
- case routeModelArgsKey:
1454
- args[argMetadata.index] = routeModel;
1455
- break;
1456
- case httpServerArgsKey:
1457
- args[argMetadata.index] = httpServer;
1458
- break;
1459
- default:
1460
- args[argMetadata.index] = !argMetadata.zodSchema
1461
- ? !context.has(argMetadata.type)
1462
- ? undefined
1463
- : context.get(argMetadata.type)
1464
- : await argumentsResolution(
1465
- !(argMetadata.type in context)
1466
- ? undefined
1467
- : context.get(argMetadata.type),
1468
- argMetadata.zodSchema,
1469
- argMetadata.index,
1470
- functionName
1471
- );
1472
- break;
1473
- }
1474
- }
1475
-
1476
- await handler(...args);
1477
- }
1478
- }
1479
- }
1480
-
1481
- return Object.freeze({
1482
- context: context
1483
- });
1484
- };
1485
-
1486
- export const BoolFactory = async (
1487
- classConstructor: new (...args: any[]) => unknown,
49
+ export const BoolFactory = async <T extends Object>(
50
+ classConstructor: TConstructor<T>,
1488
51
  options: TBoolFactoryOptions
1489
52
  ) => {
1490
53
  try {
1491
- const staticMap: Map<
1492
- string,
1493
- Readonly<{
1494
- expiredAt: Date;
1495
- file: BunFile;
1496
- }>
1497
- > = new Map();
1498
-
1499
- const {
1500
- allowLogsMethods,
1501
- staticOption,
1502
- allowOrigins,
1503
- allowMethods,
1504
- allowCredentials,
1505
- allowHeaders
1506
- } = Object.freeze({
1507
- allowLogsMethods: options?.log?.methods,
1508
- staticOption: options.static,
1509
- allowOrigins: !options.cors?.origins
1510
- ? ["*"]
1511
- : typeof options.cors.origins !== "string"
1512
- ? options.cors.origins.includes("*") || options.cors.origins.length < 1
1513
- ? ["*"]
1514
- : options.cors.origins
1515
- : [options.cors.origins !== "*" ? options.cors.origins : "*"],
1516
- allowMethods: options.cors?.methods || [
1517
- "GET",
1518
- "POST",
1519
- "PUT",
1520
- "PATCH",
1521
- "DELETE",
1522
- "OPTIONS"
1523
- ],
1524
- allowCredentials: !options.cors?.credentials ? false : true,
1525
- allowHeaders:
1526
- !options.cors?.headers || options.cors.headers.includes("*")
1527
- ? ["*"]
1528
- : options.cors.headers
1529
- });
1530
-
1531
- const inputedConstructorKeys = Reflect.getOwnMetadataKeys(classConstructor);
1532
-
1533
- if (
1534
- !inputedConstructorKeys.includes(containerKey) &&
1535
- !inputedConstructorKeys.includes(moduleKey)
1536
- ) {
1537
- throw Error(
1538
- `Can not detect! ${classConstructor.name} class is not a container or module.`
1539
- );
1540
- }
1541
-
1542
- const injector = new Injector();
1543
-
1544
- const containerMetadata: TContainerMetadata = !inputedConstructorKeys.includes(containerKey)
1545
- ? undefined
1546
- : Reflect.getOwnMetadata(containerKey, classConstructor);
1547
-
1548
- const modulesConverted = !inputedConstructorKeys.includes(containerKey)
1549
- ? [classConstructor]
1550
- : containerMetadata?.modules || [];
1551
-
1552
- const resolutedContainer = !containerMetadata
1553
- ? undefined
1554
- : await containerResolution({
1555
- containerClass: classConstructor,
1556
- options: options,
1557
- extendInjector: injector
1558
- });
1559
-
1560
- const resolutedModules = await Promise.all(
1561
- modulesConverted.map((moduleConverted) =>
1562
- moduleResolution({
1563
- moduleClass: moduleConverted,
1564
- options: options,
1565
- extendInjector: !resolutedContainer ? injector : resolutedContainer.injector
1566
- })
1567
- )
1568
- );
1569
-
1570
- const availableModuleResolutions = resolutedModules.filter(
1571
- (resolutedModule) => typeof resolutedModule !== "undefined"
1572
- );
1573
-
1574
- const prefixs = [
1575
- ...new Set(
1576
- availableModuleResolutions.map(
1577
- (availableModuleResolution) => availableModuleResolution.prefix
1578
- )
1579
- )
1580
- ];
1581
-
1582
- if (prefixs.length !== availableModuleResolutions.length) {
1583
- throw Error("Module prefix should be unique.");
1584
- }
1585
-
1586
- const webSocketsMap = new Map<string, TWebSocketEventHandlerMetadata>();
1587
-
1588
- for (const availableModuleResolution of availableModuleResolutions) {
1589
- const webSocketMap = availableModuleResolution.webSocketRouterGroup.execute();
1590
-
1591
- for (const [key, metadata] of webSocketMap.entries()) {
1592
- webSocketsMap.set(key, metadata);
1593
- }
1594
- }
1595
-
1596
- const server = Bun.serve<TWebSocketUpgradeData, {}>({
1597
- port: options.port,
1598
- fetch: async (request, server) => {
1599
- const start = performance.now(),
1600
- url = new URL(request.url),
1601
- query = Qs.parse(url.searchParams.toString(), options.queryParser),
1602
- origin = request.headers.get("origin") || "*",
1603
- method = request.method.toUpperCase(),
1604
- responseHeaders = new Headers();
1605
-
1606
- let context = new Context()
1607
- .setOptions({ isStatic: true })
1608
- .set(httpServerArgsKey, server)
1609
- .set(requestArgsKey, request)
1610
- .set(requestHeaderArgsKey, request.headers)
1611
- .set(responseHeadersArgsKey, responseHeaders)
1612
- .set(queryArgsKey, query);
1613
-
1614
- try {
1615
- const isUpgradable = isWebSocketUpgrade(request);
1616
-
1617
- let collection:
1618
- | undefined
1619
- | Required<{
1620
- route: NonNullable<ReturnType<HttpRouterGroup["find"]>>;
1621
- resolution: NonNullable<Awaited<ReturnType<typeof moduleResolution>>>;
1622
- }>;
1623
-
1624
- if (isUpgradable) {
1625
- for (const availableModuleResolution of availableModuleResolutions) {
1626
- const routeResult =
1627
- availableModuleResolution.webSocketHttpRouterGroup.find(
1628
- url.pathname,
1629
- request.method as keyof THttpMethods
1630
- );
1631
-
1632
- if (routeResult) {
1633
- collection = Object.freeze({
1634
- route: routeResult,
1635
- resolution: availableModuleResolution
1636
- });
1637
- break;
1638
- }
1639
- }
1640
-
1641
- if (!collection) {
1642
- return responseConverter(
1643
- new Response(
1644
- JSON.stringify({
1645
- httpCode: 404,
1646
- message: "Route not found",
1647
- data: undefined
1648
- }),
1649
- {
1650
- status: 404,
1651
- statusText: "Not found.",
1652
- headers: responseHeaders
1653
- }
1654
- )
1655
- );
1656
- }
1657
-
1658
- const upgradeResult = await webSocketFetcher(
1659
- {
1660
- request,
1661
- server
1662
- },
1663
- {
1664
- query: query,
1665
- responseHeaders: responseHeaders,
1666
- route: collection.route,
1667
- moduleResolution: collection.resolution
1668
- }
1669
- );
1670
-
1671
- return upgradeResult instanceof Response ? upgradeResult : undefined;
1672
- }
1673
-
1674
- [
1675
- ...(!allowCredentials
1676
- ? []
1677
- : [
1678
- {
1679
- key: "Access-Control-Allow-Credentials",
1680
- value: "true"
1681
- }
1682
- ]),
1683
- {
1684
- key: "Access-Control-Allow-Origin",
1685
- value: allowOrigins.includes("*")
1686
- ? "*"
1687
- : !allowOrigins.includes(origin)
1688
- ? allowOrigins[0]
1689
- : origin
1690
- },
1691
- { key: "Access-Control-Allow-Methods", value: allowMethods.join(", ") },
1692
- { key: "Access-Control-Allow-Headers", value: allowHeaders.join(", ") }
1693
- ].forEach(({ key, value }) => responseHeaders.set(key, value));
1694
-
1695
- if (!allowMethods.includes(method)) {
1696
- return responseConverter(
1697
- new Response(undefined, {
1698
- status: 405,
1699
- statusText: "Method Not Allowed.",
1700
- headers: responseHeaders
1701
- })
1702
- );
1703
- }
1704
-
1705
- if (request.method.toUpperCase() === "OPTIONS") {
1706
- return responseConverter(
1707
- allowOrigins.includes("*") || allowOrigins.includes(origin)
1708
- ? new Response(undefined, {
1709
- status: 204,
1710
- statusText: "No Content.",
1711
- headers: responseHeaders
1712
- })
1713
- : new Response(undefined, {
1714
- status: 417,
1715
- statusText: "Expectation Failed.",
1716
- headers: responseHeaders
1717
- })
1718
- );
1719
- }
1720
-
1721
- if (staticOption) {
1722
- const { path, headers, cacheTimeInSeconds } = staticOption;
1723
- const pathname = `${path}/${url.pathname}`;
1724
- const cachedFile = staticMap.get(pathname);
1725
-
1726
- if (!cachedFile) {
1727
- const file = Bun.file(pathname);
1728
- const isFileExists = await file.exists();
1729
-
1730
- if (isFileExists) {
1731
- if (headers) {
1732
- for (const [key, value] of Object.entries(headers)) {
1733
- responseHeaders.set(key, value);
1734
- }
1735
- }
1736
-
1737
- responseHeaders.set("Content-Type", file.type);
1738
-
1739
- return responseConverter(
1740
- new Response(await file.arrayBuffer(), {
1741
- status: 200,
1742
- statusText: "SUCCESS",
1743
- headers: responseHeaders
1744
- })
1745
- );
1746
- }
1747
- } else {
1748
- const isExpired = new Date() > cachedFile.expiredAt;
1749
-
1750
- if (isExpired) {
1751
- staticMap.delete(pathname);
1752
- }
1753
-
1754
- const file = !isExpired ? cachedFile.file : Bun.file(pathname);
1755
- const isFileExists = await file.exists();
1756
-
1757
- if (isFileExists) {
1758
- staticMap.set(
1759
- pathname,
1760
- Object.freeze({
1761
- expiredAt: TimeAdd(
1762
- new Date(),
1763
- typeof cacheTimeInSeconds !== "number"
1764
- ? DEFAULT_STATIC_CACHE_TIME_IN_SECONDS
1765
- : cacheTimeInSeconds,
1766
- ETimeUnit.seconds
1767
- ),
1768
- file: file
1769
- })
1770
- );
1771
-
1772
- if (headers) {
1773
- for (const [key, value] of Object.entries(headers)) {
1774
- responseHeaders.set(key, value);
1775
- }
1776
- }
1777
-
1778
- responseHeaders.set("Content-Type", file.type);
1779
-
1780
- return responseConverter(
1781
- new Response(await file.arrayBuffer(), {
1782
- status: 200,
1783
- statusText: "SUCCESS",
1784
- headers: responseHeaders
1785
- })
1786
- );
1787
- }
1788
- }
1789
- }
1790
-
1791
- if (resolutedContainer) {
1792
- const { context: newContext } = await httpFetcher({
1793
- context: context,
1794
- resolutedMap: {
1795
- injector: resolutedContainer.injector,
1796
- startMiddlewareGroup: resolutedContainer.startMiddlewareGroup,
1797
- guardGroup: resolutedContainer.guardGroup
1798
- },
1799
- options: {
1800
- isContainer: true
1801
- }
1802
- });
1803
-
1804
- context = newContext;
1805
- }
1806
-
1807
- for (const availableModuleResolution of availableModuleResolutions) {
1808
- const routeResult = availableModuleResolution.controllerRouterGroup.find(
1809
- url.pathname,
1810
- method as keyof THttpMethods
1811
- );
1812
-
1813
- if (routeResult) {
1814
- collection = Object.freeze({
1815
- route: routeResult,
1816
- resolution: availableModuleResolution
1817
- });
1818
- break;
1819
- }
1820
- }
1821
-
1822
- if (!collection) {
1823
- context
1824
- .setOptions({ isStatic: false })
1825
- .set(responseStatusArgsKey, 404)
1826
- .set(responseStatusTextArgsKey, "Not found.")
1827
- .set(
1828
- responseBodyArgsKey,
1829
- JSON.stringify({
1830
- httpCode: 404,
1831
- message: "Route not found",
1832
- data: undefined
1833
- })
1834
- );
1835
- } else {
1836
- const { context: newContext } = await httpFetcher({
1837
- context: context,
1838
- route: collection.route,
1839
- resolutedMap: collection.resolution
1840
- });
1841
-
1842
- context = newContext;
1843
- }
1844
-
1845
- if (resolutedContainer) {
1846
- const { context: newContext } = await httpFetcher({
1847
- context: context,
1848
- resolutedMap: {
1849
- injector: resolutedContainer.injector,
1850
- endMiddlewareGroup: resolutedContainer.endMiddlewareGroup
1851
- },
1852
- options: {
1853
- isContainer: true
1854
- }
1855
- });
1856
-
1857
- context = newContext;
1858
- }
1859
-
1860
- const latestResponseHeaders =
1861
- context.get<Headers | null | undefined>(responseHeadersArgsKey, {
1862
- isStatic: true
1863
- }) || new Headers(),
1864
- latestResponseBody =
1865
- context.get<unknown>(responseBodyArgsKey, { isStatic: false }) ||
1866
- undefined,
1867
- latestResponseStatus = context.get<unknown>(responseStatusArgsKey, {
1868
- isStatic: false
1869
- }),
1870
- latestResponseStatusText = context.get<unknown>(responseStatusArgsKey, {
1871
- isStatic: false
1872
- });
1873
-
1874
- return responseSerialize({
1875
- status:
1876
- typeof latestResponseStatus !== "number"
1877
- ? undefined
1878
- : latestResponseStatus,
1879
- statusText:
1880
- typeof latestResponseStatusText !== "string"
1881
- ? undefined
1882
- : latestResponseStatusText,
1883
- headers: latestResponseHeaders,
1884
- data: latestResponseBody
1885
- });
1886
- } catch (error) {
1887
- options.debug && console.error(error);
1888
-
1889
- return responseConverter(jsonErrorInfer(error, responseHeaders));
1890
- } finally {
1891
- if (allowLogsMethods) {
1892
- const end = performance.now();
1893
- const pathname = ansiText(url.pathname, { color: "blue" });
1894
- const convertedPID = `${Bun.color("yellow", "ansi")}${process.pid}`;
1895
- const convertedMethod = ansiText(request.method, {
1896
- color: "yellow",
1897
- backgroundColor: "blue"
1898
- });
1899
- const convertedReqIp = ansiText(
1900
- `${
1901
- request.headers.get("x-forwarded-for") ||
1902
- request.headers.get("x-real-ip") ||
1903
- server.requestIP(request)?.address ||
1904
- "<Unknown>"
1905
- }`,
1906
- {
1907
- color: "yellow"
1908
- }
1909
- );
1910
- const convertedTime = ansiText(
1911
- `${Math.round((end - start + Number.EPSILON) * 10 ** 2) / 10 ** 2}ms`,
1912
- {
1913
- color: "yellow",
1914
- backgroundColor: "blue"
1915
- }
1916
- );
1917
-
1918
- allowLogsMethods.includes(
1919
- request.method.toUpperCase() as (typeof allowLogsMethods)[number]
1920
- ) &&
1921
- console.info(
1922
- `PID: ${convertedPID} - Method: ${convertedMethod} - IP: ${convertedReqIp} - ${pathname} - Time: ${convertedTime}`
1923
- );
1924
- }
1925
- }
1926
- },
1927
- websocket: {
1928
- open: (connection) => {
1929
- const pathnameKey = `${connection.data.pathname}:::open`;
1930
- const handlerMetadata = webSocketsMap.get(pathnameKey);
1931
-
1932
- if (!handlerMetadata) {
1933
- return;
1934
- }
1935
-
1936
- const argumentsMetadata = handlerMetadata.arguments || {};
1937
- const args: Array<unknown> = [];
1938
-
1939
- for (const [_key, argumentMetadata] of Object.entries(argumentsMetadata)) {
1940
- switch (argumentMetadata.type) {
1941
- case webSocketConnectionArgsKey:
1942
- args[argumentMetadata.index] = connection;
1943
- break;
1944
- case webSocketServerArgsKey:
1945
- args[argumentMetadata.index] = server;
1946
- break;
1947
- }
1948
- }
1949
-
1950
- handlerMetadata.descriptor.value(...args);
1951
- },
1952
- close: (connection, code, reason) => {
1953
- const pathnameKey = `${connection.data.pathname}:::close`;
1954
- const handlerMetadata = webSocketsMap.get(pathnameKey);
1955
-
1956
- if (!handlerMetadata) {
1957
- return;
1958
- }
1959
-
1960
- const argumentsMetadata = handlerMetadata.arguments || {};
1961
- const args: Array<unknown> = [];
1962
-
1963
- for (const [_key, argumentMetadata] of Object.entries(argumentsMetadata)) {
1964
- switch (argumentMetadata.type) {
1965
- case webSocketConnectionArgsKey:
1966
- args[argumentMetadata.index] = connection;
1967
- break;
1968
- case webSocketServerArgsKey:
1969
- args[argumentMetadata.index] = server;
1970
- break;
1971
- case webSocketCloseCodeArgsKey:
1972
- args[argumentMetadata.index] = code;
1973
- break;
1974
- case webSocketCloseReasonArgsKey:
1975
- args[argumentMetadata.index] = reason;
1976
- break;
1977
- }
1978
- }
1979
-
1980
- handlerMetadata.descriptor.value(...args);
1981
- },
1982
- message: (connection, message) => {
1983
- const pathnameKey = `${connection.data.pathname}:::message`;
1984
- const handlerMetadata = webSocketsMap.get(pathnameKey);
1985
-
1986
- if (!handlerMetadata) {
1987
- return;
1988
- }
1989
-
1990
- const argumentsMetadata = handlerMetadata.arguments || {};
1991
- const args: Array<unknown> = [];
1992
-
1993
- for (const [_key, argumentMetadata] of Object.entries(argumentsMetadata)) {
1994
- switch (argumentMetadata.type) {
1995
- case webSocketConnectionArgsKey:
1996
- args[argumentMetadata.index] = connection;
1997
- break;
1998
- case webSocketMessageArgsKey:
1999
- args[argumentMetadata.index] = message;
2000
- break;
2001
- case webSocketServerArgsKey:
2002
- args[argumentMetadata.index] = server;
2003
- break;
2004
- }
2005
- }
2006
-
2007
- handlerMetadata.descriptor.value(...args);
2008
- },
2009
- drain: (connection) => {
2010
- const pathnameKey = `${connection.data.pathname}:::drain`;
2011
- const handlerMetadata = webSocketsMap.get(pathnameKey);
2012
-
2013
- if (!handlerMetadata) {
2014
- return;
2015
- }
2016
-
2017
- const argumentsMetadata = handlerMetadata.arguments || {};
2018
- const args: Array<unknown> = [];
2019
-
2020
- for (const [_key, argumentMetadata] of Object.entries(argumentsMetadata)) {
2021
- switch (argumentMetadata.type) {
2022
- case webSocketConnectionArgsKey:
2023
- args[argumentMetadata.index] = connection;
2024
- break;
2025
- case webSocketServerArgsKey:
2026
- args[argumentMetadata.index] = server;
2027
- break;
2028
- }
2029
- }
2030
-
2031
- handlerMetadata.descriptor.value(...args);
2032
- },
2033
- ping: (connection, data) => {
2034
- const pathnameKey = `${connection.data.pathname}:::ping`;
2035
- const handlerMetadata = webSocketsMap.get(pathnameKey);
2036
-
2037
- if (!handlerMetadata) {
2038
- return;
2039
- }
2040
-
2041
- const argumentsMetadata = handlerMetadata.arguments || {};
2042
- const args: Array<unknown> = [];
2043
-
2044
- for (const [_key, argumentMetadata] of Object.entries(argumentsMetadata)) {
2045
- switch (argumentMetadata.type) {
2046
- case webSocketConnectionArgsKey:
2047
- args[argumentMetadata.index] = connection;
2048
- break;
2049
- case webSocketServerArgsKey:
2050
- args[argumentMetadata.index] = server;
2051
- break;
2052
- case webSocketMessageArgsKey:
2053
- args[argumentMetadata.index] = data;
2054
- break;
2055
- }
2056
- }
2057
-
2058
- handlerMetadata.descriptor.value(...args);
2059
- },
2060
- pong: (connection, data) => {
2061
- const pathnameKey = `${connection.data.pathname}:::pong`;
2062
- const handlerMetadata = webSocketsMap.get(pathnameKey);
2063
-
2064
- if (!handlerMetadata) {
2065
- return;
2066
- }
2067
-
2068
- const argumentsMetadata = handlerMetadata.arguments || {};
2069
- const args: Array<unknown> = [];
54
+ const app = new Application(classConstructor, options);
2070
55
 
2071
- for (const [_key, argumentMetadata] of Object.entries(argumentsMetadata)) {
2072
- switch (argumentMetadata.type) {
2073
- case webSocketConnectionArgsKey:
2074
- args[argumentMetadata.index] = connection;
2075
- break;
2076
- case webSocketServerArgsKey:
2077
- args[argumentMetadata.index] = server;
2078
- break;
2079
- case webSocketMessageArgsKey:
2080
- args[argumentMetadata.index] = data;
2081
- break;
2082
- }
2083
- }
56
+ await app.preLaunch();
2084
57
 
2085
- handlerMetadata.descriptor.value(...args);
2086
- }
2087
- }
2088
- });
58
+ return app;
2089
59
  } catch (error) {
2090
60
  options.debug && console.error(error);
2091
61
  throw error;