@nestia/sdk 12.0.0-dev.20260601.1 → 12.0.0-dev.20260612.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.
Files changed (209) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +93 -93
  3. package/assets/bundle/api/HttpError.ts +1 -1
  4. package/assets/bundle/api/IConnection.ts +1 -1
  5. package/assets/bundle/api/Primitive.ts +1 -1
  6. package/assets/bundle/api/Resolved.ts +1 -1
  7. package/assets/bundle/api/index.ts +4 -4
  8. package/assets/bundle/api/module.ts +6 -6
  9. package/assets/bundle/distribute/README.md +37 -37
  10. package/assets/bundle/distribute/package.json +28 -28
  11. package/assets/bundle/distribute/tsconfig.json +109 -109
  12. package/assets/bundle/e2e/index.ts +42 -42
  13. package/assets/config/nestia.config.ts +97 -97
  14. package/lib/NestiaSdkApplication.js +29 -7
  15. package/lib/NestiaSdkApplication.js.map +1 -1
  16. package/lib/NestiaSwaggerComposer.js +21 -13
  17. package/lib/NestiaSwaggerComposer.js.map +1 -1
  18. package/lib/analyses/AccessorAnalyzer.d.ts +4 -1
  19. package/lib/analyses/AccessorAnalyzer.js.map +1 -1
  20. package/lib/analyses/ConfigAnalyzer.js +1 -1
  21. package/lib/analyses/PathAnalyzer.d.ts +18 -3
  22. package/lib/analyses/PathAnalyzer.js +32 -0
  23. package/lib/analyses/PathAnalyzer.js.map +1 -1
  24. package/lib/analyses/ReflectControllerAnalyzer.js +3 -2
  25. package/lib/analyses/ReflectControllerAnalyzer.js.map +1 -1
  26. package/lib/analyses/ReflectHttpOperationAnalyzer.d.ts +1 -1
  27. package/lib/analyses/ReflectHttpOperationAnalyzer.js +1 -1
  28. package/lib/analyses/ReflectHttpOperationAnalyzer.js.map +1 -1
  29. package/lib/analyses/ReflectHttpOperationResponseAnalyzer.d.ts +1 -1
  30. package/lib/analyses/ReflectHttpOperationResponseAnalyzer.js +53 -20
  31. package/lib/analyses/ReflectHttpOperationResponseAnalyzer.js.map +1 -1
  32. package/lib/analyses/ReflectMcpOperationAnalyzer.d.ts +14 -0
  33. package/lib/analyses/ReflectMcpOperationAnalyzer.js +79 -0
  34. package/lib/analyses/ReflectMcpOperationAnalyzer.js.map +1 -0
  35. package/lib/analyses/TypedMcpRouteAnalyzer.d.ts +9 -0
  36. package/lib/analyses/TypedMcpRouteAnalyzer.js +31 -0
  37. package/lib/analyses/TypedMcpRouteAnalyzer.js.map +1 -0
  38. package/lib/executable/internal/NestiaConfigLoader.js +5 -1
  39. package/lib/executable/internal/NestiaConfigLoader.js.map +1 -1
  40. package/lib/executable/internal/NestiaSdkCommand.js +30 -14
  41. package/lib/executable/internal/NestiaSdkCommand.js.map +1 -1
  42. package/lib/executable/internal/NestiaSdkWatcher.d.ts +10 -0
  43. package/lib/executable/internal/NestiaSdkWatcher.js +322 -0
  44. package/lib/executable/internal/NestiaSdkWatcher.js.map +1 -0
  45. package/lib/executable/sdk.js +12 -12
  46. package/lib/executable/sdk.js.map +1 -1
  47. package/lib/generates/CloneGenerator.js +4 -2
  48. package/lib/generates/CloneGenerator.js.map +1 -1
  49. package/lib/generates/SdkGenerator.js +50 -1
  50. package/lib/generates/SdkGenerator.js.map +1 -1
  51. package/lib/generates/SwaggerGenerator.js +18 -2
  52. package/lib/generates/SwaggerGenerator.js.map +1 -1
  53. package/lib/generates/internal/E2eFileProgrammer.js +3 -1
  54. package/lib/generates/internal/E2eFileProgrammer.js.map +1 -1
  55. package/lib/generates/internal/ImportDictionary.d.ts +1 -0
  56. package/lib/generates/internal/ImportDictionary.js +9 -4
  57. package/lib/generates/internal/ImportDictionary.js.map +1 -1
  58. package/lib/generates/internal/SdkAliasCollection.d.ts +2 -0
  59. package/lib/generates/internal/SdkAliasCollection.js +11 -2
  60. package/lib/generates/internal/SdkAliasCollection.js.map +1 -1
  61. package/lib/generates/internal/SdkDistributionComposer.d.ts +1 -0
  62. package/lib/generates/internal/SdkDistributionComposer.js +3 -0
  63. package/lib/generates/internal/SdkDistributionComposer.js.map +1 -1
  64. package/lib/generates/internal/SdkFileProgrammer.js +4 -1
  65. package/lib/generates/internal/SdkFileProgrammer.js.map +1 -1
  66. package/lib/generates/internal/SdkHttpCloneReferencer.d.ts +1 -1
  67. package/lib/generates/internal/SdkHttpCloneReferencer.js +42 -9
  68. package/lib/generates/internal/SdkHttpCloneReferencer.js.map +1 -1
  69. package/lib/generates/internal/SdkHttpFunctionProgrammer.js +3 -4
  70. package/lib/generates/internal/SdkHttpFunctionProgrammer.js.map +1 -1
  71. package/lib/generates/internal/SdkHttpNamespaceProgrammer.js +2 -1
  72. package/lib/generates/internal/SdkHttpNamespaceProgrammer.js.map +1 -1
  73. package/lib/generates/internal/SdkHttpSimulationProgrammer.js +6 -3
  74. package/lib/generates/internal/SdkHttpSimulationProgrammer.js.map +1 -1
  75. package/lib/generates/internal/SdkMcpRouteProgrammer.d.ts +15 -0
  76. package/lib/generates/internal/SdkMcpRouteProgrammer.js +148 -0
  77. package/lib/generates/internal/SdkMcpRouteProgrammer.js.map +1 -0
  78. package/lib/generates/internal/SdkRouteDirectory.d.ts +2 -1
  79. package/lib/generates/internal/SdkRouteDirectory.js.map +1 -1
  80. package/lib/generates/internal/SdkWebSocketCloneProgrammer.d.ts +6 -0
  81. package/lib/generates/internal/SdkWebSocketCloneProgrammer.js +283 -0
  82. package/lib/generates/internal/SdkWebSocketCloneProgrammer.js.map +1 -0
  83. package/lib/generates/internal/SdkWebSocketRouteProgrammer.js +11 -9
  84. package/lib/generates/internal/SdkWebSocketRouteProgrammer.js.map +1 -1
  85. package/lib/generates/internal/SwaggerOperationParameterComposer.js +10 -2
  86. package/lib/generates/internal/SwaggerOperationParameterComposer.js.map +1 -1
  87. package/lib/generates/internal/SwaggerOperationResponseComposer.d.ts +1 -1
  88. package/lib/generates/internal/SwaggerOperationResponseComposer.js +6 -1
  89. package/lib/generates/internal/SwaggerOperationResponseComposer.js.map +1 -1
  90. package/lib/generates/internal/SwaggerReadonlyArrayEmender.d.ts +9 -0
  91. package/lib/generates/internal/SwaggerReadonlyArrayEmender.js +174 -0
  92. package/lib/generates/internal/SwaggerReadonlyArrayEmender.js.map +1 -0
  93. package/lib/structures/INestiaSdkInput.d.ts +9 -2
  94. package/lib/structures/IReflectController.d.ts +2 -1
  95. package/lib/structures/IReflectHttpOperationSuccess.d.ts +4 -2
  96. package/lib/structures/IReflectMcpOperation.d.ts +35 -0
  97. package/lib/structures/IReflectMcpOperation.js +3 -0
  98. package/lib/structures/IReflectMcpOperation.js.map +1 -0
  99. package/lib/structures/IReflectMcpOperationParameter.d.ts +19 -0
  100. package/lib/structures/IReflectMcpOperationParameter.js +3 -0
  101. package/lib/structures/IReflectMcpOperationParameter.js.map +1 -0
  102. package/lib/structures/ITypedApplication.d.ts +2 -1
  103. package/lib/structures/ITypedHttpRouteSuccess.d.ts +3 -1
  104. package/lib/structures/ITypedMcpRoute.d.ts +31 -0
  105. package/lib/structures/ITypedMcpRoute.js +3 -0
  106. package/lib/structures/ITypedMcpRoute.js.map +1 -0
  107. package/lib/utils/HttpResponseContentTypeUtil.d.ts +5 -0
  108. package/lib/utils/HttpResponseContentTypeUtil.js +22 -0
  109. package/lib/utils/HttpResponseContentTypeUtil.js.map +1 -0
  110. package/native/go.mod +52 -52
  111. package/native/go.sum +84 -54
  112. package/native/sdk/register.go +322 -165
  113. package/native/sdk/sdk.go +17 -17
  114. package/native/sdk/sdk_metadata_json.go +327 -327
  115. package/native/sdk/sdk_transform.go +1879 -1549
  116. package/package.json +11 -9
  117. package/src/INestiaConfig.ts +267 -267
  118. package/src/NestiaSdkApplication.ts +39 -8
  119. package/src/NestiaSwaggerComposer.ts +153 -142
  120. package/src/analyses/AccessorAnalyzer.ts +64 -67
  121. package/src/analyses/ConfigAnalyzer.ts +330 -330
  122. package/src/analyses/ImportAnalyzer.ts +92 -92
  123. package/src/analyses/PathAnalyzer.ts +130 -69
  124. package/src/analyses/ReflectControllerAnalyzer.ts +112 -105
  125. package/src/analyses/ReflectHttpOperationAnalyzer.ts +183 -183
  126. package/src/analyses/ReflectHttpOperationExceptionAnalyzer.ts +90 -90
  127. package/src/analyses/ReflectHttpOperationParameterAnalyzer.ts +350 -350
  128. package/src/analyses/ReflectHttpOperationResponseAnalyzer.ts +163 -130
  129. package/src/analyses/ReflectMcpOperationAnalyzer.ts +124 -0
  130. package/src/analyses/ReflectMetadataAnalyzer.ts +44 -44
  131. package/src/analyses/SecurityAnalyzer.ts +25 -25
  132. package/src/analyses/TypedMcpRouteAnalyzer.ts +34 -0
  133. package/src/decorators/OperationMetadata.ts +29 -29
  134. package/src/executable/internal/CommandParser.ts +15 -15
  135. package/src/executable/internal/NestiaConfigLoader.ts +451 -446
  136. package/src/executable/internal/NestiaSdkCommand.ts +124 -106
  137. package/src/executable/internal/NestiaSdkWatcher.ts +342 -0
  138. package/src/executable/sdk.ts +90 -88
  139. package/src/generates/CloneGenerator.ts +73 -66
  140. package/src/generates/E2eGenerator.ts +32 -32
  141. package/src/generates/SdkGenerator.ts +176 -118
  142. package/src/generates/SwaggerGenerator.ts +342 -310
  143. package/src/generates/internal/E2eFileProgrammer.ts +240 -233
  144. package/src/generates/internal/FilePrinter.ts +65 -65
  145. package/src/generates/internal/ImportDictionary.ts +209 -204
  146. package/src/generates/internal/SdkAliasCollection.ts +274 -261
  147. package/src/generates/internal/SdkDistributionComposer.ts +123 -116
  148. package/src/generates/internal/SdkFileProgrammer.ts +116 -112
  149. package/src/generates/internal/SdkHttpCloneProgrammer.ts +126 -126
  150. package/src/generates/internal/SdkHttpCloneReferencer.ts +131 -77
  151. package/src/generates/internal/SdkHttpFunctionProgrammer.ts +301 -301
  152. package/src/generates/internal/SdkHttpNamespaceProgrammer.ts +520 -510
  153. package/src/generates/internal/SdkHttpParameterProgrammer.ts +165 -165
  154. package/src/generates/internal/SdkHttpRouteProgrammer.ts +109 -109
  155. package/src/generates/internal/SdkHttpSimulationProgrammer.ts +331 -314
  156. package/src/generates/internal/SdkImportWizard.ts +62 -62
  157. package/src/generates/internal/SdkMcpRouteProgrammer.ts +452 -0
  158. package/src/generates/internal/SdkRouteDirectory.ts +21 -18
  159. package/src/generates/internal/SdkTypeTagProgrammer.ts +114 -114
  160. package/src/generates/internal/SdkWebSocketCloneProgrammer.ts +319 -0
  161. package/src/generates/internal/SdkWebSocketNamespaceProgrammer.ts +389 -389
  162. package/src/generates/internal/SdkWebSocketParameterProgrammer.ts +89 -89
  163. package/src/generates/internal/SdkWebSocketRouteProgrammer.ts +331 -323
  164. package/src/generates/internal/SwaggerDescriptionComposer.ts +64 -64
  165. package/src/generates/internal/SwaggerOperationComposer.ts +119 -119
  166. package/src/generates/internal/SwaggerOperationParameterComposer.ts +175 -162
  167. package/src/generates/internal/SwaggerOperationResponseComposer.ts +115 -110
  168. package/src/generates/internal/SwaggerReadonlyArrayEmender.ts +262 -0
  169. package/src/index.ts +4 -4
  170. package/src/internal/legacy.ts +492 -492
  171. package/src/module.ts +4 -4
  172. package/src/structures/INestiaProject.ts +10 -10
  173. package/src/structures/INestiaSdkInput.ts +27 -20
  174. package/src/structures/IOperationMetadata.ts +41 -41
  175. package/src/structures/IReflectController.ts +18 -15
  176. package/src/structures/IReflectHttpOperation.ts +26 -26
  177. package/src/structures/IReflectHttpOperationException.ts +18 -18
  178. package/src/structures/IReflectHttpOperationParameter.ts +79 -79
  179. package/src/structures/IReflectHttpOperationSuccess.ts +18 -21
  180. package/src/structures/IReflectImport.ts +6 -6
  181. package/src/structures/IReflectMcpOperation.ts +38 -0
  182. package/src/structures/IReflectMcpOperationParameter.ts +27 -0
  183. package/src/structures/IReflectOperationError.ts +26 -26
  184. package/src/structures/IReflectType.ts +4 -4
  185. package/src/structures/IReflectWebSocketOperation.ts +17 -17
  186. package/src/structures/ITypedApplication.ts +12 -11
  187. package/src/structures/ITypedHttpRoute.ts +41 -41
  188. package/src/structures/ITypedHttpRouteException.ts +15 -15
  189. package/src/structures/ITypedHttpRouteParameter.ts +41 -41
  190. package/src/structures/ITypedHttpRouteSuccess.ts +18 -22
  191. package/src/structures/ITypedMcpRoute.ts +33 -0
  192. package/src/structures/ITypedWebSocketRoute.ts +24 -24
  193. package/src/structures/ITypedWebSocketRouteParameter.ts +3 -3
  194. package/src/transform.ts +59 -59
  195. package/src/typings/get-function-location.d.ts +7 -7
  196. package/src/utils/ArrayUtil.ts +26 -26
  197. package/src/utils/EmittedJavaScriptPatcher.ts +88 -88
  198. package/src/utils/FileRetriever.ts +22 -22
  199. package/src/utils/HttpResponseContentTypeUtil.ts +30 -0
  200. package/src/utils/MapUtil.ts +14 -14
  201. package/src/utils/PathUtil.ts +10 -10
  202. package/src/utils/SourceFinder.ts +63 -63
  203. package/src/utils/StringUtil.ts +17 -17
  204. package/src/utils/TsConfigReader.ts +108 -108
  205. package/src/utils/TtscExecutor.ts +68 -68
  206. package/src/utils/VersioningStrategy.ts +28 -28
  207. package/src/validators/HttpHeadersValidator.ts +11 -11
  208. package/src/validators/HttpQueryValidator.ts +11 -11
  209. package/src/validators/TextPlainValidator.ts +17 -17
