first commit
Agent Release / build (push) Has been cancelled
Server Deploy / deploy (push) Has been cancelled

This commit is contained in:
domrichardson
2026-06-15 13:58:45 +01:00
commit c9868b2108
55 changed files with 11076 additions and 0 deletions
+137
View File
@@ -0,0 +1,137 @@
export type ServerStatus = "pending" | "active" | "offline";
export type KeySource = "uploaded" | "generated";
export interface Server {
id: string;
server_id: string;
hostname: string;
ip_address: string;
os_info: string;
status: ServerStatus;
last_seen: string;
created_at: string;
}
export interface Key {
id: string;
key_id: string;
label: string;
public_key: string;
fingerprint: string;
source: KeySource;
generated_by_server_id?: string;
created_at: string;
assigned_count?: number;
}
export interface Assignment {
id: string;
key_id: string;
server_id: string;
assigned_at: string;
revoked_at: string | null;
}
export interface NewServerResponse {
server_id: string;
pre_reg_token: string;
install_command: string;
}
export interface KeyWithAssignments extends Key {
assignments: (Assignment & { server: Server })[];
}
export interface ServerWithKeys extends Server {
keys: (Assignment & { key: Key })[];
}
class ApiError extends Error {
constructor(
public status: number,
message: string
) {
super(message);
this.name = "ApiError";
}
}
async function request<T>(path: string, options?: RequestInit): Promise<T> {
const res = await fetch(`/api${path}`, {
headers: {
"Content-Type": "application/json",
...options?.headers,
},
...options,
});
if (!res.ok) {
const text = await res.text().catch(() => res.statusText);
throw new ApiError(res.status, text || `HTTP ${res.status}`);
}
if (res.status === 204) {
return undefined as T;
}
return res.json();
}
export const api = {
// Servers
listServers(): Promise<Server[]> {
return request<Server[]>("/servers");
},
getServer(serverId: string): Promise<ServerWithKeys> {
return request<ServerWithKeys>(`/servers/${serverId}`);
},
createServer(): Promise<NewServerResponse> {
return request<NewServerResponse>("/servers/new", { method: "POST" });
},
deleteServer(serverId: string): Promise<void> {
return request<void>(`/servers/${serverId}`, { method: "DELETE" });
},
generateKeyForServer(serverId: string): Promise<{ key_id: string }> {
return request<{ key_id: string }>(`/servers/${serverId}/generate-key`, {
method: "POST",
});
},
// Keys
listKeys(): Promise<Key[]> {
return request<Key[]>("/keys");
},
getKey(keyId: string): Promise<KeyWithAssignments> {
return request<KeyWithAssignments>(`/keys/${keyId}`);
},
uploadKey(label: string, public_key: string): Promise<Key> {
return request<Key>("/keys", {
method: "POST",
body: JSON.stringify({ label, public_key }),
});
},
deleteKey(keyId: string): Promise<void> {
return request<void>(`/keys/${keyId}`, { method: "DELETE" });
},
// Assignments
assignKey(keyId: string, serverId: string): Promise<Assignment> {
return request<Assignment>(`/keys/${keyId}/assign`, {
method: "POST",
body: JSON.stringify({ server_id: serverId }),
});
},
revokeKey(keyId: string, serverId: string): Promise<void> {
return request<void>(`/keys/${keyId}/assign/${serverId}`, {
method: "DELETE",
});
},
};