1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
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 };
|