// Thin fetch wrappers around /api/v2/*. Kept minimal — no state // library; each page owns its own useEffect + useState. // API base: // * dev (vite proxy) → '/api' // * prod local → '/api' (SPA at :7700/v2/, API at :7700/api/) // * prod via Tailscale → '/clawstor/api' (SPA at /clawstor, API at /clawstor/api) // // Detect at load time by checking the current URL's pathname // prefix. Cheap + no build-time coupling. const API_BASE = (() => { if (typeof window === 'undefined') return '/api'; const p = window.location.pathname; if (p.startsWith('/clawstor/') || p === '/clawstor') return '/clawstor/api'; return '/api'; })(); async function get(path) { const full = `${API_BASE}${path}`; const resp = await fetch(full, { headers: { Accept: 'application/json' } }); if (!resp.ok) { throw new Error(`${full} → ${resp.status} ${resp.statusText}`); } return resp.json(); } export const api = { fleet: () => get('/v2/fleet'), projects: () => get('/v2/projects'), nodeStatus: (name) => get(`/v2/node/${name}/status`), blobs: (limit = 200, offset = 0) => get(`/v2/storage/blobs?limit=${limit}&offset=${offset}`), tags: (prefix = '') => get(`/v2/storage/tags?prefix=${encodeURIComponent(prefix)}`), refs: (limit = 200, offset = 0) => get(`/v2/storage/refs?limit=${limit}&offset=${offset}`), snapshots: () => get('/v2/storage/snapshots'), refTracking: (repo = '') => get(`/v2/storage/ref-tracking?repo=${encodeURIComponent(repo)}`), }; /** Format bytes as MB / GB / TB as needed. */ export function fmtBytes(n) { if (n < 1024) return `${n} B`; if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KiB`; if (n < 1024 * 1024 * 1024) return `${(n / (1024 * 1024)).toFixed(1)} MiB`; if (n < 1024 * 1024 * 1024 * 1024) return `${(n / (1024 * 1024 * 1024)).toFixed(1)} GiB`; return `${(n / (1024 * 1024 * 1024 * 1024)).toFixed(2)} TiB`; } /** Human-friendly relative time. */ export function fmtAge(unix) { const now = Math.floor(Date.now() / 1000); const diff = now - unix; if (diff < 60) return `${diff}s ago`; if (diff < 3600) return `${Math.floor(diff / 60)}m ago`; if (diff < 86400) return `${Math.floor(diff / 3600)}h ago`; return `${Math.floor(diff / 86400)}d ago`; }