import { Webhook } from "svix"; import type { Route } from "./+types/clerk"; import { findOrCreateUser, updateUserByClerkId } from "~/models/user"; export async function action({ request }: Route.ActionArgs) { // Get the webhook secret from environment const WEBHOOK_SECRET = process.env.CLERK_WEBHOOK_SECRET; if (!WEBHOOK_SECRET) { throw new Error("Please add CLERK_WEBHOOK_SECRET to your .env file"); } // Get the headers const svix_id = request.headers.get("svix-id"); const svix_timestamp = request.headers.get("svix-timestamp"); const svix_signature = request.headers.get("svix-signature"); // If there are no headers, error out if (!svix_id || !svix_timestamp || !svix_signature) { return new Response("Error: Missing svix headers", { status: 400 }); } // Get the body const payload = await request.text(); // Create a new Svix instance with your webhook secret const wh = new Webhook(WEBHOOK_SECRET); let evt: any; // Verify the webhook try { evt = wh.verify(payload, { "svix-id": svix_id, "svix-timestamp": svix_timestamp, "svix-signature": svix_signature, }); } catch (err) { console.error("Error verifying webhook:", err); return new Response("Error: Verification failed", { status: 400 }); } // Handle the webhook const eventType = evt.type; console.log(`Webhook received: ${eventType}`); if (eventType === "user.created" || eventType === "user.updated") { const { id, email_addresses, first_name, last_name, image_url } = evt.data; try { if (eventType === "user.created") { // Create new user const user = await findOrCreateUser({ id, emailAddresses: email_addresses, firstName: first_name, lastName: last_name, imageUrl: image_url, }); console.log(`User created in database: ${user.id} (${user.displayName})`); } else { // Update existing user const email = email_addresses?.[0]?.email_address; if (!email) { throw new Error("User must have an email address"); } // Generate display name let displayName = ""; if (first_name || last_name) { displayName = [first_name, last_name].filter(Boolean).join(" ").trim(); } else { displayName = email.split("@")[0]; } const user = await updateUserByClerkId(id, { email, displayName, firstName: first_name || undefined, lastName: last_name || undefined, imageUrl: image_url, }); console.log(`User updated in database: ${user.id} (${user.displayName})`); } } catch (error) { console.error(`Error handling ${eventType}:`, error); return new Response(`Error: Failed to ${eventType === "user.created" ? "create" : "update"} user`, { status: 500, }); } } return new Response("Webhook processed successfully", { status: 200 }); }