Add company overview skeleton and cache
This commit is contained in:
@@ -1,4 +1,14 @@
|
||||
const YAHOO_BASE = 'https://query1.finance.yahoo.com/v8/finance/chart';
|
||||
const QUOTE_CACHE_TTL_MS = 1000 * 60;
|
||||
const PRICE_HISTORY_CACHE_TTL_MS = 1000 * 60 * 15;
|
||||
|
||||
type CacheEntry<T> = {
|
||||
expiresAt: number;
|
||||
value: T;
|
||||
};
|
||||
|
||||
const quoteCache = new Map<string, CacheEntry<number>>();
|
||||
const priceHistoryCache = new Map<string, CacheEntry<Array<{ date: string; close: number }>>>();
|
||||
|
||||
function buildYahooChartUrl(ticker: string, params: string) {
|
||||
return `${YAHOO_BASE}/${encodeURIComponent(ticker.trim().toUpperCase())}?${params}`;
|
||||
@@ -17,7 +27,12 @@ function fallbackQuote(ticker: string) {
|
||||
|
||||
export async function getQuote(ticker: string): Promise<number> {
|
||||
const normalizedTicker = ticker.trim().toUpperCase();
|
||||
const cached = quoteCache.get(normalizedTicker);
|
||||
if (cached && cached.expiresAt > Date.now()) {
|
||||
return cached.value;
|
||||
}
|
||||
|
||||
let quote = fallbackQuote(normalizedTicker);
|
||||
try {
|
||||
const response = await fetch(buildYahooChartUrl(normalizedTicker, 'interval=1d&range=1d'), {
|
||||
headers: {
|
||||
@@ -27,7 +42,11 @@ export async function getQuote(ticker: string): Promise<number> {
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
return fallbackQuote(normalizedTicker);
|
||||
quoteCache.set(normalizedTicker, {
|
||||
value: quote,
|
||||
expiresAt: Date.now() + QUOTE_CACHE_TTL_MS
|
||||
});
|
||||
return quote;
|
||||
}
|
||||
|
||||
const payload = await response.json() as {
|
||||
@@ -38,13 +57,23 @@ export async function getQuote(ticker: string): Promise<number> {
|
||||
|
||||
const price = payload.chart?.result?.[0]?.meta?.regularMarketPrice;
|
||||
if (typeof price !== 'number' || !Number.isFinite(price)) {
|
||||
return fallbackQuote(normalizedTicker);
|
||||
quoteCache.set(normalizedTicker, {
|
||||
value: quote,
|
||||
expiresAt: Date.now() + QUOTE_CACHE_TTL_MS
|
||||
});
|
||||
return quote;
|
||||
}
|
||||
|
||||
return price;
|
||||
quote = price;
|
||||
} catch {
|
||||
return fallbackQuote(normalizedTicker);
|
||||
// fall through to cached fallback
|
||||
}
|
||||
|
||||
quoteCache.set(normalizedTicker, {
|
||||
value: quote,
|
||||
expiresAt: Date.now() + QUOTE_CACHE_TTL_MS
|
||||
});
|
||||
|
||||
return quote;
|
||||
}
|
||||
|
||||
export async function getQuoteOrNull(ticker: string): Promise<number | null> {
|
||||
@@ -145,6 +174,10 @@ export async function getHistoricalClosingPrices(ticker: string, dates: string[]
|
||||
|
||||
export async function getPriceHistory(ticker: string): Promise<Array<{ date: string; close: number }>> {
|
||||
const normalizedTicker = ticker.trim().toUpperCase();
|
||||
const cached = priceHistoryCache.get(normalizedTicker);
|
||||
if (cached && cached.expiresAt > Date.now()) {
|
||||
return cached.value;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(buildYahooChartUrl(normalizedTicker, 'interval=1wk&range=20y'), {
|
||||
@@ -190,6 +223,10 @@ export async function getPriceHistory(ticker: string): Promise<Array<{ date: str
|
||||
.filter((entry): entry is { date: string; close: number } => entry !== null);
|
||||
|
||||
if (points.length > 0) {
|
||||
priceHistoryCache.set(normalizedTicker, {
|
||||
value: points,
|
||||
expiresAt: Date.now() + PRICE_HISTORY_CACHE_TTL_MS
|
||||
});
|
||||
return points;
|
||||
}
|
||||
} catch {
|
||||
@@ -201,7 +238,7 @@ export async function getPriceHistory(ticker: string): Promise<Array<{ date: str
|
||||
|
||||
const totalWeeks = 20 * 52;
|
||||
|
||||
return Array.from({ length: totalWeeks }, (_, index) => {
|
||||
const syntheticHistory = Array.from({ length: totalWeeks }, (_, index) => {
|
||||
const step = (totalWeeks - 1) - index;
|
||||
const date = new Date(now - step * 7 * 24 * 60 * 60 * 1000).toISOString();
|
||||
const wave = Math.sin(index / 8) * 0.06;
|
||||
@@ -213,4 +250,20 @@ export async function getPriceHistory(ticker: string): Promise<Array<{ date: str
|
||||
close: Number(close.toFixed(2))
|
||||
};
|
||||
});
|
||||
|
||||
priceHistoryCache.set(normalizedTicker, {
|
||||
value: syntheticHistory,
|
||||
expiresAt: Date.now() + PRICE_HISTORY_CACHE_TTL_MS
|
||||
});
|
||||
|
||||
return syntheticHistory;
|
||||
}
|
||||
|
||||
export const __pricesInternals = {
|
||||
PRICE_HISTORY_CACHE_TTL_MS,
|
||||
QUOTE_CACHE_TTL_MS,
|
||||
resetCaches() {
|
||||
quoteCache.clear();
|
||||
priceHistoryCache.clear();
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user