Repository Public
1// Auteur : Simon-Pierre Boucher — contact@spboucher.ai2// /api/stats/ecosystem-report — proxy en streaming du rapport écosystème PDF3// généré par API-KA (GET https://www.api-ka.com/api/stats/ecosystem-report).4// v2 : 5 modes de rapport (complet | synthese | tendances | repartitions |5// donnees) + plage personnalisée from/to relayés à API-KA ; un mode ou une6// période inconnus retombent sur les valeurs par défaut (tolérant — si7// API-KA ignore encore `mode`, il renvoie le rapport complet). Conserve8// Content-Type et Content-Disposition (filename groupe-ka_ecosysteme_stats_9// <periode>[_<mode>]_<date>.pdf) ; API-KA garde son propre cache de10// 10 minutes par (period, mode). Aussi exposé sous /api/stats/report11// (endpoint standard du contrat src/ka/stats/SPEC.md).12import { NextRequest } from "next/server";1314export const dynamic = "force-dynamic";1516const UPSTREAM = "https://www.api-ka.com/api/stats/ecosystem-report";17const PERIODS = new Set(["auj", "7j", "30j", "3m", "6m", "12m", "annee", "tout"]);18const MODES = new Set([19 "complet",20 "synthese",21 "tendances",22 "repartitions",23 "donnees",24]);25const DATE_RE = /^\d{4}-\d{2}-\d{2}$/;2627export async function GET(req: NextRequest) {28 const sp = req.nextUrl.searchParams;29 const rawPeriod = sp.get("period") ?? "30j";30 const rawMode = sp.get("mode") ?? "complet";31 const period = PERIODS.has(rawPeriod) ? rawPeriod : "30j";32 const mode = MODES.has(rawMode) ? rawMode : "complet";33 const qs = new URLSearchParams({ period, mode });34 const from = sp.get("from");35 const to = sp.get("to");36 if (from && DATE_RE.test(from)) qs.set("from", from);37 if (to && DATE_RE.test(to)) qs.set("to", to);3839 let upstream: Response;40 try {41 upstream = await fetch(`${UPSTREAM}?${qs}`, {42 cache: "no-store",43 signal: AbortSignal.timeout(60_000),44 headers: { accept: "application/pdf" },45 });46 } catch {47 return Response.json(48 { error: "API-KA injoignable — réessayez dans quelques instants" },49 { status: 502 },50 );51 }52 if (!upstream.ok || !upstream.body) {53 return Response.json(54 { error: `API-KA a répondu ${upstream.status}` },55 { status: 502 },56 );57 }58 const fallbackName = `groupe-ka_ecosysteme_stats_${period}${59 mode !== "complet" ? `_${mode}` : ""60 }_${new Date().toISOString().slice(0, 10)}.pdf`;61 return new Response(upstream.body, {62 status: 200,63 headers: {64 "content-type":65 upstream.headers.get("content-type") ?? "application/pdf",66 "content-disposition":67 upstream.headers.get("content-disposition") ??68 `attachment; filename="${fallbackName}"`,69 "cache-control": "no-store",70 },71 });72}73