import Stripe from 'stripe' import env from '#start/env' /** * Singleton client Stripe — lazy init pour ne pas crasher en dev/test * quand la clé n'est pas définie. Toute fonction qui nécessite Stripe * appelle `getStripe()` qui throw si la clé manque. */ let _stripe: Stripe | null = null export function getStripe(): Stripe { if (_stripe) return _stripe const key = env.get('STRIPE_SECRET_KEY') if (!key) { throw new Error( 'STRIPE_SECRET_KEY manquante. Configurer la clé dans .env avant d\'utiliser le billing.' ) } _stripe = new Stripe(key, { apiVersion: '2026-04-22.dahlia', typescript: true, appInfo: { name: 'Rubis sur l\'ongle', version: '1.0.0', }, }) return _stripe } /** * Lookup keys utilisés pour identifier les Prices Stripe sans hardcoder * d'IDs en env. Les Prices sont créées par `node ace stripe:setup` avec * ces lookup_keys, et le code les retrouve via `prices.list({lookup_keys})`. */ export const STRIPE_LOOKUP_KEYS = { pro_monthly: 'rubis_pro_monthly', pro_yearly: 'rubis_pro_yearly', business_monthly: 'rubis_business_monthly', business_yearly: 'rubis_business_yearly', } as const export type StripeLookupKey = (typeof STRIPE_LOOKUP_KEYS)[keyof typeof STRIPE_LOOKUP_KEYS] /** * Récupère un Price Stripe via son lookup_key. Throw si introuvable * (signal que `stripe:setup` n'a pas été lancé ou que les lookup_keys * ont changé). */ export async function getPriceByLookup(key: StripeLookupKey): Promise { const stripe = getStripe() const result = await stripe.prices.list({ lookup_keys: [key], limit: 1, expand: ['data.product'], }) const price = result.data[0] if (!price) { throw new Error( `Stripe Price introuvable pour lookup_key="${key}". Lancer \`node ace stripe:setup\` ?` ) } return price }