@@ -1,130 +1,163 @@
1
- import { SwaggerExample } from "@nestia/core";
2
- import {
3
- HEADERS_METADATA,
4
- HTTP_CODE_METADATA,
5
- INTERCEPTORS_METADATA,
6
- } from "@nestjs/common/constants";
7
- import { HttpQueryProgrammer, JsonMetadataFactory, sizeOf } from "../internal/legacy";
8
-
9
- import { IReflectController } from "../structures/IReflectController";
10
- import { IReflectHttpOperationSuccess } from "../structures/IReflectHttpOperationSuccess";
11
- import { IReflectOperationError } from "../structures/IReflectOperationError";
12
- import { IOperationMetadata } from "../structures/IOperationMetadata";
13
- import { TextPlainValidator } from "../validators/TextPlainValidator";
14
-
15
- export namespace ReflectHttpOperationResponseAnalyzer {
16
- export interface IContext {
17
- controller: IReflectController;
18
- function: Function;
19
- functionName: string;
20
- httpMethod: string;
21
- metadata: IOperationMetadata;
22
- errors: IReflectOperationError[];
23
- }
24
-
25
- export const analyze = (
26
- ctx: IContext,
27
- ): IReflectHttpOperationSuccess | null => {
28
- const errors: Array<string | IOperationMetadata.IError> = [];
29
- const report = () => {
30
- ctx.errors.push({
31
- file: ctx.controller.file,
32
- class: ctx.controller.class.name,
33
- function: ctx.functionName,
34
- from: "return",
35
- contents: errors,
36
- });
37
- return null;
38
- };
39
-
40
- const encrypted: boolean = hasInterceptor({
41
- name: "EncryptedRouteInterceptor",
42
- function: ctx.function,
43
- });
44
- const contentType: string | null = encrypted
45
- ? "text/plain"
46
- : hasInterceptor({
47
- name: "TypedQueryRouteInterceptor",
48
- function: ctx.function,
49
- })
50
- ? "application/x-www-form-urlencoded"
51
- : (Reflect.getMetadata(HEADERS_METADATA, ctx.function)?.find(
52
- (h: Record<string, string>) =>
53
- typeof h?.name === "string" &&
54
- typeof h?.value === "string" &&
55
- h.name.toLowerCase() === "content-type",
56
- )?.value ??
57
- Reflect.getMetadata("swagger/apiProduces", ctx.function)?.[0] ??
58
- (ctx.httpMethod === "HEAD" ? null : "application/json"));
59
-
60
- const schema =
61
- contentType === "application/json"
62
- ? ctx.metadata.success.primitive
63
- : ctx.metadata.success.resolved;
64
- if (schema.success === false) errors.push(...schema.errors);
65
- if (ctx.httpMethod === "HEAD" && contentType !== null)
66
- errors.push(`HEAD method must not have a content type.`);
67
- if (isContentType(contentType) === false)
68
- errors.push(
69
- `@nestia/sdk does not support ${JSON.stringify(contentType)} content type.`,
70
- );
71
-
72
- if (errors.length) return report();
73
- else if (
74
- ctx.metadata.success.type === null ||
75
- schema.success === false ||
76
- !isContentType(contentType)
77
- )
78
- return null;
79
-
80
- const example: SwaggerExample.IData<any> | undefined = Reflect.getMetadata(
81
- "nestia/SwaggerExample/Response",
82
- ctx.function,
83
- );
84
- return {
85
- contentType,
86
- encrypted,
87
- status:
88
- getStatus(ctx.function) ?? (ctx.httpMethod === "POST" ? 201 : 200),
89
- type: ctx.metadata.success.type,
90
- ...schema.data,
91
- validate:
92
- contentType === "application/json" || encrypted === true
93
- ? JsonMetadataFactory.validate
94
- : contentType === "application/x-www-form-urlencoded"
95
- ? HttpQueryProgrammer.validate
96
- : contentType === "text/plain"
97
- ? TextPlainValidator.validate
98
- : (next) =>
99
- sizeOf(next.metadata) !== 0
100
- ? ["HEAD method must not have any return value."]
101
- : [],
102
- example: example?.example,
103
- examples: example?.examples,
104
- };
105
- };
106
-
107
- const getStatus = (func: Function): number | null => {
108
- const text = Reflect.getMetadata(HTTP_CODE_METADATA, func);
109
- if (text === undefined) return null;
110
- const value: number = Number(text);
111
- return isNaN(value) ? null : value;
112
- };
113
-
114
- const hasInterceptor = (props: {
115
- name: string;
116
- function: Function;
117
- }): boolean => {
118
- const meta = Reflect.getMetadata(INTERCEPTORS_METADATA, props.function);
119
- if (Array.isArray(meta) === false) return false;
120
- return meta.some((elem) => elem?.constructor?.name === props.name);
121
- };
122
-
123
- const isContentType = (
124
- input: string | null,
125
- ): input is IReflectHttpOperationSuccess["contentType"] =>
126
- input === null ||
127
- input === "application/json" ||
128
- input === "text/plain" ||
129
- input === "application/x-www-form-urlencoded";
130
- }
1
+ import { SwaggerExample } from "@nestia/core";
2
+ import {
3
+ HEADERS_METADATA,
4
+ HTTP_CODE_METADATA,
5
+ INTERCEPTORS_METADATA,
6
+ } from "@nestjs/common/constants";
7
+
8
+ import {
9
+ HttpQueryProgrammer,
10
+ JsonMetadataFactory,
11
+ sizeOf,
12
+ } from "../internal/legacy";
13
+ import { IOperationMetadata } from "../structures/IOperationMetadata";
14
+ import { IReflectController } from "../structures/IReflectController";
15
+ import { IReflectHttpOperationSuccess } from "../structures/IReflectHttpOperationSuccess";
16
+ import { IReflectOperationError } from "../structures/IReflectOperationError";
17
+ import { HttpResponseContentTypeUtil } from "../utils/HttpResponseContentTypeUtil";
18
+ import { TextPlainValidator } from "../validators/TextPlainValidator";
19
+
20
+ export namespace ReflectHttpOperationResponseAnalyzer {
21
+ export interface IContext {
22
+ controller: IReflectController;
23
+ function: Function;
24
+ functionName: string;
25
+ httpMethod: string;
26
+ metadata: IOperationMetadata;
27
+ errors: IReflectOperationError[];
28
+ }
29
+
30
+ export const analyze = (
31
+ ctx: IContext,
32
+ ): IReflectHttpOperationSuccess | null => {
33
+ const errors: Array<string | IOperationMetadata.IError> = [];
34
+ const report = () => {
35
+ ctx.errors.push({
36
+ file: ctx.controller.file,
37
+ class: ctx.controller.class.name,
38
+ function: ctx.functionName,
39
+ from: "return",
40
+ contents: errors,
41
+ });
42
+ return null;
43
+ };
44
+
45
+ const encrypted: boolean = hasInterceptor({
46
+ name: "EncryptedRouteInterceptor",
47
+ function: ctx.function,
48
+ });
49
+ const contentType: string | null = encrypted
50
+ ? "text/plain"
51
+ : hasInterceptor({
52
+ name: "TypedQueryRouteInterceptor",
53
+ function: ctx.function,
54
+ })
55
+ ? "application/x-www-form-urlencoded"
56
+ : (Reflect.getMetadata(HEADERS_METADATA, ctx.function)?.find(
57
+ (h: Record<string, string>) =>
58
+ typeof h?.name === "string" &&
59
+ typeof h?.value === "string" &&
60
+ h.name.toLowerCase() === "content-type",
61
+ )?.value ??
62
+ Reflect.getMetadata("swagger/apiProduces", ctx.function)?.[0] ??
63
+ (ctx.httpMethod === "HEAD" ? null : "application/json"));
64
+
65
+ const binary: boolean = HttpResponseContentTypeUtil.isBinary(contentType);
66
+ const schema = binary
67
+ ? { success: true as const, data: EMPTY_SCHEMA }
68
+ : contentType === "application/json"
69
+ ? ctx.metadata.success.primitive
70
+ : ctx.metadata.success.resolved;
71
+ if (schema.success === false) errors.push(...schema.errors);
72
+ if (ctx.httpMethod === "HEAD" && contentType !== null)
73
+ errors.push(`HEAD method must not have a content type.`);
74
+ if (HttpResponseContentTypeUtil.isSupported(contentType) === false)
75
+ errors.push(
76
+ `@nestia/sdk does not support ${JSON.stringify(contentType)} content type.`,
77
+ );
78
+
79
+ if (errors.length) return report();
80
+ else if (
81
+ (binary === false && ctx.metadata.success.type === null) ||
82
+ schema.success === false ||
83
+ !HttpResponseContentTypeUtil.isSupported(contentType)
84
+ )
85
+ return null;
86
+
87
+ const example: SwaggerExample.IData<any> | undefined = Reflect.getMetadata(
88
+ "nestia/SwaggerExample/Response",
89
+ ctx.function,
90
+ );
91
+ return {
92
+ contentType,
93
+ binary,
94
+ encrypted,
95
+ status:
96
+ getStatus(ctx.function) ?? (ctx.httpMethod === "POST" ? 201 : 200),
97
+ type: ctx.metadata.success.type ?? { name: "ReadableStream" },
98
+ ...schema.data,
99
+ validate:
100
+ binary === true
101
+ ? () => []
102
+ : contentType === "application/json" || encrypted === true
103
+ ? JsonMetadataFactory.validate
104
+ : contentType === "application/x-www-form-urlencoded"
105
+ ? HttpQueryProgrammer.validate
106
+ : contentType === "text/plain"
107
+ ? TextPlainValidator.validate
108
+ : (next) =>
109
+ sizeOf(next.metadata) !== 0
110
+ ? ["HEAD method must not have any return value."]
111
+ : [],
112
+ example: example?.example,
113
+ examples: example?.examples,
114
+ };
115
+ };
116
+
117
+ const getStatus = (func: Function): number | null => {
118
+ const text = Reflect.getMetadata(HTTP_CODE_METADATA, func);
119
+ if (text === undefined) return null;
120
+ const value: number = Number(text);
121
+ return isNaN(value) ? null : value;
122
+ };
123
+
124
+ const hasInterceptor = (props: {
125
+ name: string;
126
+ function: Function;
127
+ }): boolean => {
128
+ const meta = Reflect.getMetadata(INTERCEPTORS_METADATA, props.function);
129
+ if (Array.isArray(meta) === false) return false;
130
+ return meta.some((elem) => elem?.constructor?.name === props.name);
131
+ };
132
+
133
+ const EMPTY_SCHEMA: IOperationMetadata.ISchema = {
134
+ components: {
135
+ aliases: [],
136
+ arrays: [],
137
+ objects: [],
138
+ tuples: [],
139
+ },
140
+ metadata: {
141
+ aliases: [],
142
+ any: false,
143
+ arrays: [],
144
+ atomics: [],
145
+ constants: [],
146
+ escaped: null,
147
+ functions: [],
148
+ maps: [],
149
+ natives: [],
150
+ nullable: false,
151
+ objects: [],
152
+ optional: false,
153
+ required: true,
154
+ rest: null,
155
+ sets: [],
156
+ templates: [],
157
+ tuples: [],
158
+ size: 0,
159
+ name: "void",
160
+ empty: true,
161
+ } as IOperationMetadata.ISchema["metadata"],
162
+ };
163
+ }
@@ -0,0 +1,124 @@
1
+ import { METHOD_METADATA, PATH_METADATA } from "@nestjs/common/constants";
2
+
3
+ import { INestiaProject } from "../structures/INestiaProject";
4
+ import { IOperationMetadata } from "../structures/IOperationMetadata";
5
+ import { IReflectController } from "../structures/IReflectController";
6
+ import { IReflectImport } from "../structures/IReflectImport";
7
+ import { IReflectMcpOperation } from "../structures/IReflectMcpOperation";
8
+ import { IReflectMcpOperationParameter } from "../structures/IReflectMcpOperationParameter";
9
+ import { ImportAnalyzer } from "./ImportAnalyzer";
10
+
11
+ export namespace ReflectMcpOperationAnalyzer {
12
+ export interface IProps {
13
+ project: Omit<INestiaProject, "config">;
14
+ controller: IReflectController;
15
+ function: Function;
16
+ name: string;
17
+ metadata: IOperationMetadata;
18
+ }
19
+
20
+ export const analyze = (ctx: IProps): IReflectMcpOperation | null => {
21
+ const route:
22
+ | {
23
+ name: string;
24
+ title?: string;
25
+ description?: string;
26
+ inputSchema: object;
27
+ outputSchema?: object;
28
+ annotations?: IReflectMcpOperation.IAnnotations;
29
+ }
30
+ | undefined = Reflect.getMetadata("nestia/McpRoute", ctx.function);
31
+ if (route === undefined) return null;
32
+
33
+ const errors: string[] = [];
34
+ const hasHttpRoute: boolean =
35
+ Reflect.getMetadata(PATH_METADATA, ctx.function) !== undefined ||
36
+ Reflect.getMetadata(METHOD_METADATA, ctx.function) !== undefined;
37
+ const hasWebSocketRoute: boolean =
38
+ Reflect.getMetadata("nestia/WebSocketRoute", ctx.function) !== undefined;
39
+
40
+ if (hasHttpRoute || hasWebSocketRoute)
41
+ errors.push(
42
+ "@McpRoute must not be combined with HTTP or WebSocket route decorators on the same method.",
43
+ );
44
+
45
+ const preconfigured: IReflectMcpOperationParameter.IPreconfigured[] = (
46
+ (Reflect.getMetadata(
47
+ "nestia/McpRoute/Parameters",
48
+ ctx.controller.class.prototype,
49
+ ctx.name,
50
+ ) ?? []) as IReflectMcpOperationParameter.IPreconfigured[]
51
+ ).sort((a, b) => a.index - b.index);
52
+
53
+ if (preconfigured.length > 1)
54
+ errors.push(
55
+ "@McpRoute tools may declare at most one @McpRoute.Params() parameter.",
56
+ );
57
+ if (ctx.function.length > 1)
58
+ errors.push(
59
+ "@McpRoute tools must have 0 or 1 parameters (the MCP arguments object).",
60
+ );
61
+
62
+ const imports: IReflectImport[] = [];
63
+ const parameters: IReflectMcpOperationParameter[] = preconfigured
64
+ .map((p) => {
65
+ const matched: IOperationMetadata.IParameter | undefined =
66
+ ctx.metadata.parameters.find(
67
+ (m: IOperationMetadata.IParameter) => p.index === m.index,
68
+ );
69
+ if (matched === undefined) {
70
+ errors.push(
71
+ `Unable to find parameter type of the ${p.index} (th) argument.`,
72
+ );
73
+ return null;
74
+ }
75
+ if (matched.type === null) {
76
+ errors.push(
77
+ `Failed to analyze the parameter type of ${JSON.stringify(matched.name)}.`,
78
+ );
79
+ return null;
80
+ }
81
+ imports.push(...matched.imports);
82
+ return {
83
+ category: "params" as const,
84
+ name: matched.name,
85
+ index: p.index,
86
+ type: matched.type,
87
+ imports: matched.imports,
88
+ description: matched.description,
89
+ jsDocTags: matched.jsDocTags,
90
+ };
91
+ })
92
+ .filter((p): p is IReflectMcpOperationParameter => !!p);
93
+
94
+ if (ctx.metadata.success?.imports?.length)
95
+ imports.push(...ctx.metadata.success.imports);
96
+
97
+ if (errors.length) {
98
+ ctx.project.errors.push({
99
+ file: ctx.controller.file,
100
+ class: ctx.controller.class.name,
101
+ function: ctx.function.name,
102
+ from: ctx.name,
103
+ contents: errors,
104
+ });
105
+ return null;
106
+ }
107
+ return {
108
+ protocol: "mcp",
109
+ name: ctx.name,
110
+ toolName: route.name,
111
+ title: route.title ?? null,
112
+ toolDescription: route.description ?? null,
113
+ inputSchema: route.inputSchema,
114
+ outputSchema: route.outputSchema ?? null,
115
+ annotations: route.annotations ?? null,
116
+ function: ctx.function,
117
+ parameters,
118
+ returnType: ctx.metadata.success?.type ?? null,
119
+ imports: ImportAnalyzer.merge(imports),
120
+ description: ctx.metadata.description ?? null,
121
+ jsDocTags: ctx.metadata.jsDocTags,
122
+ };
123
+ };
124
+ }
@@ -1,44 +1,44 @@
1
- import { VERSION_NEUTRAL } from "@nestjs/common";
2
- import { PATH_METADATA, VERSION_METADATA } from "@nestjs/common/constants";
3
- import { VersionValue } from "@nestjs/common/interfaces";
4
-
5
- import { SecurityAnalyzer } from "./SecurityAnalyzer";
6
-
7
- export namespace ReflectMetadataAnalyzer {
8
- export const paths = (target: Function): string[] => {
9
- const value: string | string[] = Reflect.getMetadata(PATH_METADATA, target);
10
- if (typeof value === "string") return [value];
11
- else if (value.length === 0) return [""];
12
- else return value;
13
- };
14
-
15
- export const extensions = (value: any): Record<string, any> => {
16
- const entire: Record<string, any>[] | undefined = Reflect.getMetadata(
17
- "swagger/apiExtension",
18
- value,
19
- );
20
- return entire ?? {};
21
- };
22
-
23
- export const securities = (value: any): Record<string, string[]>[] => {
24
- const entire: Record<string, string[]>[] | undefined = Reflect.getMetadata(
25
- "swagger/apiSecurity",
26
- value,
27
- );
28
- return entire ? SecurityAnalyzer.merge(...entire) : [];
29
- };
30
-
31
- export const versions = (
32
- target: any,
33
- ): Array<string | typeof VERSION_NEUTRAL> | undefined => {
34
- const value: VersionValue | undefined = Reflect.getMetadata(
35
- VERSION_METADATA,
36
- target,
37
- );
38
- return value === undefined
39
- ? undefined
40
- : Array.isArray(value)
41
- ? value
42
- : [value];
43
- };
44
- }
1
+ import { VERSION_NEUTRAL } from "@nestjs/common";
2
+ import { PATH_METADATA, VERSION_METADATA } from "@nestjs/common/constants";
3
+ import { VersionValue } from "@nestjs/common/interfaces";
4
+
5
+ import { SecurityAnalyzer } from "./SecurityAnalyzer";
6
+
7
+ export namespace ReflectMetadataAnalyzer {
8
+ export const paths = (target: Function): string[] => {
9
+ const value: string | string[] = Reflect.getMetadata(PATH_METADATA, target);
10
+ if (typeof value === "string") return [value];
11
+ else if (value.length === 0) return [""];
12
+ else return value;
13
+ };
14
+
15
+ export const extensions = (value: any): Record<string, any> => {
16
+ const entire: Record<string, any>[] | undefined = Reflect.getMetadata(
17
+ "swagger/apiExtension",
18
+ value,
19
+ );
20
+ return entire ?? {};
21
+ };
22
+
23
+ export const securities = (value: any): Record<string, string[]>[] => {
24
+ const entire: Record<string, string[]>[] | undefined = Reflect.getMetadata(
25
+ "swagger/apiSecurity",
26
+ value,
27
+ );
28
+ return entire ? SecurityAnalyzer.merge(...entire) : [];
29
+ };
30
+
31
+ export const versions = (
32
+ target: any,
33
+ ): Array<string | typeof VERSION_NEUTRAL> | undefined => {
34
+ const value: VersionValue | undefined = Reflect.getMetadata(
35
+ VERSION_METADATA,
36
+ target,
37
+ );
38
+ return value === undefined
39
+ ? undefined
40
+ : Array.isArray(value)
41
+ ? value
42
+ : [value];
43
+ };
44
+ }
@@ -1,25 +1,25 @@
1
- import { MapUtil } from "../utils/MapUtil";
2
-
3
- export namespace SecurityAnalyzer {
4
- export const merge = (...entire: Record<string, string[]>[]) => {
5
- const dict: Map<string | typeof none, Set<string>> = new Map();
6
- for (const obj of entire) {
7
- const entries = Object.entries(obj);
8
- for (const [key, value] of entries) {
9
- const set = MapUtil.take(dict, key, () => new Set());
10
- for (const val of value) set.add(val);
11
- }
12
- if (entries.length === 0) MapUtil.take(dict, none, () => new Set());
13
- }
14
- const output: Record<string, string[]>[] = [];
15
- for (const [key, set] of dict)
16
- key === none
17
- ? output.push({})
18
- : output.push({
19
- [key]: [...set],
20
- });
21
- return output;
22
- };
23
-
24
- const none = Symbol("none");
25
- }
1
+ import { MapUtil } from "../utils/MapUtil";
2
+
3
+ export namespace SecurityAnalyzer {
4
+ export const merge = (...entire: Record<string, string[]>[]) => {
5
+ const dict: Map<string | typeof none, Set<string>> = new Map();
6
+ for (const obj of entire) {
7
+ const entries = Object.entries(obj);
8
+ for (const [key, value] of entries) {
9
+ const set = MapUtil.take(dict, key, () => new Set());
10
+ for (const val of value) set.add(val);
11
+ }
12
+ if (entries.length === 0) MapUtil.take(dict, none, () => new Set());
13
+ }
14
+ const output: Record<string, string[]>[] = [];
15
+ for (const [key, set] of dict)
16
+ key === none
17
+ ? output.push({})
18
+ : output.push({
19
+ [key]: [...set],
20
+ });
21
+ return output;
22
+ };
23
+
24
+ const none = Symbol("none");
25
+ }
@@ -0,0 +1,34 @@
1
+ import { IReflectController } from "../structures/IReflectController";
2
+ import { IReflectMcpOperation } from "../structures/IReflectMcpOperation";
3
+ import { ITypedMcpRoute } from "../structures/ITypedMcpRoute";
4
+
5
+ export namespace TypedMcpRouteAnalyzer {
6
+ export const analyze = (props: {
7
+ controller: IReflectController;
8
+ operation: IReflectMcpOperation;
9
+ }): ITypedMcpRoute[] => [
10
+ {
11
+ protocol: "mcp",
12
+ controller: props.controller,
13
+ name: props.operation.name,
14
+ toolName: props.operation.toolName,
15
+ title: props.operation.title,
16
+ toolDescription: props.operation.toolDescription,
17
+ accessor: accessor(props.operation.toolName),
18
+ function: props.operation.function,
19
+ input: props.operation.parameters[0] ?? null,
20
+ returnType: props.operation.returnType,
21
+ inputSchema: props.operation.inputSchema,
22
+ outputSchema: props.operation.outputSchema,
23
+ annotations: props.operation.annotations,
24
+ imports: props.operation.imports,
25
+ description: props.operation.description,
26
+ jsDocTags: props.operation.jsDocTags,
27
+ },
28
+ ];
29
+
30
+ const accessor = (toolName: string): string[] => {
31
+ const safe = toolName.replace(/[^A-Za-z0-9_$]/g, "_");
32
+ return ["mcp", safe];
33
+ };
34
+ }
@@ -1,29 +1,29 @@
1
- import { IOperationMetadata } from "../structures/IOperationMetadata";
2
-
3
- /**
4
- * Carries the compile-time operation metadata the SDK / Swagger / e2e
5
- * generators read through `Reflect.getMetadata("nestia/OperationMetadata")`.
6
- *
7
- * The `@nestia/sdk` native transform injects this decorator as a synthesized
8
- * AST node, so its argument is a single JSON string literal rather than an
9
- * object literal — keeping the constructed node tree minimal. The string is
10
- * parsed once here at module-evaluation time. A pre-parsed `IOperationMetadata`
11
- * object is still accepted for hand-written or test usage.
12
- */
13
- export function OperationMetadata(
14
- metadata: IOperationMetadata | string,
15
- ): MethodDecorator {
16
- const parsed: IOperationMetadata =
17
- typeof metadata === "string"
18
- ? (JSON.parse(metadata) as IOperationMetadata)
19
- : metadata;
20
- return function OperationMetadata(target, propertyKey, descriptor) {
21
- Reflect.defineMetadata(
22
- "nestia/OperationMetadata",
23
- parsed,
24
- target,
25
- propertyKey,
26
- );
27
- return descriptor;
28
- };
29
- }
1
+ import { IOperationMetadata } from "../structures/IOperationMetadata";
2
+
3
+ /**
4
+ * Carries the compile-time operation metadata the SDK / Swagger / e2e
5
+ * generators read through `Reflect.getMetadata("nestia/OperationMetadata")`.
6
+ *
7
+ * The `@nestia/sdk` native transform injects this decorator as a synthesized
8
+ * AST node, so its argument is a single JSON string literal rather than an
9
+ * object literal — keeping the constructed node tree minimal. The string is
10
+ * parsed once here at module-evaluation time. A pre-parsed `IOperationMetadata`
11
+ * object is still accepted for hand-written or test usage.
12
+ */
13
+ export function OperationMetadata(
14
+ metadata: IOperationMetadata | string,
15
+ ): MethodDecorator {
16
+ const parsed: IOperationMetadata =
17
+ typeof metadata === "string"
18
+ ? (JSON.parse(metadata) as IOperationMetadata)
19
+ : metadata;
20
+ return function OperationMetadata(target, propertyKey, descriptor) {
21
+ Reflect.defineMetadata(
22
+ "nestia/OperationMetadata",
23
+ parsed,
24
+ target,
25
+ propertyKey,
26
+ );
27
+ return descriptor;
28
+ };
29
+ }