feat: whyrating - initial project from turbostarter boilerplate
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
import { HttpStatusCode } from "@turbostarter/shared/constants";
|
||||
import { logger } from "@turbostarter/shared/logger";
|
||||
import { HttpException } from "@turbostarter/shared/utils";
|
||||
|
||||
import { checkoutStatusChangeHandler } from "../checkout";
|
||||
import { env } from "../env";
|
||||
import { subscriptionStatusChangeHandler } from "../subscription";
|
||||
|
||||
import { LEMON_SQUEEZY_SIGNATURE_HEADER } from "./constants";
|
||||
import { validateSignature } from "./signing";
|
||||
import { webhookHasData, webhookHasMeta } from "./type-guards";
|
||||
|
||||
import type { BillingProviderStrategy } from "../../types";
|
||||
|
||||
export const webhookHandler: BillingProviderStrategy["webhookHandler"] = async (
|
||||
req,
|
||||
callbacks,
|
||||
) => {
|
||||
const body = await req.text();
|
||||
const sig = req.headers.get(LEMON_SQUEEZY_SIGNATURE_HEADER);
|
||||
|
||||
if (!sig) {
|
||||
throw new HttpException(HttpStatusCode.BAD_REQUEST, {
|
||||
code: "billing:error.webhook.signatureNotFound",
|
||||
});
|
||||
}
|
||||
|
||||
await validateSignature(sig, env.LEMON_SQUEEZY_SIGNING_SECRET, body);
|
||||
|
||||
const data = JSON.parse(body);
|
||||
|
||||
if (!webhookHasMeta(data)) {
|
||||
throw new HttpException(HttpStatusCode.BAD_REQUEST, {
|
||||
code: "billing:error.webhook.metaInvalid",
|
||||
});
|
||||
}
|
||||
|
||||
const type = data.meta.event_name;
|
||||
|
||||
logger.info(`🔔 Webhook received: ${type}`);
|
||||
|
||||
if (!webhookHasData(data)) {
|
||||
throw new HttpException(HttpStatusCode.BAD_REQUEST, {
|
||||
code: "billing:error.webhook.dataInvalid",
|
||||
});
|
||||
}
|
||||
|
||||
await callbacks?.onEvent?.(data);
|
||||
|
||||
switch (type) {
|
||||
case "subscription_created":
|
||||
await callbacks?.onSubscriptionCreated?.(data.data.id);
|
||||
await subscriptionStatusChangeHandler({
|
||||
id: data.data.id,
|
||||
});
|
||||
break;
|
||||
case "subscription_updated":
|
||||
await callbacks?.onSubscriptionUpdated?.(data.data.id);
|
||||
await subscriptionStatusChangeHandler({
|
||||
id: data.data.id,
|
||||
});
|
||||
break;
|
||||
case "subscription_expired":
|
||||
await callbacks?.onSubscriptionDeleted?.(data.data.id);
|
||||
await subscriptionStatusChangeHandler({
|
||||
id: data.data.id,
|
||||
});
|
||||
break;
|
||||
case "order_created":
|
||||
await callbacks?.onCheckoutSessionCompleted?.(data.data.id);
|
||||
await checkoutStatusChangeHandler({
|
||||
id: data.data.id,
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
return new Response(JSON.stringify({ received: true }), {
|
||||
status: 200,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user