amana / frontend /src /api.ts
Misbahuddin's picture
Deploy-readiness: Neon persistence, moderator identity, run telemetry, warm redesign
8e98f03
Raw
History Blame Contribute Delete
1.44 kB
import type {
Campaign,
CampaignSummary,
DecisionRecord,
GatedResult,
PolicySection,
Stats,
} from "./types";
async function j<T>(r: Response): Promise<T> {
if (!r.ok) {
const body = await r.json().catch(() => ({ detail: r.statusText }));
throw new Error(typeof body.detail === "string" ? body.detail : `HTTP ${r.status}`);
}
return r.json() as Promise<T>;
}
const post = (url: string, payload: unknown) =>
fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
});
export const getStats = () => fetch("/api/stats").then((r) => j<Stats>(r));
export const getCampaigns = () => fetch("/api/campaigns").then((r) => j<CampaignSummary[]>(r));
export const getCampaign = (id: string) => fetch(`/api/campaigns/${id}`).then((r) => j<Campaign>(r));
export const getDecisions = () => fetch("/api/decisions").then((r) => j<DecisionRecord[]>(r));
export const getPolicy = () => fetch("/api/policy").then((r) => j<PolicySection[]>(r));
export const runTriage = (campaign_id: string, provider: string, force = false) =>
post("/api/triage", { campaign_id, provider, force }).then((r) => j<GatedResult>(r));
export const postDecision = (
campaign_id: string,
human_decision: string,
moderator: string,
reason: string,
) =>
post("/api/decisions", { campaign_id, human_decision, moderator, reason }).then((r) =>
j<DecisionRecord>(r),
);