- Added @t3-oss/env-nextjs for improved environment variable management. - Updated zod to version 4.1.12 for enhanced validation capabilities. - Upgraded jiti to version 2.6.1 for better module loading. - Refactored environment variable imports from env.mjs to env.ts. - Removed deprecated env.mjs file and replaced it with a new env.ts file using @t3-oss/env-nextjs. - Adjusted various components and API routes to utilize the new environment variable structure. - Updated next.config.js to support the new environment variable management. - Modified Docker configuration to align with new BASE_URL handling.
140 lines
3.3 KiB
TypeScript
140 lines
3.3 KiB
TypeScript
import type { NextApiRequest, NextApiResponse } from "next";
|
|
import Stripe from "stripe";
|
|
import { env } from "~/env";
|
|
import type { PaymentsId } from "~/schemas/public/Payments";
|
|
import { appRouter } from "~/server/api/root";
|
|
import { createTRPCContext, t } from "~/server/api/trpc";
|
|
|
|
const handler = async (
|
|
req: NextApiRequest,
|
|
res: NextApiResponse,
|
|
): Promise<void> => {
|
|
const stripe = new Stripe(env.STRIPE_SECRET_KEY);
|
|
|
|
if (req.method === "POST") {
|
|
const ctx = await createTRPCContext({ req: req, res: res });
|
|
const createCaller = t.createCallerFactory(appRouter);
|
|
const caller = createCaller(ctx);
|
|
|
|
const sig = req.headers["stripe-signature"];
|
|
|
|
let event: Stripe.Event;
|
|
if (!sig) {
|
|
res.status(400).send("Webhook Error: Missing Stripe signature");
|
|
return;
|
|
}
|
|
try {
|
|
const body = await buffer(req);
|
|
event = stripe.webhooks.constructEvent(
|
|
body,
|
|
sig,
|
|
env.STRIPE_WEBHOOK_SECRET,
|
|
);
|
|
} catch (err) {
|
|
console.error("Error verifying webhook signature:", err);
|
|
res.status(400).send(`Webhook Error: ${(err as Error).message}`);
|
|
return;
|
|
}
|
|
|
|
// Handle the event
|
|
switch (event.type) {
|
|
case "payment_intent.created": {
|
|
const paymentIntent = event.data.object;
|
|
const { id, metadata } = paymentIntent;
|
|
|
|
if (!metadata) {
|
|
res.status(400).send("No metadata in payment intent");
|
|
return;
|
|
}
|
|
if (!metadata.paymentId || !(typeof metadata.paymentId === "string")) {
|
|
res.status(400).send("No orderId or userId in metadata");
|
|
return;
|
|
}
|
|
|
|
await caller.stripe.whIntentCreated({
|
|
paymentId: metadata.paymentId as PaymentsId,
|
|
pIntentId: id,
|
|
});
|
|
|
|
break;
|
|
}
|
|
case "payment_intent.succeeded": {
|
|
const paymentIntent = event.data.object;
|
|
const { id, metadata } = paymentIntent;
|
|
|
|
if (!metadata) {
|
|
res.status(400).send("No metadata in payment intent");
|
|
return;
|
|
}
|
|
if (!metadata.paymentId || !(typeof metadata.paymentId === "string")) {
|
|
res.status(400).send("No orderId or userId in metadata");
|
|
return;
|
|
}
|
|
await caller.stripe.whIntentSucceeded({
|
|
paymentId: metadata.paymentId as PaymentsId,
|
|
pIntentId: id,
|
|
pm_id:
|
|
typeof paymentIntent.payment_method === "string"
|
|
? paymentIntent.payment_method
|
|
: "",
|
|
});
|
|
|
|
break;
|
|
}
|
|
case "payment_intent.canceled": {
|
|
const paymentIntent = event.data.object;
|
|
await caller.stripe.whIntentFailed({
|
|
pIntentId: paymentIntent.id,
|
|
});
|
|
|
|
break;
|
|
}
|
|
case "payment_intent.payment_failed": {
|
|
const paymentIntent = event.data.object;
|
|
await caller.stripe.whIntentFailed({
|
|
pIntentId: paymentIntent.id,
|
|
});
|
|
break;
|
|
}
|
|
case "payment_intent.processing": {
|
|
const paymentIntent = event.data.object;
|
|
|
|
console.log("PaymentIntent processing", paymentIntent);
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
console.log(`Unhandled event type: ${event.type}`);
|
|
}
|
|
|
|
res.status(200).json({ received: true });
|
|
} else {
|
|
res.setHeader("Allow", "POST");
|
|
res.status(405).end("Method Not Allowed");
|
|
}
|
|
};
|
|
|
|
export const config = {
|
|
api: {
|
|
bodyParser: false,
|
|
},
|
|
};
|
|
|
|
const buffer = (req: NextApiRequest) => {
|
|
return new Promise<Buffer>((resolve, reject) => {
|
|
const chunks: Buffer[] = [];
|
|
|
|
req.on("data", (chunk: Buffer) => {
|
|
chunks.push(chunk);
|
|
});
|
|
|
|
req.on("end", () => {
|
|
resolve(Buffer.concat(chunks));
|
|
});
|
|
|
|
req.on("error", reject);
|
|
});
|
|
};
|
|
|
|
export default handler;
|