learning_ai_invt_trdg/web/src/lib/profileApi.ts

124 lines
3.9 KiB
TypeScript

import { getPlatformAccessToken } from './authSession';
import { tradingRuntime } from './runtime';
import { createRequestId } from '../../../shared/request-id.js';
export interface TradeProfilePayload {
id?: string;
user_id?: string;
name: string;
allocated_capital: number;
risk_per_trade_percent: number;
symbols: string;
is_active: boolean;
strategy_config: Record<string, unknown>;
created_at?: string;
updated_at?: string;
}
export interface CurrentUserProfile {
user_id: string;
first_name: string;
last_name: string;
email: string;
role: string;
trade_enable: boolean;
FMP_API_KEY?: string;
ALPACA_API_KEY?: string;
ALPACA_SECRET_KEY?: string;
REAL_ALPACA_API_KEY?: string;
REAL_ALPACA_SECRET_KEY?: string;
drop_threshold_for_buy?: number;
gain_threshold_for_sell?: number;
market_poll_interval_in_seconds?: number;
}
async function getAccessToken(): Promise<string> {
return getPlatformAccessToken();
}
async function apiRequest<T>(path: string, init?: RequestInit): Promise<T> {
const accessToken = await getAccessToken();
const response = await fetch(`${tradingRuntime.tradingApiUrl}${path}`, {
...init,
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${accessToken}`,
'x-request-id': createRequestId('web-profile'),
...(init?.headers || {}),
},
});
const body = await response.json().catch(() => ({} as any));
if (!response.ok) {
throw new Error(body?.error || `Request failed (${response.status})`);
}
return body as T;
}
function notifyProfilesUpdated() {
if (typeof window !== 'undefined') {
window.dispatchEvent(new Event('profiles-updated'));
}
}
export async function fetchCurrentUserProfile(): Promise<CurrentUserProfile> {
const response = await apiRequest<{ profile: CurrentUserProfile }>('/api/me/profile');
return response.profile;
}
export async function updateCurrentUserProfile(payload: Partial<CurrentUserProfile>): Promise<CurrentUserProfile> {
const response = await apiRequest<{ profile: CurrentUserProfile }>('/api/me/profile', {
method: 'PATCH',
body: JSON.stringify(payload),
});
return response.profile;
}
export async function fetchTradeProfiles(options?: { ensureDefault?: boolean; scope?: 'user' | 'all' }): Promise<TradeProfilePayload[]> {
const params = new URLSearchParams();
if (options?.ensureDefault) {
params.set('ensureDefault', 'true');
}
if (options?.scope === 'all') {
params.set('scope', 'all');
}
const query = params.toString() ? `?${params.toString()}` : '';
const response = await apiRequest<{ profiles: TradeProfilePayload[] }>(`/api/profiles${query}`);
return Array.isArray(response.profiles) ? response.profiles : [];
}
export async function createTradeProfile(payload: TradeProfilePayload): Promise<TradeProfilePayload> {
const response = await apiRequest<{ profile: TradeProfilePayload }>('/api/profiles', {
method: 'POST',
body: JSON.stringify(payload),
});
notifyProfilesUpdated();
return response.profile;
}
export async function updateTradeProfile(id: string, payload: Partial<TradeProfilePayload>): Promise<TradeProfilePayload> {
const response = await apiRequest<{ profile: TradeProfilePayload }>(`/api/profiles/${id}`, {
method: 'PUT',
body: JSON.stringify(payload),
});
notifyProfilesUpdated();
return response.profile;
}
export async function setTradeProfileActive(id: string, isActive: boolean): Promise<TradeProfilePayload> {
const response = await apiRequest<{ profile: TradeProfilePayload }>(`/api/profiles/${id}/active`, {
method: 'PATCH',
body: JSON.stringify({ is_active: isActive }),
});
notifyProfilesUpdated();
return response.profile;
}
export async function deleteTradeProfile(id: string): Promise<void> {
await apiRequest<{ success: boolean }>(`/api/profiles/${id}`, {
method: 'DELETE',
});
notifyProfilesUpdated();
}