diff options
| author | Somhairle H. Marisol <[email protected]> | 2026-09-17 14:32:37 +0800 |
|---|---|---|
| committer | Somhairle H. Marisol <[email protected]> | 2026-09-17 14:32:37 +0800 |
| commit | 5c0ba37eda80d39e6ceca59bb1d5f4942f858995 (patch) | |
| tree | 948723f9cedf7ccb0707fa6ee516bd30fe20fd10 /frontend/src/lib/client.ts | |
| download | strategy-lab-5c0ba37eda80d39e6ceca59bb1d5f4942f858995.tar.gz | |
chore: establish Strategy Lab source baseline (development, not release)
Diffstat (limited to 'frontend/src/lib/client.ts')
| -rw-r--r-- | frontend/src/lib/client.ts | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/frontend/src/lib/client.ts b/frontend/src/lib/client.ts new file mode 100644 index 0000000..4937902 --- /dev/null +++ b/frontend/src/lib/client.ts @@ -0,0 +1,118 @@ +// 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<void>('/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<void>('/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<void>(`/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<Capabilities>('/api/capabilities'); + +// ---- instruments ---- +export const searchInstruments = (q: string, signal?: AbortSignal) => + apiFetch<InstrumentSearchResponse>(`/api/instruments?q=${encodeURIComponent(q)}`, { signal }); + +// ---- projects ---- +export const listProjects = () => apiFetch<{ items: Project[] }>('/api/projects'); +export const createProject = (name: string, description?: string) => + apiFetch<Project>('/api/projects', { method: 'POST', body: { name, description } }); +export const getProject = (id: string) => apiFetch<Project>(`/api/projects/${id}`); +export const patchProject = (id: string, body: { name?: string; description?: string }) => + apiFetch<Project>(`/api/projects/${id}`, { method: 'PATCH', body }); +export const putDraft = (id: string, code: string, expected_generation: number) => + apiFetch<Project>(`/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<Version>(`/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<Project>(`/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<Dataset>('/api/datasets', { method: 'POST', body }); +export const getDataset = (id: string) => apiFetch<Dataset>(`/api/datasets/${id}`); +export const getDatasetPreview = (id: string) => apiFetch<DatasetPreview>(`/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<string, unknown>; + acknowledge_warnings?: boolean; +} +export const createRun = (body: RunCreateBody) => apiFetch<Run>('/api/runs', { method: 'POST', body }); +export const getRun = (id: string) => apiFetch<Run>(`/api/runs/${id}`); +export const cancelRun = (id: string) => apiFetch<Run>(`/api/runs/${id}/cancel`, { method: 'POST', body: {} }); +export const rerunRun = (id: string, use_original_data = true) => + apiFetch<Run>(`/api/runs/${id}/rerun`, { method: 'POST', body: { use_original_data } }); + +// ---- AI ---- +export const postAIAssist = (project_id: string, instruction: string, expected_generation: number) => + apiFetch<AIAssist>('/api/ai/assist', { method: 'POST', body: { project_id, instruction, expected_generation } }); +export const postAIAccept = (aiId: string, expected_generation: number) => + apiFetch<Project>(`/api/ai/${aiId}/accept`, { method: 'POST', body: { expected_generation } }); +export const getAIUsage = () => apiFetch<AIUsage>('/api/ai/usage'); + +// ---- admin ---- +export const listAdminUsers = () => apiFetch<{ items: User[] }>('/api/admin/users'); +export const patchAdminUser = (id: string, body: AdminUserUpdate) => + apiFetch<User>(`/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<void>(`/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<T>(fn: () => Promise<T>, until: (v: T) => boolean, intervalMs = 1500): Promise<T> { + for (;;) { + const v = await fn(); + if (until(v)) return v; + await new Promise((r) => setTimeout(r, intervalMs)); + } +} + +export type { BacktestResult }; |
