Initial commit: PodcastYes — AI podcast platform
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
import Stripe from "stripe";
|
||||
import { prisma } from "@/lib/db";
|
||||
import { stripePriceId, type BillingInterval } from "./catalog";
|
||||
import type { PlanKey } from "./plans";
|
||||
|
||||
let client: Stripe | null = null;
|
||||
|
||||
export function stripe(): Stripe {
|
||||
if (!client) {
|
||||
const key = process.env.STRIPE_SECRET_KEY;
|
||||
if (!key) throw new Error("STRIPE_SECRET_KEY is not set");
|
||||
client = new Stripe(key);
|
||||
}
|
||||
return client;
|
||||
}
|
||||
|
||||
export function isStripeConfigured(): boolean {
|
||||
return !!process.env.STRIPE_SECRET_KEY;
|
||||
}
|
||||
|
||||
const appUrl = () => process.env.NEXT_PUBLIC_APP_URL ?? "http://localhost:3000";
|
||||
|
||||
/** Find-or-create the Stripe customer for a user and persist the id. */
|
||||
export async function ensureStripeCustomer(user: {
|
||||
id: string;
|
||||
email: string;
|
||||
name: string;
|
||||
stripeCustomerId: string | null;
|
||||
}): Promise<string> {
|
||||
if (user.stripeCustomerId) return user.stripeCustomerId;
|
||||
const customer = await stripe().customers.create({
|
||||
email: user.email,
|
||||
name: user.name,
|
||||
metadata: { userId: user.id },
|
||||
});
|
||||
await prisma.user.update({ where: { id: user.id }, data: { stripeCustomerId: customer.id } });
|
||||
return customer.id;
|
||||
}
|
||||
|
||||
/** Create a Stripe Checkout Session for a subscription; returns the redirect URL. */
|
||||
export async function createStripeCheckout(args: {
|
||||
user: { id: string; email: string; name: string; stripeCustomerId: string | null };
|
||||
plan: PlanKey;
|
||||
interval: BillingInterval;
|
||||
subjectId: string;
|
||||
subjectType: "user" | "organization";
|
||||
}): Promise<string> {
|
||||
const price = stripePriceId(args.plan, args.interval);
|
||||
if (!price) throw new Error(`No Stripe price configured for ${args.plan}/${args.interval}`);
|
||||
const customer = await ensureStripeCustomer(args.user);
|
||||
|
||||
const session = await stripe().checkout.sessions.create({
|
||||
mode: "subscription",
|
||||
customer,
|
||||
line_items: [{ price, quantity: 1 }],
|
||||
client_reference_id: args.subjectId,
|
||||
metadata: { plan: args.plan, subjectId: args.subjectId, subjectType: args.subjectType },
|
||||
subscription_data: {
|
||||
metadata: { plan: args.plan, subjectId: args.subjectId, subjectType: args.subjectType },
|
||||
},
|
||||
allow_promotion_codes: true,
|
||||
success_url: `${appUrl()}/billing?status=success`,
|
||||
cancel_url: `${appUrl()}/billing?status=cancel`,
|
||||
});
|
||||
if (!session.url) throw new Error("Stripe did not return a checkout URL");
|
||||
return session.url;
|
||||
}
|
||||
|
||||
/** Create a Stripe Billing Portal session for managing/cancelling a subscription. */
|
||||
export async function createStripePortal(customerId: string): Promise<string> {
|
||||
const session = await stripe().billingPortal.sessions.create({
|
||||
customer: customerId,
|
||||
return_url: `${appUrl()}/billing`,
|
||||
});
|
||||
return session.url;
|
||||
}
|
||||
Reference in New Issue
Block a user