export type User = { id: number; username: string; role: "admin" }; export type AuthState = { setupRequired: boolean; user: User | null; csrfToken: string; }; export type Availability = | { available: true; value: T } | { available: false; reason: string }; export type HeadUnitStatus = | { available: true; value: { state: "connected"; identity: { manufacturer: Availability; model: Availability; androidVersion: Availability; apiLevel: Availability; buildId: Availability; abi: Availability; }; display: { size: Availability<{ widthPixels: number; heightPixels: number }>; densityDpi: Availability; }; }; } | { available: false; state: "disabled" | "unavailable" | "offline" | "unauthorized" | "ambiguous"; reason: string; }; export type SystemStatus = { collectedAt: string; hostname: string; uptimeSeconds: number; operatingSystem: string; cpu: { model: string; loadAverage: number[]; temperatureCelsius: Availability; }; memory: { totalBytes: number; usedBytes: number; availableBytes: number }; disk: Availability<{ totalBytes: number; usedBytes: number; availableBytes: number; mount: string }>; network: { interfaces: Array<{ name: string; address: string; family: string }>; interfaceReason: string | null; wifi: Availability; }; service: { state: "healthy"; processUptimeSeconds: number }; headUnit: HeadUnitStatus; }; export type UpdateStatus = { state: "idle" | "checking" | "building" | "current" | "success" | "failed"; message: string; fromRevision: string | null; toRevision: string | null; updatedAt: string; installedRevision: string | null; supported: boolean; }; type ErrorResponse = { error?: { code?: string; message?: string } }; export class ApiError extends Error { constructor( message: string, public readonly status: number, public readonly code: string ) { super(message); } } async function parseResponse(response: Response): Promise { const data = (await response.json().catch(() => ({}))) as T & ErrorResponse; if (!response.ok) { throw new ApiError(data.error?.message ?? "The request failed", response.status, data.error?.code ?? "REQUEST_FAILED"); } return data; } export async function getAuthState(): Promise { return parseResponse(await fetch("/api/auth/state", { credentials: "same-origin" })); } export async function post(path: string, body: unknown, csrfToken: string): Promise { return parseResponse( await fetch(path, { method: "POST", credentials: "same-origin", headers: { "Content-Type": "application/json", "X-CSRF-Token": csrfToken }, body: JSON.stringify(body) }) ); } export async function getStatus(): Promise { return parseResponse(await fetch("/api/status", { credentials: "same-origin" })); } export async function getUpdateStatus(): Promise { return parseResponse(await fetch("/api/system/update", { credentials: "same-origin" })); }