Files
braceiqmed/frontend/src/lib/api.ts

108 lines
2.8 KiB
TypeScript

const API_BASE = 'https://cfx9z50wj2.execute-api.ca-central-1.amazonaws.com/prod';
async function http<T>(path: string, init?: RequestInit): Promise<T> {
const base = API_BASE ? API_BASE.replace(/\/+$/, '') : '';
const normalizedPath = path.startsWith('/') ? path : `/${path}`;
const url = `${base}${normalizedPath}`;
const res = await fetch(url, {
...init,
headers: {
"Content-Type": "application/json",
...(init?.headers || {})
}
});
if (!res.ok) {
const text = await res.text().catch(() => "");
throw new Error(`HTTP ${res.status} ${res.statusText}: ${text}`);
}
return (await res.json()) as T;
}
export type CaseStatus = {
case: {
case_id: string;
status: string;
current_step: string | null;
created_at: string;
updated_at: string;
};
steps: Array<{
step_name: string;
step_order: number;
status: string;
started_at: string | null;
finished_at: string | null;
error_message: string | null;
}>;
};
export type CaseAssets = {
caseId: string;
apImageUrl: string;
bucket?: string;
key?: string;
};
export type SubmitLandmarksRequest = {
// Backend Lambda requires caseId in body (even though it's also in the URL)
caseId?: string;
view: "ap";
landmarks: Record<string, { x: number; y: number }>;
};
export type SubmitLandmarksResponse = {
ok: boolean;
caseId: string;
resumedPipeline: boolean;
values: {
pelvis_offset_px: number;
t1_offset_px: number;
tp_offset_px: number;
dominant_curve: string;
};
};
export type UploadUrlResponse = {
uploadUrl: string;
key?: string;
s3Key?: string;
};
export const api = {
createCase: (body: { notes?: string } = {}) =>
http<{ caseId: string }>(`/cases`, {
method: "POST",
body: JSON.stringify(body),
}),
startCase: (caseId: string) =>
http<{ caseId: string; executionArn?: string; status?: string }>(
`/cases/${encodeURIComponent(caseId)}/start`,
{
method: "POST",
body: JSON.stringify({}),
}
),
getUploadUrl: (caseId: string, body: { view: string; contentType?: string; filename?: string }) =>
http<UploadUrlResponse>(`/cases/${encodeURIComponent(caseId)}/upload-url`, {
method: "POST",
body: JSON.stringify(body),
}),
getCaseStatus: (caseId: string) => http<CaseStatus>(`/cases/${encodeURIComponent(caseId)}`),
getCaseAssets: (caseId: string) => http<CaseAssets>(`/cases/${encodeURIComponent(caseId)}/assets`),
// FIX: include caseId in JSON body to satisfy backend Lambda contract
submitLandmarks: (caseId: string, body: SubmitLandmarksRequest) =>
http<SubmitLandmarksResponse>(`/cases/${encodeURIComponent(caseId)}/landmarks`, {
method: "POST",
body: JSON.stringify({
...body,
}),
}),
};