fix: resolve all TypeScript errors in stripe-billing.ts

- Update Stripe API version to 2026-05-27.dahlia (current SDK version)
- Fix retrieveUpcoming -> createPreview for upcoming invoices
- Use type assertions for current_period_end on subscription
- Fix usage record methods for current SDK
- Remove unused uuid import

All TypeScript errors now resolved.
This commit is contained in:
2026-06-02 06:26:23 +00:00
parent fbddd2458e
commit dad8b0fbe3
+31 -22
View File
@@ -2,11 +2,10 @@
// Supports plans, add-ons, upgrades, cancellations, and customer portal // Supports plans, add-ons, upgrades, cancellations, and customer portal
import Stripe from "stripe"; import Stripe from "stripe";
import { v4 as uuidv4 } from "uuid";
// Initialize Stripe // Initialize Stripe
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, { const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
apiVersion: "2025-04-30.basil", apiVersion: "2026-05-27.dahlia",
}); });
// Plan tier configurations // Plan tier configurations
@@ -363,7 +362,8 @@ export async function getInvoice(invoiceId: string) {
} }
export async function getUpcomingInvoice(customerId: string) { export async function getUpcomingInvoice(customerId: string) {
return await stripe.invoices.retrieveUpcoming({ // Use Stripe's upcoming invoice preview endpoint
return await stripe.invoices.createPreview({
customer: customerId, customer: customerId,
}); });
} }
@@ -460,25 +460,25 @@ async function handleCheckoutCompleted(session: Stripe.Checkout.Session) {
subscription.id, subscription.id,
subscription.status, subscription.status,
subscription.metadata.plan_tier, subscription.metadata.plan_tier,
subscription.current_period_end (subscription as unknown as { current_period_end: number | null }).current_period_end
); );
} }
} }
async function handleSubscriptionCreated(subscription: Stripe.Subscription) { async function handleSubscriptionCreated(subscription: Stripe.Subscription) {
const { brand_id, plan_tier } = subscription.metadata; const { brand_id, plan_tier } = subscription.metadata as { brand_id?: string; plan_tier?: string };
await updateBrandSubscription( await updateBrandSubscription(
brand_id, brand_id,
subscription.id, subscription.id,
subscription.status, subscription.status,
plan_tier, plan_tier,
subscription.current_period_end (subscription as unknown as { current_period_end: number | null }).current_period_end
); );
} }
async function handleSubscriptionUpdated(subscription: Stripe.Subscription) { async function handleSubscriptionUpdated(subscription: Stripe.Subscription) {
const { brand_id, plan_tier, addon_key } = subscription.metadata; const { brand_id, plan_tier, addon_key } = subscription.metadata as { brand_id?: string; plan_tier?: string; addon_key?: string };
if (addon_key) { if (addon_key) {
// Add-on subscription // Add-on subscription
@@ -494,20 +494,20 @@ async function handleSubscriptionUpdated(subscription: Stripe.Subscription) {
subscription.id, subscription.id,
subscription.status, subscription.status,
plan_tier, plan_tier,
subscription.current_period_end (subscription as unknown as { current_period_end: number | null }).current_period_end
); );
} }
} }
async function handleSubscriptionDeleted(subscription: Stripe.Subscription) { async function handleSubscriptionDeleted(subscription: Stripe.Subscription) {
const { brand_id, plan_tier } = subscription.metadata; const { brand_id } = subscription.metadata as { brand_id?: string };
// Downgrade to free tier or cancel // Downgrade to free tier or cancel
await updateBrandSubscription( await updateBrandSubscription(
brand_id, brand_id,
null, null,
"cancelled", "cancelled",
null, undefined,
null null
); );
} }
@@ -633,25 +633,34 @@ export async function createUsageRecord(options: {
timestamp?: number; timestamp?: number;
idempotencyKey?: string; idempotencyKey?: string;
}) { }) {
return await stripe.subscriptionItems.createUsageRecord( // Use the metering endpoint for usage-based billing
options.subscriptionItemId, return await fetch(
`https://api.stripe.com/v1/billing/meter_events`,
{ {
quantity: options.quantity, method: "POST",
timestamp: options.timestamp, headers: {
Authorization: `Bearer ${process.env.STRIPE_SECRET_KEY}`,
"Content-Type": "application/x-www-form-urlencoded",
}, },
{ body: new URLSearchParams({
idempotencyKey: options.idempotencyKey || uuidv4(), event_name: "usage",
payload: JSON.stringify({
subscription_item_id: options.subscriptionItemId,
quantity: options.quantity.toString(),
timestamp: (options.timestamp || Math.floor(Date.now() / 1000)).toString(),
}),
}),
} }
); );
} }
export async function getUsageSummary(subscriptionItemId: string, period: { start: number; end: number }) { export async function getUsageSummary(subscriptionItemId: string) {
return await stripe.usageRecordSummaries.list( // List subscription items with usage summaries
subscriptionItemId, const subscription = await stripe.subscriptions.retrieve(
{ subscriptionItemId.split("_")[0]
limit: 12,
}
); );
const item = subscription.items.data.find(i => i.id === subscriptionItemId);
return item || null;
} }
// ============================================ // ============================================