export function fmtBytes(n?: number | null, digits = 1): string { if (n == null || isNaN(n)) return "—"; const units = ["B", "KB", "MB", "GB", "TB"]; let i = 0; let v = n; while (v >= 1024 && i < units.length - 1) { v /= 1024; i++; } return `${v.toFixed(i === 0 ? 0 : digits)} ${units[i]}`; } export function fmtGB(n?: number | null, digits = 1): string { if (n == null || isNaN(n)) return "—"; return `${n.toFixed(digits)} GB`; } export function fmtParams(n?: number | null): string { if (!n) return "—"; if (n >= 1e12) return `${(n / 1e12).toFixed(1)}T`; if (n >= 1e9) return `${(n / 1e9).toFixed(n >= 1e10 ? 0 : 1)}B`; if (n >= 1e6) return `${(n / 1e6).toFixed(0)}M`; return String(n); } export function fmtCtx(n?: number | null): string { if (!n) return "—"; if (n >= 1024) return `${Math.round(n / 1024)}K`; return String(n); } export function fmtMs(n?: number | null): string { if (n == null || isNaN(n)) return "—"; if (n >= 60000) return `${(n / 60000).toFixed(1)} min`; if (n >= 1000) return `${(n / 1000).toFixed(n >= 10000 ? 0 : 1)} s`; return `${Math.round(n)} ms`; } export function fmtNum(n?: number | null, digits = 0): string { if (n == null || isNaN(n)) return "—"; return n.toLocaleString("en-US", { maximumFractionDigits: digits, minimumFractionDigits: digits }); } export function fmtDate(ts?: number | string | null): string { if (!ts) return "—"; const d = typeof ts === "number" ? new Date(ts * 1000) : new Date(ts); if (isNaN(d.getTime())) return "—"; return d.toLocaleString("en-CA", { dateStyle: "medium", timeStyle: "short" }); } export function fmtAgo(ts?: number | null): string { if (!ts) return "never"; const s = Math.max(0, Date.now() / 1000 - ts); if (s < 60) return `${Math.round(s)}s ago`; if (s < 3600) return `${Math.round(s / 60)} min ago`; if (s < 86400) return `${Math.round(s / 3600)} h ago`; return `${Math.round(s / 86400)} d ago`; } export function fmtDuration(s?: number | null): string { if (s == null) return "—"; const d = Math.floor(s / 86400); const h = Math.floor((s % 86400) / 3600); const m = Math.floor((s % 3600) / 60); if (d) return `${d}d ${h}h`; if (h) return `${h}h ${m}m`; return `${m}m ${Math.floor(s % 60)}s`; } export function fmtSpeed(bps?: number | null): string { if (!bps) return "—"; return `${fmtBytes(bps)}/s`; }