@bool-ts/core 1.4.1 → 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.
- package/.prettierrc +11 -11
- package/LICENSE +21 -21
- package/__test/afterDispatcher.ts +9 -0
- package/__test/beforeDispatcher.ts +9 -0
- package/__test/controller.ts +66 -66
- package/__test/firstGuard.ts +10 -0
- package/__test/firstMiddleware.ts +9 -0
- package/__test/index.ts +8 -8
- package/__test/interfaces.ts +7 -7
- package/__test/module.ts +25 -16
- package/__test/repository.ts +16 -16
- package/__test/secondGuard.ts +10 -0
- package/__test/secondMiddleware.ts +9 -0
- package/__test/service.ts +20 -20
- package/bun.lockb +0 -0
- package/dist/decorators/arguments.d.ts +12 -6
- package/dist/decorators/arguments.js +39 -26
- package/dist/decorators/controller.d.ts +9 -1
- package/dist/decorators/controller.js +6 -4
- package/dist/decorators/dispatcher.d.ts +7 -0
- package/dist/decorators/dispatcher.js +9 -0
- package/dist/decorators/guard.d.ts +7 -0
- package/dist/decorators/guard.js +9 -0
- package/dist/decorators/http.d.ts +4 -3
- package/dist/decorators/http.js +6 -5
- package/dist/decorators/index.d.ts +13 -3
- package/dist/decorators/index.js +5 -2
- package/dist/decorators/injectable.d.ts +1 -1
- package/dist/decorators/injectable.js +1 -4
- package/dist/decorators/middleware.d.ts +7 -0
- package/dist/decorators/middleware.js +9 -0
- package/dist/decorators/module.d.ts +28 -7
- package/dist/decorators/module.js +48 -1
- package/dist/entities/route.d.ts +5 -5
- package/dist/entities/routerGroup.d.ts +1 -1
- package/dist/hooks/factory.d.ts +3 -3
- package/dist/hooks/factory.js +282 -60
- package/dist/hooks/injector.js +6 -5
- package/dist/interfaces/index.d.ts +5 -2
- package/dist/interfaces/index.js +1 -1
- package/package.json +1 -1
- package/src/decorators/arguments.ts +214 -186
- package/src/decorators/controller.ts +22 -14
- package/src/decorators/dispatcher.ts +19 -0
- package/src/decorators/guard.ts +19 -0
- package/src/decorators/http.ts +81 -81
- package/src/decorators/index.ts +28 -7
- package/src/decorators/inject.ts +13 -13
- package/src/decorators/injectable.ts +8 -11
- package/src/decorators/middleware.ts +19 -0
- package/src/decorators/module.ts +100 -21
- package/src/decorators/zodSchema.ts +20 -20
- package/src/entities/index.ts +3 -3
- package/src/entities/route.ts +328 -328
- package/src/entities/router.ts +35 -35
- package/src/entities/routerGroup.ts +34 -34
- package/src/hooks/factory.ts +653 -319
- package/src/hooks/index.ts +2 -2
- package/src/hooks/injector.ts +43 -43
- package/src/http/clientError.ts +45 -45
- package/src/http/index.ts +63 -63
- package/src/http/serverError.ts +38 -38
- package/src/index.ts +6 -6
- package/src/interfaces/controller.d.ts +1 -0
- package/src/interfaces/dispatcher.d.ts +3 -0
- package/src/interfaces/guard.d.ts +3 -0
- package/src/interfaces/index.ts +5 -3
- package/src/interfaces/middleware.d.ts +3 -0
- package/src/interfaces/module.d.ts +1 -0
- package/test.http +31 -30
- package/tsconfig.json +107 -107
package/src/hooks/factory.ts
CHANGED
|
@@ -1,319 +1,653 @@
|
|
|
1
|
-
import "colors";
|
|
2
|
-
import "reflect-metadata";
|
|
3
|
-
|
|
4
|
-
import Qs from "qs";
|
|
5
|
-
import * as Zod from "zod";
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
case "
|
|
64
|
-
return route.
|
|
65
|
-
case "
|
|
66
|
-
return route.
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
)
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
:
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
);
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
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;
|