Refine workspaces and event publishing; harden uploads and email delivery
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
import { recordEmailWebhook, verifyEmailWebhook } from "@album/email/webhooks";
|
||||
|
||||
export const runtime = "nodejs";
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const secret = process.env.RESEND_WEBHOOK_SECRET;
|
||||
if (!secret) return new Response("Webhook not configured", { status: 503 });
|
||||
// Read a bounded raw body: signature verification must precede parsing/storage.
|
||||
const reader = request.body?.getReader();
|
||||
if (!reader) return new Response("Missing body", { status: 400 });
|
||||
const chunks: Uint8Array[] = [];
|
||||
let size = 0;
|
||||
while (true) {
|
||||
const { value, done } = await reader.read();
|
||||
if (done) break;
|
||||
size += value.byteLength;
|
||||
if (size > 256 * 1024) {
|
||||
await reader.cancel();
|
||||
return new Response("Payload too large", { status: 413 });
|
||||
}
|
||||
chunks.push(value);
|
||||
}
|
||||
let event;
|
||||
try {
|
||||
event = verifyEmailWebhook(Buffer.concat(chunks).toString("utf8"), request.headers, secret);
|
||||
} catch {
|
||||
return new Response("Invalid signature or event", { status: 400 });
|
||||
}
|
||||
try {
|
||||
if (event) await recordEmailWebhook(event);
|
||||
return new Response("OK");
|
||||
} catch {
|
||||
// Non-2xx requests are retried by Resend. Never log callback payloads.
|
||||
return new Response("Temporarily unavailable", { status: 503 });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user