@bool-ts/core 1.5.7 → 1.5.8
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 -9
- package/__test/beforeDispatcher.ts +9 -9
- package/__test/controller.ts +68 -68
- package/__test/firstGuard.ts +10 -10
- package/__test/firstMiddleware.ts +9 -9
- package/__test/index.ts +8 -8
- package/__test/interfaces.ts +7 -7
- package/__test/module.ts +22 -22
- package/__test/repository.ts +16 -16
- package/__test/secondGuard.ts +10 -10
- package/__test/secondMiddleware.ts +9 -9
- package/__test/service.ts +20 -20
- package/bun.lockb +0 -0
- package/dist/entities/route.js +0 -1
- package/jsconfig.json +27 -27
- package/package.json +31 -31
- package/src/decorators/arguments.ts +214 -214
- package/src/decorators/controller.ts +22 -22
- package/src/decorators/dispatcher.ts +19 -19
- package/src/decorators/guard.ts +19 -19
- package/src/decorators/http.ts +81 -81
- package/src/decorators/index.ts +28 -28
- package/src/decorators/inject.ts +13 -13
- package/src/decorators/injectable.ts +8 -8
- package/src/decorators/middleware.ts +19 -19
- package/src/decorators/module.ts +92 -92
- package/src/decorators/zodSchema.ts +20 -20
- package/src/entities/index.ts +3 -3
- package/src/entities/route.ts +327 -328
- package/src/entities/router.ts +35 -35
- package/src/entities/routerGroup.ts +34 -34
- package/src/hooks/factory.ts +616 -616
- 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 +61 -61
- package/src/http/serverError.ts +38 -38
- package/src/index.ts +6 -6
- package/src/interfaces/controller.ts +1 -1
- package/src/interfaces/dispatcher.ts +3 -3
- package/src/interfaces/guard.ts +3 -3
- package/src/interfaces/index.ts +5 -5
- package/src/interfaces/middleware.ts +3 -3
- package/src/interfaces/module.ts +1 -1
- package/test.http +31 -31
- package/tsconfig.json +108 -108
package/src/hooks/factory.ts
CHANGED
|
@@ -1,616 +1,616 @@
|
|
|
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, prefix: modulePrefix } = 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 || ""}/${modulePrefix || ""}`)
|
|
182
|
-
);
|
|
183
|
-
|
|
184
|
-
const { allowLogsMethods } = Object.freeze({
|
|
185
|
-
allowLogsMethods: options?.log?.methods
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
// After dispatcher(s)
|
|
189
|
-
const afterDispatcherGroup = !afterDispatchers
|
|
190
|
-
? []
|
|
191
|
-
: afterDispatchers.map((afterDispatcher) => {
|
|
192
|
-
const afterDispatcherInstance = Injector.get<IDispatcher>(afterDispatcher);
|
|
193
|
-
|
|
194
|
-
return Object.freeze({
|
|
195
|
-
class: afterDispatcher,
|
|
196
|
-
funcName: "execute",
|
|
197
|
-
func: afterDispatcherInstance.execute.bind(afterDispatcherInstance)
|
|
198
|
-
});
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
Bun.serve({
|
|
202
|
-
port: options.port,
|
|
203
|
-
fetch: async (request) => {
|
|
204
|
-
const start = performance.now();
|
|
205
|
-
const url = new URL(request.url);
|
|
206
|
-
const reqHeaders = request.headers;
|
|
207
|
-
const resHeaders = new Headers();
|
|
208
|
-
const query = Qs.parse(url.searchParams.toString(), options.queryParser);
|
|
209
|
-
|
|
210
|
-
try {
|
|
211
|
-
// Execute middleware(s)
|
|
212
|
-
for (let i = 0; i < middlewareGroup.length; i++) {
|
|
213
|
-
const middlewareArguments = [];
|
|
214
|
-
const middlewareCollection = middlewareGroup[i];
|
|
215
|
-
const middlewareMetadata: Record<string, TArgumentsMetadata> =
|
|
216
|
-
Reflect.getOwnMetadata(argumentsKey, middlewareCollection.class, middlewareCollection.funcName) || {};
|
|
217
|
-
|
|
218
|
-
if (middlewareMetadata) {
|
|
219
|
-
for (const [_key, argsMetadata] of Object.entries(middlewareMetadata)) {
|
|
220
|
-
switch (argsMetadata.type) {
|
|
221
|
-
case EArgumentTypes.requestHeaders:
|
|
222
|
-
middlewareArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
223
|
-
? reqHeaders
|
|
224
|
-
: await argumentsResolution(
|
|
225
|
-
reqHeaders,
|
|
226
|
-
argsMetadata.zodSchema,
|
|
227
|
-
argsMetadata.index,
|
|
228
|
-
middlewareCollection.funcName
|
|
229
|
-
);
|
|
230
|
-
break;
|
|
231
|
-
case EArgumentTypes.body:
|
|
232
|
-
middlewareArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
233
|
-
? await request[argsMetadata.parser || "json"]()
|
|
234
|
-
: await argumentsResolution(
|
|
235
|
-
await request[argsMetadata.parser || "json"](),
|
|
236
|
-
argsMetadata.zodSchema,
|
|
237
|
-
argsMetadata.index,
|
|
238
|
-
middlewareCollection.funcName
|
|
239
|
-
);
|
|
240
|
-
break;
|
|
241
|
-
case EArgumentTypes.query:
|
|
242
|
-
middlewareArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
243
|
-
? query
|
|
244
|
-
: await argumentsResolution(
|
|
245
|
-
query,
|
|
246
|
-
argsMetadata.zodSchema,
|
|
247
|
-
argsMetadata.index,
|
|
248
|
-
middlewareCollection.funcName
|
|
249
|
-
);
|
|
250
|
-
break;
|
|
251
|
-
case EArgumentTypes.request:
|
|
252
|
-
middlewareArguments[argsMetadata.index] = request;
|
|
253
|
-
break;
|
|
254
|
-
case EArgumentTypes.responseHeaders:
|
|
255
|
-
middlewareArguments[argsMetadata.index] = resHeaders;
|
|
256
|
-
break;
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
const middlewareResult = await middlewareCollection.func(...middlewareArguments);
|
|
262
|
-
|
|
263
|
-
if (!(middlewareResult instanceof Response)) {
|
|
264
|
-
continue;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
return middlewareResult;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// Execute guard(s)
|
|
271
|
-
for (let i = 0; i < guardGroup.length; i++) {
|
|
272
|
-
const guardArguments = [];
|
|
273
|
-
const guardCollection = guardGroup[i];
|
|
274
|
-
const guardMetadata: Record<string, TArgumentsMetadata> =
|
|
275
|
-
Reflect.getOwnMetadata(argumentsKey, guardCollection.class, guardCollection.funcName) || {};
|
|
276
|
-
|
|
277
|
-
if (guardMetadata) {
|
|
278
|
-
for (const [_key, argsMetadata] of Object.entries(guardMetadata)) {
|
|
279
|
-
switch (argsMetadata.type) {
|
|
280
|
-
case EArgumentTypes.requestHeaders:
|
|
281
|
-
guardArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
282
|
-
? reqHeaders
|
|
283
|
-
: await argumentsResolution(
|
|
284
|
-
reqHeaders,
|
|
285
|
-
argsMetadata.zodSchema,
|
|
286
|
-
argsMetadata.index,
|
|
287
|
-
guardCollection.funcName
|
|
288
|
-
);
|
|
289
|
-
break;
|
|
290
|
-
case EArgumentTypes.body:
|
|
291
|
-
guardArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
292
|
-
? await request[argsMetadata.parser || "json"]()
|
|
293
|
-
: await argumentsResolution(
|
|
294
|
-
await request[argsMetadata.parser || "json"](),
|
|
295
|
-
argsMetadata.zodSchema,
|
|
296
|
-
argsMetadata.index,
|
|
297
|
-
guardCollection.funcName
|
|
298
|
-
);
|
|
299
|
-
break;
|
|
300
|
-
case EArgumentTypes.query:
|
|
301
|
-
guardArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
302
|
-
? query
|
|
303
|
-
: await argumentsResolution(
|
|
304
|
-
query,
|
|
305
|
-
argsMetadata.zodSchema,
|
|
306
|
-
argsMetadata.index,
|
|
307
|
-
guardCollection.funcName
|
|
308
|
-
);
|
|
309
|
-
break;
|
|
310
|
-
case EArgumentTypes.request:
|
|
311
|
-
guardArguments[argsMetadata.index] = request;
|
|
312
|
-
break;
|
|
313
|
-
case EArgumentTypes.responseHeaders:
|
|
314
|
-
guardArguments[argsMetadata.index] = resHeaders;
|
|
315
|
-
break;
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
const guardResult = await guardCollection.func(...guardArguments);
|
|
321
|
-
|
|
322
|
-
if (typeof guardResult !== "boolean" || !guardResult) {
|
|
323
|
-
throw new HttpClientError({
|
|
324
|
-
httpCode: 401,
|
|
325
|
-
message: "Unauthorization.",
|
|
326
|
-
data: undefined
|
|
327
|
-
});
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
const result = routerGroup.find(url.pathname, request.method as keyof THttpMethods);
|
|
332
|
-
|
|
333
|
-
if (!result) {
|
|
334
|
-
throw new HttpClientError({
|
|
335
|
-
httpCode: 404,
|
|
336
|
-
message: "Route not found.",
|
|
337
|
-
data: undefined
|
|
338
|
-
});
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
const params = result.params;
|
|
342
|
-
|
|
343
|
-
let responseBody = undefined;
|
|
344
|
-
|
|
345
|
-
// Execute before dispatcher(s)
|
|
346
|
-
for (let i = 0; i < beforeDispatcherGroup.length; i++) {
|
|
347
|
-
const beforeDispatcherArguments = [];
|
|
348
|
-
const beforeDispatcherCollection = beforeDispatcherGroup[i];
|
|
349
|
-
const beforeDispatcherMetadata: Record<string, TArgumentsMetadata> =
|
|
350
|
-
Reflect.getOwnMetadata(
|
|
351
|
-
argumentsKey,
|
|
352
|
-
beforeDispatcherCollection.class,
|
|
353
|
-
beforeDispatcherCollection.funcName
|
|
354
|
-
) || {};
|
|
355
|
-
|
|
356
|
-
if (beforeDispatcherMetadata) {
|
|
357
|
-
for (const [_key, argsMetadata] of Object.entries(beforeDispatcherMetadata)) {
|
|
358
|
-
switch (argsMetadata.type) {
|
|
359
|
-
case EArgumentTypes.requestHeaders:
|
|
360
|
-
beforeDispatcherArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
361
|
-
? reqHeaders
|
|
362
|
-
: await argumentsResolution(
|
|
363
|
-
reqHeaders,
|
|
364
|
-
argsMetadata.zodSchema,
|
|
365
|
-
argsMetadata.index,
|
|
366
|
-
beforeDispatcherCollection.funcName
|
|
367
|
-
);
|
|
368
|
-
break;
|
|
369
|
-
case EArgumentTypes.body:
|
|
370
|
-
beforeDispatcherArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
371
|
-
? await request[argsMetadata.parser || "json"]()
|
|
372
|
-
: await argumentsResolution(
|
|
373
|
-
await request[argsMetadata.parser || "json"](),
|
|
374
|
-
argsMetadata.zodSchema,
|
|
375
|
-
argsMetadata.index,
|
|
376
|
-
beforeDispatcherCollection.funcName
|
|
377
|
-
);
|
|
378
|
-
break;
|
|
379
|
-
case EArgumentTypes.params:
|
|
380
|
-
beforeDispatcherArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
381
|
-
? params
|
|
382
|
-
: await argumentsResolution(
|
|
383
|
-
params,
|
|
384
|
-
argsMetadata.zodSchema,
|
|
385
|
-
argsMetadata.index,
|
|
386
|
-
beforeDispatcherCollection.funcName
|
|
387
|
-
);
|
|
388
|
-
break;
|
|
389
|
-
case EArgumentTypes.query:
|
|
390
|
-
beforeDispatcherArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
391
|
-
? query
|
|
392
|
-
: await argumentsResolution(
|
|
393
|
-
query,
|
|
394
|
-
argsMetadata.zodSchema,
|
|
395
|
-
argsMetadata.index,
|
|
396
|
-
beforeDispatcherCollection.funcName
|
|
397
|
-
);
|
|
398
|
-
break;
|
|
399
|
-
case EArgumentTypes.param:
|
|
400
|
-
beforeDispatcherArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
401
|
-
? !(argsMetadata.key in params)
|
|
402
|
-
? undefined
|
|
403
|
-
: params[argsMetadata.key]
|
|
404
|
-
: await argumentsResolution(
|
|
405
|
-
query,
|
|
406
|
-
argsMetadata.zodSchema,
|
|
407
|
-
argsMetadata.index,
|
|
408
|
-
beforeDispatcherCollection.funcName
|
|
409
|
-
);
|
|
410
|
-
break;
|
|
411
|
-
case EArgumentTypes.request:
|
|
412
|
-
beforeDispatcherArguments[argsMetadata.index] = request;
|
|
413
|
-
break;
|
|
414
|
-
case EArgumentTypes.responseHeaders:
|
|
415
|
-
beforeDispatcherArguments[argsMetadata.index] = resHeaders;
|
|
416
|
-
break;
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
await beforeDispatcherCollection.func(...beforeDispatcherArguments);
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
// Execute controller action
|
|
425
|
-
for (let i = 0; i < result.handlers.length; i++) {
|
|
426
|
-
const controllerActionArguments = [];
|
|
427
|
-
const handler = result.handlers[i];
|
|
428
|
-
const handlerMetadata: Record<string, TArgumentsMetadata> =
|
|
429
|
-
Reflect.getOwnMetadata(argumentsKey, handler.class, handler.funcName) || {};
|
|
430
|
-
|
|
431
|
-
if (handlerMetadata) {
|
|
432
|
-
for (const [_key, argsMetadata] of Object.entries(handlerMetadata)) {
|
|
433
|
-
switch (argsMetadata.type) {
|
|
434
|
-
case EArgumentTypes.requestHeaders:
|
|
435
|
-
controllerActionArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
436
|
-
? reqHeaders
|
|
437
|
-
: await argumentsResolution(
|
|
438
|
-
reqHeaders,
|
|
439
|
-
argsMetadata.zodSchema,
|
|
440
|
-
argsMetadata.index,
|
|
441
|
-
handler.funcName
|
|
442
|
-
);
|
|
443
|
-
break;
|
|
444
|
-
case EArgumentTypes.body:
|
|
445
|
-
controllerActionArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
446
|
-
? await request[argsMetadata.parser || "json"]()
|
|
447
|
-
: await argumentsResolution(
|
|
448
|
-
await request[argsMetadata.parser || "json"](),
|
|
449
|
-
argsMetadata.zodSchema,
|
|
450
|
-
argsMetadata.index,
|
|
451
|
-
handler.funcName
|
|
452
|
-
);
|
|
453
|
-
break;
|
|
454
|
-
case EArgumentTypes.params:
|
|
455
|
-
controllerActionArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
456
|
-
? params
|
|
457
|
-
: await argumentsResolution(
|
|
458
|
-
params,
|
|
459
|
-
argsMetadata.zodSchema,
|
|
460
|
-
argsMetadata.index,
|
|
461
|
-
handler.funcName
|
|
462
|
-
);
|
|
463
|
-
break;
|
|
464
|
-
case EArgumentTypes.query:
|
|
465
|
-
controllerActionArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
466
|
-
? query
|
|
467
|
-
: await argumentsResolution(
|
|
468
|
-
query,
|
|
469
|
-
argsMetadata.zodSchema,
|
|
470
|
-
argsMetadata.index,
|
|
471
|
-
handler.funcName
|
|
472
|
-
);
|
|
473
|
-
break;
|
|
474
|
-
case EArgumentTypes.param:
|
|
475
|
-
controllerActionArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
476
|
-
? !(argsMetadata.key in params)
|
|
477
|
-
? undefined
|
|
478
|
-
: params[argsMetadata.key]
|
|
479
|
-
: await argumentsResolution(
|
|
480
|
-
query,
|
|
481
|
-
argsMetadata.zodSchema,
|
|
482
|
-
argsMetadata.index,
|
|
483
|
-
handler.funcName
|
|
484
|
-
);
|
|
485
|
-
break;
|
|
486
|
-
case EArgumentTypes.request:
|
|
487
|
-
controllerActionArguments[argsMetadata.index] = request;
|
|
488
|
-
break;
|
|
489
|
-
case EArgumentTypes.responseHeaders:
|
|
490
|
-
controllerActionArguments[argsMetadata.index] = resHeaders;
|
|
491
|
-
break;
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
responseBody = await handler.func(...controllerActionArguments);
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
// Execute after dispatcher(s)
|
|
500
|
-
for (let i = 0; i < afterDispatcherGroup.length; i++) {
|
|
501
|
-
const afterDispatcherArguments = [];
|
|
502
|
-
const afterDispatcherCollection = afterDispatcherGroup[i];
|
|
503
|
-
const afterDispatcherMetadata: Record<string, TArgumentsMetadata> =
|
|
504
|
-
Reflect.getOwnMetadata(
|
|
505
|
-
argumentsKey,
|
|
506
|
-
afterDispatcherCollection.class,
|
|
507
|
-
afterDispatcherCollection.funcName
|
|
508
|
-
) || {};
|
|
509
|
-
|
|
510
|
-
if (afterDispatcherMetadata) {
|
|
511
|
-
for (const [_key, argsMetadata] of Object.entries(afterDispatcherMetadata)) {
|
|
512
|
-
switch (argsMetadata.type) {
|
|
513
|
-
case EArgumentTypes.requestHeaders:
|
|
514
|
-
afterDispatcherArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
515
|
-
? reqHeaders
|
|
516
|
-
: await argumentsResolution(
|
|
517
|
-
reqHeaders,
|
|
518
|
-
argsMetadata.zodSchema,
|
|
519
|
-
argsMetadata.index,
|
|
520
|
-
afterDispatcherCollection.funcName
|
|
521
|
-
);
|
|
522
|
-
break;
|
|
523
|
-
case EArgumentTypes.body:
|
|
524
|
-
afterDispatcherArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
525
|
-
? await request[argsMetadata.parser || "json"]()
|
|
526
|
-
: await argumentsResolution(
|
|
527
|
-
await request[argsMetadata.parser || "json"](),
|
|
528
|
-
argsMetadata.zodSchema,
|
|
529
|
-
argsMetadata.index,
|
|
530
|
-
afterDispatcherCollection.funcName
|
|
531
|
-
);
|
|
532
|
-
break;
|
|
533
|
-
case EArgumentTypes.params:
|
|
534
|
-
afterDispatcherArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
535
|
-
? params
|
|
536
|
-
: await argumentsResolution(
|
|
537
|
-
params,
|
|
538
|
-
argsMetadata.zodSchema,
|
|
539
|
-
argsMetadata.index,
|
|
540
|
-
afterDispatcherCollection.funcName
|
|
541
|
-
);
|
|
542
|
-
break;
|
|
543
|
-
case EArgumentTypes.query:
|
|
544
|
-
afterDispatcherArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
545
|
-
? query
|
|
546
|
-
: await argumentsResolution(
|
|
547
|
-
query,
|
|
548
|
-
argsMetadata.zodSchema,
|
|
549
|
-
argsMetadata.index,
|
|
550
|
-
afterDispatcherCollection.funcName
|
|
551
|
-
);
|
|
552
|
-
break;
|
|
553
|
-
case EArgumentTypes.param:
|
|
554
|
-
afterDispatcherArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
555
|
-
? !(argsMetadata.key in params)
|
|
556
|
-
? undefined
|
|
557
|
-
: params[argsMetadata.key]
|
|
558
|
-
: await argumentsResolution(
|
|
559
|
-
query,
|
|
560
|
-
argsMetadata.zodSchema,
|
|
561
|
-
argsMetadata.index,
|
|
562
|
-
afterDispatcherCollection.funcName
|
|
563
|
-
);
|
|
564
|
-
break;
|
|
565
|
-
case EArgumentTypes.request:
|
|
566
|
-
afterDispatcherArguments[argsMetadata.index] = request;
|
|
567
|
-
break;
|
|
568
|
-
case EArgumentTypes.responseHeaders:
|
|
569
|
-
afterDispatcherArguments[argsMetadata.index] = resHeaders;
|
|
570
|
-
break;
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
await afterDispatcherCollection.func(...afterDispatcherArguments);
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
return responseBody instanceof Response
|
|
579
|
-
? responseBody
|
|
580
|
-
: new Response(
|
|
581
|
-
!responseBody
|
|
582
|
-
? undefined
|
|
583
|
-
: JSON.stringify({
|
|
584
|
-
httpCode: 200,
|
|
585
|
-
message: "SUCCESS",
|
|
586
|
-
data: responseBody
|
|
587
|
-
}),
|
|
588
|
-
{
|
|
589
|
-
status: !responseBody ? 204 : 200,
|
|
590
|
-
statusText: "SUCCESS",
|
|
591
|
-
headers: resHeaders
|
|
592
|
-
}
|
|
593
|
-
);
|
|
594
|
-
} catch (error) {
|
|
595
|
-
return jsonErrorInfer(error, resHeaders);
|
|
596
|
-
} finally {
|
|
597
|
-
if (allowLogsMethods) {
|
|
598
|
-
const end = performance.now();
|
|
599
|
-
const convertedPID = `${process.pid}`.yellow;
|
|
600
|
-
const convertedMethod = `${request.method.yellow}`.bgBlue;
|
|
601
|
-
const convertedReqIp = `${
|
|
602
|
-
request.headers.get("x-forwarded-for") || request.headers.get("x-real-ip") || "<Unknown>"
|
|
603
|
-
}`.yellow;
|
|
604
|
-
const convertedTime = `${Math.round((end - start + Number.EPSILON) * 10 ** 2) / 10 ** 2}ms`.yellow;
|
|
605
|
-
|
|
606
|
-
allowLogsMethods.includes(request.method.toUpperCase() as (typeof allowLogsMethods)[number]) &&
|
|
607
|
-
console.info(
|
|
608
|
-
`PID: ${convertedPID} - Method: ${convertedMethod} - IP: ${convertedReqIp} - ${url.pathname.blue} - Time: ${convertedTime}`
|
|
609
|
-
);
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
});
|
|
614
|
-
};
|
|
615
|
-
|
|
616
|
-
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, prefix: modulePrefix } = 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 || ""}/${modulePrefix || ""}`)
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
const { allowLogsMethods } = Object.freeze({
|
|
185
|
+
allowLogsMethods: options?.log?.methods
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// After dispatcher(s)
|
|
189
|
+
const afterDispatcherGroup = !afterDispatchers
|
|
190
|
+
? []
|
|
191
|
+
: afterDispatchers.map((afterDispatcher) => {
|
|
192
|
+
const afterDispatcherInstance = Injector.get<IDispatcher>(afterDispatcher);
|
|
193
|
+
|
|
194
|
+
return Object.freeze({
|
|
195
|
+
class: afterDispatcher,
|
|
196
|
+
funcName: "execute",
|
|
197
|
+
func: afterDispatcherInstance.execute.bind(afterDispatcherInstance)
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
Bun.serve({
|
|
202
|
+
port: options.port,
|
|
203
|
+
fetch: async (request) => {
|
|
204
|
+
const start = performance.now();
|
|
205
|
+
const url = new URL(request.url);
|
|
206
|
+
const reqHeaders = request.headers;
|
|
207
|
+
const resHeaders = new Headers();
|
|
208
|
+
const query = Qs.parse(url.searchParams.toString(), options.queryParser);
|
|
209
|
+
|
|
210
|
+
try {
|
|
211
|
+
// Execute middleware(s)
|
|
212
|
+
for (let i = 0; i < middlewareGroup.length; i++) {
|
|
213
|
+
const middlewareArguments = [];
|
|
214
|
+
const middlewareCollection = middlewareGroup[i];
|
|
215
|
+
const middlewareMetadata: Record<string, TArgumentsMetadata> =
|
|
216
|
+
Reflect.getOwnMetadata(argumentsKey, middlewareCollection.class, middlewareCollection.funcName) || {};
|
|
217
|
+
|
|
218
|
+
if (middlewareMetadata) {
|
|
219
|
+
for (const [_key, argsMetadata] of Object.entries(middlewareMetadata)) {
|
|
220
|
+
switch (argsMetadata.type) {
|
|
221
|
+
case EArgumentTypes.requestHeaders:
|
|
222
|
+
middlewareArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
223
|
+
? reqHeaders
|
|
224
|
+
: await argumentsResolution(
|
|
225
|
+
reqHeaders,
|
|
226
|
+
argsMetadata.zodSchema,
|
|
227
|
+
argsMetadata.index,
|
|
228
|
+
middlewareCollection.funcName
|
|
229
|
+
);
|
|
230
|
+
break;
|
|
231
|
+
case EArgumentTypes.body:
|
|
232
|
+
middlewareArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
233
|
+
? await request[argsMetadata.parser || "json"]()
|
|
234
|
+
: await argumentsResolution(
|
|
235
|
+
await request[argsMetadata.parser || "json"](),
|
|
236
|
+
argsMetadata.zodSchema,
|
|
237
|
+
argsMetadata.index,
|
|
238
|
+
middlewareCollection.funcName
|
|
239
|
+
);
|
|
240
|
+
break;
|
|
241
|
+
case EArgumentTypes.query:
|
|
242
|
+
middlewareArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
243
|
+
? query
|
|
244
|
+
: await argumentsResolution(
|
|
245
|
+
query,
|
|
246
|
+
argsMetadata.zodSchema,
|
|
247
|
+
argsMetadata.index,
|
|
248
|
+
middlewareCollection.funcName
|
|
249
|
+
);
|
|
250
|
+
break;
|
|
251
|
+
case EArgumentTypes.request:
|
|
252
|
+
middlewareArguments[argsMetadata.index] = request;
|
|
253
|
+
break;
|
|
254
|
+
case EArgumentTypes.responseHeaders:
|
|
255
|
+
middlewareArguments[argsMetadata.index] = resHeaders;
|
|
256
|
+
break;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const middlewareResult = await middlewareCollection.func(...middlewareArguments);
|
|
262
|
+
|
|
263
|
+
if (!(middlewareResult instanceof Response)) {
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return middlewareResult;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Execute guard(s)
|
|
271
|
+
for (let i = 0; i < guardGroup.length; i++) {
|
|
272
|
+
const guardArguments = [];
|
|
273
|
+
const guardCollection = guardGroup[i];
|
|
274
|
+
const guardMetadata: Record<string, TArgumentsMetadata> =
|
|
275
|
+
Reflect.getOwnMetadata(argumentsKey, guardCollection.class, guardCollection.funcName) || {};
|
|
276
|
+
|
|
277
|
+
if (guardMetadata) {
|
|
278
|
+
for (const [_key, argsMetadata] of Object.entries(guardMetadata)) {
|
|
279
|
+
switch (argsMetadata.type) {
|
|
280
|
+
case EArgumentTypes.requestHeaders:
|
|
281
|
+
guardArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
282
|
+
? reqHeaders
|
|
283
|
+
: await argumentsResolution(
|
|
284
|
+
reqHeaders,
|
|
285
|
+
argsMetadata.zodSchema,
|
|
286
|
+
argsMetadata.index,
|
|
287
|
+
guardCollection.funcName
|
|
288
|
+
);
|
|
289
|
+
break;
|
|
290
|
+
case EArgumentTypes.body:
|
|
291
|
+
guardArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
292
|
+
? await request[argsMetadata.parser || "json"]()
|
|
293
|
+
: await argumentsResolution(
|
|
294
|
+
await request[argsMetadata.parser || "json"](),
|
|
295
|
+
argsMetadata.zodSchema,
|
|
296
|
+
argsMetadata.index,
|
|
297
|
+
guardCollection.funcName
|
|
298
|
+
);
|
|
299
|
+
break;
|
|
300
|
+
case EArgumentTypes.query:
|
|
301
|
+
guardArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
302
|
+
? query
|
|
303
|
+
: await argumentsResolution(
|
|
304
|
+
query,
|
|
305
|
+
argsMetadata.zodSchema,
|
|
306
|
+
argsMetadata.index,
|
|
307
|
+
guardCollection.funcName
|
|
308
|
+
);
|
|
309
|
+
break;
|
|
310
|
+
case EArgumentTypes.request:
|
|
311
|
+
guardArguments[argsMetadata.index] = request;
|
|
312
|
+
break;
|
|
313
|
+
case EArgumentTypes.responseHeaders:
|
|
314
|
+
guardArguments[argsMetadata.index] = resHeaders;
|
|
315
|
+
break;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
const guardResult = await guardCollection.func(...guardArguments);
|
|
321
|
+
|
|
322
|
+
if (typeof guardResult !== "boolean" || !guardResult) {
|
|
323
|
+
throw new HttpClientError({
|
|
324
|
+
httpCode: 401,
|
|
325
|
+
message: "Unauthorization.",
|
|
326
|
+
data: undefined
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
const result = routerGroup.find(url.pathname, request.method as keyof THttpMethods);
|
|
332
|
+
|
|
333
|
+
if (!result) {
|
|
334
|
+
throw new HttpClientError({
|
|
335
|
+
httpCode: 404,
|
|
336
|
+
message: "Route not found.",
|
|
337
|
+
data: undefined
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const params = result.params;
|
|
342
|
+
|
|
343
|
+
let responseBody = undefined;
|
|
344
|
+
|
|
345
|
+
// Execute before dispatcher(s)
|
|
346
|
+
for (let i = 0; i < beforeDispatcherGroup.length; i++) {
|
|
347
|
+
const beforeDispatcherArguments = [];
|
|
348
|
+
const beforeDispatcherCollection = beforeDispatcherGroup[i];
|
|
349
|
+
const beforeDispatcherMetadata: Record<string, TArgumentsMetadata> =
|
|
350
|
+
Reflect.getOwnMetadata(
|
|
351
|
+
argumentsKey,
|
|
352
|
+
beforeDispatcherCollection.class,
|
|
353
|
+
beforeDispatcherCollection.funcName
|
|
354
|
+
) || {};
|
|
355
|
+
|
|
356
|
+
if (beforeDispatcherMetadata) {
|
|
357
|
+
for (const [_key, argsMetadata] of Object.entries(beforeDispatcherMetadata)) {
|
|
358
|
+
switch (argsMetadata.type) {
|
|
359
|
+
case EArgumentTypes.requestHeaders:
|
|
360
|
+
beforeDispatcherArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
361
|
+
? reqHeaders
|
|
362
|
+
: await argumentsResolution(
|
|
363
|
+
reqHeaders,
|
|
364
|
+
argsMetadata.zodSchema,
|
|
365
|
+
argsMetadata.index,
|
|
366
|
+
beforeDispatcherCollection.funcName
|
|
367
|
+
);
|
|
368
|
+
break;
|
|
369
|
+
case EArgumentTypes.body:
|
|
370
|
+
beforeDispatcherArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
371
|
+
? await request[argsMetadata.parser || "json"]()
|
|
372
|
+
: await argumentsResolution(
|
|
373
|
+
await request[argsMetadata.parser || "json"](),
|
|
374
|
+
argsMetadata.zodSchema,
|
|
375
|
+
argsMetadata.index,
|
|
376
|
+
beforeDispatcherCollection.funcName
|
|
377
|
+
);
|
|
378
|
+
break;
|
|
379
|
+
case EArgumentTypes.params:
|
|
380
|
+
beforeDispatcherArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
381
|
+
? params
|
|
382
|
+
: await argumentsResolution(
|
|
383
|
+
params,
|
|
384
|
+
argsMetadata.zodSchema,
|
|
385
|
+
argsMetadata.index,
|
|
386
|
+
beforeDispatcherCollection.funcName
|
|
387
|
+
);
|
|
388
|
+
break;
|
|
389
|
+
case EArgumentTypes.query:
|
|
390
|
+
beforeDispatcherArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
391
|
+
? query
|
|
392
|
+
: await argumentsResolution(
|
|
393
|
+
query,
|
|
394
|
+
argsMetadata.zodSchema,
|
|
395
|
+
argsMetadata.index,
|
|
396
|
+
beforeDispatcherCollection.funcName
|
|
397
|
+
);
|
|
398
|
+
break;
|
|
399
|
+
case EArgumentTypes.param:
|
|
400
|
+
beforeDispatcherArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
401
|
+
? !(argsMetadata.key in params)
|
|
402
|
+
? undefined
|
|
403
|
+
: params[argsMetadata.key]
|
|
404
|
+
: await argumentsResolution(
|
|
405
|
+
query,
|
|
406
|
+
argsMetadata.zodSchema,
|
|
407
|
+
argsMetadata.index,
|
|
408
|
+
beforeDispatcherCollection.funcName
|
|
409
|
+
);
|
|
410
|
+
break;
|
|
411
|
+
case EArgumentTypes.request:
|
|
412
|
+
beforeDispatcherArguments[argsMetadata.index] = request;
|
|
413
|
+
break;
|
|
414
|
+
case EArgumentTypes.responseHeaders:
|
|
415
|
+
beforeDispatcherArguments[argsMetadata.index] = resHeaders;
|
|
416
|
+
break;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
await beforeDispatcherCollection.func(...beforeDispatcherArguments);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Execute controller action
|
|
425
|
+
for (let i = 0; i < result.handlers.length; i++) {
|
|
426
|
+
const controllerActionArguments = [];
|
|
427
|
+
const handler = result.handlers[i];
|
|
428
|
+
const handlerMetadata: Record<string, TArgumentsMetadata> =
|
|
429
|
+
Reflect.getOwnMetadata(argumentsKey, handler.class, handler.funcName) || {};
|
|
430
|
+
|
|
431
|
+
if (handlerMetadata) {
|
|
432
|
+
for (const [_key, argsMetadata] of Object.entries(handlerMetadata)) {
|
|
433
|
+
switch (argsMetadata.type) {
|
|
434
|
+
case EArgumentTypes.requestHeaders:
|
|
435
|
+
controllerActionArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
436
|
+
? reqHeaders
|
|
437
|
+
: await argumentsResolution(
|
|
438
|
+
reqHeaders,
|
|
439
|
+
argsMetadata.zodSchema,
|
|
440
|
+
argsMetadata.index,
|
|
441
|
+
handler.funcName
|
|
442
|
+
);
|
|
443
|
+
break;
|
|
444
|
+
case EArgumentTypes.body:
|
|
445
|
+
controllerActionArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
446
|
+
? await request[argsMetadata.parser || "json"]()
|
|
447
|
+
: await argumentsResolution(
|
|
448
|
+
await request[argsMetadata.parser || "json"](),
|
|
449
|
+
argsMetadata.zodSchema,
|
|
450
|
+
argsMetadata.index,
|
|
451
|
+
handler.funcName
|
|
452
|
+
);
|
|
453
|
+
break;
|
|
454
|
+
case EArgumentTypes.params:
|
|
455
|
+
controllerActionArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
456
|
+
? params
|
|
457
|
+
: await argumentsResolution(
|
|
458
|
+
params,
|
|
459
|
+
argsMetadata.zodSchema,
|
|
460
|
+
argsMetadata.index,
|
|
461
|
+
handler.funcName
|
|
462
|
+
);
|
|
463
|
+
break;
|
|
464
|
+
case EArgumentTypes.query:
|
|
465
|
+
controllerActionArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
466
|
+
? query
|
|
467
|
+
: await argumentsResolution(
|
|
468
|
+
query,
|
|
469
|
+
argsMetadata.zodSchema,
|
|
470
|
+
argsMetadata.index,
|
|
471
|
+
handler.funcName
|
|
472
|
+
);
|
|
473
|
+
break;
|
|
474
|
+
case EArgumentTypes.param:
|
|
475
|
+
controllerActionArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
476
|
+
? !(argsMetadata.key in params)
|
|
477
|
+
? undefined
|
|
478
|
+
: params[argsMetadata.key]
|
|
479
|
+
: await argumentsResolution(
|
|
480
|
+
query,
|
|
481
|
+
argsMetadata.zodSchema,
|
|
482
|
+
argsMetadata.index,
|
|
483
|
+
handler.funcName
|
|
484
|
+
);
|
|
485
|
+
break;
|
|
486
|
+
case EArgumentTypes.request:
|
|
487
|
+
controllerActionArguments[argsMetadata.index] = request;
|
|
488
|
+
break;
|
|
489
|
+
case EArgumentTypes.responseHeaders:
|
|
490
|
+
controllerActionArguments[argsMetadata.index] = resHeaders;
|
|
491
|
+
break;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
responseBody = await handler.func(...controllerActionArguments);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// Execute after dispatcher(s)
|
|
500
|
+
for (let i = 0; i < afterDispatcherGroup.length; i++) {
|
|
501
|
+
const afterDispatcherArguments = [];
|
|
502
|
+
const afterDispatcherCollection = afterDispatcherGroup[i];
|
|
503
|
+
const afterDispatcherMetadata: Record<string, TArgumentsMetadata> =
|
|
504
|
+
Reflect.getOwnMetadata(
|
|
505
|
+
argumentsKey,
|
|
506
|
+
afterDispatcherCollection.class,
|
|
507
|
+
afterDispatcherCollection.funcName
|
|
508
|
+
) || {};
|
|
509
|
+
|
|
510
|
+
if (afterDispatcherMetadata) {
|
|
511
|
+
for (const [_key, argsMetadata] of Object.entries(afterDispatcherMetadata)) {
|
|
512
|
+
switch (argsMetadata.type) {
|
|
513
|
+
case EArgumentTypes.requestHeaders:
|
|
514
|
+
afterDispatcherArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
515
|
+
? reqHeaders
|
|
516
|
+
: await argumentsResolution(
|
|
517
|
+
reqHeaders,
|
|
518
|
+
argsMetadata.zodSchema,
|
|
519
|
+
argsMetadata.index,
|
|
520
|
+
afterDispatcherCollection.funcName
|
|
521
|
+
);
|
|
522
|
+
break;
|
|
523
|
+
case EArgumentTypes.body:
|
|
524
|
+
afterDispatcherArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
525
|
+
? await request[argsMetadata.parser || "json"]()
|
|
526
|
+
: await argumentsResolution(
|
|
527
|
+
await request[argsMetadata.parser || "json"](),
|
|
528
|
+
argsMetadata.zodSchema,
|
|
529
|
+
argsMetadata.index,
|
|
530
|
+
afterDispatcherCollection.funcName
|
|
531
|
+
);
|
|
532
|
+
break;
|
|
533
|
+
case EArgumentTypes.params:
|
|
534
|
+
afterDispatcherArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
535
|
+
? params
|
|
536
|
+
: await argumentsResolution(
|
|
537
|
+
params,
|
|
538
|
+
argsMetadata.zodSchema,
|
|
539
|
+
argsMetadata.index,
|
|
540
|
+
afterDispatcherCollection.funcName
|
|
541
|
+
);
|
|
542
|
+
break;
|
|
543
|
+
case EArgumentTypes.query:
|
|
544
|
+
afterDispatcherArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
545
|
+
? query
|
|
546
|
+
: await argumentsResolution(
|
|
547
|
+
query,
|
|
548
|
+
argsMetadata.zodSchema,
|
|
549
|
+
argsMetadata.index,
|
|
550
|
+
afterDispatcherCollection.funcName
|
|
551
|
+
);
|
|
552
|
+
break;
|
|
553
|
+
case EArgumentTypes.param:
|
|
554
|
+
afterDispatcherArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
555
|
+
? !(argsMetadata.key in params)
|
|
556
|
+
? undefined
|
|
557
|
+
: params[argsMetadata.key]
|
|
558
|
+
: await argumentsResolution(
|
|
559
|
+
query,
|
|
560
|
+
argsMetadata.zodSchema,
|
|
561
|
+
argsMetadata.index,
|
|
562
|
+
afterDispatcherCollection.funcName
|
|
563
|
+
);
|
|
564
|
+
break;
|
|
565
|
+
case EArgumentTypes.request:
|
|
566
|
+
afterDispatcherArguments[argsMetadata.index] = request;
|
|
567
|
+
break;
|
|
568
|
+
case EArgumentTypes.responseHeaders:
|
|
569
|
+
afterDispatcherArguments[argsMetadata.index] = resHeaders;
|
|
570
|
+
break;
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
await afterDispatcherCollection.func(...afterDispatcherArguments);
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
return responseBody instanceof Response
|
|
579
|
+
? responseBody
|
|
580
|
+
: new Response(
|
|
581
|
+
!responseBody
|
|
582
|
+
? undefined
|
|
583
|
+
: JSON.stringify({
|
|
584
|
+
httpCode: 200,
|
|
585
|
+
message: "SUCCESS",
|
|
586
|
+
data: responseBody
|
|
587
|
+
}),
|
|
588
|
+
{
|
|
589
|
+
status: !responseBody ? 204 : 200,
|
|
590
|
+
statusText: "SUCCESS",
|
|
591
|
+
headers: resHeaders
|
|
592
|
+
}
|
|
593
|
+
);
|
|
594
|
+
} catch (error) {
|
|
595
|
+
return jsonErrorInfer(error, resHeaders);
|
|
596
|
+
} finally {
|
|
597
|
+
if (allowLogsMethods) {
|
|
598
|
+
const end = performance.now();
|
|
599
|
+
const convertedPID = `${process.pid}`.yellow;
|
|
600
|
+
const convertedMethod = `${request.method.yellow}`.bgBlue;
|
|
601
|
+
const convertedReqIp = `${
|
|
602
|
+
request.headers.get("x-forwarded-for") || request.headers.get("x-real-ip") || "<Unknown>"
|
|
603
|
+
}`.yellow;
|
|
604
|
+
const convertedTime = `${Math.round((end - start + Number.EPSILON) * 10 ** 2) / 10 ** 2}ms`.yellow;
|
|
605
|
+
|
|
606
|
+
allowLogsMethods.includes(request.method.toUpperCase() as (typeof allowLogsMethods)[number]) &&
|
|
607
|
+
console.info(
|
|
608
|
+
`PID: ${convertedPID} - Method: ${convertedMethod} - IP: ${convertedReqIp} - ${url.pathname.blue} - Time: ${convertedTime}`
|
|
609
|
+
);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
});
|
|
614
|
+
};
|
|
615
|
+
|
|
616
|
+
export default BoolFactory;
|