@bool-ts/core 1.4.2 → 1.5.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 (71) hide show
  1. package/.prettierrc +11 -11
  2. package/LICENSE +21 -21
  3. package/__test/afterDispatcher.ts +9 -0
  4. package/__test/beforeDispatcher.ts +9 -0
  5. package/__test/controller.ts +66 -66
  6. package/__test/firstGuard.ts +10 -0
  7. package/__test/firstMiddleware.ts +9 -0
  8. package/__test/index.ts +8 -8
  9. package/__test/interfaces.ts +7 -7
  10. package/__test/module.ts +25 -16
  11. package/__test/repository.ts +16 -16
  12. package/__test/secondGuard.ts +10 -0
  13. package/__test/secondMiddleware.ts +9 -0
  14. package/__test/service.ts +20 -20
  15. package/bun.lockb +0 -0
  16. package/dist/decorators/arguments.d.ts +12 -6
  17. package/dist/decorators/arguments.js +39 -26
  18. package/dist/decorators/controller.d.ts +9 -1
  19. package/dist/decorators/controller.js +6 -4
  20. package/dist/decorators/dispatcher.d.ts +7 -0
  21. package/dist/decorators/dispatcher.js +9 -0
  22. package/dist/decorators/guard.d.ts +7 -0
  23. package/dist/decorators/guard.js +9 -0
  24. package/dist/decorators/http.d.ts +4 -3
  25. package/dist/decorators/http.js +6 -5
  26. package/dist/decorators/index.d.ts +13 -3
  27. package/dist/decorators/index.js +5 -2
  28. package/dist/decorators/injectable.d.ts +1 -1
  29. package/dist/decorators/injectable.js +1 -4
  30. package/dist/decorators/middleware.d.ts +7 -0
  31. package/dist/decorators/middleware.js +9 -0
  32. package/dist/decorators/module.d.ts +28 -7
  33. package/dist/decorators/module.js +48 -1
  34. package/dist/entities/route.d.ts +5 -5
  35. package/dist/entities/routerGroup.d.ts +1 -1
  36. package/dist/hooks/factory.d.ts +3 -3
  37. package/dist/hooks/factory.js +282 -60
  38. package/dist/hooks/injector.js +6 -5
  39. package/dist/interfaces/index.d.ts +5 -2
  40. package/dist/interfaces/index.js +1 -1
  41. package/package.json +1 -1
  42. package/src/decorators/arguments.ts +214 -186
  43. package/src/decorators/controller.ts +22 -14
  44. package/src/decorators/dispatcher.ts +19 -0
  45. package/src/decorators/guard.ts +19 -0
  46. package/src/decorators/http.ts +81 -81
  47. package/src/decorators/index.ts +28 -7
  48. package/src/decorators/inject.ts +13 -13
  49. package/src/decorators/injectable.ts +8 -11
  50. package/src/decorators/middleware.ts +19 -0
  51. package/src/decorators/module.ts +100 -21
  52. package/src/decorators/zodSchema.ts +20 -20
  53. package/src/entities/index.ts +3 -3
  54. package/src/entities/route.ts +328 -328
  55. package/src/entities/router.ts +35 -35
  56. package/src/entities/routerGroup.ts +34 -34
  57. package/src/hooks/factory.ts +653 -332
  58. package/src/hooks/index.ts +2 -2
  59. package/src/hooks/injector.ts +43 -43
  60. package/src/http/clientError.ts +45 -45
  61. package/src/http/index.ts +63 -63
  62. package/src/http/serverError.ts +38 -38
  63. package/src/index.ts +6 -6
  64. package/src/interfaces/controller.d.ts +1 -0
  65. package/src/interfaces/dispatcher.d.ts +3 -0
  66. package/src/interfaces/guard.d.ts +3 -0
  67. package/src/interfaces/index.ts +5 -3
  68. package/src/interfaces/middleware.d.ts +3 -0
  69. package/src/interfaces/module.d.ts +1 -0
  70. package/test.http +31 -30
  71. package/tsconfig.json +107 -107
