103 lines
3.1 KiB
TypeScript
103 lines
3.1 KiB
TypeScript
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<Agent[]> {
|
|
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<CheckState[]> {
|
|
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<InventoryData> {
|
|
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<Agent[]> {
|
|
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<OverviewData> {
|
|
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<string, number> {
|
|
return xs.reduce<Record<string, number>>((acc, x) => {
|
|
const k = x.status ?? "unknown";
|
|
acc[k] = (acc[k] ?? 0) + 1;
|
|
return acc;
|
|
}, {});
|
|
}
|