124 lines
3.9 KiB
TypeScript
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();
|
|
}
|