import { brk } from "../../utils/client.js"; import { unitFromType } from "./metrics/unit.js"; const RANGE_POINTS = 120; /** @param {string} unit */ function displayedUnit(unit) { if (unit === "usd") return "$"; if (unit === "percent") return "%"; if (unit === "btc") return " BTC"; if (unit === "addresses") return " addresses"; if (unit === "utxos") return " UTXOs"; if (unit === "blocks") return " blocks"; return ""; } /** @param {number} value @param {string | undefined} unit */ export function formatValue(value, unit) { const number = new Intl.NumberFormat("en-US", { maximumFractionDigits: 8 }).format(value); const affix = displayedUnit(unit ?? ""); return affix === "$" ? `$${number}` : `${number}${affix}`; } /** @param {{ name: string, indexes: string[], type: string, suggestedUnit?: string }} metric @param {Record} action */ export async function readMetric(metric, action) { const rawIndex = typeof action.index === "string" ? action.index : ""; const at = action.at; const dateLike = typeof at === "string" && !/^-?\d+$/.test(at); const index = metric.indexes.includes(rawIndex) ? rawIndex : dateLike && metric.indexes.includes("day1") ? "day1" : metric.indexes.includes("height") ? "height" : metric.indexes[0]; if (!index) throw new Error(`No supported index for ${metric.name}`); if ( typeof action.mode !== "string" || !["latest", "at", "range"].includes(action.mode) ) { throw new Error(`A valid position is required for ${metric.name}`); } const mode = action.mode; let response; if (mode === "at") { if (at === undefined) throw new Error("A block height or date is required"); response = await brk.getSeries( metric.name, /** @type {any} */ (index), /** @type {any} */ (at), undefined, 1, ); } else if (mode === "range") { const points = Math.min(Number(action.points) || RANGE_POINTS, RANGE_POINTS); response = await brk.getSeries( metric.name, /** @type {any} */ (index), /** @type {any} */ (action.start ?? -points), /** @type {any} */ (action.end), points, ); } else { response = await brk.getSeries( metric.name, /** @type {any} */ (index), -1, undefined, 1, ); } if (!response || typeof response !== "object" || !Array.isArray(response.data)) { throw new Error(`No data returned for ${metric.name}`); } return { name: metric.name, label: metric.name.replaceAll("_", " "), unit: metric.suggestedUnit ?? unitFromType(metric.type), index: response.index, start: response.start, end: response.end, stamp: response.stamp, values: response.data, ...(mode === "at" ? { requested: String(at) } : {}), }; }