diff --git a/src/index.ts b/src/index.ts index 1110ed5..6f1791e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -184,12 +184,37 @@ async function fetchJson(url: string): Promise { return (await response.json()) as T; } +async function fetchStatusPage(): Promise { + const response = await fetch(CLOUDFLARE_STATUS_URL, { + headers: { accept: "text/html", "user-agent": "cloudflare-status-dday/1.0" }, + signal: AbortSignal.timeout(10_000), + }); + if (!response.ok) throw new Error(`Cloudflare status page returned ${response.status}`); + return await response.text(); +} + +function parseStatusPage(html: string): { indicator: PageIndicator; description: string } | null { + const heading = html.match(/]*>\s*([^<]+?)\s*<\/h2>/i)?.[1]?.trim(); + if (!heading) return null; + + const statuses: Record = { + "All systems operational": { indicator: "none", description: "All systems operational" }, + "Minor Service Outage": { indicator: "minor", description: "Minor Service Outage" }, + "Partial System Outage": { indicator: "major", description: "Partial System Outage" }, + "Major System Outage": { indicator: "critical", description: "Major System Outage" }, + }; + + return statuses[heading] ?? null; +} + async function refreshStatus(source: "startup" | "cron") { try { - const [summary, incidentsResponse] = await Promise.all([ + const [summary, incidentsResponse, statusPage] = await Promise.all([ fetchJson(`${CLOUDFLARE_API_URL}/summary.json`), fetchJson(`${CLOUDFLARE_API_URL}/incidents.json`), + fetchStatusPage().catch(() => null), ]); + const pageStatus = statusPage ? parseStatusPage(statusPage) : null; const incidentsById = new Map(); for (const incident of [ @@ -227,8 +252,9 @@ async function refreshStatus(source: "startup" | "cron") { fetchedAt: now, pageUpdatedAt: summary.page?.updated_at ?? null, status: { - indicator: indicator(summary.status?.indicator), - description: summary.status?.description ?? "Status information is unavailable", + indicator: pageStatus?.indicator ?? indicator(summary.status?.indicator), + description: + pageStatus?.description ?? summary.status?.description ?? "Status information is unavailable", }, streak: { days: daysSince(latestIncident?.started_at ?? latestIncident?.created_at ?? null),