mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-07-23 08:58:11 -07:00
108 lines
3.5 KiB
JavaScript
108 lines
3.5 KiB
JavaScript
import { brk } from "../../utils/client.js";
|
|
|
|
const RANGE_POINTS = 120;
|
|
|
|
/** @type {Map<string, Promise<{ indexes: string[], type: string }>>} */
|
|
const infoCache = new Map();
|
|
|
|
/** @param {string} name */
|
|
function seriesInfo(name) {
|
|
let request = infoCache.get(name);
|
|
if (!request) {
|
|
request = brk.getSeriesInfo(name);
|
|
infoCache.set(name, request);
|
|
}
|
|
return request;
|
|
}
|
|
|
|
/** @param {string} type */
|
|
export function unitFromType(type) {
|
|
const value = type.toLowerCase();
|
|
if (value.includes("dollar") || value.includes("usd") || value.includes("cents")) return "usd";
|
|
if (value.includes("bitcoin") || value === "btc") return "btc";
|
|
if (value.includes("percent") || value.includes("ratio")) return "percent";
|
|
if (value.includes("address")) return "addresses";
|
|
if (value.includes("utxo") || value.includes("output")) return "utxos";
|
|
if (value.includes("block") || value.includes("height")) return "blocks";
|
|
return undefined;
|
|
}
|
|
|
|
/** @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, suggestedUnit?: string }} metric @param {Record<string, unknown>} action */
|
|
export async function readMetric(metric, action) {
|
|
const info = await seriesInfo(metric.name);
|
|
const rawIndex = typeof action.index === "string" ? action.index : "";
|
|
const indexLooksLikeValue = /^-?\d+$/.test(rawIndex) || /^\d{4}-\d{2}-\d{2}$/.test(rawIndex);
|
|
const at = action.at ?? (indexLooksLikeValue ? rawIndex : undefined);
|
|
const dateLike = typeof at === "string" && !/^-?\d+$/.test(at);
|
|
const preferredIndex = indexLooksLikeValue ? "" : rawIndex;
|
|
const index = info.indexes.includes(preferredIndex)
|
|
? preferredIndex
|
|
: dateLike && info.indexes.includes("day1")
|
|
? "day1"
|
|
: info.indexes.includes("height")
|
|
? "height"
|
|
: info.indexes[0];
|
|
const mode = typeof action.mode === "string" ? action.mode : "latest";
|
|
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(info.type),
|
|
index: response.index,
|
|
start: response.start,
|
|
end: response.end,
|
|
stamp: response.stamp,
|
|
values: response.data,
|
|
};
|
|
}
|