UNPKG

arvox-backend

Version:

Un framework backend moderne et modulaire basé sur Hono, TypeScript et l'architecture hexagonale avec authentification Better Auth + Drizzle intégrée

161 lines 6.25 kB
import { z, ZodError } from 'zod'; /** * Utility class for common validation patterns and schemas */ export class ValidationUtil { /** * Common UUID validation schema */ static uuidSchema = z.string().uuid('Invalid UUID format'); /** * Common email validation schema */ static emailSchema = z.string().email('Invalid email format'); /** * Common password validation schema */ static passwordSchema = z.string() .min(8, 'Password must be at least 8 characters') .regex(/[A-Z]/, 'Password must contain at least one uppercase letter') .regex(/[a-z]/, 'Password must contain at least one lowercase letter') .regex(/[0-9]/, 'Password must contain at least one number'); /** * Common URL validation schema */ static urlSchema = z.string().url('Invalid URL format'); /** * Common phone validation schema */ static phoneSchema = z.string() .regex(/^\+?[1-9]\d{1,14}$/, 'Invalid phone number format'); /** * Pagination parameters validation schema */ static paginationSchema = z.object({ page: z.number().int().min(1, 'Page must be at least 1').default(1), limit: z.number().int().min(1, 'Limit must be at least 1').max(100, 'Limit cannot exceed 100').default(10) }); /** * Common date validation schemas */ static dateSchema = z.date(); static dateStringSchema = z.string().datetime('Invalid date format'); static futureDateSchema = z.date().refine(date => date > new Date(), 'Date must be in the future'); static pastDateSchema = z.date().refine(date => date < new Date(), 'Date must be in the past'); /** * File validation schemas */ static imageFileSchema = z.object({ type: z.string().refine(type => type.startsWith('image/'), 'File must be an image'), size: z.number().max(5 * 1024 * 1024, 'Image size must not exceed 5MB') }); static documentFileSchema = z.object({ type: z.string().refine(type => ['application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'].includes(type), 'File must be a PDF or Word document'), size: z.number().max(10 * 1024 * 1024, 'Document size must not exceed 10MB') }); /** * Create a custom file validation schema * @param allowedTypes - Array of allowed MIME types * @param maxSize - Maximum file size in bytes * @returns Zod schema for file validation */ static createFileSchema(allowedTypes, maxSize) { return z.object({ type: z.string().refine(type => allowedTypes.includes(type), `File type must be one of: ${allowedTypes.join(', ')}`), size: z.number().max(maxSize, `File size must not exceed ${maxSize / 1024 / 1024}MB`) }); } /** * Validate and parse data with a schema * @param data - Data to validate * @param schema - Zod schema * @returns Parsed and validated data * @throws Error with formatted validation message */ static validate(data, schema) { try { return schema.parse(data); } catch (error) { if (error instanceof ZodError) { const errorMessages = error.issues.map((err) => `${err.path.join('.')}: ${err.message}`).join(', '); throw new Error(`Validation failed: ${errorMessages}`); } throw error; } } /** * Safely validate data without throwing * @param data - Data to validate * @param schema - Zod schema * @returns Result object with success status and data or errors */ static safeValidate(data, schema) { const result = schema.safeParse(data); if (result.success) { return { success: true, data: result.data }; } else { const errors = result.error.issues.map((err) => ({ path: err.path.join('.'), message: err.message })); return { success: false, errors }; } } /** * Create a schema for array validation with optional constraints * @param itemSchema - Schema for individual items * @param minItems - Minimum number of items * @param maxItems - Maximum number of items * @returns Array validation schema */ static createArraySchema(itemSchema, minItems, maxItems) { let schema = z.array(itemSchema); if (minItems !== undefined) { schema = schema.min(minItems, `Array must contain at least ${minItems} items`); } if (maxItems !== undefined) { schema = schema.max(maxItems, `Array must contain at most ${maxItems} items`); } return schema; } /** * Create a conditional schema based on another field * @param conditionField - Field to check * @param conditionValue - Value to match * @param trueSchema - Schema to use if condition is true * @param falseSchema - Schema to use if condition is false * @returns Conditional validation schema */ static createConditionalSchema(conditionField, conditionValue, trueSchema, falseSchema) { return z.union([trueSchema, falseSchema]).refine((data) => { if (data[conditionField] === conditionValue) { return trueSchema.safeParse(data).success; } else { return falseSchema.safeParse(data).success; } }, 'Conditional validation failed'); } /** * Create a schema for partial updates (all fields optional) * @param baseSchema - Base schema to make partial * @returns Partial schema */ static createPartialSchema(baseSchema) { return baseSchema.partial(); } /** * Merge multiple schemas * @param schemas - Array of schemas to merge * @returns Merged schema */ static mergeSchemas(...schemas) { if (schemas.length === 0) { throw new Error('At least one schema is required'); } return schemas.reduce((acc, schema) => acc.merge(schema), schemas[0]); } } //# sourceMappingURL=validation.util.js.map