Skip to content

Commit

Permalink
Address feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
FadhlanR committed Dec 12, 2024
1 parent d3551ba commit 3267d50
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 40 deletions.
72 changes: 55 additions & 17 deletions packages/billing/stripe-webhook-handlers/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { DBAdapter } from '@cardstack/runtime-common';
import { DBAdapter, decodeWebSafeBase64 } from '@cardstack/runtime-common';
import { handlePaymentSucceeded } from './payment-succeeded';
import { handleCheckoutSessionCompleted } from './checkout-session-completed';

import Stripe from 'stripe';
import { handleSubscriptionDeleted } from './subscription-deleted';
import { getUserByStripeId } from '../billing-queries';

export type StripeEvent = {
id: string;
Expand Down Expand Up @@ -99,17 +100,15 @@ export type StripeCheckoutSessionCompletedWebhookEvent = StripeEvent & {
// Invoice immediately (when prorating): CHECKED
// When switching to a cheaper subscription -> WAIT UNTIL END OF BILLING PERIOD TO UPDATE

export default async function stripeWebhookHandler(
dbAdapter: DBAdapter,
request: Request,
sendBillingNotification: ({
stripeCustomerId,
encodedMatrixUserId,
}: {
stripeCustomerId?: string;
encodedMatrixUserId?: string;
}) => Promise<void>,
): Promise<Response> {
export default async function stripeWebhookHandler({
dbAdapter,
request,
sendMatrixEvent,
}: {
dbAdapter: DBAdapter;
request: Request;
sendMatrixEvent: (matrixUserId: string, eventType: string) => Promise<void>;
}): Promise<Response> {
let signature = request.headers.get('stripe-signature');

if (!signature) {
Expand Down Expand Up @@ -141,7 +140,11 @@ export default async function stripeWebhookHandler(
dbAdapter,
event as StripeInvoicePaymentSucceededWebhookEvent,
);
sendBillingNotification({ stripeCustomerId: event.data.object.customer });
sendBillingNotification({
dbAdapter,
sendMatrixEvent,
stripeEvent: event,
});
break;
}
case 'customer.subscription.deleted': {
Expand All @@ -150,20 +153,55 @@ export default async function stripeWebhookHandler(
dbAdapter,
event as StripeSubscriptionDeletedWebhookEvent,
);
sendBillingNotification({ stripeCustomerId: event.data.object.customer });
sendBillingNotification({
dbAdapter,
sendMatrixEvent,
stripeEvent: event,
});
break;
}
case 'checkout.session.completed': {
await handleCheckoutSessionCompleted(
dbAdapter,
event as StripeCheckoutSessionCompletedWebhookEvent,
);
await sendBillingNotification({
stripeCustomerId: event.data.object.customer,
encodedMatrixUserId: event.data.object.client_reference_id,
sendBillingNotification({
dbAdapter,
sendMatrixEvent,
stripeEvent: event,
});
break;
}
}
return new Response('ok');
}

async function sendBillingNotification({
dbAdapter,
sendMatrixEvent,
stripeEvent,
}: {
dbAdapter: DBAdapter;
sendMatrixEvent: (matrixUserId: string, eventType: string) => Promise<void>;
stripeEvent: StripeEvent;
}) {
let matrixUserId = await extractMatrixUserId(dbAdapter, stripeEvent);
if (!matrixUserId) {
throw new Error('Failed to extract matrix user id from stripe event');
}
await sendMatrixEvent(matrixUserId, 'billing-notification');
}

async function extractMatrixUserId(dbAdapter: DBAdapter, event: StripeEvent) {
let encodedMatrixUserId = event.data.object.client_reference_id;
let matrixUserId = encodedMatrixUserId
? decodeWebSafeBase64(encodedMatrixUserId)
: undefined;

if (event.data.object.customer) {
let user = await getUserByStripeId(dbAdapter, event.data.object.customer);
matrixUserId = user?.matrixUserId;
}

return matrixUserId;
}
26 changes: 3 additions & 23 deletions packages/realm-server/handlers/handle-stripe-webhook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import Koa from 'koa';
import { fetchRequestFromContext, setContextResponse } from '../middleware';
import stripeWebhookHandler from '@cardstack/billing/stripe-webhook-handlers';
import { CreateRoutesArgs } from '../routes';
import { getUserByStripeId } from '@cardstack/billing/billing-queries';
import { decodeWebSafeBase64 } from '@cardstack/runtime-common';

export default function handleStripeWebhookRequest({
dbAdapter,
Expand All @@ -12,29 +10,11 @@ export default function handleStripeWebhookRequest({
return async function (ctxt: Koa.Context, _next: Koa.Next) {
let request = await fetchRequestFromContext(ctxt);

let response = await stripeWebhookHandler(
let response = await stripeWebhookHandler({
dbAdapter,
request,
async ({
stripeCustomerId,
encodedMatrixUserId,
}: {
stripeCustomerId?: string;
encodedMatrixUserId?: string;
}) => {
let matrixUserId = encodedMatrixUserId
? decodeWebSafeBase64(encodedMatrixUserId)
: undefined;
if (stripeCustomerId) {
let user = await getUserByStripeId(dbAdapter, stripeCustomerId);
matrixUserId = user?.matrixUserId;
}

if (matrixUserId) {
await sendEvent(matrixUserId, 'billing-notification');
}
},
);
sendMatrixEvent: sendEvent,
});
await setContextResponse(ctxt, response);
};
}
2 changes: 2 additions & 0 deletions packages/realm-server/tests/realm-server-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4338,6 +4338,7 @@ module('Realm Server', function (hooks) {
cancellation_details: {
reason: 'payment_failure',
},
customer: 'cus_123',
},
},
};
Expand Down Expand Up @@ -4488,6 +4489,7 @@ module('Realm Server', function (hooks) {
cancellation_details: {
reason: 'payment_failure',
},
customer: 'cus_123',
},
},
};
Expand Down

0 comments on commit 3267d50

Please sign in to comment.