import { sql } from "@/lib/db"; import { hashPassword } from "@/lib/password"; import { sendEmail } from "@/lib/mailer"; import { CODE_TTL_MINUTES, generateCode, hashCode, verificationEmail, } from "@/lib/otp"; const normalizePhone = (raw: string): string => { const cleaned = raw.replace(/[^\d+]/g, ""); if (cleaned.startsWith("+")) return cleaned; return `+961${cleaned.replace(/^0+/, "")}`; }; export async function POST(req: Request) { const { name, email, phone, password, role } = await req.json(); if (!name?.trim() || !email?.trim() || !password) { return Response.json( { error: "Name, email and password are required." }, { status: 400 }, ); } const normalizedRole = role === "driver" ? "driver" : "rider"; if (typeof password !== "string" || password.length < 8) { return Response.json( { error: "Password must be at least 8 characters." }, { status: 400 }, ); } try { const existing = await sql<{ id: string; email_verified: boolean }>` SELECT id, email_verified FROM users WHERE email = ${email.trim().toLowerCase()} `; if (existing[0]?.email_verified) { return Response.json( { error: "An account with this email already exists. Please sign in." }, { status: 409 }, ); } // Unverified rows may be re-registered (e.g. the first mail never arrived). await sql` INSERT INTO users (name, email, phone, password_hash, email_verified, role) VALUES ( ${name.trim()}, ${email.trim().toLowerCase()}, ${phone ? normalizePhone(phone) : null}, ${hashPassword(password)}, FALSE, ${normalizedRole} ) ON CONFLICT (email) DO UPDATE SET name = EXCLUDED.name, phone = COALESCE(EXCLUDED.phone, users.phone), password_hash = EXCLUDED.password_hash, role = EXCLUDED.role `; const code = generateCode(); await sql` INSERT INTO email_verification_codes (email, code_hash, expires_at) VALUES ( ${email.trim().toLowerCase()}, ${hashCode(email.trim().toLowerCase(), code)}, CURRENT_TIMESTAMP + make_interval(mins => ${CODE_TTL_MINUTES}) ) ON CONFLICT (email) DO UPDATE SET code_hash = EXCLUDED.code_hash, expires_at = EXCLUDED.expires_at, attempts = 0 `; const mail = verificationEmail(code); const delivered = await sendEmail( email.trim().toLowerCase(), mail.subject, mail.text, ); return Response.json( { data: { sent: delivered, // Without SMTP/Gmail configured there is nothing to receive, so // surface the code to keep self-hosted sign-up usable. ...(delivered ? {} : { devCode: code }), }, }, { status: 201 }, ); } catch (error) { console.error("[REGISTER]: ", error); return Response.json({ error: "Internal Server Error" }, { status: 500 }); } }