128 lines
4.1 KiB
TypeScript
128 lines
4.1 KiB
TypeScript
import type {
|
|
ScreenerResult,
|
|
MarketContext,
|
|
MarketCall,
|
|
CalendarEvent,
|
|
CatalystStory,
|
|
LLMAnalysis,
|
|
PortfolioHolding,
|
|
PortfolioAdvice,
|
|
} from '$lib/types.js';
|
|
|
|
const BASE = '/api';
|
|
|
|
// ── Screener ──────────────────────────────────────────────────────────────────
|
|
|
|
export async function screenTickers(tickers: string[]): Promise<ScreenerResult> {
|
|
const res = await fetch(`${BASE}/screen`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ tickers }),
|
|
});
|
|
if (!res.ok) throw new Error(await res.text());
|
|
return res.json();
|
|
}
|
|
|
|
export async function fetchCatalysts(): Promise<{ tickers: string[]; stories: CatalystStory[] }> {
|
|
const res = await fetch(`${BASE}/screen/catalysts`);
|
|
if (!res.ok) throw new Error(await res.text());
|
|
return res.json();
|
|
}
|
|
|
|
export async function analyzeTickers(tickers: string[]): Promise<{ analysis: LLMAnalysis | null }> {
|
|
const res = await fetch(`${BASE}/analyze`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ tickers }),
|
|
});
|
|
if (!res.ok) throw new Error(await res.text());
|
|
return res.json();
|
|
}
|
|
|
|
// ── Finance / Portfolio ───────────────────────────────────────────────────────
|
|
|
|
export async function fetchPortfolio(): Promise<{
|
|
advice: PortfolioAdvice[];
|
|
holdings: PortfolioHolding[];
|
|
marketContext: MarketContext | null;
|
|
netWorth: number | null;
|
|
error?: string;
|
|
}> {
|
|
const res = await fetch(`${BASE}/finance/portfolio`);
|
|
if (!res.ok) throw new Error(await res.text());
|
|
return res.json();
|
|
}
|
|
|
|
export async function addHolding(
|
|
holding: Omit<PortfolioHolding, never>,
|
|
): Promise<{ holdings: PortfolioHolding[] }> {
|
|
const res = await fetch(`${BASE}/finance/holdings`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(holding),
|
|
});
|
|
if (!res.ok) throw new Error(await res.text());
|
|
return res.json();
|
|
}
|
|
|
|
export async function removeHolding(ticker: string): Promise<{ holdings: PortfolioHolding[] }> {
|
|
const res = await fetch(`${BASE}/finance/holdings/${ticker}`, {
|
|
method: 'DELETE',
|
|
});
|
|
if (!res.ok) throw new Error(await res.text());
|
|
return res.json();
|
|
}
|
|
|
|
export async function fetchMarketContext(): Promise<MarketContext> {
|
|
const res = await fetch(`${BASE}/finance/market-context`);
|
|
if (!res.ok) throw new Error(await res.text());
|
|
return res.json();
|
|
}
|
|
|
|
// ── Market Calls ──────────────────────────────────────────────────────────────
|
|
|
|
export async function fetchCalls(): Promise<{ calls: MarketCall[] }> {
|
|
const res = await fetch(`${BASE}/calls`);
|
|
if (!res.ok) throw new Error(await res.text());
|
|
return res.json();
|
|
}
|
|
|
|
export async function fetchCall(id: string): Promise<MarketCall & { current: ScreenerResult }> {
|
|
const res = await fetch(`${BASE}/calls/${id}`);
|
|
if (!res.ok) throw new Error(await res.text());
|
|
return res.json();
|
|
}
|
|
|
|
export async function createCall(payload: {
|
|
title: string;
|
|
quarter: string;
|
|
thesis: string;
|
|
tickers: string[];
|
|
date?: string;
|
|
}): Promise<MarketCall> {
|
|
const res = await fetch(`${BASE}/calls`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(payload),
|
|
});
|
|
if (!res.ok) throw new Error(await res.text());
|
|
return res.json();
|
|
}
|
|
|
|
export async function deleteCall(id: string): Promise<{ ok: boolean }> {
|
|
const res = await fetch(`${BASE}/calls/${id}`, { method: 'DELETE' });
|
|
if (!res.ok) throw new Error(await res.text());
|
|
return res.json();
|
|
}
|
|
|
|
export async function fetchCallsCalendar(
|
|
tickers: string[] | null = null,
|
|
): Promise<{ events: CalendarEvent[] }> {
|
|
const url = tickers?.length
|
|
? `${BASE}/calls/calendar?tickers=${tickers.join(',')}`
|
|
: `${BASE}/calls/calendar`;
|
|
const res = await fetch(url);
|
|
if (!res.ok) throw new Error(await res.text());
|
|
return res.json();
|
|
}
|