UNPKG

create-mf2-app

Version:

The stack AI moves fast with.

83 lines (74 loc) 2.25 kB
import { httpRouter } from "convex/server"; import { httpAction } from "./_generated/server"; import { internal } from "./_generated/api"; import type { WebhookEvent } from "@clerk/backend"; import { Webhook } from "svix"; function ensureEnvironmentVariable(name: string): string { const value = process.env[name]; if (value === undefined) { throw new Error(`missing environment variable ${name}`); } return value; } const webhookSecret = ensureEnvironmentVariable("CLERK_WEBHOOK_SECRET"); const handleClerkWebhook = httpAction(async (ctx, request) => { const event = await validateRequest(request); if (!event) { return new Response("Error occured", { status: 400, }); } switch (event.type) { case "user.created": case "user.updated": { const existingUser = await ctx.runQuery(internal.auth.users.getUser, { subject: event.data.id, }); if (existingUser && event.type === "user.created") { console.warn("Overwriting user", event.data.id, "with", event.data); } console.log("creating/updating user", event.data.id); await ctx.runMutation(internal.auth.users.updateOrCreateUser, { clerkUser: event.data, }); break; } case "user.deleted": { const id = event.data.id!; await ctx.runMutation(internal.auth.users.deleteUserByClerkId, { id }); break; } default: { console.log("ignored Clerk webhook event", event.type); } } return new Response(null, { status: 200, }); }); const http = httpRouter(); http.route({ path: "/clerk-users-webhook", method: "POST", handler: handleClerkWebhook, }); async function validateRequest( req: Request ): Promise<WebhookEvent | undefined> { const payloadString = await req.text(); const svixHeaders = { "svix-id": req.headers.get("svix-id")!, "svix-timestamp": req.headers.get("svix-timestamp")!, "svix-signature": req.headers.get("svix-signature")!, }; const wh = new Webhook(webhookSecret); let evt: Event | null = null; try { evt = wh.verify(payloadString, svixHeaders) as Event; } catch (_) { console.log("error verifying"); return; } return evt as unknown as WebhookEvent; } export default http;