import { Webhook } from "svix";
import { headers } from "next/headers";
import { WebhookEvent } from "@clerk/nextjs/server";
import prisma from "@/lib/prisma";
import {
UserJSON,
DeletedObjectJSON,
OrganizationMembershipJSON,
OrganizationJSON,
} from "@clerk/types";
const webhookSecret = process.env.CLERK_WEBHOOK_SECRET || ``;
async function validateRequest(request: Request) {
const payloadString = await request.text();
const headerPayload = await headers();
const svixHeaders = {
"svix-id": headerPayload.get("svix-id")!,
"svix-timestamp": headerPayload.get("svix-timestamp")!,
"svix-signature": headerPayload.get("svix-signature")!,
};
const wh = new Webhook(webhookSecret);
return wh.verify(payloadString, svixHeaders) as WebhookEvent;
}
async function handleUserCreated(userData: UserJSON) {
await prisma.user.create({
data: {
id: userData.id,
clerkUserId: userData.id,
email: userData.email_addresses?.[0]?.email_address,
firstName: userData.first_name,
lastName: userData.last_name,
},
});
}
async function handleUserUpdated(userData: UserJSON) {
await prisma.user.update({
where: { clerkUserId: userData.id },
data: {
email: userData.email_addresses?.[0]?.email_address,
firstName: userData.first_name,
lastName: userData.last_name,
},
});
}
async function handleUserDeleted(userData: DeletedObjectJSON) {
await prisma.user.delete({
where: { clerkUserId: userData.id },
});
}
async function handleOrgMembershipCreated(
membershipData: OrganizationMembershipJSON
) {
await prisma.organization.upsert({
where: { id: membershipData.organization.id },
create: {
id: membershipData.organization.id,
name: membershipData.organization.name,
},
update: {
name: membershipData.organization.name,
},
});
await prisma.user.update({
where: { clerkUserId: membershipData.public_user_data.user_id },
data: {
organizations: {
connect: { id: membershipData.organization.id },
},
},
});
}
async function handleOrgMembershipDeleted(
membershipData: OrganizationMembershipJSON
) {
await prisma.user.update({
where: { clerkUserId: membershipData.public_user_data.user_id },
data: {
organizations: {
disconnect: { id: membershipData.organization.id },
},
},
});
}
async function handleOrganizationCreated(orgData: OrganizationJSON) {
await prisma.organization.create({
data: {
id: orgData.id,
name: orgData.name,
},
});
}
async function handleOrganizationUpdated(orgData: OrganizationJSON) {
await prisma.organization.update({
where: { id: orgData.id },
data: {
name: orgData.name,
},
});
}
export async function POST(request: Request) {
const payload = await validateRequest(request);
const eventType = payload.type;
switch (eventType) {
case "user.created":
await handleUserCreated(payload.data as unknown as UserJSON);
break;
case "user.updated":
await handleUserUpdated(payload.data as unknown as UserJSON);
break;
case "user.deleted":
await handleUserDeleted(payload.data as DeletedObjectJSON);
break;
case "organizationMembership.created":
await handleOrgMembershipCreated(
payload.data as OrganizationMembershipJSON
);
break;
case "organizationMembership.deleted":
await handleOrgMembershipDeleted(
payload.data as OrganizationMembershipJSON
);
break;
case "organization.created":
await handleOrganizationCreated(
payload.data as unknown as OrganizationJSON
);
break;
case "organization.updated":
await handleOrganizationUpdated(
payload.data as unknown as OrganizationJSON
);
break;
default:
console.log(`Unhandled event type: ${eventType}`);
}
return new Response("ok", { status: 200 });
}