'use server' import { prisma } from './db' import bcrypt from 'bcryptjs' import { z } from 'zod' import { signIn, signOut } from '@/auth' // Validation schemas const registerSchema = z.object({ email: z.string().email({ message: 'Invalid email address' }), password: z.string().min(8, { message: 'Password must be at least 8 characters' }), name: z.string().optional(), }) const loginSchema = z.object({ email: z.string().email({ message: 'Invalid email address' }), password: z.string().min(1, { message: 'Password is required' }), }) export type RegisterResult = | { success: true; userId: string } | { success: false; error: string } export type LoginResult = | { success: true } | { success: false; error: string } /** * Register a new user with email and password * Requirements: 1.1, 1.2, 1.3, 1.4, 1.5 */ export async function registerUser( email: string, password: string, name?: string ): Promise { try { // Validate input (Requirement 1.5 - password length validation) const validation = registerSchema.safeParse({ email, password, name }) if (!validation.success) { const errors = validation.error.issues.map((issue) => issue.message).join(', ') return { success: false, error: errors } } const { email: validEmail, password: validPassword, name: validName } = validation.data // Check if email already exists (Requirement 1.2 - duplicate email rejection) const existingUser = await prisma.user.findUnique({ where: { email: validEmail }, }) if (existingUser) { return { success: false, error: 'Email already registered' } } // Hash password (Requirement 1.3 - password hashing) const passwordHash = await bcrypt.hash(validPassword, 10) // Create user (Requirement 1.1 - create user with unique identifier) const user = await prisma.user.create({ data: { email: validEmail, passwordHash, name: validName || null, }, }) // Create session after successful registration (Requirement 1.4) try { await signIn('credentials', { email: validEmail, password: validPassword, redirect: false, }) } catch (error) { // If session creation fails, still return success since user was created console.error('Session creation failed after registration:', error) } return { success: true, userId: user.id } } catch (error) { console.error('Registration error:', error) // Handle unique constraint violation (shouldn't happen due to check above, but just in case) if (error instanceof Error && error.message.includes('Unique constraint')) { return { success: false, error: 'Email already registered' } } return { success: false, error: 'Registration failed. Please try again.' } } } /** * Login user with email and password * Requirements: 2.1, 2.2 */ export async function loginUser( email: string, password: string ): Promise { try { // Validate input (Requirement 2.1 - credential validation) const validation = loginSchema.safeParse({ email, password }) if (!validation.success) { const errors = validation.error.issues.map((issue) => issue.message).join(', ') return { success: false, error: errors } } const { email: validEmail, password: validPassword } = validation.data // Attempt to sign in (Requirement 2.1 - authenticate and create session) // The authorize function in auth.ts handles: // - Querying user from database // - Password verification with bcrypt // - Session creation on success await signIn('credentials', { email: validEmail, password: validPassword, redirect: false, }) // If signIn doesn't throw an error, authentication was successful return { success: true } } catch (error) { // Handle invalid credentials (Requirement 2.2) // NextAuth throws an error for invalid credentials console.error('Login error:', error) // Return generic error message to avoid revealing whether email exists return { success: false, error: 'Invalid email or password' } } } /** * Logout user and terminate session * Requirement: 2.5 - Logout terminates session and clears authentication tokens */ export async function logoutUser(): Promise { try { // Sign out using NextAuth - this will: // 1. Clear the session token // 2. Remove authentication cookies // 3. Terminate the session await signOut({ redirect: false }) } catch (error) { console.error('Logout error:', error) throw new Error('Logout failed') } } /** * Get current session * Requirements: 3.2 - Session validation and persistence */ export async function getCurrentSession() { try { const { auth } = await import('@/auth') const session = await auth() return session } catch (error) { console.error('Session retrieval error:', error) return null } } /** * Validate if user is authenticated * Requirements: 2.4, 3.3 - Session expiration and validation */ export async function isAuthenticated(): Promise { const session = await getCurrentSession() return !!session?.user }