/** * Author: Simon-Pierre Boucher * Contact: contact@spboucher.ai * Project: Hilmacorp.ai — Web Platform * File: app/api/contact/route.ts * Description: Contact form API route — validates input, then delivers to contact@spboucher.ai * via Resend when RESEND_API_KEY is set, otherwise persists to data/contact-messages.jsonl */ import { NextResponse } from "next/server"; import { appendFile, mkdir } from "node:fs/promises"; import path from "node:path"; import { validateContact } from "@/lib/validate"; export const runtime = "nodejs"; const CONTACT_TO = process.env.CONTACT_TO ?? "contact@spboucher.ai"; async function deliverByEmail(data: { name: string; organization: string; email: string; message: string; }): Promise { const apiKey = process.env.RESEND_API_KEY; if (!apiKey) return false; const response = await fetch("https://api.resend.com/emails", { method: "POST", headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json", }, body: JSON.stringify({ from: process.env.CONTACT_FROM ?? "Hilmacorp.ai ", to: [CONTACT_TO], reply_to: data.email, subject: `[hilmacorp.ai] Contact — ${data.name}`, text: `Name: ${data.name}\nOrganization: ${data.organization || "—"}\nEmail: ${data.email}\n\n${data.message}`, }), }); return response.ok; } async function persistLocally(data: object): Promise { const dir = path.join(process.cwd(), "data"); await mkdir(dir, { recursive: true }); const record = { receivedAt: new Date().toISOString(), to: CONTACT_TO, ...data }; await appendFile(path.join(dir, "contact-messages.jsonl"), JSON.stringify(record) + "\n", "utf8"); } export async function POST(request: Request) { let body: unknown; try { body = await request.json(); } catch { return NextResponse.json({ ok: false, errors: { body: "invalid_json" } }, { status: 400 }); } const result = validateContact(body); if (!result.ok || !result.data) { return NextResponse.json({ ok: false, errors: result.errors }, { status: 422 }); } try { const emailed = await deliverByEmail(result.data); if (!emailed) await persistLocally(result.data); return NextResponse.json({ ok: true }); } catch (error) { console.error("[contact] delivery failed:", error); try { await persistLocally(result.data); return NextResponse.json({ ok: true }); } catch { return NextResponse.json({ ok: false, errors: { server: "delivery_failed" } }, { status: 500 }); } } }