@veloxts/validation 0.4.1 → 0.4.3
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/README.md +25 -368
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,399 +1,56 @@
|
|
|
1
1
|
# @veloxts/validation
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Pre-Alpha Notice:** This framework is in early development (v0.4.x). APIs are subject to change. Not recommended for production use.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## What is this?
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Type-safe validation package for the VeloxTS Framework, providing Zod integration and validation utilities.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
npm install @veloxts/validation
|
|
11
|
-
# or
|
|
12
|
-
pnpm add @veloxts/validation
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
Note: Zod is a peer dependency and will be installed automatically if not already present.
|
|
16
|
-
|
|
17
|
-
## Quick Start
|
|
18
|
-
|
|
19
|
-
```typescript
|
|
20
|
-
import { z, parse, InferOutput } from '@veloxts/validation';
|
|
21
|
-
|
|
22
|
-
// Define a schema
|
|
23
|
-
const UserSchema = z.object({
|
|
24
|
-
id: z.string().uuid(),
|
|
25
|
-
name: z.string().min(1),
|
|
26
|
-
email: z.string().email(),
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
// Infer the TypeScript type
|
|
30
|
-
type User = InferOutput<typeof UserSchema>;
|
|
31
|
-
|
|
32
|
-
// Parse and validate data
|
|
33
|
-
const user = parse(UserSchema, {
|
|
34
|
-
id: '123e4567-e89b-012d-3456-426614174000',
|
|
35
|
-
name: 'Alice',
|
|
36
|
-
email: 'alice@example.com',
|
|
37
|
-
});
|
|
38
|
-
// user is typed as User and validated
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
## Core API
|
|
42
|
-
|
|
43
|
-
### Validation Functions
|
|
44
|
-
|
|
45
|
-
#### `parse(schema, data)`
|
|
46
|
-
|
|
47
|
-
Parses data against a schema and throws a `ValidationError` if invalid.
|
|
48
|
-
|
|
49
|
-
```typescript
|
|
50
|
-
import { parse, ValidationError } from '@veloxts/validation';
|
|
51
|
-
|
|
52
|
-
try {
|
|
53
|
-
const user = parse(UserSchema, untrustedData);
|
|
54
|
-
// user is valid and typed
|
|
55
|
-
} catch (error) {
|
|
56
|
-
if (error instanceof ValidationError) {
|
|
57
|
-
console.log('Validation failed:', error.fields);
|
|
58
|
-
// error.fields contains field-specific error messages
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
```
|
|
9
|
+
## Part of @veloxts/velox
|
|
62
10
|
|
|
63
|
-
|
|
11
|
+
This package is part of the VeloxTS Framework. For the complete framework experience, install:
|
|
64
12
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
```typescript
|
|
68
|
-
import { safeParse } from '@veloxts/validation';
|
|
69
|
-
|
|
70
|
-
const result = safeParse(UserSchema, untrustedData);
|
|
71
|
-
|
|
72
|
-
if (result.success) {
|
|
73
|
-
console.log('Valid user:', result.data);
|
|
74
|
-
} else {
|
|
75
|
-
console.log('Validation errors:', result.error.issues);
|
|
76
|
-
}
|
|
13
|
+
```bash
|
|
14
|
+
npm install @veloxts/velox
|
|
77
15
|
```
|
|
78
16
|
|
|
79
|
-
|
|
17
|
+
Visit [@veloxts/velox](https://www.npmjs.com/package/@veloxts/velox) for the complete framework documentation.
|
|
80
18
|
|
|
81
|
-
|
|
19
|
+
## Standalone Installation
|
|
82
20
|
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
uuidSchema,
|
|
86
|
-
emailSchema,
|
|
87
|
-
urlSchema,
|
|
88
|
-
nonEmptyStringSchema,
|
|
89
|
-
datetimeSchema,
|
|
90
|
-
idParamSchema,
|
|
91
|
-
timestampFieldsSchema,
|
|
92
|
-
} from '@veloxts/validation';
|
|
93
|
-
|
|
94
|
-
// UUID validation
|
|
95
|
-
const id = parse(uuidSchema, '123e4567-e89b-012d-3456-426614174000');
|
|
96
|
-
|
|
97
|
-
// Email validation
|
|
98
|
-
const email = parse(emailSchema, 'user@example.com');
|
|
99
|
-
|
|
100
|
-
// URL validation
|
|
101
|
-
const website = parse(urlSchema, 'https://example.com');
|
|
102
|
-
|
|
103
|
-
// Non-empty string (trimmed, min 1 char)
|
|
104
|
-
const name = parse(nonEmptyStringSchema, ' Alice '); // "Alice"
|
|
105
|
-
|
|
106
|
-
// ISO datetime string
|
|
107
|
-
const timestamp = parse(datetimeSchema, '2025-01-01T00:00:00Z');
|
|
108
|
-
|
|
109
|
-
// Route parameter validation (e.g., /users/:id)
|
|
110
|
-
const params = parse(idParamSchema, { id: '123e4567-...' });
|
|
111
|
-
|
|
112
|
-
// Standard timestamp fields for entities
|
|
113
|
-
const EntitySchema = z.object({
|
|
114
|
-
id: uuidSchema,
|
|
115
|
-
name: nonEmptyStringSchema,
|
|
116
|
-
}).merge(timestampFieldsSchema);
|
|
21
|
+
```bash
|
|
22
|
+
npm install @veloxts/validation
|
|
117
23
|
```
|
|
118
24
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
Built-in support for offset-based and cursor-based pagination:
|
|
122
|
-
|
|
123
|
-
```typescript
|
|
124
|
-
import {
|
|
125
|
-
paginationInputSchema,
|
|
126
|
-
createPaginatedResponseSchema,
|
|
127
|
-
calculatePaginationMeta,
|
|
128
|
-
PAGINATION_DEFAULTS,
|
|
129
|
-
} from '@veloxts/validation';
|
|
130
|
-
|
|
131
|
-
// Input schema for pagination params
|
|
132
|
-
const input = parse(paginationInputSchema, {
|
|
133
|
-
page: 1,
|
|
134
|
-
limit: 20, // default: 10, max: 100
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
// Create a paginated response schema
|
|
138
|
-
const UserListSchema = createPaginatedResponseSchema(UserSchema);
|
|
139
|
-
|
|
140
|
-
// Calculate pagination metadata
|
|
141
|
-
const meta = calculatePaginationMeta({
|
|
142
|
-
page: 1,
|
|
143
|
-
limit: 10,
|
|
144
|
-
total: 95,
|
|
145
|
-
});
|
|
146
|
-
// { page: 1, limit: 10, total: 95, totalPages: 10, hasNext: true, hasPrev: false }
|
|
147
|
-
|
|
148
|
-
// Use in procedure definitions
|
|
149
|
-
export const userProcedures = defineProcedures('users', {
|
|
150
|
-
listUsers: procedure()
|
|
151
|
-
.input(paginationInputSchema)
|
|
152
|
-
.output(UserListSchema)
|
|
153
|
-
.query(async ({ input, ctx }) => {
|
|
154
|
-
const skip = (input.page - 1) * input.limit;
|
|
155
|
-
const [data, total] = await Promise.all([
|
|
156
|
-
ctx.db.user.findMany({ skip, take: input.limit }),
|
|
157
|
-
ctx.db.user.count(),
|
|
158
|
-
]);
|
|
25
|
+
Note: Zod is a peer dependency and will be installed automatically if not already present.
|
|
159
26
|
|
|
160
|
-
|
|
161
|
-
data,
|
|
162
|
-
meta: calculatePaginationMeta({
|
|
163
|
-
page: input.page,
|
|
164
|
-
limit: input.limit,
|
|
165
|
-
total,
|
|
166
|
-
}),
|
|
167
|
-
};
|
|
168
|
-
}),
|
|
169
|
-
});
|
|
170
|
-
```
|
|
27
|
+
## Documentation
|
|
171
28
|
|
|
172
|
-
|
|
29
|
+
For detailed documentation, usage examples, and API reference, see [GUIDE.md](./GUIDE.md).
|
|
173
30
|
|
|
174
|
-
|
|
31
|
+
## Quick Example
|
|
175
32
|
|
|
176
33
|
```typescript
|
|
177
|
-
import {
|
|
34
|
+
import { z, parse } from '@veloxts/validation';
|
|
178
35
|
|
|
179
36
|
const UserSchema = z.object({
|
|
180
37
|
id: z.string().uuid(),
|
|
181
|
-
name: z.string(),
|
|
182
|
-
email: z.string().email(),
|
|
183
|
-
password: z.string(),
|
|
184
|
-
createdAt: z.string().datetime(),
|
|
185
|
-
updatedAt: z.string().datetime(),
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
// Pick specific fields
|
|
189
|
-
const UserPublicSchema = pickFields(UserSchema, ['id', 'name', 'email']);
|
|
190
|
-
// { id, name, email }
|
|
191
|
-
|
|
192
|
-
// Omit fields
|
|
193
|
-
const UserWithoutPassword = omitFields(UserSchema, ['password']);
|
|
194
|
-
// { id, name, email, createdAt, updatedAt }
|
|
195
|
-
|
|
196
|
-
// Make all fields optional
|
|
197
|
-
const PartialUserSchema = makePartial(UserSchema);
|
|
198
|
-
// All fields are optional
|
|
199
|
-
|
|
200
|
-
// Make all fields optional except specified ones
|
|
201
|
-
const UserUpdateSchema = partialExcept(UserSchema, ['id']);
|
|
202
|
-
// id is required, all other fields are optional
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
#### Type Guards
|
|
206
|
-
|
|
207
|
-
```typescript
|
|
208
|
-
import { createTypeGuard } from '@veloxts/validation';
|
|
209
|
-
|
|
210
|
-
const isUser = createTypeGuard(UserSchema);
|
|
211
|
-
|
|
212
|
-
if (isUser(data)) {
|
|
213
|
-
// data is typed as User
|
|
214
|
-
console.log(data.name);
|
|
215
|
-
}
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
### String Coercion Schemas
|
|
219
|
-
|
|
220
|
-
Useful for parsing query parameters and form data:
|
|
221
|
-
|
|
222
|
-
```typescript
|
|
223
|
-
import {
|
|
224
|
-
numberStringSchema,
|
|
225
|
-
integerStringSchema,
|
|
226
|
-
booleanStringSchema,
|
|
227
|
-
} from '@veloxts/validation';
|
|
228
|
-
|
|
229
|
-
// Parse string to number
|
|
230
|
-
const age = parse(numberStringSchema, '25'); // 25 (number)
|
|
231
|
-
|
|
232
|
-
// Parse string to integer
|
|
233
|
-
const count = parse(integerStringSchema, '42'); // 42 (number)
|
|
234
|
-
|
|
235
|
-
// Parse string to boolean
|
|
236
|
-
const enabled = parse(booleanStringSchema, 'true'); // true (boolean)
|
|
237
|
-
// Accepts: "true", "false", "1", "0", "yes", "no"
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
## Using with Procedures
|
|
241
|
-
|
|
242
|
-
Validation schemas integrate seamlessly with VeloxTS procedures:
|
|
243
|
-
|
|
244
|
-
```typescript
|
|
245
|
-
import { procedure, defineProcedures } from '@veloxts/router';
|
|
246
|
-
import { z, emailSchema, nonEmptyStringSchema } from '@veloxts/validation';
|
|
247
|
-
|
|
248
|
-
const CreateUserInput = z.object({
|
|
249
|
-
name: nonEmptyStringSchema,
|
|
250
|
-
email: emailSchema,
|
|
251
|
-
age: z.number().int().min(18).optional(),
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
export const userProcedures = defineProcedures('users', {
|
|
255
|
-
createUser: procedure()
|
|
256
|
-
.input(CreateUserInput)
|
|
257
|
-
.output(UserSchema)
|
|
258
|
-
.mutation(async ({ input, ctx }) => {
|
|
259
|
-
// input is automatically validated and typed
|
|
260
|
-
// { name: string, email: string, age?: number }
|
|
261
|
-
return ctx.db.user.create({ data: input });
|
|
262
|
-
}),
|
|
263
|
-
});
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
## Type Inference
|
|
267
|
-
|
|
268
|
-
The package provides type inference utilities for extracting types from schemas:
|
|
269
|
-
|
|
270
|
-
```typescript
|
|
271
|
-
import { InferInput, InferOutput } from '@veloxts/validation';
|
|
272
|
-
|
|
273
|
-
const UserSchema = z.object({
|
|
274
|
-
email: z.string().email(),
|
|
275
|
-
age: z.number().transform((n) => n + 1),
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
// Input type (before transformation)
|
|
279
|
-
type UserInput = InferInput<typeof UserSchema>;
|
|
280
|
-
// { email: string; age: number }
|
|
281
|
-
|
|
282
|
-
// Output type (after transformation)
|
|
283
|
-
type UserOutput = InferOutput<typeof UserSchema>;
|
|
284
|
-
// { email: string; age: number } (age is transformed)
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
## Error Handling
|
|
288
|
-
|
|
289
|
-
Validation errors are automatically formatted with field-level details:
|
|
290
|
-
|
|
291
|
-
```typescript
|
|
292
|
-
import { ValidationError, parse } from '@veloxts/validation';
|
|
293
|
-
|
|
294
|
-
const UserSchema = z.object({
|
|
295
|
-
name: z.string().min(2),
|
|
38
|
+
name: z.string().min(1),
|
|
296
39
|
email: z.string().email(),
|
|
297
|
-
age: z.number().min(18),
|
|
298
|
-
});
|
|
299
|
-
|
|
300
|
-
try {
|
|
301
|
-
parse(UserSchema, {
|
|
302
|
-
name: 'A', // too short
|
|
303
|
-
email: 'invalid', // not an email
|
|
304
|
-
age: 16, // too young
|
|
305
|
-
});
|
|
306
|
-
} catch (error) {
|
|
307
|
-
if (error instanceof ValidationError) {
|
|
308
|
-
console.log(error.message); // "Validation failed"
|
|
309
|
-
console.log(error.statusCode); // 400
|
|
310
|
-
console.log(error.fields);
|
|
311
|
-
// {
|
|
312
|
-
// name: "String must contain at least 2 character(s)",
|
|
313
|
-
// email: "Invalid email",
|
|
314
|
-
// age: "Number must be greater than or equal to 18"
|
|
315
|
-
// }
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
```
|
|
319
|
-
|
|
320
|
-
## Advanced Features
|
|
321
|
-
|
|
322
|
-
### Custom Validators
|
|
323
|
-
|
|
324
|
-
Create reusable validation functions:
|
|
325
|
-
|
|
326
|
-
```typescript
|
|
327
|
-
import { createValidator } from '@veloxts/validation';
|
|
328
|
-
|
|
329
|
-
const validateUser = createValidator(UserSchema);
|
|
330
|
-
|
|
331
|
-
// Use in middleware or handlers
|
|
332
|
-
const user = validateUser(request.body);
|
|
333
|
-
```
|
|
334
|
-
|
|
335
|
-
### Schema Composition
|
|
336
|
-
|
|
337
|
-
Build complex schemas from simpler ones:
|
|
338
|
-
|
|
339
|
-
```typescript
|
|
340
|
-
import { timestampFieldsSchema, baseEntitySchema } from '@veloxts/validation';
|
|
341
|
-
import { z } from 'zod';
|
|
342
|
-
|
|
343
|
-
const PostSchema = baseEntitySchema.extend({
|
|
344
|
-
title: z.string().min(1).max(200),
|
|
345
|
-
content: z.string().min(1),
|
|
346
|
-
authorId: z.string().uuid(),
|
|
347
|
-
published: z.boolean().default(false),
|
|
348
40
|
});
|
|
349
41
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
### Pagination Defaults
|
|
356
|
-
|
|
357
|
-
Customize pagination defaults:
|
|
358
|
-
|
|
359
|
-
```typescript
|
|
360
|
-
import { PAGINATION_DEFAULTS } from '@veloxts/validation';
|
|
361
|
-
|
|
362
|
-
console.log(PAGINATION_DEFAULTS);
|
|
363
|
-
// {
|
|
364
|
-
// page: 1,
|
|
365
|
-
// limit: 10,
|
|
366
|
-
// maxLimit: 100,
|
|
367
|
-
// }
|
|
368
|
-
|
|
369
|
-
// Create custom pagination schema
|
|
370
|
-
const customPaginationSchema = z.object({
|
|
371
|
-
page: z.number().int().min(1).default(1),
|
|
372
|
-
limit: z.number().int().min(1).max(50).default(25), // custom max
|
|
42
|
+
const user = parse(UserSchema, {
|
|
43
|
+
id: '123e4567-e89b-012d-3456-426614174000',
|
|
44
|
+
name: 'Alice',
|
|
45
|
+
email: 'alice@example.com',
|
|
373
46
|
});
|
|
374
47
|
```
|
|
375
48
|
|
|
376
|
-
##
|
|
377
|
-
|
|
378
|
-
1. **Define schemas once, reuse everywhere**: Share schemas between frontend and backend for consistent validation.
|
|
379
|
-
|
|
380
|
-
2. **Use common schemas**: Leverage built-in schemas like `emailSchema`, `uuidSchema` for consistency.
|
|
381
|
-
|
|
382
|
-
3. **Compose schemas**: Build complex schemas from simpler ones using `.extend()`, `.merge()`, and `.pick()`.
|
|
383
|
-
|
|
384
|
-
4. **Validate early**: Use `input()` in procedures to validate at the API boundary.
|
|
385
|
-
|
|
386
|
-
5. **Type inference**: Use `InferOutput` to extract TypeScript types instead of manually defining them.
|
|
387
|
-
|
|
388
|
-
## Related Packages
|
|
389
|
-
|
|
390
|
-
- [@veloxts/core](/packages/core) - Core framework with error classes
|
|
391
|
-
- [@veloxts/router](/packages/router) - Procedure definitions using validation schemas
|
|
392
|
-
- [@veloxts/client](/packages/client) - Type-safe API client with inferred types
|
|
393
|
-
|
|
394
|
-
## TypeScript Support
|
|
49
|
+
## Learn More
|
|
395
50
|
|
|
396
|
-
|
|
51
|
+
- [Full Documentation](./GUIDE.md)
|
|
52
|
+
- [VeloxTS Framework](https://www.npmjs.com/package/@veloxts/velox)
|
|
53
|
+
- [GitHub Repository](https://github.com/veloxts/velox-ts-framework)
|
|
397
54
|
|
|
398
55
|
## License
|
|
399
56
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@veloxts/validation",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3",
|
|
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": "3.24.4",
|
|
26
|
-
"@veloxts/core": "0.4.
|
|
26
|
+
"@veloxts/core": "0.4.3"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@vitest/coverage-v8": "4.0.15",
|