74 lines
1.9 KiB
TypeScript
74 lines
1.9 KiB
TypeScript
import type { NextApiRequest, NextApiResponse } from "next";
|
|
import type { Readable } from "node:stream";
|
|
|
|
import { createNextApiContext } from "@kan/api/trpc";
|
|
import * as workspaceRepo from "@kan/db/repository/workspace.repo";
|
|
import { createStripeClient } from "@kan/stripe";
|
|
|
|
async function buffer(readable: Readable) {
|
|
const chunks = [];
|
|
for await (const chunk of readable) {
|
|
chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
|
|
}
|
|
return Buffer.concat(chunks);
|
|
}
|
|
|
|
export default async function handler(
|
|
req: NextApiRequest,
|
|
res: NextApiResponse,
|
|
) {
|
|
const stripe = createStripeClient();
|
|
|
|
if (req.method !== "POST") {
|
|
return res.status(405).json({ message: "Method not allowed" });
|
|
}
|
|
|
|
const sig = req.headers["stripe-signature"];
|
|
|
|
if (!sig) {
|
|
return res.status(400).json({ message: "No signature found" });
|
|
}
|
|
|
|
try {
|
|
const buf = await buffer(req);
|
|
const rawBody = buf.toString("utf8");
|
|
|
|
const event = stripe.webhooks.constructEvent(
|
|
rawBody,
|
|
sig,
|
|
process.env.STRIPE_WEBHOOK_SECRET!,
|
|
);
|
|
|
|
const { db } = await createNextApiContext(req);
|
|
|
|
switch (event.type) {
|
|
case "checkout.session.completed": {
|
|
const checkoutSession = event.data.object;
|
|
|
|
const metaData = checkoutSession.metadata;
|
|
|
|
if (metaData?.workspacePublicId && metaData.workspaceSlug) {
|
|
await workspaceRepo.update(db, metaData.workspacePublicId, {
|
|
slug: metaData.workspaceSlug,
|
|
plan: "pro",
|
|
});
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
console.log(`Unhandled event type: ${event.type}`);
|
|
}
|
|
|
|
return res.status(200).json({ received: true });
|
|
} catch (err) {
|
|
console.error("Webhook error:", err);
|
|
return res.status(400).json({ message: "Webhook handler failed" });
|
|
}
|
|
}
|
|
|
|
export const config = {
|
|
api: {
|
|
bodyParser: false,
|
|
},
|
|
};
|