rebours/server.ts
2026-02-24 11:35:30 +01:00

141 lines
4.5 KiB
TypeScript

import { Elysia, t } from 'elysia'
import { cors } from '@elysiajs/cors'
import { staticPlugin } from '@elysiajs/static'
import Stripe from 'stripe'
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY ?? '', {
apiVersion: '2025-01-27.acacia',
})
const DOMAIN = process.env.DOMAIN ?? 'http://localhost:3000'
// Produit LUMIÈRE_ORBITALE — prix en centimes (EUR)
const PRODUCTS = {
lumiere_orbitale: {
name: 'LUMIÈRE_ORBITALE — REBOUR',
description: 'Lampe de table unique. Béton texturé coulé à la main + dôme céramique laqué. Collection 001.',
amount: 180000, // 1800 EUR
currency: 'eur',
},
}
const app = new Elysia()
.use(cors({
origin: DOMAIN,
methods: ['GET', 'POST'],
}))
// Sert les fichiers statiques (html, css, js, assets)
.use(staticPlugin({
assets: '.',
prefix: '/',
indexHTML: true,
}))
// ── Créer une session de checkout Stripe ──────────────────────────────────
.post(
'/api/checkout',
async ({ body }) => {
const product = PRODUCTS[body.product as keyof typeof PRODUCTS]
if (!product) {
throw new Error('Produit inconnu')
}
const session = await stripe.checkout.sessions.create({
mode: 'payment',
payment_method_types: ['card'],
line_items: [
{
price_data: {
currency: product.currency,
unit_amount: product.amount,
product_data: {
name: product.name,
description: product.description,
},
},
quantity: 1,
},
],
success_url: `${DOMAIN}/success.html?session_id={CHECKOUT_SESSION_ID}`,
cancel_url: `${DOMAIN}/#collection`,
locale: 'fr',
custom_text: {
submit: { message: 'Pièce unique — fabriquée à Paris. Délai de fabrication : 6 à 8 semaines.' },
},
})
return { url: session.url }
},
{
body: t.Object({
product: t.String(),
email: t.Optional(t.String({ format: 'email' })),
}),
}
)
// ── Vérification de session (page success) ────────────────────────────────
.get(
'/api/session/:id',
async ({ params }) => {
const session = await stripe.checkout.sessions.retrieve(params.id)
return {
status: session.payment_status,
amount: session.amount_total,
currency: session.currency,
customer_email: session.customer_details?.email ?? null,
}
},
{
params: t.Object({ id: t.String() }),
}
)
// ── Webhook Stripe ────────────────────────────────────────────────────────
.post('/api/webhook', async ({ request, headers }) => {
const sig = headers['stripe-signature']
const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET
if (!sig || !webhookSecret) {
return new Response('Missing signature', { status: 400 })
}
let event: Stripe.Event
const rawBody = await request.arrayBuffer()
try {
event = stripe.webhooks.constructEvent(
Buffer.from(rawBody),
sig,
webhookSecret
)
} catch (err) {
console.error('⚠ Webhook signature invalide:', err)
return new Response('Webhook Error', { status: 400 })
}
if (event.type === 'checkout.session.completed') {
const session = event.data.object as Stripe.Checkout.Session
if (session.payment_status === 'paid') {
console.log(`✓ Paiement reçu — session: ${session.id}`)
console.log(` Client: ${session.customer_details?.email}`)
console.log(` Montant: ${(session.amount_total ?? 0) / 100} EUR`)
// → ici : envoyer email confirmation, mettre à jour BDD, etc.
}
}
return { received: true }
})
.listen(3000)
console.log(`
┌──────────────────────────────────────┐
│ REBOUR — SERVEUR DÉMARRÉ │
│ http://localhost:3000 │
│ │
│ POST /api/checkout │
│ GET /api/session/:id │
│ POST /api/webhook │
└──────────────────────────────────────┘
`)