Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
import { type Check } from "./monitor_check_status.ts"; ← from monitor.check-status ^1.0.0 · built alongside by fune
import { type UptimeReport } from "./monitor_uptime_types.ts";
/**
* Seconds up, degraded, down and unknown over [from, to). Each check's status
* holds from its `at` until the next check, but for at most maxGapSeconds: a
* monitor that stopped reporting has not proved the target was up.
*/
export function uptime(checks: readonly Check[], from: number, to: number, maxGapSeconds: number): UptimeReport {
if (!Number.isSafeInteger(from) || !Number.isSafeInteger(to)) throw new RangeError("from and to must be whole seconds");
if (from > to) throw new RangeError(`from must not be after to: ${from} > ${to}`);
if (!Number.isSafeInteger(maxGapSeconds) || maxGapSeconds < 1) {
throw new RangeError(`maxGapSeconds must be a whole number of at least 1, received ${maxGapSeconds}`);
}
let up = 0;
let degraded = 0;
let down = 0;
let count = 0;
let downCount = 0;
for (let i = 0; i < checks.length; i++) {
const c = checks[i];
if (c.status !== "up" && c.status !== "degraded" && c.status !== "down") {
throw new RangeError(`unknown check status: ${String(c.status)}`);
}
if (i > 0 && c.at <= checks[i - 1].at) {
throw new RangeError(`checks must be in strictly ascending time order: ${c.at} follows ${checks[i - 1].at}`);
}
if (c.at >= from && c.at < to) {
count += 1;
if (c.status === "down") downCount += 1;
}
// The span this check vouches for, clipped to the window.
let end = c.at + maxGapSeconds;
if (i + 1 < checks.length && checks[i + 1].at < end) end = checks[i + 1].at;
const s = Math.max(c.at, from);
const e = Math.min(end, to);
if (e > s) {
if (c.status === "up") up += e - s;
else if (c.status === "degraded") degraded += e - s;
else down += e - s;
}
}
const known = up + degraded + down;
// Floored in BigInt: never 100.00% while a down second exists, and exact
// for windows whose seconds times 10000 pass 2^53.
const uptimeBasisPoints = known === 0 ? null : Number((BigInt(up + degraded) * 10000n) / BigInt(known));
return {
upSeconds: up,
degradedSeconds: degraded,
downSeconds: down,
unknownSeconds: to - from - known,
uptimeBasisPoints,
checks: count,
downChecks: downCount,
};
}