#!/usr/bin/env node /** * stripe-purge.mjs * ───────────────── * Supprime TOUS les produits (et leurs prix) du compte Stripe. * * Usage : * node scripts/stripe-purge.mjs # mode dry-run (affiche sans supprimer) * node scripts/stripe-purge.mjs --confirm # suppression réelle * * ⚠️ IRRÉVERSIBLE — utiliser avec précaution */ import 'dotenv/config' import Stripe from 'stripe' const STRIPE_SECRET_KEY = process.env.STRIPE_SECRET_KEY if (!STRIPE_SECRET_KEY) { console.error('❌ STRIPE_SECRET_KEY manquant dans .env') process.exit(1) } const stripe = new Stripe(STRIPE_SECRET_KEY) const dryRun = !process.argv.includes('--confirm') if (dryRun) { console.log('🔍 MODE DRY-RUN — aucun produit ne sera supprimé') console.log(' Ajouter --confirm pour supprimer réellement\n') } async function archivePrices(productId) { let hasMore = true let startingAfter = undefined let count = 0 while (hasMore) { const params = { product: productId, active: true, limit: 100 } if (startingAfter) params.starting_after = startingAfter const prices = await stripe.prices.list(params) for (const price of prices.data) { if (dryRun) { console.log(` 📌 Prix ${price.id} — ${price.unit_amount / 100} ${price.currency.toUpperCase()} (serait archivé)`) } else { await stripe.prices.update(price.id, { active: false }) console.log(` ✓ Prix archivé: ${price.id}`) } count++ } hasMore = prices.has_more if (prices.data.length > 0) { startingAfter = prices.data[prices.data.length - 1].id } } return count } async function main() { let hasMore = true let startingAfter = undefined let totalProducts = 0 let totalPrices = 0 console.log('🗑️ Récupération des produits Stripe...\n') while (hasMore) { const params = { limit: 100, active: true } if (startingAfter) params.starting_after = startingAfter const products = await stripe.products.list(params) for (const product of products.data) { console.log(`📦 ${product.name || product.id}`) // 1. Archiver les prix (obligatoire avant suppression) const priceCount = await archivePrices(product.id) totalPrices += priceCount // 2. Archiver puis supprimer le produit if (dryRun) { console.log(` 🗑️ Produit serait supprimé\n`) } else { // D'abord archiver (désactiver) await stripe.products.update(product.id, { active: false }) // Puis supprimer (possible uniquement si aucune facture liée) try { await stripe.products.del(product.id) console.log(` ✓ Produit supprimé\n`) } catch (err) { // Si le produit a des factures, on ne peut que l'archiver console.log(` ⚠️ Produit archivé (suppression impossible: ${err.message})\n`) } } totalProducts++ } hasMore = products.has_more if (products.data.length > 0) { startingAfter = products.data[products.data.length - 1].id } } // Aussi traiter les produits déjà archivés hasMore = true startingAfter = undefined while (hasMore) { const params = { limit: 100, active: false } if (startingAfter) params.starting_after = startingAfter const products = await stripe.products.list(params) for (const product of products.data) { console.log(`📦 (archivé) ${product.name || product.id}`) const priceCount = await archivePrices(product.id) totalPrices += priceCount if (dryRun) { console.log(` 🗑️ Produit serait supprimé\n`) } else { try { await stripe.products.del(product.id) console.log(` ✓ Produit supprimé\n`) } catch (err) { console.log(` ⚠️ Non supprimable: ${err.message}\n`) } } totalProducts++ } hasMore = products.has_more if (products.data.length > 0) { startingAfter = products.data[products.data.length - 1].id } } console.log('─'.repeat(50)) if (dryRun) { console.log(`📊 ${totalProducts} produits et ${totalPrices} prix SERAIENT supprimés`) console.log('\n👉 Relancer avec --confirm pour exécuter') } else { console.log(`✅ ${totalProducts} produits et ${totalPrices} prix traités`) } } main().catch(err => { console.error('❌ Erreur:', err.message) process.exit(1) })