@@ -1,332 +1,653 @@
1
- import "colors";
2
- import "reflect-metadata";
3
-
4
- import Qs from "qs";
5
- import * as Zod from "zod";
6
-
7
- import { Router, RouterGroup } from "../entities";
8
- import { type IControllerRoute, type TModuleOptions, controllerKey, controllerRoutesKey, moduleKey } from "../decorators";
9
- import { HttpClientError, HttpServerError, jsonErrorInfer, type THttpMethods } from "../http";
10
- import { Injector } from "./injector";
11
- import { controllerActionArgumentsKey, EArgumentTypes, type TMetadata as TArgumentsMetadata } from "../decorators/arguments";
12
-
13
- export type TBoolFactoryOptions = Required<{
14
- port: number;
15
- }> &
16
- Partial<{
17
- prefix: string;
18
- debug: boolean;
19
- log: Partial<{
20
- methods: Array<"GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "OPTIONS">;
21
- }>;
22
- queryParser: Parameters<typeof Qs.parse>[1];
23
- }>;
24
-
25
- export const controllerCreator = (controllerConstructor: new (...args: any[]) => unknown, group: RouterGroup) => {
26
- if (!Reflect.getOwnMetadataKeys(controllerConstructor).includes(controllerKey)) {
27
- throw Error(`${controllerConstructor.name} is not a controller.`);
28
- }
29
-
30
- const controller = Injector.get(controllerConstructor);
31
-
32
- if (!controller) {
33
- throw Error("Can not initialize controller.");
34
- }
35
-
36
- const controllerMetadata = Reflect.getOwnMetadata(controllerKey, controllerConstructor) || "/";
37
- const routesMetadata = (Reflect.getOwnMetadata(controllerRoutesKey, controllerConstructor) ||
38
- []) as Array<IControllerRoute>;
39
- const router = new Router(controllerMetadata);
40
-
41
- routesMetadata.forEach((routeMetadata) => {
42
- if (typeof routeMetadata.descriptor.value !== "function") {
43
- return;
44
- }
45
-
46
- const route = router.route(`/${routeMetadata.path}`);
47
- const handler = routeMetadata.descriptor.value.bind(controller);
48
- const routeArgument = {
49
- constructor: controllerConstructor,
50
- funcName: routeMetadata.methodName,
51
- func: handler
52
- };
53
-
54
- switch (routeMetadata.httpMethod) {
55
- case "GET":
56
- return route.get(routeArgument);
57
- case "POST":
58
- return route.post(routeArgument);
59
- case "PUT":
60
- return route.put(routeArgument);
61
- case "PATCH":
62
- return route.patch(routeArgument);
63
- case "DELETE":
64
- return route.delete(routeArgument);
65
- case "OPTIONS":
66
- return route.options(routeArgument);
67
- }
68
- });
69
-
70
- return group.add(router);
71
- };
72
-
73
- export const controllerActionArgumentsResolution = async (
74
- data: unknown,
75
- zodSchema: Zod.Schema,
76
- argumentIndex: number,
77
- funcName: string | symbol
78
- ) => {
79
- try {
80
- const validation = await zodSchema.safeParseAsync(data);
81
-
82
- if (!validation.success) {
83
- throw new HttpClientError({
84
- httpCode: 400,
85
- message: `Validation at the [${funcName.toString()}] method fails at positional argument [${argumentIndex}].`,
86
- data: validation.error.issues
87
- });
88
- }
89
-
90
- return validation.data;
91
- } catch (error) {
92
- if (error instanceof HttpClientError) {
93
- throw error;
94
- }
95
-
96
- throw new HttpServerError({
97
- httpCode: 500,
98
- message: `Validation at the [${funcName.toString()}] method error at positional argument [${argumentIndex}].`,
99
- data: !(error instanceof Error)
100
- ? error
101
- : [
102
- {
103
- message: error.message,
104
- code: error.name,
105
- cause: error.cause
106
- }
107
- ]
108
- });
109
- }
110
- };
111
-
112
- export const BoolFactory = (target: new (...args: any[]) => unknown, options: TBoolFactoryOptions) => {
113
- if (!Reflect.getOwnMetadataKeys(target).includes(moduleKey)) {
114
- throw Error(`${target.name} is not a module.`);
115
- }
116
-
117
- const moduleMetadata = Reflect.getOwnMetadata(moduleKey, target) as TModuleOptions;
118
- const allowOrigins = !moduleMetadata?.allowOrigins
119
- ? ["*"]
120
- : typeof moduleMetadata.allowOrigins !== "string"
121
- ? moduleMetadata.allowOrigins
122
- : [moduleMetadata.allowOrigins];
123
- const allowMethods = !moduleMetadata?.allowMethods
124
- ? ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]
125
- : moduleMetadata.allowMethods;
126
- const { allowLogsMethods } = Object.freeze({
127
- allowLogsMethods: !options?.log?.methods ? ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"] : options.log.methods
128
- });
129
-
130
- const routerGroup = new RouterGroup();
131
-
132
- moduleMetadata?.controllers &&
133
- moduleMetadata.controllers.map((controllerConstructor) => controllerCreator(controllerConstructor, routerGroup));
134
-
135
- Bun.serve({
136
- port: options.port,
137
- async fetch(request) {
138
- const start = performance.now();
139
- const url = new URL(request.url);
140
-
141
- try {
142
- const reqHeaders = request.headers;
143
- const origin = reqHeaders.get("origin");
144
- const resHeaders = new Headers({
145
- "Access-Control-Allow-Origin": origin || "*",
146
- "Access-Control-Allow-Headers": "*",
147
- "Access-Control-Allow-Credentials": "true",
148
- "Access-Control-Allow-Methods": allowMethods.join(", "),
149
- "Content-Type": "application/json"
150
- });
151
-
152
- if (!allowOrigins.includes("*")) {
153
- if (!origin) {
154
- return new Response(
155
- JSON.stringify({
156
- httpCode: 403,
157
- message: "Origin not found.",
158
- data: {
159
- origin: {
160
- code: "origin:invalid:0x00001",
161
- message: "Origin not found."
162
- }
163
- }
164
- }),
165
- {
166
- status: 403,
167
- statusText: "Origin not found.",
168
- headers: resHeaders
169
- }
170
- );
171
- }
172
-
173
- if (!allowOrigins.includes(origin)) {
174
- return new Response(
175
- JSON.stringify({
176
- httpCode: 403,
177
- message: "Origin not found.",
178
- data: {
179
- origin: {
180
- code: "origin:invalid:0x00002",
181
- message: "Invalid origin."
182
- }
183
- }
184
- }),
185
- {
186
- status: 403,
187
- statusText: "Invalid origin.",
188
- headers: resHeaders
189
- }
190
- );
191
- }
192
- }
193
-
194
- if (!allowMethods.includes(request.method.toUpperCase())) {
195
- throw new HttpClientError({
196
- httpCode: 405,
197
- message: "Method Not Allowed.",
198
- data: undefined
199
- });
200
- }
201
-
202
- const result = routerGroup.find(url.pathname, request.method as keyof THttpMethods);
203
-
204
- if (!result) {
205
- throw new HttpClientError({
206
- httpCode: 404,
207
- message: "Route not found.",
208
- data: undefined
209
- });
210
- }
211
-
212
- const params = result.params;
213
- const query = Qs.parse(url.search, options.queryParser);
214
-
215
- let responseBody = undefined;
216
-
217
- for (let i = 0; i < result.handlers.length; i++) {
218
- const handler = result.handlers[i];
219
- const handlerMetadata = (Reflect.getOwnMetadata(
220
- controllerActionArgumentsKey,
221
- handler.constructor,
222
- handler.funcName
223
- ) || {}) as Record<string, TArgumentsMetadata>;
224
-
225
- const controllerActionArguments = [];
226
-
227
- if (handlerMetadata) {
228
- for (const [_key, argsMetadata] of Object.entries(handlerMetadata)) {
229
- switch (argsMetadata.type) {
230
- case EArgumentTypes.headers:
231
- controllerActionArguments[argsMetadata.index] = !argsMetadata.zodSchema
232
- ? reqHeaders
233
- : await controllerActionArgumentsResolution(
234
- reqHeaders,
235
- argsMetadata.zodSchema,
236
- argsMetadata.index,
237
- handler.funcName
238
- );
239
- break;
240
- case EArgumentTypes.body:
241
- controllerActionArguments[argsMetadata.index] = !argsMetadata.zodSchema
242
- ? await request[argsMetadata.parser || "json"]()
243
- : await controllerActionArgumentsResolution(
244
- await request[argsMetadata.parser || "json"](),
245
- argsMetadata.zodSchema,
246
- argsMetadata.index,
247
- handler.funcName
248
- );
249
- break;
250
- case EArgumentTypes.params:
251
- controllerActionArguments[argsMetadata.index] = !argsMetadata.zodSchema
252
- ? params
253
- : await controllerActionArgumentsResolution(
254
- params,
255
- argsMetadata.zodSchema,
256
- argsMetadata.index,
257
- handler.funcName
258
- );
259
- break;
260
- case EArgumentTypes.query:
261
- controllerActionArguments[argsMetadata.index] = !argsMetadata.zodSchema
262
- ? query
263
- : await controllerActionArgumentsResolution(
264
- query,
265
- argsMetadata.zodSchema,
266
- argsMetadata.index,
267
- handler.funcName
268
- );
269
- break;
270
- case EArgumentTypes.param:
271
- controllerActionArguments[argsMetadata.index] = !argsMetadata.zodSchema
272
- ? !(argsMetadata.key in params)
273
- ? undefined
274
- : params[argsMetadata.key]
275
- : await controllerActionArgumentsResolution(
276
- query,
277
- argsMetadata.zodSchema,
278
- argsMetadata.index,
279
- handler.funcName
280
- );
281
- break;
282
- case EArgumentTypes.request:
283
- controllerActionArguments[argsMetadata.index] = request;
284
- break;
285
- }
286
- }
287
- }
288
-
289
- const responseData = await handler.func(...controllerActionArguments);
290
-
291
- if (responseData instanceof Response) {
292
- return responseData;
293
- }
294
-
295
- responseBody = responseData;
296
- }
297
-
298
- const response = new Response(
299
- JSON.stringify({
300
- httpCode: 200,
301
- message: "Success",
302
- data: responseBody
303
- }),
304
- {
305
- status: 200,
306
- statusText: "Success",
307
- headers: resHeaders
308
- }
309
- );
310
-
311
- return response;
312
- } catch (error) {
313
- return jsonErrorInfer(error);
314
- } finally {
315
- const end = performance.now();
316
- const convertedPID = `${process.pid}`.yellow;
317
- const convertedMethod = `${request.method.yellow}`.bgBlue;
318
- const convertedReqIp = `${
319
- request.headers.get("x-forwarded-for") || request.headers.get("x-real-ip") || "<Unknown>"
320
- }`.yellow;
321
- const convertedTime = `${Math.round((end - start + Number.EPSILON) * 10 ** 2) / 10 ** 2}ms`.yellow;
322
-
323
- allowLogsMethods.includes(request.method.toUpperCase()) &&
324
- console.info(
325
- `PID: ${convertedPID} - Method: ${convertedMethod} - IP: ${convertedReqIp} - ${url.pathname.blue} - Time: ${convertedTime}`
326
- );
327
- }
328
- }
329
- });
330
- };
331
-
332
- export default BoolFactory;
1
+ import "colors";
2
+ import "reflect-metadata";
3
+
4
+ import Qs from "qs";
5
+ import * as Zod from "zod";
6
+
7
+ import type { TModuleMetadata, TArgumentsMetadata, THttpMetadata, TControllerMetadata } from "../decorators";
8
+
9
+ import { Router, RouterGroup } from "../entities";
10
+ import { controllerHttpKey, controllerKey, argumentsKey, moduleKey, EArgumentTypes } from "../decorators";
11
+ import { HttpClientError, HttpServerError, jsonErrorInfer, type THttpMethods } from "../http";
12
+ import { Injector } from "./injector";
13
+ import type { IGuard, IMiddleware } from "../interfaces";
14
+ import type { IDispatcher } from "../interfaces/dispatcher";
15
+
16
+ export type TBoolFactoryOptions = Required<{
17
+ port: number;
18
+ }> &
19
+ Partial<{
20
+ prefix: string;
21
+ debug: boolean;
22
+ log: Partial<{
23
+ methods: Array<"GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "OPTIONS">;
24
+ }>;
25
+ queryParser: Parameters<typeof Qs.parse>[1];
26
+ }>;
27
+
28
+ export const controllerCreator = (
29
+ controllerConstructor: new (...args: any[]) => unknown,
30
+ group: RouterGroup,
31
+ prefix?: string
32
+ ) => {
33
+ if (!Reflect.getOwnMetadataKeys(controllerConstructor).includes(controllerKey)) {
34
+ throw Error(`${controllerConstructor.name} is not a controller.`);
35
+ }
36
+
37
+ const controller = Injector.get(controllerConstructor);
38
+
39
+ if (!controller) {
40
+ throw Error("Can not initialize controller.");
41
+ }
42
+
43
+ const controllerMetadata: TControllerMetadata = Reflect.getOwnMetadata(controllerKey, controllerConstructor) || {
44
+ prefix: "/"
45
+ };
46
+ const routesMetadata = (Reflect.getOwnMetadata(controllerHttpKey, controllerConstructor) || []) as THttpMetadata;
47
+ const router = new Router(controllerMetadata.prefix);
48
+
49
+ routesMetadata.forEach((routeMetadata) => {
50
+ if (typeof routeMetadata.descriptor.value !== "function") {
51
+ return;
52
+ }
53
+
54
+ const route = router.route(`/${prefix || ""}/${routeMetadata.path}`);
55
+ const handler = routeMetadata.descriptor.value.bind(controller);
56
+ const routeArgument = {
57
+ class: controllerConstructor,
58
+ funcName: routeMetadata.methodName,
59
+ func: handler
60
+ };
61
+
62
+ switch (routeMetadata.httpMethod) {
63
+ case "GET":
64
+ return route.get(routeArgument);
65
+ case "POST":
66
+ return route.post(routeArgument);
67
+ case "PUT":
68
+ return route.put(routeArgument);
69
+ case "PATCH":
70
+ return route.patch(routeArgument);
71
+ case "DELETE":
72
+ return route.delete(routeArgument);
73
+ case "OPTIONS":
74
+ return route.options(routeArgument);
75
+ }
76
+ });
77
+
78
+ return group.add(router);
79
+ };
80
+
81
+ export const argumentsResolution = async (
82
+ data: unknown,
83
+ zodSchema: Zod.Schema,
84
+ argumentIndex: number,
85
+ funcName: string | symbol
86
+ ) => {
87
+ try {
88
+ const validation = await zodSchema.safeParseAsync(data);
89
+
90
+ if (!validation.success) {
91
+ throw new HttpClientError({
92
+ httpCode: 400,
93
+ message: `Validation at the [${funcName.toString()}] method fails at positional argument [${argumentIndex}].`,
94
+ data: validation.error.issues
95
+ });
96
+ }
97
+
98
+ return validation.data;
99
+ } catch (error) {
100
+ if (error instanceof HttpClientError) {
101
+ throw error;
102
+ }
103
+
104
+ throw new HttpServerError({
105
+ httpCode: 500,
106
+ message: `Validation at the [${funcName.toString()}] method error at positional argument [${argumentIndex}].`,
107
+ data: !(error instanceof Error)
108
+ ? error
109
+ : [
110
+ {
111
+ message: error.message,
112
+ code: error.name,
113
+ cause: error.cause
114
+ }
115
+ ]
116
+ });
117
+ }
118
+ };
119
+
120
+ export const BoolFactory = (target: new (...args: any[]) => unknown, options: TBoolFactoryOptions) => {
121
+ if (!Reflect.getOwnMetadataKeys(target).includes(moduleKey)) {
122
+ throw Error(`${target.name} is not a module.`);
123
+ }
124
+
125
+ const moduleMetadata = Reflect.getOwnMetadata(moduleKey, target) as TModuleMetadata;
126
+
127
+ if (!moduleMetadata) {
128
+ return Bun.serve({
129
+ port: options.port,
130
+ fetch: () => new Response()
131
+ });
132
+ }
133
+
134
+ const { middlewares, guards, beforeDispatchers, controllers, afterDispatchers, options: moduleOptions } = moduleMetadata;
135
+
136
+ // Middleware(s)
137
+ const middlewareGroup = !middlewares
138
+ ? []
139
+ : middlewares.map((middleware) => {
140
+ const middlewareInstance = Injector.get<IMiddleware>(middleware);
141
+
142
+ return Object.freeze({
143
+ class: middleware,
144
+ funcName: "enforce",
145
+ func: middlewareInstance.enforce.bind(middlewareInstance)
146
+ });
147
+ });
148
+
149
+ // Guard(s)
150
+ const guardGroup = !guards
151
+ ? []
152
+ : guards.map((guard) => {
153
+ const guardInstance = Injector.get<IGuard>(guard);
154
+
155
+ return Object.freeze({
156
+ class: guard,
157
+ funcName: "enforce",
158
+ func: guardInstance.enforce.bind(guardInstance)
159
+ });
160
+ });
161
+
162
+ // Before dispatcher(s)
163
+ const beforeDispatcherGroup = !beforeDispatchers
164
+ ? []
165
+ : beforeDispatchers.map((beforeDispatcher) => {
166
+ const beforeDispatcherInstance = Injector.get<IDispatcher>(beforeDispatcher);
167
+
168
+ return Object.freeze({
169
+ class: beforeDispatcher,
170
+ funcName: "execute",
171
+ func: beforeDispatcherInstance.execute.bind(beforeDispatcherInstance)
172
+ });
173
+ });
174
+
175
+ // Controller(s)
176
+ const routerGroup = new RouterGroup();
177
+
178
+ controllers &&
179
+ controllers.map((controllerConstructor) => controllerCreator(controllerConstructor, routerGroup, options.prefix));
180
+
181
+ const allowOrigins = !moduleOptions?.allowOrigins
182
+ ? ["*"]
183
+ : typeof moduleOptions.allowOrigins !== "string"
184
+ ? moduleOptions.allowOrigins
185
+ : [moduleOptions.allowOrigins];
186
+ const allowMethods = !moduleOptions?.allowMethods
187
+ ? ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]
188
+ : moduleOptions.allowMethods;
189
+ const { allowLogsMethods } = Object.freeze({
190
+ allowLogsMethods: options?.log?.methods
191
+ });
192
+
193
+ // After dispatcher(s)
194
+ const afterDispatcherGroup = !afterDispatchers
195
+ ? []
196
+ : afterDispatchers.map((afterDispatcher) => {
197
+ const afterDispatcherInstance = Injector.get<IDispatcher>(afterDispatcher);
198
+
199
+ return Object.freeze({
200
+ class: afterDispatcher,
201
+ funcName: "execute",
202
+ func: afterDispatcherInstance.execute.bind(afterDispatcherInstance)
203
+ });
204
+ });
205
+
206
+ Bun.serve({
207
+ port: options.port,
208
+ fetch: async (request) => {
209
+ const start = performance.now();
210
+ const url = new URL(request.url);
211
+
212
+ try {
213
+ const reqHeaders = request.headers;
214
+ const origin = reqHeaders.get("origin");
215
+ const resHeaders = new Headers({
216
+ "Access-Control-Allow-Origin": origin || "*",
217
+ "Access-Control-Allow-Headers": "*",
218
+ "Access-Control-Allow-Credentials": "true",
219
+ "Access-Control-Allow-Methods": allowMethods.join(", "),
220
+ "Content-Type": "application/json"
221
+ });
222
+
223
+ if (!allowOrigins.includes("*")) {
224
+ if (!origin) {
225
+ return new Response(
226
+ JSON.stringify({
227
+ httpCode: 403,
228
+ message: "Origin not found.",
229
+ data: {
230
+ origin: {
231
+ code: "origin:invalid:0x00001",
232
+ message: "Origin not found."
233
+ }
234
+ }
235
+ }),
236
+ {
237
+ status: 403,
238
+ statusText: "Origin not found.",
239
+ headers: resHeaders
240
+ }
241
+ );
242
+ }
243
+
244
+ if (!allowOrigins.includes(origin)) {
245
+ return new Response(
246
+ JSON.stringify({
247
+ httpCode: 403,
248
+ message: "Origin not found.",
249
+ data: {
250
+ origin: {
251
+ code: "origin:invalid:0x00002",
252
+ message: "Invalid origin."
253
+ }
254
+ }
255
+ }),
256
+ {
257
+ status: 403,
258
+ statusText: "Invalid origin.",
259
+ headers: resHeaders
260
+ }
261
+ );
262
+ }
263
+ }
264
+
265
+ if (!allowMethods.includes(request.method.toUpperCase())) {
266
+ throw new HttpClientError({
267
+ httpCode: 405,
268
+ message: "Method Not Allowed.",
269
+ data: undefined
270
+ });
271
+ }
272
+
273
+ // Execute middleware(s)
274
+ for (let i = 0; i < middlewareGroup.length; i++) {
275
+ const middlewareArguments = [];
276
+ const middlewareCollection = middlewareGroup[i];
277
+ const middlewareMetadata: Record<string, TArgumentsMetadata> =
278
+ Reflect.getOwnMetadata(argumentsKey, middlewareCollection.class, middlewareCollection.funcName) || {};
279
+
280
+ if (middlewareMetadata) {
281
+ for (const [_key, argsMetadata] of Object.entries(middlewareMetadata)) {
282
+ switch (argsMetadata.type) {
283
+ case EArgumentTypes.requestHeaders:
284
+ middlewareArguments[argsMetadata.index] = !argsMetadata.zodSchema
285
+ ? reqHeaders
286
+ : await argumentsResolution(
287
+ reqHeaders,
288
+ argsMetadata.zodSchema,
289
+ argsMetadata.index,
290
+ middlewareCollection.funcName
291
+ );
292
+ break;
293
+ case EArgumentTypes.body:
294
+ middlewareArguments[argsMetadata.index] = !argsMetadata.zodSchema
295
+ ? await request[argsMetadata.parser || "json"]()
296
+ : await argumentsResolution(
297
+ await request[argsMetadata.parser || "json"](),
298
+ argsMetadata.zodSchema,
299
+ argsMetadata.index,
300
+ middlewareCollection.funcName
301
+ );
302
+ break;
303
+ case EArgumentTypes.request:
304
+ middlewareArguments[argsMetadata.index] = request;
305
+ break;
306
+ case EArgumentTypes.responseHeaders:
307
+ middlewareArguments[argsMetadata.index] = resHeaders;
308
+ break;
309
+ }
310
+ }
311
+ }
312
+
313
+ await middlewareCollection.func(...middlewareArguments);
314
+ }
315
+
316
+ // Execute guard(s)
317
+ for (let i = 0; i < guardGroup.length; i++) {
318
+ const guardArguments = [];
319
+ const guardCollection = guardGroup[i];
320
+ const guardMetadata: Record<string, TArgumentsMetadata> =
321
+ Reflect.getOwnMetadata(argumentsKey, guardCollection.class, guardCollection.funcName) || {};
322
+
323
+ if (guardMetadata) {
324
+ for (const [_key, argsMetadata] of Object.entries(guardMetadata)) {
325
+ switch (argsMetadata.type) {
326
+ case EArgumentTypes.requestHeaders:
327
+ guardArguments[argsMetadata.index] = !argsMetadata.zodSchema
328
+ ? reqHeaders
329
+ : await argumentsResolution(
330
+ reqHeaders,
331
+ argsMetadata.zodSchema,
332
+ argsMetadata.index,
333
+ guardCollection.funcName
334
+ );
335
+ break;
336
+ case EArgumentTypes.body:
337
+ guardArguments[argsMetadata.index] = !argsMetadata.zodSchema
338
+ ? await request[argsMetadata.parser || "json"]()
339
+ : await argumentsResolution(
340
+ await request[argsMetadata.parser || "json"](),
341
+ argsMetadata.zodSchema,
342
+ argsMetadata.index,
343
+ guardCollection.funcName
344
+ );
345
+ break;
346
+ case EArgumentTypes.request:
347
+ guardArguments[argsMetadata.index] = request;
348
+ break;
349
+ case EArgumentTypes.responseHeaders:
350
+ guardArguments[argsMetadata.index] = resHeaders;
351
+ break;
352
+ }
353
+ }
354
+ }
355
+
356
+ const guardResult = await guardCollection.func(...guardArguments);
357
+
358
+ if (typeof guardResult !== "boolean" || !guardResult) {
359
+ throw new HttpClientError({
360
+ httpCode: 401,
361
+ message: "Unauthorization.",
362
+ data: undefined
363
+ });
364
+ }
365
+ }
366
+
367
+ const result = routerGroup.find(url.pathname, request.method as keyof THttpMethods);
368
+
369
+ if (!result) {
370
+ throw new HttpClientError({
371
+ httpCode: 404,
372
+ message: "Route not found.",
373
+ data: undefined
374
+ });
375
+ }
376
+
377
+ const params = result.params;
378
+ const query = Qs.parse(url.search, options.queryParser);
379
+
380
+ let responseBody = undefined;
381
+
382
+ // Execute before dispatcher(s)
383
+ for (let i = 0; i < beforeDispatcherGroup.length; i++) {
384
+ const beforeDispatcherArguments = [];
385
+ const beforeDispatcherCollection = beforeDispatcherGroup[i];
386
+ const beforeDispatcherMetadata: Record<string, TArgumentsMetadata> =
387
+ Reflect.getOwnMetadata(
388
+ argumentsKey,
389
+ beforeDispatcherCollection.class,
390
+ beforeDispatcherCollection.funcName
391
+ ) || {};
392
+
393
+ if (beforeDispatcherMetadata) {
394
+ for (const [_key, argsMetadata] of Object.entries(beforeDispatcherMetadata)) {
395
+ switch (argsMetadata.type) {
396
+ case EArgumentTypes.requestHeaders:
397
+ beforeDispatcherArguments[argsMetadata.index] = !argsMetadata.zodSchema
398
+ ? reqHeaders
399
+ : await argumentsResolution(
400
+ reqHeaders,
401
+ argsMetadata.zodSchema,
402
+ argsMetadata.index,
403
+ beforeDispatcherCollection.funcName
404
+ );
405
+ break;
406
+ case EArgumentTypes.body:
407
+ beforeDispatcherArguments[argsMetadata.index] = !argsMetadata.zodSchema
408
+ ? await request[argsMetadata.parser || "json"]()
409
+ : await argumentsResolution(
410
+ await request[argsMetadata.parser || "json"](),
411
+ argsMetadata.zodSchema,
412
+ argsMetadata.index,
413
+ beforeDispatcherCollection.funcName
414
+ );
415
+ break;
416
+ case EArgumentTypes.params:
417
+ beforeDispatcherArguments[argsMetadata.index] = !argsMetadata.zodSchema
418
+ ? params
419
+ : await argumentsResolution(
420
+ params,
421
+ argsMetadata.zodSchema,
422
+ argsMetadata.index,
423
+ beforeDispatcherCollection.funcName
424
+ );
425
+ break;
426
+ case EArgumentTypes.query:
427
+ beforeDispatcherArguments[argsMetadata.index] = !argsMetadata.zodSchema
428
+ ? query
429
+ : await argumentsResolution(
430
+ query,
431
+ argsMetadata.zodSchema,
432
+ argsMetadata.index,
433
+ beforeDispatcherCollection.funcName
434
+ );
435
+ break;
436
+ case EArgumentTypes.param:
437
+ beforeDispatcherArguments[argsMetadata.index] = !argsMetadata.zodSchema
438
+ ? !(argsMetadata.key in params)
439
+ ? undefined
440
+ : params[argsMetadata.key]
441
+ : await argumentsResolution(
442
+ query,
443
+ argsMetadata.zodSchema,
444
+ argsMetadata.index,
445
+ beforeDispatcherCollection.funcName
446
+ );
447
+ break;
448
+ case EArgumentTypes.request:
449
+ beforeDispatcherArguments[argsMetadata.index] = request;
450
+ break;
451
+ case EArgumentTypes.responseHeaders:
452
+ beforeDispatcherArguments[argsMetadata.index] = resHeaders;
453
+ break;
454
+ }
455
+ }
456
+ }
457
+
458
+ await beforeDispatcherCollection.func(...beforeDispatcherArguments);
459
+ }
460
+
461
+ // Execute controller action
462
+ for (let i = 0; i < result.handlers.length; i++) {
463
+ const controllerActionArguments = [];
464
+ const handler = result.handlers[i];
465
+ const handlerMetadata: Record<string, TArgumentsMetadata> =
466
+ Reflect.getOwnMetadata(argumentsKey, handler.class, handler.funcName) || {};
467
+
468
+ if (handlerMetadata) {
469
+ for (const [_key, argsMetadata] of Object.entries(handlerMetadata)) {
470
+ switch (argsMetadata.type) {
471
+ case EArgumentTypes.requestHeaders:
472
+ controllerActionArguments[argsMetadata.index] = !argsMetadata.zodSchema
473
+ ? reqHeaders
474
+ : await argumentsResolution(
475
+ reqHeaders,
476
+ argsMetadata.zodSchema,
477
+ argsMetadata.index,
478
+ handler.funcName
479
+ );
480
+ break;
481
+ case EArgumentTypes.body:
482
+ controllerActionArguments[argsMetadata.index] = !argsMetadata.zodSchema
483
+ ? await request[argsMetadata.parser || "json"]()
484
+ : await argumentsResolution(
485
+ await request[argsMetadata.parser || "json"](),
486
+ argsMetadata.zodSchema,
487
+ argsMetadata.index,
488
+ handler.funcName
489
+ );
490
+ break;
491
+ case EArgumentTypes.params:
492
+ controllerActionArguments[argsMetadata.index] = !argsMetadata.zodSchema
493
+ ? params
494
+ : await argumentsResolution(
495
+ params,
496
+ argsMetadata.zodSchema,
497
+ argsMetadata.index,
498
+ handler.funcName
499
+ );
500
+ break;
501
+ case EArgumentTypes.query:
502
+ controllerActionArguments[argsMetadata.index] = !argsMetadata.zodSchema
503
+ ? query
504
+ : await argumentsResolution(
505
+ query,
506
+ argsMetadata.zodSchema,
507
+ argsMetadata.index,
508
+ handler.funcName
509
+ );
510
+ break;
511
+ case EArgumentTypes.param:
512
+ controllerActionArguments[argsMetadata.index] = !argsMetadata.zodSchema
513
+ ? !(argsMetadata.key in params)
514
+ ? undefined
515
+ : params[argsMetadata.key]
516
+ : await argumentsResolution(
517
+ query,
518
+ argsMetadata.zodSchema,
519
+ argsMetadata.index,
520
+ handler.funcName
521
+ );
522
+ break;
523
+ case EArgumentTypes.request:
524
+ controllerActionArguments[argsMetadata.index] = request;
525
+ break;
526
+ case EArgumentTypes.responseHeaders:
527
+ controllerActionArguments[argsMetadata.index] = resHeaders;
528
+ break;
529
+ }
530
+ }
531
+ }
532
+
533
+ responseBody = await handler.func(...controllerActionArguments);
534
+ }
535
+
536
+ // Execute after dispatcher(s)
537
+ for (let i = 0; i < afterDispatcherGroup.length; i++) {
538
+ const afterDispatcherArguments = [];
539
+ const afterDispatcherCollection = afterDispatcherGroup[i];
540
+ const afterDispatcherMetadata: Record<string, TArgumentsMetadata> =
541
+ Reflect.getOwnMetadata(
542
+ argumentsKey,
543
+ afterDispatcherCollection.class,
544
+ afterDispatcherCollection.funcName
545
+ ) || {};
546
+
547
+ if (afterDispatcherMetadata) {
548
+ for (const [_key, argsMetadata] of Object.entries(afterDispatcherMetadata)) {
549
+ switch (argsMetadata.type) {
550
+ case EArgumentTypes.requestHeaders:
551
+ afterDispatcherArguments[argsMetadata.index] = !argsMetadata.zodSchema
552
+ ? reqHeaders
553
+ : await argumentsResolution(
554
+ reqHeaders,
555
+ argsMetadata.zodSchema,
556
+ argsMetadata.index,
557
+ afterDispatcherCollection.funcName
558
+ );
559
+ break;
560
+ case EArgumentTypes.body:
561
+ afterDispatcherArguments[argsMetadata.index] = !argsMetadata.zodSchema
562
+ ? await request[argsMetadata.parser || "json"]()
563
+ : await argumentsResolution(
564
+ await request[argsMetadata.parser || "json"](),
565
+ argsMetadata.zodSchema,
566
+ argsMetadata.index,
567
+ afterDispatcherCollection.funcName
568
+ );
569
+ break;
570
+ case EArgumentTypes.params:
571
+ afterDispatcherArguments[argsMetadata.index] = !argsMetadata.zodSchema
572
+ ? params
573
+ : await argumentsResolution(
574
+ params,
575
+ argsMetadata.zodSchema,
576
+ argsMetadata.index,
577
+ afterDispatcherCollection.funcName
578
+ );
579
+ break;
580
+ case EArgumentTypes.query:
581
+ afterDispatcherArguments[argsMetadata.index] = !argsMetadata.zodSchema
582
+ ? query
583
+ : await argumentsResolution(
584
+ query,
585
+ argsMetadata.zodSchema,
586
+ argsMetadata.index,
587
+ afterDispatcherCollection.funcName
588
+ );
589
+ break;
590
+ case EArgumentTypes.param:
591
+ afterDispatcherArguments[argsMetadata.index] = !argsMetadata.zodSchema
592
+ ? !(argsMetadata.key in params)
593
+ ? undefined
594
+ : params[argsMetadata.key]
595
+ : await argumentsResolution(
596
+ query,
597
+ argsMetadata.zodSchema,
598
+ argsMetadata.index,
599
+ afterDispatcherCollection.funcName
600
+ );
601
+ break;
602
+ case EArgumentTypes.request:
603
+ afterDispatcherArguments[argsMetadata.index] = request;
604
+ break;
605
+ case EArgumentTypes.responseHeaders:
606
+ afterDispatcherArguments[argsMetadata.index] = resHeaders;
607
+ break;
608
+ }
609
+ }
610
+ }
611
+
612
+ await afterDispatcherCollection.func(...afterDispatcherArguments);
613
+ }
614
+
615
+ return responseBody instanceof Response
616
+ ? responseBody
617
+ : new Response(
618
+ !responseBody
619
+ ? undefined
620
+ : JSON.stringify({
621
+ httpCode: 200,
622
+ message: "SUCCESS",
623
+ data: responseBody
624
+ }),
625
+ {
626
+ status: !responseBody ? 204 : 200,
627
+ statusText: "SUCCESS",
628
+ headers: resHeaders
629
+ }
630
+ );
631
+ } catch (error) {
632
+ return jsonErrorInfer(error);
633
+ } finally {
634
+ if (allowLogsMethods) {
635
+ const end = performance.now();
636
+ const convertedPID = `${process.pid}`.yellow;
637
+ const convertedMethod = `${request.method.yellow}`.bgBlue;
638
+ const convertedReqIp = `${
639
+ request.headers.get("x-forwarded-for") || request.headers.get("x-real-ip") || "<Unknown>"
640
+ }`.yellow;
641
+ const convertedTime = `${Math.round((end - start + Number.EPSILON) * 10 ** 2) / 10 ** 2}ms`.yellow;
642
+
643
+ allowLogsMethods.includes(request.method.toUpperCase() as (typeof allowLogsMethods)[number]) &&
644
+ console.info(
645
+ `PID: ${convertedPID} - Method: ${convertedMethod} - IP: ${convertedReqIp} - ${url.pathname.blue} - Time: ${convertedTime}`
646
+ );
647
+ }
648
+ }
649
+ }
650
+ });
651
+ };
652
+
653
+ export default BoolFactory;