feat: retire API publique + dedupe load-balancing MF + maj pages
Some checks are pending
Deploy info-canicule / deploy (push) Waiting to run
Some checks are pending
Deploy info-canicule / deploy (push) Waiting to run
API publique retirée : - /api/vigilance et /api/vigilance/dept/[code] supprimés - Mentions retirées dans footer, /mentions-legales, /embed - /api/health garde, sans CORS (usage interne UptimeRobot + cron HC.io) - Tests E2E mis à jour (vérifient 404 sur les endpoints retirés) Pages : - /dependances : entièrement mise à jour (Sentry, sharp, Playwright, sitemap, typography ajoutés ; API MF officielle DPObs+DPVigilance, normales 1991-2020 listées ; section Services tiers ajoutée pour Opendatasoft en fallback ; section Infrastructure complétée avec GlitchTip + CrowdSec). - /soutenir : "~7€/mois mutualisés" → "~30€/mois", suppression du détail VPS OVH (juste "infra"), suppression du bloc "Réutiliser les données via API". Vigilance Météo France load-balancing : - lib/vigilance.ts : fetch parallèle x3 et garde la réponse au update_time le plus récent. Constat 2026-05-26 : le gateway MF load-balance entre instances désynchronisées (~60% renvoyaient bulletin J-1, ~40% bulletin J). Cette mitigation atteint >95% de probabilité d'avoir le bulletin frais. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
0a1f11aa00
commit
27441cdbb8
10 changed files with 139 additions and 148 deletions
|
|
@ -12,6 +12,11 @@ export const GET: APIRoute = async () => {
|
|||
};
|
||||
return new Response(JSON.stringify(body), {
|
||||
status: cacheOk ? 200 : 503,
|
||||
headers: { 'Content-Type': 'application/json', 'Cache-Control': 'no-store' },
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Cache-Control': 'no-store',
|
||||
// Pas de CORS : endpoint d'usage interne (UptimeRobot + cron HC.io freshness).
|
||||
// Pas destiné aux clients tiers.
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,24 +0,0 @@
|
|||
import type { APIRoute } from 'astro';
|
||||
import { getVigilanceSnapshot } from '../../lib/vigilance';
|
||||
|
||||
export const prerender = false;
|
||||
|
||||
// JSON public du snapshot Vigilance actuel — réutilisable sous Licence Ouverte 2.0.
|
||||
export const GET: APIRoute = async () => {
|
||||
try {
|
||||
const snap = await getVigilanceSnapshot();
|
||||
return new Response(JSON.stringify(snap), {
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=utf-8',
|
||||
'Cache-Control': 'public, max-age=300',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
return new Response(
|
||||
JSON.stringify({ error: 'fetch_failed', detail: (e as Error).message }),
|
||||
{ status: 502, headers: { 'Content-Type': 'application/json' } },
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
import type { APIRoute } from 'astro';
|
||||
import { getVigilanceSnapshot, alertsForDepartement } from '../../../../lib/vigilance';
|
||||
import { getDepartement } from '../../../../lib/departements';
|
||||
import { PHENOMENA, COLORS } from '../../../../lib/phenomena';
|
||||
|
||||
export const prerender = false;
|
||||
|
||||
// JSON par département (J + J1) — CORS *, réutilisable sous Licence Ouverte 2.0.
|
||||
// Ex : GET /api/vigilance/dept/75 → alertes Paris
|
||||
export const GET: APIRoute = async ({ params }) => {
|
||||
const codeRaw = params.code;
|
||||
if (!codeRaw) {
|
||||
return new Response(JSON.stringify({ error: 'missing_code' }), {
|
||||
status: 400,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
}
|
||||
const code = codeRaw.toUpperCase();
|
||||
const dept = getDepartement(code);
|
||||
if (!dept) {
|
||||
return new Response(JSON.stringify({ error: 'unknown_departement', code }), {
|
||||
status: 404,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
const snap = await getVigilanceSnapshot();
|
||||
const today = alertsForDepartement(snap, code, 'J');
|
||||
const tomorrow = alertsForDepartement(snap, code, 'J1');
|
||||
const enrich = (a: ReturnType<typeof alertsForDepartement>[0]) => ({
|
||||
phenomenonId: a.phenomenonId,
|
||||
phenomenon: PHENOMENA[a.phenomenonId].label,
|
||||
colorId: a.colorId,
|
||||
color: COLORS[a.colorId].name,
|
||||
beginTime: a.beginTime,
|
||||
endTime: a.endTime,
|
||||
});
|
||||
|
||||
const body = {
|
||||
departement: { code, name: dept.name, region: dept.region },
|
||||
productDatetime: snap.productDatetime,
|
||||
fetchedAt: snap.fetchedAt,
|
||||
today: today.map(enrich),
|
||||
tomorrow: tomorrow.map(enrich),
|
||||
};
|
||||
|
||||
return new Response(JSON.stringify(body), {
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=utf-8',
|
||||
'Cache-Control': 'public, max-age=300',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
return new Response(
|
||||
JSON.stringify({ error: 'fetch_failed', detail: (e as Error).message }),
|
||||
{ status: 502, headers: { 'Content-Type': 'application/json' } },
|
||||
);
|
||||
}
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue