Repository Public
1// Auteur : Simon-Pierre Boucher — contact@spboucher.ai2/**3 * POST /api/stats/report/custom — v3 : rapport PDF personnalisé4 * (src/ka/stats/SPEC.md §3bis). Corps : {"title", "period", "from", "to",5 * "blocks": [{"key": "series:…", "render": "bar"}, …]} — ordre respecté,6 * clés inconnues ignorées, aucune clé valide → 400. Généré LOCALEMENT7 * depuis l'EcoPayload consolidé (le rapport écosystème v2 à 5 modes reste,8 * lui, proxifié vers API-KA via /api/stats/ecosystem-report).9 */10import { type NextRequest, NextResponse } from "next/server";11import {12 buildCustomReport,13 customReportFilename,14 getReportPayload,15 type CustomSpec,16} from "@/lib/report-stats";17import { isPeriod } from "@/lib/ecostats";1819export const dynamic = "force-dynamic";2021export async function POST(req: NextRequest) {22 let spec: CustomSpec;23 try {24 spec = (await req.json()) as CustomSpec;25 } catch {26 return NextResponse.json({ error: "Corps JSON invalide" }, { status: 400 });27 }28 const period = isPeriod(spec?.period) ? spec.period : "30j";29 const payload = await getReportPayload(period);30 try {31 const pdf = await buildCustomReport(spec ?? {}, payload);32 return new NextResponse(new Uint8Array(pdf), {33 headers: {34 "Content-Type": "application/pdf",35 "Content-Disposition": `attachment; filename="${customReportFilename(period)}"`,36 "Cache-Control": "no-store",37 },38 });39 } catch (e) {40 if (e instanceof Error && e.message === "aucun-bloc") {41 return NextResponse.json({ error: "Aucun bloc valide dans la composition" }, { status: 400 });42 }43 throw e;44 }45}46