@bool-ts/core 1.4.2 → 1.5.1

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