0
# Validation and Error Handling
1
2
Comprehensive validation framework with sync/async validation functions, structured error payload types, and Zod integration for runtime validation within the XYO Protocol 2.0 ecosystem.
3
4
## Capabilities
5
6
### Payload Validation Functions
7
8
Type definitions for synchronous and asynchronous payload validation functions with flexible validation patterns.
9
10
```typescript { .api }
11
/**
12
* Synchronous payload validation function
13
* @param payload - Payload to validate
14
* @returns Boolean indicating validation result
15
*/
16
type SyncPayloadValidationFunction<T extends Payload = Payload> = (payload: T) => boolean;
17
18
/**
19
* Asynchronous payload validation function
20
* @param payload - Payload to validate
21
* @returns Promise resolving to boolean validation result
22
*/
23
type AsyncPayloadValidationFunction<T extends Payload = Payload> = (payload: T) => Promise<boolean>;
24
25
/**
26
* Union type for both sync and async validation functions
27
*/
28
type PayloadValidationFunction<T extends Payload = Payload> =
29
SyncPayloadValidationFunction<T> | AsyncPayloadValidationFunction<T>;
30
```
31
32
### Zod Validation Schemas
33
34
Zod-based validation schemas for runtime payload validation and type checking with full TypeScript integration.
35
36
```typescript { .api }
37
/**
38
* Import Zod for schema validation
39
*/
40
import * as z from 'zod';
41
42
/**
43
* Storage metadata Zod schema
44
*/
45
const StorageMetaZod: z.ZodObject<{
46
_hash: z.ZodType<Hash>;
47
_dataHash: z.ZodType<Hash>;
48
_sequence: z.ZodType<string>;
49
}>;
50
51
/**
52
* Base payload Zod schema
53
*/
54
const PayloadZod: z.ZodObject<{
55
schema: z.ZodType<Schema>;
56
}>;
57
58
/**
59
* Payload with storage metadata Zod schema
60
*/
61
const PayloadWithStorageMetaZod: z.ZodIntersection<
62
typeof PayloadZod,
63
typeof StorageMetaZod
64
>;
65
66
/**
67
* Any payload with flexible additional properties
68
*/
69
const AnyPayloadZod: z.ZodObject<{
70
schema: z.ZodType<Schema>;
71
}> & z.ZodCatchall<z.ZodAny>;
72
73
/**
74
* Any payload with storage metadata
75
*/
76
const AnyPayloadWithStorageMetaZod: z.ZodIntersection<
77
typeof AnyPayloadZod,
78
typeof StorageMetaZod
79
>;
80
81
/**
82
* Inferred types from Zod schemas
83
*/
84
type PayloadWithStorageMeta = z.infer<typeof PayloadWithStorageMetaZod>;
85
type AnyPayload = z.infer<typeof AnyPayloadZod>;
86
type AnyPayloadWithStorageMeta = z.infer<typeof AnyPayloadWithStorageMetaZod>;
87
88
/**
89
* Helper function to create payload schema with storage metadata
90
*/
91
function WithStorageMetaZod<T extends typeof PayloadZod>(valueZod: T): z.ZodIntersection<typeof StorageMetaZod, T>;
92
```
93
94
**Usage Examples:**
95
96
```typescript
97
import {
98
PayloadValidationFunction,
99
SyncPayloadValidationFunction,
100
AsyncPayloadValidationFunction,
101
Payload
102
} from "@xyo-network/payload-model";
103
104
// Define custom payload type
105
interface UserPayload extends Payload {
106
schema: "network.example.user";
107
name: string;
108
email: string;
109
age: number;
110
}
111
112
// Synchronous validation function
113
const validateUserSync: SyncPayloadValidationFunction<UserPayload> = (payload) => {
114
if (!payload.name || payload.name.length < 2) return false;
115
if (!payload.email || !payload.email.includes('@')) return false;
116
if (!payload.age || payload.age < 0 || payload.age > 150) return false;
117
return true;
118
};
119
120
// Asynchronous validation function
121
const validateUserAsync: AsyncPayloadValidationFunction<UserPayload> = async (payload) => {
122
// Simulate async validation (e.g., database check)
123
const emailExists = await checkEmailExists(payload.email);
124
if (emailExists) return false;
125
126
const nameValid = await validateNameFormat(payload.name);
127
return nameValid && payload.age >= 18;
128
};
129
130
// Generic validation function
131
const validateUser: PayloadValidationFunction<UserPayload> = validateUserSync;
132
133
// Use validation functions
134
const userPayload: UserPayload = {
135
schema: "network.example.user",
136
name: "Alice",
137
email: "alice@example.com",
138
age: 25
139
};
140
141
// Sync validation
142
if (validateUserSync(userPayload)) {
143
console.log("User payload is valid");
144
}
145
146
// Async validation
147
const isValid = await validateUserAsync(userPayload);
148
if (isValid) {
149
console.log("User payload passed async validation");
150
}
151
152
// Helper functions (examples)
153
async function checkEmailExists(email: string): Promise<boolean> {
154
// Simulate database check
155
return Promise.resolve(false);
156
}
157
158
async function validateNameFormat(name: string): Promise<boolean> {
159
// Simulate external validation service
160
return Promise.resolve(name.length >= 2 && /^[a-zA-Z\s]+$/.test(name));
161
}
162
```
163
164
### Module Error System
165
166
Structured error payload system for handling and communicating errors within XYO modules and operations.
167
168
```typescript { .api }
169
/**
170
* Schema constant for module errors
171
*/
172
const ModuleErrorSchema: "network.xyo.error.module";
173
174
/**
175
* Type alias for module error schema
176
*/
177
type ModuleErrorSchema = typeof ModuleErrorSchema;
178
179
/**
180
* Import JsonValue type from @xylabs/object
181
*/
182
import type { JsonValue } from '@xylabs/object';
183
184
/**
185
* Module error payload type with comprehensive error information
186
*/
187
type ModuleError = Payload<{
188
/** Additional error details as JSON value */
189
details?: JsonValue;
190
191
/** Human-readable error message */
192
message?: string;
193
194
/** Error name or type identifier */
195
name?: string;
196
197
/** Query hash or schema that caused the error */
198
query?: Hash | Schema;
199
200
/** Module error schema */
201
schema: ModuleErrorSchema;
202
}>;
203
204
/**
205
* Type guard for module error validation
206
*/
207
function isModuleError(value: unknown): value is ModuleError;
208
```
209
210
**Usage Examples:**
211
212
```typescript
213
import {
214
ModuleError,
215
ModuleErrorSchema,
216
isModuleError,
217
Payload,
218
Hash,
219
Schema
220
} from "@xyo-network/payload-model";
221
222
// Create basic module error
223
const basicError: ModuleError = {
224
schema: ModuleErrorSchema,
225
message: "Validation failed",
226
name: "ValidationError"
227
};
228
229
// Create detailed module error
230
const detailedError: ModuleError = {
231
schema: ModuleErrorSchema,
232
message: "User payload validation failed",
233
name: "UserValidationError",
234
details: {
235
field: "email",
236
reason: "Invalid email format",
237
value: "invalid-email",
238
code: "EMAIL_INVALID"
239
},
240
query: "network.example.user" as Schema
241
};
242
243
// Create error with query hash
244
const queryError: ModuleError = {
245
schema: ModuleErrorSchema,
246
message: "Query execution failed",
247
name: "QueryExecutionError",
248
details: {
249
timeout: true,
250
duration: 30000,
251
retries: 3
252
},
253
query: "0x1234567890abcdef..." as Hash
254
};
255
256
// Error handling utility
257
function createModuleError(
258
message: string,
259
name: string,
260
details?: any,
261
query?: Hash | Schema
262
): ModuleError {
263
return {
264
schema: ModuleErrorSchema,
265
message,
266
name,
267
details,
268
query
269
};
270
}
271
272
// Validate and handle errors
273
function processPayload(payload: unknown): Payload | ModuleError {
274
if (!payload || typeof payload !== 'object') {
275
return createModuleError(
276
"Invalid payload format",
277
"PayloadFormatError",
278
{ received: typeof payload }
279
);
280
}
281
282
if (isModuleError(payload)) {
283
console.error("Module error detected:", payload.message);
284
return payload;
285
}
286
287
// Process valid payload
288
return payload as Payload;
289
}
290
291
// Error result handling
292
function handleResult(result: Payload | ModuleError) {
293
if (isModuleError(result)) {
294
console.error(`Error: ${result.name} - ${result.message}`);
295
if (result.details) {
296
console.error("Details:", result.details);
297
}
298
if (result.query) {
299
console.error("Related query:", result.query);
300
}
301
return null;
302
}
303
304
return result;
305
}
306
307
// Use in validation pipeline
308
async function validateAndProcess<T extends Payload>(
309
payload: T,
310
validator: PayloadValidationFunction<T>
311
): Promise<T | ModuleError> {
312
try {
313
const isValid = await Promise.resolve(validator(payload));
314
315
if (!isValid) {
316
return createModuleError(
317
"Payload validation failed",
318
"ValidationError",
319
{ schema: payload.schema },
320
payload.schema
321
);
322
}
323
324
return payload;
325
} catch (error) {
326
return createModuleError(
327
"Validation process failed",
328
"ValidationProcessError",
329
{
330
originalError: error instanceof Error ? error.message : String(error),
331
schema: payload.schema
332
},
333
payload.schema
334
);
335
}
336
}
337
```
338
339
### Zod Integration
340
341
Runtime validation schemas using Zod for comprehensive payload structure validation and type safety.
342
343
```typescript { .api }
344
/**
345
* Base Zod schema for payload validation
346
*/
347
const PayloadZod: ZodType<{ schema: Schema }>;
348
349
/**
350
* Zod schema for storage metadata validation
351
*/
352
const StorageMetaZod: ZodType<{
353
_hash: Hash;
354
_dataHash: Hash;
355
_sequence: Sequence;
356
}>;
357
358
/**
359
* Zod schema for payload with storage metadata
360
*/
361
const PayloadWithStorageMetaZod: ZodType<PayloadWithStorageMeta>;
362
363
/**
364
* Catch-all Zod schema for any payload with additional properties
365
*/
366
const AnyPayloadZod: ZodType<AnyPayload>;
367
368
/**
369
* Catch-all Zod schema for any payload with storage metadata
370
*/
371
const AnyPayloadWithStorageMetaZod: ZodType<AnyPayloadWithStorageMeta>;
372
373
/**
374
* Helper function to add storage metadata validation to existing schema
375
*/
376
function WithStorageMetaZod<T extends typeof PayloadZod>(
377
valueZod: T
378
): ZodType<StorageMeta & z.infer<T>>;
379
380
/**
381
* Inferred types from Zod schemas
382
*/
383
type PayloadWithStorageMeta = z.infer<typeof PayloadWithStorageMetaZod>;
384
type AnyPayload = z.infer<typeof AnyPayloadZod>;
385
type AnyPayloadWithStorageMeta = z.infer<typeof AnyPayloadWithStorageMetaZod>;
386
```
387
388
**Usage Examples:**
389
390
```typescript
391
import {
392
PayloadZod,
393
AnyPayloadZod,
394
StorageMetaZod,
395
PayloadWithStorageMetaZod,
396
WithStorageMetaZod
397
} from "@xyo-network/payload-model";
398
import * as z from "zod";
399
400
// Create custom payload schema
401
const UserPayloadZod = z.object({
402
schema: z.literal("network.example.user"),
403
name: z.string().min(2).max(50),
404
email: z.string().email(),
405
age: z.number().int().min(0).max(150),
406
preferences: z.object({
407
theme: z.enum(["light", "dark"]).optional(),
408
notifications: z.boolean().optional()
409
}).optional()
410
});
411
412
type UserPayload = z.infer<typeof UserPayloadZod>;
413
414
// Validate user payload
415
const userData = {
416
schema: "network.example.user",
417
name: "Alice",
418
email: "alice@example.com",
419
age: 25,
420
preferences: {
421
theme: "dark",
422
notifications: true
423
}
424
};
425
426
try {
427
const validUser = UserPayloadZod.parse(userData);
428
console.log("Valid user:", validUser.name);
429
} catch (error) {
430
if (error instanceof z.ZodError) {
431
console.error("Validation errors:", error.errors);
432
}
433
}
434
435
// Validate any payload
436
const unknownPayload = {
437
schema: "network.example.unknown",
438
data: "some data",
439
timestamp: Date.now()
440
};
441
442
const validPayload = AnyPayloadZod.parse(unknownPayload);
443
console.log("Valid payload schema:", validPayload.schema);
444
445
// Add storage metadata to custom schema
446
const UserWithStorageZod = WithStorageMetaZod(UserPayloadZod);
447
448
const userWithStorageData = {
449
schema: "network.example.user",
450
name: "Bob",
451
email: "bob@example.com",
452
age: 30,
453
_hash: "0x123...",
454
_dataHash: "0x456...",
455
_sequence: "1234567890abcdef"
456
};
457
458
const validUserWithStorage = UserWithStorageZod.parse(userWithStorageData);
459
console.log("User with storage:", validUserWithStorage.name);
460
console.log("Storage hash:", validUserWithStorage._hash);
461
462
// Validation with error handling
463
function validatePayloadSafely<T>(
464
schema: z.ZodType<T>,
465
data: unknown
466
): { success: true; data: T } | { success: false; errors: z.ZodError } {
467
try {
468
const validated = schema.parse(data);
469
return { success: true, data: validated };
470
} catch (error) {
471
if (error instanceof z.ZodError) {
472
return { success: false, errors: error };
473
}
474
throw error;
475
}
476
}
477
478
// Use safe validation
479
const result = validatePayloadSafely(UserPayloadZod, userData);
480
if (result.success) {
481
console.log("Validated user:", result.data.name);
482
} else {
483
console.error("Validation failed:", result.errors.errors);
484
}
485
```
486
487
### Advanced Validation Patterns
488
489
Complex validation scenarios and patterns for robust payload processing.
490
491
```typescript { .api }
492
/**
493
* Schema validation with regex pattern
494
*/
495
const SchemaZod: ZodType<Schema>;
496
497
/**
498
* Schema validation functions
499
*/
500
function isSchema(value: unknown): value is Schema;
501
function asSchema(value: unknown): Schema;
502
```
503
504
**Usage Examples:**
505
506
```typescript
507
import {
508
PayloadValidationFunction,
509
ModuleError,
510
ModuleErrorSchema,
511
createModuleError,
512
SchemaZod,
513
AnyPayloadZod
514
} from "@xyo-network/payload-model";
515
import * as z from "zod";
516
517
// Complex validation pipeline
518
class PayloadValidator {
519
private validators: Map<string, PayloadValidationFunction> = new Map();
520
private schemas: Map<string, z.ZodType<any>> = new Map();
521
522
// Register schema validator
523
registerSchema<T extends Payload>(
524
schema: string,
525
zodSchema: z.ZodType<T>,
526
customValidator?: PayloadValidationFunction<T>
527
) {
528
this.schemas.set(schema, zodSchema);
529
if (customValidator) {
530
this.validators.set(schema, customValidator);
531
}
532
}
533
534
// Validate payload with comprehensive error reporting
535
async validatePayload(payload: unknown): Promise<{
536
valid: boolean;
537
payload?: Payload;
538
errors: ModuleError[];
539
}> {
540
const errors: ModuleError[] = [];
541
542
// Basic structure validation
543
try {
544
const basicPayload = AnyPayloadZod.parse(payload);
545
546
// Schema format validation
547
if (!SchemaZod.safeParse(basicPayload.schema).success) {
548
errors.push({
549
schema: ModuleErrorSchema,
550
message: "Invalid schema format",
551
name: "SchemaFormatError",
552
details: { schema: basicPayload.schema }
553
});
554
return { valid: false, errors };
555
}
556
557
// Schema-specific validation
558
const zodSchema = this.schemas.get(basicPayload.schema);
559
if (zodSchema) {
560
const zodResult = zodSchema.safeParse(payload);
561
if (!zodResult.success) {
562
errors.push({
563
schema: ModuleErrorSchema,
564
message: "Schema validation failed",
565
name: "ZodValidationError",
566
details: {
567
errors: zodResult.error.errors,
568
schema: basicPayload.schema
569
},
570
query: basicPayload.schema
571
});
572
}
573
}
574
575
// Custom validation
576
const customValidator = this.validators.get(basicPayload.schema);
577
if (customValidator) {
578
try {
579
const isValid = await Promise.resolve(customValidator(basicPayload));
580
if (!isValid) {
581
errors.push({
582
schema: ModuleErrorSchema,
583
message: "Custom validation failed",
584
name: "CustomValidationError",
585
details: { schema: basicPayload.schema },
586
query: basicPayload.schema
587
});
588
}
589
} catch (error) {
590
errors.push({
591
schema: ModuleErrorSchema,
592
message: "Custom validation error",
593
name: "CustomValidationException",
594
details: {
595
error: error instanceof Error ? error.message : String(error),
596
schema: basicPayload.schema
597
},
598
query: basicPayload.schema
599
});
600
}
601
}
602
603
return {
604
valid: errors.length === 0,
605
payload: errors.length === 0 ? basicPayload : undefined,
606
errors
607
};
608
609
} catch (error) {
610
errors.push({
611
schema: ModuleErrorSchema,
612
message: "Payload structure validation failed",
613
name: "StructureValidationError",
614
details: {
615
error: error instanceof Error ? error.message : String(error)
616
}
617
});
618
619
return { valid: false, errors };
620
}
621
}
622
623
// Batch validation
624
async validateBatch(payloads: unknown[]): Promise<{
625
valid: Payload[];
626
invalid: { payload: unknown; errors: ModuleError[] }[];
627
}> {
628
const valid: Payload[] = [];
629
const invalid: { payload: unknown; errors: ModuleError[] }[] = [];
630
631
for (const payload of payloads) {
632
const result = await this.validatePayload(payload);
633
if (result.valid && result.payload) {
634
valid.push(result.payload);
635
} else {
636
invalid.push({ payload, errors: result.errors });
637
}
638
}
639
640
return { valid, invalid };
641
}
642
}
643
644
// Usage example
645
const validator = new PayloadValidator();
646
647
// Register user schema
648
const UserSchema = z.object({
649
schema: z.literal("network.example.user"),
650
name: z.string().min(2),
651
email: z.string().email(),
652
age: z.number().int().min(0)
653
});
654
655
const userCustomValidator: PayloadValidationFunction = async (payload) => {
656
// Custom business logic validation
657
return payload.name !== "admin"; // Example: no admin users allowed
658
};
659
660
validator.registerSchema("network.example.user", UserSchema, userCustomValidator);
661
662
// Validate payloads
663
const testPayloads = [
664
{ schema: "network.example.user", name: "Alice", email: "alice@example.com", age: 25 },
665
{ schema: "network.example.user", name: "admin", email: "admin@example.com", age: 35 },
666
{ schema: "invalid.schema.format", data: "test" },
667
"invalid payload"
668
];
669
670
const batchResult = await validator.validateBatch(testPayloads);
671
console.log(`Valid: ${batchResult.valid.length}, Invalid: ${batchResult.invalid.length}`);
672
673
batchResult.invalid.forEach(({ payload, errors }) => {
674
console.error("Invalid payload:", errors.map(e => e.message));
675
});
676
```
677
678
## Advanced Error Handling Patterns
679
680
### Error Recovery and Transformation
681
682
```typescript
683
import { ModuleError, ModuleErrorSchema, Payload } from "@xyo-network/payload-model";
684
685
// Error recovery utilities
686
class ErrorRecovery {
687
// Attempt to recover from validation errors
688
static tryRecover(error: ModuleError, originalPayload: unknown): Payload | null {
689
if (error.name === "SchemaFormatError" && error.details?.schema) {
690
// Try to fix common schema format issues
691
const fixedSchema = this.fixSchemaFormat(error.details.schema);
692
if (fixedSchema && typeof originalPayload === 'object' && originalPayload) {
693
return { ...(originalPayload as object), schema: fixedSchema };
694
}
695
}
696
697
return null;
698
}
699
700
private static fixSchemaFormat(schema: string): string | null {
701
// Example: fix common schema format issues
702
if (schema.includes("_")) {
703
return schema.replace(/_/g, ".");
704
}
705
if (schema.toUpperCase() === schema) {
706
return schema.toLowerCase();
707
}
708
return null;
709
}
710
711
// Transform errors for external reporting
712
static transformError(error: ModuleError): {
713
code: string;
714
message: string;
715
details?: any;
716
} {
717
return {
718
code: error.name || "UNKNOWN_ERROR",
719
message: error.message || "An unknown error occurred",
720
details: error.details
721
};
722
}
723
}
724
```
725
726
## Types Reference
727
728
### Validation Function Types
729
730
- **`SyncPayloadValidationFunction<T>`**: Synchronous validation function type
731
- **`AsyncPayloadValidationFunction<T>`**: Asynchronous validation function type
732
- **`PayloadValidationFunction<T>`**: Union of sync/async validation functions
733
734
### Error Types
735
736
- **`ModuleError`**: Structured error payload type
737
- **`ModuleErrorSchema`**: Module error schema constant
738
739
### Zod Integration Types
740
741
- **`PayloadWithStorageMeta`**: Payload with storage metadata (inferred from Zod)
742
- **`AnyPayload`**: Any payload type (inferred from Zod)
743
- **`AnyPayloadWithStorageMeta`**: Any payload with storage metadata (inferred from Zod)
744
745
### Validation Schema Types
746
747
- **`PayloadZod`**: Base payload Zod schema
748
- **`StorageMetaZod`**: Storage metadata Zod schema
749
- **`PayloadWithStorageMetaZod`**: Payload with storage metadata Zod schema
750
- **`AnyPayloadZod`**: Catch-all payload Zod schema
751
- **`AnyPayloadWithStorageMetaZod`**: Catch-all payload with storage metadata Zod schema
752
753
### Constants
754
755
- **`ModuleErrorSchema`**: "network.xyo.error.module"
756
757
### Functions
758
759
- **`isModuleError(value)`**: Type guard for module errors
760
- **`WithStorageMetaZod<T>(schema)`**: Add storage metadata validation to Zod schema