@qbit-oss/api 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +467 -2
- package/lib/index.d.mts +551 -0
- package/lib/index.d.ts +551 -0
- package/lib/index.js +1921 -0
- package/lib/index.js.map +1 -0
- package/lib/index.mjs +1889 -0
- package/lib/index.mjs.map +1 -0
- package/package.json +61 -4
- package/src/index.ts +3069 -0
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// @qbit-oss/api — typed esplora (electrs) REST client for qbit.\n//\n// Speaks the standard esplora REST surface directly (no facade), against a\n// configurable per-chain base URL. Deliberately carries NONE of the legacy\n// centralized surface: no asset/token endpoints, no remote wallet config, and\n// no device-id / channel / client telemetry headers. The test suite enforces\n// this by construction (see the guard in test/).\n\nimport { sha256 } from '@noble/hashes/sha256'\n\n// ---------------------------------------------------------------------------\n// Esplora response types\n// ---------------------------------------------------------------------------\n\nexport interface EsploraChainStats {\n funded_txo_count: number\n funded_txo_sum: number\n spent_txo_count: number\n spent_txo_sum: number\n tx_count: number\n}\n\nexport interface EsploraAddressStats {\n address: string\n chain_stats: EsploraChainStats\n mempool_stats: EsploraChainStats\n}\n\nexport interface EsploraTxStatus {\n confirmed: boolean\n block_height?: number\n block_hash?: string\n block_time?: number\n}\n\nexport interface EsploraUtxo {\n txid: string\n vout: number\n value: number\n status: EsploraTxStatus\n}\n\nexport interface EsploraVin {\n txid: string\n vout: number\n prevout: EsploraVout | null\n scriptsig: string\n scriptsig_asm: string\n witness?: string[]\n is_coinbase: boolean\n sequence: number\n}\n\nexport interface EsploraVout {\n scriptpubkey: string\n scriptpubkey_asm: string\n scriptpubkey_type: string\n scriptpubkey_address?: string\n value: number\n}\n\nexport interface EsploraTx {\n txid: string\n version: number\n locktime: number\n vin: EsploraVin[]\n vout: EsploraVout[]\n size: number\n weight: number\n fee: number\n status: EsploraTxStatus\n}\n\n/** esplora returns `{ \"<target_blocks>\": <sat/vB> }`, e.g. `{ \"1\": 12.3, \"6\": 4.1 }`. */\nexport type EsploraFeeEstimates = Record<string, number>\n\n/**\n * mempool-qbit retains mempool's field names, but the first three values come\n * from projected blocks 1, 2, and 3. Economy and minimum are policy floors,\n * not confirmation-target estimates.\n */\nexport interface MempoolRecommendedFees {\n fastestFee: number\n halfHourFee: number\n hourFee: number\n economyFee: number\n minimumFee: number\n}\n\nexport interface AddressHistory {\n confirmed: EsploraTx[]\n mempool: EsploraTx[]\n}\n\n/**\n * Per-call cancellation and time budget. Both cover every dependent request of\n * the call — pagination, retries, backoff, and response-body reads.\n */\nexport interface RequestOptions {\n /**\n * Aborting rejects the call with an `aborted` `QbitApiError` and stops further\n * requests (`unknown_outcome` from `broadcastTx` once its POST may have been sent).\n */\n signal?: AbortSignal\n /**\n * Overall budget for the call in ms; exceeding it rejects with a `timeout`\n * `QbitApiError` (`unknown_outcome` from `broadcastTx` once its POST may have been sent).\n */\n deadlineMs?: number\n}\n\nexport interface AddressHistoryOptions extends RequestOptions {\n /**\n * Maximum history page fetches for the whole call, including the terminal\n * empty response and a rescan (default 256). The address-stats reads are not\n * page fetches, nor is `EsploraClient`'s `/txs/mempool` fetch.\n */\n maxPages?: number\n /**\n * Maximum raw transaction rows accepted for the whole call, a rescan\n * included, before failing closed (default 6,400).\n */\n maxTransactions?: number\n}\n\nexport interface BroadcastTxOptions extends RequestOptions {\n /**\n * Transaction id (64 hex characters) of `rawTxHex`. Derived from the hex when\n * omitted; when both are available they must agree.\n */\n txid?: string\n}\n\n// ---------------------------------------------------------------------------\n// Error taxonomy (user-presentable)\n// ---------------------------------------------------------------------------\n\nexport type QbitApiErrorKind =\n | 'rate_limit' // HTTP 429\n | 'payload_too_large' // HTTP 413\n | 'not_found' // HTTP 404\n | 'http' // other non-2xx\n | 'network' // fetch threw (offline / DNS / CORS)\n | 'timeout' // request or call deadline expired\n | 'aborted' // caller's AbortSignal fired\n | 'parse' // body was not the expected JSON/text\n | 'pagination_limit' // history scan exceeded its configured page or transaction bound\n | 'invalid_cursor' // an address-history scan could not be shown complete; retry it\n | 'unknown_outcome' // a submission may have reached the node; check the txid before resubmitting\n\nexport interface QbitApiErrorOptions {\n status?: number\n url?: string\n cause?: unknown\n /**\n * The underlying error before redaction. It is kept off the error object:\n * read it with `QbitApiError.unredactedCause(error)`.\n */\n unredactedCause?: unknown\n retryAfterMs?: number\n /**\n * Trimmed response body preview, capped at 200 characters. Errors the client\n * creates redact the base URL from it as they do in `message`.\n */\n responseBody?: string\n /** Transaction id of the submission an `unknown_outcome` error refers to, when known. */\n txid?: string\n}\n\n/** Underlying errors before redaction, by the `QbitApiError` that carries their redacted copy. */\nconst unredactedCauses = new WeakMap<object, unknown>()\n\n/** Brand shared by every copy of this class: `Symbol.for` keys are global across builds and realms. */\nconst QBIT_API_ERROR_BRAND = Symbol.for('qbit-js.QbitApiError')\n\nexport class QbitApiError extends Error {\n readonly kind: QbitApiErrorKind\n readonly status?: number\n readonly url?: string\n readonly retryAfterMs?: number\n /**\n * The underlying error. Errors the client creates attach a redacted copy,\n * safe to log: see `QbitApiError.unredactedCause`.\n */\n readonly cause?: unknown\n readonly responseBody?: string\n readonly txid?: string\n\n /**\n * The underlying error of `error` as the fetch implementation threw it, or\n * undefined. Its message, stack and properties can contain the full request\n * URL, base-URL secrets included, so it is kept off the error object, where\n * no logger, error reporter or serializer can reach it. Do not log it where\n * the base URL is secret.\n */\n static unredactedCause(error: unknown): unknown {\n return typeof error === 'object' && error !== null ? unredactedCauses.get(error) : undefined\n }\n\n /**\n * Whether `value` is a `QbitApiError` (or a subclass instance) from any copy\n * of `@qbit-oss/api`. `instanceof` only recognizes errors from the same copy,\n * so it is false when an app loads both the CommonJS and the ESM build (or\n * two installed versions) and the error comes from the other one. This checks\n * a brand, `Symbol.for('qbit-js.QbitApiError')`, set on the class prototype\n * instead. It identifies the class, not where the error came from: any code\n * can set the brand. An error from another version can carry a `kind` this\n * version does not list, so keep a default branch when switching on it.\n */\n static is(value: unknown): value is QbitApiError {\n return typeof value === 'object' && value !== null && (value as Record<symbol, unknown>)[QBIT_API_ERROR_BRAND] === true\n }\n\n constructor(kind: QbitApiErrorKind, message: string, options: QbitApiErrorOptions = {}) {\n super(message)\n this.name = 'QbitApiError'\n this.kind = kind\n if (options.status !== undefined) this.status = options.status\n if (options.url !== undefined) this.url = options.url\n if (options.retryAfterMs !== undefined) this.retryAfterMs = options.retryAfterMs\n if (options.cause !== undefined) this.cause = options.cause\n if (options.unredactedCause !== undefined) unredactedCauses.set(this, options.unredactedCause)\n if (options.responseBody !== undefined) this.responseBody = options.responseBody\n if (options.txid !== undefined) this.txid = options.txid\n }\n}\n\nObject.defineProperty(QbitApiError.prototype, QBIT_API_ERROR_BRAND, { value: true })\n\n// ---------------------------------------------------------------------------\n// Client\n// ---------------------------------------------------------------------------\n\n/**\n * Fetch credential policy, the values of the DOM's `RequestCredentials`.\n * Declared here so the published types compile without the DOM lib, which\n * `@types/node` does not provide this name from.\n */\nexport type QbitFetchCredentials = 'omit' | 'same-origin' | 'include'\n\nexport interface EsploraClientOptions {\n /** Base URL for the esplora endpoint, e.g. `https://blockstream.info/testnet/api`. */\n baseUrl: string\n /**\n * Accept a plain `http:` baseUrl on a non-loopback host (default false).\n * Without TLS, request headers such as API keys and every response are\n * exposed to the network. `localhost`, `127.0.0.0/8` and `[::1]` are always\n * accepted.\n */\n allowInsecureHttp?: boolean\n /**\n * Custom fetch (defaults to global fetch). It should honour\n * `redirect: 'manual'`; a reply it reports as `redirected`, or whose `url`\n * is not the requested URL (another scheme, host, port, path or query), is\n * refused, but only after the redirected request was sent. A `QbitApiError`\n * it throws, from any copy of this package (see `QbitApiError.is`),\n * propagates as it is, or as the `cause` of an `unknown_outcome` from a\n * submission that may have been sent. One from another copy is judged by its\n * public fields only, since that copy keeps the original cause and response\n * body to itself: on a submission, its `network` error never proves that\n * nothing was sent, and its response body never triggers the `/tx/push`\n * fallback.\n */\n fetchFn?: typeof fetch\n /** Fetch credential policy (default `omit`). */\n credentials?: QbitFetchCredentials\n /** Per-request timeout in ms (default 15000). */\n timeoutMs?: number\n /**\n * Retry attempts for transient failures — network/timeout/5xx/429 on reads\n * (default 2). Submissions only repeat attempts that provably never reached\n * the server; see `broadcastTx`.\n */\n retries?: number\n /** Base backoff in ms; grows exponentially per attempt (default 300). */\n retryBaseDelayMs?: number\n /**\n * Longest server-requested `Retry-After` delay the client will sleep before\n * retrying, in ms (default 30000, at most 2147483647). A longer request is not\n * slept on: a read's 429/5xx (`rate_limit` / `http`) or a submission's 429\n * (`rate_limit`) is thrown at once with `retryAfterMs` set. A submission's\n * 5xx is never retried, so the cap does not apply to it; see `broadcastTx`.\n */\n maxRetryAfterMs?: number\n /** Extra request headers. UDID/telemetry headers are intentionally unsupported. */\n headers?: Record<string, string>\n /**\n * Sleep function (injectable for tests); defaults to an abortable setTimeout.\n * Receives the call's signal; the client stops waiting on abort either way.\n */\n sleepFn?: (ms: number, signal?: AbortSignal) => Promise<void>\n /** Cancels every in-flight and future call on this client when aborted. */\n signal?: AbortSignal\n}\n\nexport interface MempoolQbitClientOptions extends EsploraClientOptions {\n /** Maximum combined-history requests fetched per call (default 256). */\n maxAddressHistoryPages?: number\n}\n\nconst TRANSIENT_STATUSES = new Set([429, 500, 502, 503, 504])\nconst IDEMPOTENT_METHODS = new Set(['GET', 'HEAD'])\n/** 5xx replies that mean the server did not process the request at all. */\nconst UNPROCESSED_SERVER_ERROR_STATUSES = new Set([501, 505, 511])\n/** Error codes that only occur before a connection exists, so nothing was sent. */\nconst PRE_CONNECTION_ERROR_CODES = new Set(['ECONNREFUSED', 'ENOTFOUND', 'EAI_AGAIN', 'UND_ERR_CONNECT_TIMEOUT'])\n/** Route errors that are pre-send only from the connect syscall; later ones can follow a written request. */\nconst CONNECT_STAGE_ERROR_CODES = new Set(['EHOSTUNREACH', 'ENETUNREACH'])\n/**\n * String codes a backend relays when its own node call fails: Node system and\n * internal errors (`ETIMEDOUT`, `ECONNRESET`, `ERR_STREAM_PREMATURE_CLOSE`),\n * undici (`UND_ERR_*`) and http-parser (`HPE_*`) errors. Other strings are\n * gateway or application codes that say nothing about the node call.\n */\nconst TRANSPORT_ERROR_CODE_PATTERN = /^(?:E[A-Z0-9_]+|UND_ERR_[A-Z0-9_]+|HPE_[A-Z0-9_]+)$/\nconst TXID_PATTERN = /^[0-9a-f]{64}$/\nconst DEFAULT_MAX_ADDRESS_HISTORY_PAGES = 256\nconst DEFAULT_MAX_ADDRESS_HISTORY_TRANSACTIONS = 6_400\nconst DEFAULT_MAX_RETRY_AFTER_MS = 30_000\n/** setTimeout stores its delay as a signed 32-bit int; larger values fire after ~1 ms. */\nconst MAX_TIMER_DELAY_MS = 2_147_483_647\nconst MAX_RETRIES = 10\n\nconst UNSAFE_BASE_URL_CHAR =\n /[\\s\\p{Cc}\\\\?#]|(?![\\u200c\\u200d])[\\p{Cf}\\p{Default_Ignorable_Code_Point}]/u\n\nfunction validBaseUrl(value: unknown, allowInsecureHttp: boolean | undefined): string {\n // Paths are appended to the raw string, so a query or fragment would swallow\n // them. new URL() silently strips whitespace and C0 controls, turns\n // backslashes into slashes (`/api\\` would request `/api//...`), and\n // percent-encodes C1 controls (U+0080-U+009F), format characters and other\n // default-ignorable code points (e.g. U+00AD, U+200B, U+FE0F, U+034F) into a\n // different path, or drops them from the host.\n // fetch rejects credentials. Other non-ASCII stays valid: IDN hosts map to\n // punycode and path characters get their standard UTF-8 percent-encoding.\n // ZWNJ/ZWJ (U+200C/U+200D) are exempt in the host because they are\n // significant in some IDN labels (new URL() rejects them where IDNA does not\n // allow them); in the path they are invisible and rejected like the rest.\n // The parts are read with `schemeAndHost`, as React Native's URL getters\n // throw before 0.80 and misread the host from 0.80; where the runtime's URL\n // parser follows the URL Standard, it must also accept the URL.\n const invalid = () =>\n new QbitApiError(\n 'http',\n 'baseUrl must be an absolute http(s) URL without whitespace, control or format characters, backslashes, credentials, query or fragment'\n )\n if (typeof value !== 'string' || UNSAFE_BASE_URL_CHAR.test(value)) throw invalid()\n if (followsUrlStandard() && standardHref(value) === undefined) throw invalid()\n const url = schemeAndHost(value)\n if (\n !url ||\n (url.protocol !== 'http:' && url.protocol !== 'https:') ||\n !url.hostname ||\n url.userinfo ||\n !/^\\d*$/.test(url.port) ||\n Number(url.port) > 65535 ||\n /%E2%80%8[CD]|[\\u200c\\u200d]/i.test(url.path)\n ) {\n throw invalid()\n }\n // Plain http exposes request headers (API keys) and every response to the\n // network; loopback is exempt for local and regtest backends.\n if (url.protocol === 'http:' && allowInsecureHttp !== true && !isLoopbackHostname(url.hostname)) {\n throw new QbitApiError(\n 'http',\n 'baseUrl must use https unless its host is loopback; pass allowInsecureHttp: true to allow plain http'\n )\n }\n return value.replace(/\\/+$/, '')\n}\n\nfunction integerOption(\n value: number | undefined,\n defaultValue: number,\n name: keyof EsploraClientOptions,\n min: number,\n max: number\n): number {\n // Only an omitted option takes the default; an explicit null is invalid.\n const option = value === undefined ? defaultValue : value\n if (!Number.isInteger(option) || option < min || option > max) {\n throw new QbitApiError('http', `${name} must be an integer from ${min} to ${max}`)\n }\n return option\n}\n\nfunction retryBaseDelayOption(value: number | undefined): number {\n const delay = value === undefined ? 300 : value\n if (typeof delay !== 'number' || !Number.isFinite(delay) || delay < 0 || delay > MAX_TIMER_DELAY_MS) {\n throw new QbitApiError(\n 'http',\n `retryBaseDelayMs must be a finite number from 0 to ${MAX_TIMER_DELAY_MS}`\n )\n }\n return delay\n}\n\nfunction defaultSleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(abortErrorFor(signal))\n return\n }\n const onAbort = () => {\n clearTimeout(timer)\n reject(abortErrorFor(signal!))\n }\n const timer = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort)\n resolve()\n }, ms)\n signal?.addEventListener('abort', onAbort, { once: true })\n })\n}\n\n// ---------------------------------------------------------------------------\n// Operation scope: one signal per public call, carried through every\n// dependent request, retry, and backoff.\n// ---------------------------------------------------------------------------\n\n/**\n * Signals created by this module, always aborted with the `QbitApiError` the\n * call rejects with. Any other signal belongs to a caller, whose reason is\n * only ever a cause, even when it is an error this module returned earlier.\n */\nconst internalSignals = new WeakSet<AbortSignal>()\n\nfunction internalAbortController(): AbortController {\n const controller = new AbortController()\n internalSignals.add(controller.signal)\n return controller\n}\n\n/** The `QbitApiError` an aborted signal stands for: a deadline or caller cancellation. */\nfunction abortErrorFor(signal: AbortSignal): QbitApiError {\n const reason: unknown = signal.reason\n // `instanceof`, not `QbitApiError.is`: only this module aborts its internal\n // signals, always with its own errors.\n if (internalSignals.has(signal) && reason instanceof QbitApiError) return reason\n return new QbitApiError('aborted', `request aborted by caller${formatErrorCause(reason)}`, {\n cause: reason,\n })\n}\n\ninterface OperationScope {\n signal: AbortSignal\n dispose(): void\n}\n\nfunction openOperationScope(\n sources: (AbortSignal | undefined)[],\n deadlineMs: number | undefined\n): OperationScope {\n if (\n deadlineMs !== undefined &&\n !(Number.isFinite(deadlineMs) && deadlineMs > 0 && deadlineMs <= MAX_TIMER_DELAY_MS)\n ) {\n throw new QbitApiError(\n 'http',\n `deadlineMs must be a positive number no greater than ${MAX_TIMER_DELAY_MS}`\n )\n }\n\n const controller = internalAbortController()\n const cleanups: (() => void)[] = []\n const dispose = () => {\n for (const cleanup of cleanups) cleanup()\n cleanups.length = 0\n }\n const abort = (error: QbitApiError) => {\n if (controller.signal.aborted) return\n controller.abort(error)\n dispose()\n }\n\n for (const source of sources) {\n if (source === undefined) continue\n if (source.aborted) {\n abort(abortErrorFor(source))\n break\n }\n const onAbort = () => abort(abortErrorFor(source))\n source.addEventListener('abort', onAbort, { once: true })\n cleanups.push(() => source.removeEventListener('abort', onAbort))\n }\n if (deadlineMs !== undefined && !controller.signal.aborted) {\n const timer = setTimeout(\n () =>\n abort(new QbitApiError('timeout', `operation exceeded its ${deadlineMs}ms deadline`)),\n deadlineMs\n )\n cleanups.push(() => clearTimeout(timer))\n }\n\n if (controller.signal.aborted) {\n dispose()\n throw abortErrorFor(controller.signal)\n }\n return { signal: controller.signal, dispose }\n}\n\n/** Settle with `promise`, or reject as soon as `signal` aborts, whichever is first. */\nfunction raceAbort<T>(promise: Promise<T>, signal: AbortSignal): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const onAbort = () => reject(abortErrorFor(signal))\n if (signal.aborted) onAbort()\n else signal.addEventListener('abort', onAbort, { once: true })\n promise.then(\n value => {\n signal.removeEventListener('abort', onAbort)\n resolve(value)\n },\n (error: unknown) => {\n signal.removeEventListener('abort', onAbort)\n reject(error)\n }\n )\n })\n}\n\ninterface InflightRequest {\n response: Promise<Response>\n consumers: number\n /** Aborts the shared request once every consumer has abandoned it. */\n controller: AbortController\n}\n\nexport class EsploraClient {\n /** As configured, without trailing slashes. It can carry secrets: errors show `errorUrl(path)`. */\n protected readonly baseUrl: string\n private readonly fetchFn: typeof fetch\n private readonly timeoutMs: number\n private readonly retries: number\n private readonly retryBaseDelayMs: number\n private readonly maxRetryAfterMs: number\n private readonly headers: Record<string, string>\n private readonly credentials: QbitFetchCredentials\n private readonly sleepFn: (ms: number, signal?: AbortSignal) => Promise<void>\n private readonly signal: AbortSignal | undefined\n /** In-flight GET de-dup: concurrent identical GETs share one request. */\n private readonly inflight = new Map<string, InflightRequest>()\n\n constructor(options: EsploraClientOptions) {\n if (!options.baseUrl) {\n throw new QbitApiError('http', 'EsploraClient requires a baseUrl')\n }\n const baseUrl = validBaseUrl(options.baseUrl, options.allowInsecureHttp)\n const timeoutMs = integerOption(options.timeoutMs, 15000, 'timeoutMs', 1, MAX_TIMER_DELAY_MS)\n const retries = integerOption(options.retries, 2, 'retries', 0, MAX_RETRIES)\n const retryBaseDelayMs = retryBaseDelayOption(options.retryBaseDelayMs)\n const maxRetryAfterMs = integerOption(\n options.maxRetryAfterMs,\n DEFAULT_MAX_RETRY_AFTER_MS,\n 'maxRetryAfterMs',\n 0,\n MAX_TIMER_DELAY_MS\n )\n const fetchImpl = options.fetchFn ?? globalThis.fetch\n if (typeof fetchImpl !== 'function') {\n throw new QbitApiError('network', 'no fetch implementation available; pass options.fetchFn')\n }\n this.baseUrl = baseUrl\n this.fetchFn = options.fetchFn ? fetchImpl : fetchImpl.bind(globalThis)\n this.timeoutMs = timeoutMs\n this.retries = retries\n this.retryBaseDelayMs = retryBaseDelayMs\n this.maxRetryAfterMs = maxRetryAfterMs\n this.headers = { ...(options.headers ?? {}) }\n this.credentials = options.credentials ?? 'omit'\n this.sleepFn = options.sleepFn ?? defaultSleep\n this.signal = options.signal\n }\n\n // --- esplora endpoints -------------------------------------------------\n\n getAddressStats(address: string, options?: RequestOptions): Promise<EsploraAddressStats> {\n return this.getJson<EsploraAddressStats>(`/address/${encodeURIComponent(address)}`, options)\n }\n\n getAddressUtxos(address: string, options?: RequestOptions): Promise<EsploraUtxo[]> {\n return this.getJson<EsploraUtxo[]>(`/address/${encodeURIComponent(address)}/utxo`, options)\n }\n\n /**\n * Confirmed transaction history for an address, newest first, 25 per page.\n * Pass the last txid of the previous page as `afterTxid` to paginate.\n */\n getAddressTxs(\n address: string,\n afterTxid?: string,\n options?: RequestOptions\n ): Promise<EsploraTx[]> {\n const suffix = afterTxid ? `/${encodeURIComponent(afterTxid)}` : ''\n return this.getJson<EsploraTx[]>(\n `/address/${encodeURIComponent(address)}/txs/chain${suffix}`,\n options\n )\n }\n\n /**\n * Unconfirmed (mempool) transactions touching an address. electrs lists at\n * most `--rest-default-max-mempool-txs` (default 50) of them, with no way to\n * page further; `getAddressHistory` detects that cap.\n */\n getAddressMempoolTxs(address: string, options?: RequestOptions): Promise<EsploraTx[]> {\n return this.getJson<EsploraTx[]>(\n `/address/${encodeURIComponent(address)}/txs/mempool`,\n options\n )\n }\n\n /**\n * Complete address history from a bounded, page-one scan. The confirmed\n * chain route is exhausted explicitly; short pages are not assumed final.\n *\n * electrs answers a chain cursor it does not know (a lagging node behind a\n * load balancer, or a reorg between pages) with HTTP 200 and `[]`, and\n * `/txs/mempool` stops at 50 rows, so the scan alone cannot tell a short\n * history from a complete one. The address stats are therefore read before\n * and after the scan, each in a request of its own, and the history is\n * returned only if both reads agree and it holds exactly\n * `chain_stats.tx_count` confirmed and `mempool_stats.tx_count` mempool\n * transactions. If the stats changed during the scan, the address is scanned\n * once more; if they change again, or the counts differ, the call rejects\n * with `invalid_cursor`. Stats without a non-negative safe-integer\n * `tx_count` reject with `parse`. `maxPages` and `maxTransactions` cover\n * both scans.\n */\n getAddressHistory(\n address: string,\n options: AddressHistoryOptions = {}\n ): Promise<AddressHistory> {\n return this.runOperation(options, signal => this.scanAddressHistory(address, options, signal))\n }\n\n private async scanAddressHistory(\n address: string,\n options: AddressHistoryOptions,\n signal: AbortSignal\n ): Promise<AddressHistory> {\n const maxPages = positiveAddressHistoryLimit(\n options.maxPages,\n DEFAULT_MAX_ADDRESS_HISTORY_PAGES,\n 'maxPages'\n )\n const maxTransactions = positiveAddressHistoryLimit(\n options.maxTransactions,\n DEFAULT_MAX_ADDRESS_HISTORY_TRANSACTIONS,\n 'maxTransactions'\n )\n const budget = createAddressHistoryBudget()\n return verifiedAddressHistory(\n address,\n 'esplora',\n () => this.getJson<unknown>(`/address/${encodeURIComponent(address)}`, { signal }, false),\n () => this.scanAddressHistoryOnce(address, maxPages, maxTransactions, budget, signal)\n )\n }\n\n private async scanAddressHistoryOnce(\n address: string,\n maxPages: number,\n maxTransactions: number,\n budget: AddressHistoryBudget,\n signal: AbortSignal\n ): Promise<AddressHistory> {\n // A rescan only gets the page fetches the first scan left.\n if (budget.pageRequests >= maxPages) {\n throw addressHistoryPageLimitError(address, maxPages, 'esplora')\n }\n const state = createAddressHistoryScanState()\n\n const mempoolRows = reserveAddressHistoryTransactions(\n budget,\n await this.getAddressMempoolTxs(address, { signal }),\n maxTransactions,\n address,\n 'esplora',\n 'esplora mempool'\n )\n const mempoolTxs = assertAddressHistoryPage(mempoolRows, address, 'esplora mempool')\n appendAddressHistoryTransactions(state, mempoolTxs, 'mempool', address, 'esplora')\n\n let cursor: string | undefined\n const seenCursors = new Set<string>()\n\n while (true) {\n budget.pageRequests += 1\n const rows = reserveAddressHistoryTransactions(\n budget,\n await this.getAddressTxs(address, cursor, { signal }),\n maxTransactions,\n address,\n 'esplora',\n 'esplora confirmed'\n )\n if (rows.length === 0) break\n\n if (budget.pageRequests === maxPages) {\n throw addressHistoryPageLimitError(address, maxPages, 'esplora')\n }\n const txs = assertAddressHistoryPage(rows, address, 'esplora confirmed')\n cursor = nextAddressHistoryCursor(txs, cursor, seenCursors, address, 'esplora')\n appendAddressHistoryTransactions(state, txs, 'confirmed', address, 'esplora')\n }\n\n return { confirmed: state.confirmed, mempool: state.mempool }\n }\n\n getTx(txid: string, options?: RequestOptions): Promise<EsploraTx> {\n return this.getJson<EsploraTx>(`/tx/${encodeURIComponent(txid)}`, options)\n }\n\n /**\n * Raw transaction hex as the backend serializes it (with witness data when\n * the transaction has any), in lowercase. The reply is checked before it is\n * returned: it must be non-empty, even-length hex that decodes to one\n * complete transaction whose txid (the double SHA-256 of its\n * witness-stripped serialization, as qbit Core computes it) is `txid`,\n * compared case-insensitively. The transaction must be encoded as qbit\n * Core's decoder requires: every count and length in its shortest\n * CompactSize form and at most 0x02000000, and no witness flag when every\n * witness stack is empty. Anything else, including the empty `200`\n * reply mempool.qbit.org serves, throws a `parse` `QbitApiError`, so a\n * backend cannot hand back an empty string or another transaction. Spaces,\n * tabs and line breaks around the hex are ignored. The txid does not commit\n * to witness data, so a reply with altered or stripped witnesses still\n * passes; compare the wtxid if you need them.\n */\n async getTxHex(txid: string, options?: RequestOptions): Promise<string> {\n const path = `/tx/${encodeURIComponent(txid)}/hex`\n const text = await this.getText(path, options)\n const hex = trimAsciiWhitespace(text).toLowerCase()\n const invalid = (reason: string) =>\n new QbitApiError('parse', `transaction hex reply ${reason}`, {\n url: this.errorUrl(path),\n responseBody: responseBodyPreview(text, this.baseUrl),\n })\n if (hex === '') throw invalid('was empty')\n if (hex.length % 2 !== 0 || !/^[0-9a-f]+$/.test(hex)) {\n throw invalid(`was not even-length hex: ${quotedResponseText(text, this.baseUrl)}`)\n }\n const actual = tryTxidFromRawTx(hex)\n if (actual === undefined) throw invalid('is not a well-formed transaction')\n if (actual !== String(txid).toLowerCase()) throw invalid(`is transaction ${actual}, not the one requested`)\n return hex\n }\n\n getTxStatus(txid: string, options?: RequestOptions): Promise<EsploraTxStatus> {\n return this.getJson<EsploraTxStatus>(`/tx/${encodeURIComponent(txid)}/status`, options)\n }\n\n getFeeEstimates(options?: RequestOptions): Promise<EsploraFeeEstimates> {\n return this.getJson<EsploraFeeEstimates>('/fee-estimates', options)\n }\n\n async getTipHeight(options?: RequestOptions): Promise<number> {\n const text = await this.getText('/blocks/tip/height', options)\n const height = Number(text.trim())\n if (!Number.isInteger(height)) {\n throw new QbitApiError('parse', `tip height was not an integer: ${quotedResponseText(text, this.baseUrl)}`, {\n url: this.errorUrl('/blocks/tip/height'),\n responseBody: responseBodyPreview(text, this.baseUrl),\n })\n }\n return height\n }\n\n async getTipHash(options?: RequestOptions): Promise<string> {\n return (await this.getText('/blocks/tip/hash', options)).trim()\n }\n\n /**\n * Broadcast a raw transaction hex. Resolves with the txid once the node has\n * the transaction, including when it reports the transaction as already in\n * its mempool or chain. A submission is never re-sent after an attempt that\n * may have reached the node: a timeout, an ambiguous network error, or a\n * 5xx reply whose body carries no verdict from the node rejects with\n * `unknown_outcome` carrying the txid so the caller can check\n * `getTxStatus(txid)` before resubmitting the same hex. Only 429 replies and\n * connection failures that happened before anything was sent are retried; a\n * 429 whose `Retry-After` exceeds `maxRetryAfterMs` is not waited on and\n * rejects at once as `rate_limit` with `retryAfterMs`, without a re-send.\n * A redirect is never followed. A refused one (a 3xx, a browser opaque\n * redirect, or a reply from a redirect the runtime followed) rejects with\n * `unknown_outcome` too, with the `http` refusal as `cause`: the POST\n * reached the backend, which may have accepted it before redirecting, and\n * a runtime that followed the redirect may have re-sent it.\n * Coded node rejections fail closed as `http` errors whatever the HTTP\n * status, since qbit Core's own JSON-RPC server answers 500 for every RPC\n * error and a backend or proxy may relay that status. When no txid\n * can be derived from the hex and none is supplied, a 2xx reply resolves only\n * if its body is itself a 64-hex txid; any other 2xx body is `unknown_outcome`.\n * Hex `txidFromRawTx` cannot read, including encodings qbit Core refuses to\n * decode, is still sent as it is, and the node gives the verdict.\n * A malformed `rawTxHex` argument or an `options.txid` that is not a 64-hex\n * transaction id matching the hex throws a `TypeError` before anything is sent.\n *\n * `options.signal` / `options.deadlineMs` bound the whole call. An abort or\n * expired deadline before the POST is sent rejects with `aborted` /\n * `timeout`; once the POST may have been sent (in flight or while its reply\n * is read) it rejects with `unknown_outcome`, with that error as `cause`.\n * A reply whose body stalls past `timeoutMs` or cannot be read is\n * `unknown_outcome` too. A 429 reply is the exception throughout: it proves\n * nothing was submitted, so one whose body is lost is retried (then\n * `rate_limit`), and an abort or deadline during its body is definite.\n */\n async broadcastTx(rawTxHex: string, options?: BroadcastTxOptions): Promise<string> {\n return this.submitTx('/tx', rawTxHex, resolveBroadcastTxid(rawTxHex, options), options)\n }\n\n // --- adapters (clean, wallet-friendly shapes) --------------------------\n\n /** Confirmed + mempool balance for an address, in satoshis. */\n async getAddressBalance(address: string, options?: RequestOptions): Promise<AddressBalance> {\n return addressBalanceFromStats(await this.getAddressStats(address, options))\n }\n\n /** Fee-rate tiers (sat/vB), ascending by confirmation target. */\n async getFeeTiers(options?: RequestOptions): Promise<FeeRateTier[]> {\n return feeTiersFromEstimates(await this.getFeeEstimates(options))\n }\n\n // --- internals ---------------------------------------------------------\n\n /**\n * Run one public call under a single signal that combines the client's\n * signal, the caller's signal, and the caller's deadline. Pass `{ signal }`\n * to dependent calls so they share the same cancellation and budget.\n */\n protected async runOperation<T>(\n options: RequestOptions | undefined,\n run: (signal: AbortSignal) => Promise<T>\n ): Promise<T> {\n const scope = openOperationScope([this.signal, options?.signal], options?.deadlineMs)\n try {\n return await run(scope.signal)\n } finally {\n scope.dispose()\n }\n }\n\n /**\n * GET and parse JSON. With `dedup` false the request is sent on its own\n * instead of joining an identical one already in flight, whose reply may\n * predate requests this call has made since.\n */\n protected getJson<T>(path: string, options?: RequestOptions, dedup = true): Promise<T> {\n return this.runOperation(options, async signal => {\n const response = await this.request(path, { method: 'GET', dedup }, { signal })\n const url = this.errorUrl(path)\n const text = await readBody(response, url, this.baseUrl, signal)\n if (!response.ok) throw httpError(response, text, url, this.baseUrl)\n try {\n return JSON.parse(text) as T\n } catch (cause) {\n // V8's JSON.parse error quotes the first characters of the body, and a\n // token cut short there escapes redaction, so the cause is a generic\n // SyntaxError; the original stays behind QbitApiError.unredactedCause().\n throw new QbitApiError('parse', `failed to parse JSON from ${path}`, {\n url,\n responseBody: responseBodyPreview(text, this.baseUrl),\n cause: new SyntaxError('response body is not valid JSON'),\n unredactedCause: cause,\n })\n }\n })\n }\n\n protected getText(path: string, options?: RequestOptions): Promise<string> {\n return this.runOperation(options, async signal => {\n const response = await this.request(path, { method: 'GET', dedup: true }, { signal })\n const url = this.errorUrl(path)\n const text = await readBody(response, url, this.baseUrl, signal)\n if (!response.ok) throw httpError(response, text, url, this.baseUrl)\n return text\n })\n }\n\n /**\n * POST a transaction submission under the submission retry policy and\n * classify the node's reply. `txid` identifies the submission in\n * `unknown_outcome` errors and is the result for already-known replies.\n * An abort or deadline once the POST may have been sent, including while\n * the reply body is read, is an `unknown_outcome` too, unless the reply is\n * a 429.\n */\n protected submitTx(\n path: string,\n body: string,\n txid: string | undefined,\n options?: RequestOptions\n ): Promise<string> {\n return this.runOperation(options, async signal => {\n const url = `${this.baseUrl}${path}`\n const errorUrl = this.errorUrl(path)\n const response = await this.requestWithRetry(\n url,\n { method: 'POST', body, headers: { 'content-type': 'text/plain' } },\n signal,\n txid\n )\n let text: string\n try {\n text = (await readBody(response, errorUrl, this.baseUrl, signal)).trim()\n } catch (cause) {\n // A 429 proves nothing was submitted, even when the call is cut short here.\n if (response.status === 429 && signal.aborted) throw abortErrorFor(signal)\n throw unknownOutcomeError(errorUrl, txid, `HTTP ${response.status} reply body could not be read`, {\n status: response.status,\n cause,\n })\n }\n const detail = responseBodyPreview(text, this.baseUrl)\n const reply = httpReplyMessage(response.status, errorUrl, detail)\n if (response.ok) {\n // Only a reply that echoes the txid proves the node took this transaction.\n // Without a txid to compare against, the body must itself be a txid: a\n // gateway may answer 2xx with an HTML page or an empty body after the\n // node accepted the submission, so anything else is an unknown outcome.\n const echoed = text.toLowerCase()\n if (txid === undefined) {\n if (TXID_PATTERN.test(echoed)) return echoed\n } else if (echoed === txid) {\n return txid\n }\n const reason = txid === undefined ? 'reply is not a txid' : 'reply did not echo the txid'\n throw unknownOutcomeError(errorUrl, txid, `${reason} (${reply})`, {\n status: response.status,\n responseBody: detail,\n })\n }\n if (UNPROCESSED_SERVER_ERROR_STATUSES.has(response.status)) throw httpError(response, text, errorUrl, this.baseUrl)\n // The body is read before the status is judged: qbit Core's JSON-RPC server\n // answers HTTP 500 for every RPC error (src/httprpc.cpp, JSONErrorReply),\n // so a relayed envelope carrying the node's verdict can arrive as a 5xx.\n const rejection = parseBroadcastReply(text)\n if (isAlreadyKnownBroadcastReply(rejection)) {\n if (txid !== undefined) return txid\n throw unknownOutcomeError(errorUrl, undefined, `node already knows the transaction: ${reply}`, {\n status: response.status,\n responseBody: detail,\n })\n }\n if (response.status >= 500) {\n // A 5xx alone says the server failed, not whether the node saw the\n // transaction; only the node's own rejection in the body settles it.\n if (isDefiniteNodeRejection(rejection)) throw httpError(response, text, errorUrl, this.baseUrl)\n throw unknownOutcomeError(errorUrl, txid, reply, { status: response.status, responseBody: detail })\n }\n if (isRelayedTransportFailure(rejection)) {\n throw unknownOutcomeError(errorUrl, txid, `backend lost its node connection (${reply})`, {\n status: response.status,\n responseBody: detail,\n })\n }\n throw httpError(response, text, errorUrl, this.baseUrl)\n })\n }\n\n protected request(\n path: string,\n init: { method: string; body?: string; headers?: Record<string, string>; dedup: boolean },\n options?: RequestOptions\n ): Promise<Response> {\n return this.runOperation(options, signal => {\n const url = `${this.baseUrl}${path}`\n return init.dedup\n ? this.requestShared(url, init, signal)\n : this.requestWithRetry(url, init, signal)\n })\n }\n\n /**\n * Concurrent identical GETs share one request. One caller giving up only\n * stops waiting; the shared request is aborted once every caller has left.\n */\n private async requestShared(\n url: string,\n init: { method: string; headers?: Record<string, string> },\n signal: AbortSignal\n ): Promise<Response> {\n let pending = this.inflight.get(url)\n if (pending === undefined) {\n const controller = internalAbortController()\n pending = {\n response: this.requestWithRetry(url, init, controller.signal),\n consumers: 0,\n controller,\n }\n this.inflight.set(url, pending)\n }\n pending.consumers += 1\n\n let response: Response\n try {\n response = await raceAbort(pending.response, signal)\n } catch (error) {\n pending.consumers -= 1\n if (pending.consumers === 0) {\n if (this.inflight.get(url) === pending) this.inflight.delete(url)\n if (signal.aborted) {\n const errorUrl = redactBaseUrl(url, this.baseUrl)\n pending.controller.abort(new QbitApiError('aborted', `request abandoned: ${errorUrl}`, { url: errorUrl }))\n // If the response already arrived, nobody will read its body.\n pending.response.then(discardResponseBody, () => undefined)\n }\n }\n throw error\n }\n\n pending.consumers -= 1\n // The last waiter consumes the original body; earlier waiters receive clones.\n if (pending.consumers === 0) {\n if (this.inflight.get(url) === pending) this.inflight.delete(url)\n return response\n }\n return response.clone()\n }\n\n /**\n * Idempotent requests (GET/HEAD) retry on network errors, timeouts, and\n * transient statuses. Any other method is a submission: an attempt is only\n * repeated when it provably never reached the server (429, or a connection\n * failure before anything was sent), and an attempt that may have been\n * processed fails with `unknown_outcome` instead of being re-sent; that\n * includes an abort or deadline that fires while a submission is in flight,\n * and a refused redirect. `txid` labels that error when the submission is a\n * transaction.\n */\n private async requestWithRetry(\n url: string,\n init: { method: string; body?: string; headers?: Record<string, string> },\n signal: AbortSignal,\n txid?: string\n ): Promise<Response> {\n const idempotent = IDEMPOTENT_METHODS.has(init.method.toUpperCase())\n const errorUrl = redactBaseUrl(url, this.baseUrl)\n let lastError: QbitApiError | undefined\n for (let attempt = 0; attempt <= this.retries; attempt += 1) {\n // Every earlier attempt was provably unsent (or a read), so an abort or\n // deadline before this one starts is a definite `aborted` / `timeout`.\n if (signal.aborted) throw abortErrorFor(signal)\n const reply: { status?: number; retryAfterMs?: number; refusedRedirect?: true } = {}\n let response: Response\n try {\n response = await this.fetchOnce(url, init, signal, reply)\n } catch (error) {\n // Another copy's QbitApiError (from a custom fetchFn) passes through too.\n lastError =\n QbitApiError.is(error)\n ? error\n : new QbitApiError('network', redactBaseUrl(String(error), this.baseUrl), {\n url: errorUrl,\n ...causeOptions(error, this.baseUrl),\n })\n // A refused redirect is never followed or retried. A submission's POST\n // still reached the origin, which may have accepted it before\n // redirecting (303), and a runtime that followed the redirect itself\n // may have re-sent it to the target (307/308).\n if (!idempotent && reply.refusedRedirect) {\n throw unknownOutcomeError(errorUrl, txid, lastError.message, {\n ...(lastError.status === undefined ? {} : { status: lastError.status }),\n cause: lastError,\n })\n }\n // fetchOnce reads the body, so a submission reply can arrive and then stall,\n // fail mid-read, or be cut short by an abort or the deadline. A 429 still\n // proves the submission was not processed; any other reply may follow an\n // accepted POST.\n if (!idempotent && reply.status === 429) {\n if (signal.aborted) throw abortErrorFor(signal)\n const { retryAfterMs } = reply\n if (attempt < this.retries && (retryAfterMs === undefined || retryAfterMs <= this.maxRetryAfterMs)) {\n await this.sleep(retryAfterMs ?? this.backoffMs(attempt), signal)\n continue\n }\n throw new QbitApiError('rate_limit', `HTTP 429 from ${errorUrl} (reply body could not be read)`, {\n status: 429,\n url: errorUrl,\n cause: lastError,\n ...(retryAfterMs === undefined ? {} : { retryAfterMs }),\n })\n }\n if (!idempotent && reply.status !== undefined) {\n throw unknownOutcomeError(errorUrl, txid, `HTTP ${reply.status} reply body could not be read`, {\n status: reply.status,\n cause: lastError,\n })\n }\n // A read whose transient reply (429/5xx) fails mid-body is retried like\n // the status itself, honouring Retry-After within the cap; the final\n // attempt's failure surfaces as before. A stalled body is a timeout and\n // takes the timeout path below.\n if (\n idempotent &&\n lastError.kind === 'parse' &&\n reply.status !== undefined &&\n TRANSIENT_STATUSES.has(reply.status)\n ) {\n const { retryAfterMs } = reply\n const overCap = retryAfterMs !== undefined && retryAfterMs > this.maxRetryAfterMs\n if (attempt < this.retries && !overCap && !signal.aborted) {\n await this.sleep(retryAfterMs ?? this.backoffMs(attempt), signal)\n continue\n }\n throw lastError\n }\n if (lastError.kind !== 'network' && lastError.kind !== 'timeout' && lastError.kind !== 'aborted') {\n throw lastError\n }\n // An abort or deadline here fired while the attempt was in flight, so a\n // submission may already have reached the server, like a timeout.\n // Judge the original fetch error: the public `cause` is a depth-limited\n // redacted copy that can drop a nested failure meaning the POST was sent.\n // Another copy of this package keeps that original where this one cannot\n // read it, so a `network` error from that copy never counts as unsent.\n const unsent =\n idempotent ||\n (lastError.kind === 'network' &&\n lastError instanceof QbitApiError &&\n isPreConnectionFailure(QbitApiError.unredactedCause(lastError) ?? lastError))\n if (!unsent) {\n // A custom fetchFn's own QbitApiError is not redacted; its message is, where quoted here.\n const reason = redactBaseUrl(String(lastError.message), this.baseUrl)\n throw unknownOutcomeError(errorUrl, txid, reason, { cause: lastError })\n }\n if (lastError.kind !== 'aborted' && attempt < this.retries && !signal.aborted) {\n await this.sleep(this.backoffMs(attempt), signal)\n continue\n }\n throw lastError\n }\n\n const retryable = idempotent ? TRANSIENT_STATUSES.has(response.status) : response.status === 429\n if (retryable && attempt < this.retries) {\n const retryAfterMs = parseRetryAfter(response.headers.get('retry-after'))\n // Never park the request (and every de-duplicated waiter) on an\n // unbounded server-chosen delay: hand the error, with retryAfterMs, to the caller.\n if (retryAfterMs !== undefined && retryAfterMs > this.maxRetryAfterMs) return response\n // Never wait on cleanup: a body whose cancel never settles must not\n // hold the call past an abort or deadline.\n void discardResponseBody(response)\n await this.sleep(retryAfterMs ?? this.backoffMs(attempt), signal)\n continue\n }\n return response\n }\n // Unreachable in practice, but satisfies the type checker.\n throw lastError ?? new QbitApiError('network', `request failed: ${errorUrl}`, { url: errorUrl })\n }\n\n /** Backoff that rejects as soon as `signal` aborts, even if `sleepFn` ignores it. */\n private async sleep(ms: number, signal: AbortSignal): Promise<void> {\n if (signal.aborted) throw abortErrorFor(signal)\n await raceAbort(\n Promise.resolve().then(() => this.sleepFn(ms, signal)),\n signal\n )\n }\n\n /**\n * One attempt under one timeout that spans the headers and the whole body,\n * also bounded by the call's signal until the body is buffered. Every\n * response it returns is fully buffered, whatever its status, so no caller\n * (retry loop, de-duplicated clone, or error path) can block on the network\n * after the timer is cleared. A body that misses the attempt timeout fails\n * the attempt as `timeout`, even for a status that would otherwise be\n * retried; an abort or call deadline, before or after the headers, rejects\n * with the call's `aborted` / `timeout` error. `reply.status` is set once\n * the headers arrive. A redirect is refused before its body is read, which\n * is cancelled instead, and `reply.refusedRedirect` is set; see\n * `refuseRedirect`.\n */\n private async fetchOnce(\n url: string,\n init: { method: string; body?: string; headers?: Record<string, string> },\n signal: AbortSignal,\n reply: { status?: number; retryAfterMs?: number; refusedRedirect?: true }\n ): Promise<Response> {\n if (signal.aborted) throw abortErrorFor(signal)\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), this.timeoutMs)\n // The operation signal bounds each attempt: its timeout is effectively\n // min(timeoutMs, time left before the call's deadline).\n const onAbort = () => controller.abort(signal.reason)\n signal.addEventListener('abort', onAbort, { once: true })\n const requestInit: RequestInit = {\n method: init.method,\n headers: { ...this.headers, ...(init.headers ?? {}) },\n mode: 'cors',\n redirect: 'manual',\n credentials: this.credentials,\n signal: controller.signal,\n }\n if (init.body !== undefined) requestInit.body = init.body\n let pending: Promise<Response> | undefined\n try {\n let response: Response\n try {\n pending = this.fetchFn(url, requestInit)\n response = await raceAbort(pending, signal)\n } catch (cause) {\n if (signal.aborted) {\n // A fetch that ignores its signal may still deliver a response nobody reads.\n pending?.then(discardResponseBody, () => undefined)\n throw abortErrorFor(signal)\n }\n if (QbitApiError.is(cause)) throw cause // from a custom fetchFn, built by any copy of this package\n if (isAbortError(cause)) throw this.timeoutError(url, cause)\n // fetch implementations may quote the request URL in their own messages.\n const errorUrl = redactBaseUrl(url, this.baseUrl)\n throw new QbitApiError('network', `network error: ${errorUrl}${redactBaseUrl(formatErrorCause(cause), this.baseUrl)}`, {\n url: errorUrl,\n ...causeOptions(cause, this.baseUrl),\n })\n }\n // Checked on the raw reply, since a buffered copy loses `type` and\n // `redirected`, and before `reply.status` is set, so the retry loop\n // never retries the refusal.\n try {\n refuseRedirect(response, url, this.baseUrl)\n } catch (refusal) {\n reply.refusedRedirect = true\n throw refusal\n }\n reply.status = response.status\n const retryAfterMs = parseRetryAfter(response.headers.get('retry-after'))\n if (retryAfterMs !== undefined) reply.retryAfterMs = retryAfterMs\n\n let text: string\n try {\n text = await readBodyUntilAborted(response, controller.signal)\n } catch (cause) {\n // The call signal also aborts `controller`, so only an abort it did not\n // cause is this attempt's own timeout.\n if (signal.aborted) throw abortErrorFor(signal)\n if (controller.signal.aborted) throw this.timeoutError(url, cause, response.status)\n throw bodyReadError(response, cause, redactBaseUrl(url, this.baseUrl), this.baseUrl)\n }\n return bufferedResponse(response, text)\n } finally {\n clearTimeout(timer)\n signal.removeEventListener('abort', onAbort)\n }\n }\n\n /** `status` is set when the headers arrived and the body missed the deadline. */\n private timeoutError(url: string, cause: unknown, status?: number): QbitApiError {\n // fetch implementations may quote the request URL in their own messages.\n const errorUrl = redactBaseUrl(url, this.baseUrl)\n return new QbitApiError(\n 'timeout',\n `request timed out after ${this.timeoutMs}ms: ${errorUrl}${redactBaseUrl(formatErrorCause(cause), this.baseUrl)}`,\n { url: errorUrl, ...causeOptions(cause, this.baseUrl), ...(status === undefined ? {} : { status }) }\n )\n }\n\n private backoffMs(attempt: number): number {\n return Math.min(this.retryBaseDelayMs * 2 ** attempt, MAX_TIMER_DELAY_MS)\n }\n\n /** The request URL for `path` as errors show it: see `redactedBaseUrl`. */\n protected errorUrl(path: string): string {\n return `${redactedBaseUrl(this.baseUrl)}${path}`\n }\n}\n\nconst MEMPOOL_QBIT_ADDRESS_PAGE_SIZE = 10\n\n/**\n * Adapter for mempool-qbit's public Node API (`/api/v1` prefix). Most routes\n * match Esplora, but address pagination and fees use mempool-style shapes.\n */\nexport class MempoolQbitClient extends EsploraClient {\n private readonly maxAddressHistoryPages: number\n\n constructor(options: MempoolQbitClientOptions) {\n super(options)\n const maxAddressHistoryPages =\n options.maxAddressHistoryPages ?? DEFAULT_MAX_ADDRESS_HISTORY_PAGES\n if (!Number.isSafeInteger(maxAddressHistoryPages) || maxAddressHistoryPages < 1) {\n throw new QbitApiError('http', 'maxAddressHistoryPages must be a positive integer')\n }\n this.maxAddressHistoryPages = maxAddressHistoryPages\n }\n\n /**\n * Complete address history from one bounded traversal of mempool-qbit's\n * combined endpoint. Page size is intentionally not assumed.\n *\n * The result is checked against the address stats, read before and after\n * the traversal, as `EsploraClient.getAddressHistory` describes, and a\n * traversal during which they changed is repeated once. qbit-electrs\n * answers a cursor that is the last mempool row with `[]` instead of the\n * confirmed rows that follow, so an address whose mempool rows fill whole\n * pages (50 each by default) rejects with `invalid_cursor` while it has\n * confirmed history, rather than returning none.\n */\n override getAddressHistory(\n address: string,\n options: AddressHistoryOptions = {}\n ): Promise<AddressHistory> {\n return this.runOperation(options, signal =>\n this.scanCombinedAddressHistory(address, options, signal)\n )\n }\n\n private async scanCombinedAddressHistory(\n address: string,\n options: AddressHistoryOptions,\n signal: AbortSignal\n ): Promise<AddressHistory> {\n const requestedMaxPages = positiveAddressHistoryLimit(\n options.maxPages,\n this.maxAddressHistoryPages,\n 'maxPages'\n )\n const maxPages = Math.min(requestedMaxPages, this.maxAddressHistoryPages)\n const maxTransactions = positiveAddressHistoryLimit(\n options.maxTransactions,\n DEFAULT_MAX_ADDRESS_HISTORY_TRANSACTIONS,\n 'maxTransactions'\n )\n const budget = createAddressHistoryBudget()\n return verifiedAddressHistory(\n address,\n 'mempool-qbit',\n () => this.getJson<unknown>(`/address/${encodeURIComponent(address)}`, { signal }, false),\n () => this.scanCombinedAddressHistoryOnce(address, maxPages, maxTransactions, budget, signal)\n )\n }\n\n private async scanCombinedAddressHistoryOnce(\n address: string,\n maxPages: number,\n maxTransactions: number,\n budget: AddressHistoryBudget,\n signal: AbortSignal\n ): Promise<AddressHistory> {\n // A rescan only gets the page fetches the first scan left.\n if (budget.pageRequests >= maxPages) {\n throw this.addressHistoryPaginationLimitError(address, maxPages)\n }\n const state = createAddressHistoryScanState()\n let cursor: string | undefined\n const seenCursors = new Set<string>()\n\n while (true) {\n budget.pageRequests += 1\n const suffix = cursor ? `?after_txid=${encodeURIComponent(cursor)}` : ''\n const rows = reserveAddressHistoryTransactions(\n budget,\n await this.getJson<unknown>(`/address/${encodeURIComponent(address)}/txs${suffix}`, {\n signal,\n }),\n maxTransactions,\n address,\n 'mempool-qbit',\n 'mempool-qbit combined'\n )\n if (rows.length === 0) break\n\n if (budget.pageRequests === maxPages) {\n throw this.addressHistoryPaginationLimitError(address, maxPages)\n }\n const txs = assertAddressHistoryPage(rows, address, 'mempool-qbit combined')\n cursor = nextAddressHistoryCursor(txs, cursor, seenCursors, address, 'mempool-qbit')\n appendAddressHistoryTransactions(state, txs, 'combined', address, 'mempool-qbit')\n }\n\n return { confirmed: state.confirmed, mempool: state.mempool }\n }\n\n /**\n * Confirmed transaction history for an address, newest first.\n * mempool-qbit paginates combined history with `?after_txid=...` and sorts\n * mempool entries first, so full mempool-only pages must still advance.\n * Without `afterTxid`, an empty page right after a mempool row is checked\n * against the address stats: qbit-electrs answers that cursor with `[]`\n * instead of the confirmed rows that follow, so the call rejects with\n * `invalid_cursor` if the stats count more confirmed transactions than it\n * found.\n */\n override getAddressTxs(\n address: string,\n afterTxid?: string,\n options?: RequestOptions\n ): Promise<EsploraTx[]> {\n return this.runOperation(options, signal => this.scanAddressTxs(address, afterTxid, signal))\n }\n\n private async scanAddressTxs(\n address: string,\n afterTxid: string | undefined,\n signal: AbortSignal\n ): Promise<EsploraTx[]> {\n const confirmedTxs: EsploraTx[] = []\n let cursor: string | undefined\n let continuationFound = afterTxid === undefined\n let cursorIsMempoolTx = false\n const seenCursors = new Set<string>()\n const seenTxids = new Set<string>()\n let pageCount = 0\n\n while (confirmedTxs.length < 25) {\n if (pageCount >= this.maxAddressHistoryPages) {\n throw this.addressHistoryPaginationLimitError(address)\n }\n pageCount += 1\n const suffix = cursor ? `?after_txid=${encodeURIComponent(cursor)}` : ''\n const txs = await this.getJson<EsploraTx[]>(\n `/address/${encodeURIComponent(address)}/txs${suffix}`,\n { signal }\n )\n if (txs.length === 0) {\n if (!continuationFound) throw this.invalidAddressHistoryCursorError(address, afterTxid!)\n if (afterTxid === undefined && cursorIsMempoolTx) {\n await this.assertConfirmedHistoryReached(address, confirmedTxs.length, signal)\n }\n break\n }\n\n for (const tx of txs) {\n if (!continuationFound) {\n if (isConfirmedTx(tx)) seenTxids.add(tx.txid)\n if (tx.txid !== afterTxid) continue\n if (!isConfirmedTx(tx)) {\n throw this.invalidAddressHistoryCursorError(address, afterTxid)\n }\n continuationFound = true\n continue\n }\n if (isConfirmedTx(tx) && !seenTxids.has(tx.txid)) {\n confirmedTxs.push(tx)\n seenTxids.add(tx.txid)\n }\n }\n\n const nextCursor = txs[txs.length - 1]?.txid\n if (confirmedTxs.length >= 25) break\n if (txs.length < MEMPOOL_QBIT_ADDRESS_PAGE_SIZE) {\n if (!continuationFound) throw this.invalidAddressHistoryCursorError(address, afterTxid!)\n break\n }\n if (!nextCursor || nextCursor === cursor || seenCursors.has(nextCursor)) {\n if (!continuationFound) throw this.invalidAddressHistoryCursorError(address, afterTxid!)\n throw this.nonAdvancingAddressHistoryCursorError(address, nextCursor ?? cursor)\n }\n\n seenCursors.add(nextCursor)\n cursor = nextCursor\n cursorIsMempoolTx = !isConfirmedTx(txs[txs.length - 1]!)\n }\n\n return confirmedTxs.slice(0, 25)\n }\n\n /**\n * qbit-electrs's combined route answers an `after_txid` that is the last\n * mempool row with `[]`, not the confirmed rows that follow: it passes the\n * mempool txid on as the chain cursor, which `history()` never finds\n * (`src/rest.rs:992-998` in Qbit-Org/qbit-electrs@53102e9). Reject that\n * empty page when the address stats count confirmed transactions the scan\n * has not seen.\n */\n private async assertConfirmedHistoryReached(\n address: string,\n confirmedSeen: number,\n signal: AbortSignal\n ): Promise<void> {\n const stats = addressHistoryStats(\n await this.getJson<unknown>(`/address/${encodeURIComponent(address)}`, { signal }, false),\n address,\n 'mempool-qbit'\n )\n if (stats.chain_stats.tx_count > confirmedSeen) {\n throw new QbitApiError(\n 'invalid_cursor',\n `mempool-qbit combined history ended after a mempool transaction with ${confirmedSeen} of ${stats.chain_stats.tx_count} confirmed transactions: ${address}`\n )\n }\n }\n\n /**\n * mempool-qbit does not expose `/txs/mempool`. Page through the combined\n * history until confirmed entries begin, collecting the leading mempool set.\n */\n override getAddressMempoolTxs(address: string, options?: RequestOptions): Promise<EsploraTx[]> {\n return this.runOperation(options, signal => this.scanAddressMempoolTxs(address, signal))\n }\n\n private async scanAddressMempoolTxs(address: string, signal: AbortSignal): Promise<EsploraTx[]> {\n const mempoolTxs: EsploraTx[] = []\n let cursor: string | undefined\n const seenCursors = new Set<string>()\n const seenTxids = new Set<string>()\n let pageCount = 0\n\n while (true) {\n if (pageCount >= this.maxAddressHistoryPages) {\n throw this.addressHistoryPaginationLimitError(address)\n }\n pageCount += 1\n const suffix = cursor ? `?after_txid=${encodeURIComponent(cursor)}` : ''\n const txs = await this.getJson<EsploraTx[]>(\n `/address/${encodeURIComponent(address)}/txs${suffix}`,\n { signal }\n )\n if (txs.length === 0) break\n\n for (const tx of txs) {\n if (!isConfirmedTx(tx) && !seenTxids.has(tx.txid)) {\n mempoolTxs.push(tx)\n seenTxids.add(tx.txid)\n }\n }\n\n const nextCursor = txs[txs.length - 1]?.txid\n if (txs.some(isConfirmedTx) || txs.length < MEMPOOL_QBIT_ADDRESS_PAGE_SIZE) break\n if (!nextCursor || nextCursor === cursor || seenCursors.has(nextCursor)) {\n throw this.nonAdvancingAddressHistoryCursorError(address, nextCursor ?? cursor)\n }\n\n seenCursors.add(nextCursor)\n cursor = nextCursor\n }\n\n return mempoolTxs\n }\n\n getMempoolRecommendedFees(options?: RequestOptions): Promise<MempoolRecommendedFees> {\n return this.getJson<MempoolRecommendedFees>('/fees/recommended', options)\n }\n\n override async getFeeEstimates(options?: RequestOptions): Promise<EsploraFeeEstimates> {\n return feeEstimatesFromMempoolRecommendedFees(await this.getMempoolRecommendedFees(options))\n }\n\n /**\n * Broadcast via `/tx`, falling back to the `/tx/push` form route only when\n * `/tx` reported that it did not submit the transaction. The fallback is a\n * second submission, so it follows the same policy: an already-known reply\n * resolves with the txid and an uncertain attempt rejects with\n * `unknown_outcome`. An uncertain `/tx` attempt never falls back.\n *\n * One signal and deadline cover both requests, with the same abort rules as\n * `EsploraClient.broadcastTx`. An abort or expired deadline during `/tx`\n * never sends the `/tx/push` fallback.\n */\n override async broadcastTx(rawTxHex: string, options?: BroadcastTxOptions): Promise<string> {\n const txid = resolveBroadcastTxid(rawTxHex, options)\n return this.runOperation(options, async signal => {\n try {\n return await this.submitTx('/tx', rawTxHex, txid, { signal })\n } catch (error) {\n if (!shouldRetryBroadcastViaTxPush(error)) {\n throw error\n }\n // The backend's form route parses the literal `txHash=<hex>` text itself.\n return this.submitTx('/tx/push', `txHash=${rawTxHex}`, txid, { signal })\n }\n })\n }\n\n private addressHistoryPaginationLimitError(\n address: string,\n maxPages = this.maxAddressHistoryPages\n ): QbitApiError {\n return new QbitApiError(\n 'pagination_limit',\n `mempool-qbit address history exceeded ${maxPages} pages: ${address}`\n )\n }\n\n private invalidAddressHistoryCursorError(address: string, afterTxid: string): QbitApiError {\n return new QbitApiError(\n 'invalid_cursor',\n `mempool-qbit address history cursor is stale or not confirmed: ${afterTxid} (${address})`\n )\n }\n\n private nonAdvancingAddressHistoryCursorError(address: string, cursor?: string): QbitApiError {\n return new QbitApiError(\n 'invalid_cursor',\n `mempool-qbit address history cursor stopped advancing: ${quotedResponseText(String(cursor ?? '(missing)'), this.baseUrl)} (${address})`\n )\n }\n}\n\n// ---------------------------------------------------------------------------\n// Adapters & helpers\n// ---------------------------------------------------------------------------\n\nexport interface AddressBalance {\n address: string\n confirmedSats: number\n mempoolSats: number\n totalSats: number\n}\n\n/**\n * Confirmed, mempool and total balance in satoshis from esplora address stats.\n *\n * Throws a `parse` {@link QbitApiError} unless `stats` has a string `address`\n * and `chain_stats` / `mempool_stats` objects whose `funded_txo_sum` and\n * `spent_txo_sum` are non-negative safe integers, the confirmed balance is not\n * negative, and `totalSats` is a non-negative safe integer. `mempoolSats` may\n * be negative while mempool transactions spend confirmed outputs.\n *\n * `funded_txo_sum` and `spent_txo_sum` are lifetime totals of everything the\n * address has received and spent, not balances, and `MAX_MONEY` does not\n * bound them. `JSON.parse` cannot represent integers above\n * `Number.MAX_SAFE_INTEGER` (2^53 - 1 sats, about 90M QBT) exactly, so it\n * rounds them, and they fail closed rather than yield a plausible but wrong\n * balance. A reused address that has received more than that over its life\n * therefore fails on every call, however little it holds now. For such an\n * address, sum the `value` of each output from\n * {@link EsploraClient.getAddressUtxos} instead; that raw endpoint is not\n * validated, so check that each value is a non-negative safe integer.\n *\n * The `parse` error for a negative total, here and from\n * {@link EsploraClient.getAddressBalance}, can be transient right after a\n * block on electrs: it applies the block's headers before indexing it and\n * does not deduplicate mempool stats against the chain, so a spend that was\n * just confirmed can count in both `chain_stats` and `mempool_stats` for a\n * moment. Retry it on the next poll.\n */\nexport function addressBalanceFromStats(stats: EsploraAddressStats): AddressBalance {\n if (\n !isRecord(stats) ||\n typeof stats.address !== 'string' ||\n !hasSafeTxoSums(stats.chain_stats) ||\n !hasSafeTxoSums(stats.mempool_stats)\n ) {\n throw new QbitApiError('parse', 'address stats lacked a string address or non-negative safe-integer funded/spent sums')\n }\n const confirmedSats = stats.chain_stats.funded_txo_sum - stats.chain_stats.spent_txo_sum\n const mempoolSats = stats.mempool_stats.funded_txo_sum - stats.mempool_stats.spent_txo_sum\n const totalSats = confirmedSats + mempoolSats\n if (confirmedSats < 0 || !isSafeSatAmount(totalSats)) {\n throw new QbitApiError('parse', 'address stats implied a negative or unsafe balance')\n }\n return {\n address: stats.address,\n confirmedSats,\n mempoolSats,\n totalSats,\n }\n}\n\n/**\n * Default `maxFeeRate` for {@link feeTiersFromEstimates}, in sat/vB. qbit Core's\n * `sendrawtransaction` refuses fee rates above `DEFAULT_MAX_RAW_TX_FEE_RATE{COIN / 10}`\n * per kvB by default (`src/node/transaction.h:27`), which is 10,000 sat/vB.\n */\nexport const DEFAULT_MAX_FEE_RATE_SAT_VB = 10_000\n\n/** Core's longest fee-estimate horizon: 42 periods of 24 blocks (`src/policy/fees.h:158-159`). */\nconst MAX_FEE_ESTIMATE_TARGET = 1008\n\nfunction isPositiveFeeRate(value: unknown): value is number {\n return typeof value === 'number' && Number.isFinite(value) && value > 0\n}\n\n/**\n * Only non-negative safe integers are exact satoshi amounts after `JSON.parse`.\n * Core's `MAX_MONEY` (`src/consensus/amount.h:26`) is 2.1e16, above 2^53, and\n * lifetime `funded_txo_sum` / `spent_txo_sum` totals are not bounded even by\n * that, so larger values are valid but cannot be represented and fail closed.\n */\nfunction isSafeSatAmount(value: unknown): value is number {\n return Number.isSafeInteger(value) && (value as number) >= 0\n}\n\nfunction hasSafeTxoSums(value: unknown): boolean {\n return (\n isRecord(value) &&\n isSafeSatAmount(value['funded_txo_sum']) &&\n isSafeSatAmount(value['spent_txo_sum'])\n )\n}\n\nexport interface FeeRateTier {\n /** Confirmation target in blocks. */\n target: number\n /** Fee rate in sat/vB. */\n feeRate: number\n}\n\n/**\n * Map mempool-qbit's projected blocks, leaving named policy floors unlabelled.\n *\n * Throws a `parse` {@link QbitApiError} unless `fees` is an object whose\n * `fastestFee`, `halfHourFee` and `hourFee` are finite numbers above 0. The\n * fee-rate ceiling is applied downstream by {@link feeTiersFromEstimates}.\n */\nexport function feeEstimatesFromMempoolRecommendedFees(fees: MempoolRecommendedFees): EsploraFeeEstimates {\n if (!isRecord(fees)) {\n throw new QbitApiError('parse', 'mempool-qbit recommended fees were not a JSON object')\n }\n for (const field of ['fastestFee', 'halfHourFee', 'hourFee'] as const) {\n if (!isPositiveFeeRate(fees[field])) {\n throw new QbitApiError('parse', `mempool-qbit recommended fees had an invalid ${field}`)\n }\n }\n return {\n '1': fees.fastestFee,\n '2': fees.halfHourFee,\n '3': fees.hourFee,\n }\n}\n\n/**\n * Fee-rate tiers (sat/vB) from an esplora fee-estimate map, ascending by\n * confirmation target. `{}` yields `[]`.\n *\n * Fails closed with a `parse` {@link QbitApiError} unless `estimates` is an\n * object whose every key is a canonical decimal target from 1 to 1008 blocks\n * and whose every value is a finite fee rate above 0 and at most `maxFeeRate`\n * (default {@link DEFAULT_MAX_FEE_RATE_SAT_VB}). The default is a ceiling, not\n * a sanity check: it only rejects rates above Core's default broadcast limit,\n * so a hostile or broken backend can still return 9,999 sat/vB. Set a lower\n * ceiling with `feeTiersFromEstimates(await client.getFeeEstimates(), { maxFeeRate })`,\n * cap the total fee before signing, or both.\n * Previously, malformed entries were silently dropped and no ceiling applied.\n *\n * @throws TypeError when `options.maxFeeRate` is not a finite number above 0.\n */\nexport function feeTiersFromEstimates(\n estimates: EsploraFeeEstimates,\n options: { maxFeeRate?: number } = {}\n): FeeRateTier[] {\n const maxFeeRate = options.maxFeeRate ?? DEFAULT_MAX_FEE_RATE_SAT_VB\n if (!isPositiveFeeRate(maxFeeRate)) {\n throw new TypeError('maxFeeRate must be a finite number above 0')\n }\n if (!isRecord(estimates)) {\n throw new QbitApiError('parse', 'fee estimates were not a JSON object')\n }\n return Object.entries(estimates)\n .map(([key, feeRate]) => {\n const target = Number(key)\n if (!/^[1-9]\\d*$/.test(key) || target > MAX_FEE_ESTIMATE_TARGET) {\n throw new QbitApiError(\n 'parse',\n `fee estimates had a confirmation target that is not a decimal block count from 1 to ${MAX_FEE_ESTIMATE_TARGET}`\n )\n }\n if (!isPositiveFeeRate(feeRate) || feeRate > maxFeeRate) {\n throw new QbitApiError(\n 'parse',\n `fee estimate for target ${target} was not a finite rate above 0 and at most ${maxFeeRate} sat/vB`\n )\n }\n return { target, feeRate }\n })\n .sort((a, b) => a.target - b.target)\n}\n\n/**\n * Transaction id of a raw transaction hex in legacy or BIP144 (witness)\n * encoding: the double SHA-256 of the witness-stripped serialization,\n * displayed byte-reversed. Throws a `parse` `QbitApiError` when the hex is not\n * a structurally complete transaction, or uses an encoding qbit Core refuses\n * to decode even where the txid would not change: a count or length (witness\n * section included) in a longer CompactSize form than its value needs or above\n * 0x02000000 (Core's MAX_SIZE), or a witness flag with every witness stack\n * empty.\n */\nexport function txidFromRawTx(rawTxHex: string): string {\n const txid = tryTxidFromRawTx(rawTxHex)\n if (txid === undefined) {\n throw new QbitApiError('parse', 'raw transaction hex is not a well-formed transaction')\n }\n return txid\n}\n\n/**\n * `text` without the spaces, tabs, CRs and LFs around it. An index scan, since\n * a regex trim backtracks quadratically over a long whitespace run inside the\n * text, and a reply body is unbounded. Other whitespace (NBSP, ...) is kept.\n */\nfunction trimAsciiWhitespace(text: string): string {\n let start = 0\n let end = text.length\n while (start < end && isAsciiWhitespace(text.charCodeAt(start))) start += 1\n while (end > start && isAsciiWhitespace(text.charCodeAt(end - 1))) end -= 1\n return text.slice(start, end)\n}\n\nfunction isAsciiWhitespace(code: number): boolean {\n return code === 0x20 || code === 0x09 || code === 0x0a || code === 0x0d\n}\n\nfunction tryTxidFromRawTx(rawTxHex: string): string | undefined {\n const bytes = hexToBytes(rawTxHex)\n const stripped = bytes === undefined ? undefined : witnessStrippedTx(bytes)\n if (stripped === undefined) return undefined\n return bytesToHex(sha256(sha256(stripped)).reverse())\n}\n\n/**\n * The txid a submission is tracked by: `options.txid` when given (it must be a\n * 64-hex id and agree with the hex), else the id derived from the hex, else\n * undefined when the hex is not a parseable transaction. Argument errors are\n * `TypeError`s thrown before any request is made.\n */\nfunction resolveBroadcastTxid(\n rawTxHex: string,\n options: BroadcastTxOptions | null | undefined\n): string | undefined {\n if (typeof rawTxHex !== 'string') {\n throw new TypeError('broadcastTx: rawTxHex must be a hex string')\n }\n const requested = (options ?? {}).txid\n const derived = tryTxidFromRawTx(rawTxHex)\n if (requested === undefined) return derived\n const provided = typeof requested === 'string' ? requested.toLowerCase() : ''\n if (!TXID_PATTERN.test(provided)) {\n throw new TypeError('broadcastTx: options.txid must be a 64-character hex transaction id')\n }\n if (derived !== undefined && derived !== provided) {\n throw new TypeError(\n `broadcastTx: options.txid ${provided} does not match the transaction hex (${derived})`\n )\n }\n return provided\n}\n\n/** qbit Core `serialize.h` MAX_SIZE: the largest CompactSize `ReadCompactSize` accepts. */\nconst COMPACT_SIZE_MAX = 0x02000000\n\nclass RawTxReader {\n private offset = 0\n\n constructor(private readonly bytes: Uint8Array) {}\n\n get position(): number {\n return this.offset\n }\n\n get remaining(): number {\n return this.bytes.length - this.offset\n }\n\n skip(length: number): void {\n if (length > this.remaining) throw new RangeError('raw transaction is truncated')\n this.offset += length\n }\n\n readUint8(): number {\n this.skip(1)\n return this.bytes[this.offset - 1]!\n }\n\n /**\n * qbit Core `ReadCompactSize` with its default range check (serialize.h:330\n * at v1.0.0). Only the shortest encoding of a value is valid: a `fd` prefix\n * must carry at least 0xfd, `fe` at least 0x10000 and `ff` at least\n * 0x100000000, or Core throws `non-canonical ReadCompactSize()`. A value\n * above MAX_SIZE (serialize.h:32) fails `size too large`, so every `ff`\n * encoding fails one check or the other. Core reads every count and length\n * in a transaction this way, witness stacks included.\n */\n readCompactSize(): number {\n const first = this.readUint8()\n if (first < 0xfd) return first\n const width = first === 0xfd ? 2 : first === 0xfe ? 4 : 8\n let value = 0\n for (let i = 0; i < width; i += 1) value += this.readUint8() * 2 ** (8 * i)\n const minimum = first === 0xfd ? 0xfd : first === 0xfe ? 0x10000 : 2 ** 32\n if (value < minimum) throw new RangeError('raw transaction has a non-canonical CompactSize')\n if (value > COMPACT_SIZE_MAX) throw new RangeError('raw transaction length is too large')\n return value\n }\n\n skipVarBytes(): void {\n this.skip(this.readCompactSize())\n }\n}\n\n/**\n * The witness-stripped encoding of a complete transaction, or undefined when\n * the bytes are truncated, carry trailing data, use an unknown marker, encode\n * a count or length non-canonically or above MAX_SIZE, or set the witness flag\n * with every witness stack empty. qbit Core refuses the last two even though\n * the witness section does not change the txid (`non-canonical\n * ReadCompactSize()` / `size too large`, serialize.h:330-359, and\n * `Superfluous witness record`, primitives/transaction.h:237-246, at v1.0.0;\n * a stack holding one empty item is not empty, per `ComputeHasWitness`,\n * primitives/transaction.cpp:74). Structure only: script contents and counts\n * are not validated further, so any transaction a node could decode yields\n * its txid.\n */\nfunction witnessStrippedTx(bytes: Uint8Array): Uint8Array | undefined {\n const reader = new RawTxReader(bytes)\n try {\n reader.skip(4) // version\n const witness = reader.remaining >= 2 && bytes[4] === 0x00\n if (witness) {\n if (bytes[5] !== 0x01) return undefined\n reader.skip(2) // marker + flag\n }\n const bodyStart = reader.position\n const inputCount = reader.readCompactSize()\n for (let i = 0; i < inputCount; i += 1) {\n reader.skip(36) // outpoint\n reader.skipVarBytes() // scriptSig\n reader.skip(4) // sequence\n }\n const outputCount = reader.readCompactSize()\n for (let i = 0; i < outputCount; i += 1) {\n reader.skip(8) // value\n reader.skipVarBytes() // scriptPubKey\n }\n const bodyEnd = reader.position\n if (witness) {\n let hasWitness = false\n for (let i = 0; i < inputCount; i += 1) {\n const items = reader.readCompactSize()\n if (items > 0) hasWitness = true\n for (let j = 0; j < items; j += 1) reader.skipVarBytes()\n }\n if (!hasWitness) return undefined\n }\n reader.skip(4) // locktime\n if (reader.remaining !== 0) return undefined\n if (!witness) return bytes\n const stripped = new Uint8Array(4 + (bodyEnd - bodyStart) + 4)\n stripped.set(bytes.subarray(0, 4), 0)\n stripped.set(bytes.subarray(bodyStart, bodyEnd), 4)\n stripped.set(bytes.subarray(bytes.length - 4), stripped.length - 4)\n return stripped\n } catch {\n return undefined\n }\n}\n\nfunction hexToBytes(hex: string): Uint8Array | undefined {\n if (hex.length % 2 !== 0 || !/^[0-9a-fA-F]*$/.test(hex)) return undefined\n const bytes = new Uint8Array(hex.length / 2)\n for (let i = 0; i < bytes.length; i += 1) {\n bytes[i] = parseInt(hex.slice(2 * i, 2 * i + 2), 16)\n }\n return bytes\n}\n\nfunction bytesToHex(bytes: Uint8Array): string {\n let hex = ''\n for (const byte of bytes) hex += byte.toString(16).padStart(2, '0')\n return hex\n}\n\ntype AddressHistoryBackend = 'esplora' | 'mempool-qbit'\ntype AddressHistorySource = 'confirmed' | 'mempool' | 'combined'\n\ninterface AddressHistoryScanState extends AddressHistory {\n seenTxids: Set<string>\n}\n\nfunction createAddressHistoryScanState(): AddressHistoryScanState {\n return {\n confirmed: [],\n mempool: [],\n seenTxids: new Set<string>(),\n }\n}\n\n/** Page fetches and raw rows one `getAddressHistory` call has used, across its scans. */\ninterface AddressHistoryBudget {\n pageRequests: number\n rawTransactions: number\n}\n\nfunction createAddressHistoryBudget(): AddressHistoryBudget {\n return { pageRequests: 0, rawTransactions: 0 }\n}\n\n/** Scans repeated because the address stats changed during the previous one. */\nconst MAX_ADDRESS_HISTORY_RESCANS = 1\n\ntype AddressHistoryStats = Pick<EsploraAddressStats, 'chain_stats' | 'mempool_stats'>\n\nconst ADDRESS_STATS_FIELDS = [\n 'funded_txo_count',\n 'funded_txo_sum',\n 'spent_txo_count',\n 'spent_txo_sum',\n 'tx_count',\n] as const\n\n/**\n * Run `scan` between two reads of the address stats and return its history\n * only if the reads agree and it holds exactly `chain_stats.tx_count`\n * confirmed and `mempool_stats.tx_count` mempool transactions. electrs\n * returns HTTP 200 and `[]` for a cursor it cannot find (`skip_while` in\n * `ChainQuery::_history`, `src/new_index/schema.rs:1031-1060` in\n * Qbit-Org/qbit-electrs@53102e9), and both counts are of distinct txids, as\n * the history routes list them (`stats_delta`, `schema.rs:1277-1305`;\n * `Mempool::stats`, `src/new_index/mempool.rs:280-292`). A scan during which\n * the stats changed is repeated, starting from the later read.\n */\nasync function verifiedAddressHistory(\n address: string,\n backend: AddressHistoryBackend,\n readStats: () => Promise<unknown>,\n scan: () => Promise<AddressHistory>\n): Promise<AddressHistory> {\n let before = addressHistoryStats(await readStats(), address, backend)\n for (let scans = 1; ; scans += 1) {\n const history = await scan()\n const after = addressHistoryStats(await readStats(), address, backend)\n if (!sameAddressHistoryStats(before, after)) {\n if (scans > MAX_ADDRESS_HISTORY_RESCANS) {\n throw new QbitApiError(\n 'invalid_cursor',\n `${backend} address stats changed during each of ${scans} history scans: ${address}`\n )\n }\n before = after\n continue\n }\n const confirmed = after.chain_stats.tx_count\n const mempool = after.mempool_stats.tx_count\n if (history.confirmed.length !== confirmed || history.mempool.length !== mempool) {\n throw new QbitApiError(\n 'invalid_cursor',\n `${backend} address history returned ${history.confirmed.length} confirmed and ${history.mempool.length} mempool transactions, but the address stats count ${confirmed} and ${mempool}: ${address}`\n )\n }\n return history\n }\n}\n\nfunction addressHistoryStats(\n value: unknown,\n address: string,\n backend: AddressHistoryBackend\n): AddressHistoryStats {\n if (!isRecord(value) || !hasTxCount(value['chain_stats']) || !hasTxCount(value['mempool_stats'])) {\n throw new QbitApiError(\n 'parse',\n `${backend} address stats lacked a non-negative safe-integer chain or mempool tx_count: ${address}`\n )\n }\n return value as unknown as AddressHistoryStats\n}\n\nfunction hasTxCount(value: unknown): boolean {\n return isRecord(value) && Number.isSafeInteger(value['tx_count']) && (value['tx_count'] as number) >= 0\n}\n\nfunction sameAddressHistoryStats(a: AddressHistoryStats, b: AddressHistoryStats): boolean {\n return ADDRESS_STATS_FIELDS.every(\n field =>\n a.chain_stats[field] === b.chain_stats[field] &&\n a.mempool_stats[field] === b.mempool_stats[field]\n )\n}\n\nfunction positiveAddressHistoryLimit(\n value: number | undefined,\n defaultValue: number,\n name: keyof AddressHistoryOptions\n): number {\n const limit = value ?? defaultValue\n if (!Number.isSafeInteger(limit) || limit < 1) {\n throw new QbitApiError('http', `${name} must be a positive integer`)\n }\n return limit\n}\n\nfunction assertAddressHistoryPage(\n value: unknown[],\n address: string,\n source: string\n): EsploraTx[] {\n value.forEach((tx, index) => {\n const status = isRecord(tx) ? tx['status'] : undefined\n const vin = isRecord(tx) ? tx['vin'] : undefined\n const vout = isRecord(tx) ? tx['vout'] : undefined\n if (\n !isRecord(tx) ||\n typeof tx['txid'] !== 'string' ||\n !/^[0-9a-f]{64}$/i.test(tx['txid']) ||\n !isRecord(status) ||\n typeof status['confirmed'] !== 'boolean' ||\n !Array.isArray(vin) ||\n !vin.every(isRecord) ||\n !Array.isArray(vout) ||\n !vout.every(isRecord)\n ) {\n throw new QbitApiError(\n 'parse',\n `${source} address history transaction ${index} had an invalid txid, status, vin, or vout: ${address}`\n )\n }\n const spendsFromAddress = vin.some(\n input =>\n isRecord(input) &&\n isRecord(input['prevout']) &&\n addressHistoryAddressMatches(input['prevout']['scriptpubkey_address'], address)\n )\n const paysToAddress = vout.some(\n output =>\n isRecord(output) && addressHistoryAddressMatches(output['scriptpubkey_address'], address)\n )\n if (!spendsFromAddress && !paysToAddress) {\n throw new QbitApiError(\n 'parse',\n `${source} address history transaction ${index} did not touch ${address}`\n )\n }\n })\n return value as EsploraTx[]\n}\n\nfunction reserveAddressHistoryTransactions(\n budget: AddressHistoryBudget,\n value: unknown,\n maxTransactions: number,\n address: string,\n backend: AddressHistoryBackend,\n source: string\n): unknown[] {\n if (!Array.isArray(value)) {\n throw new QbitApiError('parse', `${source} address history was not an array: ${address}`)\n }\n budget.rawTransactions += value.length\n if (budget.rawTransactions > maxTransactions) {\n throw new QbitApiError(\n 'pagination_limit',\n `${backend} address history exceeded ${maxTransactions} transactions: ${address}`\n )\n }\n return value\n}\n\nfunction addressHistoryAddressMatches(value: unknown, address: string): boolean {\n if (typeof value !== 'string') return false\n if (value === address) return true\n if (!isUniformCaseQbitBech32(value) || !isUniformCaseQbitBech32(address)) return false\n return value.toLowerCase() === address.toLowerCase()\n}\n\nconst QBIT_BECH32_HRPS = new Set(['qb', 'tq', 'qbrt'])\n\nfunction isUniformCaseQbitBech32(value: string): boolean {\n const normalized = value.toLowerCase()\n const separator = value.lastIndexOf('1')\n const hrp = normalized.slice(0, separator)\n const data = value.slice(separator + 1)\n const hasUniformCase = value === value.toLowerCase() || value === value.toUpperCase()\n return (\n separator > 0 &&\n QBIT_BECH32_HRPS.has(hrp) &&\n data.length >= 6 &&\n hasUniformCase &&\n /^[qpzry9x8gf2tvdw0s3jn54khce6mua7l]+$/i.test(data)\n )\n}\n\nfunction nextAddressHistoryCursor(\n txs: EsploraTx[],\n cursor: string | undefined,\n seenCursors: Set<string>,\n address: string,\n backend: AddressHistoryBackend\n): string {\n const nextCursor = txs[txs.length - 1]?.txid\n if (!nextCursor) {\n throw new QbitApiError(\n 'invalid_cursor',\n `${backend} address history cursor stopped advancing: (missing) (${address})`\n )\n }\n const normalizedNextCursor = nextCursor.toLowerCase()\n if (normalizedNextCursor === cursor?.toLowerCase() || seenCursors.has(normalizedNextCursor)) {\n throw new QbitApiError(\n 'invalid_cursor',\n `${backend} address history cursor stopped advancing: ${nextCursor} (${address})`\n )\n }\n seenCursors.add(normalizedNextCursor)\n return nextCursor\n}\n\nfunction appendAddressHistoryTransactions(\n state: AddressHistoryScanState,\n txs: EsploraTx[],\n source: AddressHistorySource,\n address: string,\n backend: AddressHistoryBackend\n): void {\n for (const tx of txs) {\n const normalizedTxid = tx.txid.toLowerCase()\n if (state.seenTxids.has(normalizedTxid)) {\n throw new QbitApiError(\n 'invalid_cursor',\n `${backend} address history repeated transaction ${tx.txid}: ${address}`\n )\n }\n state.seenTxids.add(normalizedTxid)\n\n const confirmed = isConfirmedTx(tx)\n if (source === 'confirmed' && !confirmed) {\n throw new QbitApiError(\n 'parse',\n `esplora confirmed history returned an unconfirmed transaction ${tx.txid}: ${address}`\n )\n }\n if (source === 'mempool' && confirmed) {\n throw new QbitApiError(\n 'parse',\n `esplora mempool history returned a confirmed transaction ${tx.txid}: ${address}`\n )\n }\n\n if (confirmed) state.confirmed.push(tx)\n else state.mempool.push(tx)\n }\n}\n\nfunction addressHistoryPageLimitError(\n address: string,\n maxPages: number,\n backend: AddressHistoryBackend\n): QbitApiError {\n return new QbitApiError(\n 'pagination_limit',\n `${backend} address history exceeded ${maxPages} page fetches: ${address}`\n )\n}\n\nfunction isConfirmedTx(tx: EsploraTx): boolean {\n return tx.status?.confirmed === true\n}\n\nfunction unknownOutcomeError(\n url: string,\n txid: string | undefined,\n reason: string,\n options: Omit<QbitApiErrorOptions, 'url' | 'txid'> = {}\n): QbitApiError {\n const subject = txid === undefined ? 'the transaction' : `txid ${txid}`\n return new QbitApiError(\n 'unknown_outcome',\n `transaction submission outcome unknown (${reason}); ${subject} may have been accepted, check its status before resubmitting`,\n { ...options, url, ...(txid === undefined ? {} : { txid }) }\n )\n}\n\ninterface ErrorCodeEntry {\n code: string\n syscall: string | undefined\n}\n\n/**\n * True when every coded error in the chain says no connection was\n * established. `EHOSTUNREACH`/`ENETUNREACH` count only from the connect\n * syscall, since a route can also vanish after the request was written.\n */\nfunction isPreConnectionFailure(error: unknown): boolean {\n const entries = collectErrorCodes(error, 0, [])\n return (\n entries.length > 0 &&\n entries.every(\n entry =>\n PRE_CONNECTION_ERROR_CODES.has(entry.code) ||\n (CONNECT_STAGE_ERROR_CODES.has(entry.code) && entry.syscall === 'connect')\n )\n )\n}\n\nfunction collectErrorCodes(error: unknown, depth: number, entries: ErrorCodeEntry[]): ErrorCodeEntry[] {\n if (!isRecord(error)) return entries\n // Too deep to judge: count it as a failure that may have reached the server,\n // so a cut-off member can't leave only pre-connection codes behind.\n if (depth > 5) {\n entries.push({ code: 'UNJUDGED', syscall: undefined })\n return entries\n }\n const nested = error['errors']\n if (Array.isArray(nested) && nested.length > 0) {\n // An AggregateError (happy eyeballs) summarises its members; judge each member.\n for (const entry of nested) collectErrorCodes(entry, depth + 1, entries)\n } else if (typeof error['code'] === 'string') {\n const syscall = error['syscall']\n entries.push({ code: error['code'], syscall: typeof syscall === 'string' ? syscall : undefined })\n }\n collectErrorCodes(error['cause'], depth + 1, entries)\n return entries\n}\n\n/**\n * Node replies meaning this exact transaction is already in the mempool or\n * chain: qbit Core's `txn-already-in-mempool`, `txn-already-known`,\n * `txn-same-nonwitness-data-in-mempool`, and RPC error -27 (already in block\n * chain / outputs already in utxo set), as relayed by esplora and mempool.\n * Conflicts with a different transaction (`txn-mempool-conflict`,\n * `bad-txns-inputs-missingorspent`) are not matched.\n */\nconst ALREADY_KNOWN_BROADCAST_REPLY =\n /\\b(?:txn already in mempool|txn already known|txn same nonwitness data in mempool|transaction already in block ?chain|transaction outputs already in utxo set)\\b/\n\nfunction isAlreadyKnownBroadcastReply(reply: BroadcastReply): boolean {\n if (reply.code === -27) return true\n return ALREADY_KNOWN_BROADCAST_REPLY.test(normalizeReplyText(reply.message))\n}\n\n/**\n * A reply in which the backend reports that its own call to the node failed\n * in transit or came back unreadable, so the node may still have processed\n * it. mempool-qbit serialises the transport error code (`{\"code\":\"ETIMEDOUT\"}`,\n * `ESOCKETTIMEDOUT`, `ECONNRESET`; backend/src/rpc-api/jsonrpc.ts via\n * bitcoin.routes.ts), `-32603` when the node answered 200 with an unreadable\n * body, or `-32602` when it answered non-200 with one: qbit Core answers 500\n * for every RPC error, so that reply may have been a -27 (already confirmed)\n * as well as a rejection or an auth failure, and `sendrawtransaction` itself\n * never raises -32602. qbit-electrs answers `Connection error` once it cannot\n * reconnect to the daemon (src/daemon.rs). Codes proving the backend never\n * connected (`ECONNREFUSED`, `ENOTFOUND`, `EAI_AGAIN`) stay definite failures.\n */\nfunction isRelayedTransportFailure(reply: BroadcastReply): boolean {\n if (typeof reply.code === 'string') return !PRE_CONNECTION_ERROR_CODES.has(reply.code)\n if (reply.code === -32603 || reply.code === -32602) return true\n return /^connection error\\b/.test(normalizeReplyText(reply.message))\n}\n\n/**\n * JSON-RPC request-level codes: the server refused the request before running\n * any method (qbit Core src/rpc/protocol.h). `-32602` is left out because a\n * relaying backend reuses it for an unreadable non-200 node reply; see\n * `isRelayedTransportFailure`.\n */\nconst RPC_REQUEST_ERROR_CODES = new Set([-32700, -32600, -32601])\n\n/**\n * True for an RPC error code that is the node's verdict on the request: one of\n * qbit Core's application codes (src/rpc/protocol.h defines -1 … -36; for\n * `sendrawtransaction` that is -22 `TX decode failed`, -25 verify error /\n * missing inputs, -26 rejected by network rules, -28 warming up, and the\n * parameter errors -1/-3/-8, all raised before the mempool is touched —\n * src/rpc/mempool.cpp, src/rpc/util.cpp `RPCErrorFromTransactionError`), or\n * a request-level code. `-32603` and `-32602` (mempool-qbit's markers for an\n * unreadable node reply) and the implementation-defined server-error range\n * `-32099 … -32000`, which Core never emits and proxies use for upstream\n * failures, describe the server or its transport, not the transaction.\n */\nfunction isNodeVerdictCode(code: number): boolean {\n return (code >= -99 && code <= -1) || RPC_REQUEST_ERROR_CODES.has(code)\n}\n\n/**\n * qbit Core's literal transaction reject reasons (src/validation.cpp,\n * src/policy/policy.cpp, src/consensus/tx_check.cpp, src/rpc/mempool.cpp),\n * recognised only at the start of an uncoded reply. Reasons that are ordinary\n * words (`coinbase`, `version`) are left out so a gateway page cannot match.\n */\nconst DEFINITE_REJECTION_REPLY =\n /^(?:bad txns |bad witness nonstandard|bad cb length|txn mempool conflict|tx decode failed|tx size\\b|tx output not p2mr|scriptsig (?:size|not pushonly)|scriptpubkey\\b|bare multisig|datacarrier|dust\\b|non (?:bip68 )?final|(?:mempool |block |(?:non )?mandatory )script verify flag|min relay fee not met|mempool min fee not met|insufficient fee|max feerate exceeded|mempool full|too long mempool chain|truc violation|missing ephemeral spends|bip125 replacement disallowed|too many potential replacements|replacement adds unconfirmed|missing inputs|no mempool\\b)/\n\n/**\n * A reply in which the node itself refused or rejected this submission, so\n * the transaction was not accepted whatever the HTTP status says: a node\n * verdict code, a relayed code proving the backend never connected to the\n * node, or, when the body carries no code at all, one of Core's reject\n * reasons. Already-known replies (-27) are resolved before this is consulted.\n */\nfunction isDefiniteNodeRejection(reply: BroadcastReply): boolean {\n if (typeof reply.code === 'number') return isNodeVerdictCode(reply.code)\n if (typeof reply.code === 'string') return PRE_CONNECTION_ERROR_CODES.has(reply.code)\n return DEFINITE_REJECTION_REPLY.test(normalizeReplyText(reply.message))\n}\n\n/**\n * Fallback only after `/tx` reported that it did not submit: a missing route\n * or the backend's generic no-RPC-code failure. `unknown_outcome` never\n * qualifies, since the transaction may already be with the node.\n */\nfunction shouldRetryBroadcastViaTxPush(error: unknown): boolean {\n if (!QbitApiError.is(error)) return false\n if (\n (error.kind === 'not_found' && error.status === 404) ||\n (error.kind === 'http' && (error.status === 405 || error.status === 501))\n ) {\n return true\n }\n // Another copy's error keeps its raw body where this copy cannot read it, and\n // its `responseBody` may be a redacted preview, so its body never qualifies.\n const body = error instanceof QbitApiError ? (rawResponseBodies.get(error) ?? error.responseBody) : undefined\n if (error.kind !== 'http' || error.status !== 400 || body === undefined) {\n return false\n }\n\n // mempool-qbit reserves this generic response for failures without an RPC\n // error code; a reply carrying a node RPC or transport code is never that\n // generic failure, whatever its message says.\n const reply = parseBroadcastReply(body)\n if (reply.code !== undefined) return false\n return /^(?:(?:failed|unable) to|could not) (?:send|submit|broadcast)(?: raw)? transaction$/.test(\n normalizeReplyText(reply.message)\n )\n}\n\ninterface BroadcastReply {\n /**\n * Node RPC error code (a negative integer, as all of qbit Core's are) or\n * relayed transport code (upper-cased, see `TRANSPORT_ERROR_CODE_PATTERN`)\n * from a structured body. A positive number is an HTTP status echo and\n * any other string a gateway code; neither describes the node call, so\n * both are left out.\n */\n code: number | string | undefined\n /** Human-readable detail: the structured body's message, or the body itself. */\n message: string\n}\n\n/**\n * Read a rejection body into its error code and message. Backends answer in\n * several shapes: plain text, optionally with an embedded\n * `sendrawtransaction RPC error: {\"code\":...,\"message\":...}` object (esplora,\n * mempool-qbit); the node's JSON-RPC envelope `{\"error\":{\"code\",\"message\"}}`;\n * a flat `{\"code\",\"message\"}` object; or a JSON string / `{\"error\":\"...\"}` /\n * `{\"message\":\"...\"}` wrapper around the plain-text form. The code is taken\n * from the structured object before the body is reduced to its message, since\n * the code is authoritative while the message may be localised or reworded.\n * A nested `error.code` wins over a top-level `code`.\n */\nfunction parseBroadcastReply(body: string): BroadcastReply {\n let text = body\n try {\n const parsed = JSON.parse(body) as unknown\n if (typeof parsed === 'string') {\n text = parsed\n } else if (isRecord(parsed)) {\n const nested = parsed['error']\n const code = errorCodeOf(nested) ?? errorCodeOf(parsed)\n let message = body\n if (typeof nested === 'string') message = nested\n else if (isRecord(nested) && typeof nested['message'] === 'string') message = nested['message']\n else if (typeof parsed['message'] === 'string') message = parsed['message']\n // A JSON wrapper around the plain-text form still carries the code in that text.\n return { code: code ?? embeddedErrorCode(message), message }\n }\n } catch {\n // Plain-text backend errors are expected here.\n }\n return { code: embeddedErrorCode(text), message: text }\n}\n\nfunction errorCodeOf(value: unknown): number | string | undefined {\n if (!isRecord(value)) return undefined\n const code = value['code']\n if (typeof code === 'number') return Number.isInteger(code) && code < 0 ? code : undefined\n if (typeof code !== 'string') return undefined\n const transportCode = code.toUpperCase()\n return TRANSPORT_ERROR_CODE_PATTERN.test(transportCode) ? transportCode : undefined\n}\n\n/**\n * Code from an esplora/mempool `sendrawtransaction RPC error: {\"code\":...}`\n * object embedded in plain text: a number for node RPC errors, or a string\n * when mempool-qbit relays its own transport failure (`{\"code\":\"ETIMEDOUT\"}`).\n */\nfunction embeddedErrorCode(text: string): number | string | undefined {\n const start = text.indexOf('{')\n const end = text.lastIndexOf('}')\n if (start === -1 || end <= start) return undefined\n try {\n const parsed = JSON.parse(text.slice(start, end + 1)) as unknown\n if (isRecord(parsed)) return errorCodeOf(parsed['error']) ?? errorCodeOf(parsed)\n } catch {\n // Not an RPC error object; the caller falls back to message matching.\n }\n return undefined\n}\n\nfunction normalizeReplyText(text: string): string {\n return text.toLowerCase().replace(/[^a-z0-9]+/g, ' ').trim()\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\n/** `Retry-After` (delta-seconds or HTTP-date) as a non-negative, finite whole number of ms. */\nfunction parseRetryAfter(value: string | null): number | undefined {\n if (!value) return undefined\n let ms: number\n const seconds = Number(value)\n // Overlong delta-seconds overflow to Infinity; keep them as \"too long\", not unparseable.\n if (!Number.isNaN(seconds)) {\n ms = seconds * 1000\n } else {\n const date = Date.parse(value)\n if (!Number.isFinite(date)) return undefined\n ms = date - Date.now()\n }\n return Math.min(Math.max(0, Math.ceil(ms)), Number.MAX_SAFE_INTEGER)\n}\n\nfunction isAbortError(error: unknown): boolean {\n return typeof error === 'object' && error !== null && (error as { name?: string }).name === 'AbortError'\n}\n\n/** `localhost`, `127.0.0.0/8` or `[::1]`, as normalized by the URL parser (`127.1` is `127.0.0.1`). */\nfunction isLoopbackHostname(hostname: string): boolean {\n return hostname === 'localhost' || hostname === '[::1]' || /^127\\.\\d+\\.\\d+\\.\\d+$/.test(hostname)\n}\n\n/** Ports a URL parser drops from a URL with this scheme. */\nconst DEFAULT_PORTS: Record<string, string> = {\n 'http:': '80',\n 'https:': '443',\n 'ws:': '80',\n 'wss:': '443',\n 'ftp:': '21',\n}\n\n/**\n * The lowercased scheme and host of a URL with a scheme, without userinfo or\n * one trailing dot, whether it has userinfo (an `@` in the authority), its\n * port (empty for the scheme's default) and its path with the query (`/` for\n * an empty path, without the fragment); undefined for a relative URL that\n * `base` does not resolve. A runtime URL parser that\n * follows the URL Standard canonicalizes first (`127.1`, IDN, `[0::1]`, dot\n * segments, percent-encoding), but the parts are read by hand: React Native's\n * global URL throws from `protocol` and `hostname` before 0.80, and from 0.80\n * reads them with regexes that neither lowercase nor end the authority at the\n * first `/`, so `https://evil.example/@host` would have the hostname `host`.\n * There the configured spelling is read, since its `href` appends a `/`.\n */\nfunction schemeAndHost(\n url: string,\n base?: string\n): { protocol: string; hostname: string; userinfo: boolean; port: string; path: string } | undefined {\n const match = /^([a-z][a-z\\d+.-]*:)[/\\\\]*([^/?#\\\\]*)([^#]*)/i.exec(standardHref(url, base) ?? url)\n if (!match) return undefined\n const protocol = match[1]!.toLowerCase()\n const at = match[2]!.lastIndexOf('@')\n const authority = match[2]!.slice(at + 1)\n const [, hostname, port] = /^(\\[[^\\]]*\\]|[^:]*):?(.*)$/s.exec(authority)!\n return {\n protocol,\n hostname: hostname!.toLowerCase().replace(/\\.$/, ''),\n userinfo: at !== -1,\n port: port === DEFAULT_PORTS[protocol] ? '' : port!,\n path: match[3]!.startsWith('/') ? match[3]! : `/${match[3]!}`,\n }\n}\n\n/**\n * `new URL(url, base).href` where the runtime's URL parser follows the URL\n * Standard; undefined where it does not parse `url`, and on React Native.\n */\nfunction standardHref(url: string, base?: string): string | undefined {\n if (!followsUrlStandard()) return undefined\n try {\n return new URL(url, base).href\n } catch {\n return undefined\n }\n}\n\n/**\n * Whether the runtime's URL parser follows the URL Standard (Node, browsers,\n * Deno, Bun). React Native's does not: its `href` is the input with a `/`\n * appended, and its other getters throw before 0.80.\n */\nfunction followsUrlStandard(): boolean {\n try {\n return new URL('HTTP://Q.EXAMPLE:80/a/../b').href === 'http://q.example/b'\n } catch {\n return false\n }\n}\n\n/**\n * True when `response.url` is not the requested URL: another scheme, host,\n * port, or path and query. React Native's fetch ignores `redirect: 'manual'`:\n * the platform follows the redirect and the reply arrives with the final URL\n * in `url` but without `redirected`. A redirect within the backend is refused\n * too, since its reply answers another request (another transaction's status,\n * say). Both URLs are read with `schemeAndHost`, so the case of the scheme and\n * host, a default port and a trailing dot on the host do not count. When\n * either URL cannot be read, the reply counts as from another URL.\n */\nfunction fromAnotherUrl(response: Response, url: string): boolean {\n if (typeof response.url !== 'string' || response.url === '') return false\n const requested = schemeAndHost(url)\n const replied = schemeAndHost(response.url)\n if (!requested || !replied) return true\n return (\n replied.protocol !== requested.protocol ||\n replied.hostname !== requested.hostname ||\n replied.port !== requested.port ||\n replied.path !== requested.path\n )\n}\n\n/**\n * Requests use `redirect: 'manual'`, so a redirect arrives here as a 3xx, or in\n * browsers as an `opaqueredirect` with status 0. Following it would send the\n * configured headers wherever `Location` points and accept that server's reply\n * as backend data. A fetch that ignores `redirect` and follows anyway reports\n * `redirected`, or a `url` other than the request's; its reply is refused too.\n */\nfunction refuseRedirect(response: Response, url: string, baseUrl: string): Response {\n const opaque = response.type === 'opaqueredirect'\n const redirectStatus = response.status >= 300 && response.status <= 399\n if (!opaque && !redirectStatus && response.redirected !== true && !fromAnotherUrl(response, url)) {\n return response\n }\n void discardResponseBody(response)\n const errorUrl = redactBaseUrl(url, baseUrl)\n if (opaque) {\n throw new QbitApiError('http', `redirect refused (target hidden by the browser): ${errorUrl}`, { url: errorUrl })\n }\n if (redirectStatus) {\n const target = redactRedirectTarget(redirectTargetOrigin(response.headers.get('location'), url), baseUrl)\n throw new QbitApiError('http', `HTTP ${response.status} redirect to ${target} refused: ${errorUrl}`, {\n status: response.status,\n url: errorUrl,\n })\n }\n const target = redactRedirectTarget(redirectTargetOrigin(response.url, url), baseUrl)\n throw new QbitApiError('http', `fetch followed a redirect to ${target}; reply discarded: ${errorUrl}`, {\n url: errorUrl,\n })\n}\n\n/**\n * A redirect target as its origin only; its path and query may carry tokens.\n * Read with `schemeAndHost`, not the runtime's `origin`: React Native's throws\n * before 0.80 and from 0.80 keeps userinfo and a query. Where the runtime\n * cannot resolve a relative location, a scheme-relative one keeps the\n * request's scheme and any other keeps its origin.\n */\nfunction redirectTargetOrigin(location: string | null, url: string): string {\n if (!location) return 'an unspecified location'\n const target =\n schemeAndHost(location, url) ??\n schemeAndHost(/^[/\\\\]{2}/.test(location) ? `${schemeAndHost(url)?.protocol ?? ''}${location}` : url)\n if (!target) return 'an invalid location'\n if (!/^(?:https?|wss?|ftp):$/.test(target.protocol)) return `a ${target.protocol} URL`\n if (!/^(?:[a-z\\d._~-]+|\\[[a-f\\d:.]+\\])$/.test(target.hostname) || !/^\\d*$/.test(target.port)) {\n return 'an invalid location'\n }\n return `${target.protocol}//${target.hostname}${target.port ? `:${target.port}` : ''}`\n}\n\n/**\n * The base URL as errors show it: its origin, with `/...` in place of any path\n * or query, where hosted indexers often put an API token\n * (`https://host/<token>/api`). Errors get logged and reported. Read by hand\n * after the runtime's URL parser has normalized it, as in `schemeAndHost`:\n * React Native's `origin` throws before 0.80 and keeps credentials from 0.80.\n * `...` alone when the host cannot be read reliably.\n */\nfunction redactedBaseUrl(baseUrl: string): string {\n let href = baseUrl\n try {\n href = new URL(baseUrl).href\n } catch {\n // Not parsable here: read the configured spelling.\n }\n const match = /^(https?:)[/\\\\]*([^/?#\\\\]*)/i.exec(href)\n if (!match) return '...' // Not an http(s) URL: show none of it.\n const host = match[2]!.slice(match[2]!.lastIndexOf('@') + 1).toLowerCase()\n // A password with a raw `/`, `?`, `#` or `\\` ends the authority early, so\n // the host read can be `user:password-prefix`, or (`apikey:8443/x@host`) a\n // username and a numeric password the URL parser takes for host and port.\n // Show only a plain host[:port] with no `@` after it.\n if (!/^(?:[a-z\\d._~-]+|\\[[a-f\\d:.]+\\])(?::\\d*)?$/.test(host) || href.slice(match[0].length).includes('@')) {\n return '...'\n }\n const origin = `${match[1]!.toLowerCase()}//${host}`\n return basePath(href) ? `${origin}/...` : origin\n}\n\n/**\n * `text` with the base URL replaced by `redactedBaseUrl`, both as configured\n * and as the URL parser normalizes it: fetch implementations quote either form\n * in their own error messages. The base URL's path and query become `/...`\n * where they appear on their own, as servers quote the request path (Express:\n * `Cannot GET /<token>/api/blocks/tip/height`), and each of `baseUrlParts`\n * becomes `...`, as a server may quote a token alone. One pass, longest match\n * first, so replaced text is not matched again.\n */\nfunction redactBaseUrl(text: string, baseUrl: string): string {\n const spellings = [baseUrl]\n try {\n spellings.push(new URL(baseUrl).href.replace(/\\/+$/, ''))\n } catch {\n // Unparsable: only the configured spelling can appear.\n }\n const redacted = redactedBaseUrl(baseUrl)\n const replacements = new Map<string, string>()\n for (const part of spellings.flatMap(baseUrlParts)) replacements.set(part, '...')\n for (const path of spellings.map(basePath)) if (path) replacements.set(path, '/...')\n for (const spelling of spellings) if (spelling) replacements.set(spelling, redacted)\n if (replacements.size === 0) return text\n const pattern = [...replacements.keys()]\n .sort((a, b) => b.length - a.length)\n .map(needle => needle.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'))\n .join('|')\n return text.replace(new RegExp(pattern, 'g'), match => replacements.get(match)!)\n}\n\n/**\n * Parts of a base URL that a server may quote on their own (`invalid api key\n * <token>`, a JSON-escaped `\\/<token>\\/` or `%2F`-joined path): each path\n * segment, query value and userinfo part of at least 8 characters, also\n * percent-decoded. Userinfo runs to the last `@` before the query, so a\n * password with a raw `/` is found whole, and path segments are read both\n * after the authority and after that `@`.\n */\nfunction baseUrlParts(url: string): string[] {\n const match = /^(?:[a-z][a-z\\d+.-]*:[/\\\\]*)?([^?#]*)(?:\\?([^#]*))?/i.exec(url)!\n const beforeQuery = match[1]!\n const at = beforeQuery.lastIndexOf('@')\n const userinfo = at === -1 ? '' : beforeQuery.slice(0, at)\n const colon = userinfo.indexOf(':')\n const parts = [\n ...(colon === -1 ? [userinfo] : [userinfo.slice(0, colon), userinfo.slice(colon + 1)]),\n ...beforeQuery.split(/[/\\\\]/).slice(1),\n ...beforeQuery.slice(at + 1).split(/[/\\\\]/).slice(1),\n ...(match[2] ?? '').split('&').map(pair => pair.slice(pair.indexOf('=') + 1)),\n ]\n return parts.flatMap(part => [part, percentDecoded(part)]).filter(part => part.length >= 8)\n}\n\nfunction percentDecoded(text: string): string {\n try {\n return decodeURIComponent(text)\n } catch {\n return text\n }\n}\n\n/** What follows the origin of an absolute URL; empty for a bare origin or a relative URL. */\nfunction basePath(url: string): string {\n const path = /^[a-z][a-z\\d+.-]*:[/\\\\]*[^/?#\\\\]*(.*)$/i.exec(url)?.[1] ?? ''\n return path === '/' ? '' : path\n}\n\n/**\n * A redirect target's origin with the base URL's parts redacted. The server\n * chose it, and a provider that moves a key from the path into a subdomain\n * would put the key in the message. Hosts are lowercased, so parts are matched\n * case-insensitively.\n */\nfunction redactRedirectTarget(target: string, baseUrl: string): string {\n const redacted = redactBaseUrl(target, baseUrl)\n const parts = [...new Set(baseUrlParts(baseUrl))].sort((a, b) => b.length - a.length)\n if (parts.length === 0) return redacted\n const pattern = parts.map(part => part.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')).join('|')\n return redacted.replace(new RegExp(pattern, 'gi'), '...')\n}\n\n/** A response body preview: trimmed, the base URL redacted, capped at 200 characters. */\nfunction responseBodyPreview(text: string, baseUrl: string): string {\n return redactBaseUrl(text.trim(), baseUrl).slice(0, 200)\n}\n\n/** Response text quoted in an error message: `responseBodyPreview` with control characters escaped. */\nfunction quotedResponseText(text: string, baseUrl: string): string {\n return escapeControlChars(responseBodyPreview(text, baseUrl))\n}\n\n/** How many levels of nested errors and objects a redacted cause keeps. */\nconst REDACTED_CAUSE_DEPTH = 5\n\n/** Built-in error classes a redacted cause keeps, so `cause instanceof TypeError` still holds. */\nconst NATIVE_ERRORS: (new (message?: string) => Error)[] = [\n Error,\n TypeError,\n RangeError,\n SyntaxError,\n ReferenceError,\n EvalError,\n URIError,\n]\n\n/** `QbitApiError` options for an underlying error: a redacted `cause`, the original kept off the error. */\nfunction causeOptions(cause: unknown, baseUrl: string): { cause: unknown; unredactedCause: unknown } {\n return { cause: redactedCause(cause, baseUrl, REDACTED_CAUSE_DEPTH), unredactedCause: cause }\n}\n\n/**\n * A copy of an underlying error that is safe to log. Fetch implementations put\n * the full request URL in their errors (Bun's `path`, Node's messages for a\n * credentialed or relative URL, node-fetch's), and loggers print `cause`\n * (`console.error`, `util.inspect`, Sentry, pino). Strings pass through\n * `redactBaseUrl`: the message, the stack and every string property. Errors\n * (a nested `cause` included), arrays and plain objects are copied the same\n * way, `depth` levels deep, keeping each property's enumerability; deeper\n * values, accessors and other objects are left out. An error keeps its\n * `name`, and its class when that is a built-in one.\n */\nfunction redactedCause(value: unknown, baseUrl: string, depth: number): unknown {\n if (typeof value === 'string') return redactBaseUrl(value, baseUrl)\n if (typeof value === 'function') return undefined\n if (typeof value !== 'object' || value === null) return value\n if (depth === 0) return undefined\n if (Array.isArray(value)) return value.map(item => redactedCause(item, baseUrl, depth - 1))\n try {\n let copy: object\n const prototype: unknown = Object.getPrototypeOf(value)\n if (value instanceof Error) {\n const ErrorClass = NATIVE_ERRORS.find(errorClass => errorClass === value.constructor) ?? Error\n const error = new ErrorClass(redactBaseUrl(String(value.message), baseUrl))\n if (error.name !== value.name) {\n Object.defineProperty(error, 'name', { value: String(value.name), writable: true, configurable: true })\n }\n error.stack = typeof value.stack === 'string' ? redactBaseUrl(value.stack, baseUrl) : `${error.name}: ${error.message}`\n copy = error\n } else if (prototype === Object.prototype || prototype === null) {\n copy = {}\n } else {\n return undefined\n }\n for (const key of Object.getOwnPropertyNames(value)) {\n if (value instanceof Error && (key === 'message' || key === 'stack')) continue\n const descriptor = Object.getOwnPropertyDescriptor(value, key)\n if (descriptor === undefined || !('value' in descriptor)) continue\n const redacted = redactedCause(descriptor.value, baseUrl, depth - 1)\n if (redacted === undefined && descriptor.value !== undefined) continue\n Object.defineProperty(copy, key, {\n value: redacted,\n enumerable: descriptor.enumerable ?? false,\n writable: true,\n configurable: true,\n })\n }\n return copy\n } catch {\n return undefined\n }\n}\n\n/**\n * Response text for an error message, with control characters (CR and LF\n * included), Unicode line separators and bidi controls escaped so a hostile\n * body cannot forge or reorder log lines. `responseBody` keeps them unescaped.\n */\nfunction escapeControlChars(text: string): string {\n return text.replace(/[\\p{Cc}\\p{Zl}\\p{Zp}\\p{Bidi_Control}]/gu, char => {\n if (char === '\\n') return '\\\\n'\n if (char === '\\r') return '\\\\r'\n if (char === '\\t') return '\\\\t'\n return `\\\\u${char.charCodeAt(0).toString(16).padStart(4, '0')}`\n })\n}\n\nfunction formatErrorCause(error: unknown): string {\n if (error instanceof Error) {\n return ` (${error.name}: ${error.message})`\n }\n if (typeof error === 'string') {\n return ` (${error})`\n }\n return ''\n}\n\n/**\n * Read a call's response body as text through `readBodyUntilAborted`, the one\n * body reader. If `signal` aborts first, reject at once with the call's\n * `aborted` / `timeout` error and cancel the body (best-effort, never\n * awaited); a failed read is `parse`. fetchOnce has already buffered the\n * response, so a de-duplicated GET's clone reads from memory. `url` is the\n * request URL as errors show it.\n */\nasync function readBody(response: Response, url: string, baseUrl: string, signal: AbortSignal): Promise<string> {\n if (signal.aborted) {\n const error = abortErrorFor(signal)\n void discardResponseBody(response, error)\n throw error\n }\n try {\n return await readBodyUntilAborted(response, signal)\n } catch (cause) {\n if (signal.aborted) throw abortErrorFor(signal)\n throw bodyReadError(response, cause, url, baseUrl)\n }\n}\n\nfunction bodyReadError(response: Response, cause: unknown, url: string, baseUrl: string): QbitApiError {\n return new QbitApiError('parse', `failed to read response body from ${url}`, {\n url,\n status: response.status,\n ...causeOptions(cause, baseUrl),\n })\n}\n\n/**\n * Read the whole body as text, giving up as soon as `signal` aborts. The\n * stream is cancelled on failure, so a body that stalls after the headers\n * releases its connection even if the fetch implementation ignores the signal.\n */\nasync function readBodyUntilAborted(response: Response, signal: AbortSignal): Promise<string> {\n let rejectAborted: (reason: unknown) => void = () => {}\n const aborted = new Promise<never>((_, reject) => {\n rejectAborted = reject\n })\n // Every path below races `aborted`; this only guards an early synchronous throw.\n aborted.catch(() => {})\n const onAbort = () => rejectAborted(signal.reason)\n if (signal.aborted) onAbort()\n else signal.addEventListener('abort', onAbort, { once: true })\n\n try {\n const body = response.body\n if (!body || typeof body.getReader !== 'function' || typeof TextDecoder !== 'function') {\n try {\n return await Promise.race([response.text(), aborted])\n } catch (error) {\n if (signal.aborted) releaseBody(body, signal.reason)\n throw error\n }\n }\n const reader = body.getReader()\n const decoder = new TextDecoder()\n let text = ''\n try {\n while (true) {\n const chunk = await Promise.race([reader.read(), aborted])\n if (chunk.done) return text + decoder.decode()\n text += decoder.decode(chunk.value, { stream: true })\n }\n } catch (error) {\n reader.cancel(error).catch(() => {\n // Cancellation is best-effort; the read failure remains authoritative.\n })\n throw error\n }\n } finally {\n signal.removeEventListener('abort', onAbort)\n }\n}\n\n/**\n * Best-effort, non-blocking release of a body whose `text()` lost the race to\n * the deadline, for a fetch implementation that ignores the signal once the\n * headers have arrived. A web stream is cancelled (a no-op if `text()` holds\n * its lock). A Node-style stream is destroyed with the reason, which settles\n * a consumer such as `text()` that listens for `'error'`; with no `'error'`\n * listener it is destroyed without one, since an unhandled `'error'` event\n * would crash the process.\n */\nfunction releaseBody(body: unknown, reason: unknown): void {\n if (body === null || typeof body !== 'object') return\n const stream = body as { cancel?: unknown; destroy?: unknown; listenerCount?: unknown }\n try {\n if (typeof stream.cancel === 'function') {\n const result = stream.cancel(reason) as { then?: unknown } | null | undefined\n if (result && typeof result.then === 'function') (result as PromiseLike<unknown>).then(undefined, () => {})\n } else if (typeof stream.destroy === 'function') {\n const handled = typeof stream.listenerCount === 'function' && Number(stream.listenerCount('error')) > 0\n if (handled) stream.destroy(reason)\n else stream.destroy()\n }\n } catch {\n // Cleanup is best-effort; the timeout remains authoritative.\n }\n}\n\n/** Statuses whose responses carry no body; `new Response` rejects one for them. */\nconst NULL_BODY_STATUSES = new Set([204, 205, 304])\n\n/**\n * A fully buffered copy of `response`. A custom `fetchFn` (node-fetch on old\n * Node, React Native polyfills) may run where there is no global `Response`,\n * or one that rejects the fetched status, so this falls back to a minimal\n * Response-like object instead of failing the attempt.\n */\nfunction bufferedResponse(response: Response, text: string): Response {\n const body = NULL_BODY_STATUSES.has(response.status) ? null : text\n const buffered = constructedResponse(response, body) ?? plainBufferedResponse(response, body ?? '')\n // Constructed responses (and their clones) have an empty `url`; keep the\n // fetched one for errors, including on clones handed to de-duplicated GETs.\n // `headers` stays the fetched object, which may be a foreign or minimal\n // `Headers`, so it is never handed to the constructor to re-parse.\n Object.defineProperties(buffered, {\n url: { value: response.url },\n headers: { value: response.headers },\n clone: { value: () => bufferedResponse(response, text) },\n })\n return buffered\n}\n\nfunction constructedResponse(response: Response, body: string | null): Response | undefined {\n if (typeof Response !== 'function') return undefined\n try {\n return new Response(body, { status: response.status, statusText: response.statusText })\n } catch {\n return undefined\n }\n}\n\n/**\n * The subset of `Response` the client and `request()` callers rely on:\n * status fields, `text()`/`json()` with single-use `bodyUsed` semantics, and\n * (added by the caller) `url`, `headers` and `clone()`. `body` is `null`, as\n * there is no stream to read or cancel.\n */\nfunction plainBufferedResponse(response: Response, text: string): Response {\n let bodyUsed = false\n const consume = async (): Promise<string> => {\n if (bodyUsed) throw new TypeError('Body has already been consumed')\n bodyUsed = true\n return text\n }\n return {\n status: response.status,\n statusText: response.statusText,\n ok: response.status >= 200 && response.status <= 299,\n redirected: response.redirected ?? false,\n type: response.type ?? 'default',\n body: null,\n get bodyUsed() {\n return bodyUsed\n },\n text: consume,\n json: async () => JSON.parse(await consume()) as unknown,\n } as unknown as Response\n}\n\nasync function discardResponseBody(response: Response, reason?: unknown): Promise<void> {\n if (response.body === null || response.bodyUsed) return\n try {\n await response.body.cancel(reason)\n } catch {\n // Cleanup is best-effort; the retry result remains authoritative.\n }\n}\n\n/** A reply as error messages quote it: `url` redacted, `detail` a `responseBodyPreview`. */\nfunction httpReplyMessage(status: number, url: string, detail: string): string {\n return `HTTP ${status} from ${url}${detail ? `: ${escapeControlChars(detail)}` : ''}`\n}\n\n/**\n * Unredacted response previews, keyed by error. Only the SDK's own decisions\n * read them (the `/tx/push` fallback): redaction can rewrite words of a reply\n * when a base-URL part matches them.\n */\nconst rawResponseBodies = new WeakMap<QbitApiError, string>()\n\nfunction httpError(response: Response, body: string, url: string, baseUrl: string): QbitApiError {\n const status = response.status\n const detail = responseBodyPreview(body, baseUrl)\n const message = httpReplyMessage(status, url, detail)\n const options: QbitApiErrorOptions = { status, url, responseBody: detail }\n const retryAfterMs = parseRetryAfter(response.headers.get('retry-after'))\n if (retryAfterMs !== undefined) options.retryAfterMs = retryAfterMs\n const error =\n status === 429\n ? new QbitApiError('rate_limit', message, options)\n : status === 413\n ? new QbitApiError('payload_too_large', message, options)\n : status === 404\n ? new QbitApiError('not_found', message, options)\n : new QbitApiError('http', message, options)\n rawResponseBodies.set(error, body.trim().slice(0, 200))\n return error\n}\n"],"mappings":"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","names":["target"]}
|