@getvision/adapter-express 0.0.10-5fbff2a-develop → 0.1.0-6e5c887-develop
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/CHANGELOG.md +13 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -4
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +4 -0
- package/dist/validator.d.ts +43 -0
- package/dist/validator.d.ts.map +1 -0
- package/dist/validator.js +72 -0
- package/dist/zod-validator.d.ts +1 -0
- package/dist/zod-validator.d.ts.map +1 -1
- package/dist/zod-validator.js +1 -0
- package/package.json +2 -2
- package/src/index.ts +4 -3
- package/src/types.ts +15 -0
- package/src/validator.ts +146 -0
- package/src/zod-validator.ts +1 -0
- package/dist/zod-utils.d.ts +0 -7
- package/dist/zod-utils.d.ts.map +0 -1
- package/dist/zod-utils.js +0 -145
- package/src/zod-utils.ts +0 -170
package/CHANGELOG.md
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -81,4 +81,5 @@ export declare function enableAutoDiscovery(app: Application, options?: {
|
|
|
81
81
|
*/
|
|
82
82
|
export declare function getVisionInstance(): VisionCore | null;
|
|
83
83
|
export { zValidator, getRouteSchema, getAllRouteSchemas } from './zod-validator';
|
|
84
|
+
export { validator } from './validator';
|
|
84
85
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAC3E,OAAO,EACL,UAAU,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAC3E,OAAO,EACL,UAAU,EAKX,MAAM,iBAAiB,CAAA;AACxB,OAAO,KAAK,EAAiB,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAI7F,UAAU,aAAa;IACrB,MAAM,EAAE,UAAU,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,CAAA;CACnB;AAID;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,IAAI,aAAa,CAMhD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,KAInB,CAAC,EACP,MAAM,MAAM,EACZ,YAAY,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,YAAK,EACpC,IAAI,MAAM,CAAC,KACV,CAAC,CAqCL;AAMD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,oBAAyB,SAIlD,OAAO,OAAO,QAAQ,QAAQ,YAAY,UAkM1D;AAuFD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,iBAAiB,EAAE,CAAA;CAAE,GAAG,IAAI,CA8FxG;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,UAAU,GAAG,IAAI,CAErD;AAGD,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAEhF,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { VisionCore, autoDetectPackageInfo, autoDetectIntegrations, runInTraceContext, } from '@getvision/core';
|
|
1
|
+
import { VisionCore, autoDetectPackageInfo, autoDetectIntegrations, runInTraceContext, generateTemplate, } from '@getvision/core';
|
|
2
2
|
import { AsyncLocalStorage } from 'async_hooks';
|
|
3
|
-
import { generateZodTemplate } from './zod-utils';
|
|
4
3
|
const visionContext = new AsyncLocalStorage();
|
|
5
4
|
/**
|
|
6
5
|
* Get current vision context (vision instance and traceId)
|
|
@@ -396,8 +395,7 @@ export function enableAutoDiscovery(app, options) {
|
|
|
396
395
|
};
|
|
397
396
|
if (schema) {
|
|
398
397
|
route.schema = schema;
|
|
399
|
-
|
|
400
|
-
const requestBody = generateZodTemplate(schema);
|
|
398
|
+
const requestBody = generateTemplate(schema);
|
|
401
399
|
if (requestBody) {
|
|
402
400
|
route.requestBody = requestBody;
|
|
403
401
|
}
|
|
@@ -437,3 +435,4 @@ export function getVisionInstance() {
|
|
|
437
435
|
}
|
|
438
436
|
// Export Zod validator for schema-based validation
|
|
439
437
|
export { zValidator, getRouteSchema, getAllRouteSchemas } from './zod-validator';
|
|
438
|
+
export { validator } from './validator';
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Re-export validation types from @vision/core
|
|
3
|
+
*/
|
|
4
|
+
export type { StandardSchemaV1, ValidationSchema, ValidationErrorResponse } from '@getvision/core';
|
|
5
|
+
export { ValidationError, createValidationErrorResponse, UniversalValidator } from '@getvision/core';
|
|
6
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,YAAY,EACV,gBAAgB,EAChB,gBAAgB,EAChB,uBAAuB,EACxB,MAAM,iBAAiB,CAAA;AAExB,OAAO,EACL,eAAe,EACf,6BAA6B,EAC7B,kBAAkB,EACnB,MAAM,iBAAiB,CAAA"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { RequestHandler } from 'express';
|
|
2
|
+
import type { ZodTypeAny } from 'zod';
|
|
3
|
+
import type { StandardSchemaV1, ValidationSchema } from '@getvision/core';
|
|
4
|
+
/**
|
|
5
|
+
* Get stored schema for a route
|
|
6
|
+
*/
|
|
7
|
+
export declare function getRouteSchema(method: string, path: string): ValidationSchema | undefined;
|
|
8
|
+
/**
|
|
9
|
+
* Get all stored schemas
|
|
10
|
+
*/
|
|
11
|
+
export declare function getAllRouteSchemas(): Map<string, {
|
|
12
|
+
method: string;
|
|
13
|
+
path: string;
|
|
14
|
+
schema: ValidationSchema;
|
|
15
|
+
target: string;
|
|
16
|
+
}>;
|
|
17
|
+
/**
|
|
18
|
+
* Universal validator middleware for Express that supports any Standard Schema-compliant library
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* import { validator } from '@getvision/adapter-express'
|
|
23
|
+
* import { z } from 'zod'
|
|
24
|
+
*
|
|
25
|
+
* const schema = z.object({
|
|
26
|
+
* name: z.string().describe('User name'),
|
|
27
|
+
* email: z.string().email().describe('User email'),
|
|
28
|
+
* })
|
|
29
|
+
*
|
|
30
|
+
* app.post('/users', validator('body', schema), (req, res) => {
|
|
31
|
+
* // req.body is now typed and validated
|
|
32
|
+
* const { name, email } = req.body
|
|
33
|
+
* res.json({ name, email })
|
|
34
|
+
* })
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare function validator<S extends ZodTypeAny>(target: 'body', schema: S): RequestHandler<any, any, import('zod').infer<S>, any>;
|
|
38
|
+
export declare function validator<S extends ZodTypeAny>(target: 'query', schema: S): RequestHandler<any, any, any, import('zod').infer<S>>;
|
|
39
|
+
export declare function validator<S extends ZodTypeAny>(target: 'params', schema: S): RequestHandler<import('zod').infer<S>, any, any, any>;
|
|
40
|
+
export declare function validator<S extends StandardSchemaV1<any, any>>(target: 'body', schema: S): RequestHandler<any, any, StandardSchemaV1.Infer<S>['output'], any>;
|
|
41
|
+
export declare function validator<S extends StandardSchemaV1<any, any>>(target: 'query', schema: S): RequestHandler<any, any, any, StandardSchemaV1.Infer<S>['output']>;
|
|
42
|
+
export declare function validator<S extends StandardSchemaV1<any, any>>(target: 'params', schema: S): RequestHandler<StandardSchemaV1.Infer<S>['output'], any, any, any>;
|
|
43
|
+
//# sourceMappingURL=validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../src/validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAmC,cAAc,EAAE,MAAM,SAAS,CAAA;AAC9E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,KAAK,CAAA;AACrC,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAUzE;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAGzF;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,GAAG,CAAC,MAAM,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,gBAAgB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAE5H;AAID;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,UAAU,EAC5C,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,CAAC,GACR,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;AAExD,wBAAgB,SAAS,CAAC,CAAC,SAAS,UAAU,EAC5C,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,CAAC,GACR,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;AAExD,wBAAgB,SAAS,CAAC,CAAC,SAAS,UAAU,EAC5C,MAAM,EAAE,QAAQ,EAChB,MAAM,EAAE,CAAC,GACR,cAAc,CAAC,OAAO,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;AAExD,wBAAgB,SAAS,CAAC,CAAC,SAAS,gBAAgB,CAAC,GAAG,EAAE,GAAG,CAAC,EAC5D,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,CAAC,GACR,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAA;AAErE,wBAAgB,SAAS,CAAC,CAAC,SAAS,gBAAgB,CAAC,GAAG,EAAE,GAAG,CAAC,EAC5D,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,CAAC,GACR,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;AAErE,wBAAgB,SAAS,CAAC,CAAC,SAAS,gBAAgB,CAAC,GAAG,EAAE,GAAG,CAAC,EAC5D,MAAM,EAAE,QAAQ,EAChB,MAAM,EAAE,CAAC,GACR,cAAc,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { ValidationError, createValidationErrorResponse, UniversalValidator } from '@getvision/core';
|
|
2
|
+
// Store schemas for Vision introspection
|
|
3
|
+
const routeSchemas = new Map();
|
|
4
|
+
/**
|
|
5
|
+
* Get stored schema for a route
|
|
6
|
+
*/
|
|
7
|
+
export function getRouteSchema(method, path) {
|
|
8
|
+
const key = `${method}:${path}`;
|
|
9
|
+
return routeSchemas.get(key)?.schema;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Get all stored schemas
|
|
13
|
+
*/
|
|
14
|
+
export function getAllRouteSchemas() {
|
|
15
|
+
return routeSchemas;
|
|
16
|
+
}
|
|
17
|
+
export function validator(target, schema) {
|
|
18
|
+
const middleware = (req, res, next) => {
|
|
19
|
+
// Store schema for Vision (we'll update it later with actual route info)
|
|
20
|
+
const key = `${req.method}:${req.route?.path || req.path}`;
|
|
21
|
+
if (req.route?.path) {
|
|
22
|
+
routeSchemas.set(key, {
|
|
23
|
+
method: req.method,
|
|
24
|
+
path: req.route.path,
|
|
25
|
+
schema,
|
|
26
|
+
target,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
// Get data to validate based on target
|
|
30
|
+
let data;
|
|
31
|
+
switch (target) {
|
|
32
|
+
case 'body':
|
|
33
|
+
data = req.body;
|
|
34
|
+
break;
|
|
35
|
+
case 'query':
|
|
36
|
+
data = req.query;
|
|
37
|
+
break;
|
|
38
|
+
case 'params':
|
|
39
|
+
data = req.params;
|
|
40
|
+
break;
|
|
41
|
+
default:
|
|
42
|
+
return next(new Error(`Invalid validation target: ${target}`));
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
// Validate data using UniversalValidator
|
|
46
|
+
const validated = UniversalValidator.parse(schema, data);
|
|
47
|
+
// Store validated data back
|
|
48
|
+
switch (target) {
|
|
49
|
+
case 'body':
|
|
50
|
+
req.body = validated;
|
|
51
|
+
break;
|
|
52
|
+
case 'query':
|
|
53
|
+
req.query = validated;
|
|
54
|
+
break;
|
|
55
|
+
case 'params':
|
|
56
|
+
req.params = validated;
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
next();
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
if (error instanceof ValidationError) {
|
|
63
|
+
const requestId = req.headers['x-request-id'];
|
|
64
|
+
return res.status(400).json(createValidationErrorResponse(error.issues, requestId));
|
|
65
|
+
}
|
|
66
|
+
next(error);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
middleware.__visionSchema = schema;
|
|
70
|
+
middleware.__visionTarget = target;
|
|
71
|
+
return middleware;
|
|
72
|
+
}
|
package/dist/zod-validator.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export declare function getAllRouteSchemas(): Map<string, {
|
|
|
14
14
|
}>;
|
|
15
15
|
type ValidateTarget = 'body' | 'query' | 'params';
|
|
16
16
|
/**
|
|
17
|
+
* @deprecated Use validator instead
|
|
17
18
|
* Zod validator middleware for Express
|
|
18
19
|
* Similar to @hono/zod-validator but stores schema for Vision introspection
|
|
19
20
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zod-validator.d.ts","sourceRoot":"","sources":["../src/zod-validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAmC,cAAc,EAAE,MAAM,SAAS,CAAA;AAC9E,OAAO,KAAK,EAAE,SAAS,EAAY,MAAM,KAAK,CAAA;AAK9C;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAGlF;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,GAAG,CAAC,MAAM,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,SAAS,CAAA;CAAE,CAAC,CAErG;AAED,KAAK,cAAc,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAA;AAEjD
|
|
1
|
+
{"version":3,"file":"zod-validator.d.ts","sourceRoot":"","sources":["../src/zod-validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAmC,cAAc,EAAE,MAAM,SAAS,CAAA;AAC9E,OAAO,KAAK,EAAE,SAAS,EAAY,MAAM,KAAK,CAAA;AAK9C;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAGlF;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,GAAG,CAAC,MAAM,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,SAAS,CAAA;CAAE,CAAC,CAErG;AAED,KAAK,cAAc,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAA;AAEjD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,SAAS,EAC5C,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,CAAC,GACR,cAAc,CA6DhB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,cAAc,GAAG,SAAS,GAAG,SAAS,CAG/E"}
|
package/dist/zod-validator.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@getvision/adapter-express",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0-6e5c887-develop",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./src/index.ts"
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
},
|
|
13
13
|
"license": "MIT",
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@getvision/core": "0.0
|
|
15
|
+
"@getvision/core": "0.1.0",
|
|
16
16
|
"zod": "^4.1.11"
|
|
17
17
|
},
|
|
18
18
|
"peerDependencies": {
|
package/src/index.ts
CHANGED
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
autoDetectPackageInfo,
|
|
5
5
|
autoDetectIntegrations,
|
|
6
6
|
runInTraceContext,
|
|
7
|
+
generateTemplate,
|
|
7
8
|
} from '@getvision/core'
|
|
8
9
|
import type { RouteMetadata, VisionExpressOptions, ServiceDefinition } from '@getvision/core'
|
|
9
10
|
import { AsyncLocalStorage } from 'async_hooks'
|
|
10
|
-
import { generateZodTemplate } from './zod-utils'
|
|
11
11
|
|
|
12
12
|
// Context storage for vision, traceId, and rootSpanId
|
|
13
13
|
interface VisionContext {
|
|
@@ -483,8 +483,7 @@ export function enableAutoDiscovery(app: Application, options?: { services?: Ser
|
|
|
483
483
|
|
|
484
484
|
if (schema) {
|
|
485
485
|
route.schema = schema
|
|
486
|
-
|
|
487
|
-
const requestBody = generateZodTemplate(schema)
|
|
486
|
+
const requestBody = generateTemplate(schema)
|
|
488
487
|
if (requestBody) {
|
|
489
488
|
route.requestBody = requestBody
|
|
490
489
|
}
|
|
@@ -532,3 +531,5 @@ export function getVisionInstance(): VisionCore | null {
|
|
|
532
531
|
|
|
533
532
|
// Export Zod validator for schema-based validation
|
|
534
533
|
export { zValidator, getRouteSchema, getAllRouteSchemas } from './zod-validator'
|
|
534
|
+
|
|
535
|
+
export { validator } from './validator'
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Re-export validation types from @vision/core
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export type {
|
|
6
|
+
StandardSchemaV1,
|
|
7
|
+
ValidationSchema,
|
|
8
|
+
ValidationErrorResponse
|
|
9
|
+
} from '@getvision/core'
|
|
10
|
+
|
|
11
|
+
export {
|
|
12
|
+
ValidationError,
|
|
13
|
+
createValidationErrorResponse,
|
|
14
|
+
UniversalValidator
|
|
15
|
+
} from '@getvision/core'
|
package/src/validator.ts
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import type { Request, Response, NextFunction, RequestHandler } from 'express'
|
|
2
|
+
import type { ZodTypeAny } from 'zod'
|
|
3
|
+
import type { StandardSchemaV1, ValidationSchema } from '@getvision/core'
|
|
4
|
+
import {
|
|
5
|
+
ValidationError,
|
|
6
|
+
createValidationErrorResponse,
|
|
7
|
+
UniversalValidator
|
|
8
|
+
} from '@getvision/core'
|
|
9
|
+
|
|
10
|
+
// Store schemas for Vision introspection
|
|
11
|
+
const routeSchemas = new Map<string, { method: string; path: string; schema: ValidationSchema; target: string }>()
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Get stored schema for a route
|
|
15
|
+
*/
|
|
16
|
+
export function getRouteSchema(method: string, path: string): ValidationSchema | undefined {
|
|
17
|
+
const key = `${method}:${path}`
|
|
18
|
+
return routeSchemas.get(key)?.schema
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Get all stored schemas
|
|
23
|
+
*/
|
|
24
|
+
export function getAllRouteSchemas(): Map<string, { method: string; path: string; schema: ValidationSchema; target: string }> {
|
|
25
|
+
return routeSchemas
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
type ValidateTarget = 'body' | 'query' | 'params'
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Universal validator middleware for Express that supports any Standard Schema-compliant library
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* import { validator } from '@getvision/adapter-express'
|
|
36
|
+
* import { z } from 'zod'
|
|
37
|
+
*
|
|
38
|
+
* const schema = z.object({
|
|
39
|
+
* name: z.string().describe('User name'),
|
|
40
|
+
* email: z.string().email().describe('User email'),
|
|
41
|
+
* })
|
|
42
|
+
*
|
|
43
|
+
* app.post('/users', validator('body', schema), (req, res) => {
|
|
44
|
+
* // req.body is now typed and validated
|
|
45
|
+
* const { name, email } = req.body
|
|
46
|
+
* res.json({ name, email })
|
|
47
|
+
* })
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export function validator<S extends ZodTypeAny>(
|
|
51
|
+
target: 'body',
|
|
52
|
+
schema: S
|
|
53
|
+
): RequestHandler<any, any, import('zod').infer<S>, any>
|
|
54
|
+
|
|
55
|
+
export function validator<S extends ZodTypeAny>(
|
|
56
|
+
target: 'query',
|
|
57
|
+
schema: S
|
|
58
|
+
): RequestHandler<any, any, any, import('zod').infer<S>>
|
|
59
|
+
|
|
60
|
+
export function validator<S extends ZodTypeAny>(
|
|
61
|
+
target: 'params',
|
|
62
|
+
schema: S
|
|
63
|
+
): RequestHandler<import('zod').infer<S>, any, any, any>
|
|
64
|
+
|
|
65
|
+
export function validator<S extends StandardSchemaV1<any, any>>(
|
|
66
|
+
target: 'body',
|
|
67
|
+
schema: S
|
|
68
|
+
): RequestHandler<any, any, StandardSchemaV1.Infer<S>['output'], any>
|
|
69
|
+
|
|
70
|
+
export function validator<S extends StandardSchemaV1<any, any>>(
|
|
71
|
+
target: 'query',
|
|
72
|
+
schema: S
|
|
73
|
+
): RequestHandler<any, any, any, StandardSchemaV1.Infer<S>['output']>
|
|
74
|
+
|
|
75
|
+
export function validator<S extends StandardSchemaV1<any, any>>(
|
|
76
|
+
target: 'params',
|
|
77
|
+
schema: S
|
|
78
|
+
): RequestHandler<StandardSchemaV1.Infer<S>['output'], any, any, any>
|
|
79
|
+
|
|
80
|
+
export function validator(
|
|
81
|
+
target: ValidateTarget,
|
|
82
|
+
schema: ValidationSchema
|
|
83
|
+
): RequestHandler {
|
|
84
|
+
const middleware: RequestHandler = (req: Request, res: Response, next: NextFunction) => {
|
|
85
|
+
// Store schema for Vision (we'll update it later with actual route info)
|
|
86
|
+
const key = `${req.method}:${req.route?.path || req.path}`
|
|
87
|
+
if (req.route?.path) {
|
|
88
|
+
routeSchemas.set(key, {
|
|
89
|
+
method: req.method,
|
|
90
|
+
path: req.route.path,
|
|
91
|
+
schema,
|
|
92
|
+
target,
|
|
93
|
+
})
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Get data to validate based on target
|
|
97
|
+
let data: unknown
|
|
98
|
+
switch (target) {
|
|
99
|
+
case 'body':
|
|
100
|
+
data = req.body
|
|
101
|
+
break
|
|
102
|
+
case 'query':
|
|
103
|
+
data = req.query
|
|
104
|
+
break
|
|
105
|
+
case 'params':
|
|
106
|
+
data = req.params
|
|
107
|
+
break
|
|
108
|
+
default:
|
|
109
|
+
return next(new Error(`Invalid validation target: ${target}`))
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
// Validate data using UniversalValidator
|
|
114
|
+
const validated = UniversalValidator.parse(schema, data)
|
|
115
|
+
|
|
116
|
+
// Store validated data back
|
|
117
|
+
switch (target) {
|
|
118
|
+
case 'body':
|
|
119
|
+
req.body = validated
|
|
120
|
+
break
|
|
121
|
+
case 'query':
|
|
122
|
+
req.query = validated as any
|
|
123
|
+
break
|
|
124
|
+
case 'params':
|
|
125
|
+
req.params = validated as any
|
|
126
|
+
break
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
next()
|
|
130
|
+
} catch (error) {
|
|
131
|
+
if (error instanceof ValidationError) {
|
|
132
|
+
const requestId = req.headers['x-request-id'] as string
|
|
133
|
+
return res.status(400).json(
|
|
134
|
+
createValidationErrorResponse(error.issues, requestId)
|
|
135
|
+
)
|
|
136
|
+
}
|
|
137
|
+
next(error)
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Attach schema to middleware for Vision introspection
|
|
142
|
+
;(middleware as any).__visionSchema = schema
|
|
143
|
+
;(middleware as any).__visionTarget = target
|
|
144
|
+
|
|
145
|
+
return middleware
|
|
146
|
+
}
|
package/src/zod-validator.ts
CHANGED
|
@@ -22,6 +22,7 @@ export function getAllRouteSchemas(): Map<string, { method: string; path: string
|
|
|
22
22
|
type ValidateTarget = 'body' | 'query' | 'params'
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
|
+
* @deprecated Use validator instead
|
|
25
26
|
* Zod validator middleware for Express
|
|
26
27
|
* Similar to @hono/zod-validator but stores schema for Vision introspection
|
|
27
28
|
*
|
package/dist/zod-utils.d.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { ZodType } from 'zod';
|
|
2
|
-
import type { RequestBodySchema } from '@getvision/core';
|
|
3
|
-
/**
|
|
4
|
-
* Generate JSON template with comments from Zod schema
|
|
5
|
-
*/
|
|
6
|
-
export declare function generateZodTemplate(schema: ZodType): RequestBodySchema | undefined;
|
|
7
|
-
//# sourceMappingURL=zod-utils.d.ts.map
|
package/dist/zod-utils.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"zod-utils.d.ts","sourceRoot":"","sources":["../src/zod-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAyB,MAAM,KAAK,CAAA;AACzD,OAAO,KAAK,EAAE,iBAAiB,EAAe,MAAM,iBAAiB,CAAA;AAErE;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,GAAG,iBAAiB,GAAG,SAAS,CAalF"}
|
package/dist/zod-utils.js
DELETED
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Generate JSON template with comments from Zod schema
|
|
3
|
-
*/
|
|
4
|
-
export function generateZodTemplate(schema) {
|
|
5
|
-
try {
|
|
6
|
-
const fields = extractZodFields(schema);
|
|
7
|
-
const template = generateJsonTemplate(fields);
|
|
8
|
-
return {
|
|
9
|
-
template,
|
|
10
|
-
fields,
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
catch (error) {
|
|
14
|
-
console.warn('Failed to generate template from Zod schema:', error);
|
|
15
|
-
return undefined;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Extract fields from Zod schema (supports v3 and v4)
|
|
20
|
-
*/
|
|
21
|
-
function extractZodFields(schema, path = []) {
|
|
22
|
-
const fields = [];
|
|
23
|
-
// Support both v3 (_def) and v4 (def)
|
|
24
|
-
const def = schema.def || schema._def;
|
|
25
|
-
if (!def)
|
|
26
|
-
return fields;
|
|
27
|
-
// Unwrap ZodOptional, ZodNullable, ZodDefault - not needed for top level object
|
|
28
|
-
let unwrapped = schema;
|
|
29
|
-
const currentDef = unwrapped.def || unwrapped._def;
|
|
30
|
-
const typeName = currentDef?.type || currentDef?.typeName;
|
|
31
|
-
if (typeName === 'object' || typeName === 'ZodObject') {
|
|
32
|
-
// Get shape - it can be a function (getter) or direct object
|
|
33
|
-
const shapeValue = currentDef?.shape;
|
|
34
|
-
const shape = typeof shapeValue === 'function' ? shapeValue() : shapeValue;
|
|
35
|
-
for (const [key, value] of Object.entries(shape || {})) {
|
|
36
|
-
const fieldSchema = value;
|
|
37
|
-
const fieldDef = fieldSchema.def || fieldSchema._def;
|
|
38
|
-
const isOptional = fieldSchema.type === 'optional' ||
|
|
39
|
-
fieldDef?.type === 'optional' ||
|
|
40
|
-
fieldDef?.typeName === 'ZodOptional' ||
|
|
41
|
-
fieldDef?.typeName === 'ZodDefault';
|
|
42
|
-
// Get description - might be in wrapped schema for optional fields
|
|
43
|
-
let description = fieldDef?.description || fieldSchema.description;
|
|
44
|
-
if (!description && fieldDef?.wrapped) {
|
|
45
|
-
const wrappedDef = fieldDef.wrapped.def || fieldDef.wrapped._def;
|
|
46
|
-
description = wrappedDef?.description || fieldDef.wrapped.description;
|
|
47
|
-
}
|
|
48
|
-
// Determine type
|
|
49
|
-
let fieldType = getZodType(fieldSchema);
|
|
50
|
-
// Check for nested objects/arrays
|
|
51
|
-
const nested = extractZodFields(fieldSchema, [...path, key]);
|
|
52
|
-
fields.push({
|
|
53
|
-
name: key,
|
|
54
|
-
type: fieldType,
|
|
55
|
-
description,
|
|
56
|
-
required: !isOptional,
|
|
57
|
-
nested: nested.length > 0 ? nested : undefined,
|
|
58
|
-
example: getZodExample(fieldSchema, fieldType),
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
return fields;
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Get Zod type as string (supports v3 and v4)
|
|
66
|
-
*/
|
|
67
|
-
function getZodType(schema) {
|
|
68
|
-
let unwrapped = schema;
|
|
69
|
-
let def = unwrapped.def || unwrapped._def;
|
|
70
|
-
// Unwrap optional/nullable/default
|
|
71
|
-
while (def?.type === 'optional' ||
|
|
72
|
-
def?.type === 'nullable' ||
|
|
73
|
-
def?.type === 'default' ||
|
|
74
|
-
def?.typeName === 'ZodOptional' ||
|
|
75
|
-
def?.typeName === 'ZodNullable' ||
|
|
76
|
-
def?.typeName === 'ZodDefault') {
|
|
77
|
-
unwrapped = def?.innerType || def?.wrapped || unwrapped;
|
|
78
|
-
def = unwrapped.def || unwrapped._def;
|
|
79
|
-
}
|
|
80
|
-
// Support both v4 (type) and v3 (typeName)
|
|
81
|
-
const typeName = def?.type || def?.typeName || unwrapped.type;
|
|
82
|
-
switch (typeName) {
|
|
83
|
-
case 'string':
|
|
84
|
-
case 'ZodString':
|
|
85
|
-
return 'string';
|
|
86
|
-
case 'number':
|
|
87
|
-
case 'ZodNumber':
|
|
88
|
-
return 'number';
|
|
89
|
-
case 'boolean':
|
|
90
|
-
case 'ZodBoolean':
|
|
91
|
-
return 'boolean';
|
|
92
|
-
case 'array':
|
|
93
|
-
case 'ZodArray':
|
|
94
|
-
return 'array';
|
|
95
|
-
case 'object':
|
|
96
|
-
case 'ZodObject':
|
|
97
|
-
return 'object';
|
|
98
|
-
case 'enum':
|
|
99
|
-
case 'ZodEnum':
|
|
100
|
-
return 'enum';
|
|
101
|
-
case 'date':
|
|
102
|
-
case 'ZodDate':
|
|
103
|
-
return 'date';
|
|
104
|
-
default:
|
|
105
|
-
return 'any';
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
|
-
* Get example value for Zod type
|
|
110
|
-
*/
|
|
111
|
-
function getZodExample(schema, type) {
|
|
112
|
-
switch (type) {
|
|
113
|
-
case 'string': return '';
|
|
114
|
-
case 'number': return 0;
|
|
115
|
-
case 'boolean': return false;
|
|
116
|
-
case 'array': return [];
|
|
117
|
-
case 'object': return {};
|
|
118
|
-
default: return null;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Generate JSONC template with comments
|
|
123
|
-
*/
|
|
124
|
-
function generateJsonTemplate(fields, indent = 0) {
|
|
125
|
-
const lines = [];
|
|
126
|
-
const spacing = ' '.repeat(indent);
|
|
127
|
-
lines.push('{');
|
|
128
|
-
fields.forEach((field, index) => {
|
|
129
|
-
const isLast = index === fields.length - 1;
|
|
130
|
-
const description = field.description || field.name;
|
|
131
|
-
// Add comment
|
|
132
|
-
lines.push(`${spacing} // ${description}`);
|
|
133
|
-
// Add field
|
|
134
|
-
let value;
|
|
135
|
-
if (field.nested && field.nested.length > 0) {
|
|
136
|
-
value = generateJsonTemplate(field.nested, indent + 1);
|
|
137
|
-
}
|
|
138
|
-
else {
|
|
139
|
-
value = JSON.stringify(field.example);
|
|
140
|
-
}
|
|
141
|
-
lines.push(`${spacing} "${field.name}": ${value}${isLast ? '' : ','}`);
|
|
142
|
-
});
|
|
143
|
-
lines.push(`${spacing}}`);
|
|
144
|
-
return lines.join('\n');
|
|
145
|
-
}
|
package/src/zod-utils.ts
DELETED
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
import type { ZodType, ZodObject, ZodTypeAny } from 'zod'
|
|
2
|
-
import type { RequestBodySchema, SchemaField } from '@getvision/core'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Generate JSON template with comments from Zod schema
|
|
6
|
-
*/
|
|
7
|
-
export function generateZodTemplate(schema: ZodType): RequestBodySchema | undefined {
|
|
8
|
-
try {
|
|
9
|
-
const fields = extractZodFields(schema)
|
|
10
|
-
const template = generateJsonTemplate(fields)
|
|
11
|
-
|
|
12
|
-
return {
|
|
13
|
-
template,
|
|
14
|
-
fields,
|
|
15
|
-
}
|
|
16
|
-
} catch (error) {
|
|
17
|
-
console.warn('Failed to generate template from Zod schema:', error)
|
|
18
|
-
return undefined
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Extract fields from Zod schema (supports v3 and v4)
|
|
24
|
-
*/
|
|
25
|
-
function extractZodFields(schema: ZodTypeAny, path: string[] = []): SchemaField[] {
|
|
26
|
-
const fields: SchemaField[] = []
|
|
27
|
-
|
|
28
|
-
// Support both v3 (_def) and v4 (def)
|
|
29
|
-
const def = (schema as any).def || (schema as any)._def
|
|
30
|
-
if (!def) return fields
|
|
31
|
-
|
|
32
|
-
// Unwrap ZodOptional, ZodNullable, ZodDefault - not needed for top level object
|
|
33
|
-
let unwrapped: any = schema
|
|
34
|
-
|
|
35
|
-
const currentDef = (unwrapped as any).def || (unwrapped as any)._def
|
|
36
|
-
const typeName = currentDef?.type || currentDef?.typeName
|
|
37
|
-
|
|
38
|
-
if (typeName === 'object' || typeName === 'ZodObject') {
|
|
39
|
-
// Get shape - it can be a function (getter) or direct object
|
|
40
|
-
const shapeValue = currentDef?.shape
|
|
41
|
-
const shape = typeof shapeValue === 'function' ? shapeValue() : shapeValue
|
|
42
|
-
|
|
43
|
-
for (const [key, value] of Object.entries(shape || {})) {
|
|
44
|
-
const fieldSchema: any = value
|
|
45
|
-
const fieldDef = fieldSchema.def || fieldSchema._def
|
|
46
|
-
const isOptional = fieldSchema.type === 'optional' ||
|
|
47
|
-
fieldDef?.type === 'optional' ||
|
|
48
|
-
fieldDef?.typeName === 'ZodOptional' ||
|
|
49
|
-
fieldDef?.typeName === 'ZodDefault'
|
|
50
|
-
|
|
51
|
-
// Get description - might be in wrapped schema for optional fields
|
|
52
|
-
let description = fieldDef?.description || fieldSchema.description
|
|
53
|
-
if (!description && fieldDef?.wrapped) {
|
|
54
|
-
const wrappedDef = fieldDef.wrapped.def || fieldDef.wrapped._def
|
|
55
|
-
description = wrappedDef?.description || fieldDef.wrapped.description
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Determine type
|
|
59
|
-
let fieldType = getZodType(fieldSchema)
|
|
60
|
-
|
|
61
|
-
// Check for nested objects/arrays
|
|
62
|
-
const nested = extractZodFields(fieldSchema, [...path, key])
|
|
63
|
-
|
|
64
|
-
fields.push({
|
|
65
|
-
name: key,
|
|
66
|
-
type: fieldType,
|
|
67
|
-
description,
|
|
68
|
-
required: !isOptional,
|
|
69
|
-
nested: nested.length > 0 ? nested : undefined,
|
|
70
|
-
example: getZodExample(fieldSchema, fieldType),
|
|
71
|
-
})
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return fields
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Get Zod type as string (supports v3 and v4)
|
|
80
|
-
*/
|
|
81
|
-
function getZodType(schema: ZodTypeAny): string {
|
|
82
|
-
let unwrapped: any = schema
|
|
83
|
-
let def = (unwrapped as any).def || (unwrapped as any)._def
|
|
84
|
-
|
|
85
|
-
// Unwrap optional/nullable/default
|
|
86
|
-
while (def?.type === 'optional' ||
|
|
87
|
-
def?.type === 'nullable' ||
|
|
88
|
-
def?.type === 'default' ||
|
|
89
|
-
def?.typeName === 'ZodOptional' ||
|
|
90
|
-
def?.typeName === 'ZodNullable' ||
|
|
91
|
-
def?.typeName === 'ZodDefault') {
|
|
92
|
-
unwrapped = def?.innerType || def?.wrapped || unwrapped
|
|
93
|
-
def = (unwrapped as any).def || (unwrapped as any)._def
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Support both v4 (type) and v3 (typeName)
|
|
97
|
-
const typeName = def?.type || def?.typeName || (unwrapped as any).type
|
|
98
|
-
|
|
99
|
-
switch (typeName) {
|
|
100
|
-
case 'string':
|
|
101
|
-
case 'ZodString':
|
|
102
|
-
return 'string'
|
|
103
|
-
case 'number':
|
|
104
|
-
case 'ZodNumber':
|
|
105
|
-
return 'number'
|
|
106
|
-
case 'boolean':
|
|
107
|
-
case 'ZodBoolean':
|
|
108
|
-
return 'boolean'
|
|
109
|
-
case 'array':
|
|
110
|
-
case 'ZodArray':
|
|
111
|
-
return 'array'
|
|
112
|
-
case 'object':
|
|
113
|
-
case 'ZodObject':
|
|
114
|
-
return 'object'
|
|
115
|
-
case 'enum':
|
|
116
|
-
case 'ZodEnum':
|
|
117
|
-
return 'enum'
|
|
118
|
-
case 'date':
|
|
119
|
-
case 'ZodDate':
|
|
120
|
-
return 'date'
|
|
121
|
-
default:
|
|
122
|
-
return 'any'
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Get example value for Zod type
|
|
128
|
-
*/
|
|
129
|
-
function getZodExample(schema: ZodTypeAny, type: string): any {
|
|
130
|
-
switch (type) {
|
|
131
|
-
case 'string': return ''
|
|
132
|
-
case 'number': return 0
|
|
133
|
-
case 'boolean': return false
|
|
134
|
-
case 'array': return []
|
|
135
|
-
case 'object': return {}
|
|
136
|
-
default: return null
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Generate JSONC template with comments
|
|
142
|
-
*/
|
|
143
|
-
function generateJsonTemplate(fields: SchemaField[], indent = 0): string {
|
|
144
|
-
const lines: string[] = []
|
|
145
|
-
const spacing = ' '.repeat(indent)
|
|
146
|
-
|
|
147
|
-
lines.push('{')
|
|
148
|
-
|
|
149
|
-
fields.forEach((field, index) => {
|
|
150
|
-
const isLast = index === fields.length - 1
|
|
151
|
-
const description = field.description || field.name
|
|
152
|
-
|
|
153
|
-
// Add comment
|
|
154
|
-
lines.push(`${spacing} // ${description}`)
|
|
155
|
-
|
|
156
|
-
// Add field
|
|
157
|
-
let value: string
|
|
158
|
-
if (field.nested && field.nested.length > 0) {
|
|
159
|
-
value = generateJsonTemplate(field.nested, indent + 1)
|
|
160
|
-
} else {
|
|
161
|
-
value = JSON.stringify(field.example)
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
lines.push(`${spacing} "${field.name}": ${value}${isLast ? '' : ','}`)
|
|
165
|
-
})
|
|
166
|
-
|
|
167
|
-
lines.push(`${spacing}}`)
|
|
168
|
-
|
|
169
|
-
return lines.join('\n')
|
|
170
|
-
}
|