import type { SourceModule } from "../registry"; import { UptimeConfig, UptimePayload, type UptimeConfig as Config, type UptimePayload as Payload, } from "@/lib/schemas/sources/uptime"; const TIMEOUT_MS = 8000; async function ping(url: string, parentSignal?: AbortSignal): Promise { const target = /^https?:\/\//.test(url) ? url : `https://${url}`; const ctrl = new AbortController(); const timer = setTimeout(() => ctrl.abort(), TIMEOUT_MS); const onAbort = () => ctrl.abort(); parentSignal?.addEventListener("abort", onAbort); const started = Date.now(); try { const res = await fetch(target, { method: "GET", redirect: "follow", signal: ctrl.signal }); return { url, ok: res.ok, status: res.status, ms: Date.now() - started }; } catch { return { url, ok: false, status: null, ms: null }; } finally { clearTimeout(timer); parentSignal?.removeEventListener("abort", onAbort); } } export const uptimeModule: SourceModule = { kind: "uptime", label: "Uptime", keyless: true, defaultRefreshSeconds: 600, configSchema: UptimeConfig, payloadSchema: UptimePayload, isConfigured: (config) => config.urls.length > 0, async fetch({ config, signal }) { const sites = await Promise.all(config.urls.map((u) => ping(u.trim(), signal))); return { sites }; }, };