All files / src/lib validation-schemas.ts

100% Statements 125/125
100% Branches 6/6
100% Functions 2/2
100% Lines 125/125

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 1261x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 63x 63x 63x 63x 63x 63x 63x 63x 22x 21x 21x 28x 28x 28x 28x 28x 21x 21x 21x 1x 1x 63x  
import { z } from "zod";
 
/**
 * Validation schemas for API endpoints
 * All schemas use Zod for runtime validation
 */
 
// ============================================================================
// PRODUCT SCHEMAS
// ============================================================================
 
export const createProductSchema = z.object({
  title: z.string().min(1, "Title is required").max(255, "Title must be less than 255 characters"),
  description: z.string().optional().default(""),
  price: z.number().positive("Price must be positive"),
  discountedPrice: z.number().positive("Discounted price must be positive"),
  stock: z.number().nonnegative("Stock must be non-negative").optional().default(0),
  sku: z.string().optional(),
  categoryId: z.number().positive("Category ID must be positive"),
  images: z
    .array(
      z.object({
        url: z.string().url("Invalid image URL"),
        type: z.enum(["THUMBNAIL", "PREVIEW"])})
    )
    .optional()});
 
export const updateProductSchema = z.object({
  title: z.string().min(1).max(255).optional(),
  description: z.string().optional(),
  price: z.number().positive().optional(),
  discountedPrice: z.number().positive().optional(),
  stock: z.number().nonnegative().optional(),
  sku: z.string().optional(),
  categoryId: z.number().positive().optional()});
 
export type CreateProductInput = z.infer<typeof createProductSchema>;
export type UpdateProductInput = z.infer<typeof updateProductSchema>;
 
// ============================================================================
// CATEGORY SCHEMAS
// ============================================================================
 
export const createCategorySchema = z.object({
  title: z.string().min(1, "Title is required").max(255, "Title must be less than 255 characters"),
  slug: z.string().optional(),
  imageUrl: z.string().url("Invalid image URL").optional(),
  description: z.string().optional()});
 
export type CreateCategoryInput = z.infer<typeof createCategorySchema>;
 
// ============================================================================
// CART SCHEMAS
// ============================================================================
 
export const addToCartSchema = z.object({
  productId: z.coerce.number().positive("Product ID must be positive"),
  quantity: z.coerce.number().int().positive("Quantity must be at least 1")});
 
export const updateCartItemSchema = z.object({
  quantity: z.coerce.number().int().positive("Quantity must be at least 1")});
 
export type AddToCartInput = z.infer<typeof addToCartSchema>;
export type UpdateCartItemInput = z.infer<typeof updateCartItemSchema>;
 
// ============================================================================
// WISHLIST SCHEMAS
// ============================================================================
 
export const addToWishlistSchema = z.object({
  productId: z.coerce.number().positive("Product ID must be positive")});
 
export type AddToWishlistInput = z.infer<typeof addToWishlistSchema>;
 
// ============================================================================
// AUTH SCHEMAS
// ============================================================================
 
export const signupSchema = z.object({
  email: z.string().email("Invalid email address"),
  password: z.string().min(6, "Password must be at least 6 characters"),
  name: z.string().min(1, "Name is required").optional(),
  passwordConfirm: z.string()}).refine((data) => data.password === data.passwordConfirm, {
  message: "Passwords do not match",
  path: ["passwordConfirm"]});
 
export const signinSchema = z.object({
  email: z.string().email("Invalid email address"),
  password: z.string().min(1, "Password is required")});
 
export type SignupInput = z.infer<typeof signupSchema>;
export type SigninInput = z.infer<typeof signinSchema>;
 
// ============================================================================
// UTILITY FUNCTION
// ============================================================================
 
/**
 * Safely parse and validate input data
 * @param schema Zod schema to validate against
 * @param data Data to validate
 * @returns Validated data or null with error messages
 */
export function validateInput<T>(
  schema: z.ZodSchema<T>,
  data: unknown
): { success: boolean; data?: T; errors?: Record<string, string[]> } {
  try {
    const validatedData = schema.parse(data);
    return { success: true, data: validatedData };
  } catch (error) {
    if (error instanceof z.ZodError) {
      const errors: Record<string, string[]> = {};
      error.issues.forEach((issue) => {
        const path = issue.path.join(".");
        if (!errors[path]) {
          errors[path] = [];
        }
        errors[path].push(issue.message);
      });
      return { success: false, errors };
    }
    return { success: false, errors: { general: ["Validation failed"] } };
  }
}