Files
famdone/frontend/src/lib/server/stripe-events.ts
T
2026-08-22 19:49:46 +01:00

49 lines
1.8 KiB
TypeScript

import { pbAdmin } from '$lib/server/pocketbase';
import type Stripe from 'stripe';
// Shared Stripe event handling. The real webhook (/api/webhooks/stripe) routes
// through here so the DB effects are identical.
export async function handleStripeEvent(event: Stripe.Event): Promise<void> {
switch (event.type) {
case 'checkout.session.completed': {
const session = event.data.object as Stripe.Checkout.Session;
const famId = session.metadata?.famId;
if (famId && session.customer) {
await pbAdmin.update('fams', famId, {
stripeCustomerId: String(session.customer),
active: true,
paymentMode: 'sub'
});
}
break;
}
case 'customer.subscription.created':
case 'customer.subscription.updated':
case 'customer.subscription.paused': {
const sub = event.data.object as Stripe.Subscription;
await setActiveFromSubscription(sub);
break;
}
case 'customer.subscription.deleted': {
const sub = event.data.object as Stripe.Subscription;
const fams = await pbAdmin.getList('fams', `stripeCustomerId = '${sub.customer}'`);
const fam = fams[0];
if (fam) {
await pbAdmin.update('fams', fam.id, { active: false, paymentMode: 'canceled' });
}
break;
}
}
}
async function setActiveFromSubscription(sub: Stripe.Subscription) {
// The fam that owns this subscription — look up by the customer id stored
// on the fam (set at checkout). Stripe customer id is unique per fam.
const fams = await pbAdmin.getList('fams', `stripeCustomerId = '${sub.customer}'`);
const fam = fams[0];
if (!fam) return;
// Active only while the sub is trialing/active (not past_due/canceled/paused).
const active =
sub.status === 'trialing' || sub.status === 'active' || sub.status === 'past_due';
await pbAdmin.update('fams', fam.id, { active, paymentMode: 'sub' });
}