import { EmailMessage } from "cloudflare:email";
import { initialState, step, needsTimeline, composeMessage } from "./logic.js";
const FORGE = "https://zeitforge.app";
const TIMEOUT_MS = 10_000;
const STATE_KEY = "state";
async function get(url) {
try {
return await fetch(url, { signal: AbortSignal.timeout(TIMEOUT_MS), redirect: "manual" });
} catch (err) {
return { error: String(err && err.message ? err.message : err) };
}
}
async function checkHealth() {
const res = await get(`${FORGE}/api/v1/version`);
if (res.error) return { status: null, ready: false, error: res.error };
let j = {};
try {
j = await res.json();
} catch {}
return { status: res.status, ready: j.ready === true, version: j.version, node: j.node };
}
async function checkTimeline() {
const res = await get(`${FORGE}/r/quarry/timeline`);
if (res.error) return 599;
await res.body?.cancel();
return res.status;
}
async function loadState(env) {
const raw = await env.PROBE_STATE.get(STATE_KEY, "json");
return raw || initialState();
}
async function send(env, action, state) {
const { subject, body } = composeMessage(action, state, FORGE);
const raw = [
`From: ${env.ALERT_FROM}`,
`To: ${env.ALERT_TO}`,
`Subject: ${subject}`,
`Date: ${new Date().toUTCString()}`,
`Message-ID: <${crypto.randomUUID()}@${env.ALERT_FROM.split("@")[1]}>`,
"MIME-Version: 1.0",
"Content-Type: text/plain; charset=utf-8",
"",
body,
].join("\r\n");
await env.ALERT_EMAIL.send(new EmailMessage(env.ALERT_FROM, env.ALERT_TO, raw));
}
async function probe(env) {
const now = Date.now();
const prev = await loadState(env);
const health = await checkHealth();
const timelineStatus = needsTimeline(health) ? await checkTimeline() : null;
const { state, actions } = step(prev, { health, timelineStatus }, now);
// Persist before sending so a mail failure retries neither as a duplicate nor forever.
await env.PROBE_STATE.put(STATE_KEY, JSON.stringify(state));
for (const a of actions) await send(env, a, state);
return state;
}
export default {
async scheduled(_event, env, ctx) {
ctx.waitUntil(probe(env));
},
async fetch(_req, env) {
return Response.json(await loadState(env));
},
};