From b502d98bb423f06dd29277f52844dbd06ffdeea2 Mon Sep 17 00:00:00 2001 From: ikramBagban <107988060+IkramBagban@users.noreply.github.com> Date: Wed, 26 Feb 2025 23:03:53 +0530 Subject: [PATCH] refactor: seperate routes and controllers, and fix some type errors --- .../backend/controllers/payment.controller.ts | 449 +++++++++++++++++ .../backend/controllers/webhook.controller.ts | 86 ++++ apps/backend/index.ts | 4 +- apps/backend/routes/payment.routes.ts | 458 +----------------- apps/backend/routes/webhook.routes.ts | 90 +--- 5 files changed, 559 insertions(+), 528 deletions(-) create mode 100644 apps/backend/controllers/payment.controller.ts create mode 100644 apps/backend/controllers/webhook.controller.ts diff --git a/apps/backend/controllers/payment.controller.ts b/apps/backend/controllers/payment.controller.ts new file mode 100644 index 0000000..842e615 --- /dev/null +++ b/apps/backend/controllers/payment.controller.ts @@ -0,0 +1,449 @@ +import express from "express"; +import Stripe from "stripe"; +import { prismaClient } from "db"; +import { PlanType } from "@prisma/client"; + +import { + createStripeSession, + verifyStripePayment, + createSubscriptionRecord, + PaymentService, +} from "../services/payment"; + +const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, { + apiVersion: "2025-01-27.acacia", +}); + +export const createPayment = async ( + req: express.Request, + res: express.Response +) => { + try { + const { plan, isAnnual, method } = req.body; + const userId = req.userId; + const userEmail = (req as any).user?.email; + + console.log("Payment request received:", { + userId, + plan, + isAnnual, + method, + headers: req.headers, + body: req.body, + }); + + if (!userId) { + res.status(401).json({ message: "Unauthorized" }); + return; + } + + if (!userEmail) { + res.status(400).json({ message: "User email is required" }); + return; + } + + if (!plan || !method) { + res.status(400).json({ message: "Missing required fields" }); + return; + } + + if (method === "stripe") { + try { + const session = await createStripeSession( + userId, + plan as "basic" | "premium", + isAnnual, + userEmail + ); + console.log("Stripe session created:", session); + res.json({ sessionId: session.id }); + return; + } catch (error) { + console.error("Stripe session creation error:", error); + res.status(500).json({ + message: "Error creating payment session", + details: + process.env.NODE_ENV === "development" + ? (error as Error).message + : undefined, + }); + return; + } + } + + if (method === "razorpay") { + try { + const order = await PaymentService.createRazorpayOrder( + userId, + plan, + isAnnual + ); + console.log("Razorpay order created successfully:", order); + res.json(order); + return; + } catch (error) { + console.error("Razorpay error:", error); + res.status(500).json({ + message: "Error creating Razorpay order", + details: + process.env.NODE_ENV === "development" + ? (error as Error).message + : undefined, + }); + return; + } + } + + res.status(400).json({ message: "Invalid payment method" }); + return; + } catch (error) { + console.error("Payment creation error:", error); + res.status(500).json({ + message: "Error creating payment session", + details: error instanceof Error ? error.message : "Unknown error", + }); + return; + } +}; + +export const verifyStripe = async ( + req: express.Request, + res: express.Response +) => { + try { + const { sessionId } = req.body; + if (!sessionId) { + res.status(400).json({ message: "Session ID is required" }); + return; + } + + console.log("Verifying session:", sessionId); + + // Get the session with expanded payment_intent + const session = await stripe.checkout.sessions.retrieve(sessionId, { + expand: ["payment_intent", "subscription"], + }); + + console.log("Session status:", session.payment_status); + console.log("Session metadata:", session.metadata); + + // Check if payment is successful + if (session.payment_status !== "paid") { + res.status(400).json({ + success: false, + message: "Payment not completed", + }); + return; + } + + const userId = session.metadata?.userId; + const plan = session.metadata?.plan as PlanType; + + if (!userId || !plan) { + res.status(400).json({ + success: false, + message: "Missing user or plan information", + }); + return; + } + + // Get payment intent ID + const paymentIntentId = + typeof session.payment_intent === "string" + ? session.payment_intent + : session.payment_intent?.id; + + if (!paymentIntentId) { + res.status(400).json({ + success: false, + message: "Missing payment information", + }); + return; + } + + // Create subscription and add credits + await createSubscriptionRecord(userId, plan, paymentIntentId, sessionId); + + res.json({ success: true }); + return; + } catch (error) { + console.error("Stripe verification error:", error); + res.status(500).json({ + success: false, + message: error instanceof Error ? error.message : "Unknown error", + }); + return; + } +}; + +export const verifyRazorpay = async ( + req: express.Request, + res: express.Response +) => { + try { + const { + razorpay_payment_id, + razorpay_order_id, + razorpay_signature, + plan, + isAnnual, + } = req.body; + + // Debug log + console.log("Verification Request:", { + userId: req.userId, + paymentId: razorpay_payment_id, + orderId: razorpay_order_id, + signature: razorpay_signature, + plan, + isAnnual, + }); + + if ( + !razorpay_payment_id || + !razorpay_order_id || + !razorpay_signature || + !plan + ) { + res.status(400).json({ + message: "Missing required fields", + received: { + razorpay_payment_id, + razorpay_order_id, + razorpay_signature, + plan, + }, + }); + return; + } + + try { + const isValid = await PaymentService.verifyRazorpaySignature({ + paymentId: razorpay_payment_id, + orderId: razorpay_order_id, + signature: razorpay_signature, + }); + + if (!isValid) { + res.status(400).json({ message: "Invalid payment signature" }); + return; + } + + // Create subscription and add credits + const subscription = await PaymentService.createSubscriptionRecord( + req.userId!, + plan as PlanType, + razorpay_payment_id, + razorpay_order_id, + isAnnual + ); + + // Get updated credits + const userCredit = await prismaClient.userCredit.findUnique({ + where: { userId: req.userId! }, + select: { amount: true }, + }); + + console.log("Payment successful:", { + subscription, + credits: userCredit?.amount, + }); + + res.json({ + success: true, + credits: userCredit?.amount || 0, + subscription, + }); + } catch (verifyError) { + console.error("Verification process error:", verifyError); + res.status(500).json({ + message: "Error processing payment verification", + details: + verifyError instanceof Error ? verifyError.message : "Unknown error", + }); + } + } catch (error) { + console.error("Route handler error:", error); + res.status(500).json({ + message: "Error verifying payment", + details: error instanceof Error ? error.message : "Unknown error", + }); + } +}; + +export const getSubscription = async ( + req: express.Request, + res: express.Response +) => { + try { + const subscription = await prismaClient.subscription.findFirst({ + where: { + userId: req.params.userId, + }, + orderBy: { + createdAt: "desc", + }, + select: { + plan: true, + createdAt: true, + }, + }); + + res.json({ + subscription: subscription || null, + }); + return; + } catch (error) { + console.error("Error fetching subscription:", error); + res.status(500).json({ message: "Error fetching subscription status" }); + return; + } +}; + +export const getUserCreditsByUserId = async ( + req: express.Request, + res: express.Response +) => { + try { + const userCredit = await prismaClient.userCredit.findUnique({ + where: { + userId: req.params.userId, + }, + select: { + amount: true, + }, + }); + + res.json({ + credits: userCredit?.amount || 0, + }); + return; + } catch (error) { + console.error("Error fetching credits:", error); + res.status(500).json({ message: "Error fetching credits" }); + return; + } +}; + +export const getAuthorizedUserCredits = async ( + req: express.Request, + res: express.Response +) => { + try { + if (!req.userId) { + res.status(401).json({ message: "Unauthorized" }); + return; + } + + const userCredit = await prismaClient.userCredit.findUnique({ + where: { + userId: req.userId, + }, + select: { + amount: true, + updatedAt: true, + }, + }); + + res.json({ + credits: userCredit?.amount || 0, + lastUpdated: userCredit?.updatedAt || null, + }); + return; + } catch (error) { + console.error("Error fetching credits:", error); + res.status(500).json({ + message: "Error fetching credits", + details: error instanceof Error ? error.message : "Unknown error", + }); + return; + } +}; + +export const verifyPayment = async ( + req: express.Request, + res: express.Response +) => { + try { + const { sessionId } = req.body; + + if (!sessionId) { + res.status(400).json({ message: "Session ID is required" }); + return; + } + + // Verify the payment session + const isValid = await verifyStripePayment(sessionId); + + if (isValid) { + res.json({ success: true }); + return; + } else { + res.status(400).json({ message: "Payment verification failed" }); + return; + } + } catch (error) { + console.error("Payment verification error:", error); + res.status(500).json({ + message: "Error verifying payment", + details: error instanceof Error ? error.message : "Unknown error", + }); + return; + } +}; + +export const stripeWebhookHandler = async ( + req: express.Request, + res: express.Response +) => { + const sig = req.headers["stripe-signature"]; + + try { + if (!sig) throw new Error("No Stripe signature found"); + + const event = stripe.webhooks.constructEvent( + req.body, + sig, + process.env.STRIPE_WEBHOOK_SECRET! + ); + + console.log("Webhook event received:", event.type); + + switch (event.type) { + case "checkout.session.completed": { + const session = event.data.object as Stripe.Checkout.Session; + const userId = session.metadata?.userId; + const plan = session.metadata?.plan as PlanType; + + if (!userId || !plan) { + throw new Error("Missing metadata in session"); + } + + console.log("Processing successful payment:", { + userId, + plan, + sessionId: session.id, + }); + + await createSubscriptionRecord( + userId, + plan, + session.payment_intent as string, + session.id + ); + + console.log("Successfully processed payment and added credits"); + break; + } + } + + res.json({ received: true }); + } catch (error) { + console.error("Webhook error:", error); + res + .status(400) + .send( + `Webhook Error: ${error instanceof Error ? error.message : "Unknown error"}` + ); + } +}; diff --git a/apps/backend/controllers/webhook.controller.ts b/apps/backend/controllers/webhook.controller.ts new file mode 100644 index 0000000..11a66e7 --- /dev/null +++ b/apps/backend/controllers/webhook.controller.ts @@ -0,0 +1,86 @@ +import { prismaClient } from "db"; +import { Webhook } from "svix"; + +export const clerkWebhookHandler = async (req, res) => { + const SIGNING_SECRET = process.env.SIGNING_SECRET; + + if (!SIGNING_SECRET) { + throw new Error( + "Error: Please add SIGNING_SECRET from Clerk Dashboard to .env" + ); + } + + const wh = new Webhook(SIGNING_SECRET); + const headers = req.headers; + const payload = req.body; + + const svix_id = headers["svix-id"]; + const svix_timestamp = headers["svix-timestamp"]; + const svix_signature = headers["svix-signature"]; + + if (!svix_id || !svix_timestamp || !svix_signature) { + return res.status(400).json({ + success: false, + message: "Error: Missing svix headers", + }); + } + + let evt: any; + + try { + evt = wh.verify(JSON.stringify(payload), { + "svix-id": svix_id as string, + "svix-timestamp": svix_timestamp as string, + "svix-signature": svix_signature as string, + }); + } catch (err) { + console.log("Error: Could not verify webhook:", err.message); + return res.status(400).json({ + success: false, + message: err.message, + }); + } + + const { id } = evt.data; + const eventType = evt.type; + + try { + switch (eventType) { + case "user.created": + case "user.updated": { + await prismaClient.user.upsert({ + where: { clerkId: id }, + update: { + name: `${evt.data.first_name ?? ""} ${evt.data.last_name ?? ""}`.trim(), + email: evt.data.email_addresses[0].email_address, + profilePicture: evt.data.profile_image_url, + }, + create: { + clerkId: id, + name: `${evt.data.first_name ?? ""} ${evt.data.last_name ?? ""}`.trim(), + email: evt.data.email_addresses[0].email_address, + profilePicture: evt.data.profile_image_url, + }, + }); + break; + } + + case "user.deleted": { + await prismaClient.user.delete({ + where: { clerkId: id }, + }); + break; + } + + default: + console.log(`Unhandled event type: ${eventType}`); + break; + } + } catch (error) { + console.error("Error handling webhook:", error); + return res + .status(500) + .json({ success: false, message: "Internal Server Error" }); + } + return res.status(200).json({ success: true, message: "Webhook received" }); +}; diff --git a/apps/backend/index.ts b/apps/backend/index.ts index 6281e76..0cf96c3 100644 --- a/apps/backend/index.ts +++ b/apps/backend/index.ts @@ -13,7 +13,7 @@ import { authMiddleware } from "./middleware"; import dotenv from "dotenv"; import paymentRoutes from "./routes/payment.routes"; -import {router as webhookRouter} from './routes/webhook.routes'; +import webhookRouter from "./routes/webhook.routes"; const IMAGE_GEN_CREDITS = 1; const TRAIN_MODEL_CREDITS = 20; @@ -355,7 +355,7 @@ app.post("/fal-ai/webhook/image", async (req, res) => { }); app.use("/payment", paymentRoutes); -app.use("/api/webhook",webhookRouter ); +app.use("/api/webhook", webhookRouter); app.listen(PORT, () => { console.log(`Server is running on port ${PORT}`); diff --git a/apps/backend/routes/payment.routes.ts b/apps/backend/routes/payment.routes.ts index 8ba0c9b..1ae3788 100644 --- a/apps/backend/routes/payment.routes.ts +++ b/apps/backend/routes/payment.routes.ts @@ -1,462 +1,40 @@ import express from "express"; + import { authMiddleware } from "../middleware"; -import { PlanType } from "@prisma/client"; -import { prismaClient } from "db"; -import Stripe from "stripe"; import { - createStripeSession, - createRazorpayOrder, - verifyStripePayment, - getStripeSession, - verifyRazorpaySignature, - createSubscriptionRecord, - PaymentService, -} from "../services/payment"; + createPayment, + getAuthorizedUserCredits, + getSubscription, + getUserCreditsByUserId, + stripeWebhookHandler, + verifyPayment, + verifyRazorpay, + verifyStripe, +} from "../controllers/payment.controller"; const router = express.Router(); -const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, { - apiVersion: "2025-01-27.acacia", -}); - -router.post( - "/create", - authMiddleware, - async (req: express.Request, res: express.Response) => { - try { - const { plan, isAnnual, method } = req.body; - const userId = req.userId; - const userEmail = (req as any).user?.email; - - console.log("Payment request received:", { - userId, - plan, - isAnnual, - method, - headers: req.headers, - body: req.body, - }); - - if (!userId) { - res.status(401).json({ message: "Unauthorized" }); - return; - } - - if (!userEmail) { - res.status(400).json({ message: "User email is required" }); - return; - } - - if (!plan || !method) { - res.status(400).json({ message: "Missing required fields" }); - return; - } - - if (method === "stripe") { - try { - const session = await createStripeSession( - userId, - plan as "basic" | "premium", - isAnnual, - userEmail - ); - console.log("Stripe session created:", session); - res.json({ sessionId: session.id }); - return; - } catch (error) { - console.error("Stripe session creation error:", error); - res.status(500).json({ - message: "Error creating payment session", - details: - process.env.NODE_ENV === "development" - ? (error as Error).message - : undefined, - }); - return; - } - } - - if (method === "razorpay") { - try { - const order = await PaymentService.createRazorpayOrder( - userId, - plan, - isAnnual - ); - console.log("Razorpay order created successfully:", order); - res.json(order); - return; - } catch (error) { - console.error("Razorpay error:", error); - res.status(500).json({ - message: "Error creating Razorpay order", - details: - process.env.NODE_ENV === "development" - ? (error as Error).message - : undefined, - }); - return; - } - } - - res.status(400).json({ message: "Invalid payment method" }); - return; - } catch (error) { - console.error("Payment creation error:", error); - res.status(500).json({ - message: "Error creating payment session", - details: error instanceof Error ? error.message : "Unknown error", - }); - return; - } - } -); - -router.post( - "/stripe/verify", - authMiddleware, - async (req: express.Request, res: express.Response) => { - try { - const { sessionId } = req.body; - if (!sessionId) { - res.status(400).json({ message: "Session ID is required" }); - return; - } - - console.log("Verifying session:", sessionId); - - // Get the session with expanded payment_intent - const session = await stripe.checkout.sessions.retrieve(sessionId, { - expand: ["payment_intent", "subscription"], - }); - - console.log("Session status:", session.payment_status); - console.log("Session metadata:", session.metadata); - - // Check if payment is successful - if (session.payment_status !== "paid") { - res.status(400).json({ - success: false, - message: "Payment not completed", - }); - return; - } - - const userId = session.metadata?.userId; - const plan = session.metadata?.plan as PlanType; - - if (!userId || !plan) { - res.status(400).json({ - success: false, - message: "Missing user or plan information", - }); - return; - } - - // Get payment intent ID - const paymentIntentId = - typeof session.payment_intent === "string" - ? session.payment_intent - : session.payment_intent?.id; - - if (!paymentIntentId) { - res.status(400).json({ - success: false, - message: "Missing payment information", - }); - return; - } - - // Create subscription and add credits - await createSubscriptionRecord(userId, plan, paymentIntentId, sessionId); - - res.json({ success: true }); - return; - } catch (error) { - console.error("Stripe verification error:", error); - res.status(500).json({ - success: false, - message: error instanceof Error ? error.message : "Unknown error", - }); - return; - } - } -); - -router.post( - "/razorpay/verify", - authMiddleware, - async (req: express.Request, res: express.Response) => { - try { - const { - razorpay_payment_id, - razorpay_order_id, - razorpay_signature, - plan, - isAnnual, - } = req.body; - // Debug log - console.log("Verification Request:", { - userId: req.userId, - paymentId: razorpay_payment_id, - orderId: razorpay_order_id, - signature: razorpay_signature, - plan, - isAnnual, - }); +router.post("/create", authMiddleware, createPayment); - if ( - !razorpay_payment_id || - !razorpay_order_id || - !razorpay_signature || - !plan - ) { - res.status(400).json({ - message: "Missing required fields", - received: { - razorpay_payment_id, - razorpay_order_id, - razorpay_signature, - plan, - }, - }); - return; - } +router.post("/stripe/verify", authMiddleware, verifyStripe); - try { - const isValid = await PaymentService.verifyRazorpaySignature({ - paymentId: razorpay_payment_id, - orderId: razorpay_order_id, - signature: razorpay_signature, - }); +router.post("/razorpay/verify", authMiddleware, verifyRazorpay); - if (!isValid) { - res.status(400).json({ message: "Invalid payment signature" }); - return; - } +router.get("/subscription/:userId", getSubscription); - // Create subscription and add credits - const subscription = await PaymentService.createSubscriptionRecord( - req.userId!, - plan as PlanType, - razorpay_payment_id, - razorpay_order_id, - isAnnual - ); - - // Get updated credits - const userCredit = await prismaClient.userCredit.findUnique({ - where: { userId: req.userId! }, - select: { amount: true }, - }); - - console.log("Payment successful:", { - subscription, - credits: userCredit?.amount, - }); - - res.json({ - success: true, - credits: userCredit?.amount || 0, - subscription, - }); - } catch (verifyError) { - console.error("Verification process error:", verifyError); - res.status(500).json({ - message: "Error processing payment verification", - details: - verifyError instanceof Error - ? verifyError.message - : "Unknown error", - }); - } - } catch (error) { - console.error("Route handler error:", error); - res.status(500).json({ - message: "Error verifying payment", - details: error instanceof Error ? error.message : "Unknown error", - }); - } - } -); - -router.get( - "/subscription/:userId", - async (req: express.Request, res: express.Response) => { - try { - const subscription = await prismaClient.subscription.findFirst({ - where: { - userId: req.params.userId, - }, - orderBy: { - createdAt: "desc", - }, - select: { - plan: true, - createdAt: true, - }, - }); - - res.json({ - subscription: subscription || null, - }); - return; - } catch (error) { - console.error("Error fetching subscription:", error); - res.status(500).json({ message: "Error fetching subscription status" }); - return; - } - } -); - -router.get( - "/credits/:userId", - async (req: express.Request, res: express.Response) => { - try { - const userCredit = await prismaClient.userCredit.findUnique({ - where: { - userId: req.params.userId, - }, - select: { - amount: true, - }, - }); - - res.json({ - credits: userCredit?.amount || 0, - }); - return; - } catch (error) { - console.error("Error fetching credits:", error); - res.status(500).json({ message: "Error fetching credits" }); - return; - } - } -); +router.get("/credits/:userId", getUserCreditsByUserId); // Add this route to get user credits -router.get( - "/credits", - authMiddleware, - async (req: express.Request, res: express.Response) => { - try { - if (!req.userId) { - res.status(401).json({ message: "Unauthorized" }); - return; - } - - const userCredit = await prismaClient.userCredit.findUnique({ - where: { - userId: req.userId, - }, - select: { - amount: true, - updatedAt: true, - }, - }); - - res.json({ - credits: userCredit?.amount || 0, - lastUpdated: userCredit?.updatedAt || null, - }); - return; - } catch (error) { - console.error("Error fetching credits:", error); - res.status(500).json({ - message: "Error fetching credits", - details: error instanceof Error ? error.message : "Unknown error", - }); - return; - } - } -); +router.get("/credits", authMiddleware, getAuthorizedUserCredits); // Add Stripe webhook handler router.post( "/webhook", express.raw({ type: "application/json" }), - async (req, res) => { - const sig = req.headers["stripe-signature"]; - - try { - if (!sig) throw new Error("No Stripe signature found"); - - const event = stripe.webhooks.constructEvent( - req.body, - sig, - process.env.STRIPE_WEBHOOK_SECRET! - ); - - console.log("Webhook event received:", event.type); - - switch (event.type) { - case "checkout.session.completed": { - const session = event.data.object as Stripe.Checkout.Session; - const userId = session.metadata?.userId; - const plan = session.metadata?.plan as PlanType; - - if (!userId || !plan) { - throw new Error("Missing metadata in session"); - } - - console.log("Processing successful payment:", { - userId, - plan, - sessionId: session.id, - }); - - await createSubscriptionRecord( - userId, - plan, - session.payment_intent as string, - session.id - ); - - console.log("Successfully processed payment and added credits"); - break; - } - } - - res.json({ received: true }); - } catch (error) { - console.error("Webhook error:", error); - res - .status(400) - .send( - `Webhook Error: ${error instanceof Error ? error.message : "Unknown error"}` - ); - } - } + stripeWebhookHandler ); // Add this new verification endpoint -router.post("/verify", async (req, res) => { - try { - const { sessionId } = req.body; - - if (!sessionId) { - res.status(400).json({ message: "Session ID is required" }); - return; - } - - // Verify the payment session - const isValid = await verifyStripePayment(sessionId); - - if (isValid) { - res.json({ success: true }); - return; - } else { - res.status(400).json({ message: "Payment verification failed" }); - return; - } - } catch (error) { - console.error("Payment verification error:", error); - res.status(500).json({ - message: "Error verifying payment", - details: error instanceof Error ? error.message : "Unknown error", - }); - return; - } -}); +router.post("/verify", verifyPayment); export default router; diff --git a/apps/backend/routes/webhook.routes.ts b/apps/backend/routes/webhook.routes.ts index f5138f2..c2122ea 100644 --- a/apps/backend/routes/webhook.routes.ts +++ b/apps/backend/routes/webhook.routes.ts @@ -1,94 +1,12 @@ -import { prismaClient } from "db"; import { Router } from "express"; -import { Webhook } from "svix"; +import { clerkWebhookHandler } from "../controllers/webhook.controller"; -export const router = Router(); +const router = Router(); /** * POST api/webhook/clerk * Clerk webhook endpoint */ -router.post("/clerk", async (req, res) => { - const SIGNING_SECRET = - process.env.SIGNING_SECRET +router.post("/clerk", clerkWebhookHandler); - if (!SIGNING_SECRET) { - throw new Error( - "Error: Please add SIGNING_SECRET from Clerk Dashboard to .env" - ); - } - - const wh = new Webhook(SIGNING_SECRET); - const headers = req.headers; - const payload = req.body; - - const svix_id = headers["svix-id"]; - const svix_timestamp = headers["svix-timestamp"]; - const svix_signature = headers["svix-signature"]; - - if (!svix_id || !svix_timestamp || !svix_signature) { - return res.status(400).json({ - success: false, - message: "Error: Missing svix headers", - }); - } - - let evt: any; - - try { - evt = wh.verify(JSON.stringify(payload), { - "svix-id": svix_id as string, - "svix-timestamp": svix_timestamp as string, - "svix-signature": svix_signature as string, - }); - } catch (err) { - console.log("Error: Could not verify webhook:", err.message); - return res.status(400).json({ - success: false, - message: err.message, - }); - } - - const { id } = evt.data; - const eventType = evt.type; - - try { - switch (eventType) { - case "user.created": - case "user.updated": { - await prismaClient.user.upsert({ - where: { clerkId: id }, - update: { - name: `${evt.data.first_name ?? ""} ${evt.data.last_name ?? ""}`.trim(), - email: evt.data.email_addresses[0].email_address, - profilePicture: evt.data.profile_image_url, - }, - create: { - clerkId: id, - name: `${evt.data.first_name ?? ""} ${evt.data.last_name ?? ""}`.trim(), - email: evt.data.email_addresses[0].email_address, - profilePicture: evt.data.profile_image_url, - }, - }); - break; - } - - case "user.deleted": { - await prismaClient.user.delete({ - where: { clerkId: id }, - }); - break; - } - - default: - console.log(`Unhandled event type: ${eventType}`); - break; - } - } catch (error) { - console.error("Error handling webhook:", error); - return res - .status(500) - .json({ success: false, message: "Internal Server Error" }); - } - return res.status(200).json({ success: true, message: "Webhook received" }); -}); +export default router;