Files
HexaHost-GameCloud/apps/web/src/lib/api/admin.ts

144 lines
3.9 KiB
TypeScript

import { apiFetch } from "./auth";
export interface AdminDashboardStats {
activeUsers: number;
totalServers: number;
runningServers: number;
queueLength: number;
onlineNodes: number;
failedJobs24h: number;
openAbuseReports: number;
openTickets: number;
generatedAt: string;
}
export interface AdminUser {
id: string;
email: string;
username: string;
displayName: string | null;
status: string;
roles: string[];
twoFactorEnabled: boolean;
sessionCount: number;
serverCount: number;
createdAt: string;
}
export interface AdminJob {
id: string;
queue: string;
jobName: string;
status: string;
attempts: number;
error: string | null;
startedAt: string | null;
completedAt: string | null;
createdAt: string;
}
export interface AdminAuditEvent {
id: string;
action: string;
entityType: string | null;
entityId: string | null;
metadata: unknown;
ipAddress: string | null;
createdAt: string;
user: { id: string; email: string; username: string } | null;
}
export interface GameNodeSummary {
id: string;
name: string;
hostname: string;
status: string;
maxServers: number;
maxRamMb: number;
platformRamMb: number;
activeServers: number;
reservedRamMb: number;
availableRamMb: number;
lastHeartbeatAt: string | null;
agentVersion: string | null;
drainRequestedAt: string | null;
createdAt: string;
}
export async function getAdminDashboardStats(): Promise<AdminDashboardStats> {
return apiFetch<AdminDashboardStats>("/admin/dashboard");
}
export async function listAdminNodes(): Promise<{ nodes: GameNodeSummary[] }> {
return apiFetch<{ nodes: GameNodeSummary[] }>("/admin/nodes");
}
export async function drainAdminNode(nodeId: string): Promise<GameNodeSummary> {
return apiFetch<GameNodeSummary>(`/admin/nodes/${nodeId}/drain`, {
method: "POST",
});
}
export async function setAdminNodeMaintenance(
nodeId: string,
enabled: boolean,
): Promise<GameNodeSummary> {
return apiFetch<GameNodeSummary>(`/admin/nodes/${nodeId}/maintenance`, {
method: "POST",
body: JSON.stringify({ enabled }),
});
}
export async function searchAdminUsers(params?: {
q?: string;
limit?: number;
}): Promise<{ users: AdminUser[] }> {
const search = new URLSearchParams();
if (params?.q) search.set("q", params.q);
if (params?.limit) search.set("limit", String(params.limit));
const query = search.toString();
return apiFetch<{ users: AdminUser[] }>(
`/admin/users${query ? `?${query}` : ""}`,
);
}
export async function suspendAdminUser(userId: string): Promise<{ id: string; status: string }> {
return apiFetch<{ id: string; status: string }>(`/admin/users/${userId}/suspend`, {
method: "POST",
});
}
export async function unsuspendAdminUser(userId: string): Promise<{ id: string; status: string }> {
return apiFetch<{ id: string; status: string }>(`/admin/users/${userId}/unsuspend`, {
method: "POST",
});
}
export async function listAdminJobs(params?: {
limit?: number;
status?: string;
queue?: string;
}): Promise<{ jobs: AdminJob[] }> {
const search = new URLSearchParams();
if (params?.limit) search.set("limit", String(params.limit));
if (params?.status) search.set("status", params.status);
if (params?.queue) search.set("queue", params.queue);
const query = search.toString();
return apiFetch<{ jobs: AdminJob[] }>(`/admin/jobs${query ? `?${query}` : ""}`);
}
export async function listAdminAuditEvents(params?: {
limit?: number;
cursor?: string;
action?: string;
}): Promise<{ items: AdminAuditEvent[]; nextCursor: string | null }> {
const search = new URLSearchParams();
if (params?.limit) search.set("limit", String(params.limit));
if (params?.cursor) search.set("cursor", params.cursor);
if (params?.action) search.set("action", params.action);
const query = search.toString();
return apiFetch<{ items: AdminAuditEvent[]; nextCursor: string | null }>(
`/admin/audit${query ? `?${query}` : ""}`,
);
}