UNPKG

ghost

Version:

The professional publishing platform

101 lines (92 loc) 3.64 kB
const logging = require('@tryghost/logging'); module.exports = class WebhookController { /** * @param {object} deps * @param {import('./WebhookManager')} deps.webhookManager * @param {import('./services/webhook/CheckoutSessionEventService')} deps.checkoutSessionEventService * @param {import('./services/webhook/SubscriptionEventService')} deps.subscriptionEventService * @param {import('./services/webhook/InvoiceEventService')} deps.invoiceEventService */ constructor(deps) { this.checkoutSessionEventService = deps.checkoutSessionEventService; this.subscriptionEventService = deps.subscriptionEventService; this.invoiceEventService = deps.invoiceEventService; this.webhookManager = deps.webhookManager; this.handlers = { 'customer.subscription.deleted': this.subscriptionEvent, 'customer.subscription.updated': this.subscriptionEvent, 'customer.subscription.created': this.subscriptionEvent, 'invoice.payment_succeeded': this.invoiceEvent, 'checkout.session.completed': this.checkoutSessionEvent }; } /** * Handles a Stripe webhook event. * - Parses the webhook event * - Delegates the event to the appropriate handler * - Returns a 200 response to Stripe to confirm receipt of the event, or an error response if the event is not handled or if an error occurs * @param {import('express').Request} req * @param {import('express').Response} res * @returns {Promise<void>} */ async handle(req, res) { if (!req.body || !req.headers['stripe-signature']) { res.writeHead(400); return res.end(); } let event; try { event = this.webhookManager.parseWebhook(req.body, req.headers['stripe-signature']); } catch (err) { logging.error(err); res.writeHead(401); return res.end(); } logging.info(`Handling webhook ${event.type}`); try { await this.handleEvent(event); res.writeHead(200); res.end(); } catch (err) { logging.error(`Error handling webhook ${event.type}`, err); res.writeHead(err.statusCode || 500); res.end(); } } /** * Accepts a webhook's event payload and delegates it to the appropriate handler based on the event type * @private * @param {import('stripe').Stripe.Event} event * @returns {Promise<void>} */ async handleEvent(event) { if (!this.handlers[event.type]) { return; } await this.handlers[event.type].call(this, event.data.object); } /** * Delegates any `customer.subscription.*` events to the `subscriptionEventService` * @param {import('stripe').Stripe.Subscription} subscription * @private */ async subscriptionEvent(subscription) { await this.subscriptionEventService.handleSubscriptionEvent(subscription); } /** * Delegates any `invoice.*` events to the `invoiceEventService` * @param {import('stripe').Stripe.Invoice} invoice * @private */ async invoiceEvent(invoice) { await this.invoiceEventService.handleInvoiceEvent(invoice); } /** * Delegates any `checkout.session.*` events to the `checkoutSessionEventService` * @param {import('stripe').Stripe.Checkout.Session} session * @private */ async checkoutSessionEvent(session) { await this.checkoutSessionEventService.handleEvent(session); } };