Refine workspaces and event publishing; harden uploads and email delivery

This commit is contained in:
2026-09-09 15:44:00 -04:00
parent f5702caaea
commit 574f29a68e
93 changed files with 2885 additions and 535 deletions
+50
View File
@@ -0,0 +1,50 @@
import { expect, test } from "bun:test";
import { createHmac } from "node:crypto";
import { and, eq, inArray } from "drizzle-orm";
import { emailDeliveries, emailWebhookEvents, events, getDb, groups } from "@album/database";
import { emailDeliveryOutcome, recordEmailWebhook, verifyEmailWebhook } from "./webhooks";
const key = Buffer.from("local-test-signing-secret-not-production");
const secret = `whsec_${key.toString("base64")}`;
function signed(type = "email.delivered", timestamp = Math.floor(Date.now() / 1000)) {
const id = `test_${crypto.randomUUID()}`;
const payload = JSON.stringify({ type, created_at: new Date().toISOString(), data: { email_id: crypto.randomUUID() } });
const signature = createHmac("sha256", key).update(`${id}.${timestamp}.${payload}`).digest("base64");
return { payload, headers: new Headers({ "svix-id": id, "svix-timestamp": `${timestamp}`, "svix-signature": `v1,${signature}` }) };
}
test("webhooks require an authentic, fresh, unmodified signature", () => {
const input = signed();
expect(verifyEmailWebhook(input.payload, input.headers, secret)?.outcome).toBe("delivered");
expect(() => verifyEmailWebhook(input.payload + " ", input.headers, secret)).toThrow();
expect(() => verifyEmailWebhook(input.payload, new Headers(), secret)).toThrow();
const stale = signed("email.delivered", 1);
expect(() => verifyEmailWebhook(stale.payload, stale.headers, secret)).toThrow();
const ignored = signed("email.opened");
expect(verifyEmailWebhook(ignored.payload, ignored.headers, secret)).toBeNull();
});
test.skipIf(process.env.WEBHOOK_INTEGRATION !== "1")("early, duplicate and reordered callbacks preserve terminal outcome and event scope", async () => {
if (!["localhost", "127.0.0.1"].includes(new URL(process.env.DATABASE_URL!).hostname)) throw new Error("Local database required");
const db = getDb();
const [group] = await db.select({ id: groups.id }).from(groups).limit(1);
const input = signed("email.bounced");
const callback = verifyEmailWebhook(input.payload, input.headers, secret)!;
const ids = [callback.id, `${callback.id}-delivered`];
const [event] = await db.insert(events).values({ groupId: group!.id, title: "Webhook test", slug: `webhook-${crypto.randomUUID()}` }).returning();
try {
await Promise.all([recordEmailWebhook(callback), recordEmailWebhook(callback)]);
expect(await db.select().from(emailWebhookEvents).where(eq(emailWebhookEvents.id, callback.id))).toHaveLength(1);
const [delivery] = await db.insert(emailDeliveries).values({ eventId: event!.id, recipient: "webhook@manyangles.test", provider: "resend", payload: { to: "webhook@manyangles.test", from: "test@manyangles.test", subject: "Test", html: "", text: "", referenceId: "test" } }).returning();
const scope = and(eq(emailDeliveries.eventId, event!.id), eq(emailDeliveries.id, delivery!.id));
expect((await db.select({ outcome: emailDeliveryOutcome }).from(emailDeliveries).where(scope))[0]?.outcome).toBeNull();
await db.update(emailDeliveries).set({ providerId: callback.providerId }).where(scope);
await recordEmailWebhook({ ...callback, id: ids[1]!, outcome: "delivered", occurredAt: new Date(Date.now() + 1000) });
expect((await db.select({ outcome: emailDeliveryOutcome }).from(emailDeliveries).where(scope))[0]?.outcome).toBe("bounced");
expect(await db.select({ outcome: emailDeliveryOutcome }).from(emailDeliveries).where(eq(emailDeliveries.eventId, crypto.randomUUID()))).toHaveLength(0);
await db.update(emailDeliveries).set({ provider: "mailpit" }).where(scope);
expect((await db.select({ outcome: emailDeliveryOutcome }).from(emailDeliveries).where(scope))[0]?.outcome).toBeNull();
} finally {
await db.delete(events).where(eq(events.id, event!.id));
await db.delete(emailWebhookEvents).where(inArray(emailWebhookEvents.id, ids));
}
});