@nestia/core 3.14.1 → 3.15.0-dev.20240926
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/lib/decorators/EncryptedRoute.d.ts +19 -0
- package/lib/decorators/EncryptedRoute.js +28 -6
- package/lib/decorators/EncryptedRoute.js.map +1 -1
- package/lib/decorators/TypedRoute.d.ts +46 -0
- package/lib/decorators/TypedRoute.js +27 -2
- package/lib/decorators/TypedRoute.js.map +1 -1
- package/lib/decorators/internal/get_path_and_stringify.js +20 -7
- package/lib/decorators/internal/get_path_and_stringify.js.map +1 -1
- package/lib/options/INestiaTransformOptions.d.ts +1 -1
- package/lib/options/IResponseBodyStringifier.d.ts +5 -1
- package/lib/programmers/TypedRouteProgrammer.js +5 -0
- package/lib/programmers/TypedRouteProgrammer.js.map +1 -1
- package/package.json +3 -3
- package/src/decorators/EncryptedRoute.ts +43 -7
- package/src/decorators/TypedRoute.ts +71 -6
- package/src/decorators/internal/get_path_and_stringify.ts +37 -7
- package/src/options/INestiaTransformOptions.ts +8 -1
- package/src/options/IResponseBodyStringifier.ts +6 -1
- package/src/programmers/TypedRouteProgrammer.ts +13 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { IResponseBodyStringifier } from "../options/IResponseBodyStringifier";
|
|
2
|
+
import { TypedRoute } from "./TypedRoute";
|
|
2
3
|
/**
|
|
3
4
|
* Encrypted router decorator functions.
|
|
4
5
|
*
|
|
@@ -75,4 +76,22 @@ export declare namespace EncryptedRoute {
|
|
|
75
76
|
<T>(stringify?: IResponseBodyStringifier<T> | null): MethodDecorator;
|
|
76
77
|
<T>(path: string | string[], stringify?: IResponseBodyStringifier<T> | null): MethodDecorator;
|
|
77
78
|
};
|
|
79
|
+
/**
|
|
80
|
+
* Set the logger function for the response validation failure.
|
|
81
|
+
*
|
|
82
|
+
* If you've configured the transformation option to `validate.log`
|
|
83
|
+
* in the `tsconfig.json` file, then the error log information of the
|
|
84
|
+
* response validation failure would be logged through this function
|
|
85
|
+
* instead of throwing the 400 bad request error.
|
|
86
|
+
*
|
|
87
|
+
* By the way, be careful. If you've configured the response
|
|
88
|
+
* transformation option to be `validate.log` or `validateEquals.log`,
|
|
89
|
+
* client may get wrong response data. Therefore, this way is not
|
|
90
|
+
* recommended in the common backend server case.
|
|
91
|
+
*
|
|
92
|
+
* @param func Logger function
|
|
93
|
+
* @default console.log
|
|
94
|
+
*/
|
|
95
|
+
function setValidateErrorLogger(func: (err: IValidateErrorLog) => void): void;
|
|
96
|
+
export import IValidateErrorLog = TypedRoute.IValidateErrorLog;
|
|
78
97
|
}
|
|
@@ -9,6 +9,7 @@ const common_1 = require("@nestjs/common");
|
|
|
9
9
|
const operators_1 = require("rxjs/operators");
|
|
10
10
|
const typia_1 = __importDefault(require("typia"));
|
|
11
11
|
const Singleton_1 = require("../utils/Singleton");
|
|
12
|
+
const TypedRoute_1 = require("./TypedRoute");
|
|
12
13
|
const EncryptedConstant_1 = require("./internal/EncryptedConstant");
|
|
13
14
|
const get_path_and_stringify_1 = require("./internal/get_path_and_stringify");
|
|
14
15
|
const headers_to_object_1 = require("./internal/headers_to_object");
|
|
@@ -70,9 +71,32 @@ var EncryptedRoute;
|
|
|
70
71
|
* @returns Method decorator
|
|
71
72
|
*/
|
|
72
73
|
EncryptedRoute.Delete = Generator("Delete");
|
|
74
|
+
/**
|
|
75
|
+
* Set the logger function for the response validation failure.
|
|
76
|
+
*
|
|
77
|
+
* If you've configured the transformation option to `validate.log`
|
|
78
|
+
* in the `tsconfig.json` file, then the error log information of the
|
|
79
|
+
* response validation failure would be logged through this function
|
|
80
|
+
* instead of throwing the 400 bad request error.
|
|
81
|
+
*
|
|
82
|
+
* By the way, be careful. If you've configured the response
|
|
83
|
+
* transformation option to be `validate.log` or `validateEquals.log`,
|
|
84
|
+
* client may get wrong response data. Therefore, this way is not
|
|
85
|
+
* recommended in the common backend server case.
|
|
86
|
+
*
|
|
87
|
+
* @param func Logger function
|
|
88
|
+
* @default console.log
|
|
89
|
+
*/
|
|
90
|
+
function setValidateErrorLogger(func) {
|
|
91
|
+
TypedRoute_1.TypedRoute.setValidateErrorLogger(func);
|
|
92
|
+
}
|
|
93
|
+
EncryptedRoute.setValidateErrorLogger = setValidateErrorLogger;
|
|
94
|
+
/**
|
|
95
|
+
* @internal
|
|
96
|
+
*/
|
|
73
97
|
function Generator(method) {
|
|
74
98
|
function route(...args) {
|
|
75
|
-
const [path, stringify] = (0, get_path_and_stringify_1.get_path_and_stringify)(`EncryptedRoute.${method}`)(...args);
|
|
99
|
+
const [path, stringify] = (0, get_path_and_stringify_1.get_path_and_stringify)(TypedRoute_1.TypedRoute.__logger)(`EncryptedRoute.${method}`)(...args);
|
|
76
100
|
return (0, common_1.applyDecorators)(ROUTERS[method](path), (0, common_1.UseInterceptors)(new EncryptedRouteInterceptor(method, stringify)));
|
|
77
101
|
}
|
|
78
102
|
return route;
|
|
@@ -107,11 +131,9 @@ class EncryptedRouteInterceptor {
|
|
|
107
131
|
const param = Reflect.getMetadata(EncryptedConstant_1.ENCRYPTION_METADATA_KEY, context.getClass());
|
|
108
132
|
if (!param)
|
|
109
133
|
return Error(`Error on EncryptedRoute.${this.method}(): no password found.`);
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
});
|
|
114
|
-
const body = this.stringify(value);
|
|
134
|
+
const request = http.getRequest();
|
|
135
|
+
const headers = new Singleton_1.Singleton(() => (0, headers_to_object_1.headers_to_object)(request.headers));
|
|
136
|
+
const body = this.stringify(value, request.method, request.url);
|
|
115
137
|
const password = typeof param === "function"
|
|
116
138
|
? param({
|
|
117
139
|
headers: headers.get(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EncryptedRoute.js","sourceRoot":"","sources":["../../src/decorators/EncryptedRoute.ts"],"names":[],"mappings":";;;;;;AAAA,2DAAwD;AAExD,2CAWwB;AAGxB,8CAAiD;AACjD,kDAA0B;AAG1B,kDAA+C;AAC/C,oEAAuE;AACvE,8EAA2E;AAC3E,oEAAiE;AACjE,wDAAqD;AAErD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,IAAiB,cAAc,
|
|
1
|
+
{"version":3,"file":"EncryptedRoute.js","sourceRoot":"","sources":["../../src/decorators/EncryptedRoute.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { IValidation } from "typia";
|
|
1
2
|
import { IResponseBodyStringifier } from "../options/IResponseBodyStringifier";
|
|
2
3
|
/**
|
|
3
4
|
* Type safe router decorator functions.
|
|
@@ -70,4 +71,49 @@ export declare namespace TypedRoute {
|
|
|
70
71
|
<T>(stringify?: IResponseBodyStringifier<T>): MethodDecorator;
|
|
71
72
|
<T>(path: string | string[], stringify?: IResponseBodyStringifier<T>): MethodDecorator;
|
|
72
73
|
};
|
|
74
|
+
/**
|
|
75
|
+
* Set the logger function for the response validation failure.
|
|
76
|
+
*
|
|
77
|
+
* If you've configured the transformation option to `validate.log`
|
|
78
|
+
* in the `tsconfig.json` file, then the error log information of the
|
|
79
|
+
* response validation failure would be logged through this function
|
|
80
|
+
* instead of throwing the 400 bad request error.
|
|
81
|
+
*
|
|
82
|
+
* By the way, be careful. If you've configured the response
|
|
83
|
+
* transformation option to be `validate.log` or `validateEquals.log`,
|
|
84
|
+
* client may get wrong response data. Therefore, this way is not
|
|
85
|
+
* recommendedin the common backend server case.
|
|
86
|
+
*
|
|
87
|
+
* @param func Logger function
|
|
88
|
+
* @default console.log
|
|
89
|
+
*/
|
|
90
|
+
function setValidateErrorLogger(func: (err: IValidateErrorLog) => void): void;
|
|
91
|
+
/**
|
|
92
|
+
* Error log information of the response validation failure.
|
|
93
|
+
*
|
|
94
|
+
* `IValidationErrorLog` is a structure representing the error log
|
|
95
|
+
* information when the returned value from the `@TypedRoute` or
|
|
96
|
+
* `@EncryptedRoute` decorated controller method is not following
|
|
97
|
+
* the promised type `T`.
|
|
98
|
+
*
|
|
99
|
+
* If you've configured the transformation option to `validate.log` or
|
|
100
|
+
* `validateEquals.log` in the `tsconfig.json` file, then this error log
|
|
101
|
+
* information `IValidateErrorLog` would be logged through the
|
|
102
|
+
* {@link setValidateErrorLogger} function instead of throwing the
|
|
103
|
+
* 400 bad request error.
|
|
104
|
+
*/
|
|
105
|
+
interface IValidateErrorLog {
|
|
106
|
+
/**
|
|
107
|
+
* HTTP method of the request.
|
|
108
|
+
*/
|
|
109
|
+
method: string;
|
|
110
|
+
/**
|
|
111
|
+
* HTTP path of the request.
|
|
112
|
+
*/
|
|
113
|
+
path: string;
|
|
114
|
+
/**
|
|
115
|
+
* Validation error information with detailed reasons.
|
|
116
|
+
*/
|
|
117
|
+
error: IValidation.IFailure;
|
|
118
|
+
}
|
|
73
119
|
}
|
|
@@ -61,12 +61,36 @@ var TypedRoute;
|
|
|
61
61
|
* @returns Method decorator
|
|
62
62
|
*/
|
|
63
63
|
TypedRoute.Delete = Generator("Delete");
|
|
64
|
+
/**
|
|
65
|
+
* Set the logger function for the response validation failure.
|
|
66
|
+
*
|
|
67
|
+
* If you've configured the transformation option to `validate.log`
|
|
68
|
+
* in the `tsconfig.json` file, then the error log information of the
|
|
69
|
+
* response validation failure would be logged through this function
|
|
70
|
+
* instead of throwing the 400 bad request error.
|
|
71
|
+
*
|
|
72
|
+
* By the way, be careful. If you've configured the response
|
|
73
|
+
* transformation option to be `validate.log` or `validateEquals.log`,
|
|
74
|
+
* client may get wrong response data. Therefore, this way is not
|
|
75
|
+
* recommendedin the common backend server case.
|
|
76
|
+
*
|
|
77
|
+
* @param func Logger function
|
|
78
|
+
* @default console.log
|
|
79
|
+
*/
|
|
80
|
+
function setValidateErrorLogger(func) {
|
|
81
|
+
TypedRoute.__logger = func;
|
|
82
|
+
}
|
|
83
|
+
TypedRoute.setValidateErrorLogger = setValidateErrorLogger;
|
|
84
|
+
/**
|
|
85
|
+
* @internal
|
|
86
|
+
*/
|
|
87
|
+
TypedRoute.__logger = console.log;
|
|
64
88
|
/**
|
|
65
89
|
* @internal
|
|
66
90
|
*/
|
|
67
91
|
function Generator(method) {
|
|
68
92
|
function route(...args) {
|
|
69
|
-
const [path, stringify] = (0, get_path_and_stringify_1.get_path_and_stringify)(`TypedRoute.${method}`)(...args);
|
|
93
|
+
const [path, stringify] = (0, get_path_and_stringify_1.get_path_and_stringify)(TypedRoute.__logger)(`TypedRoute.${method}`)(...args);
|
|
70
94
|
return (0, common_1.applyDecorators)(ROUTERS[method](path), (0, common_1.UseInterceptors)(new TypedRouteInterceptor(stringify)));
|
|
71
95
|
}
|
|
72
96
|
return route;
|
|
@@ -96,9 +120,10 @@ class TypedRouteInterceptor {
|
|
|
96
120
|
}
|
|
97
121
|
intercept(context, next) {
|
|
98
122
|
const http = context.switchToHttp();
|
|
123
|
+
const request = http.getRequest();
|
|
99
124
|
const response = http.getResponse();
|
|
100
125
|
response.header("Content-Type", "application/json");
|
|
101
|
-
return next.handle().pipe((0, operators_1.map)((value) => this.stringify(value)), (0, operators_1.catchError)((err) => (0, route_error_1.route_error)(http.getRequest(), err)));
|
|
126
|
+
return next.handle().pipe((0, operators_1.map)((value) => this.stringify(value, request.method, request.url)), (0, operators_1.catchError)((err) => (0, route_error_1.route_error)(http.getRequest(), err)));
|
|
102
127
|
}
|
|
103
128
|
}
|
|
104
129
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TypedRoute.js","sourceRoot":"","sources":["../../src/decorators/TypedRoute.ts"],"names":[],"mappings":";;;;;;AAAA,2CAWwB;AAGxB,8CAAiD;AACjD,
|
|
1
|
+
{"version":3,"file":"TypedRoute.js","sourceRoot":"","sources":["../../src/decorators/TypedRoute.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,26 +10,26 @@ const NoTransformConfigurationError_1 = require("../NoTransformConfigurationErro
|
|
|
10
10
|
/**
|
|
11
11
|
* @internal
|
|
12
12
|
*/
|
|
13
|
-
const get_path_and_stringify = (method) => (...args) => {
|
|
13
|
+
const get_path_and_stringify = (logger) => (method) => (...args) => {
|
|
14
14
|
const path = args[0] === undefined ||
|
|
15
15
|
typeof args[0] === "string" ||
|
|
16
16
|
Array.isArray(args[0])
|
|
17
17
|
? args[0]
|
|
18
18
|
: null;
|
|
19
19
|
const functor = path === null ? args[0] : args[1];
|
|
20
|
-
return [path !== null && path !== void 0 ? path : undefined, take(method)(functor)];
|
|
20
|
+
return [path !== null && path !== void 0 ? path : undefined, take(logger)(method)(functor)];
|
|
21
21
|
};
|
|
22
22
|
exports.get_path_and_stringify = get_path_and_stringify;
|
|
23
23
|
/**
|
|
24
24
|
* @internal
|
|
25
25
|
*/
|
|
26
|
-
const take = (method) => (functor) => {
|
|
26
|
+
const take = (logger) => (method) => (functor) => {
|
|
27
27
|
if (functor === undefined) {
|
|
28
28
|
(0, NoTransformConfigurationError_1.NoTransformConfigurationError)(method);
|
|
29
|
-
return JSON.stringify;
|
|
29
|
+
return (input, _method, _path) => JSON.stringify(input);
|
|
30
30
|
}
|
|
31
31
|
else if (functor === null)
|
|
32
|
-
return JSON.stringify;
|
|
32
|
+
return (input, _method, _path) => JSON.stringify(input);
|
|
33
33
|
else if (functor.type === "stringify")
|
|
34
34
|
return functor.stringify;
|
|
35
35
|
else if (functor.type === "assert")
|
|
@@ -38,6 +38,9 @@ const take = (method) => (functor) => {
|
|
|
38
38
|
return is(functor.is);
|
|
39
39
|
else if (functor.type === "validate")
|
|
40
40
|
return validate(functor.validate);
|
|
41
|
+
else if (functor.type === "validate.log" ||
|
|
42
|
+
functor.type === "validateEquals.log")
|
|
43
|
+
return validateLog(functor.validate)(logger);
|
|
41
44
|
throw new Error(`Error on nestia.core.${method}(): invalid typed stringify function.`);
|
|
42
45
|
};
|
|
43
46
|
/**
|
|
@@ -62,7 +65,7 @@ const assert = (closure) => (data) => {
|
|
|
62
65
|
/**
|
|
63
66
|
* @internal
|
|
64
67
|
*/
|
|
65
|
-
const is = (closure) => (data) => {
|
|
68
|
+
const is = (closure) => (data, _method, _path) => {
|
|
66
69
|
const result = closure(data);
|
|
67
70
|
if (result === null)
|
|
68
71
|
throw new common_1.InternalServerErrorException(MESSAGE);
|
|
@@ -71,7 +74,7 @@ const is = (closure) => (data) => {
|
|
|
71
74
|
/**
|
|
72
75
|
* @internal
|
|
73
76
|
*/
|
|
74
|
-
const validate = (closure) => (data) => {
|
|
77
|
+
const validate = (closure) => (data, _method, _path) => {
|
|
75
78
|
const result = closure(data);
|
|
76
79
|
if (result.success === false)
|
|
77
80
|
throw new common_1.InternalServerErrorException({
|
|
@@ -80,6 +83,16 @@ const validate = (closure) => (data) => {
|
|
|
80
83
|
});
|
|
81
84
|
return result.data;
|
|
82
85
|
};
|
|
86
|
+
const validateLog = (closure) => (logger) => (data, method, path) => {
|
|
87
|
+
const result = closure(data);
|
|
88
|
+
if (result.success === false)
|
|
89
|
+
logger({
|
|
90
|
+
error: result,
|
|
91
|
+
method,
|
|
92
|
+
path,
|
|
93
|
+
});
|
|
94
|
+
return JSON.stringify(data);
|
|
95
|
+
};
|
|
83
96
|
/**
|
|
84
97
|
* @internal
|
|
85
98
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get_path_and_stringify.js","sourceRoot":"","sources":["../../../src/decorators/internal/get_path_and_stringify.ts"],"names":[],"mappings":";;;;;;AAAA,2CAA8D;AAC9D,kDAA2D;AAG3D,oFAAiF;
|
|
1
|
+
{"version":3,"file":"get_path_and_stringify.js","sourceRoot":"","sources":["../../../src/decorators/internal/get_path_and_stringify.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export interface INestiaTransformOptions {
|
|
2
2
|
validate?: "assert" | "is" | "validate" | "assertEquals" | "equals" | "validateEquals" | "assertClone" | "validateClone" | "assertPrune" | "validatePrune";
|
|
3
|
-
stringify?: "stringify" | "assert" | "is" | "validate" | null;
|
|
3
|
+
stringify?: "stringify" | "assert" | "is" | "validate" | "validate.log" | "validateEquals.log" | null;
|
|
4
4
|
throws?: boolean;
|
|
5
5
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IValidation } from "typia";
|
|
2
|
-
export type IResponseBodyStringifier<T> = IResponseBodyStringifier.IStringify<T> | IResponseBodyStringifier.IIs<T> | IResponseBodyStringifier.IAssert<T> | IResponseBodyStringifier.IValidate<T>;
|
|
2
|
+
export type IResponseBodyStringifier<T> = IResponseBodyStringifier.IStringify<T> | IResponseBodyStringifier.IIs<T> | IResponseBodyStringifier.IAssert<T> | IResponseBodyStringifier.IValidate<T> | IResponseBodyStringifier.IValidateLog<T>;
|
|
3
3
|
export declare namespace IResponseBodyStringifier {
|
|
4
4
|
interface IStringify<T> {
|
|
5
5
|
type: "stringify";
|
|
@@ -17,4 +17,8 @@ export declare namespace IResponseBodyStringifier {
|
|
|
17
17
|
type: "validate";
|
|
18
18
|
validate: (input: T) => IValidation<string>;
|
|
19
19
|
}
|
|
20
|
+
interface IValidateLog<T> {
|
|
21
|
+
type: "validate.log" | "validateEquals.log";
|
|
22
|
+
validate: (input: T) => IValidation<T>;
|
|
23
|
+
}
|
|
20
24
|
}
|
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.TypedRouteProgrammer = void 0;
|
|
7
7
|
const typescript_1 = __importDefault(require("typescript"));
|
|
8
|
+
const ValidateProgrammer_1 = require("typia/lib/programmers/ValidateProgrammer");
|
|
8
9
|
const JsonAssertStringifyProgrammer_1 = require("typia/lib/programmers/json/JsonAssertStringifyProgrammer");
|
|
9
10
|
const JsonIsStringifyProgrammer_1 = require("typia/lib/programmers/json/JsonIsStringifyProgrammer");
|
|
10
11
|
const JsonStringifyProgrammer_1 = require("typia/lib/programmers/json/JsonStringifyProgrammer");
|
|
@@ -24,6 +25,10 @@ var TypedRouteProgrammer;
|
|
|
24
25
|
return parameter("validate", JsonValidateStringifyProgrammer_1.JsonValidateStringifyProgrammer.write);
|
|
25
26
|
else if (project.options.stringify === "stringify")
|
|
26
27
|
return parameter("stringify", JsonStringifyProgrammer_1.JsonStringifyProgrammer.write);
|
|
28
|
+
else if (project.options.stringify === "validate.log")
|
|
29
|
+
return parameter("validate.log", (project) => (modulo) => ValidateProgrammer_1.ValidateProgrammer.write(project)(modulo)(false));
|
|
30
|
+
else if (project.options.stringify === "validateEquals.log")
|
|
31
|
+
return parameter("validateEquals.log", (project) => (modulo) => ValidateProgrammer_1.ValidateProgrammer.write(project)(modulo)(true));
|
|
27
32
|
else if (project.options.stringify === null)
|
|
28
33
|
return typescript_1.default.factory.createNull();
|
|
29
34
|
// ASSERT IS DEFAULT
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TypedRouteProgrammer.js","sourceRoot":"","sources":["../../src/programmers/TypedRouteProgrammer.ts"],"names":[],"mappings":";;;;;;AAAA,4DAA4B;AAC5B,4GAAyG;AACzG,oGAAiG;AACjG,gGAA6F;AAC7F,gHAA6G;AAK7G,IAAiB,oBAAoB,
|
|
1
|
+
{"version":3,"file":"TypedRouteProgrammer.js","sourceRoot":"","sources":["../../src/programmers/TypedRouteProgrammer.ts"],"names":[],"mappings":";;;;;;AAAA,4DAA4B;AAC5B,iFAA8E;AAC9E,4GAAyG;AACzG,oGAAiG;AACjG,gGAA6F;AAC7F,gHAA6G;AAK7G,IAAiB,oBAAoB,CAqDpC;AArDD,WAAiB,oBAAoB;IACtB,6BAAQ,GACnB,CAAC,OAAgC,EAAE,EAAE,CACrC,CAAC,MAAiC,EAAE,EAAE,CACtC,CAAC,IAAa,EAAiB,EAAE;QAC/B,0BAA0B;QAC1B,MAAM,SAAS,GAAG,CAChB,GAAW,EACX,UAIqC,EACrC,EAAE,CACF,oBAAE,CAAC,OAAO,CAAC,6BAA6B,CAAC;YACvC,oBAAE,CAAC,OAAO,CAAC,wBAAwB,CACjC,oBAAE,CAAC,OAAO,CAAC,gBAAgB,CAAC,MAAM,CAAC,EACnC,oBAAE,CAAC,OAAO,CAAC,mBAAmB,CAAC,GAAG,CAAC,CACpC;YACD,oBAAE,CAAC,OAAO,CAAC,wBAAwB,CACjC,oBAAE,CAAC,OAAO,CAAC,gBAAgB,CAAC,GAAG,CAAC,EAChC,UAAU,iCACL,OAAO,KACV,OAAO,EAAE,EAAE,IACX,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CACjB;SACF,CAAC,CAAC;QAEL,UAAU;QACV,IAAI,OAAO,CAAC,OAAO,CAAC,SAAS,KAAK,IAAI;YACpC,OAAO,SAAS,CAAC,IAAI,EAAE,qDAAyB,CAAC,KAAK,CAAC,CAAC;aACrD,IAAI,OAAO,CAAC,OAAO,CAAC,SAAS,KAAK,UAAU;YAC/C,OAAO,SAAS,CAAC,UAAU,EAAE,iEAA+B,CAAC,KAAK,CAAC,CAAC;aACjE,IAAI,OAAO,CAAC,OAAO,CAAC,SAAS,KAAK,WAAW;YAChD,OAAO,SAAS,CAAC,WAAW,EAAE,iDAAuB,CAAC,KAAK,CAAC,CAAC;aAC1D,IAAI,OAAO,CAAC,OAAO,CAAC,SAAS,KAAK,cAAc;YACnD,OAAO,SAAS,CACd,cAAc,EACd,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CACtB,uCAAkB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CACnD,CAAC;aACC,IAAI,OAAO,CAAC,OAAO,CAAC,SAAS,KAAK,oBAAoB;YACzD,OAAO,SAAS,CACd,oBAAoB,EACpB,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CACtB,uCAAkB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAClD,CAAC;aACC,IAAI,OAAO,CAAC,OAAO,CAAC,SAAS,KAAK,IAAI;YACzC,OAAO,oBAAE,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;QAEjC,oBAAoB;QACpB,OAAO,SAAS,CAAC,QAAQ,EAAE,6DAA6B,CAAC,KAAK,CAAC,CAAC;IAClE,CAAC,CAAC;AACN,CAAC,EArDgB,oBAAoB,oCAApB,oBAAoB,QAqDpC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nestia/core",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.15.0-dev.20240926",
|
|
4
4
|
"description": "Super-fast validation decorators of NestJS",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"typings": "lib/index.d.ts",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
},
|
|
37
37
|
"homepage": "https://nestia.io",
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@nestia/fetcher": "^3.
|
|
39
|
+
"@nestia/fetcher": "^3.15.0-dev.20240926",
|
|
40
40
|
"@nestjs/common": ">=7.0.1",
|
|
41
41
|
"@nestjs/core": ">=7.0.1",
|
|
42
42
|
"@samchon/openapi": "^1.0.2",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"ws": "^7.5.3"
|
|
54
54
|
},
|
|
55
55
|
"peerDependencies": {
|
|
56
|
-
"@nestia/fetcher": ">=3.
|
|
56
|
+
"@nestia/fetcher": ">=3.15.0-dev.20240926",
|
|
57
57
|
"@nestjs/common": ">=7.0.1",
|
|
58
58
|
"@nestjs/core": ">=7.0.1",
|
|
59
59
|
"reflect-metadata": ">=0.1.12",
|
|
@@ -19,6 +19,7 @@ import typia from "typia";
|
|
|
19
19
|
|
|
20
20
|
import { IResponseBodyStringifier } from "../options/IResponseBodyStringifier";
|
|
21
21
|
import { Singleton } from "../utils/Singleton";
|
|
22
|
+
import { TypedRoute } from "./TypedRoute";
|
|
22
23
|
import { ENCRYPTION_METADATA_KEY } from "./internal/EncryptedConstant";
|
|
23
24
|
import { get_path_and_stringify } from "./internal/get_path_and_stringify";
|
|
24
25
|
import { headers_to_object } from "./internal/headers_to_object";
|
|
@@ -85,6 +86,33 @@ export namespace EncryptedRoute {
|
|
|
85
86
|
*/
|
|
86
87
|
export const Delete = Generator("Delete");
|
|
87
88
|
|
|
89
|
+
/**
|
|
90
|
+
* Set the logger function for the response validation failure.
|
|
91
|
+
*
|
|
92
|
+
* If you've configured the transformation option to `validate.log`
|
|
93
|
+
* in the `tsconfig.json` file, then the error log information of the
|
|
94
|
+
* response validation failure would be logged through this function
|
|
95
|
+
* instead of throwing the 400 bad request error.
|
|
96
|
+
*
|
|
97
|
+
* By the way, be careful. If you've configured the response
|
|
98
|
+
* transformation option to be `validate.log` or `validateEquals.log`,
|
|
99
|
+
* client may get wrong response data. Therefore, this way is not
|
|
100
|
+
* recommended in the common backend server case.
|
|
101
|
+
*
|
|
102
|
+
* @param func Logger function
|
|
103
|
+
* @default console.log
|
|
104
|
+
*/
|
|
105
|
+
export function setValidateErrorLogger(
|
|
106
|
+
func: (err: IValidateErrorLog) => void,
|
|
107
|
+
): void {
|
|
108
|
+
TypedRoute.setValidateErrorLogger(func);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export import IValidateErrorLog = TypedRoute.IValidateErrorLog;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* @internal
|
|
115
|
+
*/
|
|
88
116
|
function Generator(method: "Get" | "Post" | "Put" | "Patch" | "Delete") {
|
|
89
117
|
function route(path?: string | string[]): MethodDecorator;
|
|
90
118
|
function route<T>(
|
|
@@ -96,7 +124,7 @@ export namespace EncryptedRoute {
|
|
|
96
124
|
): MethodDecorator;
|
|
97
125
|
|
|
98
126
|
function route(...args: any[]): MethodDecorator {
|
|
99
|
-
const [path, stringify] = get_path_and_stringify(
|
|
127
|
+
const [path, stringify] = get_path_and_stringify(TypedRoute.__logger)(
|
|
100
128
|
`EncryptedRoute.${method}`,
|
|
101
129
|
)(...args);
|
|
102
130
|
return applyDecorators(
|
|
@@ -130,7 +158,11 @@ for (const method of [
|
|
|
130
158
|
class EncryptedRouteInterceptor implements NestInterceptor {
|
|
131
159
|
public constructor(
|
|
132
160
|
private readonly method: string,
|
|
133
|
-
private readonly stringify: (
|
|
161
|
+
private readonly stringify: (
|
|
162
|
+
input: any,
|
|
163
|
+
method: string,
|
|
164
|
+
path: string,
|
|
165
|
+
) => string,
|
|
134
166
|
) {}
|
|
135
167
|
|
|
136
168
|
public intercept(context: ExecutionContext, next: CallHandler) {
|
|
@@ -149,11 +181,15 @@ class EncryptedRouteInterceptor implements NestInterceptor {
|
|
|
149
181
|
`Error on EncryptedRoute.${this.method}(): no password found.`,
|
|
150
182
|
);
|
|
151
183
|
|
|
152
|
-
const
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
const body: string | undefined = this.stringify(
|
|
184
|
+
const request: express.Request = http.getRequest();
|
|
185
|
+
const headers: Singleton<Record<string, string>> = new Singleton(() =>
|
|
186
|
+
headers_to_object(request.headers),
|
|
187
|
+
);
|
|
188
|
+
const body: string | undefined = this.stringify(
|
|
189
|
+
value,
|
|
190
|
+
request.method,
|
|
191
|
+
request.url,
|
|
192
|
+
);
|
|
157
193
|
const password: IEncryptionPassword =
|
|
158
194
|
typeof param === "function"
|
|
159
195
|
? param({
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
import { HttpArgumentsHost } from "@nestjs/common/interfaces";
|
|
14
14
|
import type express from "express";
|
|
15
15
|
import { catchError, map } from "rxjs/operators";
|
|
16
|
-
import typia from "typia";
|
|
16
|
+
import typia, { IValidation } from "typia";
|
|
17
17
|
|
|
18
18
|
import { IResponseBodyStringifier } from "../options/IResponseBodyStringifier";
|
|
19
19
|
import { get_path_and_stringify } from "./internal/get_path_and_stringify";
|
|
@@ -75,6 +75,64 @@ export namespace TypedRoute {
|
|
|
75
75
|
*/
|
|
76
76
|
export const Delete = Generator("Delete");
|
|
77
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Set the logger function for the response validation failure.
|
|
80
|
+
*
|
|
81
|
+
* If you've configured the transformation option to `validate.log`
|
|
82
|
+
* in the `tsconfig.json` file, then the error log information of the
|
|
83
|
+
* response validation failure would be logged through this function
|
|
84
|
+
* instead of throwing the 400 bad request error.
|
|
85
|
+
*
|
|
86
|
+
* By the way, be careful. If you've configured the response
|
|
87
|
+
* transformation option to be `validate.log` or `validateEquals.log`,
|
|
88
|
+
* client may get wrong response data. Therefore, this way is not
|
|
89
|
+
* recommendedin the common backend server case.
|
|
90
|
+
*
|
|
91
|
+
* @param func Logger function
|
|
92
|
+
* @default console.log
|
|
93
|
+
*/
|
|
94
|
+
export function setValidateErrorLogger(
|
|
95
|
+
func: (err: IValidateErrorLog) => void,
|
|
96
|
+
): void {
|
|
97
|
+
__logger = func;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Error log information of the response validation failure.
|
|
102
|
+
*
|
|
103
|
+
* `IValidationErrorLog` is a structure representing the error log
|
|
104
|
+
* information when the returned value from the `@TypedRoute` or
|
|
105
|
+
* `@EncryptedRoute` decorated controller method is not following
|
|
106
|
+
* the promised type `T`.
|
|
107
|
+
*
|
|
108
|
+
* If you've configured the transformation option to `validate.log` or
|
|
109
|
+
* `validateEquals.log` in the `tsconfig.json` file, then this error log
|
|
110
|
+
* information `IValidateErrorLog` would be logged through the
|
|
111
|
+
* {@link setValidateErrorLogger} function instead of throwing the
|
|
112
|
+
* 400 bad request error.
|
|
113
|
+
*/
|
|
114
|
+
export interface IValidateErrorLog {
|
|
115
|
+
/**
|
|
116
|
+
* HTTP method of the request.
|
|
117
|
+
*/
|
|
118
|
+
method: string;
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* HTTP path of the request.
|
|
122
|
+
*/
|
|
123
|
+
path: string;
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Validation error information with detailed reasons.
|
|
127
|
+
*/
|
|
128
|
+
error: IValidation.IFailure;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* @internal
|
|
133
|
+
*/
|
|
134
|
+
export let __logger: (log: IValidateErrorLog) => void = console.log;
|
|
135
|
+
|
|
78
136
|
/**
|
|
79
137
|
* @internal
|
|
80
138
|
*/
|
|
@@ -87,9 +145,9 @@ export namespace TypedRoute {
|
|
|
87
145
|
): MethodDecorator;
|
|
88
146
|
|
|
89
147
|
function route(...args: any[]): MethodDecorator {
|
|
90
|
-
const [path, stringify] = get_path_and_stringify(
|
|
91
|
-
|
|
92
|
-
);
|
|
148
|
+
const [path, stringify] = get_path_and_stringify(__logger)(
|
|
149
|
+
`TypedRoute.${method}`,
|
|
150
|
+
)(...args);
|
|
93
151
|
return applyDecorators(
|
|
94
152
|
ROUTERS[method](path),
|
|
95
153
|
UseInterceptors(new TypedRouteInterceptor(stringify)),
|
|
@@ -118,15 +176,22 @@ for (const method of [
|
|
|
118
176
|
* @internal
|
|
119
177
|
*/
|
|
120
178
|
class TypedRouteInterceptor implements NestInterceptor {
|
|
121
|
-
public constructor(
|
|
179
|
+
public constructor(
|
|
180
|
+
private readonly stringify: (
|
|
181
|
+
input: any,
|
|
182
|
+
method: string,
|
|
183
|
+
path: string,
|
|
184
|
+
) => string,
|
|
185
|
+
) {}
|
|
122
186
|
|
|
123
187
|
public intercept(context: ExecutionContext, next: CallHandler) {
|
|
124
188
|
const http: HttpArgumentsHost = context.switchToHttp();
|
|
189
|
+
const request: express.Request = http.getRequest();
|
|
125
190
|
const response: express.Response = http.getResponse();
|
|
126
191
|
response.header("Content-Type", "application/json");
|
|
127
192
|
|
|
128
193
|
return next.handle().pipe(
|
|
129
|
-
map((value) => this.stringify(value)),
|
|
194
|
+
map((value) => this.stringify(value, request.method, request.url)),
|
|
130
195
|
catchError((err) => route_error(http.getRequest(), err)),
|
|
131
196
|
);
|
|
132
197
|
}
|
|
@@ -3,13 +3,20 @@ import typia, { IValidation, TypeGuardError } from "typia";
|
|
|
3
3
|
|
|
4
4
|
import { IResponseBodyStringifier } from "../../options/IResponseBodyStringifier";
|
|
5
5
|
import { NoTransformConfigurationError } from "../NoTransformConfigurationError";
|
|
6
|
+
import { TypedRoute } from "../TypedRoute";
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* @internal
|
|
9
10
|
*/
|
|
10
11
|
export const get_path_and_stringify =
|
|
12
|
+
(logger: (log: TypedRoute.IValidateErrorLog) => void) =>
|
|
11
13
|
(method: string) =>
|
|
12
|
-
(
|
|
14
|
+
(
|
|
15
|
+
...args: any[]
|
|
16
|
+
): [
|
|
17
|
+
string | string[] | undefined,
|
|
18
|
+
(input: any, _method: string, _path: string) => string,
|
|
19
|
+
] => {
|
|
13
20
|
const path: string | string[] | null | undefined =
|
|
14
21
|
args[0] === undefined ||
|
|
15
22
|
typeof args[0] === "string" ||
|
|
@@ -18,23 +25,32 @@ export const get_path_and_stringify =
|
|
|
18
25
|
: null;
|
|
19
26
|
const functor: IResponseBodyStringifier<any> | undefined =
|
|
20
27
|
path === null ? args[0] : args[1];
|
|
21
|
-
return [path ?? undefined, take(method)(functor)];
|
|
28
|
+
return [path ?? undefined, take(logger)(method)(functor)];
|
|
22
29
|
};
|
|
23
30
|
|
|
24
31
|
/**
|
|
25
32
|
* @internal
|
|
26
33
|
*/
|
|
27
34
|
const take =
|
|
35
|
+
(logger: (log: TypedRoute.IValidateErrorLog) => void) =>
|
|
28
36
|
(method: string) =>
|
|
29
37
|
<T>(functor?: IResponseBodyStringifier<T> | null) => {
|
|
30
38
|
if (functor === undefined) {
|
|
31
39
|
NoTransformConfigurationError(method);
|
|
32
|
-
return
|
|
33
|
-
|
|
40
|
+
return (input: T, _method: string, _path: string) =>
|
|
41
|
+
JSON.stringify(input);
|
|
42
|
+
} else if (functor === null)
|
|
43
|
+
return (input: T, _method: string, _path: string) =>
|
|
44
|
+
JSON.stringify(input);
|
|
34
45
|
else if (functor.type === "stringify") return functor.stringify;
|
|
35
46
|
else if (functor.type === "assert") return assert(functor.assert);
|
|
36
47
|
else if (functor.type === "is") return is(functor.is);
|
|
37
48
|
else if (functor.type === "validate") return validate(functor.validate);
|
|
49
|
+
else if (
|
|
50
|
+
functor.type === "validate.log" ||
|
|
51
|
+
functor.type === "validateEquals.log"
|
|
52
|
+
)
|
|
53
|
+
return validateLog(functor.validate)(logger);
|
|
38
54
|
throw new Error(
|
|
39
55
|
`Error on nestia.core.${method}(): invalid typed stringify function.`,
|
|
40
56
|
);
|
|
@@ -45,7 +61,7 @@ const take =
|
|
|
45
61
|
*/
|
|
46
62
|
const assert =
|
|
47
63
|
<T>(closure: (data: T) => string) =>
|
|
48
|
-
(data: T) => {
|
|
64
|
+
(data: T): string => {
|
|
49
65
|
try {
|
|
50
66
|
return closure(data);
|
|
51
67
|
} catch (exp) {
|
|
@@ -66,7 +82,7 @@ const assert =
|
|
|
66
82
|
*/
|
|
67
83
|
const is =
|
|
68
84
|
<T>(closure: (data: T) => string | null) =>
|
|
69
|
-
(data: T) => {
|
|
85
|
+
(data: T, _method: string, _path: string) => {
|
|
70
86
|
const result: string | null = closure(data);
|
|
71
87
|
if (result === null) throw new InternalServerErrorException(MESSAGE);
|
|
72
88
|
return result;
|
|
@@ -77,7 +93,7 @@ const is =
|
|
|
77
93
|
*/
|
|
78
94
|
const validate =
|
|
79
95
|
<T>(closure: (data: T) => IValidation<string>) =>
|
|
80
|
-
(data: T) => {
|
|
96
|
+
(data: T, _method: string, _path: string): string => {
|
|
81
97
|
const result: IValidation<string> = closure(data);
|
|
82
98
|
if (result.success === false)
|
|
83
99
|
throw new InternalServerErrorException({
|
|
@@ -87,6 +103,20 @@ const validate =
|
|
|
87
103
|
return result.data;
|
|
88
104
|
};
|
|
89
105
|
|
|
106
|
+
const validateLog =
|
|
107
|
+
<T>(closure: (data: T) => IValidation<any>) =>
|
|
108
|
+
(logger: (log: TypedRoute.IValidateErrorLog) => void) =>
|
|
109
|
+
(data: T, method: string, path: string): string => {
|
|
110
|
+
const result: IValidation<any> = closure(data);
|
|
111
|
+
if (result.success === false)
|
|
112
|
+
logger({
|
|
113
|
+
error: result,
|
|
114
|
+
method,
|
|
115
|
+
path,
|
|
116
|
+
});
|
|
117
|
+
return JSON.stringify(data);
|
|
118
|
+
};
|
|
119
|
+
|
|
90
120
|
/**
|
|
91
121
|
* @internal
|
|
92
122
|
*/
|
|
@@ -13,6 +13,13 @@ export interface INestiaTransformOptions {
|
|
|
13
13
|
// PRUNE
|
|
14
14
|
| "assertPrune"
|
|
15
15
|
| "validatePrune";
|
|
16
|
-
stringify?:
|
|
16
|
+
stringify?:
|
|
17
|
+
| "stringify"
|
|
18
|
+
| "assert"
|
|
19
|
+
| "is"
|
|
20
|
+
| "validate"
|
|
21
|
+
| "validate.log"
|
|
22
|
+
| "validateEquals.log"
|
|
23
|
+
| null;
|
|
17
24
|
throws?: boolean;
|
|
18
25
|
}
|
|
@@ -4,7 +4,8 @@ export type IResponseBodyStringifier<T> =
|
|
|
4
4
|
| IResponseBodyStringifier.IStringify<T>
|
|
5
5
|
| IResponseBodyStringifier.IIs<T>
|
|
6
6
|
| IResponseBodyStringifier.IAssert<T>
|
|
7
|
-
| IResponseBodyStringifier.IValidate<T
|
|
7
|
+
| IResponseBodyStringifier.IValidate<T>
|
|
8
|
+
| IResponseBodyStringifier.IValidateLog<T>;
|
|
8
9
|
export namespace IResponseBodyStringifier {
|
|
9
10
|
export interface IStringify<T> {
|
|
10
11
|
type: "stringify";
|
|
@@ -22,4 +23,8 @@ export namespace IResponseBodyStringifier {
|
|
|
22
23
|
type: "validate";
|
|
23
24
|
validate: (input: T) => IValidation<string>;
|
|
24
25
|
}
|
|
26
|
+
export interface IValidateLog<T> {
|
|
27
|
+
type: "validate.log" | "validateEquals.log";
|
|
28
|
+
validate: (input: T) => IValidation<T>;
|
|
29
|
+
}
|
|
25
30
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import ts from "typescript";
|
|
2
|
+
import { ValidateProgrammer } from "typia/lib/programmers/ValidateProgrammer";
|
|
2
3
|
import { JsonAssertStringifyProgrammer } from "typia/lib/programmers/json/JsonAssertStringifyProgrammer";
|
|
3
4
|
import { JsonIsStringifyProgrammer } from "typia/lib/programmers/json/JsonIsStringifyProgrammer";
|
|
4
5
|
import { JsonStringifyProgrammer } from "typia/lib/programmers/json/JsonStringifyProgrammer";
|
|
@@ -42,6 +43,18 @@ export namespace TypedRouteProgrammer {
|
|
|
42
43
|
return parameter("validate", JsonValidateStringifyProgrammer.write);
|
|
43
44
|
else if (project.options.stringify === "stringify")
|
|
44
45
|
return parameter("stringify", JsonStringifyProgrammer.write);
|
|
46
|
+
else if (project.options.stringify === "validate.log")
|
|
47
|
+
return parameter(
|
|
48
|
+
"validate.log",
|
|
49
|
+
(project) => (modulo) =>
|
|
50
|
+
ValidateProgrammer.write(project)(modulo)(false),
|
|
51
|
+
);
|
|
52
|
+
else if (project.options.stringify === "validateEquals.log")
|
|
53
|
+
return parameter(
|
|
54
|
+
"validateEquals.log",
|
|
55
|
+
(project) => (modulo) =>
|
|
56
|
+
ValidateProgrammer.write(project)(modulo)(true),
|
|
57
|
+
);
|
|
45
58
|
else if (project.options.stringify === null)
|
|
46
59
|
return ts.factory.createNull();
|
|
47
60
|
|