import type { AuthenticatedContext } from "../../context.js"; import { implement } from "@orpc/server"; import { contract } from "@reviq/api-contract"; import { TOKEN_DURATIONS } from "../../utils/cookies.js"; import { generateExpiry, generateSecureToken } from "../../utils/crypto.js"; import { sendVerificationEmail } from "../../utils/email.js"; const os = implement(contract); /** * Resend email verification to authenticated user * Requires authentication * * Flow: * 1. Check if email is already verified (return early if so) * 2. Delete any existing verification tokens for this user * 3. Generate new secure token (64 hex chars) * 4. Create new email_verifications record with 24 hour expiry * 5. Send verification email (stubbed) */ export const resendVerificationEmail = os.auth.resendVerificationEmail.handler( async ({ context }) => { const ctx = context as AuthenticatedContext; // Check if email is already verified if (ctx.user.emailVerifiedAt !== null) { // Email already verified, return early return; } // Delete any existing verification tokens for this user await ctx.db .deleteFrom("email_verifications") .where("user_id", "=", ctx.user.id) .execute(); // Generate new secure token const token = generateSecureToken(); const expiresAt = generateExpiry(TOKEN_DURATIONS.EMAIL_VERIFICATION); // Create new verification record await ctx.db .insertInto("email_verifications") .values({ user_id: ctx.user.id, token, expires_at: expiresAt, }) .execute(); // Send verification email (stubbed) await sendVerificationEmail(ctx.user.email, token); }, );