1export function fmtBytes(n?: number | null, digits = 1): string {2 if (n == null || isNaN(n)) return "—";3 const units = ["B", "KB", "MB", "GB", "TB"];4 let i = 0;5 let v = n;6 while (v >= 1024 && i < units.length - 1) {7 v /= 1024;8 i++;9 }10 return `${v.toFixed(i === 0 ? 0 : digits)} ${units[i]}`;11}1213export function fmtGB(n?: number | null, digits = 1): string {14 if (n == null || isNaN(n)) return "—";15 return `${n.toFixed(digits)} GB`;16}1718export function fmtParams(n?: number | null): string {19 if (!n) return "—";20 if (n >= 1e12) return `${(n / 1e12).toFixed(1)}T`;21 if (n >= 1e9) return `${(n / 1e9).toFixed(n >= 1e10 ? 0 : 1)}B`;22 if (n >= 1e6) return `${(n / 1e6).toFixed(0)}M`;23 return String(n);24}2526export function fmtCtx(n?: number | null): string {27 if (!n) return "—";28 if (n >= 1024) return `${Math.round(n / 1024)}K`;29 return String(n);30}3132export function fmtMs(n?: number | null): string {33 if (n == null || isNaN(n)) return "—";34 if (n >= 60000) return `${(n / 60000).toFixed(1)} min`;35 if (n >= 1000) return `${(n / 1000).toFixed(n >= 10000 ? 0 : 1)} s`;36 return `${Math.round(n)} ms`;37}3839export function fmtNum(n?: number | null, digits = 0): string {40 if (n == null || isNaN(n)) return "—";41 return n.toLocaleString("en-US", { maximumFractionDigits: digits, minimumFractionDigits: digits });42}4344export function fmtDate(ts?: number | string | null): string {45 if (!ts) return "—";46 const d = typeof ts === "number" ? new Date(ts * 1000) : new Date(ts);47 if (isNaN(d.getTime())) return "—";48 return d.toLocaleString("en-CA", { dateStyle: "medium", timeStyle: "short" });49}5051export function fmtAgo(ts?: number | null): string {52 if (!ts) return "never";53 const s = Math.max(0, Date.now() / 1000 - ts);54 if (s < 60) return `${Math.round(s)}s ago`;55 if (s < 3600) return `${Math.round(s / 60)} min ago`;56 if (s < 86400) return `${Math.round(s / 3600)} h ago`;57 return `${Math.round(s / 86400)} d ago`;58}5960export function fmtDuration(s?: number | null): string {61 if (s == null) return "—";62 const d = Math.floor(s / 86400);63 const h = Math.floor((s % 86400) / 3600);64 const m = Math.floor((s % 3600) / 60);65 if (d) return `${d}d ${h}h`;66 if (h) return `${h}h ${m}m`;67 return `${m}m ${Math.floor(s % 60)}s`;68}6970export function fmtSpeed(bps?: number | null): string {71 if (!bps) return "—";72 return `${fmtBytes(bps)}/s`;73}74