import { z } from "zod"; import { validatePassword } from "~/lib/validation"; import { VALIDATION_CONFIG } from "~/config"; /** * User API Validation Schemas * * Zod schemas for user-related operations like authentication, * profile updates, and password management */ // ============================================================================ // Custom Password Validator // ============================================================================ /** * Secure password validation with strength requirements * Minimum length from config, uppercase, lowercase, number, and special character */ const securePasswordSchema = z .string() .min( VALIDATION_CONFIG.MIN_PASSWORD_LENGTH, `Password must be at least ${VALIDATION_CONFIG.MIN_PASSWORD_LENGTH} characters` ) .refine( (password) => { const result = validatePassword(password); return result.isValid; }, (password) => { const result = validatePassword(password); return { message: result.errors.join(", ") || "Password does not meet requirements" }; } ); // ============================================================================ // Authentication Schemas // ============================================================================ /** * User registration schema */ export const registerUserSchema = z .object({ email: z.string().email(), password: securePasswordSchema, passwordConfirmation: z.string().min(VALIDATION_CONFIG.MIN_PASSWORD_LENGTH) }) .refine((data) => data.password === data.passwordConfirmation, { message: "Passwords do not match", path: ["passwordConfirmation"] }); /** * User login schema */ export const loginUserSchema = z.object({ email: z.string().email(), password: z.string().min(1, "Password is required") }); /** * OAuth provider schema */ export const oauthProviderSchema = z.enum(["google", "github"]); // ============================================================================ // Profile Management Schemas // ============================================================================ /** * Update email schema */ export const updateEmailSchema = z.object({ email: z.string().email() }); /** * Update display name schema */ export const updateDisplayNameSchema = z.object({ displayName: z.string().min(1).max(50) }); /** * Update profile image schema */ export const updateProfileImageSchema = z.object({ imageUrl: z.string().url() }); // ============================================================================ // Password Management Schemas // ============================================================================ /** * Change password schema (requires old password) */ export const changePasswordSchema = z .object({ oldPassword: z.string().min(1, "Current password is required"), newPassword: securePasswordSchema, newPasswordConfirmation: z .string() .min(VALIDATION_CONFIG.MIN_PASSWORD_LENGTH) }) .refine((data) => data.newPassword === data.newPasswordConfirmation, { message: "Passwords do not match", path: ["newPasswordConfirmation"] }) .refine((data) => data.oldPassword !== data.newPassword, { message: "New password must be different from current password", path: ["newPassword"] }); /** * Set password schema (for OAuth users adding password) */ export const setPasswordSchema = z .object({ newPassword: securePasswordSchema, newPasswordConfirmation: z .string() .min(VALIDATION_CONFIG.MIN_PASSWORD_LENGTH) }) .refine((data) => data.newPassword === data.newPasswordConfirmation, { message: "Passwords do not match", path: ["newPasswordConfirmation"] }); /** * Request password reset schema */ export const requestPasswordResetSchema = z.object({ email: z.string().email() }); /** * Reset password schema (with token) */ export const resetPasswordSchema = z .object({ token: z.string().min(1), newPassword: securePasswordSchema, newPasswordConfirmation: z .string() .min(VALIDATION_CONFIG.MIN_PASSWORD_LENGTH) }) .refine((data) => data.newPassword === data.newPasswordConfirmation, { message: "Passwords do not match", path: ["newPasswordConfirmation"] }); // ============================================================================ // Account Management Schemas // ============================================================================ /** * Delete account schema */ export const deleteAccountSchema = z.object({ password: z.string().min(1, "Password is required to delete account") }); /** * Email verification schema */ export const verifyEmailSchema = z.object({ token: z.string().min(1) }); // ============================================================================ // Type Exports // ============================================================================ export type RegisterUserInput = z.infer; export type LoginUserInput = z.infer; export type OAuthProvider = z.infer; export type UpdateEmailInput = z.infer; export type UpdateDisplayNameInput = z.infer; export type UpdateProfileImageInput = z.infer; export type ChangePasswordInput = z.infer; export type SetPasswordInput = z.infer; export type RequestPasswordResetInput = z.infer< typeof requestPasswordResetSchema >; export type ResetPasswordInput = z.infer; export type DeleteAccountInput = z.infer; export type VerifyEmailInput = z.infer;