// Generated, do not edit. sha256:f1a362d8f5a38865a6fcd067548c9a9a2cf682e9141ad905ab0415dc770a62a9 import { CONFIG } from '../../shared/config.js'; import { activeConnection } from '../data/connections.js'; import { t } from '../i18n/index.js'; export async function explorerBase() { return (await activeConnection('btc_explorer')).url; } const HTTP_TIMEOUT_MS = 12000; const HTTP_BACKOFF_MS = [2000, 5000, 10000]; export async function fetchJson(url, label, options = {}) { let laatste; for (let poging = 0; poging <= HTTP_BACKOFF_MS.length; poging++) { if (poging) await new Promise(r => setTimeout(r, HTTP_BACKOFF_MS[poging - 1])); const ctrl = new AbortController(); const timer = setTimeout(() => ctrl.abort(), HTTP_TIMEOUT_MS); try { const res = await fetch(url, { ...options, signal: ctrl.signal }); if (res.ok) return await res.json(); laatste = new Error(t('integrations.price.callFailed', { label, status: res.status })); if (res.status < 500 && res.status !== 429) throw laatste; } catch (e) { if (e === laatste) throw e; laatste = e.name === 'AbortError' ? new Error(t('integrations.price.callTimeout', { label, s: HTTP_TIMEOUT_MS / 1000 })) : e; } finally { clearTimeout(timer); } } throw laatste; } export async function addressInfo(addr) { const base = await explorerBase(); const d = await fetchJson(`${base}/api/address/${addr}`, t('integrations.price.labelAddress', { adres: addr })); const balance_sats = d.chain_stats.funded_txo_sum - d.chain_stats.spent_txo_sum; const tx_count = d.chain_stats.tx_count + d.mempool_stats.tx_count; return { balance_sats, tx_count }; } const PAGE = 25; const MAX_PAGES = 200; const lastConfirmedTxid = batch => { for (let i = batch.length - 1; i >= 0; i--) { if (batch[i].status && batch[i].status.confirmed) return batch[i].txid; } return null; }; export async function addressTxs(addr) { const base = await explorerBase(); const all = await fetchJson(`${base}/api/address/${addr}/txs`, t('integrations.price.labelAddressTxs', { adres: addr })); let cursor = lastConfirmedTxid(all); let pages = 0; while (cursor && pages < MAX_PAGES) { await new Promise(r => setTimeout(r, 150)); let batch; try { batch = await fetchJson(`${base}/api/address/${addr}/txs/chain/${cursor}`, t('integrations.price.labelAddressTxsPage')); } catch (e) { console.warn(`[addressTxs] pagination stopped for ${addr}: ${e.message}`); break; } if (!batch.length) break; all.push(...batch); if (batch.length < PAGE) break; cursor = batch[batch.length - 1].txid; pages++; } return all; }