import { z } from 'zod'; import { ALLOWED_UNITS } from '../config/constants'; export const signupSchema = z.object({ email: z.string().email('Invalid email format.'), password: z .string() .min(8, 'Password must be at least 8 characters.') .regex(/^[a-zA-Z0-9]+$/, 'Password must be alphanumeric.'), name: z.string().min(1, 'Name is required.').max(255), }); export const signinSchema = z.object({ email: z.string().email('Invalid email format.'), password: z.string().min(1, 'Password is required.'), }); export const googleAuthSchema = z.object({ id_token: z.string().min(1, 'id_token is required.'), }); export const passwordResetRequestSchema = z.object({ email: z.string().email('Invalid email format.'), }); export const passwordResetConfirmSchema = z.object({ token: z.string().min(1, 'Token is required.'), new_password: z .string() .min(8, 'Password must be at least 8 characters.') .regex(/^[a-zA-Z0-9]+$/, 'Password must be alphanumeric.'), }); export const addPantryItemSchema = z.object({ item_name: z.string().min(1, 'Item name is required.').max(255), quantity: z .number() .int('Quantity must be a whole number.') .positive('Quantity must be positive.'), }); export const updatePantryItemSchema = z.object({ quantity: z .number() .int('Quantity must be a whole number.') .positive('Quantity must be positive.'), last_modified: z.string().datetime().optional(), }); export const createShoppingListSchema = z.object({ list_name: z.string().min(1, 'List name is required.').max(255), }); export const addShoppingListItemSchema = z.object({ item_name: z.string().min(1, 'Item name is required.').max(255), quantity: z.number().positive('Quantity must be positive.'), unit: z.enum(ALLOWED_UNITS as [string, ...string[]], { errorMap: () => ({ message: `Unit must be one of: ${ALLOWED_UNITS.join(', ')}` }), }), }); export const updateShoppingListItemSchema = z .object({ quantity: z.number().positive('Quantity must be positive.').optional(), unit: z .enum(ALLOWED_UNITS as [string, ...string[]], { errorMap: () => ({ message: `Unit must be one of: ${ALLOWED_UNITS.join(', ')}` }), }) .optional(), checked_off: z.boolean().optional(), }) .refine( (data) => Object.keys(data).length > 0, { message: 'At least one field must be provided.' } ); export const addRecipesToListSchema = z.object({ recipe_ids: z .array(z.string().uuid('Each recipe_id must be a valid UUID.')) .min(1, 'At least one recipe_id is required.'), scale_factor: z.number().int().min(1).max(3).optional().default(1), }); export const recipeQuerySchema = z.object({ filter: z.enum(['all', 'can_make', 'can_partially_make']).optional().default('all'), page: z.coerce.number().int().positive().optional().default(1), limit: z.coerce.number().int().positive().max(50).optional().default(20), search: z.string().optional(), }); export const recipeDetailQuerySchema = z.object({ scale: z.coerce.number().int().min(1).max(3).optional().default(1), }); export const syncQuerySchema = z.object({ since: z.string().datetime('since must be a valid ISO 8601 timestamp.'), });