rebours/public/main.js
2026-02-27 16:20:16 +01:00

115 lines
4.4 KiB
JavaScript

import Fastify from 'fastify'
import cors from '@fastify/cors'
import Stripe from 'stripe'
import { readFileSync } from 'node:fs'
import dotenv from 'dotenv';
dotenv.config()
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY ?? '')
const DOMAIN = process.env.DOMAIN ?? 'http://localhost:3000'
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,
currency: 'eur',
},
}
const app = Fastify({ logger: true })
await app.register(cors, { origin: '*', methods: ['GET', 'POST'] })
// ── SEO ───────────────────────────────────────────────────────────────────────
app.get('/robots.txt', (_, reply) => {
reply
.type('text/plain')
.header('Cache-Control', 'public, max-age=86400')
.send(`User-agent: *\nAllow: /\nSitemap: ${DOMAIN}/sitemap.xml\n`)
})
app.get('/sitemap.xml', (_, reply) => {
const today = new Date().toISOString().split('T')[0]
reply
.type('application/xml')
.header('Cache-Control', 'public, max-age=86400')
.send(
`<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n <url><loc>${DOMAIN}/</loc><lastmod>${today}</lastmod><changefreq>weekly</changefreq><priority>1.0</priority></url>\n</urlset>`
)
})
// ── Checkout Stripe ───────────────────────────────────────────────────────────
app.post('/api/checkout', async (request, reply) => {
const { product, email } = request.body ?? {}
const p = PRODUCTS[product]
if (!p) return reply.code(404).send({ error: 'Produit inconnu' })
const session = await stripe.checkout.sessions.create({
mode: 'payment',
payment_method_types: ['card'],
line_items: [{
price_data: {
currency: p.currency,
unit_amount: p.amount,
product_data: { name: p.name, description: p.description },
},
quantity: 1,
}],
success_url: `${DOMAIN}/success?session_id={CHECKOUT_SESSION_ID}`,
cancel_url: `${DOMAIN}/#collection`,
locale: 'fr',
customer_email: email ?? undefined,
custom_text: {
submit: { message: 'Pièce unique — fabriquée à Paris. Délai : 6 à 8 semaines.' },
},
})
return { url: session.url }
})
// ── Vérification session ──────────────────────────────────────────────────────
app.get('/api/session/:id', async (request) => {
const session = await stripe.checkout.sessions.retrieve(request.params.id)
return {
status: session.payment_status,
amount: session.amount_total,
currency: session.currency,
customer_email: session.customer_details?.email ?? null,
}
})
// ── Webhook Stripe ────────────────────────────────────────────────────────────
app.addContentTypeParser('application/json', { parseAs: 'buffer' }, (req, body, done) => {
done(null, body)
})
app.post('/api/webhook', async (request, reply) => {
const sig = request.headers['stripe-signature']
const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET
if (!sig || !webhookSecret) return reply.code(400).send('Missing signature')
let event
try {
event = stripe.webhooks.constructEvent(request.body, sig, webhookSecret)
} catch {
return reply.code(400).send('Webhook Error')
}
if (event.type === 'checkout.session.completed') {
const session = event.data.object
if (session.payment_status === 'paid') {
app.log.info(`✓ Paiement — ${session.id}${session.customer_details?.email}`)
}
}
return { received: true }
})
// ── Start ─────────────────────────────────────────────────────────────────────
try {
await app.listen({ port: 3000, host: '127.0.0.1' })
} catch (err) {
app.log.error(err)
process.exit(1)
}