// HTTP-клиент и хуки. Типы ответов HTTP в generated.ts пока не попадают — // там только события WS; здесь описаны руками по docs/arch/CONTRACT.md#http-api. import { useMutation, useQuery } from "@tanstack/react-query"; import type { Level, SessionMode } from "@/shared/types/generated"; export class ApiError extends Error { constructor( readonly status: number, readonly code: string, ) { super(`${status} ${code}`); } } async function request(path: string, init?: RequestInit): Promise { const response = await fetch(path, { ...init, headers: { "Content-Type": "application/json", ...init?.headers }, }); if (!response.ok) { const body = await response.json().catch(() => ({})); throw new ApiError(response.status, body.detail ?? response.statusText); } return response.json() as Promise; } export interface Health { status: string; models_ready: boolean; embeddings_ready: boolean; scenarios_loaded: number; offline: boolean; } export interface ScenarioSummary { id: string; title: string; type: string; level: Level; topics: string[]; modes: SessionMode[]; dds: string | null; } export interface SessionInfo { session_id: string; scenario_id: string; mode: SessionMode; attempt: number; trainee_id: string | null; group_id: string | null; } export const useHealth = () => useQuery({ queryKey: ["health"], queryFn: () => request("/api/health"), refetchInterval: 5_000 }); export const useScenarios = () => useQuery({ queryKey: ["scenarios"], queryFn: () => request("/api/scenarios") }); export const useSessions = (params: { trainee?: string; group?: string; mode?: SessionMode } = {}) => { const query = new URLSearchParams( Object.entries(params).filter(([, value]) => value) as [string, string][], ).toString(); return useQuery({ queryKey: ["sessions", query], queryFn: () => request(`/api/sessions${query ? `?${query}` : ""}`), refetchInterval: 15_000, }); }; export const useCreateSession = () => useMutation({ mutationFn: (body: { scenario_id: string; mode: SessionMode; trainee?: string; group?: string }) => request("/api/sessions", { method: "POST", body: JSON.stringify(body) }), });