From 88c38e74f9eaf12b225f93732725cf0287646f80 Mon Sep 17 00:00:00 2001 From: nym21 Date: Mon, 1 Jun 2026 14:25:21 +0200 Subject: [PATCH] heatmaps: part 21 --- .../src/generators/javascript/api.rs | 16 +- .../src/generators/javascript/client.rs | 34 +- crates/brk_types/src/urpd_aggregation.rs | 7 +- .../docs/type-aliases/UrpdAggregation.md | 2 +- modules/brk-client/index.js | 614 +++++++++--------- packages/brk_client/brk_client/__init__.py | 4 +- website/scripts/_types.js | 2 +- website/scripts/options/partial.js | 5 + website/src/heatmap/tooltip/index.js | 4 +- website/src/heatmap/urpd.js | 149 +++++ 10 files changed, 508 insertions(+), 329 deletions(-) create mode 100644 website/src/heatmap/urpd.js diff --git a/crates/brk_bindgen/src/generators/javascript/api.rs b/crates/brk_bindgen/src/generators/javascript/api.rs index bf32476c8..cc31315d2 100644 --- a/crates/brk_bindgen/src/generators/javascript/api.rs +++ b/crates/brk_bindgen/src/generators/javascript/api.rs @@ -51,7 +51,7 @@ fn generate_get_method(output: &mut String, endpoint: &Endpoint) { } writeln!( output, - " * @param {{{{ signal?: AbortSignal, onValue?: (value: {}) => void }}}} [options]", + " * @param {{{{ signal?: AbortSignal, onValue?: (value: {}) => void, cache?: boolean }}}} [options]", return_type ) .unwrap(); @@ -60,22 +60,22 @@ fn generate_get_method(output: &mut String, endpoint: &Endpoint) { let params = build_method_params(endpoint); let params_with_opts = if params.is_empty() { - "{ signal, onValue } = {}".to_string() + "{ signal, onValue, cache } = {}".to_string() } else { - format!("{}, {{ signal, onValue }} = {{}}", params) + format!("{}, {{ signal, onValue, cache }} = {{}}", params) }; writeln!(output, " async {}({}) {{", method_name, params_with_opts).unwrap(); let path = build_path_template(&endpoint.path, &endpoint.path_params); let fetch_call: String = if endpoint.returns_binary() { - "this.getBytes(path, { signal, onValue })".to_string() + "this.getBytes(path, { signal, onValue, cache })".to_string() } else if endpoint.returns_json() { - "this.getJson(path, { signal, onValue })".to_string() + "this.getJson(path, { signal, onValue, cache })".to_string() } else if endpoint.response_kind.text_is_numeric() { - "Number(await this.getText(path, { signal, onValue: onValue ? (v) => onValue(Number(v)) : undefined }))".to_string() + "Number(await this.getText(path, { signal, cache, onValue: onValue ? (v) => onValue(Number(v)) : undefined }))".to_string() } else { - "this.getText(path, { signal, onValue })".to_string() + "this.getText(path, { signal, onValue, cache })".to_string() }; write_path_assignment(output, endpoint, &path); @@ -83,7 +83,7 @@ fn generate_get_method(output: &mut String, endpoint: &Endpoint) { if endpoint.supports_csv { writeln!( output, - " if (format === 'csv') return this.getText(path, {{ signal, onValue }});" + " if (format === 'csv') return this.getText(path, {{ signal, onValue, cache }});" ) .unwrap(); } diff --git a/crates/brk_bindgen/src/generators/javascript/client.rs b/crates/brk_bindgen/src/generators/javascript/client.rs index 80744f2eb..b53de54fa 100644 --- a/crates/brk_bindgen/src/generators/javascript/client.rs +++ b/crates/brk_bindgen/src/generators/javascript/client.rs @@ -448,14 +448,17 @@ class BrkClientBase {{ /** * @param {{string}} path - * @param {{{{ signal?: AbortSignal }}}} [options] + * @param {{{{ signal?: AbortSignal, cache?: boolean }}}} [options] * @returns {{Promise}} */ - async get(path, {{ signal }} = {{}}) {{ + async get(path, {{ signal, cache = true }} = {{}}) {{ const url = `${{this.baseUrl}}${{path}}`; const signals = [AbortSignal.timeout(this.timeout)]; if (signal) signals.push(signal); - const res = await fetch(url, {{ signal: AbortSignal.any(signals) }}); + /** @type {{RequestInit}} */ + const init = {{ signal: AbortSignal.any(signals) }}; + if (!cache) init.cache = 'no-store'; + const res = await fetch(url, init); if (!res.ok) throw new BrkError(`HTTP ${{res.status}}: ${{url}}`, res.status); return res; }} @@ -475,10 +478,17 @@ class BrkClientBase {{ * @template T * @param {{string}} path * @param {{(res: Response) => Promise}} parse - Response body reader - * @param {{{{ onValue?: (value: T) => void, signal?: AbortSignal }}}} [options] + * @param {{{{ onValue?: (value: T) => void, signal?: AbortSignal, cache?: boolean }}}} [options] * @returns {{Promise}} */ - async _getCached(path, parse, {{ onValue, signal }} = {{}}) {{ + async _getCached(path, parse, {{ onValue, signal, cache = true }} = {{}}) {{ + if (!cache) {{ + const res = await this.get(path, {{ signal, cache }}); + const value = await parse(res); + if (onValue) onValue(value); + return value; + }} + const url = `${{this.baseUrl}}${{path}}`; /** @type {{_MemEntry | undefined}} */ const memHit = this._memGet(url); @@ -497,8 +507,8 @@ class BrkClientBase {{ this._memSet(url, netEtag, value); if (onValue) onValue(value); if (cloned && browserCache) {{ - const cache = browserCache; - _runIdle(() => cache.put(url, cloned)); + const cacheStore = browserCache; + _runIdle(() => cacheStore.put(url, cloned)); }} return value; }} catch {{ @@ -531,8 +541,8 @@ class BrkClientBase {{ this._memSet(url, netEtag, value); if (onValue) onValue(value); if (cloned && browserCache) {{ - const cache = browserCache; - _runIdle(() => cache.put(url, cloned)); + const cacheStore = browserCache; + _runIdle(() => cacheStore.put(url, cloned)); }} return value; }} catch (e) {{ @@ -546,7 +556,7 @@ class BrkClientBase {{ * Make a GET request expecting a JSON response. Cached and supports `onValue`. * @template T * @param {{string}} path - * @param {{{{ onValue?: (value: T) => void, signal?: AbortSignal }}}} [options] + * @param {{{{ onValue?: (value: T) => void, signal?: AbortSignal, cache?: boolean }}}} [options] * @returns {{Promise}} */ getJson(path, options) {{ @@ -557,7 +567,7 @@ class BrkClientBase {{ * Make a GET request expecting a text response (text/plain, text/csv, ...). * Cached and supports `onValue`, same as `getJson`. * @param {{string}} path - * @param {{{{ onValue?: (value: string) => void, signal?: AbortSignal }}}} [options] + * @param {{{{ onValue?: (value: string) => void, signal?: AbortSignal, cache?: boolean }}}} [options] * @returns {{Promise}} */ getText(path, options) {{ @@ -568,7 +578,7 @@ class BrkClientBase {{ * Make a GET request expecting binary data (application/octet-stream). * Cached and supports `onValue`, same as `getJson`. * @param {{string}} path - * @param {{{{ onValue?: (value: Uint8Array) => void, signal?: AbortSignal }}}} [options] + * @param {{{{ onValue?: (value: Uint8Array) => void, signal?: AbortSignal, cache?: boolean }}}} [options] * @returns {{Promise}} */ getBytes(path, options) {{ diff --git a/crates/brk_types/src/urpd_aggregation.rs b/crates/brk_types/src/urpd_aggregation.rs index 7ae320585..e2a7c96f4 100644 --- a/crates/brk_types/src/urpd_aggregation.rs +++ b/crates/brk_types/src/urpd_aggregation.rs @@ -6,7 +6,7 @@ use crate::Cents; /// Aggregation strategy for URPD buckets. /// Options: raw (no aggregation), lin200/lin500/lin1000 (linear $200/$500/$1000), -/// log10/log50/log100/log200/log500/log1000 (logarithmic with 10/50/100/200/500/1000 buckets per decade). +/// log10/log50/log100/log200/log500/log1000/log2000 (logarithmic with 10/50/100/200/500/1000/2000 buckets per decade). #[derive( Debug, Display, Clone, Copy, Default, PartialEq, Eq, Deserialize, Serialize, JsonSchema, )] @@ -24,6 +24,7 @@ pub enum UrpdAggregation { Log200, Log500, Log1000, + Log2000, } impl UrpdAggregation { @@ -46,6 +47,7 @@ impl UrpdAggregation { Self::Log200 => Some(200), Self::Log500 => Some(500), Self::Log1000 => Some(1000), + Self::Log2000 => Some(2000), _ => None, } } @@ -64,7 +66,8 @@ impl UrpdAggregation { | Self::Log100 | Self::Log200 | Self::Log500 - | Self::Log1000 => { + | Self::Log1000 + | Self::Log2000 => { if price_cents == Cents::ZERO { return Cents::ZERO; } diff --git a/modules/brk-client/docs/type-aliases/UrpdAggregation.md b/modules/brk-client/docs/type-aliases/UrpdAggregation.md index 6224755ef..8a42ec37b 100644 --- a/modules/brk-client/docs/type-aliases/UrpdAggregation.md +++ b/modules/brk-client/docs/type-aliases/UrpdAggregation.md @@ -6,7 +6,7 @@ # Type Alias: UrpdAggregation -> **UrpdAggregation** = `"raw"` \| `"lin200"` \| `"lin500"` \| `"lin1000"` \| `"log10"` \| `"log50"` \| `"log100"` \| `"log200"` +> **UrpdAggregation** = `"raw"` \| `"lin200"` \| `"lin500"` \| `"lin1000"` \| `"log10"` \| `"log50"` \| `"log100"` \| `"log200"` \| `"log500"` \| `"log1000"` \| `"log2000"` Defined in: [Developer/brk/modules/brk-client/index.js:1354](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L1354) diff --git a/modules/brk-client/index.js b/modules/brk-client/index.js index 3919790a5..94e32d2bc 100644 --- a/modules/brk-client/index.js +++ b/modules/brk-client/index.js @@ -1357,9 +1357,9 @@ on serialization otherwise. /** * Aggregation strategy for URPD buckets. * Options: raw (no aggregation), lin200/lin500/lin1000 (linear $200/$500/$1000), - * log10/log50/log100/log200/log500/log1000 (logarithmic with 10/50/100/200/500/1000 buckets per decade). + * log10/log50/log100/log200/log500/log1000/log2000 (logarithmic with 10/50/100/200/500/1000/2000 buckets per decade). * - * @typedef {("raw"|"lin200"|"lin500"|"lin1000"|"log10"|"log50"|"log100"|"log200"|"log500"|"log1000")} UrpdAggregation + * @typedef {("raw"|"lin200"|"lin500"|"lin1000"|"log10"|"log50"|"log100"|"log200"|"log500"|"log1000"|"log2000")} UrpdAggregation */ /** * A single bucket in a URPD snapshot. @@ -1882,14 +1882,17 @@ class BrkClientBase { /** * @param {string} path - * @param {{ signal?: AbortSignal }} [options] + * @param {{ signal?: AbortSignal, cache?: boolean }} [options] * @returns {Promise} */ - async get(path, { signal } = {}) { + async get(path, { signal, cache = true } = {}) { const url = `${this.baseUrl}${path}`; const signals = [AbortSignal.timeout(this.timeout)]; if (signal) signals.push(signal); - const res = await fetch(url, { signal: AbortSignal.any(signals) }); + /** @type {RequestInit} */ + const init = { signal: AbortSignal.any(signals) }; + if (!cache) init.cache = 'no-store'; + const res = await fetch(url, init); if (!res.ok) throw new BrkError(`HTTP ${res.status}: ${url}`, res.status); return res; } @@ -1909,10 +1912,17 @@ class BrkClientBase { * @template T * @param {string} path * @param {(res: Response) => Promise} parse - Response body reader - * @param {{ onValue?: (value: T) => void, signal?: AbortSignal }} [options] + * @param {{ onValue?: (value: T) => void, signal?: AbortSignal, cache?: boolean }} [options] * @returns {Promise} */ - async _getCached(path, parse, { onValue, signal } = {}) { + async _getCached(path, parse, { onValue, signal, cache = true } = {}) { + if (!cache) { + const res = await this.get(path, { signal, cache }); + const value = await parse(res); + if (onValue) onValue(value); + return value; + } + const url = `${this.baseUrl}${path}`; /** @type {_MemEntry | undefined} */ const memHit = this._memGet(url); @@ -1931,8 +1941,8 @@ class BrkClientBase { this._memSet(url, netEtag, value); if (onValue) onValue(value); if (cloned && browserCache) { - const cache = browserCache; - _runIdle(() => cache.put(url, cloned)); + const cacheStore = browserCache; + _runIdle(() => cacheStore.put(url, cloned)); } return value; } catch { @@ -1965,8 +1975,8 @@ class BrkClientBase { this._memSet(url, netEtag, value); if (onValue) onValue(value); if (cloned && browserCache) { - const cache = browserCache; - _runIdle(() => cache.put(url, cloned)); + const cacheStore = browserCache; + _runIdle(() => cacheStore.put(url, cloned)); } return value; } catch (e) { @@ -1980,7 +1990,7 @@ class BrkClientBase { * Make a GET request expecting a JSON response. Cached and supports `onValue`. * @template T * @param {string} path - * @param {{ onValue?: (value: T) => void, signal?: AbortSignal }} [options] + * @param {{ onValue?: (value: T) => void, signal?: AbortSignal, cache?: boolean }} [options] * @returns {Promise} */ getJson(path, options) { @@ -1991,7 +2001,7 @@ class BrkClientBase { * Make a GET request expecting a text response (text/plain, text/csv, ...). * Cached and supports `onValue`, same as `getJson`. * @param {string} path - * @param {{ onValue?: (value: string) => void, signal?: AbortSignal }} [options] + * @param {{ onValue?: (value: string) => void, signal?: AbortSignal, cache?: boolean }} [options] * @returns {Promise} */ getText(path, options) { @@ -2002,7 +2012,7 @@ class BrkClientBase { * Make a GET request expecting binary data (application/octet-stream). * Cached and supports `onValue`, same as `getJson`. * @param {string} path - * @param {{ onValue?: (value: Uint8Array) => void, signal?: AbortSignal }} [options] + * @param {{ onValue?: (value: Uint8Array) => void, signal?: AbortSignal, cache?: boolean }} [options] * @returns {Promise} */ getBytes(path, options) { @@ -10546,12 +10556,12 @@ class BrkClient extends BrkClientBase { * Liveness probe. Returns server identity, uptime, and indexed/computed heights from local state only (no bitcoind round-trip). For real chain-tip catch-up, see `/api/server/sync`. * * Endpoint: `GET /health` - * @param {{ signal?: AbortSignal, onValue?: (value: Health) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: Health) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getHealth({ signal, onValue } = {}) { + async getHealth({ signal, onValue, cache } = {}) { const path = `/health`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -10560,12 +10570,12 @@ class BrkClient extends BrkClientBase { * Returns the current version of the API server * * Endpoint: `GET /version` - * @param {{ signal?: AbortSignal, onValue?: (value: string) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: string) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getVersion({ signal, onValue } = {}) { + async getVersion({ signal, onValue, cache } = {}) { const path = `/version`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -10574,12 +10584,12 @@ class BrkClient extends BrkClientBase { * Returns the sync status of the indexer, including indexed height, tip height, blocks behind, and last indexed timestamp. * * Endpoint: `GET /api/server/sync` - * @param {{ signal?: AbortSignal, onValue?: (value: SyncStatus) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: SyncStatus) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getSyncStatus({ signal, onValue } = {}) { + async getSyncStatus({ signal, onValue, cache } = {}) { const path = `/api/server/sync`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -10588,12 +10598,12 @@ class BrkClient extends BrkClientBase { * Returns the disk space used by BRK and Bitcoin data. * * Endpoint: `GET /api/server/disk` - * @param {{ signal?: AbortSignal, onValue?: (value: DiskUsage) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: DiskUsage) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getDiskUsage({ signal, onValue } = {}) { + async getDiskUsage({ signal, onValue, cache } = {}) { const path = `/api/server/disk`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -10602,12 +10612,12 @@ class BrkClient extends BrkClientBase { * Returns the complete hierarchical catalog of available series organized as a tree structure. Series are grouped by categories and subcategories. * * Endpoint: `GET /api/series` - * @param {{ signal?: AbortSignal, onValue?: (value: TreeNode) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: TreeNode) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getSeriesTree({ signal, onValue } = {}) { + async getSeriesTree({ signal, onValue, cache } = {}) { const path = `/api/series`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -10616,12 +10626,12 @@ class BrkClient extends BrkClientBase { * Returns the number of series available per index type. * * Endpoint: `GET /api/series/count` - * @param {{ signal?: AbortSignal, onValue?: (value: SeriesCount[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: SeriesCount[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getSeriesCount({ signal, onValue } = {}) { + async getSeriesCount({ signal, onValue, cache } = {}) { const path = `/api/series/count`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -10630,12 +10640,12 @@ class BrkClient extends BrkClientBase { * Returns all available indexes with their accepted query aliases. Use any alias when querying series. * * Endpoint: `GET /api/series/indexes` - * @param {{ signal?: AbortSignal, onValue?: (value: IndexInfo[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: IndexInfo[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getIndexes({ signal, onValue } = {}) { + async getIndexes({ signal, onValue, cache } = {}) { const path = `/api/series/indexes`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -10647,16 +10657,16 @@ class BrkClient extends BrkClientBase { * * @param {number=} [page] - Pagination index * @param {number=} [per_page] - Results per page (default: 1000, max: 1000) - * @param {{ signal?: AbortSignal, onValue?: (value: PaginatedSeries) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: PaginatedSeries) => void, cache?: boolean }} [options] * @returns {Promise} */ - async listSeries(page, per_page, { signal, onValue } = {}) { + async listSeries(page, per_page, { signal, onValue, cache } = {}) { const params = new URLSearchParams(); if (page !== undefined) params.set('page', String(page)); if (per_page !== undefined) params.set('per_page', String(per_page)); const query = params.toString(); const path = `/api/series/list${query ? '?' + query : ''}`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -10668,16 +10678,16 @@ class BrkClient extends BrkClientBase { * * @param {SeriesName} q - Search query string * @param {Limit=} [limit] - Maximum number of results - * @param {{ signal?: AbortSignal, onValue?: (value: string[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: string[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async searchSeries(q, limit, { signal, onValue } = {}) { + async searchSeries(q, limit, { signal, onValue, cache } = {}) { const params = new URLSearchParams(); params.set('q', String(q)); if (limit !== undefined) params.set('limit', String(limit)); const query = params.toString(); const path = `/api/series/search${query ? '?' + query : ''}`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -10688,12 +10698,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/series/{series}` * * @param {SeriesName} series - * @param {{ signal?: AbortSignal, onValue?: (value: SeriesInfo) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: SeriesInfo) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getSeriesInfo(series, { signal, onValue } = {}) { + async getSeriesInfo(series, { signal, onValue, cache } = {}) { const path = `/api/series/${series}`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -10709,10 +10719,10 @@ class BrkClient extends BrkClientBase { * @param {RangeIndex=} [end] - Exclusive end: integer index, date (YYYY-MM-DD), or timestamp (ISO 8601). Negative integers count from end. Aliases: `to`, `t`, `e` * @param {Limit=} [limit] - Maximum number of values to return (ignored if `end` is set). Aliases: `count`, `c`, `l` * @param {Format=} [format] - Format of the output - * @param {{ signal?: AbortSignal, onValue?: (value: AnySeriesData | string) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: AnySeriesData | string) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getSeries(series, index, start, end, limit, format, { signal, onValue } = {}) { + async getSeries(series, index, start, end, limit, format, { signal, onValue, cache } = {}) { const params = new URLSearchParams(); if (start !== undefined) params.set('start', String(start)); if (end !== undefined) params.set('end', String(end)); @@ -10720,8 +10730,8 @@ class BrkClient extends BrkClientBase { if (format !== undefined) params.set('format', String(format)); const query = params.toString(); const path = `/api/series/${series}/${index}${query ? '?' + query : ''}`; - if (format === 'csv') return this.getText(path, { signal, onValue }); - return this.getJson(path, { signal, onValue }); + if (format === 'csv') return this.getText(path, { signal, onValue, cache }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -10737,10 +10747,10 @@ class BrkClient extends BrkClientBase { * @param {RangeIndex=} [end] - Exclusive end: integer index, date (YYYY-MM-DD), or timestamp (ISO 8601). Negative integers count from end. Aliases: `to`, `t`, `e` * @param {Limit=} [limit] - Maximum number of values to return (ignored if `end` is set). Aliases: `count`, `c`, `l` * @param {Format=} [format] - Format of the output - * @param {{ signal?: AbortSignal, onValue?: (value: boolean[] | string) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: boolean[] | string) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getSeriesData(series, index, start, end, limit, format, { signal, onValue } = {}) { + async getSeriesData(series, index, start, end, limit, format, { signal, onValue, cache } = {}) { const params = new URLSearchParams(); if (start !== undefined) params.set('start', String(start)); if (end !== undefined) params.set('end', String(end)); @@ -10748,8 +10758,8 @@ class BrkClient extends BrkClientBase { if (format !== undefined) params.set('format', String(format)); const query = params.toString(); const path = `/api/series/${series}/${index}/data${query ? '?' + query : ''}`; - if (format === 'csv') return this.getText(path, { signal, onValue }); - return this.getJson(path, { signal, onValue }); + if (format === 'csv') return this.getText(path, { signal, onValue, cache }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -10761,12 +10771,12 @@ class BrkClient extends BrkClientBase { * * @param {SeriesName} series - Series name * @param {Index} index - Aggregation index - * @param {{ signal?: AbortSignal, onValue?: (value: *) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: *) => void, cache?: boolean }} [options] * @returns {Promise<*>} */ - async getSeriesLatest(series, index, { signal, onValue } = {}) { + async getSeriesLatest(series, index, { signal, onValue, cache } = {}) { const path = `/api/series/${series}/${index}/latest`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -10778,12 +10788,12 @@ class BrkClient extends BrkClientBase { * * @param {SeriesName} series - Series name * @param {Index} index - Aggregation index - * @param {{ signal?: AbortSignal, onValue?: (value: number) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: number) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getSeriesLen(series, index, { signal, onValue } = {}) { + async getSeriesLen(series, index, { signal, onValue, cache } = {}) { const path = `/api/series/${series}/${index}/len`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -10795,12 +10805,12 @@ class BrkClient extends BrkClientBase { * * @param {SeriesName} series - Series name * @param {Index} index - Aggregation index - * @param {{ signal?: AbortSignal, onValue?: (value: Version) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: Version) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getSeriesVersion(series, index, { signal, onValue } = {}) { + async getSeriesVersion(series, index, { signal, onValue, cache } = {}) { const path = `/api/series/${series}/${index}/version`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -10816,10 +10826,10 @@ class BrkClient extends BrkClientBase { * @param {RangeIndex=} [end] - Exclusive end: integer index, date (YYYY-MM-DD), or timestamp (ISO 8601). Negative integers count from end. Aliases: `to`, `t`, `e` * @param {Limit=} [limit] - Maximum number of values to return (ignored if `end` is set). Aliases: `count`, `c`, `l` * @param {Format=} [format] - Format of the output - * @param {{ signal?: AbortSignal, onValue?: (value: AnySeriesData[] | string) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: AnySeriesData[] | string) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getSeriesBulk(series, index, start, end, limit, format, { signal, onValue } = {}) { + async getSeriesBulk(series, index, start, end, limit, format, { signal, onValue, cache } = {}) { const params = new URLSearchParams(); params.set('series', String(series)); params.set('index', String(index)); @@ -10829,8 +10839,8 @@ class BrkClient extends BrkClientBase { if (format !== undefined) params.set('format', String(format)); const query = params.toString(); const path = `/api/series/bulk${query ? '?' + query : ''}`; - if (format === 'csv') return this.getText(path, { signal, onValue }); - return this.getJson(path, { signal, onValue }); + if (format === 'csv') return this.getText(path, { signal, onValue, cache }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -10839,12 +10849,12 @@ class BrkClient extends BrkClientBase { * Cohorts for which URPD data is available. Returns names like `all`, `sth`, `lth`, `utxos_under_1h_old`. * * Endpoint: `GET /api/urpd` - * @param {{ signal?: AbortSignal, onValue?: (value: Cohort[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: Cohort[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async listUrpdCohorts({ signal, onValue } = {}) { + async listUrpdCohorts({ signal, onValue, cache } = {}) { const path = `/api/urpd`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -10855,12 +10865,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/urpd/{cohort}/dates` * * @param {Cohort} cohort - * @param {{ signal?: AbortSignal, onValue?: (value: Date[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: Date[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async listUrpdDates(cohort, { signal, onValue } = {}) { + async listUrpdDates(cohort, { signal, onValue, cache } = {}) { const path = `/api/urpd/${cohort}/dates`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -10874,15 +10884,15 @@ class BrkClient extends BrkClientBase { * * @param {Cohort} cohort * @param {UrpdAggregation=} [agg] - Aggregation strategy. Default: raw (no aggregation). Accepts `bucket` as alias. - * @param {{ signal?: AbortSignal, onValue?: (value: Urpd) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: Urpd) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getUrpd(cohort, agg, { signal, onValue } = {}) { + async getUrpd(cohort, agg, { signal, onValue, cache } = {}) { const params = new URLSearchParams(); if (agg !== undefined) params.set('agg', String(agg)); const query = params.toString(); const path = `/api/urpd/${cohort}${query ? '?' + query : ''}`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -10897,15 +10907,15 @@ class BrkClient extends BrkClientBase { * @param {Cohort} cohort * @param {string} date * @param {UrpdAggregation=} [agg] - Aggregation strategy. Default: raw (no aggregation). Accepts `bucket` as alias. - * @param {{ signal?: AbortSignal, onValue?: (value: Urpd) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: Urpd) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getUrpdAt(cohort, date, agg, { signal, onValue } = {}) { + async getUrpdAt(cohort, date, agg, { signal, onValue, cache } = {}) { const params = new URLSearchParams(); if (agg !== undefined) params.set('agg', String(agg)); const query = params.toString(); const path = `/api/urpd/${cohort}/${date}${query ? '?' + query : ''}`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -10916,12 +10926,12 @@ class BrkClient extends BrkClientBase { * *[Mempool.space docs](https://mempool.space/docs/api/rest#get-difficulty-adjustment)* * * Endpoint: `GET /api/v1/difficulty-adjustment` - * @param {{ signal?: AbortSignal, onValue?: (value: DifficultyAdjustment) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: DifficultyAdjustment) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getDifficultyAdjustment({ signal, onValue } = {}) { + async getDifficultyAdjustment({ signal, onValue, cache } = {}) { const path = `/api/v1/difficulty-adjustment`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -10932,12 +10942,12 @@ class BrkClient extends BrkClientBase { * *[Mempool.space docs](https://mempool.space/docs/api/rest#get-price)* * * Endpoint: `GET /api/v1/prices` - * @param {{ signal?: AbortSignal, onValue?: (value: Prices) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: Prices) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getPrices({ signal, onValue } = {}) { + async getPrices({ signal, onValue, cache } = {}) { const path = `/api/v1/prices`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -10950,15 +10960,15 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/v1/historical-price` * * @param {Timestamp=} [timestamp] - * @param {{ signal?: AbortSignal, onValue?: (value: HistoricalPrice) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: HistoricalPrice) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getHistoricalPrice(timestamp, { signal, onValue } = {}) { + async getHistoricalPrice(timestamp, { signal, onValue, cache } = {}) { const params = new URLSearchParams(); if (timestamp !== undefined) params.set('timestamp', String(timestamp)); const query = params.toString(); const path = `/api/v1/historical-price${query ? '?' + query : ''}`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -10971,12 +10981,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/address/{address}` * * @param {Addr} address - * @param {{ signal?: AbortSignal, onValue?: (value: AddrStats) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: AddrStats) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getAddress(address, { signal, onValue } = {}) { + async getAddress(address, { signal, onValue, cache } = {}) { const path = `/api/address/${address}`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -10989,12 +10999,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/address/{address}/txs` * * @param {Addr} address - * @param {{ signal?: AbortSignal, onValue?: (value: Transaction[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: Transaction[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getAddressTxs(address, { signal, onValue } = {}) { + async getAddressTxs(address, { signal, onValue, cache } = {}) { const path = `/api/address/${address}/txs`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11007,12 +11017,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/address/{address}/txs/chain` * * @param {Addr} address - * @param {{ signal?: AbortSignal, onValue?: (value: Transaction[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: Transaction[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getAddressConfirmedTxs(address, { signal, onValue } = {}) { + async getAddressConfirmedTxs(address, { signal, onValue, cache } = {}) { const path = `/api/address/${address}/txs/chain`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11026,12 +11036,12 @@ class BrkClient extends BrkClientBase { * * @param {Addr} address * @param {Txid} after_txid - Last txid from the previous page (return transactions strictly older than this) - * @param {{ signal?: AbortSignal, onValue?: (value: Transaction[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: Transaction[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getAddressConfirmedTxsAfter(address, after_txid, { signal, onValue } = {}) { + async getAddressConfirmedTxsAfter(address, after_txid, { signal, onValue, cache } = {}) { const path = `/api/address/${address}/txs/chain/${after_txid}`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11044,12 +11054,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/address/{address}/txs/mempool` * * @param {Addr} address - * @param {{ signal?: AbortSignal, onValue?: (value: Transaction[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: Transaction[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getAddressMempoolTxs(address, { signal, onValue } = {}) { + async getAddressMempoolTxs(address, { signal, onValue, cache } = {}) { const path = `/api/address/${address}/txs/mempool`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11062,12 +11072,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/address/{address}/utxo` * * @param {Addr} address - * @param {{ signal?: AbortSignal, onValue?: (value: Utxo[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: Utxo[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getAddressUtxos(address, { signal, onValue } = {}) { + async getAddressUtxos(address, { signal, onValue, cache } = {}) { const path = `/api/address/${address}/utxo`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11080,12 +11090,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/v1/validate-address/{address}` * * @param {string} address - Bitcoin address to validate (can be any string) - * @param {{ signal?: AbortSignal, onValue?: (value: AddrValidation) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: AddrValidation) => void, cache?: boolean }} [options] * @returns {Promise} */ - async validateAddress(address, { signal, onValue } = {}) { + async validateAddress(address, { signal, onValue, cache } = {}) { const path = `/api/v1/validate-address/${address}`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11098,12 +11108,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/block/{hash}` * * @param {BlockHash} hash - * @param {{ signal?: AbortSignal, onValue?: (value: BlockInfo) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: BlockInfo) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getBlock(hash, { signal, onValue } = {}) { + async getBlock(hash, { signal, onValue, cache } = {}) { const path = `/api/block/${hash}`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11116,12 +11126,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/v1/block/{hash}` * * @param {BlockHash} hash - * @param {{ signal?: AbortSignal, onValue?: (value: BlockInfoV1) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: BlockInfoV1) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getBlockV1(hash, { signal, onValue } = {}) { + async getBlockV1(hash, { signal, onValue, cache } = {}) { const path = `/api/v1/block/${hash}`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11134,12 +11144,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/block/{hash}/header` * * @param {BlockHash} hash - * @param {{ signal?: AbortSignal, onValue?: (value: Hex) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: Hex) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getBlockHeader(hash, { signal, onValue } = {}) { + async getBlockHeader(hash, { signal, onValue, cache } = {}) { const path = `/api/block/${hash}/header`; - return this.getText(path, { signal, onValue }); + return this.getText(path, { signal, onValue, cache }); } /** @@ -11152,12 +11162,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/block-height/{height}` * * @param {Height} height - * @param {{ signal?: AbortSignal, onValue?: (value: BlockHash) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: BlockHash) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getBlockByHeight(height, { signal, onValue } = {}) { + async getBlockByHeight(height, { signal, onValue, cache } = {}) { const path = `/api/block-height/${height}`; - return this.getText(path, { signal, onValue }); + return this.getText(path, { signal, onValue, cache }); } /** @@ -11170,12 +11180,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/v1/mining/blocks/timestamp/{timestamp}` * * @param {Timestamp} timestamp - * @param {{ signal?: AbortSignal, onValue?: (value: BlockTimestamp) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: BlockTimestamp) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getBlockByTimestamp(timestamp, { signal, onValue } = {}) { + async getBlockByTimestamp(timestamp, { signal, onValue, cache } = {}) { const path = `/api/v1/mining/blocks/timestamp/${timestamp}`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11188,12 +11198,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/block/{hash}/raw` * * @param {BlockHash} hash - * @param {{ signal?: AbortSignal, onValue?: (value: Uint8Array) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: Uint8Array) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getBlockRaw(hash, { signal, onValue } = {}) { + async getBlockRaw(hash, { signal, onValue, cache } = {}) { const path = `/api/block/${hash}/raw`; - return this.getBytes(path, { signal, onValue }); + return this.getBytes(path, { signal, onValue, cache }); } /** @@ -11206,12 +11216,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/block/{hash}/status` * * @param {BlockHash} hash - * @param {{ signal?: AbortSignal, onValue?: (value: BlockStatus) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: BlockStatus) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getBlockStatus(hash, { signal, onValue } = {}) { + async getBlockStatus(hash, { signal, onValue, cache } = {}) { const path = `/api/block/${hash}/status`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11222,12 +11232,12 @@ class BrkClient extends BrkClientBase { * *[Mempool.space docs](https://mempool.space/docs/api/rest#get-block-tip-height)* * * Endpoint: `GET /api/blocks/tip/height` - * @param {{ signal?: AbortSignal, onValue?: (value: Height) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: Height) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getBlockTipHeight({ signal, onValue } = {}) { + async getBlockTipHeight({ signal, onValue, cache } = {}) { const path = `/api/blocks/tip/height`; - return Number(await this.getText(path, { signal, onValue: onValue ? (v) => onValue(Number(v)) : undefined })); + return Number(await this.getText(path, { signal, cache, onValue: onValue ? (v) => onValue(Number(v)) : undefined })); } /** @@ -11238,12 +11248,12 @@ class BrkClient extends BrkClientBase { * *[Mempool.space docs](https://mempool.space/docs/api/rest#get-block-tip-hash)* * * Endpoint: `GET /api/blocks/tip/hash` - * @param {{ signal?: AbortSignal, onValue?: (value: BlockHash) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: BlockHash) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getBlockTipHash({ signal, onValue } = {}) { + async getBlockTipHash({ signal, onValue, cache } = {}) { const path = `/api/blocks/tip/hash`; - return this.getText(path, { signal, onValue }); + return this.getText(path, { signal, onValue, cache }); } /** @@ -11257,12 +11267,12 @@ class BrkClient extends BrkClientBase { * * @param {BlockHash} hash - Bitcoin block hash * @param {BlockTxIndex} index - Transaction index within the block (0-based) - * @param {{ signal?: AbortSignal, onValue?: (value: Txid) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: Txid) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getBlockTxid(hash, index, { signal, onValue } = {}) { + async getBlockTxid(hash, index, { signal, onValue, cache } = {}) { const path = `/api/block/${hash}/txid/${index}`; - return this.getText(path, { signal, onValue }); + return this.getText(path, { signal, onValue, cache }); } /** @@ -11275,12 +11285,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/block/{hash}/txids` * * @param {BlockHash} hash - * @param {{ signal?: AbortSignal, onValue?: (value: Txid[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: Txid[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getBlockTxids(hash, { signal, onValue } = {}) { + async getBlockTxids(hash, { signal, onValue, cache } = {}) { const path = `/api/block/${hash}/txids`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11293,12 +11303,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/block/{hash}/txs` * * @param {BlockHash} hash - * @param {{ signal?: AbortSignal, onValue?: (value: Transaction[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: Transaction[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getBlockTxs(hash, { signal, onValue } = {}) { + async getBlockTxs(hash, { signal, onValue, cache } = {}) { const path = `/api/block/${hash}/txs`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11312,12 +11322,12 @@ class BrkClient extends BrkClientBase { * * @param {BlockHash} hash - Bitcoin block hash * @param {BlockTxIndex} start_index - Starting transaction index within the block (0-based) - * @param {{ signal?: AbortSignal, onValue?: (value: Transaction[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: Transaction[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getBlockTxsFromIndex(hash, start_index, { signal, onValue } = {}) { + async getBlockTxsFromIndex(hash, start_index, { signal, onValue, cache } = {}) { const path = `/api/block/${hash}/txs/${start_index}`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11328,12 +11338,12 @@ class BrkClient extends BrkClientBase { * *[Mempool.space docs](https://mempool.space/docs/api/rest#get-blocks)* * * Endpoint: `GET /api/blocks` - * @param {{ signal?: AbortSignal, onValue?: (value: BlockInfo[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: BlockInfo[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getBlocks({ signal, onValue } = {}) { + async getBlocks({ signal, onValue, cache } = {}) { const path = `/api/blocks`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11346,12 +11356,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/blocks/{height}` * * @param {Height} height - * @param {{ signal?: AbortSignal, onValue?: (value: BlockInfo[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: BlockInfo[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getBlocksFromHeight(height, { signal, onValue } = {}) { + async getBlocksFromHeight(height, { signal, onValue, cache } = {}) { const path = `/api/blocks/${height}`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11362,12 +11372,12 @@ class BrkClient extends BrkClientBase { * *[Mempool.space docs](https://mempool.space/docs/api/rest#get-blocks-v1)* * * Endpoint: `GET /api/v1/blocks` - * @param {{ signal?: AbortSignal, onValue?: (value: BlockInfoV1[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: BlockInfoV1[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getBlocksV1({ signal, onValue } = {}) { + async getBlocksV1({ signal, onValue, cache } = {}) { const path = `/api/v1/blocks`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11380,12 +11390,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/v1/blocks/{height}` * * @param {Height} height - * @param {{ signal?: AbortSignal, onValue?: (value: BlockInfoV1[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: BlockInfoV1[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getBlocksV1FromHeight(height, { signal, onValue } = {}) { + async getBlocksV1FromHeight(height, { signal, onValue, cache } = {}) { const path = `/api/v1/blocks/${height}`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11396,12 +11406,12 @@ class BrkClient extends BrkClientBase { * *[Mempool.space docs](https://mempool.space/docs/api/rest#get-mining-pools)* * * Endpoint: `GET /api/v1/mining/pools` - * @param {{ signal?: AbortSignal, onValue?: (value: PoolInfo[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: PoolInfo[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getPools({ signal, onValue } = {}) { + async getPools({ signal, onValue, cache } = {}) { const path = `/api/v1/mining/pools`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11414,12 +11424,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/v1/mining/pools/{time_period}` * * @param {TimePeriod} time_period - * @param {{ signal?: AbortSignal, onValue?: (value: PoolsSummary) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: PoolsSummary) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getPoolStats(time_period, { signal, onValue } = {}) { + async getPoolStats(time_period, { signal, onValue, cache } = {}) { const path = `/api/v1/mining/pools/${time_period}`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11432,12 +11442,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/v1/mining/pool/{slug}` * * @param {PoolSlug} slug - * @param {{ signal?: AbortSignal, onValue?: (value: PoolDetail) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: PoolDetail) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getPool(slug, { signal, onValue } = {}) { + async getPool(slug, { signal, onValue, cache } = {}) { const path = `/api/v1/mining/pool/${slug}`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11448,12 +11458,12 @@ class BrkClient extends BrkClientBase { * *[Mempool.space docs](https://mempool.space/docs/api/rest#get-mining-pool-hashrates)* * * Endpoint: `GET /api/v1/mining/hashrate/pools` - * @param {{ signal?: AbortSignal, onValue?: (value: PoolHashrateEntry[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: PoolHashrateEntry[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getPoolsHashrate({ signal, onValue } = {}) { + async getPoolsHashrate({ signal, onValue, cache } = {}) { const path = `/api/v1/mining/hashrate/pools`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11466,12 +11476,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/v1/mining/hashrate/pools/{time_period}` * * @param {TimePeriod} time_period - * @param {{ signal?: AbortSignal, onValue?: (value: PoolHashrateEntry[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: PoolHashrateEntry[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getPoolsHashrateByPeriod(time_period, { signal, onValue } = {}) { + async getPoolsHashrateByPeriod(time_period, { signal, onValue, cache } = {}) { const path = `/api/v1/mining/hashrate/pools/${time_period}`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11484,12 +11494,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/v1/mining/pool/{slug}/hashrate` * * @param {PoolSlug} slug - * @param {{ signal?: AbortSignal, onValue?: (value: PoolHashrateEntry[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: PoolHashrateEntry[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getPoolHashrate(slug, { signal, onValue } = {}) { + async getPoolHashrate(slug, { signal, onValue, cache } = {}) { const path = `/api/v1/mining/pool/${slug}/hashrate`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11502,12 +11512,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/v1/mining/pool/{slug}/blocks` * * @param {PoolSlug} slug - * @param {{ signal?: AbortSignal, onValue?: (value: BlockInfoV1[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: BlockInfoV1[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getPoolBlocks(slug, { signal, onValue } = {}) { + async getPoolBlocks(slug, { signal, onValue, cache } = {}) { const path = `/api/v1/mining/pool/${slug}/blocks`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11521,12 +11531,12 @@ class BrkClient extends BrkClientBase { * * @param {PoolSlug} slug * @param {Height} height - * @param {{ signal?: AbortSignal, onValue?: (value: BlockInfoV1[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: BlockInfoV1[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getPoolBlocksFrom(slug, height, { signal, onValue } = {}) { + async getPoolBlocksFrom(slug, height, { signal, onValue, cache } = {}) { const path = `/api/v1/mining/pool/${slug}/blocks/${height}`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11537,12 +11547,12 @@ class BrkClient extends BrkClientBase { * *[Mempool.space docs](https://mempool.space/docs/api/rest#get-hashrate)* * * Endpoint: `GET /api/v1/mining/hashrate` - * @param {{ signal?: AbortSignal, onValue?: (value: HashrateSummary) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: HashrateSummary) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getHashrate({ signal, onValue } = {}) { + async getHashrate({ signal, onValue, cache } = {}) { const path = `/api/v1/mining/hashrate`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11555,12 +11565,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/v1/mining/hashrate/{time_period}` * * @param {TimePeriod} time_period - * @param {{ signal?: AbortSignal, onValue?: (value: HashrateSummary) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: HashrateSummary) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getHashrateByPeriod(time_period, { signal, onValue } = {}) { + async getHashrateByPeriod(time_period, { signal, onValue, cache } = {}) { const path = `/api/v1/mining/hashrate/${time_period}`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11571,12 +11581,12 @@ class BrkClient extends BrkClientBase { * *[Mempool.space docs](https://mempool.space/docs/api/rest#get-difficulty-adjustments)* * * Endpoint: `GET /api/v1/mining/difficulty-adjustments` - * @param {{ signal?: AbortSignal, onValue?: (value: DifficultyAdjustmentEntry[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: DifficultyAdjustmentEntry[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getDifficultyAdjustments({ signal, onValue } = {}) { + async getDifficultyAdjustments({ signal, onValue, cache } = {}) { const path = `/api/v1/mining/difficulty-adjustments`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11589,12 +11599,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/v1/mining/difficulty-adjustments/{time_period}` * * @param {TimePeriod} time_period - * @param {{ signal?: AbortSignal, onValue?: (value: DifficultyAdjustmentEntry[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: DifficultyAdjustmentEntry[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getDifficultyAdjustmentsByPeriod(time_period, { signal, onValue } = {}) { + async getDifficultyAdjustmentsByPeriod(time_period, { signal, onValue, cache } = {}) { const path = `/api/v1/mining/difficulty-adjustments/${time_period}`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11607,12 +11617,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/v1/mining/reward-stats/{block_count}` * * @param {number} block_count - Number of recent blocks to include - * @param {{ signal?: AbortSignal, onValue?: (value: RewardStats) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: RewardStats) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getRewardStats(block_count, { signal, onValue } = {}) { + async getRewardStats(block_count, { signal, onValue, cache } = {}) { const path = `/api/v1/mining/reward-stats/${block_count}`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11625,12 +11635,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/v1/mining/blocks/fees/{time_period}` * * @param {TimePeriod} time_period - * @param {{ signal?: AbortSignal, onValue?: (value: BlockFeesEntry[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: BlockFeesEntry[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getBlockFees(time_period, { signal, onValue } = {}) { + async getBlockFees(time_period, { signal, onValue, cache } = {}) { const path = `/api/v1/mining/blocks/fees/${time_period}`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11643,12 +11653,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/v1/mining/blocks/rewards/{time_period}` * * @param {TimePeriod} time_period - * @param {{ signal?: AbortSignal, onValue?: (value: BlockRewardsEntry[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: BlockRewardsEntry[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getBlockRewards(time_period, { signal, onValue } = {}) { + async getBlockRewards(time_period, { signal, onValue, cache } = {}) { const path = `/api/v1/mining/blocks/rewards/${time_period}`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11661,12 +11671,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/v1/mining/blocks/fee-rates/{time_period}` * * @param {TimePeriod} time_period - * @param {{ signal?: AbortSignal, onValue?: (value: BlockFeeRatesEntry[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: BlockFeeRatesEntry[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getBlockFeeRates(time_period, { signal, onValue } = {}) { + async getBlockFeeRates(time_period, { signal, onValue, cache } = {}) { const path = `/api/v1/mining/blocks/fee-rates/${time_period}`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11679,12 +11689,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/v1/mining/blocks/sizes-weights/{time_period}` * * @param {TimePeriod} time_period - * @param {{ signal?: AbortSignal, onValue?: (value: BlockSizesWeights) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: BlockSizesWeights) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getBlockSizesWeights(time_period, { signal, onValue } = {}) { + async getBlockSizesWeights(time_period, { signal, onValue, cache } = {}) { const path = `/api/v1/mining/blocks/sizes-weights/${time_period}`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11695,12 +11705,12 @@ class BrkClient extends BrkClientBase { * *[Mempool.space docs](https://mempool.space/docs/api/rest#get-mempool-blocks-fees)* * * Endpoint: `GET /api/v1/fees/mempool-blocks` - * @param {{ signal?: AbortSignal, onValue?: (value: MempoolBlock[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: MempoolBlock[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getMempoolBlocks({ signal, onValue } = {}) { + async getMempoolBlocks({ signal, onValue, cache } = {}) { const path = `/api/v1/fees/mempool-blocks`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11711,12 +11721,12 @@ class BrkClient extends BrkClientBase { * *[Mempool.space docs](https://mempool.space/docs/api/rest#get-recommended-fees)* * * Endpoint: `GET /api/v1/fees/recommended` - * @param {{ signal?: AbortSignal, onValue?: (value: RecommendedFees) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: RecommendedFees) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getRecommendedFees({ signal, onValue } = {}) { + async getRecommendedFees({ signal, onValue, cache } = {}) { const path = `/api/v1/fees/recommended`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11727,12 +11737,12 @@ class BrkClient extends BrkClientBase { * *[Mempool.space docs](https://mempool.space/docs/api/rest#get-recommended-fees-precise)* * * Endpoint: `GET /api/v1/fees/precise` - * @param {{ signal?: AbortSignal, onValue?: (value: RecommendedFees) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: RecommendedFees) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getPreciseFees({ signal, onValue } = {}) { + async getPreciseFees({ signal, onValue, cache } = {}) { const path = `/api/v1/fees/precise`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11743,12 +11753,12 @@ class BrkClient extends BrkClientBase { * *[Mempool.space docs](https://mempool.space/docs/api/rest#get-mempool)* * * Endpoint: `GET /api/mempool` - * @param {{ signal?: AbortSignal, onValue?: (value: MempoolInfo) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: MempoolInfo) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getMempool({ signal, onValue } = {}) { + async getMempool({ signal, onValue, cache } = {}) { const path = `/api/mempool`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11757,12 +11767,12 @@ class BrkClient extends BrkClientBase { * Returns an opaque hash that changes whenever the projected next block changes. Same value as the mempool ETag. Useful as a freshness/liveness signal: if it stays constant for tens of seconds on a live network, the mempool sync loop has stalled. * * Endpoint: `GET /api/mempool/hash` - * @param {{ signal?: AbortSignal, onValue?: (value: NextBlockHash) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: NextBlockHash) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getMempoolHash({ signal, onValue } = {}) { + async getMempoolHash({ signal, onValue, cache } = {}) { const path = `/api/mempool/hash`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11773,12 +11783,12 @@ class BrkClient extends BrkClientBase { * *[Mempool.space docs](https://mempool.space/docs/api/rest#get-mempool-transaction-ids)* * * Endpoint: `GET /api/mempool/txids` - * @param {{ signal?: AbortSignal, onValue?: (value: Txid[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: Txid[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getMempoolTxids({ signal, onValue } = {}) { + async getMempoolTxids({ signal, onValue, cache } = {}) { const path = `/api/mempool/txids`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11789,12 +11799,12 @@ class BrkClient extends BrkClientBase { * *[Mempool.space docs](https://mempool.space/docs/api/rest#get-mempool-recent)* * * Endpoint: `GET /api/mempool/recent` - * @param {{ signal?: AbortSignal, onValue?: (value: MempoolRecentTx[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: MempoolRecentTx[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getMempoolRecent({ signal, onValue } = {}) { + async getMempoolRecent({ signal, onValue, cache } = {}) { const path = `/api/mempool/recent`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11805,12 +11815,12 @@ class BrkClient extends BrkClientBase { * *[Mempool.space docs](https://mempool.space/docs/api/rest#get-replacements)* * * Endpoint: `GET /api/v1/replacements` - * @param {{ signal?: AbortSignal, onValue?: (value: ReplacementNode[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: ReplacementNode[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getReplacements({ signal, onValue } = {}) { + async getReplacements({ signal, onValue, cache } = {}) { const path = `/api/v1/replacements`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11821,12 +11831,12 @@ class BrkClient extends BrkClientBase { * *[Mempool.space docs](https://mempool.space/docs/api/rest#get-fullrbf-replacements)* * * Endpoint: `GET /api/v1/fullrbf/replacements` - * @param {{ signal?: AbortSignal, onValue?: (value: ReplacementNode[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: ReplacementNode[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getFullrbfReplacements({ signal, onValue } = {}) { + async getFullrbfReplacements({ signal, onValue, cache } = {}) { const path = `/api/v1/fullrbf/replacements`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11835,12 +11845,12 @@ class BrkClient extends BrkClientBase { * Bitcoin Core's `getblocktemplate` selection: full transaction bodies in GBT order with aggregate stats. The returned `hash` is an opaque content token; pass it as `` on `/api/v1/mempool/block-template/diff/{hash}` to fetch deltas instead of refetching the whole template. * * Endpoint: `GET /api/v1/mempool/block-template` - * @param {{ signal?: AbortSignal, onValue?: (value: BlockTemplate) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: BlockTemplate) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getBlockTemplate({ signal, onValue } = {}) { + async getBlockTemplate({ signal, onValue, cache } = {}) { const path = `/api/v1/mempool/block-template`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11851,12 +11861,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/v1/mempool/block-template/diff/{hash}` * * @param {NextBlockHash} hash - * @param {{ signal?: AbortSignal, onValue?: (value: BlockTemplateDiff) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: BlockTemplateDiff) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getBlockTemplateDiff(hash, { signal, onValue } = {}) { + async getBlockTemplateDiff(hash, { signal, onValue, cache } = {}) { const path = `/api/v1/mempool/block-template/diff/${hash}`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11865,12 +11875,12 @@ class BrkClient extends BrkClientBase { * Returns the current BTC/USD price in dollars, derived from on-chain round-dollar output patterns in the last 12 blocks plus mempool. * * Endpoint: `GET /api/mempool/price` - * @param {{ signal?: AbortSignal, onValue?: (value: Dollars) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: Dollars) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getLivePrice({ signal, onValue } = {}) { + async getLivePrice({ signal, onValue, cache } = {}) { const path = `/api/mempool/price`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11879,12 +11889,12 @@ class BrkClient extends BrkClientBase { * Current BTC/USD price in dollars. Same value as `/api/mempool/price`. Confirmed per-height history is available at `/api/vecs/height-to-price`. * * Endpoint: `GET /api/oracle/price` - * @param {{ signal?: AbortSignal, onValue?: (value: Dollars) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: Dollars) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getOraclePrice({ signal, onValue } = {}) { + async getOraclePrice({ signal, onValue, cache } = {}) { const path = `/api/oracle/price`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11893,12 +11903,12 @@ class BrkClient extends BrkClientBase { * Live smoothed histogram of oracle-eligible payment outputs, binned by output value on the oracle log scale. It combines the committed oracle window with the forming mempool block. A flat array of log-scale bins. * * Endpoint: `GET /api/oracle/histogram/payments/live` - * @param {{ signal?: AbortSignal, onValue?: (value: number[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: number[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getOracleHistogramPaymentsLive({ signal, onValue } = {}) { + async getOracleHistogramPaymentsLive({ signal, onValue, cache } = {}) { const path = `/api/oracle/histogram/payments/live`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11909,12 +11919,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/oracle/histogram/payments/{point}` * * @param {string} point - * @param {{ signal?: AbortSignal, onValue?: (value: number[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: number[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getOracleHistogramPayments(point, { signal, onValue } = {}) { + async getOracleHistogramPayments(point, { signal, onValue, cache } = {}) { const path = `/api/oracle/histogram/payments/${point}`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11923,12 +11933,12 @@ class BrkClient extends BrkClientBase { * Live unfiltered output value histogram for the forming mempool block. Every live output is binned by value on the oracle log scale; no oracle payment filters are applied. A flat array of log-scale bins, all zero when no mempool is configured. * * Endpoint: `GET /api/oracle/histogram/outputs/live` - * @param {{ signal?: AbortSignal, onValue?: (value: number[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: number[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getOracleHistogramOutputsLive({ signal, onValue } = {}) { + async getOracleHistogramOutputsLive({ signal, onValue, cache } = {}) { const path = `/api/oracle/histogram/outputs/live`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11939,12 +11949,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/oracle/histogram/outputs/{point}` * * @param {string} point - * @param {{ signal?: AbortSignal, onValue?: (value: number[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: number[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getOracleHistogramOutputs(point, { signal, onValue } = {}) { + async getOracleHistogramOutputs(point, { signal, onValue, cache } = {}) { const path = `/api/oracle/histogram/outputs/${point}`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11955,12 +11965,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/tx-index/{index}` * * @param {TxIndex} index - * @param {{ signal?: AbortSignal, onValue?: (value: Txid) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: Txid) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getTxByIndex(index, { signal, onValue } = {}) { + async getTxByIndex(index, { signal, onValue, cache } = {}) { const path = `/api/tx-index/${index}`; - return this.getText(path, { signal, onValue }); + return this.getText(path, { signal, onValue, cache }); } /** @@ -11973,12 +11983,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/v1/cpfp/{txid}` * * @param {Txid} txid - * @param {{ signal?: AbortSignal, onValue?: (value: CpfpInfo) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: CpfpInfo) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getCpfp(txid, { signal, onValue } = {}) { + async getCpfp(txid, { signal, onValue, cache } = {}) { const path = `/api/v1/cpfp/${txid}`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -11991,12 +12001,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/v1/tx/{txid}/rbf` * * @param {Txid} txid - * @param {{ signal?: AbortSignal, onValue?: (value: RbfResponse) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: RbfResponse) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getTxRbf(txid, { signal, onValue } = {}) { + async getTxRbf(txid, { signal, onValue, cache } = {}) { const path = `/api/v1/tx/${txid}/rbf`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -12009,12 +12019,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/tx/{txid}` * * @param {Txid} txid - * @param {{ signal?: AbortSignal, onValue?: (value: Transaction) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: Transaction) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getTx(txid, { signal, onValue } = {}) { + async getTx(txid, { signal, onValue, cache } = {}) { const path = `/api/tx/${txid}`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -12027,12 +12037,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/tx/{txid}/hex` * * @param {Txid} txid - * @param {{ signal?: AbortSignal, onValue?: (value: Hex) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: Hex) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getTxHex(txid, { signal, onValue } = {}) { + async getTxHex(txid, { signal, onValue, cache } = {}) { const path = `/api/tx/${txid}/hex`; - return this.getText(path, { signal, onValue }); + return this.getText(path, { signal, onValue, cache }); } /** @@ -12045,12 +12055,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/tx/{txid}/merkleblock-proof` * * @param {Txid} txid - * @param {{ signal?: AbortSignal, onValue?: (value: Hex) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: Hex) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getTxMerkleblockProof(txid, { signal, onValue } = {}) { + async getTxMerkleblockProof(txid, { signal, onValue, cache } = {}) { const path = `/api/tx/${txid}/merkleblock-proof`; - return this.getText(path, { signal, onValue }); + return this.getText(path, { signal, onValue, cache }); } /** @@ -12063,12 +12073,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/tx/{txid}/merkle-proof` * * @param {Txid} txid - * @param {{ signal?: AbortSignal, onValue?: (value: MerkleProof) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: MerkleProof) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getTxMerkleProof(txid, { signal, onValue } = {}) { + async getTxMerkleProof(txid, { signal, onValue, cache } = {}) { const path = `/api/tx/${txid}/merkle-proof`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -12082,12 +12092,12 @@ class BrkClient extends BrkClientBase { * * @param {Txid} txid - Transaction ID * @param {Vout} vout - Output index - * @param {{ signal?: AbortSignal, onValue?: (value: TxOutspend) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: TxOutspend) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getTxOutspend(txid, vout, { signal, onValue } = {}) { + async getTxOutspend(txid, vout, { signal, onValue, cache } = {}) { const path = `/api/tx/${txid}/outspend/${vout}`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -12100,12 +12110,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/tx/{txid}/outspends` * * @param {Txid} txid - * @param {{ signal?: AbortSignal, onValue?: (value: TxOutspend[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: TxOutspend[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getTxOutspends(txid, { signal, onValue } = {}) { + async getTxOutspends(txid, { signal, onValue, cache } = {}) { const path = `/api/tx/${txid}/outspends`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -12118,12 +12128,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/tx/{txid}/raw` * * @param {Txid} txid - * @param {{ signal?: AbortSignal, onValue?: (value: Uint8Array) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: Uint8Array) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getTxRaw(txid, { signal, onValue } = {}) { + async getTxRaw(txid, { signal, onValue, cache } = {}) { const path = `/api/tx/${txid}/raw`; - return this.getBytes(path, { signal, onValue }); + return this.getBytes(path, { signal, onValue, cache }); } /** @@ -12136,12 +12146,12 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/tx/{txid}/status` * * @param {Txid} txid - * @param {{ signal?: AbortSignal, onValue?: (value: TxStatus) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: TxStatus) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getTxStatus(txid, { signal, onValue } = {}) { + async getTxStatus(txid, { signal, onValue, cache } = {}) { const path = `/api/tx/${txid}/status`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -12154,15 +12164,15 @@ class BrkClient extends BrkClientBase { * Endpoint: `GET /api/v1/transaction-times` * * @param {Txid[]} txId - Transaction IDs to look up (max 250 per request). - * @param {{ signal?: AbortSignal, onValue?: (value: number[]) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: number[]) => void, cache?: boolean }} [options] * @returns {Promise} */ - async getTransactionTimes(txId, { signal, onValue } = {}) { + async getTransactionTimes(txId, { signal, onValue, cache } = {}) { const params = new URLSearchParams(); for (const _v of txId) params.append('txId[]', String(_v)); const query = params.toString(); const path = `/api/v1/transaction-times${query ? '?' + query : ''}`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } /** @@ -12189,12 +12199,12 @@ class BrkClient extends BrkClientBase { * Full OpenAPI 3.1 specification for this API. * * Endpoint: `GET /openapi.json` - * @param {{ signal?: AbortSignal, onValue?: (value: *) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: *) => void, cache?: boolean }} [options] * @returns {Promise<*>} */ - async getOpenapi({ signal, onValue } = {}) { + async getOpenapi({ signal, onValue, cache } = {}) { const path = `/openapi.json`; - return this.getText(path, { signal, onValue }); + return this.getText(path, { signal, onValue, cache }); } /** @@ -12203,12 +12213,12 @@ class BrkClient extends BrkClientBase { * Compact OpenAPI specification optimized for LLM consumption. Removes redundant fields while preserving essential API information. Full spec available at `/openapi.json`. * * Endpoint: `GET /api.json` - * @param {{ signal?: AbortSignal, onValue?: (value: *) => void }} [options] + * @param {{ signal?: AbortSignal, onValue?: (value: *) => void, cache?: boolean }} [options] * @returns {Promise<*>} */ - async getApi({ signal, onValue } = {}) { + async getApi({ signal, onValue, cache } = {}) { const path = `/api.json`; - return this.getJson(path, { signal, onValue }); + return this.getJson(path, { signal, onValue, cache }); } } diff --git a/packages/brk_client/brk_client/__init__.py b/packages/brk_client/brk_client/__init__.py index cfe584f38..036c83648 100644 --- a/packages/brk_client/brk_client/__init__.py +++ b/packages/brk_client/brk_client/__init__.py @@ -144,8 +144,8 @@ CoinbaseTag = str CostBasisValue = Literal["supply", "realized", "unrealized"] # Aggregation strategy for URPD buckets. # Options: raw (no aggregation), lin200/lin500/lin1000 (linear $200/$500/$1000), -# log10/log50/log100/log200/log500/log1000 (logarithmic with 10/50/100/200/500/1000 buckets per decade). -UrpdAggregation = Literal["raw", "lin200", "lin500", "lin1000", "log10", "log50", "log100", "log200", "log500", "log1000"] +# log10/log50/log100/log200/log500/log1000/log2000 (logarithmic with 10/50/100/200/500/1000/2000 buckets per decade). +UrpdAggregation = Literal["raw", "lin200", "lin500", "lin1000", "log10", "log50", "log100", "log200", "log500", "log1000", "log2000"] # Position of a transaction inside a `CpfpCluster.txs` array. Cluster-local, # has no meaning outside the enclosing cluster. CpfpClusterTxIndex = int diff --git a/website/scripts/_types.js b/website/scripts/_types.js index 511ff1a67..098c1b9ec 100644 --- a/website/scripts/_types.js +++ b/website/scripts/_types.js @@ -2,7 +2,7 @@ * @import { IChartApi, ISeriesApi as _ISeriesApi, SeriesDefinition, SingleValueData as _SingleValueData, CandlestickData as _CandlestickData, BaselineData as _BaselineData, HistogramData as _HistogramData, SeriesType as LCSeriesType, IPaneApi, LineSeriesPartialOptions as _LineSeriesPartialOptions, HistogramSeriesPartialOptions as _HistogramSeriesPartialOptions, BaselineSeriesPartialOptions as _BaselineSeriesPartialOptions, CandlestickSeriesPartialOptions as _CandlestickSeriesPartialOptions, WhitespaceData, DeepPartial, ChartOptions, Time, LineData as _LineData, createChart as CreateLCChart, LineStyle, createSeriesMarkers as CreateSeriesMarkers, SeriesMarker, ISeriesMarkersPluginApi } from './modules/lightweight-charts/5.2.0/dist/typings.js' * * @import * as Brk from "./modules/brk-client/index.js" - * @import { BrkClient, Index, SeriesData } from "./modules/brk-client/index.js" + * @import { BrkClient, Index, SeriesData, Urpd } from "./modules/brk-client/index.js" * * @import { Options } from './options/full.js' * diff --git a/website/scripts/options/partial.js b/website/scripts/options/partial.js index c41f41883..31044dfdd 100644 --- a/website/scripts/options/partial.js +++ b/website/scripts/options/partial.js @@ -30,6 +30,7 @@ import { oracleOutputsHeatmapOption, oraclePaymentsHeatmapOption, } from "../../src/heatmap/oracle.js"; +import { urpdSupplyHeatmapOption } from "../../src/heatmap/urpd.js"; // Re-export types for external consumers export * from "./types.js"; @@ -309,6 +310,10 @@ export function createPartialOptions() { name: "oracle histograms", tree: [oracleOutputsHeatmapOption, oraclePaymentsHeatmapOption], }, + { + name: "URPD", + tree: [urpdSupplyHeatmapOption], + }, ], }, diff --git a/website/src/heatmap/tooltip/index.js b/website/src/heatmap/tooltip/index.js index 14c29c810..e4ab2e1ec 100644 --- a/website/src/heatmap/tooltip/index.js +++ b/website/src/heatmap/tooltip/index.js @@ -4,11 +4,13 @@ import { numberToShortUSFormat } from "../../../scripts/utils/format.js"; * @param {Object} [args] * @param {string} [args.valueLabel] * @param {string} [args.averageLabel] + * @param {(value: number) => string} [args.formatValue] * @returns {HeatmapTooltipFn} */ export function defaultTooltip({ valueLabel = "Value", averageLabel = "Avg value", + formatValue = formatNumber, } = {}) { return ({ option, grid, col, row }) => { const dateRange = grid.getDateIndexRange(col); @@ -25,7 +27,7 @@ export function defaultTooltip({ return [ date, `${capitalize(yLabel)}: ${formatY(yRange.start)} to ${formatY(yRange.end)}`, - `${label}: ${formatNumber(value)}`, + `${label}: ${formatValue(value)}`, ].join("\n"); }; } diff --git a/website/src/heatmap/urpd.js b/website/src/heatmap/urpd.js new file mode 100644 index 000000000..b75735323 --- /dev/null +++ b/website/src/heatmap/urpd.js @@ -0,0 +1,149 @@ +import { brk } from "../../scripts/utils/client.js"; +import { numberToShortUSFormat } from "../../scripts/utils/format.js"; +import { createAverageGrid } from "./grid.js"; +import { INFERNO_LUT, logIntensityColor } from "./lut.js"; +import { defaultTooltip } from "./tooltip/index.js"; + +const COHORT = "all"; +const AGGREGATION = "raw"; +const MIN_LOG = -2; +const MAX_LOG = 6; +const DEFAULT_MIN_LOG = Math.log10(1_000); +const DEFAULT_MAX_LOG = Math.log10(250_000); +const PRICE_CHOICES = [ + { label: "$0.01", value: Math.log10(0.01) }, + { label: "$0.1", value: Math.log10(0.1) }, + { label: "$1", value: 0 }, + { label: "$10", value: 1 }, + { label: "$100", value: 2 }, + { label: "$250", value: Math.log10(250) }, + { label: "$1k", value: Math.log10(1_000) }, + { label: "$2.5k", value: Math.log10(2_500) }, + { label: "$5k", value: Math.log10(5_000) }, + { label: "$10k", value: Math.log10(10_000) }, + { label: "$25k", value: Math.log10(25_000) }, + { label: "$50k", value: Math.log10(50_000) }, + { label: "$100k", value: Math.log10(100_000) }, + { label: "$250k", value: Math.log10(250_000) }, + { label: "$500k", value: Math.log10(500_000) }, + { label: "$1M", value: Math.log10(1_000_000) }, +]; + +/** @satisfies {PartialHeatmapOption} */ +export const urpdSupplyHeatmapOption = { + kind: "heatmap", + name: "Supply", + title: "URPD Supply", + points: { + fetch: (date, signal, onPoints) => + fetchUrpdSupplyPoints(date, signal, onPoints), + }, + grid: createAverageGrid({ + yMin: MIN_LOG, + yMax: MAX_LOG, + }), + color: logIntensityColor(INFERNO_LUT), + axis: { + y: { + label: "price", + choices: PRICE_CHOICES, + format: formatPrice, + }, + }, + defaults: { + from: "2017", + to: "today", + yMin: DEFAULT_MIN_LOG, + yMax: DEFAULT_MAX_LOG, + }, + tooltip: defaultTooltip({ + valueLabel: "Supply", + averageLabel: "Avg supply", + formatValue: formatBitcoin, + }), +}; + +/** + * @param {string} date + * @param {AbortSignal} signal + * @param {(points: HeatmapPoints) => void} [onPoints] + * @returns {Promise} + */ +async function fetchUrpdSupplyPoints(date, signal, onPoints) { + /** @type {HeatmapPoints | undefined} */ + let points; + const urpd = await brk.getUrpdAt(COHORT, date, AGGREGATION, { + signal, + cache: false, + onValue: onPoints + ? (value) => { + points = toSupplyPoints(value); + onPoints(points); + } + : undefined, + }); + + return points ?? toSupplyPoints(urpd); +} + +/** + * @param {Urpd} urpd + * @returns {HeatmapPoints} + */ +function toSupplyPoints(urpd) { + const buckets = urpd.buckets; + const y = new Float64Array(buckets.length); + const values = new Float64Array(buckets.length); + let length = 0; + + for (let i = 0; i < buckets.length; i++) { + const bucket = buckets[i]; + if (bucket.priceFloor <= 0 || !Number.isFinite(bucket.supply)) continue; + y[length] = Math.log10(bucket.priceFloor); + values[length] = bucket.supply; + length++; + } + + return { + kind: "explicit", + y: y.subarray(0, length), + values: values.subarray(0, length), + }; +} + +/** @param {number} value */ +function formatPrice(value) { + const rounded = Math.round(value); + if (Math.abs(value - rounded) < 0.001) { + const choice = PRICE_CHOICES.find((choice) => choice.value === rounded); + if (choice) return choice.label; + } + + const price = 10 ** value; + if (price >= 1_000_000) return `$${formatCompact(price / 1_000_000)}M`; + if (price >= 1_000) return `$${formatCompact(price / 1_000)}k`; + return `$${formatCompact(price)}`; +} + +/** @param {number} value */ +function formatBitcoin(value) { + return `${numberToShortUSFormat(value)} BTC`; +} + +/** @param {number} value */ +function formatCompact(value) { + if (value >= 1000) return `${formatNumber(value / 1000)}k`; + return formatNumber(value); +} + +/** @param {number} value */ +function formatNumber(value) { + if (value >= 100) return String(Math.round(value)); + if (value >= 10) return trimNumber(value.toFixed(1)); + return trimNumber(value.toFixed(2)); +} + +/** @param {string} value */ +function trimNumber(value) { + return value.replace(/\.?0+$/, ""); +}