CI / ruff · pytest (pull_request) Successful in 2m9s
Conflict in app/api/routes.py: /demo/personas keeps the dev version (demo console, DB patients with scenarios); the patient app gets its own /patient/demo-personas (synthetic ЕМИАС accounts). Anonymous sign-in now always creates a doctor-less pseudonymous profile, since the dialog API of #12 serves known profiles only. Refs #77 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
58 lines
2.0 KiB
TypeScript
58 lines
2.0 KiB
TypeScript
import type {
|
|
AuthResult,
|
|
Catalog,
|
|
CrisisResource,
|
|
DemoPersona,
|
|
DialogEvent,
|
|
Focus,
|
|
MedsReference,
|
|
Reply,
|
|
Results,
|
|
TodayPlan,
|
|
} from "./types";
|
|
|
|
// Web: same-origin /api/v1 (Vite proxy in dev). Mobile shell: set VITE_API_BASE to the absolute API URL at build.
|
|
const BASE: string = import.meta.env.VITE_API_BASE ?? "/api/v1";
|
|
|
|
export class ApiError extends Error {
|
|
constructor(
|
|
readonly status: number,
|
|
message: string,
|
|
) {
|
|
super(message);
|
|
}
|
|
}
|
|
|
|
async function request<T>(path: string, init?: RequestInit): Promise<T> {
|
|
let res: Response;
|
|
try {
|
|
res = await fetch(`${BASE}${path}`, {
|
|
...init,
|
|
headers: { "Content-Type": "application/json", ...init?.headers },
|
|
});
|
|
} catch {
|
|
throw new ApiError(0, "network");
|
|
}
|
|
if (!res.ok) throw new ApiError(res.status, res.statusText);
|
|
return (await res.json()) as T;
|
|
}
|
|
|
|
const post = <T>(path: string, body?: unknown) =>
|
|
request<T>(path, { method: "POST", body: body === undefined ? undefined : JSON.stringify(body) });
|
|
|
|
export const api = {
|
|
signInEmias: (code: string) => post<AuthResult>("/auth/emias", { code }),
|
|
signInEmiasDemo: (personaToken: string) => post<AuthResult>("/auth/emias/demo", { persona_token: personaToken }),
|
|
signInAnonymous: (focus: Focus) => post<AuthResult>("/auth/anonymous", { focus }),
|
|
demoPersonas: () => request<DemoPersona[]>("/patient/demo-personas"),
|
|
crisisResources: () => request<CrisisResource[]>("/crisis/resources"),
|
|
catalog: () => request<Catalog>("/instruments/catalog"),
|
|
medsReference: () => request<MedsReference>("/meds/reference"),
|
|
today: (token: string) => request<TodayPlan>(`/me/${encodeURIComponent(token)}/today`),
|
|
results: (token: string) => request<Results>(`/me/${encodeURIComponent(token)}/results`),
|
|
sendEvent: async (token: string, event: DialogEvent) =>
|
|
(await post<{ replies: Reply[] }>(`/dialog/${encodeURIComponent(token)}/events`, event)).replies,
|
|
outbox: async (token: string) =>
|
|
(await request<{ replies: Reply[] }>(`/dialog/${encodeURIComponent(token)}/outbox`)).replies,
|
|
};
|