Build MVP with Pi installer and atomic updates
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
export type User = { id: number; username: string; role: "admin" };
|
||||
|
||||
export type AuthState = {
|
||||
setupRequired: boolean;
|
||||
user: User | null;
|
||||
csrfToken: string;
|
||||
};
|
||||
|
||||
export type Availability<T> =
|
||||
| { available: true; value: T }
|
||||
| { available: false; reason: string };
|
||||
|
||||
export type SystemStatus = {
|
||||
collectedAt: string;
|
||||
hostname: string;
|
||||
uptimeSeconds: number;
|
||||
operatingSystem: string;
|
||||
cpu: {
|
||||
model: string;
|
||||
loadAverage: number[];
|
||||
temperatureCelsius: Availability<number>;
|
||||
};
|
||||
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<string>;
|
||||
};
|
||||
service: { state: "healthy"; processUptimeSeconds: number };
|
||||
};
|
||||
|
||||
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<T>(response: Response): Promise<T> {
|
||||
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<AuthState> {
|
||||
return parseResponse<AuthState>(await fetch("/api/auth/state", { credentials: "same-origin" }));
|
||||
}
|
||||
|
||||
export async function post<T>(path: string, body: unknown, csrfToken: string): Promise<T> {
|
||||
return parseResponse<T>(
|
||||
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<SystemStatus> {
|
||||
return parseResponse<SystemStatus>(await fetch("/api/status", { credentials: "same-origin" }));
|
||||
}
|
||||
|
||||
export async function getUpdateStatus(): Promise<UpdateStatus> {
|
||||
return parseResponse<UpdateStatus>(await fetch("/api/system/update", { credentials: "same-origin" }));
|
||||
}
|
||||
Reference in New Issue
Block a user