const net = require('net') const fulcrumTimeoutMs = 3000 function queryFulcrum(fulcrumUrl, method, params = []) { return new Promise((resolve) => { if (!fulcrumUrl) { resolve({ ok: false, result: null, error: 'Fulcrum URL is not configured', }) return } let parsed try { parsed = new URL(fulcrumUrl) } catch { resolve({ ok: false, result: null, error: 'Invalid Fulcrum URL', }) return } if (parsed.protocol !== 'tcp:') { resolve({ ok: false, result: null, error: 'Fulcrum URL must use tcp://', }) return } const host = parsed.hostname const port = Number(parsed.port) if (!host || !port) { resolve({ ok: false, result: null, error: 'Fulcrum URL is missing host or port', }) return } const socket = net.createConnection({ host, port, }) let response = '' let settled = false const finish = (value) => { if (settled) { return } settled = true socket.destroy() resolve(value) } socket.setTimeout(fulcrumTimeoutMs) socket.on('connect', () => { const request = JSON.stringify({ jsonrpc: '2.0', id: 1, method, params, }) + '\n' socket.write(request) }) socket.on('data', (data) => { response += data.toString() const lines = response.split('\n') for (const line of lines) { if (!line.trim()) { continue } let message try { message = JSON.parse(line) } catch { continue } if (message.error) { finish({ ok: false, result: null, error: message.error, }) return } if ( Object.prototype.hasOwnProperty.call( message, 'result', ) ) { finish({ ok: true, result: message.result, error: null, }) return } } }) socket.on('timeout', () => { finish({ ok: false, result: null, error: 'Connection timed out', }) }) socket.on('error', (error) => { finish({ ok: false, result: null, error: error.message, }) }) socket.on('close', () => { if (!settled) { finish({ ok: false, result: null, error: 'Connection closed before a response was received', }) } }) }) } async function getTransaction(txid) { if (typeof txid !== 'string' || !txid.trim()) { throw new Error('Transaction ID is required') } const fulcrumUrl = process.env.MUNIN_FULCRUM_URL || null if (!fulcrumUrl) { throw new Error('Fulcrum URL is not configured') } const result = await queryFulcrum( fulcrumUrl, 'blockchain.transaction.get', [txid.trim(), true], ) if (!result.ok) { throw new Error( `Failed to query transaction: ${JSON.stringify(result.error)}`, ) } return result.result } module.exports = { getTransaction, }