SPB Git

Repository Public

route.ts 2.6 KB 73 lines typescript

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
Files main
Menu

Theme