UNPKG

@abstraxn/relayer

Version:

Abstraxn Relayer package for handling gas-less transactions, facilitating smart contract interactions, and relaying user transactions efficiently.

203 lines 7.17 kB
import { io } from 'socket.io-client'; export class WebSocketManager { constructor(relayerUrl, config = {}) { this.socket = null; this.subscribedTransactions = new Map(); this.isConnected = false; this.relayerUrl = relayerUrl; this.config = { enabled: true, autoConnect: true, reconnection: true, timeout: 60000, ...config, }; } /** * Connect to WebSocket server */ connect() { var _a; if (!this.config.enabled || ((_a = this.socket) === null || _a === void 0 ? void 0 : _a.connected)) { return; } try { // Parse the URL to extract host and query parameters const url = new URL(this.relayerUrl); // Use only the origin (protocol + host) and preserve query parameters const wsUrl = `${url.protocol.replace('http', 'ws')}//${url.host}/${url.search}`; this.socket = io(`${wsUrl}`, { transports: ['websocket', 'polling'], autoConnect: this.config.autoConnect, reconnection: this.config.reconnection, timeout: this.config.timeout, }); this.setupEventHandlers(); if (this.config.autoConnect) { this.socket.connect(); } } catch (error) { console.error('Failed to initialize WebSocket connection:', error); } } /** * Disconnect from WebSocket server */ disconnect() { if (this.socket) { this.socket.disconnect(); this.socket = null; this.isConnected = false; this.subscribedTransactions.clear(); } } /** * Check if WebSocket is connected */ connected() { var _a; return this.isConnected && ((_a = this.socket) === null || _a === void 0 ? void 0 : _a.connected) === true; } /** * Subscribe to transaction updates */ async subscribeToTransaction(txId, events = {}) { if (!this.socket || !this.connected()) { throw new Error('WebSocket not connected. Call connect() first.'); } // Store event handlers for this transaction this.subscribedTransactions.set(txId, events); // Subscribe to transaction updates via WebSocket this.socket.emit('subscribe_transaction', { txId }); return new Promise((resolve, reject) => { var _a, _b; const timeout = setTimeout(() => { reject(new Error(`Subscription timeout for transaction ${txId}`)); }, 5000); (_a = this.socket) === null || _a === void 0 ? void 0 : _a.once('subscribed', (data) => { var _a; if (((_a = data.data) === null || _a === void 0 ? void 0 : _a.txId) === txId) { clearTimeout(timeout); resolve(); } }); (_b = this.socket) === null || _b === void 0 ? void 0 : _b.once('error', (error) => { clearTimeout(timeout); reject(error); }); }); } /** * Unsubscribe from transaction updates */ unsubscribeFromTransaction(txId) { if (this.socket && this.connected()) { this.socket.emit('unsubscribe_transaction', { txId }); } this.subscribedTransactions.delete(txId); } /** * Get current transaction status via WebSocket */ getTransactionStatus(txId) { if (this.socket && this.connected()) { this.socket.emit('get_transaction_status', { txId }); } } /** * Setup WebSocket event handlers */ setupEventHandlers() { if (!this.socket) return; // Connection events this.socket.on('connect', () => { this.isConnected = true; this.notifyGlobalEvent('onConnect'); }); this.socket.on('disconnect', () => { this.isConnected = false; this.notifyGlobalEvent('onDisconnect'); }); this.socket.on('error', (error) => { const errorObj = error instanceof Error ? error : new Error((error === null || error === void 0 ? void 0 : error.message) || 'WebSocket error'); this.notifyGlobalEvent('onError', errorObj); }); // Transaction events this.socket.on('transaction_created', (data) => { this.handleTransactionCreated(data); }); this.socket.on('transaction_update', (update) => { this.handleTransactionUpdate(update); }); // Subscription confirmation this.socket.on('subscribed', (data) => { console.log('Subscribed to transaction:', data === null || data === void 0 ? void 0 : data.txId); }); this.socket.on('unsubscribed', (data) => { console.log('Unsubscribed from transaction:', data === null || data === void 0 ? void 0 : data.txId); }); } /** * Handle transaction creation events */ handleTransactionCreated(event) { const events = this.subscribedTransactions.get(event.txId); if (events === null || events === void 0 ? void 0 : events.onTransactionCreated) { try { events.onTransactionCreated(event); } catch (error) { console.error('Error in transaction created handler:', error); } } } /** * Handle transaction status updates */ handleTransactionUpdate(update) { const events = this.subscribedTransactions.get(update.txId); if (events === null || events === void 0 ? void 0 : events.onTransactionUpdate) { try { events.onTransactionUpdate(update); } catch (error) { console.error('Error in transaction update handler:', error); } } // Auto-unsubscribe when transaction is final if (['confirmed', 'failed', 'rejected'].includes(update.status)) { setTimeout(() => { this.unsubscribeFromTransaction(update.txId); }, 1000); // Give a moment for final event handling } } /** * Notify global event handlers */ notifyGlobalEvent(eventType, data) { this.subscribedTransactions.forEach((events) => { const handler = events[eventType]; if (handler && typeof handler === 'function') { try { handler(data); } catch (error) { console.error(`Error in ${String(eventType)} handler:`, error); } } }); } /** * Get connection status information */ getConnectionInfo() { return { connected: this.connected(), subscribedTransactions: this.subscribedTransactions.size, url: this.relayerUrl, }; } } //# sourceMappingURL=WebSocketManager.js.map