@nestia/core 14.0.0 → 14.0.2
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/MIGRATION.md +20 -0
- package/README.md +1 -1
- package/lib/adaptors/McpAdaptor.d.ts +29 -3
- package/lib/adaptors/McpAdaptor.js +150 -24
- package/lib/adaptors/McpAdaptor.js.map +1 -1
- package/lib/adaptors/WebSocketAdaptor.d.ts +37 -0
- package/lib/adaptors/WebSocketAdaptor.js +184 -48
- package/lib/adaptors/WebSocketAdaptor.js.map +1 -1
- package/lib/adaptors/internal/RoutePathMatcher.d.ts +1 -0
- package/lib/adaptors/internal/RoutePathMatcher.js +88 -0
- package/lib/adaptors/internal/RoutePathMatcher.js.map +1 -0
- package/lib/adaptors/internal/external_context.d.ts +1 -0
- package/lib/adaptors/internal/external_context.js +56 -0
- package/lib/adaptors/internal/external_context.js.map +1 -0
- package/lib/decorators/DynamicModule.d.ts +12 -0
- package/lib/decorators/DynamicModule.js +12 -0
- package/lib/decorators/DynamicModule.js.map +1 -1
- package/lib/decorators/EncryptedBody.d.ts +14 -6
- package/lib/decorators/EncryptedBody.js +39 -16
- package/lib/decorators/EncryptedBody.js.map +1 -1
- package/lib/decorators/EncryptedController.d.ts +6 -1
- package/lib/decorators/EncryptedController.js +7 -2
- package/lib/decorators/EncryptedController.js.map +1 -1
- package/lib/decorators/EncryptedModule.d.ts +25 -6
- package/lib/decorators/EncryptedModule.js +87 -18
- package/lib/decorators/EncryptedModule.js.map +1 -1
- package/lib/decorators/EncryptedRoute.d.ts +20 -11
- package/lib/decorators/EncryptedRoute.js +27 -13
- package/lib/decorators/EncryptedRoute.js.map +1 -1
- package/lib/decorators/HumanRoute.d.ts +5 -0
- package/lib/decorators/HumanRoute.js +5 -0
- package/lib/decorators/HumanRoute.js.map +1 -1
- package/lib/decorators/McpRoute.d.ts +31 -19
- package/lib/decorators/McpRoute.js +12 -1
- package/lib/decorators/McpRoute.js.map +1 -1
- package/lib/decorators/PlainBody.d.ts +7 -1
- package/lib/decorators/PlainBody.js +16 -8
- package/lib/decorators/PlainBody.js.map +1 -1
- package/lib/decorators/SwaggerCustomizer.d.ts +15 -0
- package/lib/decorators/SwaggerCustomizer.js +5 -0
- package/lib/decorators/SwaggerCustomizer.js.map +1 -1
- package/lib/decorators/SwaggerExample.d.ts +51 -22
- package/lib/decorators/SwaggerExample.js +35 -22
- package/lib/decorators/SwaggerExample.js.map +1 -1
- package/lib/decorators/TypedBody.d.ts +10 -3
- package/lib/decorators/TypedBody.js +20 -10
- package/lib/decorators/TypedBody.js.map +1 -1
- package/lib/decorators/TypedException.d.ts +10 -0
- package/lib/decorators/TypedFormData.d.ts +81 -9
- package/lib/decorators/TypedFormData.js +121 -31
- package/lib/decorators/TypedFormData.js.map +1 -1
- package/lib/decorators/TypedHeaders.d.ts +5 -0
- package/lib/decorators/TypedHeaders.js +5 -0
- package/lib/decorators/TypedHeaders.js.map +1 -1
- package/lib/decorators/TypedParam.d.ts +12 -3
- package/lib/decorators/TypedParam.js +12 -3
- package/lib/decorators/TypedParam.js.map +1 -1
- package/lib/decorators/TypedQuery.d.ts +17 -1
- package/lib/decorators/TypedQuery.js +25 -4
- package/lib/decorators/TypedQuery.js.map +1 -1
- package/lib/decorators/TypedRoute.d.ts +25 -10
- package/lib/decorators/TypedRoute.js +19 -10
- package/lib/decorators/TypedRoute.js.map +1 -1
- package/lib/decorators/WebSocketRoute.d.ts +18 -1
- package/lib/decorators/WebSocketRoute.js +18 -1
- package/lib/decorators/WebSocketRoute.js.map +1 -1
- package/lib/decorators/doNotThrowTransformError.d.ts +14 -0
- package/lib/decorators/doNotThrowTransformError.js +14 -0
- package/lib/decorators/doNotThrowTransformError.js.map +1 -1
- package/lib/decorators/internal/EncryptedConstant.js +13 -2
- package/lib/decorators/internal/EncryptedConstant.js.map +1 -1
- package/lib/decorators/internal/IRequestBodyValidation.d.ts +66 -0
- package/lib/decorators/internal/IRequestBodyValidation.js +3 -0
- package/lib/decorators/internal/IRequestBodyValidation.js.map +1 -0
- package/lib/decorators/internal/IWebSocketRouteReflect.d.ts +93 -1
- package/lib/decorators/internal/get_encryption_password.d.ts +1 -0
- package/lib/decorators/internal/get_encryption_password.js +14 -0
- package/lib/decorators/internal/get_encryption_password.js.map +1 -0
- package/lib/decorators/internal/get_path_and_querify.js +23 -9
- package/lib/decorators/internal/get_path_and_querify.js.map +1 -1
- package/lib/decorators/internal/get_path_and_stringify.js +3 -7
- package/lib/decorators/internal/get_path_and_stringify.js.map +1 -1
- package/lib/decorators/internal/get_text_body.js +9 -3
- package/lib/decorators/internal/get_text_body.js.map +1 -1
- package/lib/decorators/internal/group_entries.d.ts +1 -0
- package/lib/decorators/internal/group_entries.js +19 -0
- package/lib/decorators/internal/group_entries.js.map +1 -0
- package/lib/decorators/internal/load_controller.d.ts +14 -0
- package/lib/decorators/internal/load_controller.js +14 -0
- package/lib/decorators/internal/load_controller.js.map +1 -1
- package/lib/decorators/internal/split_route_arguments.d.ts +1 -0
- package/lib/decorators/internal/split_route_arguments.js +22 -0
- package/lib/decorators/internal/split_route_arguments.js.map +1 -0
- package/lib/decorators/internal/validate_request_body.js +68 -25
- package/lib/decorators/internal/validate_request_body.js.map +1 -1
- package/lib/decorators/internal/validate_request_form_data.js +3 -1
- package/lib/decorators/internal/validate_request_form_data.js.map +1 -1
- package/lib/decorators/internal/validate_request_headers.js +2 -1
- package/lib/decorators/internal/validate_request_headers.js.map +1 -1
- package/lib/decorators/internal/validate_request_query.js +3 -1
- package/lib/decorators/internal/validate_request_query.js.map +1 -1
- package/lib/options/IRequestBodyValidator.d.ts +71 -0
- package/lib/options/IRequestFormDataProps.d.ts +80 -0
- package/lib/options/IRequestHeadersValidator.d.ts +67 -0
- package/lib/options/IRequestQueryValidator.d.ts +68 -0
- package/lib/options/IResponseBodyQuerifier.d.ts +125 -1
- package/lib/options/IResponseBodyStringifier.d.ts +107 -0
- package/lib/typings/Creator.d.ts +10 -0
- package/lib/utils/ArrayUtil.d.ts +21 -0
- package/lib/utils/ArrayUtil.js +22 -1
- package/lib/utils/ArrayUtil.js.map +1 -1
- package/lib/utils/ExceptionManager.d.ts +43 -4
- package/lib/utils/ExceptionManager.js +44 -6
- package/lib/utils/ExceptionManager.js.map +1 -1
- package/lib/utils/SourceFinder.d.ts +22 -0
- package/lib/utils/SourceFinder.js +60 -10
- package/lib/utils/SourceFinder.js.map +1 -1
- package/lib/utils/VersioningStrategy.d.ts +45 -2
- package/lib/utils/VersioningStrategy.js +40 -7
- package/lib/utils/VersioningStrategy.js.map +1 -1
- package/native/go.mod +1 -1
- package/native/go.sum +2 -2
- package/native/plugin/plan.go +68 -2
- package/native/transform/ast.go +23 -3
- package/native/transform/build.go +51 -57
- package/native/transform/buildoutput/output.go +147 -0
- package/native/transform/contributor.go +9 -0
- package/native/transform/core_querify.go +63 -9
- package/native/transform/core_transform.go +180 -98
- package/native/transform/core_websocket.go +111 -14
- package/native/transform/node_transform.go +17 -8
- package/native/transform/package.go +55 -0
- package/native/transform/printer.go +1 -3
- package/native/transform/run.go +18 -0
- package/native/transform/schemaprojection/project.go +213 -0
- package/native/transform/transform.go +29 -18
- package/native/transform/typia_fast.go +6 -0
- package/native/transform.cjs +49 -0
- package/package.json +13 -15
- package/src/adaptors/McpAdaptor.ts +215 -33
- package/src/adaptors/WebSocketAdaptor.ts +202 -52
- package/src/adaptors/internal/RoutePathMatcher.ts +91 -0
- package/src/adaptors/internal/external_context.ts +81 -0
- package/src/decorators/DynamicModule.ts +12 -0
- package/src/decorators/EncryptedBody.ts +39 -15
- package/src/decorators/EncryptedController.ts +12 -3
- package/src/decorators/EncryptedModule.ts +89 -18
- package/src/decorators/EncryptedRoute.ts +27 -16
- package/src/decorators/HumanRoute.ts +5 -0
- package/src/decorators/McpRoute.ts +31 -19
- package/src/decorators/PlainBody.ts +20 -10
- package/src/decorators/SwaggerCustomizer.ts +15 -0
- package/src/decorators/SwaggerExample.ts +51 -22
- package/src/decorators/TypedBody.ts +18 -9
- package/src/decorators/TypedException.ts +10 -0
- package/src/decorators/TypedFormData.ts +207 -45
- package/src/decorators/TypedHeaders.ts +5 -0
- package/src/decorators/TypedParam.ts +12 -3
- package/src/decorators/TypedQuery.ts +35 -7
- package/src/decorators/TypedRoute.ts +25 -10
- package/src/decorators/WebSocketRoute.ts +18 -1
- package/src/decorators/doNotThrowTransformError.ts +14 -0
- package/src/decorators/internal/EncryptedConstant.ts +14 -1
- package/src/decorators/internal/IMcpRouteReflect.ts +7 -1
- package/src/decorators/internal/IRequestBodyValidation.ts +65 -0
- package/src/decorators/internal/IWebSocketRouteReflect.ts +95 -1
- package/src/decorators/internal/get_encryption_password.ts +19 -0
- package/src/decorators/internal/get_path_and_querify.ts +31 -10
- package/src/decorators/internal/get_path_and_stringify.ts +3 -9
- package/src/decorators/internal/get_text_body.ts +8 -4
- package/src/decorators/internal/group_entries.ts +17 -0
- package/src/decorators/internal/load_controller.ts +14 -0
- package/src/decorators/internal/split_route_arguments.ts +20 -0
- package/src/decorators/internal/validate_request_body.ts +87 -34
- package/src/decorators/internal/validate_request_form_data.ts +3 -1
- package/src/decorators/internal/validate_request_headers.ts +2 -2
- package/src/decorators/internal/validate_request_query.ts +3 -2
- package/src/options/IRequestBodyValidator.ts +71 -0
- package/src/options/IRequestFormDataProps.ts +80 -0
- package/src/options/IRequestHeadersValidator.ts +67 -0
- package/src/options/IRequestQueryValidator.ts +68 -0
- package/src/options/IResponseBodyQuerifier.ts +126 -1
- package/src/options/IResponseBodyStringifier.ts +107 -0
- package/src/typings/Creator.ts +10 -0
- package/src/utils/ArrayUtil.ts +22 -3
- package/src/utils/ExceptionManager.ts +50 -6
- package/src/utils/SourceFinder.ts +62 -10
- package/src/utils/VersioningStrategy.ts +55 -11
- package/lib/transform.d.ts +0 -10
- package/lib/transform.js +0 -25
- package/lib/transform.js.map +0 -1
- package/src/transform.ts +0 -26
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { IEncryptionPassword } from "@nestia/fetcher";
|
|
2
2
|
import { Controller } from "@nestjs/common";
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { ENCRYPTION_CONTROLLER_METADATA_KEY } from "./internal/EncryptedConstant";
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Encrypted controller.
|
|
8
8
|
*
|
|
9
9
|
* `EncryptedController` is an extension of the {@link nest.Controller} class
|
|
10
|
-
* decorator function who configures encryption password of the AES-128/256
|
|
10
|
+
* decorator function who configures encryption password of the AES-128/192/256
|
|
11
11
|
* algorithm. The encryption algorithm and password would be used by
|
|
12
12
|
* {@link EncryptedRoute} and {@link EncryptedBody} to encrypt the request and
|
|
13
13
|
* response body of the HTTP protocol.
|
|
@@ -28,13 +28,22 @@ import { ENCRYPTION_METADATA_KEY } from "./internal/EncryptedConstant";
|
|
|
28
28
|
* @param path Path of the HTTP request
|
|
29
29
|
* @param password Encryption password or its getter function
|
|
30
30
|
* @returns Class decorator
|
|
31
|
+
* @evidence contracts/common.md#principled-implementation The decorator stores the password as metadata on the class and then applies Nest's `Controller(path)`, so the encrypted decorators can find the password by reading the class.
|
|
32
|
+
* @evidence contracts/common.md#clear-and-simple-design One decorator that composes a metadata write with the standard decorator.
|
|
33
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts It uses Nest's public `Controller` decorator and the reflect metadata API.
|
|
34
|
+
* @evidence contracts/common.md#meaningful-documentation The comment states the password forms and the encrypted decorators it enables.
|
|
35
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation Controller paths are HTTP routing metadata and passwords are in-memory values; neither is a native filesystem path.
|
|
31
36
|
*/
|
|
32
37
|
export function EncryptedController(
|
|
33
38
|
path: string,
|
|
34
39
|
password: IEncryptionPassword | IEncryptionPassword.Closure,
|
|
35
40
|
): ClassDecorator {
|
|
36
41
|
return function (target: any) {
|
|
37
|
-
Reflect.defineMetadata(
|
|
42
|
+
Reflect.defineMetadata(
|
|
43
|
+
ENCRYPTION_CONTROLLER_METADATA_KEY,
|
|
44
|
+
password,
|
|
45
|
+
target,
|
|
46
|
+
);
|
|
38
47
|
Controller(path)(target);
|
|
39
48
|
};
|
|
40
49
|
}
|
|
@@ -9,16 +9,20 @@ import { load_controllers } from "./internal/load_controller";
|
|
|
9
9
|
* Encrypted module.
|
|
10
10
|
*
|
|
11
11
|
* `EncryptedModule` is an extension of the {@link Module} class decorator
|
|
12
|
-
* function who configures encryption password of the AES-128/256 algorithm.
|
|
13
|
-
* encryption algorithm and password would be used by {@link EncryptedRoute}
|
|
14
|
-
* {@link EncryptedBody} to encrypt the request and response bod of the HTTP
|
|
12
|
+
* function who configures encryption password of the AES-128/192/256 algorithm.
|
|
13
|
+
* The encryption algorithm and password would be used by {@link EncryptedRoute}
|
|
14
|
+
* and {@link EncryptedBody} to encrypt the request and response bod of the HTTP
|
|
15
15
|
* protocol.
|
|
16
16
|
*
|
|
17
17
|
* By using this `EncryptedModule` decorator function, all of the
|
|
18
18
|
* {@link Controller controllers} configured in the _metadata_ would be
|
|
19
|
-
* automatically changed to the {@link EncryptedController} with the _password_
|
|
20
|
-
*
|
|
21
|
-
*
|
|
19
|
+
* automatically changed to the {@link EncryptedController} with the _password_,
|
|
20
|
+
* and so would the controllers of every module it imports: module classes,
|
|
21
|
+
* dynamic modules (`{ module, imports, controllers }`), `forwardRef()`s, and
|
|
22
|
+
* promises of them, however deep and even when cyclic. If there're some
|
|
23
|
+
* original {@link EncryptedController} decorated classes in the _metadata_,
|
|
24
|
+
* their encryption password would be kept, as would a subclass's that inherits
|
|
25
|
+
* one.
|
|
22
26
|
*
|
|
23
27
|
* Therefore, if you're planning to place original {@link EncryptedController}
|
|
24
28
|
* decorated classes in the _metadata_, I hope them to have different encryption
|
|
@@ -34,6 +38,11 @@ import { load_controllers } from "./internal/load_controller";
|
|
|
34
38
|
* @param metadata Module configuration metadata
|
|
35
39
|
* @param password Encryption password or its getter function
|
|
36
40
|
* @returns Class decorator
|
|
41
|
+
* @evidence contracts/common.md#principled-implementation A visited set breaks import cycles, the controllers of each visited module get the password as metadata, asynchronous modules are awaited through the same promise Nest awaits, and a forward reference is resolved once its class exists.
|
|
42
|
+
* @evidence contracts/common.md#clear-and-simple-design One decorator whose traversal is a private function; the dynamic-module helper is in the merged namespace.
|
|
43
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts The traversal uses the public metadata keys of Nest modules; no module name is special-cased.
|
|
44
|
+
* @evidence contracts/common.md#meaningful-documentation The comment states which module shapes are followed.
|
|
45
|
+
* @evidence contracts/portability.md#os-neutral-implementation The decorator traverses Nest module metadata in memory; its dynamic helper delegates native paths and file-URL imports to load_controllers instead of composing platform-specific import strings.
|
|
37
46
|
*/
|
|
38
47
|
export function EncryptedModule(
|
|
39
48
|
metadata: Parameters<typeof Module>[0],
|
|
@@ -45,6 +54,16 @@ export function EncryptedModule(
|
|
|
45
54
|
};
|
|
46
55
|
}
|
|
47
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Helpers of {@link EncryptedModule}, namely `dynamic`, which builds an
|
|
59
|
+
* encrypted module from controller paths.
|
|
60
|
+
*
|
|
61
|
+
* @evidence contracts/common.md#principled-implementation `dynamic` loads the controllers with the shared loader, wraps an object password into a closure, and returns a class decorated by `EncryptedModule`.
|
|
62
|
+
* @evidence contracts/common.md#clear-and-simple-design One function that reuses the loader and the decorator.
|
|
63
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Paths and password are caller input.
|
|
64
|
+
* @evidence contracts/common.md#meaningful-documentation The comment documents the path forms and the password argument.
|
|
65
|
+
* @evidence contracts/portability.md#os-neutral-implementation The decorator traverses Nest module metadata in memory; its dynamic helper delegates native paths and file-URL imports to load_controllers instead of composing platform-specific import strings.
|
|
66
|
+
*/
|
|
48
67
|
export namespace EncryptedModule {
|
|
49
68
|
/**
|
|
50
69
|
* Dynamic encrypted module.
|
|
@@ -81,18 +100,70 @@ export namespace EncryptedModule {
|
|
|
81
100
|
}
|
|
82
101
|
}
|
|
83
102
|
|
|
84
|
-
/**
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
103
|
+
/**
|
|
104
|
+
* Gives every controller the module reaches the module's password: those of the
|
|
105
|
+
* module itself and of each import, whether a module class, a dynamic module
|
|
106
|
+
* (its `module`, and its own `imports` and `controllers`), a `forwardRef()`, or
|
|
107
|
+
* a promise of one. Each module is visited once, so a cyclic import graph
|
|
108
|
+
* terminates.
|
|
109
|
+
*
|
|
110
|
+
* @internal
|
|
111
|
+
*/
|
|
112
|
+
const iterate = (password: IEncryptionPassword.Closure) => {
|
|
113
|
+
const visited: Set<object> = new Set();
|
|
114
|
+
const controllers = (list: unknown): void => {
|
|
115
|
+
if (Array.isArray(list))
|
|
116
|
+
for (const c of list)
|
|
96
117
|
if (typeof c === "function")
|
|
97
118
|
Reflect.defineMetadata(ENCRYPTION_METADATA_KEY, password, c);
|
|
98
119
|
};
|
|
120
|
+
const imports = (list: unknown): void => {
|
|
121
|
+
if (Array.isArray(list)) for (const imp of list) visit(imp);
|
|
122
|
+
};
|
|
123
|
+
const visit = (input: unknown): void => {
|
|
124
|
+
if (
|
|
125
|
+
typeof input !== "function" &&
|
|
126
|
+
(typeof input !== "object" || input === null)
|
|
127
|
+
)
|
|
128
|
+
return;
|
|
129
|
+
if (visited.has(input)) return;
|
|
130
|
+
visited.add(input);
|
|
131
|
+
|
|
132
|
+
if (typeof input === "function") {
|
|
133
|
+
imports(Reflect.getMetadata("imports", input));
|
|
134
|
+
controllers(Reflect.getMetadata("controllers", input));
|
|
135
|
+
} else if (typeof (input as PromiseLike<unknown>).then === "function")
|
|
136
|
+
// an asynchronous dynamic module; NestJS awaits the same promise while
|
|
137
|
+
// scanning, after this callback, registered first, has run
|
|
138
|
+
(input as PromiseLike<unknown>).then(visit, () => {});
|
|
139
|
+
else if (typeof (input as IForwardReference).forwardRef === "function") {
|
|
140
|
+
// the class a forward reference names may not be defined yet while the
|
|
141
|
+
// decorators run; it is once the synchronous module graph has loaded
|
|
142
|
+
const resolve = (): unknown => {
|
|
143
|
+
try {
|
|
144
|
+
return (input as IForwardReference).forwardRef();
|
|
145
|
+
} catch {
|
|
146
|
+
return undefined;
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
const target: unknown = resolve();
|
|
150
|
+
if (target !== undefined) visit(target);
|
|
151
|
+
else void Promise.resolve().then(() => visit(resolve()));
|
|
152
|
+
} else {
|
|
153
|
+
const dynamic = input as {
|
|
154
|
+
module?: unknown;
|
|
155
|
+
imports?: unknown;
|
|
156
|
+
controllers?: unknown;
|
|
157
|
+
};
|
|
158
|
+
visit(dynamic.module);
|
|
159
|
+
imports(dynamic.imports);
|
|
160
|
+
controllers(dynamic.controllers);
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
return visit;
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
/** @internal */
|
|
167
|
+
interface IForwardReference {
|
|
168
|
+
forwardRef: () => unknown;
|
|
169
|
+
}
|
|
@@ -20,7 +20,7 @@ import typia from "typia";
|
|
|
20
20
|
import { IResponseBodyStringifier } from "../options/IResponseBodyStringifier";
|
|
21
21
|
import { Singleton } from "../utils/Singleton";
|
|
22
22
|
import { TypedRoute } from "./TypedRoute";
|
|
23
|
-
import {
|
|
23
|
+
import { get_encryption_password } from "./internal/get_encryption_password";
|
|
24
24
|
import { get_path_and_stringify } from "./internal/get_path_and_stringify";
|
|
25
25
|
import { headers_to_object } from "./internal/headers_to_object";
|
|
26
26
|
import { route_error } from "./internal/route_error";
|
|
@@ -29,22 +29,26 @@ import { route_error } from "./internal/route_error";
|
|
|
29
29
|
* Encrypted router decorator functions.
|
|
30
30
|
*
|
|
31
31
|
* `EncryptedRoute` is a module containing router decorator functions which
|
|
32
|
-
* encrypts response body data through AES-128/256 encryption
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* [typia](https://github.com/samchon/typia).
|
|
32
|
+
* encrypts response body data through AES-128/192/256 encryption after
|
|
33
|
+
* serializing it with a [typia](https://github.com/samchon/typia) function
|
|
34
|
+
* generated from the declared return type.
|
|
36
35
|
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* `
|
|
40
|
-
*
|
|
36
|
+
* The default assert serializer rejects a response outside the declared type
|
|
37
|
+
* with a 500 error. The configured stringify mode chooses the validation policy
|
|
38
|
+
* before encryption; `validate.log` logs failures and serializes the original
|
|
39
|
+
* value. Interceptors running afterwards receive ciphertext.
|
|
41
40
|
*
|
|
42
|
-
* - AES-128/256
|
|
41
|
+
* - AES-128/192/256
|
|
43
42
|
* - CBC mode
|
|
44
43
|
* - PKCS #5 Padding
|
|
45
44
|
* - Base64 Encoding
|
|
46
45
|
*
|
|
47
46
|
* @author Jeongho Nam - https://github.com/samchon
|
|
47
|
+
* @evidence contracts/common.md#principled-implementation Each route method decorates Nest's router decorator with an interceptor that serializes the value as the transform chose, encrypts it with the password of the controller or module, and answers `text/plain` on success only, so an error keeps its own JSON type.
|
|
48
|
+
* @evidence contracts/common.md#clear-and-simple-design One generator function creates the five HTTP-method decorators, and the interceptor and the router table are module-private.
|
|
49
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts The password lookup and the serializer come from shared modules; the loop after the namespace copies the marker properties of typia's stringify functions onto the five decorators as the transform expects, which mutates only these exported functions.
|
|
50
|
+
* @evidence contracts/common.md#meaningful-documentation The comment documents the decorator family and its password requirement.
|
|
51
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation Route paths and serialized ciphertext are HTTP protocol values; response interception does not access native files or launch a process.
|
|
48
52
|
*/
|
|
49
53
|
export namespace EncryptedRoute {
|
|
50
54
|
/**
|
|
@@ -56,7 +60,7 @@ export namespace EncryptedRoute {
|
|
|
56
60
|
export const Get = Generator("Get");
|
|
57
61
|
|
|
58
62
|
/**
|
|
59
|
-
* Encrypted router decorator function for the
|
|
63
|
+
* Encrypted router decorator function for the POST method.
|
|
60
64
|
*
|
|
61
65
|
* @param paths Path(s) of the HTTP request
|
|
62
66
|
* @returns Method decorator
|
|
@@ -93,7 +97,7 @@ export namespace EncryptedRoute {
|
|
|
93
97
|
* If you've configured the transformation option to `validate.log` in the
|
|
94
98
|
* `tsconfig.json` file, then the error log information of the response
|
|
95
99
|
* validation failure would be logged through this function instead of
|
|
96
|
-
* throwing the
|
|
100
|
+
* throwing the 500 internal server error.
|
|
97
101
|
*
|
|
98
102
|
* By the way, be careful. If you've configured the response transformation
|
|
99
103
|
* option to be `validate.log`, client may get wrong response data. Therefore,
|
|
@@ -101,6 +105,11 @@ export namespace EncryptedRoute {
|
|
|
101
105
|
*
|
|
102
106
|
* @default console.log
|
|
103
107
|
* @param func Logger function
|
|
108
|
+
* @evidence contracts/common.md#principled-implementation It stores the logger in `TypedRoute`, which owns the single logger both route families use.
|
|
109
|
+
* @evidence contracts/common.md#clear-and-simple-design A one-line delegation, so the logger has one owner.
|
|
110
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts It changes only the logger variable.
|
|
111
|
+
* @evidence contracts/common.md#meaningful-documentation The comment states which validate mode uses the logger.
|
|
112
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation Route paths and serialized ciphertext are HTTP protocol values; response interception does not access native files or launch a process.
|
|
104
113
|
*/
|
|
105
114
|
export function setValidateErrorLogger(
|
|
106
115
|
func: (log: IValidateErrorLog) => void,
|
|
@@ -168,10 +177,7 @@ class EncryptedRouteInterceptor implements NestInterceptor {
|
|
|
168
177
|
const param:
|
|
169
178
|
| IEncryptionPassword
|
|
170
179
|
| IEncryptionPassword.Closure
|
|
171
|
-
| undefined =
|
|
172
|
-
ENCRYPTION_METADATA_KEY,
|
|
173
|
-
context.getClass(),
|
|
174
|
-
);
|
|
180
|
+
| undefined = get_encryption_password(context.getClass());
|
|
175
181
|
if (!param)
|
|
176
182
|
throw new Error(
|
|
177
183
|
`Error on EncryptedRoute.${this.method}(): no password found.`,
|
|
@@ -196,6 +202,11 @@ class EncryptedRouteInterceptor implements NestInterceptor {
|
|
|
196
202
|
: param;
|
|
197
203
|
|
|
198
204
|
if (body === undefined) return body;
|
|
205
|
+
// the ciphertext is text/plain, as the document declares; set on the
|
|
206
|
+
// success path alone, so an error keeps its JSON body's type (Express
|
|
207
|
+
// would otherwise send a string as text/html)
|
|
208
|
+
const response: express.Response = http.getResponse();
|
|
209
|
+
response.header("Content-Type", "text/plain");
|
|
199
210
|
return AesPkcs5.encrypt(body, password.key, password.iv);
|
|
200
211
|
}),
|
|
201
212
|
catchError((err) => route_error(http.getRequest(), err)),
|
|
@@ -13,6 +13,11 @@ import { SwaggerCustomizer } from "./SwaggerCustomizer";
|
|
|
13
13
|
*
|
|
14
14
|
* @author Jeongho Nam - https://github.com/samchon
|
|
15
15
|
* @returns Method decorator
|
|
16
|
+
* @evidence contracts/common.md#principled-implementation The decorator marks the operation with the `x-samchon-human` extension through `SwaggerCustomizer`, so the generated document carries the mark without another metadata path.
|
|
17
|
+
* @evidence contracts/common.md#clear-and-simple-design One call to the customizer.
|
|
18
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts The extension name is the documented contract of the generated document.
|
|
19
|
+
* @evidence contracts/common.md#meaningful-documentation The comment states that a marked API is left out of the LLM function calling schema.
|
|
20
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation The OpenAPI extension is an in-memory document property and has no native path or process representation.
|
|
16
21
|
*/
|
|
17
22
|
export function HumanRoute(): MethodDecorator {
|
|
18
23
|
return SwaggerCustomizer((props) => {
|
|
@@ -25,27 +25,28 @@ import { validate_request_body } from "./internal/validate_request_body";
|
|
|
25
25
|
* the {@link INestApplication} instance at bootstrap. The decorator alone only
|
|
26
26
|
* stores reflection metadata.
|
|
27
27
|
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
28
|
+
* Example:
|
|
29
|
+
*
|
|
30
|
+
* ```typescript
|
|
31
|
+
* import core from "@nestia/core";
|
|
32
32
|
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* }
|
|
33
|
+
* @Controller()
|
|
34
|
+
* export class WeatherController {
|
|
35
|
+
* /**
|
|
36
|
+
* * Return current weather for a city.
|
|
37
|
+
* *
|
|
38
|
+
* * @title Get weather
|
|
39
|
+
* *\/
|
|
40
|
+
* @core.McpRoute("get_weather")
|
|
41
|
+
* public async get(
|
|
42
|
+
* @core.McpRoute.Params() params: { city: string },
|
|
43
|
+
* ): Promise<{ temp: number }> {
|
|
44
|
+
* return { temp: 22 };
|
|
46
45
|
* }
|
|
47
|
-
*
|
|
46
|
+
* }
|
|
47
|
+
* ```
|
|
48
48
|
*
|
|
49
|
+
* @author wildduck - https://github.com/wildduck2
|
|
49
50
|
* @param name Unique tool identifier exposed to MCP clients via `tools/list`.
|
|
50
51
|
* @returns Method decorator.
|
|
51
52
|
*/
|
|
@@ -78,6 +79,16 @@ export function McpRoute(input: string | McpRoute.IConfig): MethodDecorator {
|
|
|
78
79
|
};
|
|
79
80
|
}
|
|
80
81
|
|
|
82
|
+
/**
|
|
83
|
+
* Types and parameter decorator of {@link McpRoute}: the tool configuration and
|
|
84
|
+
* `McpRoute.Params`.
|
|
85
|
+
*
|
|
86
|
+
* @evidence contracts/common.md#principled-implementation Tool metadata retains its definition and default empty-object schema. Params records its argument position and shared checker; successful assert/validate data becomes the tool argument, while errors retain InvalidParams mapping and legacy error-only callbacks retain raw input. The adaptor reads the same metadata field names when registering tools.
|
|
87
|
+
* @evidence contracts/common.md#clear-and-simple-design Two decorators and one config type in one namespace, sharing one `emplace` helper for parameter metadata.
|
|
88
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts It uses the reflect metadata API and no NestJS internals; the input schema is filled by the generator, not hardcoded here.
|
|
89
|
+
* @evidence contracts/common.md#meaningful-documentation The comment documents the two call forms, the configuration fields, and the parameter decorator.
|
|
90
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation Tool schemas and parameter metadata are protocol data held on controller methods, without native filesystem access.
|
|
91
|
+
*/
|
|
81
92
|
export namespace McpRoute {
|
|
82
93
|
/**
|
|
83
94
|
* Configuration object emitted by the nestia transformer at compile time.
|
|
@@ -104,7 +115,8 @@ export namespace McpRoute {
|
|
|
104
115
|
* `tools/call` request against the TypeScript type `T` using typia. A failed
|
|
105
116
|
* validation surfaces to the client as a JSON-RPC `-32602` (`InvalidParams`)
|
|
106
117
|
* error with structured diagnostics, giving the LLM precise feedback to
|
|
107
|
-
* self-correct.
|
|
118
|
+
* self-correct. Successful assert and validate data becomes the tool
|
|
119
|
+
* argument, so clone validators can supply a copy of the incoming arguments.
|
|
108
120
|
*
|
|
109
121
|
* MCP tools accept exactly one arguments object; applying this decorator more
|
|
110
122
|
* than once on a single method is a compile-time error. The decorated type
|
|
@@ -15,7 +15,8 @@ import { validate_request_body } from "./internal/validate_request_body";
|
|
|
15
15
|
* Plain body decorator.
|
|
16
16
|
*
|
|
17
17
|
* `PlainBody` is a decorator function getting full body text from the HTTP
|
|
18
|
-
* request.
|
|
18
|
+
* request. The transformed assertion's successful string is the decorated
|
|
19
|
+
* argument.
|
|
19
20
|
*
|
|
20
21
|
* If you adjust the regular {@link Body} decorator function to the body
|
|
21
22
|
* parameter, you can't get the full body text because the {@link Body} tries to
|
|
@@ -32,10 +33,18 @@ import { validate_request_body } from "./internal/validate_request_body";
|
|
|
32
33
|
*
|
|
33
34
|
* @author Jeongho Nam - https://github.com/samchon
|
|
34
35
|
* @returns Parameter decorator
|
|
36
|
+
* @evidence contracts/common.md#principled-implementation The decorator reads text only for text/plain requests; an installed assertion resolves the argument value through the shared body checker, while no assertion retains raw text. Absent input is accepted when its assertion accepts undefined and otherwise continues through the media-type error path.
|
|
37
|
+
* @evidence contracts/common.md#clear-and-simple-design One parameter decorator shares body absence, media recognition, text reading and successful-value resolution with the other request decorators.
|
|
38
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Text comes from the request parser or shared raw-body reader, not a fabricated value; no runtime controller or body identity is special-cased.
|
|
39
|
+
* @evidence contracts/common.md#meaningful-documentation The comment distinguishes full body text from JSON parsing and states that the transformed assertion supplies the argument.
|
|
40
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation HTTP text bodies and decoded string values carry no native filesystem or subprocess boundary.
|
|
35
41
|
*/
|
|
36
42
|
export function PlainBody(): ParameterDecorator;
|
|
37
43
|
|
|
38
|
-
/**
|
|
44
|
+
/**
|
|
45
|
+
* Registers the transformed text assertion and binds its successful value. The
|
|
46
|
+
* public overload accepts no runtime assertion; the transform supplies it.
|
|
47
|
+
*/
|
|
39
48
|
export function PlainBody(
|
|
40
49
|
assert?: (input: unknown) => string,
|
|
41
50
|
): ParameterDecorator {
|
|
@@ -52,17 +61,18 @@ export function PlainBody(
|
|
|
52
61
|
const request: express.Request | FastifyRequest = context
|
|
53
62
|
.switchToHttp()
|
|
54
63
|
.getRequest();
|
|
55
|
-
if (
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
64
|
+
if (is_request_body_undefined(request)) {
|
|
65
|
+
if (checker === null) return undefined;
|
|
66
|
+
const result = checker.resolve(undefined);
|
|
67
|
+
if (result.success) return result.data;
|
|
68
|
+
}
|
|
69
|
+
if (!is_media_type(request.headers["content-type"], "text/plain"))
|
|
61
70
|
throw new BadRequestException(`Request body type is not "text/plain".`);
|
|
62
71
|
const value: string = await get_text_body(request);
|
|
63
72
|
if (checker) {
|
|
64
|
-
const
|
|
65
|
-
if (
|
|
73
|
+
const result = checker.resolve(value);
|
|
74
|
+
if (!result.success) throw result.error;
|
|
75
|
+
return result.data;
|
|
66
76
|
}
|
|
67
77
|
return value;
|
|
68
78
|
})();
|
|
@@ -13,6 +13,11 @@ import { OpenApi } from "@typia/interface";
|
|
|
13
13
|
* @author Jeongho Nam - https://github.com/samchon
|
|
14
14
|
* @param closure Callback function which can customize the swagger data
|
|
15
15
|
* @returns Method decorator
|
|
16
|
+
* @evidence contracts/common.md#principled-implementation Each use appends the closure to an array of metadata owned by the method, created on first use, so several customizers on one method run in order.
|
|
17
|
+
* @evidence contracts/common.md#clear-and-simple-design One decorator function with one metadata list per method.
|
|
18
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts It uses the reflect metadata API; the closure is the caller's.
|
|
19
|
+
* @evidence contracts/common.md#meaningful-documentation The comment documents that the closure receives the document, the operation, and lookup helpers.
|
|
20
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation The callback and endpoint accessors edit an OpenAPI document; their path fields are HTTP routes rather than native file identities.
|
|
16
21
|
*/
|
|
17
22
|
export function SwaggerCustomizer(
|
|
18
23
|
closure: (props: SwaggerCustomizer.IProps) => unknown,
|
|
@@ -44,6 +49,16 @@ export function SwaggerCustomizer(
|
|
|
44
49
|
return descriptor;
|
|
45
50
|
};
|
|
46
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* Types of {@link SwaggerCustomizer}: the properties the closure receives and
|
|
54
|
+
* the endpoint accessors.
|
|
55
|
+
*
|
|
56
|
+
* @evidence contracts/common.md#principled-implementation The types describe the document, the current operation, and lookups by function or by path and method, which is what a customization needs to edit the generated document.
|
|
57
|
+
* @evidence contracts/common.md#clear-and-simple-design Three types with no runtime members.
|
|
58
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts It contains types only.
|
|
59
|
+
* @evidence contracts/common.md#meaningful-documentation Each type and member documents its meaning.
|
|
60
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation The callback and endpoint accessors edit an OpenAPI document; their path fields are HTTP routes rather than native file identities.
|
|
61
|
+
*/
|
|
47
62
|
export namespace SwaggerCustomizer {
|
|
48
63
|
/**
|
|
49
64
|
* Properties for the `SwaggerCustomizer` decorator.
|
|
@@ -9,30 +9,43 @@
|
|
|
9
9
|
* The decorators only affect Swagger document generation. They do not change
|
|
10
10
|
* runtime behavior, validation, or SDK function signatures.
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
12
|
+
* Example:
|
|
13
|
+
*
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import core from "@nestia/core";
|
|
16
|
+
* import { Controller } from "@nestjs/common";
|
|
17
|
+
* import typia from "typia";
|
|
18
18
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
19
|
+
* @Controller("bbs/articles")
|
|
20
|
+
* export class BbsArticlesController {
|
|
21
|
+
* // Single response example.
|
|
22
|
+
* @core.SwaggerExample.Response(typia.random<IBbsArticle>())
|
|
23
|
+
* @core.TypedRoute.Post()
|
|
24
|
+
* public async create(
|
|
25
|
+
* // Multiple named parameter examples plus a default one.
|
|
26
|
+
* @core.SwaggerExample.Parameter(typia.random<IBbsArticle.ICreate>())
|
|
27
|
+
* @core.SwaggerExample.Parameter(
|
|
28
|
+
* "x",
|
|
29
|
+
* typia.random<IBbsArticle.ICreate>(),
|
|
30
|
+
* )
|
|
31
|
+
* @core.SwaggerExample.Parameter(
|
|
32
|
+
* "y",
|
|
33
|
+
* typia.random<IBbsArticle.ICreate>(),
|
|
34
|
+
* )
|
|
35
|
+
* @core.TypedBody()
|
|
36
|
+
* input: IBbsArticle.ICreate,
|
|
37
|
+
* ): Promise<IBbsArticle> {
|
|
38
|
+
* // ...
|
|
34
39
|
* }
|
|
35
|
-
*
|
|
40
|
+
* }
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* @author Jeongho Nam - https://github.com/samchon
|
|
44
|
+
* @evidence contracts/common.md#principled-implementation Examples are stored as metadata on the method or on the parameter position; a call with one argument sets the single example, and a call with a key and a value adds a named example, so both OpenAPI forms are expressible.
|
|
45
|
+
* @evidence contracts/common.md#clear-and-simple-design Two decorators over three private metadata helpers that find or create the record.
|
|
46
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts The examples are caller data, and nothing is generated here.
|
|
47
|
+
* @evidence contracts/common.md#meaningful-documentation The comment documents both decorators and the two call forms.
|
|
48
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation Example metadata contains caller values and parameter indices without a native path or process boundary.
|
|
36
49
|
*/
|
|
37
50
|
export namespace SwaggerExample {
|
|
38
51
|
/**
|
|
@@ -51,6 +64,11 @@ export namespace SwaggerExample {
|
|
|
51
64
|
* document.
|
|
52
65
|
*
|
|
53
66
|
* @template T Type of the example value (typically the route's response DTO).
|
|
67
|
+
* @evidence contracts/common.md#principled-implementation The value or the keyed value is recorded on the method's response example record, which the document generator reads.
|
|
68
|
+
* @evidence contracts/common.md#clear-and-simple-design One decorator with two overloads.
|
|
69
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts The value is stored as given.
|
|
70
|
+
* @evidence contracts/common.md#meaningful-documentation The comment documents the overloads with an example.
|
|
71
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation Example metadata contains caller values and parameter indices without a native path or process boundary.
|
|
54
72
|
*/
|
|
55
73
|
export function Response<T>(value: T): MethodDecorator;
|
|
56
74
|
export function Response<T>(key: string, value: T): MethodDecorator;
|
|
@@ -81,6 +99,11 @@ export namespace SwaggerExample {
|
|
|
81
99
|
* `@TypedParam()`, `@TypedQuery()`, etc.); decorator order does not matter.
|
|
82
100
|
*
|
|
83
101
|
* @template T Type of the example value (typically the parameter's DTO).
|
|
102
|
+
* @evidence contracts/common.md#principled-implementation The value or the keyed value is recorded on the record for that parameter index, so several parameters keep separate examples.
|
|
103
|
+
* @evidence contracts/common.md#clear-and-simple-design One decorator with two overloads.
|
|
104
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts The value is stored as given.
|
|
105
|
+
* @evidence contracts/common.md#meaningful-documentation The comment documents the overloads with an example.
|
|
106
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation Example metadata contains caller values and parameter indices without a native path or process boundary.
|
|
84
107
|
*/
|
|
85
108
|
export function Parameter<T>(value: T): ParameterDecorator;
|
|
86
109
|
export function Parameter<T>(key: string, value: T): ParameterDecorator;
|
|
@@ -100,6 +123,12 @@ export namespace SwaggerExample {
|
|
|
100
123
|
* Reflects the OpenAPI spec's two example fields: a single default `example`,
|
|
101
124
|
* and/or a named map `examples`. `index` is used internally to associate
|
|
102
125
|
* parameter examples with the right parameter position.
|
|
126
|
+
*
|
|
127
|
+
* @evidence contracts/common.md#principled-implementation The record holds the single example, the named examples, and the parameter index, which is everything the generator needs to attach examples.
|
|
128
|
+
* @evidence contracts/common.md#clear-and-simple-design A flat record whose members are all optional.
|
|
129
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts It is a type and adds no runtime behavior.
|
|
130
|
+
* @evidence contracts/common.md#meaningful-documentation The comment states the meaning of the members.
|
|
131
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation Example metadata contains caller values and parameter indices without a native path or process boundary.
|
|
103
132
|
*/
|
|
104
133
|
export interface IData<T> {
|
|
105
134
|
examples?: Record<string, T>;
|
|
@@ -16,14 +16,21 @@ import { validate_request_body } from "./internal/validate_request_body";
|
|
|
16
16
|
*
|
|
17
17
|
* `TypedBody` is a decorator function getting `application/json` typed data
|
|
18
18
|
* from request body. Also, it validates the request body data type through
|
|
19
|
-
* [typia](https://github.com/samchon/typia)
|
|
20
|
-
*
|
|
19
|
+
* [typia](https://github.com/samchon/typia) using the declared TypeScript
|
|
20
|
+
* type.
|
|
21
21
|
*
|
|
22
22
|
* For reference, when the request body data is not following the promised type
|
|
23
23
|
* `T`, `BadRequestException` error (status code: 400) would be thrown.
|
|
24
|
+
* Successful assert and validate callbacks supply the decorated argument; clone
|
|
25
|
+
* validators can therefore return a copy without replacing the raw body.
|
|
24
26
|
*
|
|
25
27
|
* @author Jeongho Nam - https://github.com/samchon
|
|
26
|
-
* @param validator Custom validator if required. Default is `typia.
|
|
28
|
+
* @param validator Custom validator if required. Default is `typia.validate()`
|
|
29
|
+
* @evidence contracts/common.md#principled-implementation An absent body with no content type is accepted only when the validator accepts undefined; any other body must be application/json. The checker returns explicitly tagged successful data or the existing validation error, so cloned values reach the argument while raw request.body retains its identity and errors retain their response priority.
|
|
30
|
+
* @evidence contracts/common.md#clear-and-simple-design One parameter decorator composes shared media/absence checks and tagged resolution. The shared internal runner owns descriptor selection and error translation; PlainBody uses the same successful-value protocol for its optional transformed text assertion, preserving raw text when no assertion exists and preserving its absent-input/media error priority.
|
|
31
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts The validator is generated from the type by the transform; without it the decorator throws the configuration error unless the guard is turned off.
|
|
32
|
+
* @evidence contracts/common.md#meaningful-documentation The comment documents the decorator, the media type rule, and the validation modes.
|
|
33
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation Parsed HTTP bodies and validation callbacks are independent of native filesystem and process representation.
|
|
27
34
|
*/
|
|
28
35
|
export function TypedBody<T>(
|
|
29
36
|
validator?: IRequestBodyValidator<T>,
|
|
@@ -36,9 +43,11 @@ export function TypedBody<T>(
|
|
|
36
43
|
const request: express.Request | FastifyRequest = context
|
|
37
44
|
.switchToHttp()
|
|
38
45
|
.getRequest();
|
|
39
|
-
if (is_request_body_undefined(request)
|
|
40
|
-
|
|
41
|
-
|
|
46
|
+
if (is_request_body_undefined(request)) {
|
|
47
|
+
const result = checker.resolve(undefined);
|
|
48
|
+
if (result.success) return result.data;
|
|
49
|
+
}
|
|
50
|
+
if (
|
|
42
51
|
is_media_type(request.headers["content-type"], "application/json") ===
|
|
43
52
|
false
|
|
44
53
|
)
|
|
@@ -46,8 +55,8 @@ export function TypedBody<T>(
|
|
|
46
55
|
`Request body type is not "application/json".`,
|
|
47
56
|
);
|
|
48
57
|
|
|
49
|
-
const
|
|
50
|
-
if (
|
|
51
|
-
return
|
|
58
|
+
const result = checker.resolve(request.body);
|
|
59
|
+
if (!result.success) throw result.error;
|
|
60
|
+
return result.data;
|
|
52
61
|
})();
|
|
53
62
|
}
|
|
@@ -117,6 +117,16 @@ export function TypedException<T>(...args: any[]): MethodDecorator {
|
|
|
117
117
|
return descriptor;
|
|
118
118
|
};
|
|
119
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* Types of {@link TypedException}: the response properties a declaration
|
|
122
|
+
* carries, and its named examples.
|
|
123
|
+
*
|
|
124
|
+
* @evidence contracts/common.md#principled-implementation The decorator records each declared status, description, and example on the method's metadata list, so the document generator can add the responses; the overloads without a type argument return `never` so a missing type argument is a compile error.
|
|
125
|
+
* @evidence contracts/common.md#clear-and-simple-design One decorator whose overloads split the property form and the positional form.
|
|
126
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts It records declarations and never changes how the route responds.
|
|
127
|
+
* @evidence contracts/common.md#meaningful-documentation The comment documents the forms and that the status accepts range spellings.
|
|
128
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation Response declarations contain HTTP status codes and examples, without native files or subprocesses.
|
|
129
|
+
*/
|
|
120
130
|
export namespace TypedException {
|
|
121
131
|
/** Properties for the exception. */
|
|
122
132
|
export interface IProps<T> {
|