templates2.Base.Nuxt/server/api/billing/checkout.post.ts
w4c-templates a7a56fd5e0
Some checks failed
CI / quality (push) Has been cancelled
chore(template): publish Base.Nuxt
2026-10-11 23:23:38 +03:00

40 lines
1.6 KiB
TypeScript

import { z } from 'zod';
import { db } from '../../utils/db';
import { getCurrentUser } from '../../utils/auth';
import { getPayments } from '../../utils/payments';
import { recordAudit } from '../../utils/audit';
const schema = z.object({ plan: z.enum(['free', 'pro']) });
export default defineEventHandler(async (event) => {
const user = await getCurrentUser(event);
if (!user) throw createError({ statusCode: 401, statusMessage: 'Unauthorized' });
const parsed = schema.safeParse(await readBody(event).catch(() => ({})));
if (!parsed.success) throw createError({ statusCode: 400, statusMessage: 'Invalid plan' });
const config = useRuntimeConfig(event);
const siteUrl = String(config.public.siteUrl).replace(/\/$/, '');
const provider = getPayments(event);
const result = await provider.createCheckout({
userId: user.id,
email: user.email,
plan: parsed.data.plan,
successUrl: `${siteUrl}/dashboard`,
cancelUrl: `${siteUrl}/pricing`,
});
// The mock provider has no external redirect: activate the subscription right away.
if (provider.name === 'mock') {
const currentPeriodEnd = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000);
await db.subscription.upsert({
where: { userId: user.id },
update: { plan: parsed.data.plan, status: 'active', provider: 'mock', currentPeriodEnd },
create: { userId: user.id, plan: parsed.data.plan, status: 'active', provider: 'mock', currentPeriodEnd },
});
}
await recordAudit({ actorId: user.id, action: 'billing.checkout', target: parsed.data.plan, meta: { provider: provider.name } });
return { id: result.id, url: result.url, provider: provider.name };
});