summaryrefslogtreecommitdiff
path: root/frontend/src/lib/client.ts
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-17 14:32:37 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-17 14:32:37 +0800
commit5c0ba37eda80d39e6ceca59bb1d5f4942f858995 (patch)
tree948723f9cedf7ccb0707fa6ee516bd30fe20fd10 /frontend/src/lib/client.ts
downloadstrategy-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.ts118
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 };