feat: read raw iCalendar feed via browser session

Isolated CalDAV transport module that reuses the browser's Nextcloud
session (cookies, no stored password). Returns a discriminated result
and detects the HTTP-200 login-page redirect by sniffing the body for
BEGIN:VCALENDAR. compterEvenements counts real VEVENT line starts as the
T1 proof of life.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Pierre Martin
2026-06-30 00:07:43 +02:00
co-authored by Claude Opus 4.8
parent 4889a9931a
commit 1432aba561
2 changed files with 123 additions and 0 deletions
+38
View File
@@ -0,0 +1,38 @@
// Transport CalDAV isolé : récupère le flux iCalendar brut du calendrier
// Nextcloud de l'Atelier du Huit en réutilisant la session du navigateur
// (cookies). Aucun mot de passe stocké. Le module reste pur de toute
// présentation : il renvoie un *type* d'erreur, pas un message.
export const URL_CALENDRIER =
"https://atelier-huit.frama.space/remote.php/dav/calendars/Pierre/latelier-du-huit-sbastien_shared_by_admin/?export";
// fetchImpl est injecté (obligatoire) pour la testabilité.
// Résultat discriminé : { ok:true, flux } | { ok:false, erreur }.
export async function recupererFluxCalendrier(fetchImpl) {
let reponse;
try {
reponse = await fetchImpl(URL_CALENDRIER, { credentials: "include" });
} catch {
return { ok: false, erreur: "reseau" };
}
if (reponse.status === 401 || reponse.status === 403) {
return { ok: false, erreur: "non-connecte" };
}
if (!reponse.ok) {
return { ok: false, erreur: "serveur" };
}
const flux = await reponse.text();
// Piège central : une redirection vers la page de login renvoie un 200 HTML.
if (!flux.trimStart().startsWith("BEGIN:VCALENDAR")) {
return { ok: false, erreur: "non-connecte" };
}
return { ok: true, flux };
}
// Preuve de vie de T1 : compte les vrais débuts de VEVENT (ancrage ligne, pas
// une chaîne « BEGIN:VEVENT » apparaissant dans une DESCRIPTION).
export function compterEvenements(flux) {
return (flux.match(/^BEGIN:VEVENT\s*$/gm) ?? []).length;
}