@veloxts/validation 0.7.1 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/dist/middleware.d.ts +1 -1
- package/dist/middleware.js +32 -33
- package/dist/naming.js +1 -3
- package/dist/schemas/query.js +13 -12
- package/dist/schemas/serialization.js +26 -45
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# @veloxts/validation
|
|
2
2
|
|
|
3
|
+
## 0.7.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- chore(auth,core,create,cli,client,orm,mcp,router,validation,web): simplify code for clarity and maintainability
|
|
8
|
+
- Updated dependencies
|
|
9
|
+
- @veloxts/core@0.7.2
|
|
10
|
+
|
|
3
11
|
## 0.7.1
|
|
4
12
|
|
|
5
13
|
### Patch Changes
|
package/dist/middleware.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* @module middleware
|
|
8
8
|
*/
|
|
9
9
|
import { ValidationError } from '@veloxts/core';
|
|
10
|
-
import { ZodError,
|
|
10
|
+
import type { ZodError, ZodType } from 'zod';
|
|
11
11
|
import type { AnySchema, AnyZodSchema, SafeParseResult } from './types.js';
|
|
12
12
|
/**
|
|
13
13
|
* Transforms Zod validation issues into a field-error map
|
package/dist/middleware.js
CHANGED
|
@@ -7,11 +7,27 @@
|
|
|
7
7
|
* @module middleware
|
|
8
8
|
*/
|
|
9
9
|
import { ValidationError } from '@veloxts/core';
|
|
10
|
-
import { ZodError } from 'zod';
|
|
11
10
|
import { isSchema, isZodSchema } from './types.js';
|
|
12
11
|
// ============================================================================
|
|
13
12
|
// Error Transformation
|
|
14
13
|
// ============================================================================
|
|
14
|
+
/**
|
|
15
|
+
* Filters symbol keys from a Zod issue path, keeping only string and number segments.
|
|
16
|
+
* Zod 4 issue paths use `PropertyKey[]` which may include symbols.
|
|
17
|
+
*/
|
|
18
|
+
function filterIssuePath(path) {
|
|
19
|
+
return path.filter((p) => typeof p !== 'symbol');
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Converts Zod issues into framework-friendly ValidationIssue objects
|
|
23
|
+
*/
|
|
24
|
+
function zodIssuesToValidationIssues(issues) {
|
|
25
|
+
return issues.map((issue) => ({
|
|
26
|
+
path: filterIssuePath(issue.path),
|
|
27
|
+
message: issue.message,
|
|
28
|
+
code: issue.code,
|
|
29
|
+
}));
|
|
30
|
+
}
|
|
15
31
|
/**
|
|
16
32
|
* Transforms Zod validation issues into a field-error map
|
|
17
33
|
*
|
|
@@ -22,7 +38,6 @@ export function formatZodErrors(issues) {
|
|
|
22
38
|
const fields = {};
|
|
23
39
|
for (const issue of issues) {
|
|
24
40
|
const path = issue.path.join('.') || '_root';
|
|
25
|
-
// Only keep the first error for each field
|
|
26
41
|
if (!(path in fields)) {
|
|
27
42
|
fields[path] = issue.message;
|
|
28
43
|
}
|
|
@@ -37,12 +52,8 @@ export function formatZodErrors(issues) {
|
|
|
37
52
|
* @returns ValidationError with field-specific errors
|
|
38
53
|
*/
|
|
39
54
|
export function zodErrorToValidationError(error, customMessage) {
|
|
40
|
-
const fields = formatZodErrors(error.issues
|
|
41
|
-
|
|
42
|
-
message: i.message,
|
|
43
|
-
})));
|
|
44
|
-
const message = customMessage ?? 'Validation failed';
|
|
45
|
-
return new ValidationError(message, fields);
|
|
55
|
+
const fields = formatZodErrors(zodIssuesToValidationIssues(error.issues));
|
|
56
|
+
return new ValidationError(customMessage ?? 'Validation failed', fields);
|
|
46
57
|
}
|
|
47
58
|
// ============================================================================
|
|
48
59
|
// Validation Functions
|
|
@@ -68,28 +79,21 @@ export function zodErrorToValidationError(error, customMessage) {
|
|
|
68
79
|
* ```
|
|
69
80
|
*/
|
|
70
81
|
export function parse(schema, data, errorMessage) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
return result.data;
|
|
76
|
-
}
|
|
77
|
-
throw new ValidationError(errorMessage ?? 'Validation failed', formatZodErrors(result.error));
|
|
78
|
-
}
|
|
79
|
-
if (isZodSchema(schema)) {
|
|
80
|
-
return schema.parse(data);
|
|
82
|
+
if (isSchema(schema)) {
|
|
83
|
+
const result = schema.safeParse(data);
|
|
84
|
+
if (result.success) {
|
|
85
|
+
return result.data;
|
|
81
86
|
}
|
|
82
|
-
throw new
|
|
87
|
+
throw new ValidationError(errorMessage ?? 'Validation failed', formatZodErrors(result.error));
|
|
83
88
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
if (error instanceof ZodError) {
|
|
89
|
-
throw zodErrorToValidationError(error, errorMessage);
|
|
89
|
+
if (isZodSchema(schema)) {
|
|
90
|
+
const result = schema.safeParse(data);
|
|
91
|
+
if (result.success) {
|
|
92
|
+
return result.data;
|
|
90
93
|
}
|
|
91
|
-
throw error;
|
|
94
|
+
throw zodErrorToValidationError(result.error, errorMessage);
|
|
92
95
|
}
|
|
96
|
+
throw new Error('Invalid schema provided to parse()');
|
|
93
97
|
}
|
|
94
98
|
/**
|
|
95
99
|
* Safely parses data without throwing
|
|
@@ -116,18 +120,13 @@ export function safeParse(schema, data) {
|
|
|
116
120
|
return schema.safeParse(data);
|
|
117
121
|
}
|
|
118
122
|
if (isZodSchema(schema)) {
|
|
119
|
-
const
|
|
120
|
-
const result = zodSchema.safeParse(data);
|
|
123
|
+
const result = schema.safeParse(data);
|
|
121
124
|
if (result.success) {
|
|
122
125
|
return { success: true, data: result.data };
|
|
123
126
|
}
|
|
124
127
|
return {
|
|
125
128
|
success: false,
|
|
126
|
-
error: result.error.issues
|
|
127
|
-
path: issue.path.filter((p) => typeof p !== 'symbol'),
|
|
128
|
-
message: issue.message,
|
|
129
|
-
code: issue.code,
|
|
130
|
-
})),
|
|
129
|
+
error: zodIssuesToValidationIssues(result.error.issues),
|
|
131
130
|
};
|
|
132
131
|
}
|
|
133
132
|
return {
|
package/dist/naming.js
CHANGED
|
@@ -76,7 +76,5 @@ export function inferMethodFromName(procedureName) {
|
|
|
76
76
|
* ```
|
|
77
77
|
*/
|
|
78
78
|
export function isQueryProcedure(procedureName) {
|
|
79
|
-
return (procedureName
|
|
80
|
-
procedureName.startsWith('list') ||
|
|
81
|
-
procedureName.startsWith('find'));
|
|
79
|
+
return inferMethodFromName(procedureName) === 'GET';
|
|
82
80
|
}
|
package/dist/schemas/query.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* @module schemas/query
|
|
9
9
|
*/
|
|
10
10
|
import { z } from 'zod';
|
|
11
|
+
import { createPaginationSchema } from './pagination.js';
|
|
11
12
|
export function queryNumber(defaultValue) {
|
|
12
13
|
const base = z.coerce.number();
|
|
13
14
|
return defaultValue !== undefined ? base.default(defaultValue) : base;
|
|
@@ -88,19 +89,23 @@ export function queryArray(options = {}) {
|
|
|
88
89
|
.filter(Boolean));
|
|
89
90
|
// Apply min/max constraints via refinement if needed
|
|
90
91
|
if (min !== undefined || max !== undefined) {
|
|
92
|
+
let message;
|
|
93
|
+
if (min !== undefined && max !== undefined) {
|
|
94
|
+
message = `Array must have ${min}-${max} items`;
|
|
95
|
+
}
|
|
96
|
+
else if (min !== undefined) {
|
|
97
|
+
message = `Array must have at least ${min} item(s)`;
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
message = `Array must have at most ${max} item(s)`;
|
|
101
|
+
}
|
|
91
102
|
return baseSchema.refine((arr) => {
|
|
92
103
|
if (min !== undefined && arr.length < min)
|
|
93
104
|
return false;
|
|
94
105
|
if (max !== undefined && arr.length > max)
|
|
95
106
|
return false;
|
|
96
107
|
return true;
|
|
97
|
-
}, {
|
|
98
|
-
message: min !== undefined && max !== undefined
|
|
99
|
-
? `Array must have ${min}-${max} items`
|
|
100
|
-
: min !== undefined
|
|
101
|
-
? `Array must have at least ${min} item(s)`
|
|
102
|
-
: `Array must have at most ${max} item(s)`,
|
|
103
|
-
});
|
|
108
|
+
}, { message });
|
|
104
109
|
}
|
|
105
110
|
return baseSchema;
|
|
106
111
|
}
|
|
@@ -140,9 +145,5 @@ export function queryEnum(values, defaultValue) {
|
|
|
140
145
|
* ```
|
|
141
146
|
*/
|
|
142
147
|
export function pagination(options = {}) {
|
|
143
|
-
|
|
144
|
-
return z.object({
|
|
145
|
-
page: z.coerce.number().int().positive().default(defaultPage),
|
|
146
|
-
limit: z.coerce.number().int().positive().max(maxLimit).default(defaultLimit),
|
|
147
|
-
});
|
|
148
|
+
return createPaginationSchema(options);
|
|
148
149
|
}
|
|
@@ -10,6 +10,29 @@ import { z } from 'zod';
|
|
|
10
10
|
// ============================================================================
|
|
11
11
|
// Prisma Decimal Helpers
|
|
12
12
|
// ============================================================================
|
|
13
|
+
/**
|
|
14
|
+
* Converts a Prisma Decimal, number, or string to a number.
|
|
15
|
+
* Shared conversion logic for all prismaDecimal variants.
|
|
16
|
+
*/
|
|
17
|
+
function coerceToNumber(val) {
|
|
18
|
+
if (typeof val === 'object' &&
|
|
19
|
+
val !== null &&
|
|
20
|
+
'toNumber' in val &&
|
|
21
|
+
typeof val.toNumber === 'function') {
|
|
22
|
+
return val.toNumber();
|
|
23
|
+
}
|
|
24
|
+
if (typeof val === 'number') {
|
|
25
|
+
return val;
|
|
26
|
+
}
|
|
27
|
+
if (typeof val === 'string') {
|
|
28
|
+
const num = Number.parseFloat(val);
|
|
29
|
+
if (Number.isNaN(num)) {
|
|
30
|
+
throw new Error(`Cannot convert "${val}" to number`);
|
|
31
|
+
}
|
|
32
|
+
return num;
|
|
33
|
+
}
|
|
34
|
+
throw new Error(`Cannot convert ${typeof val} to number`);
|
|
35
|
+
}
|
|
13
36
|
/**
|
|
14
37
|
* Creates a field that accepts Prisma Decimal and transforms to number
|
|
15
38
|
*
|
|
@@ -30,23 +53,7 @@ export function prismaDecimal() {
|
|
|
30
53
|
if (val === null || val === undefined) {
|
|
31
54
|
throw new Error('Expected Decimal, got null/undefined');
|
|
32
55
|
}
|
|
33
|
-
|
|
34
|
-
if (typeof val === 'object' && 'toNumber' in val && typeof val.toNumber === 'function') {
|
|
35
|
-
return val.toNumber();
|
|
36
|
-
}
|
|
37
|
-
// Already a number
|
|
38
|
-
if (typeof val === 'number') {
|
|
39
|
-
return val;
|
|
40
|
-
}
|
|
41
|
-
// String (from JSON)
|
|
42
|
-
if (typeof val === 'string') {
|
|
43
|
-
const num = Number.parseFloat(val);
|
|
44
|
-
if (Number.isNaN(num)) {
|
|
45
|
-
throw new Error(`Cannot convert "${val}" to number`);
|
|
46
|
-
}
|
|
47
|
-
return num;
|
|
48
|
-
}
|
|
49
|
-
throw new Error(`Cannot convert ${typeof val} to number`);
|
|
56
|
+
return coerceToNumber(val);
|
|
50
57
|
});
|
|
51
58
|
}
|
|
52
59
|
/**
|
|
@@ -59,20 +66,7 @@ export function prismaDecimalNullable() {
|
|
|
59
66
|
if (val === null || val === undefined) {
|
|
60
67
|
return null;
|
|
61
68
|
}
|
|
62
|
-
|
|
63
|
-
return val.toNumber();
|
|
64
|
-
}
|
|
65
|
-
if (typeof val === 'number') {
|
|
66
|
-
return val;
|
|
67
|
-
}
|
|
68
|
-
if (typeof val === 'string') {
|
|
69
|
-
const num = Number.parseFloat(val);
|
|
70
|
-
if (Number.isNaN(num)) {
|
|
71
|
-
throw new Error(`Cannot convert "${val}" to number`);
|
|
72
|
-
}
|
|
73
|
-
return num;
|
|
74
|
-
}
|
|
75
|
-
throw new Error(`Cannot convert ${typeof val} to number`);
|
|
69
|
+
return coerceToNumber(val);
|
|
76
70
|
});
|
|
77
71
|
}
|
|
78
72
|
/**
|
|
@@ -85,20 +79,7 @@ export function prismaDecimalOptional() {
|
|
|
85
79
|
if (val === null || val === undefined) {
|
|
86
80
|
return undefined;
|
|
87
81
|
}
|
|
88
|
-
|
|
89
|
-
return val.toNumber();
|
|
90
|
-
}
|
|
91
|
-
if (typeof val === 'number') {
|
|
92
|
-
return val;
|
|
93
|
-
}
|
|
94
|
-
if (typeof val === 'string') {
|
|
95
|
-
const num = Number.parseFloat(val);
|
|
96
|
-
if (Number.isNaN(num)) {
|
|
97
|
-
throw new Error(`Cannot convert "${val}" to number`);
|
|
98
|
-
}
|
|
99
|
-
return num;
|
|
100
|
-
}
|
|
101
|
-
throw new Error(`Cannot convert ${typeof val} to number`);
|
|
82
|
+
return coerceToNumber(val);
|
|
102
83
|
});
|
|
103
84
|
}
|
|
104
85
|
// ============================================================================
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@veloxts/validation",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.2",
|
|
4
4
|
"description": "Zod integration and validation middleware for VeloxTS framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"zod": "4.3.6",
|
|
26
|
-
"@veloxts/core": "0.7.
|
|
26
|
+
"@veloxts/core": "0.7.2"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@vitest/coverage-v8": "4.0.18",
|