import { z } from 'zod'; import { VALIDATION_LIMITS } from './constants'; /** * Validation schemas using Zod * * This module contains all validation schemas for forms and API inputs. * Schemas provide both runtime validation and TypeScript type generation. */ // Common validation patterns const requiredString = z.string().min(1, 'This field is required'); // Closet item validation export const closetItemSchema = z.object({ name: requiredString.max( VALIDATION_LIMITS.NAME_MAX_LENGTH, `Name must be less than ${VALIDATION_LIMITS.NAME_MAX_LENGTH} characters` ), brand: requiredString.max( VALIDATION_LIMITS.BRAND_MAX_LENGTH, `Brand must be less than ${VALIDATION_LIMITS.BRAND_MAX_LENGTH} characters` ), category: requiredString, imageFile: z.instanceof(File).optional(), imageUrl: z.string().url().optional(), }); export type ClosetItemInput = z.infer; // Search filters validation (simplified to only search query, page, limit) export const searchFiltersSchema = z.object({ query: z .string() .max(VALIDATION_LIMITS.SEARCH_QUERY_MAX_LENGTH, 'Search query too long') .optional(), page: z.number().min(1).optional(), limit: z .number() .min(1) .max(VALIDATION_LIMITS.MAX_PAGINATION_LIMIT) .optional(), }); export type SearchFiltersInput = z.infer; // API error validation export const apiErrorSchema = z.object({ message: z.string(), code: z.string().optional(), details: z.record(z.unknown()).optional(), }); export type ApiError = z.infer; // Pagination validation export const paginationSchema = z.object({ page: z.number().min(1), limit: z.number().min(1).max(VALIDATION_LIMITS.MAX_PAGINATION_LIMIT), total: z.number().min(0), totalPages: z.number().min(0), }); export type PaginationInfo = z.infer; // Generic list response validation export const createListResponseSchema = ( itemSchema: T ) => z.object({ data: z.array(itemSchema), pagination: paginationSchema.optional(), meta: z.record(z.unknown()).optional(), }); // Validation helpers export const validateInput = ( schema: T, data: unknown ): z.infer => { const result = schema.safeParse(data); if (!result.success) { throw new Error( `Validation failed: ${result.error.issues.map((i) => i.message).join(', ')}` ); } // eslint-disable-next-line @typescript-eslint/no-unsafe-return return result.data; };