@bool-ts/core 1.2.4 → 1.3.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/__test/controller.ts +15 -7
- package/bun.lockb +0 -0
- package/dist/decorators/http.js +111 -0
- package/dist/decorators/index.d.ts +1 -0
- package/dist/decorators/index.js +4 -1
- package/dist/decorators/inject.d.ts +1 -1
- package/dist/decorators/inject.js +1 -1
- package/dist/decorators/zodSchema.d.ts +3 -0
- package/dist/decorators/zodSchema.js +24 -0
- package/dist/hooks/factory.js +15 -14
- package/package.json +3 -2
- package/src/decorators/http.ts +148 -0
- package/src/decorators/index.ts +1 -0
- package/src/decorators/inject.ts +1 -1
- package/src/decorators/zodSchema.ts +33 -0
- package/src/hooks/factory.ts +18 -17
package/__test/controller.ts
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
import type { IService } from "./interfaces";
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import * as Zod from "zod";
|
|
4
|
+
|
|
5
|
+
import { Controller, Delete, Get, Inject, Options, Patch, Post, Put, ZodSchema } from "../src";
|
|
4
6
|
import { TestService } from "./service";
|
|
5
7
|
import { Request, Response } from "express";
|
|
6
8
|
|
|
7
9
|
|
|
10
|
+
const getAbcSchema = Zod.object({
|
|
11
|
+
headers: Zod.object({
|
|
12
|
+
authorization: Zod.string().min(10)
|
|
13
|
+
})
|
|
14
|
+
});
|
|
15
|
+
|
|
8
16
|
@Controller("test")
|
|
9
17
|
export class TestController {
|
|
10
18
|
constructor(
|
|
@@ -13,7 +21,7 @@ export class TestController {
|
|
|
13
21
|
|
|
14
22
|
@Get("abc")
|
|
15
23
|
private _get(
|
|
16
|
-
req: Request,
|
|
24
|
+
@ZodSchema(getAbcSchema) req: Request,
|
|
17
25
|
res: Response
|
|
18
26
|
) {
|
|
19
27
|
console.log("this.testService", this.testService.exec())
|
|
@@ -22,7 +30,7 @@ export class TestController {
|
|
|
22
30
|
|
|
23
31
|
@Post("abc")
|
|
24
32
|
private _post(
|
|
25
|
-
req: Request,
|
|
33
|
+
@ZodSchema(getAbcSchema) req: Request,
|
|
26
34
|
res: Response
|
|
27
35
|
) {
|
|
28
36
|
console.log("req.body", req.body);
|
|
@@ -31,7 +39,7 @@ export class TestController {
|
|
|
31
39
|
|
|
32
40
|
@Put()
|
|
33
41
|
private _put(
|
|
34
|
-
req: Request,
|
|
42
|
+
@ZodSchema(getAbcSchema) req: Request,
|
|
35
43
|
res: Response
|
|
36
44
|
) {
|
|
37
45
|
res.json({ test: "success" }).send();
|
|
@@ -39,7 +47,7 @@ export class TestController {
|
|
|
39
47
|
|
|
40
48
|
@Patch("abc/:id")
|
|
41
49
|
private _patch(
|
|
42
|
-
req: Request,
|
|
50
|
+
@ZodSchema(getAbcSchema) req: Request,
|
|
43
51
|
res: Response
|
|
44
52
|
) {
|
|
45
53
|
console.log(req.params)
|
|
@@ -48,7 +56,7 @@ export class TestController {
|
|
|
48
56
|
|
|
49
57
|
@Delete()
|
|
50
58
|
private _delete(
|
|
51
|
-
req: Request,
|
|
59
|
+
@ZodSchema(getAbcSchema) req: Request,
|
|
52
60
|
res: Response
|
|
53
61
|
) {
|
|
54
62
|
res.json({ test: "success" }).send();
|
|
@@ -56,7 +64,7 @@ export class TestController {
|
|
|
56
64
|
|
|
57
65
|
@Options()
|
|
58
66
|
private _options(
|
|
59
|
-
req: Request,
|
|
67
|
+
@ZodSchema(getAbcSchema) req: Request,
|
|
60
68
|
res: Response
|
|
61
69
|
) {
|
|
62
70
|
res.json({ test: "success" }).send();
|
package/bun.lockb
CHANGED
|
Binary file
|
package/dist/decorators/http.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Options = exports.Delete = exports.Patch = exports.Put = exports.Post = exports.Get = exports.controllerRoutesKey = void 0;
|
|
4
|
+
const http_1 = require("../http");
|
|
5
|
+
const zodSchema_1 = require("./zodSchema");
|
|
4
6
|
exports.controllerRoutesKey = "__bool:controller.routes__";
|
|
5
7
|
/**
|
|
6
8
|
*
|
|
@@ -11,6 +13,7 @@ const Get = (path = "/") => (target, methodName, descriptor) => {
|
|
|
11
13
|
if (typeof descriptor.value !== "function") {
|
|
12
14
|
throw Error("Get decorator only use for method.");
|
|
13
15
|
}
|
|
16
|
+
// Define controller metadata
|
|
14
17
|
Reflect.defineMetadata(exports.controllerRoutesKey, [
|
|
15
18
|
...Reflect.getOwnMetadata(exports.controllerRoutesKey, target.constructor) || [],
|
|
16
19
|
{
|
|
@@ -20,6 +23,24 @@ const Get = (path = "/") => (target, methodName, descriptor) => {
|
|
|
20
23
|
descriptor: descriptor
|
|
21
24
|
}
|
|
22
25
|
], target.constructor);
|
|
26
|
+
// Define route parameters zod validation
|
|
27
|
+
const currentMethod = descriptor.value;
|
|
28
|
+
descriptor.value = function () {
|
|
29
|
+
const zodSchemaMetadata = Reflect.getOwnMetadata(zodSchema_1.controllerRouteZodSchemaKey, target.constructor, methodName);
|
|
30
|
+
if (zodSchemaMetadata) {
|
|
31
|
+
for (const zodSchemaProp in zodSchemaMetadata) {
|
|
32
|
+
const tmpZodMetadata = zodSchemaMetadata[zodSchemaProp];
|
|
33
|
+
const validation = tmpZodMetadata.schema.safeParse(arguments[tmpZodMetadata.index]);
|
|
34
|
+
if (!validation.success) {
|
|
35
|
+
throw new http_1.HttpClientError({
|
|
36
|
+
httpCode: 400,
|
|
37
|
+
data: validation.error.issues
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return currentMethod.apply(this, arguments);
|
|
43
|
+
};
|
|
23
44
|
};
|
|
24
45
|
exports.Get = Get;
|
|
25
46
|
/**
|
|
@@ -40,6 +61,24 @@ const Post = (path = "/") => (target, methodName, descriptor) => {
|
|
|
40
61
|
descriptor: descriptor
|
|
41
62
|
}
|
|
42
63
|
], target.constructor);
|
|
64
|
+
// Define route parameters zod validation
|
|
65
|
+
const currentMethod = descriptor.value;
|
|
66
|
+
descriptor.value = function () {
|
|
67
|
+
const zodSchemaMetadata = Reflect.getOwnMetadata(zodSchema_1.controllerRouteZodSchemaKey, target.constructor, methodName);
|
|
68
|
+
if (zodSchemaMetadata) {
|
|
69
|
+
for (const zodSchemaProp in zodSchemaMetadata) {
|
|
70
|
+
const tmpZodMetadata = zodSchemaMetadata[zodSchemaProp];
|
|
71
|
+
const validation = tmpZodMetadata.schema.safeParse(arguments[tmpZodMetadata.index]);
|
|
72
|
+
if (!validation.success) {
|
|
73
|
+
throw new http_1.HttpClientError({
|
|
74
|
+
httpCode: 400,
|
|
75
|
+
data: validation.error.issues
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return currentMethod.apply(this, arguments);
|
|
81
|
+
};
|
|
43
82
|
};
|
|
44
83
|
exports.Post = Post;
|
|
45
84
|
/**
|
|
@@ -60,6 +99,24 @@ const Put = (path = "/") => (target, methodName, descriptor) => {
|
|
|
60
99
|
descriptor: descriptor
|
|
61
100
|
}
|
|
62
101
|
], target.constructor);
|
|
102
|
+
// Define route parameters zod validation
|
|
103
|
+
const currentMethod = descriptor.value;
|
|
104
|
+
descriptor.value = function () {
|
|
105
|
+
const zodSchemaMetadata = Reflect.getOwnMetadata(zodSchema_1.controllerRouteZodSchemaKey, target.constructor, methodName);
|
|
106
|
+
if (zodSchemaMetadata) {
|
|
107
|
+
for (const zodSchemaProp in zodSchemaMetadata) {
|
|
108
|
+
const tmpZodMetadata = zodSchemaMetadata[zodSchemaProp];
|
|
109
|
+
const validation = tmpZodMetadata.schema.safeParse(arguments[tmpZodMetadata.index]);
|
|
110
|
+
if (!validation.success) {
|
|
111
|
+
throw new http_1.HttpClientError({
|
|
112
|
+
httpCode: 400,
|
|
113
|
+
data: validation.error.issues
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return currentMethod.apply(this, arguments);
|
|
119
|
+
};
|
|
63
120
|
};
|
|
64
121
|
exports.Put = Put;
|
|
65
122
|
/**
|
|
@@ -80,6 +137,24 @@ const Patch = (path = "/") => (target, methodName, descriptor) => {
|
|
|
80
137
|
descriptor: descriptor
|
|
81
138
|
}
|
|
82
139
|
], target.constructor);
|
|
140
|
+
// Define route parameters zod validation
|
|
141
|
+
const currentMethod = descriptor.value;
|
|
142
|
+
descriptor.value = function () {
|
|
143
|
+
const zodSchemaMetadata = Reflect.getOwnMetadata(zodSchema_1.controllerRouteZodSchemaKey, target.constructor, methodName);
|
|
144
|
+
if (zodSchemaMetadata) {
|
|
145
|
+
for (const zodSchemaProp in zodSchemaMetadata) {
|
|
146
|
+
const tmpZodMetadata = zodSchemaMetadata[zodSchemaProp];
|
|
147
|
+
const validation = tmpZodMetadata.schema.safeParse(arguments[tmpZodMetadata.index]);
|
|
148
|
+
if (!validation.success) {
|
|
149
|
+
throw new http_1.HttpClientError({
|
|
150
|
+
httpCode: 400,
|
|
151
|
+
data: validation.error.issues
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return currentMethod.apply(this, arguments);
|
|
157
|
+
};
|
|
83
158
|
};
|
|
84
159
|
exports.Patch = Patch;
|
|
85
160
|
/**
|
|
@@ -100,6 +175,24 @@ const Delete = (path = "/") => (target, methodName, descriptor) => {
|
|
|
100
175
|
descriptor: descriptor
|
|
101
176
|
}
|
|
102
177
|
], target.constructor);
|
|
178
|
+
// Define route parameters zod validation
|
|
179
|
+
const currentMethod = descriptor.value;
|
|
180
|
+
descriptor.value = function () {
|
|
181
|
+
const zodSchemaMetadata = Reflect.getOwnMetadata(zodSchema_1.controllerRouteZodSchemaKey, target.constructor, methodName);
|
|
182
|
+
if (zodSchemaMetadata) {
|
|
183
|
+
for (const zodSchemaProp in zodSchemaMetadata) {
|
|
184
|
+
const tmpZodMetadata = zodSchemaMetadata[zodSchemaProp];
|
|
185
|
+
const validation = tmpZodMetadata.schema.safeParse(arguments[tmpZodMetadata.index]);
|
|
186
|
+
if (!validation.success) {
|
|
187
|
+
throw new http_1.HttpClientError({
|
|
188
|
+
httpCode: 400,
|
|
189
|
+
data: validation.error.issues
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return currentMethod.apply(this, arguments);
|
|
195
|
+
};
|
|
103
196
|
};
|
|
104
197
|
exports.Delete = Delete;
|
|
105
198
|
/**
|
|
@@ -120,6 +213,24 @@ const Options = (path = "/") => (target, methodName, descriptor) => {
|
|
|
120
213
|
descriptor: descriptor
|
|
121
214
|
}
|
|
122
215
|
], target.constructor);
|
|
216
|
+
// Define route parameters zod validation
|
|
217
|
+
const currentMethod = descriptor.value;
|
|
218
|
+
descriptor.value = function () {
|
|
219
|
+
const zodSchemaMetadata = Reflect.getOwnMetadata(zodSchema_1.controllerRouteZodSchemaKey, target.constructor, methodName);
|
|
220
|
+
if (zodSchemaMetadata) {
|
|
221
|
+
for (const zodSchemaProp in zodSchemaMetadata) {
|
|
222
|
+
const tmpZodMetadata = zodSchemaMetadata[zodSchemaProp];
|
|
223
|
+
const validation = tmpZodMetadata.schema.safeParse(arguments[tmpZodMetadata.index]);
|
|
224
|
+
if (!validation.success) {
|
|
225
|
+
throw new http_1.HttpClientError({
|
|
226
|
+
httpCode: 400,
|
|
227
|
+
data: validation.error.issues
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return currentMethod.apply(this, arguments);
|
|
233
|
+
};
|
|
123
234
|
};
|
|
124
235
|
exports.Options = Options;
|
|
125
236
|
exports.default = {
|
|
@@ -3,3 +3,4 @@ export { Inject, injectKey } from "./inject";
|
|
|
3
3
|
export { Injectable, injectableKey } from "./injectable";
|
|
4
4
|
export { Module, moduleKey, type TModuleOptions } from "./module";
|
|
5
5
|
export { Get, Post, Put, Patch, Delete, Options, controllerRoutesKey, type IControllerRoute } from "./http";
|
|
6
|
+
export { ZodSchema, controllerRouteZodSchemaKey } from "./zodSchema";
|
package/dist/decorators/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.controllerRoutesKey = exports.Options = exports.Delete = exports.Patch = exports.Put = exports.Post = exports.Get = exports.moduleKey = exports.Module = exports.injectableKey = exports.Injectable = exports.injectKey = exports.Inject = exports.controllerKey = exports.Controller = void 0;
|
|
3
|
+
exports.controllerRouteZodSchemaKey = exports.ZodSchema = exports.controllerRoutesKey = exports.Options = exports.Delete = exports.Patch = exports.Put = exports.Post = exports.Get = exports.moduleKey = exports.Module = exports.injectableKey = exports.Injectable = exports.injectKey = exports.Inject = exports.controllerKey = exports.Controller = void 0;
|
|
4
4
|
var controller_1 = require("./controller");
|
|
5
5
|
Object.defineProperty(exports, "Controller", { enumerable: true, get: function () { return controller_1.Controller; } });
|
|
6
6
|
Object.defineProperty(exports, "controllerKey", { enumerable: true, get: function () { return controller_1.controllerKey; } });
|
|
@@ -21,3 +21,6 @@ Object.defineProperty(exports, "Patch", { enumerable: true, get: function () { r
|
|
|
21
21
|
Object.defineProperty(exports, "Delete", { enumerable: true, get: function () { return http_1.Delete; } });
|
|
22
22
|
Object.defineProperty(exports, "Options", { enumerable: true, get: function () { return http_1.Options; } });
|
|
23
23
|
Object.defineProperty(exports, "controllerRoutesKey", { enumerable: true, get: function () { return http_1.controllerRoutesKey; } });
|
|
24
|
+
var zodSchema_1 = require("./zodSchema");
|
|
25
|
+
Object.defineProperty(exports, "ZodSchema", { enumerable: true, get: function () { return zodSchema_1.ZodSchema; } });
|
|
26
|
+
Object.defineProperty(exports, "controllerRouteZodSchemaKey", { enumerable: true, get: function () { return zodSchema_1.controllerRouteZodSchemaKey; } });
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare const injectKey = "design:paramtypes";
|
|
2
2
|
export declare const Inject: <T extends Object>(classDefinition: {
|
|
3
3
|
new (...args: any[]): T;
|
|
4
|
-
}) => (target: Object,
|
|
4
|
+
}) => (target: Object, methodName: string | symbol | undefined, parameterIndex: number) => void;
|
|
5
5
|
export default Inject;
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.Inject = exports.injectKey = void 0;
|
|
4
4
|
exports.injectKey = "design:paramtypes";
|
|
5
5
|
const Inject = (classDefinition) => {
|
|
6
|
-
return (target,
|
|
6
|
+
return (target, methodName, parameterIndex) => {
|
|
7
7
|
const designParameterTypes = Reflect.getMetadata(exports.injectKey, target) || [];
|
|
8
8
|
designParameterTypes[parameterIndex] = classDefinition;
|
|
9
9
|
Reflect.defineMetadata(exports.injectKey, designParameterTypes, target);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ZodSchema = exports.controllerRouteZodSchemaKey = void 0;
|
|
4
|
+
exports.controllerRouteZodSchemaKey = "__bool:controller.route.zodSchema__";
|
|
5
|
+
const ZodSchema = (schema) => {
|
|
6
|
+
try {
|
|
7
|
+
schema.safeParse(undefined);
|
|
8
|
+
}
|
|
9
|
+
catch (err) {
|
|
10
|
+
throw Error("Zod schema parameter do not allow async.");
|
|
11
|
+
}
|
|
12
|
+
return (target, methodName, parameterIndex) => {
|
|
13
|
+
if (!methodName) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const zodSchemasMetadata = Reflect.getOwnMetadata(exports.controllerRouteZodSchemaKey, target.constructor, methodName) || {};
|
|
17
|
+
zodSchemasMetadata[`paramterIndexes.${parameterIndex}`] = {
|
|
18
|
+
index: parameterIndex,
|
|
19
|
+
schema: schema
|
|
20
|
+
};
|
|
21
|
+
Reflect.defineMetadata(exports.controllerRouteZodSchemaKey, zodSchemasMetadata, target.constructor, methodName);
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
exports.ZodSchema = ZodSchema;
|
package/dist/hooks/factory.js
CHANGED
|
@@ -123,7 +123,19 @@ const BoolFactory = (target, options) => {
|
|
|
123
123
|
req.body = Object.freeze({});
|
|
124
124
|
}
|
|
125
125
|
next();
|
|
126
|
-
}
|
|
126
|
+
},
|
|
127
|
+
// Response time log
|
|
128
|
+
ResponseTime.default((req, res, time) => {
|
|
129
|
+
const requestMethod = req.method.toUpperCase();
|
|
130
|
+
if (!factoryOptions.allowLogsMethods.includes(requestMethod)) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const convertedMethod = `${requestMethod.yellow}`.bgBlue;
|
|
134
|
+
const convertedPID = `${process.pid}`.yellow;
|
|
135
|
+
const convertedReqIp = `${req.headers["x-forwarded-for"] || req.headers["x-real-ip"] || req.ip || "<Unknown>"}`.yellow;
|
|
136
|
+
const convertedTime = `${Math.round((time + Number.EPSILON) * 10 ** 2) / 10 ** 2}ms`.yellow;
|
|
137
|
+
console.info(`PID: ${convertedPID} - Method: ${convertedMethod} - IP: ${convertedReqIp} - ${req.originalUrl.blue} - Time: ${convertedTime}`);
|
|
138
|
+
}));
|
|
127
139
|
app.use((req, res, next) => {
|
|
128
140
|
if (!allowOrigins.includes("*")) {
|
|
129
141
|
if (!allowOrigins.includes(req.headers.origin || "*")) {
|
|
@@ -149,6 +161,7 @@ const BoolFactory = (target, options) => {
|
|
|
149
161
|
app.use(routers) : app.use(!metadata.prefix.startsWith("/") ?
|
|
150
162
|
`/${metadata.prefix}` : metadata.prefix, routers);
|
|
151
163
|
}
|
|
164
|
+
// Register error catcher
|
|
152
165
|
app.use(
|
|
153
166
|
// Error catcher
|
|
154
167
|
(err, req, res, next) => {
|
|
@@ -157,19 +170,7 @@ const BoolFactory = (target, options) => {
|
|
|
157
170
|
return;
|
|
158
171
|
}
|
|
159
172
|
console.error("Headers:", JSON.stringify(req.headers), "\nBody:", JSON.stringify(req.body), "\nError:", JSON.stringify(err));
|
|
160
|
-
}
|
|
161
|
-
// Response time log
|
|
162
|
-
ResponseTime.default((req, res, time) => {
|
|
163
|
-
const requestMethod = req.method.toUpperCase();
|
|
164
|
-
if (!factoryOptions.allowLogsMethods.includes(requestMethod)) {
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
|
-
const convertedMethod = `${requestMethod.yellow}`.bgBlue;
|
|
168
|
-
const convertedPID = `${process.pid}`.yellow;
|
|
169
|
-
const convertedReqIp = `${req.headers["x-forwarded-for"] || req.headers["x-real-ip"] || req.ip || "<Unknown>"}`.yellow;
|
|
170
|
-
const convertedTime = `${Math.round((time + Number.EPSILON) * 10 ** 2) / 10 ** 2}ms`.yellow;
|
|
171
|
-
console.info(`PID: ${convertedPID} - Method: ${convertedMethod} - IP: ${convertedReqIp} - ${req.originalUrl.blue} - Time: ${convertedTime}`);
|
|
172
|
-
}));
|
|
173
|
+
});
|
|
173
174
|
return app;
|
|
174
175
|
};
|
|
175
176
|
exports.BoolFactory = BoolFactory;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bool-ts/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
"express": "^5.0.0-beta.3",
|
|
23
23
|
"qs": "^6.12.1",
|
|
24
24
|
"reflect-metadata": "^0.2.2",
|
|
25
|
-
"response-time": "^2.3.2"
|
|
25
|
+
"response-time": "^2.3.2",
|
|
26
|
+
"zod": "^3.23.8"
|
|
26
27
|
},
|
|
27
28
|
"devDependencies": {
|
|
28
29
|
"@types/express": "^4.17.21",
|
package/src/decorators/http.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { HttpClientError } from "../http";
|
|
2
|
+
import { controllerRouteZodSchemaKey } from "./zodSchema";
|
|
3
|
+
|
|
1
4
|
export interface IControllerRoute {
|
|
2
5
|
path: string;
|
|
3
6
|
httpMethod: "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "OPTIONS";
|
|
@@ -24,6 +27,7 @@ export const Get = (
|
|
|
24
27
|
throw Error("Get decorator only use for method.");
|
|
25
28
|
}
|
|
26
29
|
|
|
30
|
+
// Define controller metadata
|
|
27
31
|
Reflect.defineMetadata(controllerRoutesKey, [
|
|
28
32
|
...Reflect.getOwnMetadata(controllerRoutesKey, target.constructor) || [],
|
|
29
33
|
{
|
|
@@ -33,6 +37,30 @@ export const Get = (
|
|
|
33
37
|
descriptor: descriptor
|
|
34
38
|
}
|
|
35
39
|
], target.constructor);
|
|
40
|
+
|
|
41
|
+
// Define route parameters zod validation
|
|
42
|
+
const currentMethod = descriptor.value;
|
|
43
|
+
|
|
44
|
+
descriptor.value = function () {
|
|
45
|
+
const zodSchemaMetadata = Reflect.getOwnMetadata(controllerRouteZodSchemaKey, target.constructor, methodName);
|
|
46
|
+
|
|
47
|
+
if (zodSchemaMetadata) {
|
|
48
|
+
for (const zodSchemaProp in zodSchemaMetadata) {
|
|
49
|
+
const tmpZodMetadata = zodSchemaMetadata[zodSchemaProp];
|
|
50
|
+
|
|
51
|
+
const validation = tmpZodMetadata.schema.safeParse(arguments[tmpZodMetadata.index]);
|
|
52
|
+
|
|
53
|
+
if (!validation.success) {
|
|
54
|
+
throw new HttpClientError({
|
|
55
|
+
httpCode: 400,
|
|
56
|
+
data: validation.error.issues
|
|
57
|
+
})
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return currentMethod.apply(this, arguments);
|
|
63
|
+
}
|
|
36
64
|
}
|
|
37
65
|
|
|
38
66
|
|
|
@@ -61,6 +89,30 @@ export const Post = (
|
|
|
61
89
|
descriptor: descriptor
|
|
62
90
|
}
|
|
63
91
|
], target.constructor);
|
|
92
|
+
|
|
93
|
+
// Define route parameters zod validation
|
|
94
|
+
const currentMethod = descriptor.value;
|
|
95
|
+
|
|
96
|
+
descriptor.value = function () {
|
|
97
|
+
const zodSchemaMetadata = Reflect.getOwnMetadata(controllerRouteZodSchemaKey, target.constructor, methodName);
|
|
98
|
+
|
|
99
|
+
if (zodSchemaMetadata) {
|
|
100
|
+
for (const zodSchemaProp in zodSchemaMetadata) {
|
|
101
|
+
const tmpZodMetadata = zodSchemaMetadata[zodSchemaProp];
|
|
102
|
+
|
|
103
|
+
const validation = tmpZodMetadata.schema.safeParse(arguments[tmpZodMetadata.index]);
|
|
104
|
+
|
|
105
|
+
if (!validation.success) {
|
|
106
|
+
throw new HttpClientError({
|
|
107
|
+
httpCode: 400,
|
|
108
|
+
data: validation.error.issues
|
|
109
|
+
})
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return currentMethod.apply(this, arguments);
|
|
115
|
+
}
|
|
64
116
|
}
|
|
65
117
|
|
|
66
118
|
|
|
@@ -89,6 +141,30 @@ export const Put = (
|
|
|
89
141
|
descriptor: descriptor
|
|
90
142
|
}
|
|
91
143
|
], target.constructor);
|
|
144
|
+
|
|
145
|
+
// Define route parameters zod validation
|
|
146
|
+
const currentMethod = descriptor.value;
|
|
147
|
+
|
|
148
|
+
descriptor.value = function () {
|
|
149
|
+
const zodSchemaMetadata = Reflect.getOwnMetadata(controllerRouteZodSchemaKey, target.constructor, methodName);
|
|
150
|
+
|
|
151
|
+
if (zodSchemaMetadata) {
|
|
152
|
+
for (const zodSchemaProp in zodSchemaMetadata) {
|
|
153
|
+
const tmpZodMetadata = zodSchemaMetadata[zodSchemaProp];
|
|
154
|
+
|
|
155
|
+
const validation = tmpZodMetadata.schema.safeParse(arguments[tmpZodMetadata.index]);
|
|
156
|
+
|
|
157
|
+
if (!validation.success) {
|
|
158
|
+
throw new HttpClientError({
|
|
159
|
+
httpCode: 400,
|
|
160
|
+
data: validation.error.issues
|
|
161
|
+
})
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return currentMethod.apply(this, arguments);
|
|
167
|
+
}
|
|
92
168
|
}
|
|
93
169
|
|
|
94
170
|
|
|
@@ -117,6 +193,30 @@ export const Patch = (
|
|
|
117
193
|
descriptor: descriptor
|
|
118
194
|
}
|
|
119
195
|
], target.constructor);
|
|
196
|
+
|
|
197
|
+
// Define route parameters zod validation
|
|
198
|
+
const currentMethod = descriptor.value;
|
|
199
|
+
|
|
200
|
+
descriptor.value = function () {
|
|
201
|
+
const zodSchemaMetadata = Reflect.getOwnMetadata(controllerRouteZodSchemaKey, target.constructor, methodName);
|
|
202
|
+
|
|
203
|
+
if (zodSchemaMetadata) {
|
|
204
|
+
for (const zodSchemaProp in zodSchemaMetadata) {
|
|
205
|
+
const tmpZodMetadata = zodSchemaMetadata[zodSchemaProp];
|
|
206
|
+
|
|
207
|
+
const validation = tmpZodMetadata.schema.safeParse(arguments[tmpZodMetadata.index]);
|
|
208
|
+
|
|
209
|
+
if (!validation.success) {
|
|
210
|
+
throw new HttpClientError({
|
|
211
|
+
httpCode: 400,
|
|
212
|
+
data: validation.error.issues
|
|
213
|
+
})
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return currentMethod.apply(this, arguments);
|
|
219
|
+
}
|
|
120
220
|
}
|
|
121
221
|
|
|
122
222
|
|
|
@@ -145,6 +245,30 @@ export const Delete = (
|
|
|
145
245
|
descriptor: descriptor
|
|
146
246
|
}
|
|
147
247
|
], target.constructor);
|
|
248
|
+
|
|
249
|
+
// Define route parameters zod validation
|
|
250
|
+
const currentMethod = descriptor.value;
|
|
251
|
+
|
|
252
|
+
descriptor.value = function () {
|
|
253
|
+
const zodSchemaMetadata = Reflect.getOwnMetadata(controllerRouteZodSchemaKey, target.constructor, methodName);
|
|
254
|
+
|
|
255
|
+
if (zodSchemaMetadata) {
|
|
256
|
+
for (const zodSchemaProp in zodSchemaMetadata) {
|
|
257
|
+
const tmpZodMetadata = zodSchemaMetadata[zodSchemaProp];
|
|
258
|
+
|
|
259
|
+
const validation = tmpZodMetadata.schema.safeParse(arguments[tmpZodMetadata.index]);
|
|
260
|
+
|
|
261
|
+
if (!validation.success) {
|
|
262
|
+
throw new HttpClientError({
|
|
263
|
+
httpCode: 400,
|
|
264
|
+
data: validation.error.issues
|
|
265
|
+
})
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return currentMethod.apply(this, arguments);
|
|
271
|
+
}
|
|
148
272
|
}
|
|
149
273
|
|
|
150
274
|
|
|
@@ -173,6 +297,30 @@ export const Options = (
|
|
|
173
297
|
descriptor: descriptor
|
|
174
298
|
}
|
|
175
299
|
], target.constructor);
|
|
300
|
+
|
|
301
|
+
// Define route parameters zod validation
|
|
302
|
+
const currentMethod = descriptor.value;
|
|
303
|
+
|
|
304
|
+
descriptor.value = function () {
|
|
305
|
+
const zodSchemaMetadata = Reflect.getOwnMetadata(controllerRouteZodSchemaKey, target.constructor, methodName);
|
|
306
|
+
|
|
307
|
+
if (zodSchemaMetadata) {
|
|
308
|
+
for (const zodSchemaProp in zodSchemaMetadata) {
|
|
309
|
+
const tmpZodMetadata = zodSchemaMetadata[zodSchemaProp];
|
|
310
|
+
|
|
311
|
+
const validation = tmpZodMetadata.schema.safeParse(arguments[tmpZodMetadata.index]);
|
|
312
|
+
|
|
313
|
+
if (!validation.success) {
|
|
314
|
+
throw new HttpClientError({
|
|
315
|
+
httpCode: 400,
|
|
316
|
+
data: validation.error.issues
|
|
317
|
+
})
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
return currentMethod.apply(this, arguments);
|
|
323
|
+
}
|
|
176
324
|
}
|
|
177
325
|
|
|
178
326
|
export default {
|
package/src/decorators/index.ts
CHANGED
|
@@ -3,3 +3,4 @@ export { Inject, injectKey } from "./inject";
|
|
|
3
3
|
export { Injectable, injectableKey } from "./injectable";
|
|
4
4
|
export { Module, moduleKey, type TModuleOptions } from "./module";
|
|
5
5
|
export { Get, Post, Put, Patch, Delete, Options, controllerRoutesKey, type IControllerRoute } from "./http";
|
|
6
|
+
export { ZodSchema, controllerRouteZodSchemaKey } from "./zodSchema";
|
package/src/decorators/inject.ts
CHANGED
|
@@ -5,7 +5,7 @@ export const Inject = <T extends Object>(
|
|
|
5
5
|
) => {
|
|
6
6
|
return (
|
|
7
7
|
target: Object,
|
|
8
|
-
|
|
8
|
+
methodName: string | symbol | undefined,
|
|
9
9
|
parameterIndex: number
|
|
10
10
|
) => {
|
|
11
11
|
const designParameterTypes: any[] = Reflect.getMetadata(injectKey, target) || [];
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import * as Zod from "zod";
|
|
2
|
+
|
|
3
|
+
export const controllerRouteZodSchemaKey = "__bool:controller.route.zodSchema__";
|
|
4
|
+
|
|
5
|
+
export const ZodSchema = (
|
|
6
|
+
schema: Zod.Schema
|
|
7
|
+
) => {
|
|
8
|
+
try {
|
|
9
|
+
schema.safeParse(undefined);
|
|
10
|
+
}
|
|
11
|
+
catch (err) {
|
|
12
|
+
throw Error("Zod schema parameter do not allow async.");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
target: Object,
|
|
17
|
+
methodName: string | symbol | undefined,
|
|
18
|
+
parameterIndex: number
|
|
19
|
+
) => {
|
|
20
|
+
if (!methodName) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const zodSchemasMetadata = Reflect.getOwnMetadata(controllerRouteZodSchemaKey, target.constructor, methodName) || {};
|
|
25
|
+
|
|
26
|
+
zodSchemasMetadata[`paramterIndexes.${parameterIndex}`] = {
|
|
27
|
+
index: parameterIndex,
|
|
28
|
+
schema: schema
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
Reflect.defineMetadata(controllerRouteZodSchemaKey, zodSchemasMetadata, target.constructor, methodName);
|
|
32
|
+
}
|
|
33
|
+
}
|
package/src/hooks/factory.ts
CHANGED
|
@@ -136,7 +136,22 @@ export const BoolFactory = (
|
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
next();
|
|
139
|
-
}
|
|
139
|
+
},
|
|
140
|
+
// Response time log
|
|
141
|
+
ResponseTime.default((req: Request, res: Response, time: number) => {
|
|
142
|
+
const requestMethod = req.method.toUpperCase();
|
|
143
|
+
|
|
144
|
+
if (!factoryOptions.allowLogsMethods.includes(requestMethod)) {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const convertedMethod = `${requestMethod.yellow}`.bgBlue;
|
|
149
|
+
const convertedPID = `${process.pid}`.yellow;
|
|
150
|
+
const convertedReqIp = `${req.headers["x-forwarded-for"] || req.headers["x-real-ip"] || req.ip || "<Unknown>"}`.yellow;
|
|
151
|
+
const convertedTime = `${Math.round((time + Number.EPSILON) * 10 ** 2) / 10 ** 2}ms`.yellow;
|
|
152
|
+
|
|
153
|
+
console.info(`PID: ${convertedPID} - Method: ${convertedMethod} - IP: ${convertedReqIp} - ${req.originalUrl.blue} - Time: ${convertedTime}`);
|
|
154
|
+
})
|
|
140
155
|
);
|
|
141
156
|
|
|
142
157
|
app.use((req: Request, res: Response, next: NextFunction) => {
|
|
@@ -168,6 +183,7 @@ export const BoolFactory = (
|
|
|
168
183
|
`/${metadata.prefix}` : metadata.prefix, routers);
|
|
169
184
|
}
|
|
170
185
|
|
|
186
|
+
// Register error catcher
|
|
171
187
|
app.use(
|
|
172
188
|
// Error catcher
|
|
173
189
|
(err: Errback, req: Request, res: Response, next: NextFunction) => {
|
|
@@ -178,22 +194,7 @@ export const BoolFactory = (
|
|
|
178
194
|
}
|
|
179
195
|
|
|
180
196
|
console.error("Headers:", JSON.stringify(req.headers), "\nBody:", JSON.stringify(req.body), "\nError:", JSON.stringify(err));
|
|
181
|
-
}
|
|
182
|
-
// Response time log
|
|
183
|
-
ResponseTime.default((req: Request, res: Response, time: number) => {
|
|
184
|
-
const requestMethod = req.method.toUpperCase();
|
|
185
|
-
|
|
186
|
-
if (!factoryOptions.allowLogsMethods.includes(requestMethod)) {
|
|
187
|
-
return;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
const convertedMethod = `${requestMethod.yellow}`.bgBlue;
|
|
191
|
-
const convertedPID = `${process.pid}`.yellow;
|
|
192
|
-
const convertedReqIp = `${req.headers["x-forwarded-for"] || req.headers["x-real-ip"] || req.ip || "<Unknown>"}`.yellow;
|
|
193
|
-
const convertedTime = `${Math.round((time + Number.EPSILON) * 10 ** 2) / 10 ** 2}ms`.yellow;
|
|
194
|
-
|
|
195
|
-
console.info(`PID: ${convertedPID} - Method: ${convertedMethod} - IP: ${convertedReqIp} - ${req.originalUrl.blue} - Time: ${convertedTime}`);
|
|
196
|
-
})
|
|
197
|
+
}
|
|
197
198
|
);
|
|
198
199
|
|
|
199
200
|
return app;
|