@tsgonest/runtime 0.0.1
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/dist/config.d.ts +54 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +29 -0
- package/dist/config.js.map +1 -0
- package/dist/discovery.d.ts +89 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +159 -0
- package/dist/discovery.js.map +1 -0
- package/dist/errors.d.ts +20 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +19 -0
- package/dist/errors.js.map +1 -0
- package/dist/fast-interceptor.d.ts +82 -0
- package/dist/fast-interceptor.d.ts.map +1 -0
- package/dist/fast-interceptor.js +145 -0
- package/dist/fast-interceptor.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/serialization.d.ts +65 -0
- package/dist/serialization.d.ts.map +1 -0
- package/dist/serialization.js +123 -0
- package/dist/serialization.js.map +1 -0
- package/dist/validation-pipe.d.ts +79 -0
- package/dist/validation-pipe.d.ts.map +1 -0
- package/dist/validation-pipe.js +154 -0
- package/dist/validation-pipe.js.map +1 -0
- package/package.json +58 -0
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for tsgonest.
|
|
3
|
+
*/
|
|
4
|
+
export interface TsgonestConfig {
|
|
5
|
+
/** Controller file discovery patterns. */
|
|
6
|
+
controllers?: {
|
|
7
|
+
/** Glob patterns for controller files to include. */
|
|
8
|
+
include?: string[];
|
|
9
|
+
/** Glob patterns for files to exclude. */
|
|
10
|
+
exclude?: string[];
|
|
11
|
+
};
|
|
12
|
+
/** Code transformation settings. */
|
|
13
|
+
transforms?: {
|
|
14
|
+
/** Generate validation companion files. */
|
|
15
|
+
validation?: boolean;
|
|
16
|
+
/** Generate serialization companion files. */
|
|
17
|
+
serialization?: boolean;
|
|
18
|
+
};
|
|
19
|
+
/** OpenAPI document generation settings. */
|
|
20
|
+
openapi?: {
|
|
21
|
+
/** Output path for the generated OpenAPI document. */
|
|
22
|
+
output?: string;
|
|
23
|
+
/** API title for the OpenAPI info section. */
|
|
24
|
+
title?: string;
|
|
25
|
+
/** API version for the OpenAPI info section. */
|
|
26
|
+
version?: string;
|
|
27
|
+
/** API description for the OpenAPI info section. */
|
|
28
|
+
description?: string;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Type-safe config helper for tsgonest.config.ts.
|
|
33
|
+
* Provides autocomplete and validation for the config object.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* import { defineConfig } from "@tsgonest/runtime";
|
|
38
|
+
*
|
|
39
|
+
* export default defineConfig({
|
|
40
|
+
* controllers: {
|
|
41
|
+
* include: ["src/**\/*.controller.ts"],
|
|
42
|
+
* },
|
|
43
|
+
* transforms: {
|
|
44
|
+
* validation: true,
|
|
45
|
+
* serialization: true,
|
|
46
|
+
* },
|
|
47
|
+
* openapi: {
|
|
48
|
+
* output: "dist/openapi.json",
|
|
49
|
+
* },
|
|
50
|
+
* });
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export declare function defineConfig(config: TsgonestConfig): TsgonestConfig;
|
|
54
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,0CAA0C;IAC1C,WAAW,CAAC,EAAE;QACZ,qDAAqD;QACrD,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;QACnB,0CAA0C;QAC1C,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC;IAEF,oCAAoC;IACpC,UAAU,CAAC,EAAE;QACX,2CAA2C;QAC3C,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,8CAA8C;QAC9C,aAAa,CAAC,EAAE,OAAO,CAAC;KACzB,CAAC;IAEF,4CAA4C;IAC5C,OAAO,CAAC,EAAE;QACR,sDAAsD;QACtD,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,8CAA8C;QAC9C,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,gDAAgD;QAChD,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,oDAAoD;QACpD,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;CACH;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,cAAc,GAAG,cAAc,CAEnE"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.defineConfig = defineConfig;
|
|
4
|
+
/**
|
|
5
|
+
* Type-safe config helper for tsgonest.config.ts.
|
|
6
|
+
* Provides autocomplete and validation for the config object.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { defineConfig } from "@tsgonest/runtime";
|
|
11
|
+
*
|
|
12
|
+
* export default defineConfig({
|
|
13
|
+
* controllers: {
|
|
14
|
+
* include: ["src/**\/*.controller.ts"],
|
|
15
|
+
* },
|
|
16
|
+
* transforms: {
|
|
17
|
+
* validation: true,
|
|
18
|
+
* serialization: true,
|
|
19
|
+
* },
|
|
20
|
+
* openapi: {
|
|
21
|
+
* output: "dist/openapi.json",
|
|
22
|
+
* },
|
|
23
|
+
* });
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
function defineConfig(config) {
|
|
27
|
+
return config;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";;AAuDA,oCAEC;AAxBD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,SAAgB,YAAY,CAAC,MAAsB;IACjD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route mapping entry — maps a controller method to its return type.
|
|
3
|
+
* Key format in the manifest: "ControllerName.methodName"
|
|
4
|
+
*/
|
|
5
|
+
export interface RouteMapping {
|
|
6
|
+
/** The DTO type name (e.g., "UserResponse"). */
|
|
7
|
+
returnType: string;
|
|
8
|
+
/** Whether the method returns an array of the return type. */
|
|
9
|
+
isArray?: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* The manifest file generated by tsgonest during compilation.
|
|
13
|
+
* Maps DTO type names to their companion file paths and function names.
|
|
14
|
+
*/
|
|
15
|
+
export interface TsgonestManifest {
|
|
16
|
+
validators: Record<string, ManifestEntry>;
|
|
17
|
+
serializers: Record<string, ManifestEntry>;
|
|
18
|
+
routes?: Record<string, RouteMapping>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* A single entry in the manifest, pointing to a companion file and exported function.
|
|
22
|
+
*/
|
|
23
|
+
export interface ManifestEntry {
|
|
24
|
+
/** Relative path to the companion JS file. */
|
|
25
|
+
file: string;
|
|
26
|
+
/** Name of the exported function in the companion file. */
|
|
27
|
+
fn: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Discovers and loads companion file functions from the tsgonest manifest.
|
|
31
|
+
*/
|
|
32
|
+
export declare class CompanionDiscovery {
|
|
33
|
+
private manifest;
|
|
34
|
+
private manifestDir;
|
|
35
|
+
private cache;
|
|
36
|
+
/**
|
|
37
|
+
* Load the manifest from a directory.
|
|
38
|
+
* Searches for __tsgonest_manifest.json in the given directory.
|
|
39
|
+
*/
|
|
40
|
+
loadManifest(distDir: string): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Load the manifest from a JSON string.
|
|
43
|
+
* Used for testing or when the manifest is embedded.
|
|
44
|
+
*/
|
|
45
|
+
loadManifestFromJSON(json: string, baseDir: string): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Get a validator function for a DTO type name.
|
|
48
|
+
* Returns the assert function that throws on invalid input.
|
|
49
|
+
*/
|
|
50
|
+
getValidator(typeName: string): ((input: unknown) => unknown) | null;
|
|
51
|
+
/**
|
|
52
|
+
* Get a serializer function for a DTO type name.
|
|
53
|
+
* Returns a function that converts the input to a JSON string.
|
|
54
|
+
*/
|
|
55
|
+
getSerializer(typeName: string): ((input: unknown) => string) | null;
|
|
56
|
+
/**
|
|
57
|
+
* Check if a validator exists for a type.
|
|
58
|
+
*/
|
|
59
|
+
hasValidator(typeName: string): boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Check if a serializer exists for a type.
|
|
62
|
+
*/
|
|
63
|
+
hasSerializer(typeName: string): boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Get all registered validator type names.
|
|
66
|
+
*/
|
|
67
|
+
getValidatorTypes(): string[];
|
|
68
|
+
/**
|
|
69
|
+
* Get all registered serializer type names.
|
|
70
|
+
*/
|
|
71
|
+
getSerializerTypes(): string[];
|
|
72
|
+
/**
|
|
73
|
+
* Look up the return type for a controller method from the route map.
|
|
74
|
+
* @param controllerName The controller class name (e.g., "UserController").
|
|
75
|
+
* @param methodName The method name (e.g., "findAll").
|
|
76
|
+
* @returns The route mapping or null if not found.
|
|
77
|
+
*/
|
|
78
|
+
getRouteMapping(controllerName: string, methodName: string): RouteMapping | null;
|
|
79
|
+
/**
|
|
80
|
+
* Get a serializer function for a controller method, using the route map.
|
|
81
|
+
* This is the primary lookup path for the fast interceptor — no Reflect metadata needed.
|
|
82
|
+
* @returns An object with the serializer function and whether it's an array, or null.
|
|
83
|
+
*/
|
|
84
|
+
getSerializerForRoute(controllerName: string, methodName: string): {
|
|
85
|
+
serializer: (input: unknown) => string;
|
|
86
|
+
isArray: boolean;
|
|
87
|
+
} | null;
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=discovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,gDAAgD;IAChD,UAAU,EAAE,MAAM,CAAC;IACnB,8DAA8D;IAC9D,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC1C,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC3C,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;CACvC;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,2DAA2D;IAC3D,EAAE,EAAE,MAAM,CAAC;CACZ;AAUD;;GAEG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAiC;IACjD,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,KAAK,CAGX;IAEF;;;OAGG;IACH,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAgBtC;;;OAGG;IACH,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO;IAU5D;;;OAGG;IACH,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,GAAG,IAAI;IAyBpE;;;OAGG;IACH,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,CAAC,GAAG,IAAI;IAyBpE;;OAEG;IACH,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAIvC;;OAEG;IACH,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAIxC;;OAEG;IACH,iBAAiB,IAAI,MAAM,EAAE;IAI7B;;OAEG;IACH,kBAAkB,IAAI,MAAM,EAAE;IAI9B;;;;;OAKG;IACH,eAAe,CAAC,cAAc,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI;IAMhF;;;;OAIG;IACH,qBAAqB,CACnB,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,GACjB;QAAE,UAAU,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI;CASvE"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CompanionDiscovery = void 0;
|
|
4
|
+
const path_1 = require("path");
|
|
5
|
+
const fs_1 = require("fs");
|
|
6
|
+
/**
|
|
7
|
+
* Discovers and loads companion file functions from the tsgonest manifest.
|
|
8
|
+
*/
|
|
9
|
+
class CompanionDiscovery {
|
|
10
|
+
manifest = null;
|
|
11
|
+
manifestDir = '';
|
|
12
|
+
cache = {
|
|
13
|
+
validators: new Map(),
|
|
14
|
+
serializers: new Map(),
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Load the manifest from a directory.
|
|
18
|
+
* Searches for __tsgonest_manifest.json in the given directory.
|
|
19
|
+
*/
|
|
20
|
+
loadManifest(distDir) {
|
|
21
|
+
const manifestPath = (0, path_1.join)(distDir, '__tsgonest_manifest.json');
|
|
22
|
+
if (!(0, fs_1.existsSync)(manifestPath)) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
const content = (0, fs_1.readFileSync)(manifestPath, 'utf-8');
|
|
27
|
+
this.manifest = JSON.parse(content);
|
|
28
|
+
this.manifestDir = (0, path_1.dirname)(manifestPath);
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Load the manifest from a JSON string.
|
|
37
|
+
* Used for testing or when the manifest is embedded.
|
|
38
|
+
*/
|
|
39
|
+
loadManifestFromJSON(json, baseDir) {
|
|
40
|
+
try {
|
|
41
|
+
this.manifest = JSON.parse(json);
|
|
42
|
+
this.manifestDir = baseDir;
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Get a validator function for a DTO type name.
|
|
51
|
+
* Returns the assert function that throws on invalid input.
|
|
52
|
+
*/
|
|
53
|
+
getValidator(typeName) {
|
|
54
|
+
// Check cache
|
|
55
|
+
const cached = this.cache.validators.get(typeName);
|
|
56
|
+
if (cached)
|
|
57
|
+
return cached;
|
|
58
|
+
if (!this.manifest)
|
|
59
|
+
return null;
|
|
60
|
+
const entry = this.manifest.validators[typeName];
|
|
61
|
+
if (!entry)
|
|
62
|
+
return null;
|
|
63
|
+
try {
|
|
64
|
+
const filePath = (0, path_1.join)(this.manifestDir, entry.file);
|
|
65
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
66
|
+
const mod = require(filePath);
|
|
67
|
+
const fn = mod[entry.fn];
|
|
68
|
+
if (typeof fn === 'function') {
|
|
69
|
+
this.cache.validators.set(typeName, fn);
|
|
70
|
+
return fn;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
// Failed to load companion file
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Get a serializer function for a DTO type name.
|
|
80
|
+
* Returns a function that converts the input to a JSON string.
|
|
81
|
+
*/
|
|
82
|
+
getSerializer(typeName) {
|
|
83
|
+
// Check cache
|
|
84
|
+
const cached = this.cache.serializers.get(typeName);
|
|
85
|
+
if (cached)
|
|
86
|
+
return cached;
|
|
87
|
+
if (!this.manifest)
|
|
88
|
+
return null;
|
|
89
|
+
const entry = this.manifest.serializers[typeName];
|
|
90
|
+
if (!entry)
|
|
91
|
+
return null;
|
|
92
|
+
try {
|
|
93
|
+
const filePath = (0, path_1.join)(this.manifestDir, entry.file);
|
|
94
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
95
|
+
const mod = require(filePath);
|
|
96
|
+
const fn = mod[entry.fn];
|
|
97
|
+
if (typeof fn === 'function') {
|
|
98
|
+
this.cache.serializers.set(typeName, fn);
|
|
99
|
+
return fn;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
// Failed to load companion file
|
|
104
|
+
}
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Check if a validator exists for a type.
|
|
109
|
+
*/
|
|
110
|
+
hasValidator(typeName) {
|
|
111
|
+
return this.manifest?.validators[typeName] != null;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Check if a serializer exists for a type.
|
|
115
|
+
*/
|
|
116
|
+
hasSerializer(typeName) {
|
|
117
|
+
return this.manifest?.serializers[typeName] != null;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Get all registered validator type names.
|
|
121
|
+
*/
|
|
122
|
+
getValidatorTypes() {
|
|
123
|
+
return this.manifest ? Object.keys(this.manifest.validators) : [];
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Get all registered serializer type names.
|
|
127
|
+
*/
|
|
128
|
+
getSerializerTypes() {
|
|
129
|
+
return this.manifest ? Object.keys(this.manifest.serializers) : [];
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Look up the return type for a controller method from the route map.
|
|
133
|
+
* @param controllerName The controller class name (e.g., "UserController").
|
|
134
|
+
* @param methodName The method name (e.g., "findAll").
|
|
135
|
+
* @returns The route mapping or null if not found.
|
|
136
|
+
*/
|
|
137
|
+
getRouteMapping(controllerName, methodName) {
|
|
138
|
+
if (!this.manifest?.routes)
|
|
139
|
+
return null;
|
|
140
|
+
const key = `${controllerName}.${methodName}`;
|
|
141
|
+
return this.manifest.routes[key] ?? null;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Get a serializer function for a controller method, using the route map.
|
|
145
|
+
* This is the primary lookup path for the fast interceptor — no Reflect metadata needed.
|
|
146
|
+
* @returns An object with the serializer function and whether it's an array, or null.
|
|
147
|
+
*/
|
|
148
|
+
getSerializerForRoute(controllerName, methodName) {
|
|
149
|
+
const mapping = this.getRouteMapping(controllerName, methodName);
|
|
150
|
+
if (!mapping)
|
|
151
|
+
return null;
|
|
152
|
+
const serializer = this.getSerializer(mapping.returnType);
|
|
153
|
+
if (!serializer)
|
|
154
|
+
return null;
|
|
155
|
+
return { serializer, isArray: mapping.isArray ?? false };
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
exports.CompanionDiscovery = CompanionDiscovery;
|
|
159
|
+
//# sourceMappingURL=discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"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"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation error details for a single field.
|
|
3
|
+
*/
|
|
4
|
+
export interface ValidationErrorDetail {
|
|
5
|
+
/** The path to the invalid field (e.g., "input.name"). */
|
|
6
|
+
path: string;
|
|
7
|
+
/** The expected type or constraint. */
|
|
8
|
+
expected: string;
|
|
9
|
+
/** The received type or value description. */
|
|
10
|
+
received: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Error thrown when validation fails.
|
|
14
|
+
* Contains structured error details for each invalid field.
|
|
15
|
+
*/
|
|
16
|
+
export declare class TsgonestValidationError extends Error {
|
|
17
|
+
readonly errors: ValidationErrorDetail[];
|
|
18
|
+
constructor(errors: ValidationErrorDetail[]);
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,uCAAuC;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,SAAgB,MAAM,EAAE,qBAAqB,EAAE,CAAC;gBAEpC,MAAM,EAAE,qBAAqB,EAAE;CAO5C"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TsgonestValidationError = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Error thrown when validation fails.
|
|
6
|
+
* Contains structured error details for each invalid field.
|
|
7
|
+
*/
|
|
8
|
+
class TsgonestValidationError extends Error {
|
|
9
|
+
errors;
|
|
10
|
+
constructor(errors) {
|
|
11
|
+
const message = `Validation failed: ${errors.length} error(s)\n` +
|
|
12
|
+
errors.map(e => ` - ${e.path}: expected ${e.expected}, received ${e.received}`).join('\n');
|
|
13
|
+
super(message);
|
|
14
|
+
this.name = 'TsgonestValidationError';
|
|
15
|
+
this.errors = errors;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
exports.TsgonestValidationError = TsgonestValidationError;
|
|
19
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":";;;AAYA;;;GAGG;AACH,MAAa,uBAAwB,SAAQ,KAAK;IAChC,MAAM,CAA0B;IAEhD,YAAY,MAA+B;QACzC,MAAM,OAAO,GAAG,sBAAsB,MAAM,CAAC,MAAM,aAAa;YAC9D,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,cAAc,CAAC,CAAC,QAAQ,cAAc,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9F,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC;QACtC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAVD,0DAUC"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
|
|
2
|
+
import type { Observable } from 'rxjs';
|
|
3
|
+
import { CompanionDiscovery } from './discovery';
|
|
4
|
+
/**
|
|
5
|
+
* Options for configuring the TsgonestFastInterceptor.
|
|
6
|
+
*/
|
|
7
|
+
export interface FastInterceptorOptions {
|
|
8
|
+
/**
|
|
9
|
+
* Path to the dist directory containing the tsgonest manifest.
|
|
10
|
+
* Defaults to the current working directory's dist/ folder.
|
|
11
|
+
*/
|
|
12
|
+
distDir?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Pre-loaded CompanionDiscovery instance.
|
|
15
|
+
* If provided, distDir is ignored.
|
|
16
|
+
*/
|
|
17
|
+
discovery?: CompanionDiscovery;
|
|
18
|
+
/**
|
|
19
|
+
* Type name overrides for specific routes.
|
|
20
|
+
* Map of "ControllerName.methodName" to type name.
|
|
21
|
+
* Takes priority over the route map in the manifest.
|
|
22
|
+
*/
|
|
23
|
+
typeOverrides?: Record<string, string>;
|
|
24
|
+
/**
|
|
25
|
+
* Whether to set the raw response directly (bypassing NestJS JSON serialization).
|
|
26
|
+
* When true, the interceptor writes the pre-serialized JSON string directly to
|
|
27
|
+
* the response with Content-Type: application/json, skipping JSON.stringify entirely.
|
|
28
|
+
*
|
|
29
|
+
* When false (default), the interceptor returns the pre-serialized string and
|
|
30
|
+
* relies on NestJS/Express to write it (which may still call JSON.stringify on
|
|
31
|
+
* the string — wrapping it in quotes). Use `true` for maximum performance.
|
|
32
|
+
*
|
|
33
|
+
* Defaults to true.
|
|
34
|
+
*/
|
|
35
|
+
rawResponse?: boolean;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* A high-performance NestJS interceptor that replaces JSON.stringify with
|
|
39
|
+
* tsgonest-generated schema-aware serializers on responses.
|
|
40
|
+
*
|
|
41
|
+
* Unlike `TsgonestSerializationInterceptor`, this interceptor uses the
|
|
42
|
+
* **route map** in the manifest to look up which serializer to use for each
|
|
43
|
+
* controller method — no Reflect.getMetadata or emitDecoratorMetadata needed.
|
|
44
|
+
*
|
|
45
|
+
* The route map is populated at build time by tsgonest's static analysis of
|
|
46
|
+
* NestJS controllers, making this zero-config and guaranteed to work.
|
|
47
|
+
*
|
|
48
|
+
* Performance: 2-5x faster JSON serialization compared to JSON.stringify,
|
|
49
|
+
* because the generated serializers use string concatenation with known
|
|
50
|
+
* property names and types, avoiding the overhead of generic object traversal.
|
|
51
|
+
*
|
|
52
|
+
* Usage:
|
|
53
|
+
* ```ts
|
|
54
|
+
* import { TsgonestFastInterceptor } from '@tsgonest/runtime';
|
|
55
|
+
*
|
|
56
|
+
* // In main.ts (after app creation):
|
|
57
|
+
* app.useGlobalInterceptors(new TsgonestFastInterceptor());
|
|
58
|
+
*
|
|
59
|
+
* // With options:
|
|
60
|
+
* app.useGlobalInterceptors(new TsgonestFastInterceptor({
|
|
61
|
+
* distDir: 'dist',
|
|
62
|
+
* rawResponse: true, // bypass JSON.stringify entirely
|
|
63
|
+
* }));
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export declare class TsgonestFastInterceptor implements NestInterceptor {
|
|
67
|
+
private discovery;
|
|
68
|
+
private typeOverrides;
|
|
69
|
+
private rawResponse;
|
|
70
|
+
private initialized;
|
|
71
|
+
private distDir;
|
|
72
|
+
constructor(options?: FastInterceptorOptions);
|
|
73
|
+
/**
|
|
74
|
+
* Ensure the manifest is loaded (lazy init on first request).
|
|
75
|
+
*/
|
|
76
|
+
private ensureInitialized;
|
|
77
|
+
/**
|
|
78
|
+
* Intercept the response and apply fast serialization if a route mapping exists.
|
|
79
|
+
*/
|
|
80
|
+
intercept(context: ExecutionContext, next: CallHandler): Observable<unknown>;
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=fast-interceptor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fast-interceptor.d.ts","sourceRoot":"","sources":["../src/fast-interceptor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AACrF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AACvC,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAE/B;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEvC;;;;;;;;;;OAUG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,qBAAa,uBAAwB,YAAW,eAAe;IAC7D,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,aAAa,CAAyB;IAC9C,OAAO,CAAC,WAAW,CAAU;IAC7B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,OAAO,CAAqB;gBAExB,OAAO,GAAE,sBAA2B;IAahD;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAQzB;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,WAAW,GAAG,UAAU,CAAC,OAAO,CAAC;CAyF7E"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TsgonestFastInterceptor = void 0;
|
|
4
|
+
const discovery_1 = require("./discovery");
|
|
5
|
+
/**
|
|
6
|
+
* A high-performance NestJS interceptor that replaces JSON.stringify with
|
|
7
|
+
* tsgonest-generated schema-aware serializers on responses.
|
|
8
|
+
*
|
|
9
|
+
* Unlike `TsgonestSerializationInterceptor`, this interceptor uses the
|
|
10
|
+
* **route map** in the manifest to look up which serializer to use for each
|
|
11
|
+
* controller method — no Reflect.getMetadata or emitDecoratorMetadata needed.
|
|
12
|
+
*
|
|
13
|
+
* The route map is populated at build time by tsgonest's static analysis of
|
|
14
|
+
* NestJS controllers, making this zero-config and guaranteed to work.
|
|
15
|
+
*
|
|
16
|
+
* Performance: 2-5x faster JSON serialization compared to JSON.stringify,
|
|
17
|
+
* because the generated serializers use string concatenation with known
|
|
18
|
+
* property names and types, avoiding the overhead of generic object traversal.
|
|
19
|
+
*
|
|
20
|
+
* Usage:
|
|
21
|
+
* ```ts
|
|
22
|
+
* import { TsgonestFastInterceptor } from '@tsgonest/runtime';
|
|
23
|
+
*
|
|
24
|
+
* // In main.ts (after app creation):
|
|
25
|
+
* app.useGlobalInterceptors(new TsgonestFastInterceptor());
|
|
26
|
+
*
|
|
27
|
+
* // With options:
|
|
28
|
+
* app.useGlobalInterceptors(new TsgonestFastInterceptor({
|
|
29
|
+
* distDir: 'dist',
|
|
30
|
+
* rawResponse: true, // bypass JSON.stringify entirely
|
|
31
|
+
* }));
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
class TsgonestFastInterceptor {
|
|
35
|
+
discovery;
|
|
36
|
+
typeOverrides;
|
|
37
|
+
rawResponse;
|
|
38
|
+
initialized = false;
|
|
39
|
+
distDir;
|
|
40
|
+
constructor(options = {}) {
|
|
41
|
+
this.typeOverrides = options.typeOverrides ?? {};
|
|
42
|
+
this.rawResponse = options.rawResponse ?? true;
|
|
43
|
+
if (options.discovery) {
|
|
44
|
+
this.discovery = options.discovery;
|
|
45
|
+
this.initialized = true;
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
this.discovery = new discovery_1.CompanionDiscovery();
|
|
49
|
+
this.distDir = options.distDir;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Ensure the manifest is loaded (lazy init on first request).
|
|
54
|
+
*/
|
|
55
|
+
ensureInitialized() {
|
|
56
|
+
if (this.initialized)
|
|
57
|
+
return;
|
|
58
|
+
this.initialized = true;
|
|
59
|
+
const distDir = this.distDir || 'dist';
|
|
60
|
+
this.discovery.loadManifest(distDir);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Intercept the response and apply fast serialization if a route mapping exists.
|
|
64
|
+
*/
|
|
65
|
+
intercept(context, next) {
|
|
66
|
+
this.ensureInitialized();
|
|
67
|
+
const handler = context.getHandler();
|
|
68
|
+
const controller = context.getClass();
|
|
69
|
+
const controllerName = controller.name;
|
|
70
|
+
const methodName = handler.name;
|
|
71
|
+
// 1. Check explicit type overrides first
|
|
72
|
+
const overrideKey = `${controllerName}.${methodName}`;
|
|
73
|
+
const overrideType = this.typeOverrides[overrideKey];
|
|
74
|
+
// 2. Look up via route map (the primary path — zero-config)
|
|
75
|
+
let serializerFn = null;
|
|
76
|
+
let isArray = false;
|
|
77
|
+
if (overrideType) {
|
|
78
|
+
serializerFn = this.discovery.getSerializer(overrideType);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
const routeInfo = this.discovery.getSerializerForRoute(controllerName, methodName);
|
|
82
|
+
if (routeInfo) {
|
|
83
|
+
serializerFn = routeInfo.serializer;
|
|
84
|
+
isArray = routeInfo.isArray;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (!serializerFn) {
|
|
88
|
+
// No serializer available — pass through to default JSON.stringify
|
|
89
|
+
return next.handle();
|
|
90
|
+
}
|
|
91
|
+
// Capture for closure
|
|
92
|
+
const serializer = serializerFn;
|
|
93
|
+
const useRawResponse = this.rawResponse;
|
|
94
|
+
const isArrayResponse = isArray;
|
|
95
|
+
// Lazy-import rxjs to avoid requiring it at module load time
|
|
96
|
+
try {
|
|
97
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
98
|
+
const { map } = require('rxjs');
|
|
99
|
+
return next.handle().pipe(map((data) => {
|
|
100
|
+
if (data === null || data === undefined) {
|
|
101
|
+
return data;
|
|
102
|
+
}
|
|
103
|
+
let jsonString;
|
|
104
|
+
if (isArrayResponse || Array.isArray(data)) {
|
|
105
|
+
// Serialize array: serialize each element, join with commas
|
|
106
|
+
const items = Array.isArray(data) ? data : [data];
|
|
107
|
+
const parts = items.map(item => serializer(item));
|
|
108
|
+
jsonString = '[' + parts.join(',') + ']';
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
jsonString = serializer(data);
|
|
112
|
+
}
|
|
113
|
+
if (useRawResponse) {
|
|
114
|
+
// Write directly to the response, bypassing NestJS JSON serialization
|
|
115
|
+
const httpCtx = context.switchToHttp();
|
|
116
|
+
const response = httpCtx.getResponse();
|
|
117
|
+
// Works with both Express and Fastify
|
|
118
|
+
if (typeof response.type === 'function') {
|
|
119
|
+
// Fastify
|
|
120
|
+
response.type('application/json');
|
|
121
|
+
response.send(jsonString);
|
|
122
|
+
}
|
|
123
|
+
else if (typeof response.setHeader === 'function') {
|
|
124
|
+
// Express
|
|
125
|
+
response.setHeader('Content-Type', 'application/json');
|
|
126
|
+
response.end(jsonString);
|
|
127
|
+
}
|
|
128
|
+
// Return undefined to signal NestJS not to send anything else.
|
|
129
|
+
// The response is already sent.
|
|
130
|
+
return undefined;
|
|
131
|
+
}
|
|
132
|
+
// Non-raw mode: return the pre-serialized JSON.
|
|
133
|
+
// Note: NestJS will call JSON.stringify on this string,
|
|
134
|
+
// wrapping it in quotes. This mode is less optimal but safer.
|
|
135
|
+
return jsonString;
|
|
136
|
+
}));
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
// rxjs not available — pass through
|
|
140
|
+
return next.handle();
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
exports.TsgonestFastInterceptor = TsgonestFastInterceptor;
|
|
145
|
+
//# sourceMappingURL=fast-interceptor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fast-interceptor.js","sourceRoot":"","sources":["../src/fast-interceptor.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { TsgonestValidationPipe } from './validation-pipe';
|
|
2
|
+
export type { ValidationPipeOptions } from './validation-pipe';
|
|
3
|
+
export { TsgonestSerializationInterceptor } from './serialization';
|
|
4
|
+
export type { SerializationInterceptorOptions } from './serialization';
|
|
5
|
+
export { TsgonestFastInterceptor } from './fast-interceptor';
|
|
6
|
+
export type { FastInterceptorOptions } from './fast-interceptor';
|
|
7
|
+
export { TsgonestValidationError } from './errors';
|
|
8
|
+
export type { ValidationErrorDetail } from './errors';
|
|
9
|
+
export { CompanionDiscovery } from './discovery';
|
|
10
|
+
export type { TsgonestManifest, ManifestEntry, RouteMapping } from './discovery';
|
|
11
|
+
export { defineConfig } from './config';
|
|
12
|
+
export type { TsgonestConfig } from './config';
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,YAAY,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAG/D,OAAO,EAAE,gCAAgC,EAAE,MAAM,iBAAiB,CAAC;AACnE,YAAY,EAAE,+BAA+B,EAAE,MAAM,iBAAiB,CAAC;AAGvE,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,YAAY,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAGjE,OAAO,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AACnD,YAAY,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAGtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGjF,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,YAAY,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.defineConfig = exports.CompanionDiscovery = exports.TsgonestValidationError = exports.TsgonestFastInterceptor = exports.TsgonestSerializationInterceptor = exports.TsgonestValidationPipe = void 0;
|
|
4
|
+
// Validation
|
|
5
|
+
var validation_pipe_1 = require("./validation-pipe");
|
|
6
|
+
Object.defineProperty(exports, "TsgonestValidationPipe", { enumerable: true, get: function () { return validation_pipe_1.TsgonestValidationPipe; } });
|
|
7
|
+
// Serialization (legacy — uses Reflect.getMetadata)
|
|
8
|
+
var serialization_1 = require("./serialization");
|
|
9
|
+
Object.defineProperty(exports, "TsgonestSerializationInterceptor", { enumerable: true, get: function () { return serialization_1.TsgonestSerializationInterceptor; } });
|
|
10
|
+
// Fast Serialization (recommended — uses route map, no Reflect needed)
|
|
11
|
+
var fast_interceptor_1 = require("./fast-interceptor");
|
|
12
|
+
Object.defineProperty(exports, "TsgonestFastInterceptor", { enumerable: true, get: function () { return fast_interceptor_1.TsgonestFastInterceptor; } });
|
|
13
|
+
// Errors
|
|
14
|
+
var errors_1 = require("./errors");
|
|
15
|
+
Object.defineProperty(exports, "TsgonestValidationError", { enumerable: true, get: function () { return errors_1.TsgonestValidationError; } });
|
|
16
|
+
// Discovery
|
|
17
|
+
var discovery_1 = require("./discovery");
|
|
18
|
+
Object.defineProperty(exports, "CompanionDiscovery", { enumerable: true, get: function () { return discovery_1.CompanionDiscovery; } });
|
|
19
|
+
// Config
|
|
20
|
+
var config_1 = require("./config");
|
|
21
|
+
Object.defineProperty(exports, "defineConfig", { enumerable: true, get: function () { return config_1.defineConfig; } });
|
|
22
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,aAAa;AACb,qDAA2D;AAAlD,yHAAA,sBAAsB,OAAA;AAG/B,oDAAoD;AACpD,iDAAmE;AAA1D,iIAAA,gCAAgC,OAAA;AAGzC,uEAAuE;AACvE,uDAA6D;AAApD,2HAAA,uBAAuB,OAAA;AAGhC,SAAS;AACT,mCAAmD;AAA1C,iHAAA,uBAAuB,OAAA;AAGhC,YAAY;AACZ,yCAAiD;AAAxC,+GAAA,kBAAkB,OAAA;AAG3B,SAAS;AACT,mCAAwC;AAA/B,sGAAA,YAAY,OAAA"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
|
|
2
|
+
import type { Observable } from 'rxjs';
|
|
3
|
+
import { CompanionDiscovery } from './discovery';
|
|
4
|
+
/**
|
|
5
|
+
* Options for configuring the TsgonestSerializationInterceptor.
|
|
6
|
+
*/
|
|
7
|
+
export interface SerializationInterceptorOptions {
|
|
8
|
+
/**
|
|
9
|
+
* Path to the dist directory containing the tsgonest manifest.
|
|
10
|
+
* Defaults to the current working directory's dist/ folder.
|
|
11
|
+
*/
|
|
12
|
+
distDir?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Pre-loaded CompanionDiscovery instance.
|
|
15
|
+
* If provided, distDir is ignored.
|
|
16
|
+
*/
|
|
17
|
+
discovery?: CompanionDiscovery;
|
|
18
|
+
/**
|
|
19
|
+
* Type name overrides for specific routes.
|
|
20
|
+
* Map of "ControllerName.methodName" → type name.
|
|
21
|
+
*/
|
|
22
|
+
typeOverrides?: Record<string, string>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* A NestJS interceptor that uses tsgonest-generated companion serialization
|
|
26
|
+
* functions for fast JSON output.
|
|
27
|
+
*
|
|
28
|
+
* When a serializer companion exists for a controller method's return type,
|
|
29
|
+
* this interceptor replaces the default JSON.stringify with the generated
|
|
30
|
+
* fast serializer (string concatenation approach).
|
|
31
|
+
*
|
|
32
|
+
* Usage:
|
|
33
|
+
* ```ts
|
|
34
|
+
* import { TsgonestSerializationInterceptor } from '@tsgonest/runtime';
|
|
35
|
+
*
|
|
36
|
+
* // In main.ts:
|
|
37
|
+
* app.useGlobalInterceptors(new TsgonestSerializationInterceptor({ distDir: 'dist' }));
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export declare class TsgonestSerializationInterceptor implements NestInterceptor {
|
|
41
|
+
private discovery;
|
|
42
|
+
private typeOverrides;
|
|
43
|
+
private initialized;
|
|
44
|
+
private distDir;
|
|
45
|
+
constructor(options?: SerializationInterceptorOptions);
|
|
46
|
+
/**
|
|
47
|
+
* Ensure the manifest is loaded.
|
|
48
|
+
*/
|
|
49
|
+
private ensureInitialized;
|
|
50
|
+
/**
|
|
51
|
+
* Intercept the response and apply fast serialization if available.
|
|
52
|
+
*/
|
|
53
|
+
intercept(context: ExecutionContext, next: CallHandler): Observable<unknown>;
|
|
54
|
+
/**
|
|
55
|
+
* Resolve the return type name for a controller method.
|
|
56
|
+
*
|
|
57
|
+
* Strategy:
|
|
58
|
+
* 1. Check typeOverrides for "ControllerName.methodName"
|
|
59
|
+
* 2. Check Reflect metadata (if available) for return type
|
|
60
|
+
* 3. Check the manifest for all registered serializer types
|
|
61
|
+
* and match by method name convention (e.g., "findAll" → look for array type)
|
|
62
|
+
*/
|
|
63
|
+
private resolveTypeName;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=serialization.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialization.d.ts","sourceRoot":"","sources":["../src/serialization.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AACrF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AACvC,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD;;GAEG;AACH,MAAM,WAAW,+BAA+B;IAC9C;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAE/B;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACxC;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,gCAAiC,YAAW,eAAe;IACtE,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,aAAa,CAAyB;IAC9C,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,OAAO,CAAqB;gBAExB,OAAO,GAAE,+BAAoC;IAYzD;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAQzB;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,WAAW,GAAG,UAAU,CAAC,OAAO,CAAC;IA4C5E;;;;;;;;OAQG;IACH,OAAO,CAAC,eAAe;CAkCxB"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TsgonestSerializationInterceptor = void 0;
|
|
4
|
+
const discovery_1 = require("./discovery");
|
|
5
|
+
/**
|
|
6
|
+
* A NestJS interceptor that uses tsgonest-generated companion serialization
|
|
7
|
+
* functions for fast JSON output.
|
|
8
|
+
*
|
|
9
|
+
* When a serializer companion exists for a controller method's return type,
|
|
10
|
+
* this interceptor replaces the default JSON.stringify with the generated
|
|
11
|
+
* fast serializer (string concatenation approach).
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* ```ts
|
|
15
|
+
* import { TsgonestSerializationInterceptor } from '@tsgonest/runtime';
|
|
16
|
+
*
|
|
17
|
+
* // In main.ts:
|
|
18
|
+
* app.useGlobalInterceptors(new TsgonestSerializationInterceptor({ distDir: 'dist' }));
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
class TsgonestSerializationInterceptor {
|
|
22
|
+
discovery;
|
|
23
|
+
typeOverrides;
|
|
24
|
+
initialized = false;
|
|
25
|
+
distDir;
|
|
26
|
+
constructor(options = {}) {
|
|
27
|
+
this.typeOverrides = options.typeOverrides ?? {};
|
|
28
|
+
if (options.discovery) {
|
|
29
|
+
this.discovery = options.discovery;
|
|
30
|
+
this.initialized = true;
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
this.discovery = new discovery_1.CompanionDiscovery();
|
|
34
|
+
this.distDir = options.distDir;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Ensure the manifest is loaded.
|
|
39
|
+
*/
|
|
40
|
+
ensureInitialized() {
|
|
41
|
+
if (this.initialized)
|
|
42
|
+
return;
|
|
43
|
+
this.initialized = true;
|
|
44
|
+
const distDir = this.distDir || 'dist';
|
|
45
|
+
this.discovery.loadManifest(distDir);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Intercept the response and apply fast serialization if available.
|
|
49
|
+
*/
|
|
50
|
+
intercept(context, next) {
|
|
51
|
+
this.ensureInitialized();
|
|
52
|
+
const handler = context.getHandler();
|
|
53
|
+
const controller = context.getClass();
|
|
54
|
+
// Determine the return type name
|
|
55
|
+
const typeName = this.resolveTypeName(controller, handler);
|
|
56
|
+
if (!typeName) {
|
|
57
|
+
return next.handle();
|
|
58
|
+
}
|
|
59
|
+
// Look up the serializer for this type
|
|
60
|
+
const serializer = this.discovery.getSerializer(typeName);
|
|
61
|
+
if (!serializer) {
|
|
62
|
+
return next.handle();
|
|
63
|
+
}
|
|
64
|
+
// Lazy-import rxjs map to avoid requiring rxjs at import time
|
|
65
|
+
try {
|
|
66
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
67
|
+
const { map } = require('rxjs');
|
|
68
|
+
return next.handle().pipe(map((data) => {
|
|
69
|
+
if (data === null || data === undefined) {
|
|
70
|
+
return data;
|
|
71
|
+
}
|
|
72
|
+
// If the data is an array, serialize each element
|
|
73
|
+
if (Array.isArray(data)) {
|
|
74
|
+
const parts = data.map(item => serializer(item));
|
|
75
|
+
return '[' + parts.join(',') + ']';
|
|
76
|
+
}
|
|
77
|
+
return serializer(data);
|
|
78
|
+
}));
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
// rxjs not available — pass through
|
|
82
|
+
return next.handle();
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Resolve the return type name for a controller method.
|
|
87
|
+
*
|
|
88
|
+
* Strategy:
|
|
89
|
+
* 1. Check typeOverrides for "ControllerName.methodName"
|
|
90
|
+
* 2. Check Reflect metadata (if available) for return type
|
|
91
|
+
* 3. Check the manifest for all registered serializer types
|
|
92
|
+
* and match by method name convention (e.g., "findAll" → look for array type)
|
|
93
|
+
*/
|
|
94
|
+
resolveTypeName(controller, handler) {
|
|
95
|
+
const controllerName = controller.name;
|
|
96
|
+
const methodName = handler.name;
|
|
97
|
+
// 1. Check explicit overrides
|
|
98
|
+
const overrideKey = `${controllerName}.${methodName}`;
|
|
99
|
+
if (this.typeOverrides[overrideKey]) {
|
|
100
|
+
return this.typeOverrides[overrideKey];
|
|
101
|
+
}
|
|
102
|
+
// 2. Check Reflect metadata for return type (if emitDecoratorMetadata is enabled)
|
|
103
|
+
if (typeof Reflect !== 'undefined' && Reflect.getMetadata) {
|
|
104
|
+
const returnType = Reflect.getMetadata('design:returntype', controller.prototype, methodName);
|
|
105
|
+
if (returnType && returnType.name && returnType.name !== 'Promise' && returnType.name !== 'Object') {
|
|
106
|
+
const typeName = returnType.name;
|
|
107
|
+
if (this.discovery.hasSerializer(typeName)) {
|
|
108
|
+
return typeName;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// 3. Check custom metadata set by tsgonest (via __tsgonest_return_type__)
|
|
113
|
+
if (typeof Reflect !== 'undefined' && Reflect.getMetadata) {
|
|
114
|
+
const tsgonestReturnType = Reflect.getMetadata('__tsgonest_return_type__', controller.prototype, methodName);
|
|
115
|
+
if (tsgonestReturnType && this.discovery.hasSerializer(tsgonestReturnType)) {
|
|
116
|
+
return tsgonestReturnType;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
exports.TsgonestSerializationInterceptor = TsgonestSerializationInterceptor;
|
|
123
|
+
//# sourceMappingURL=serialization.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialization.js","sourceRoot":"","sources":["../src/serialization.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { PipeTransform, ArgumentMetadata } from '@nestjs/common';
|
|
2
|
+
import { CompanionDiscovery } from './discovery';
|
|
3
|
+
/**
|
|
4
|
+
* Options for configuring the TsgonestValidationPipe.
|
|
5
|
+
*/
|
|
6
|
+
export interface ValidationPipeOptions {
|
|
7
|
+
/**
|
|
8
|
+
* Path to the dist directory containing the tsgonest manifest.
|
|
9
|
+
* Defaults to the current working directory's dist/ folder.
|
|
10
|
+
*/
|
|
11
|
+
distDir?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Pre-loaded CompanionDiscovery instance.
|
|
14
|
+
* If provided, distDir is ignored.
|
|
15
|
+
*/
|
|
16
|
+
discovery?: CompanionDiscovery;
|
|
17
|
+
/**
|
|
18
|
+
* Whether to throw an error if validation fails.
|
|
19
|
+
* Defaults to true. When false, returns null for invalid input.
|
|
20
|
+
*/
|
|
21
|
+
throwOnError?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* HTTP status code to use when throwing validation errors.
|
|
24
|
+
* Defaults to 400 (Bad Request).
|
|
25
|
+
*/
|
|
26
|
+
errorHttpStatusCode?: number;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A NestJS pipe that validates incoming request data using
|
|
30
|
+
* tsgonest-generated companion validation functions.
|
|
31
|
+
*
|
|
32
|
+
* Usage:
|
|
33
|
+
* ```ts
|
|
34
|
+
* import { TsgonestValidationPipe } from '@tsgonest/runtime';
|
|
35
|
+
*
|
|
36
|
+
* // In main.ts:
|
|
37
|
+
* app.useGlobalPipes(new TsgonestValidationPipe({ distDir: 'dist' }));
|
|
38
|
+
*
|
|
39
|
+
* // Or with a pre-loaded discovery:
|
|
40
|
+
* const discovery = new CompanionDiscovery();
|
|
41
|
+
* discovery.loadManifest('dist');
|
|
42
|
+
* app.useGlobalPipes(new TsgonestValidationPipe({ discovery }));
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export declare class TsgonestValidationPipe implements PipeTransform {
|
|
46
|
+
private discovery;
|
|
47
|
+
private throwOnError;
|
|
48
|
+
private errorHttpStatusCode;
|
|
49
|
+
private initialized;
|
|
50
|
+
private distDir;
|
|
51
|
+
constructor(options?: ValidationPipeOptions);
|
|
52
|
+
/**
|
|
53
|
+
* Ensure the manifest is loaded.
|
|
54
|
+
*/
|
|
55
|
+
private ensureInitialized;
|
|
56
|
+
/**
|
|
57
|
+
* Transform (validate) the incoming value.
|
|
58
|
+
* If a companion validator exists for the metatype, it is called.
|
|
59
|
+
* Otherwise, the value is returned unchanged.
|
|
60
|
+
*/
|
|
61
|
+
transform(value: unknown, metadata: ArgumentMetadata): unknown;
|
|
62
|
+
/**
|
|
63
|
+
* Extract the type name from a NestJS metatype.
|
|
64
|
+
* Filters out built-in types (String, Number, Boolean, etc.).
|
|
65
|
+
*/
|
|
66
|
+
private getTypeName;
|
|
67
|
+
/**
|
|
68
|
+
* Parse error messages from generated assert functions.
|
|
69
|
+
* The generated code throws errors like:
|
|
70
|
+
* "Validation failed: input.name expected string, received number"
|
|
71
|
+
*/
|
|
72
|
+
private parseAssertError;
|
|
73
|
+
/**
|
|
74
|
+
* Create an HTTP exception for validation errors.
|
|
75
|
+
* Uses a dynamic import approach to avoid hard NestJS dependency at import time.
|
|
76
|
+
*/
|
|
77
|
+
private createHttpException;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=validation-pipe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation-pipe.d.ts","sourceRoot":"","sources":["../src/validation-pipe.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAQ,MAAM,gBAAgB,CAAC;AAC5E,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAGjD;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAE/B;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,sBAAuB,YAAW,aAAa;IAC1D,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,YAAY,CAAU;IAC9B,OAAO,CAAC,mBAAmB,CAAS;IACpC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,OAAO,CAAqB;gBAExB,OAAO,GAAE,qBAA0B;IAa/C;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAQzB;;;;OAIG;IACH,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,gBAAgB,GAAG,OAAO;IA8C9D;;;OAGG;IACH,OAAO,CAAC,WAAW;IAQnB;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IAmBxB;;;OAGG;IACH,OAAO,CAAC,mBAAmB;CAuB5B"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TsgonestValidationPipe = void 0;
|
|
4
|
+
const discovery_1 = require("./discovery");
|
|
5
|
+
const errors_1 = require("./errors");
|
|
6
|
+
/**
|
|
7
|
+
* A NestJS pipe that validates incoming request data using
|
|
8
|
+
* tsgonest-generated companion validation functions.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* ```ts
|
|
12
|
+
* import { TsgonestValidationPipe } from '@tsgonest/runtime';
|
|
13
|
+
*
|
|
14
|
+
* // In main.ts:
|
|
15
|
+
* app.useGlobalPipes(new TsgonestValidationPipe({ distDir: 'dist' }));
|
|
16
|
+
*
|
|
17
|
+
* // Or with a pre-loaded discovery:
|
|
18
|
+
* const discovery = new CompanionDiscovery();
|
|
19
|
+
* discovery.loadManifest('dist');
|
|
20
|
+
* app.useGlobalPipes(new TsgonestValidationPipe({ discovery }));
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
class TsgonestValidationPipe {
|
|
24
|
+
discovery;
|
|
25
|
+
throwOnError;
|
|
26
|
+
errorHttpStatusCode;
|
|
27
|
+
initialized = false;
|
|
28
|
+
distDir;
|
|
29
|
+
constructor(options = {}) {
|
|
30
|
+
this.throwOnError = options.throwOnError ?? true;
|
|
31
|
+
this.errorHttpStatusCode = options.errorHttpStatusCode ?? 400;
|
|
32
|
+
if (options.discovery) {
|
|
33
|
+
this.discovery = options.discovery;
|
|
34
|
+
this.initialized = true;
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
this.discovery = new discovery_1.CompanionDiscovery();
|
|
38
|
+
this.distDir = options.distDir;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Ensure the manifest is loaded.
|
|
43
|
+
*/
|
|
44
|
+
ensureInitialized() {
|
|
45
|
+
if (this.initialized)
|
|
46
|
+
return;
|
|
47
|
+
this.initialized = true;
|
|
48
|
+
const distDir = this.distDir || 'dist';
|
|
49
|
+
this.discovery.loadManifest(distDir);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Transform (validate) the incoming value.
|
|
53
|
+
* If a companion validator exists for the metatype, it is called.
|
|
54
|
+
* Otherwise, the value is returned unchanged.
|
|
55
|
+
*/
|
|
56
|
+
transform(value, metadata) {
|
|
57
|
+
this.ensureInitialized();
|
|
58
|
+
// Only validate body, query, and param types
|
|
59
|
+
if (!metadata.metatype) {
|
|
60
|
+
return value;
|
|
61
|
+
}
|
|
62
|
+
const typeName = this.getTypeName(metadata.metatype);
|
|
63
|
+
if (!typeName) {
|
|
64
|
+
return value;
|
|
65
|
+
}
|
|
66
|
+
// Look up the validator (assert function) for this type
|
|
67
|
+
const validator = this.discovery.getValidator(typeName);
|
|
68
|
+
if (!validator) {
|
|
69
|
+
// No companion found — pass through
|
|
70
|
+
return value;
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
return validator(value);
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
if (!this.throwOnError) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
// Re-throw TsgonestValidationError as a structured HTTP error
|
|
80
|
+
if (err instanceof errors_1.TsgonestValidationError) {
|
|
81
|
+
throw this.createHttpException(err.errors);
|
|
82
|
+
}
|
|
83
|
+
// For errors from the generated assert functions that throw plain Error
|
|
84
|
+
if (err instanceof Error && err.message) {
|
|
85
|
+
// The generated assert functions throw errors with structured messages
|
|
86
|
+
// Parse them if possible, otherwise wrap
|
|
87
|
+
const details = this.parseAssertError(err.message);
|
|
88
|
+
if (details.length > 0) {
|
|
89
|
+
throw this.createHttpException(details);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
throw err;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Extract the type name from a NestJS metatype.
|
|
97
|
+
* Filters out built-in types (String, Number, Boolean, etc.).
|
|
98
|
+
*/
|
|
99
|
+
getTypeName(metatype) {
|
|
100
|
+
const builtInTypes = [String, Number, Boolean, Array, Object];
|
|
101
|
+
if (builtInTypes.includes(metatype)) {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
return metatype.name || null;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Parse error messages from generated assert functions.
|
|
108
|
+
* The generated code throws errors like:
|
|
109
|
+
* "Validation failed: input.name expected string, received number"
|
|
110
|
+
*/
|
|
111
|
+
parseAssertError(message) {
|
|
112
|
+
const details = [];
|
|
113
|
+
const lines = message.split('\n');
|
|
114
|
+
for (const line of lines) {
|
|
115
|
+
// Match patterns like " - input.name: expected string, received number"
|
|
116
|
+
const match = line.match(/^\s*-?\s*(.+?):\s*expected\s+(.+?),\s*received\s+(.+)$/);
|
|
117
|
+
if (match) {
|
|
118
|
+
details.push({
|
|
119
|
+
path: match[1].trim(),
|
|
120
|
+
expected: match[2].trim(),
|
|
121
|
+
received: match[3].trim(),
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return details;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Create an HTTP exception for validation errors.
|
|
129
|
+
* Uses a dynamic import approach to avoid hard NestJS dependency at import time.
|
|
130
|
+
*/
|
|
131
|
+
createHttpException(errors) {
|
|
132
|
+
// Try to create a NestJS HttpException
|
|
133
|
+
try {
|
|
134
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
135
|
+
const { HttpException } = require('@nestjs/common');
|
|
136
|
+
return new HttpException({
|
|
137
|
+
statusCode: this.errorHttpStatusCode,
|
|
138
|
+
message: 'Validation failed',
|
|
139
|
+
errors: errors.map(e => ({
|
|
140
|
+
property: e.path,
|
|
141
|
+
constraints: { tsgonest: `expected ${e.expected}, received ${e.received}` },
|
|
142
|
+
})),
|
|
143
|
+
}, this.errorHttpStatusCode);
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
// Fallback if @nestjs/common not available
|
|
147
|
+
const err = new errors_1.TsgonestValidationError(errors);
|
|
148
|
+
err.status = this.errorHttpStatusCode;
|
|
149
|
+
return err;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
exports.TsgonestValidationPipe = TsgonestValidationPipe;
|
|
154
|
+
//# sourceMappingURL=validation-pipe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation-pipe.js","sourceRoot":"","sources":["../src/validation-pipe.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tsgonest/runtime",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Runtime utilities for tsgonest — validation pipe, serialization interceptor, and companion file discovery",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.mjs",
|
|
11
|
+
"require": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"@nestjs/common": ">=9.0.0",
|
|
19
|
+
"@nestjs/core": ">=9.0.0",
|
|
20
|
+
"rxjs": ">=7.0.0"
|
|
21
|
+
},
|
|
22
|
+
"peerDependenciesMeta": {
|
|
23
|
+
"@nestjs/common": {
|
|
24
|
+
"optional": true
|
|
25
|
+
},
|
|
26
|
+
"@nestjs/core": {
|
|
27
|
+
"optional": true
|
|
28
|
+
},
|
|
29
|
+
"rxjs": {
|
|
30
|
+
"optional": true
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"keywords": [
|
|
34
|
+
"nestjs",
|
|
35
|
+
"typescript",
|
|
36
|
+
"validation",
|
|
37
|
+
"serialization",
|
|
38
|
+
"openapi",
|
|
39
|
+
"tsgonest"
|
|
40
|
+
],
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@nestjs/common": "^10.0.0",
|
|
43
|
+
"@nestjs/core": "^10.0.0",
|
|
44
|
+
"@types/node": "^25.3.0",
|
|
45
|
+
"reflect-metadata": "^0.2.0",
|
|
46
|
+
"rxjs": "^7.8.0",
|
|
47
|
+
"typescript": "^5.7.0"
|
|
48
|
+
},
|
|
49
|
+
"license": "MIT",
|
|
50
|
+
"repository": {
|
|
51
|
+
"type": "git",
|
|
52
|
+
"url": "https://github.com/tsgonest/tsgonest"
|
|
53
|
+
},
|
|
54
|
+
"scripts": {
|
|
55
|
+
"build": "tsc",
|
|
56
|
+
"test": "vitest --run"
|
|
57
|
+
}
|
|
58
|
+
}
|