// Central typed binding layer for the 策研 Strategy Lab HTTP contract. import { apiFetch } from './api'; import type { AIAssist, AIUsage, AdminUserUpdate, BacktestResult, Capabilities, Dataset, DatasetPreview, DatasetRequest, InstrumentSearchResponse, Invitation, Project, Run, SessionInfo, User, Version } from './types'; export const getHealth = () => apiFetch<{ status: string; version: string; worker_available: boolean; ai_configured: boolean }>('/api/health'); // ---- auth ---- export const postLogin = (email: string, password: string) => apiFetch<{ user: User }>('/api/auth/login', { method: 'POST', body: { email, password } }); export const postLogout = () => apiFetch('/api/auth/logout', { method: 'POST', body: {} }); export const getMe = () => apiFetch<{ user: User }>('/api/auth/me'); export const postRegister = (invite_token: string, name: string, email: string, password: string) => apiFetch<{ user: User }>('/api/auth/register', { method: 'POST', body: { invite_token, name, email, password } }); export const patchProfile = (name: string) => apiFetch<{ user: User }>('/api/auth/profile', { method: 'PATCH', body: { name } }); export const postPassword = (current_password: string, new_password: string) => apiFetch('/api/auth/password', { method: 'POST', body: { current_password, new_password } }); export const getSessions = () => apiFetch<{ items: SessionInfo[] }>('/api/auth/sessions'); export const deleteSession = (id: string) => apiFetch(`/api/auth/sessions/${id}`, { method: 'DELETE', body: {} }); export const postResetPassword = (token: string, new_password: string) => apiFetch<{ user?: User }>('/api/auth/reset-password', { method: 'POST', body: { token, new_password } }); // ---- capabilities ---- export const getCapabilities = () => apiFetch('/api/capabilities'); // ---- instruments ---- export const searchInstruments = (q: string, signal?: AbortSignal) => apiFetch(`/api/instruments?q=${encodeURIComponent(q)}`, { signal }); // ---- projects ---- export const listProjects = () => apiFetch<{ items: Project[] }>('/api/projects'); export const createProject = (name: string, description?: string) => apiFetch('/api/projects', { method: 'POST', body: { name, description } }); export const getProject = (id: string) => apiFetch(`/api/projects/${id}`); export const patchProject = (id: string, body: { name?: string; description?: string }) => apiFetch(`/api/projects/${id}`, { method: 'PATCH', body }); export const putDraft = (id: string, code: string, expected_generation: number) => apiFetch(`/api/projects/${id}/draft`, { method: 'PUT', body: { code, expected_generation } }); export const listVersions = (id: string) => apiFetch<{ items: Version[] }>(`/api/projects/${id}/versions`); export const postVersion = (id: string, message: string) => apiFetch(`/api/projects/${id}/versions`, { method: 'POST', body: { message } }); export const getVersionCode = (id: string, versionId: string) => apiFetch<{ code: string }>(`/api/projects/${id}/versions/${versionId}`); export const postRestore = (id: string, version_id: string, expected_generation: number) => apiFetch(`/api/projects/${id}/restore`, { method: 'POST', body: { version_id, expected_generation } }); // ---- datasets ---- export const listDatasets = () => apiFetch<{ items: Dataset[] }>('/api/datasets'); export const createDataset = (body: DatasetRequest) => apiFetch('/api/datasets', { method: 'POST', body }); export const getDataset = (id: string) => apiFetch(`/api/datasets/${id}`); export const getDatasetPreview = (id: string) => apiFetch(`/api/datasets/${id}/preview`); // ---- runs ---- export const listRuns = (project_id?: string) => apiFetch<{ items: Run[] }>(project_id ? `/api/runs?project_id=${encodeURIComponent(project_id)}` : '/api/runs'); export interface RunCreateBody { project_id: string; dataset_id: string; capital: number; commission: number; slippage: number; benchmark_symbol?: string | null; parameters?: Record; acknowledge_warnings?: boolean; } export const createRun = (body: RunCreateBody) => apiFetch('/api/runs', { method: 'POST', body }); export const getRun = (id: string) => apiFetch(`/api/runs/${id}`); export const cancelRun = (id: string) => apiFetch(`/api/runs/${id}/cancel`, { method: 'POST', body: {} }); export const rerunRun = (id: string, use_original_data = true) => apiFetch(`/api/runs/${id}/rerun`, { method: 'POST', body: { use_original_data } }); // ---- AI ---- export const postAIAssist = (project_id: string, instruction: string, expected_generation: number) => apiFetch('/api/ai/assist', { method: 'POST', body: { project_id, instruction, expected_generation } }); export const postAIAccept = (aiId: string, expected_generation: number) => apiFetch(`/api/ai/${aiId}/accept`, { method: 'POST', body: { expected_generation } }); export const getAIUsage = () => apiFetch('/api/ai/usage'); // ---- admin ---- export const listAdminUsers = () => apiFetch<{ items: User[] }>('/api/admin/users'); export const patchAdminUser = (id: string, body: AdminUserUpdate) => apiFetch(`/api/admin/users/${id}`, { method: 'PATCH', body }); export const postAdminUserPassword = (id: string) => apiFetch<{ reset_token: string; expires_at: string }>(`/api/admin/users/${id}/reset-password`, { method: 'POST', body: {} }); export const createInvitation = (body: { email?: string; role?: string; expires_hours?: number }) => apiFetch<{ token: string; expires_at: string }>('/api/admin/invitations', { method: 'POST', body }); export const listInvitations = () => apiFetch<{ items: Invitation[] }>('/api/admin/invitations'); export const deleteInvitation = (id: string) => apiFetch(`/api/admin/invitations/${id}`, { method: 'DELETE', body: {} }); export const getAdminAudit = () => apiFetch<{ items: { actor?: string | null; action: string; target?: string | null; status: string; time: string; detail?: string | null }[] }>( '/api/admin/audit' ); // helpers export async function poll(fn: () => Promise, until: (v: T) => boolean, intervalMs = 1500): Promise { for (;;) { const v = await fn(); if (until(v)) return v; await new Promise((r) => setTimeout(r, intervalMs)); } } export type { BacktestResult };