import { prisma } from '@/prisma'; import zod from 'zod/v4'; export const userEmailClientSchema = zod .email('Invalid email address') .min(3, 'Email is required'); export const userEmailSchema = userEmailClientSchema.refine(async (val) => { const existingUser = await prisma.user.findUnique({ where: { email: val }, }); return !existingUser; }, 'Email in use by another account'); export const userFirstNameSchema = zod .string() .min(1, 'First name is required') .max(32, 'First name must be at most 32 characters long'); export const userLastNameSchema = zod .string() .min(1, 'Last name is required') .max(32, 'Last name must be at most 32 characters long'); export const userNameClientSchema = zod .string() .min(3, 'Username is required') .max(32, 'Username must be at most 32 characters long') .regex( /^[a-zA-Z0-9_]+$/, 'Username can only contain letters, numbers, and underscores', ) .refine((val) => !disallowedUsernames.includes(val?.toLowerCase() || ''), { error: 'Username is not allowed', }); export const userNameSchema = userNameClientSchema.refine(async (val) => { const existingUser = await prisma.user.findUnique({ where: { name: val }, }); return !existingUser; }, 'Username in use by another account'); export const loginClientSchema = zod.object({ email: userEmailClientSchema.or(userNameClientSchema), password: zod.string().min(1, 'Password is required'), }); export const userIdSchema = zod .string() .min(1, 'User ID is required') .refine(async (val) => { const user = await prisma.user.findUnique({ where: { id: val }, }); return !!user; }, 'User not found'); export const registerSchema = zod .object({ firstName: userFirstNameSchema, lastName: userLastNameSchema, email: userEmailSchema, password: zod .string() .min(8, 'Password must be at least 8 characters long') .max(128, 'Password must be at most 128 characters long'), confirmPassword: zod .string() .min(8, 'Password must be at least 8 characters long') .max(128, 'Password must be at most 128 characters long'), username: userNameSchema, }) .refine((data) => data.password === data.confirmPassword, { error: 'Passwords do not match', path: ['confirmPassword'], }) .refine( (data) => !data.password.includes(data.firstName) && !data.password.includes(data.lastName) && !data.password.includes(data.email) && !data.password.includes(data.username), { error: 'Password cannot contain your first name, last name, email, or username', path: ['password'], }, ); export const registerClientSchema = zod .object({ firstName: userFirstNameSchema, lastName: userLastNameSchema, email: userEmailClientSchema, password: zod .string() .min(8, 'Password must be at least 8 characters long') .max(128, 'Password must be at most 128 characters long'), confirmPassword: zod .string() .min(8, 'Password must be at least 8 characters long') .max(128, 'Password must be at most 128 characters long'), username: userNameClientSchema, }) .refine((data) => data.password === data.confirmPassword, { error: 'Passwords do not match', path: ['confirmPassword'], }) .refine( (data) => !data.password.includes(data.firstName) && !data.password.includes(data.lastName) && !data.password.includes(data.email) && !data.password.includes(data.username), { error: 'Password cannot contain your first name, last name, email, or username', path: ['password'], }, ); export const disallowedUsernames = ['me', 'admin', 'search'];