Replace entire codebase with homarr-labs/homarr
This commit is contained in:
75
packages/request-handler/src/stock-price.ts
Normal file
75
packages/request-handler/src/stock-price.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import dayjs from "dayjs";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { fetchWithTrustedCertificatesAsync } from "@homarr/core/infrastructure/http";
|
||||
import { withTimeoutAsync } from "@homarr/core/infrastructure/http/timeout";
|
||||
|
||||
import { createCachedWidgetRequestHandler } from "./lib/cached-widget-request-handler";
|
||||
|
||||
export const fetchStockPriceHandler = createCachedWidgetRequestHandler({
|
||||
queryKey: "fetchStockPriceResult",
|
||||
widgetKind: "stockPrice",
|
||||
async requestAsync(input: { stock: string; timeRange: string; timeInterval: string }) {
|
||||
const response = await withTimeoutAsync(async (signal) => {
|
||||
return await fetchWithTrustedCertificatesAsync(
|
||||
`https://query1.finance.yahoo.com/v8/finance/chart/${input.stock}?range=${input.timeRange}&interval=${input.timeInterval}`,
|
||||
{ signal },
|
||||
);
|
||||
});
|
||||
const data = dataSchema.parse(await response.json());
|
||||
|
||||
if ("error" in data) {
|
||||
throw new Error(data.error.description);
|
||||
}
|
||||
if (data.chart.result.length !== 1) {
|
||||
throw new Error("Received multiple results");
|
||||
}
|
||||
const firstResult = data.chart.result[0];
|
||||
if (!firstResult) {
|
||||
throw new Error("Received invalid data");
|
||||
}
|
||||
|
||||
const priceHistory =
|
||||
firstResult.indicators.quote[0]?.close.filter(
|
||||
// Filter out null values from price arrays (Yahoo Finance returns null for missing data points)
|
||||
(value) => value !== null && value !== undefined,
|
||||
) ?? [];
|
||||
|
||||
return {
|
||||
priceHistory,
|
||||
previousClose: firstResult.meta.previousClose ?? priceHistory[0] ?? 1,
|
||||
symbol: firstResult.meta.symbol,
|
||||
shortName: firstResult.meta.shortName,
|
||||
};
|
||||
},
|
||||
cacheDuration: dayjs.duration(5, "minutes"),
|
||||
});
|
||||
|
||||
const dataSchema = z
|
||||
.object({
|
||||
error: z.object({
|
||||
description: z.string(),
|
||||
}),
|
||||
})
|
||||
.or(
|
||||
z.object({
|
||||
chart: z.object({
|
||||
result: z.array(
|
||||
z.object({
|
||||
indicators: z.object({
|
||||
quote: z.array(
|
||||
z.object({
|
||||
close: z.array(z.number().nullish()),
|
||||
}),
|
||||
),
|
||||
}),
|
||||
meta: z.object({
|
||||
symbol: z.string(),
|
||||
shortName: z.string(),
|
||||
previousClose: z.number().optional(),
|
||||
}),
|
||||
}),
|
||||
),
|
||||
}),
|
||||
}),
|
||||
);
|
||||
Reference in New Issue
Block a user