aboutsummaryrefslogtreecommitdiffstats
path: root/src/api.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/api.js')
-rw-r--r--src/api.js30
1 files changed, 15 insertions, 15 deletions
diff --git a/src/api.js b/src/api.js
index 8ceb870..1c70640 100644
--- a/src/api.js
+++ b/src/api.js
@@ -147,22 +147,22 @@ export class Api {
return { fastestFee: 20, halfHourFee: 10, hourFee: 5, economyFee: 2, minimumFee: 1 };
}
+ // Broadcast to ALL explorers in parallel (not via the throttle — a send is
+ // urgent) so the tx is visible regardless of which explorer the recipient
+ // watches. Resolves with the txid if any accept it; rejects only if all fail.
async broadcast(hexTx) {
- let lastErr;
- for (const base of this._hosts) {
- try {
- const res = await this.#run(base + '/tx', { method: 'POST', body: hexTx });
- const body = await res.text();
- if (!res.ok) {
- lastErr = new Error(body || `${res.status} broadcast failed`);
- continue;
- }
- return body.trim(); // txid
- } catch (e) {
- lastErr = e;
- }
- }
- throw lastErr;
+ if (this.offline) throw new Error('offline');
+ const attempts = this._hosts.map(async (base) => {
+ const res = await fetch(base + '/tx', { method: 'POST', body: hexTx });
+ const body = await res.text();
+ if (res.status === 429) this.#penalize();
+ if (!res.ok) throw new Error(body || `${res.status} broadcast failed`);
+ return body.trim(); // txid
+ });
+ const results = await Promise.allSettled(attempts);
+ const ok = results.find((r) => r.status === 'fulfilled');
+ if (ok) return ok.value;
+ throw (results.find((r) => r.status === 'rejected') || {}).reason || new Error('broadcast failed');
}
}