UNPKG

@bsv/wallet-toolbox

Version:

BRC100 conforming wallet, wallet storage and wallet signer components

111 lines 4.12 kB
"use strict"; /** * Client for Arcade transaction status updates. * * Uses react-native-sse EventSource to connect to Arcade's * `GET /events?callbackToken=<token>` endpoint for real-time * status updates via SSE. * * Supports on-demand fetching via fetchEvents() for use on * app open, balance refresh, transaction list view, etc. * The EventSource stays connected between fetches for live updates. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.ArcSSEClient = void 0; const TAG = '[ArcSSE]'; class ArcSSEClient { constructor(options) { this.options = options; this.es = null; this.connected = false; this.connecting = false; this._lastEventId = options.lastEventId; let base = options.baseUrl; while (base.endsWith('/')) { base = base.slice(0, -1); } this.url = `${base}/events?callbackToken=${encodeURIComponent(options.callbackToken)}`; } get lastEventId() { return this._lastEventId; } /** * Open the SSE connection. Events will be dispatched via onEvent as they arrive. */ connect() { if (this.es) { console.log(`${TAG} already connected`); return; } this.connecting = true; const ESClass = this.options.EventSourceClass; const headers = { 'Last-Event-ID': this._lastEventId || '0' }; if (this.options.arcApiKey) { headers['Authorization'] = `Bearer ${this.options.arcApiKey}`; } console.log(`${TAG} connecting to ${this.url} (Last-Event-ID: ${headers['Last-Event-ID']})`); this.es = new ESClass(this.url, { headers, debug: true, pollingInterval: 0 // Don't auto-reconnect on close — we manage lifecycle }); this.es.addEventListener('open', () => { this.connected = true; this.connecting = false; console.log(`${TAG} connected`); }); this.es.addEventListener('status', (event) => { var _a, _b; try { const data = JSON.parse(event.data); console.log(`${TAG} event: txid=${data.txid} status=${data.txStatus}`); if (event.lastEventId) { this._lastEventId = event.lastEventId; (_b = (_a = this.options).onLastEventIdChanged) === null || _b === void 0 ? void 0 : _b.call(_a, event.lastEventId); } this.options.onEvent(data); } catch (_c) { console.log(`${TAG} malformed event: ${String(event.data).substring(0, 200)}`); } }); this.es.addEventListener('error', (event) => { var _a, _b; console.log(`${TAG} error:`, JSON.stringify(event)); this.connected = false; this.connecting = false; (_b = (_a = this.options).onError) === null || _b === void 0 ? void 0 : _b.call(_a, new Error(event.message || 'SSE error')); }); } /** Close the connection and clean up */ close() { if (this.es) { console.log(`${TAG} closing`); this.es.close(); this.es = null; this.connected = false; this.connecting = false; } } /** * Ensure connection is open. If already connected, this is a no-op. * If not connected, opens a new connection with catchup from lastEventId. * Returns immediately — events arrive asynchronously via onEvent callback. */ async fetchEvents() { if (!this.es && !this.connecting) { this.connect(); } else if (this.es && !this.connected && !this.connecting) { // Connection exists but failed — reconnect this.close(); this.connect(); } // Events arrive asynchronously — return 0 since we can't know the count synchronously return 0; } } exports.ArcSSEClient = ArcSSEClient; //# sourceMappingURL=ArcSSEClient.js.map