fix+perf: corrections de revue (currentEcheance, dayOfYear, SWR, last-good, doc apikey)

- vigilance: currentEcheance basée sur productDatetime (jour calme renvoyait J1 à tort)
- normales: dayOfYear extrait en Europe/Paris pour 'now' (UTC mélangeait les jours après minuit)
- meteofrance-auth + CLAUDE.md: header `apikey:` documenté correctement (pas Authorization Bearer)
- cache: SWR — envelope {v, fu}, hard TTL = ttl*6, refresh background avec lock anti-stampede
- vigilance: snapshot last-good (TTL 30j) écrit à chaque fetch, fallback final si MF+ODS KO
- vigilance: nettoyage variable url morte dans fetchOpendatasoft

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Florian 2026-05-26 18:58:03 +02:00
parent e72f25b33d
commit 290f9be7b9
5 changed files with 201 additions and 45 deletions

View file

@ -27,12 +27,19 @@ export interface DailyNormale {
}
// Day-of-year en convention "leap calendar" (1..366), aligné sur le calendrier bissextile.
// Les années non-bissextiles : on bascule simplement le 1er mars au doy 60 si pas 29 fév.
// Mais pour matcher l'indexation du JSON (1..366), on utilise une convention stable.
// Extraction Y/M/D en Europe/Paris pour rester cohérent avec :
// - les pages SSR qui formatent en Europe/Paris (todayLabel, productDate),
// - les obs climato YYYY-MM-DD (parsées en UTC midnight, donc Paris == J ou J-1
// selon offset DST, mais ça représente toujours la "journée Paris" du jour
// suivant — assez proche pour le lookup normale).
// - `new Date()` (now) : en UTC, getUTC* renvoie hier entre 00h et 01h/02h Paris.
// Toujours utiliser le jour Paris-local.
export function dayOfYear(date: Date): number {
const y = date.getUTCFullYear();
const m = date.getUTCMonth() + 1;
const d = date.getUTCDate();
// sv-SE → format "YYYY-MM-DD"
const iso = date.toLocaleDateString('sv-SE', { timeZone: 'Europe/Paris' });
const y = parseInt(iso.slice(0, 4), 10);
const m = parseInt(iso.slice(5, 7), 10);
const d = parseInt(iso.slice(8, 10), 10);
const cumulNonLeap = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];
const cumulLeap = [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335];
const isLeap = (y % 4 === 0 && y % 100 !== 0) || (y % 400 === 0);