import "server-only"; import { ApiError, api, type Agent, type CheckState, type StoredEvent } from "@/lib/api"; import type { components } from "@/lib/api-types"; import { LIVENESS_CHECK_ID, withLivenessChecks, withLivenessEvents } from "@/lib/check-groups"; import type { InventoryData, OverviewData } from "@/lib/view-types"; type Incident = components["schemas"]["Incident"]; export async function loadAgents(): Promise { const agents: Agent[] = []; let cursor: string | undefined; do { const page = await api.listAgents({ cursor, limit: 500 }); agents.push(...page.items); cursor = page.next_cursor ?? undefined; } while (cursor); return agents; } export async function loadChecks(agentId?: string): Promise { const checks: CheckState[] = []; let cursor: string | undefined; do { const page = await api.listChecks({ agent_id: agentId, cursor, limit: 500 }); checks.push(...page.items); cursor = page.next_cursor ?? undefined; } while (cursor); return checks; } export async function loadInventory(): Promise { const [agents, checks] = await Promise.all([loadAgents(), loadChecks()]); return { agents, checks: withLivenessChecks(agents, checks) }; } export async function loadEventsWithLiveness({ agentId, checkId, cursor, limit, }: { agentId?: string; checkId?: string; cursor?: string; limit?: number; } = {}): Promise<{ items: StoredEvent[]; next_cursor?: string | null }> { const data = await api.queryEvents({ agent_id: agentId, check_id: checkId, cursor, limit }); if (cursor || (checkId && checkId !== LIVENESS_CHECK_ID)) return data; const agents = agentId ? await loadOptionalAgent(agentId) : await loadAgents(); return { ...data, items: withLivenessEvents(agents, data.items, { agentId, checkId, cursor }), }; } async function loadOptionalAgent(agentId: string): Promise { try { return [await api.getAgent(agentId)]; } catch (e) { if (e instanceof ApiError && e.status === 404) return []; throw e; } } export async function loadIncidents( state?: "open" | "resolved", ): Promise<{ items: Incident[] }> { const items: Incident[] = []; let cursor: string | undefined; do { const page = await api.listIncidents({ state, cursor, limit: 500 }); items.push(...page.items); cursor = page.next_cursor ?? undefined; } while (cursor); return { items }; } export async function loadOverview(): Promise { const [agents, checks, incidents] = await Promise.all([ loadAgents(), loadChecks(), api.listIncidents({ state: "open", limit: 500 }), ]); const checksWithLiveness = withLivenessChecks(agents, checks); return { agents: tally(agents), checks: tally(checksWithLiveness), openIncidents: incidents.items.length, totalAgents: agents.length, totalChecks: checksWithLiveness.length, }; } function tally(xs: { status?: string }[]): Record { return xs.reduce>((acc, x) => { const k = x.status ?? "unknown"; acc[k] = (acc[k] ?? 0) + 1; return acc; }, {}); }