@samouraiwallet/electrum-client
Advanced tools
Comparing version 1.4.0 to 1.5.0
# Changelog | ||
## 1.5.0 (2024-09-27) | ||
- Removed unnecessary boilerplate (TlsSocketWrapper) | ||
- Added static `createClient` method for more convenience | ||
- Updated dependencies | ||
- (DEV) - Updated to Node.js v18 | ||
- (DEV) - Swtiched to PNPM | ||
- (DEV) - Switched from eslint to biome | ||
## 1.4.0 (2023-05-24) | ||
@@ -4,0 +13,0 @@ - Updated keepAlive to use interval instead of timeout |
@@ -1,7 +0,7 @@ | ||
import { Client } from './lib/client.js'; | ||
import { Callbacks, ElectrumConfig, ElectrumRequestBatchParams, ElectrumRequestParams, PersistencePolicy, Protocol } from './types'; | ||
import { Client } from "./lib/client.js"; | ||
import type { Callbacks, CreateClientParams, ElectrumConfig, ElectrumRequestBatchParams, ElectrumRequestParams, PersistencePolicy, Protocol } from "./types"; | ||
export declare class ElectrumClient extends Client { | ||
private onConnectCallback; | ||
private onCloseCallback; | ||
private onLogCallback; | ||
private readonly onConnectCallback; | ||
private readonly onCloseCallback; | ||
private readonly onLogCallback; | ||
private timeLastCall; | ||
@@ -12,8 +12,42 @@ private persistencePolicy; | ||
versionInfo: [string, string]; | ||
/** | ||
* Constructs an instance of ElectrumClient. | ||
* | ||
* @param {number} port - The port number to connect to. | ||
* @param {string} host - The host address to connect to. | ||
* @param {Protocol} protocol - The protocol to use for the connection. | ||
* @param {Callbacks} [callbacks] - Optional callbacks for connection events. | ||
*/ | ||
constructor(port: number, host: string, protocol: Protocol, callbacks?: Callbacks); | ||
/** | ||
* Creates an instance of ElectrumClient and initializes it with the provided configuration. | ||
* | ||
* @param {CreateClientParams} params - The parameters required to create and initialize the client. | ||
* @param {number} params.port - The port number to connect to. | ||
* @param {string} params.host - The host address to connect to. | ||
* @param {Protocol} params.protocol - The protocol to use for the connection. | ||
* @param {Callbacks} [params.callbacks] - Optional callbacks for connection events. | ||
* @param {ElectrumConfig} params.electrumConfig - The Electrum configuration to use. | ||
* @param {PersistencePolicy} [params.persistencePolicy] - Optional persistence policy for the client. | ||
* | ||
* @returns {Promise<ElectrumClient>} A promise that resolves to an initialized ElectrumClient instance. | ||
*/ | ||
static createClient(params: CreateClientParams): Promise<ElectrumClient>; | ||
/** | ||
* Initializes the Electrum client with the provided configuration and persistence policy. | ||
* | ||
* @param {ElectrumConfig} electrumConfig - The Electrum configuration to use. | ||
* @param {PersistencePolicy} [persistencePolicy] - Optional persistence policy for the client. | ||
* @returns {Promise<ElectrumClient>} A promise that resolves to the initialized ElectrumClient instance. | ||
*/ | ||
initElectrum(electrumConfig: ElectrumConfig, persistencePolicy?: PersistencePolicy): Promise<ElectrumClient>; | ||
protected request(method: string, params: ElectrumRequestParams): Promise<unknown>; | ||
protected requestBatch(method: string, params: ElectrumRequestParams, secondParam?: ElectrumRequestBatchParams): Promise<unknown>; | ||
protected request<T>(method: string, params: ElectrumRequestParams<T>): Promise<unknown>; | ||
protected requestBatch<T>(method: string, params: ElectrumRequestParams<T>, secondParam?: ElectrumRequestBatchParams): Promise<unknown>; | ||
protected onClose(): void; | ||
private keepAlive; | ||
/** | ||
* Closes the Electrum client connection and stops the keep-alive ping interval. | ||
* | ||
* @returns {void} | ||
*/ | ||
close(): void; | ||
@@ -20,0 +54,0 @@ private reconnect; |
@@ -1,10 +0,20 @@ | ||
import { Client } from './lib/client.js'; | ||
import { Client } from "./lib/client.js"; | ||
export class ElectrumClient extends Client { | ||
/** | ||
* Constructs an instance of ElectrumClient. | ||
* | ||
* @param {number} port - The port number to connect to. | ||
* @param {string} host - The host address to connect to. | ||
* @param {Protocol} protocol - The protocol to use for the connection. | ||
* @param {Callbacks} [callbacks] - Optional callbacks for connection events. | ||
*/ | ||
constructor(port, host, protocol, callbacks) { | ||
super(port, host, protocol, callbacks); | ||
this.onConnectCallback = (callbacks && callbacks.onConnect) ? callbacks.onConnect : null; | ||
this.onCloseCallback = (callbacks && callbacks.onClose) ? callbacks.onClose : null; | ||
this.onLogCallback = (callbacks && callbacks.onLog) ? callbacks.onLog : (str) => { | ||
console.log(str); | ||
}; | ||
this.onConnectCallback = callbacks?.onConnect ?? null; | ||
this.onCloseCallback = callbacks?.onClose ?? null; | ||
this.onLogCallback = callbacks?.onLog | ||
? callbacks.onLog | ||
: (str) => { | ||
console.log(str); | ||
}; | ||
this.timeLastCall = 0; | ||
@@ -19,8 +29,32 @@ this.persistencePolicy = { | ||
this.pingInterval = null; | ||
this.versionInfo = ['', '']; | ||
this.versionInfo = ["", ""]; | ||
} | ||
/** | ||
* Creates an instance of ElectrumClient and initializes it with the provided configuration. | ||
* | ||
* @param {CreateClientParams} params - The parameters required to create and initialize the client. | ||
* @param {number} params.port - The port number to connect to. | ||
* @param {string} params.host - The host address to connect to. | ||
* @param {Protocol} params.protocol - The protocol to use for the connection. | ||
* @param {Callbacks} [params.callbacks] - Optional callbacks for connection events. | ||
* @param {ElectrumConfig} params.electrumConfig - The Electrum configuration to use. | ||
* @param {PersistencePolicy} [params.persistencePolicy] - Optional persistence policy for the client. | ||
* | ||
* @returns {Promise<ElectrumClient>} A promise that resolves to an initialized ElectrumClient instance. | ||
*/ | ||
static async createClient(params) { | ||
const client = new ElectrumClient(params.port, params.host, params.protocol, params.callbacks); | ||
return await client.initElectrum(params.electrumConfig, params.persistencePolicy); | ||
} | ||
/** | ||
* Initializes the Electrum client with the provided configuration and persistence policy. | ||
* | ||
* @param {ElectrumConfig} electrumConfig - The Electrum configuration to use. | ||
* @param {PersistencePolicy} [persistencePolicy] - Optional persistence policy for the client. | ||
* @returns {Promise<ElectrumClient>} A promise that resolves to the initialized ElectrumClient instance. | ||
*/ | ||
async initElectrum(electrumConfig, persistencePolicy) { | ||
this.persistencePolicy = { | ||
...this.persistencePolicy, | ||
...persistencePolicy | ||
...persistencePolicy, | ||
}; | ||
@@ -51,6 +85,6 @@ this.electrumConfig = electrumConfig; | ||
const list = [ | ||
'server.peers.subscribe', | ||
'blockchain.numblocks.subscribe', | ||
'blockchain.headers.subscribe', | ||
'blockchain.address.subscribe', | ||
"server.peers.subscribe", | ||
"blockchain.numblocks.subscribe", | ||
"blockchain.headers.subscribe", | ||
"blockchain.address.subscribe", | ||
]; | ||
@@ -87,3 +121,4 @@ for (const event of list) | ||
this.pingInterval = setInterval(() => { | ||
if (this.timeLastCall !== 0 && Date.now() > this.timeLastCall + pingPeriod) { | ||
if (this.timeLastCall !== 0 && | ||
Date.now() > this.timeLastCall + pingPeriod) { | ||
this.server_ping().catch((error) => { | ||
@@ -95,2 +130,7 @@ this.log(`Keep-Alive ping failed: ${error}`); | ||
} | ||
/** | ||
* Closes the Electrum client connection and stops the keep-alive ping interval. | ||
* | ||
* @returns {void} | ||
*/ | ||
close() { | ||
@@ -101,8 +141,16 @@ super.close(); | ||
} | ||
this.reconnect = this.reconnect = this.onClose = this.keepAlive = () => Promise.resolve(this); | ||
this.reconnect = | ||
this.reconnect = | ||
this.onClose = | ||
this.keepAlive = | ||
() => Promise.resolve(this); // dirty hack to make it stop reconnecting | ||
} | ||
reconnect() { | ||
this.log('Electrum attempting reconnect...'); | ||
this.log("Electrum attempting reconnect..."); | ||
this.initSocket(); | ||
return this.persistencePolicy == null ? this.initElectrum(this.electrumConfig) : this.initElectrum(this.electrumConfig, this.persistencePolicy); | ||
return this.persistencePolicy == null | ||
? // biome-ignore lint/style/noNonNullAssertion: | ||
this.initElectrum(this.electrumConfig) | ||
: // biome-ignore lint/style/noNonNullAssertion: | ||
this.initElectrum(this.electrumConfig, this.persistencePolicy); | ||
} | ||
@@ -112,105 +160,112 @@ log(str) { | ||
} | ||
// ElectrumX API | ||
server_version(client_name, protocol_version) { | ||
return this.request('server.version', [client_name, protocol_version]); | ||
return this.request("server.version", [client_name, protocol_version]); | ||
} | ||
server_banner() { | ||
return this.request('server.banner', []); | ||
return this.request("server.banner", []); | ||
} | ||
server_features() { | ||
return this.request('server.features', []); | ||
return this.request("server.features", []); | ||
} | ||
server_ping() { | ||
return this.request('server.ping', []); | ||
return this.request("server.ping", []); | ||
} | ||
server_addPeer(features) { | ||
return this.request('server.add_peer', [features]); | ||
return this.request("server.add_peer", [features]); | ||
} | ||
serverDonation_address() { | ||
return this.request('server.donation_address', []); | ||
return this.request("server.donation_address", []); | ||
} | ||
serverPeers_subscribe() { | ||
return this.request('server.peers.subscribe', []); | ||
return this.request("server.peers.subscribe", []); | ||
} | ||
blockchainAddress_getProof(address) { | ||
return this.request('blockchain.address.get_proof', [address]); | ||
return this.request("blockchain.address.get_proof", [address]); | ||
} | ||
blockchainScripthash_getBalance(scripthash) { | ||
return this.request('blockchain.scripthash.get_balance', [scripthash]); | ||
return this.request("blockchain.scripthash.get_balance", [scripthash]); | ||
} | ||
blockchainScripthash_getBalanceBatch(scripthashes) { | ||
return this.requestBatch('blockchain.scripthash.get_balance', scripthashes); | ||
return this.requestBatch("blockchain.scripthash.get_balance", scripthashes); | ||
} | ||
blockchainScripthash_listunspentBatch(scripthashes) { | ||
return this.requestBatch('blockchain.scripthash.listunspent', scripthashes); | ||
return this.requestBatch("blockchain.scripthash.listunspent", scripthashes); | ||
} | ||
blockchainScripthash_getHistory(scripthash) { | ||
return this.request('blockchain.scripthash.get_history', [scripthash]); | ||
return this.request("blockchain.scripthash.get_history", [scripthash]); | ||
} | ||
blockchainScripthash_getHistoryBatch(scripthashes) { | ||
return this.requestBatch('blockchain.scripthash.get_history', scripthashes); | ||
return this.requestBatch("blockchain.scripthash.get_history", scripthashes); | ||
} | ||
blockchainScripthash_getMempool(scripthash) { | ||
return this.request('blockchain.scripthash.get_mempool', [scripthash]); | ||
return this.request("blockchain.scripthash.get_mempool", [scripthash]); | ||
} | ||
blockchainScripthash_listunspent(scripthash) { | ||
return this.request('blockchain.scripthash.listunspent', [scripthash]); | ||
return this.request("blockchain.scripthash.listunspent", [scripthash]); | ||
} | ||
blockchainScripthash_subscribe(scripthash) { | ||
return this.request('blockchain.scripthash.subscribe', [scripthash]); | ||
return this.request("blockchain.scripthash.subscribe", [scripthash]); | ||
} | ||
blockchainBlock_getHeader(height) { | ||
return this.request('blockchain.block.get_header', [height]); | ||
return this.request("blockchain.block.get_header", [height]); | ||
} | ||
blockchainBlock_headers(start_height, count) { | ||
return this.request('blockchain.block.headers', [start_height, count]); | ||
return this.request("blockchain.block.headers", [start_height, count]); | ||
} | ||
blockchainEstimatefee(number) { | ||
return this.request('blockchain.estimatefee', [number]); | ||
return this.request("blockchain.estimatefee", [number]); | ||
} | ||
blockchainHeaders_subscribe() { | ||
return this.request('blockchain.headers.subscribe', []); | ||
return this.request("blockchain.headers.subscribe", []); | ||
} | ||
blockchain_relayfee() { | ||
return this.request('blockchain.relayfee', []); | ||
return this.request("blockchain.relayfee", []); | ||
} | ||
blockchainTransaction_broadcast(rawtx) { | ||
return this.request('blockchain.transaction.broadcast', [rawtx]); | ||
return this.request("blockchain.transaction.broadcast", [rawtx]); | ||
} | ||
blockchainTransaction_get(tx_hash, verbose = false) { | ||
return this.request('blockchain.transaction.get', [tx_hash, verbose]); | ||
return this.request("blockchain.transaction.get", [tx_hash, verbose]); | ||
} | ||
blockchainTransaction_getBatch(tx_hashes, verbose = false) { | ||
return this.requestBatch('blockchain.transaction.get', tx_hashes, verbose); | ||
return this.requestBatch("blockchain.transaction.get", tx_hashes, verbose); | ||
} | ||
blockchainTransaction_getMerkle(tx_hash, height) { | ||
return this.request('blockchain.transaction.get_merkle', [tx_hash, height]); | ||
return this.request("blockchain.transaction.get_merkle", [tx_hash, height]); | ||
} | ||
mempool_getFeeHistogram() { | ||
return this.request('mempool.get_fee_histogram', []); | ||
return this.request("mempool.get_fee_histogram", []); | ||
} | ||
// --------------------------------- | ||
// protocol 1.1 deprecated method | ||
// --------------------------------- | ||
blockchainUtxo_getAddress(tx_hash, index) { | ||
return this.request('blockchain.utxo.get_address', [tx_hash, index]); | ||
return this.request("blockchain.utxo.get_address", [tx_hash, index]); | ||
} | ||
blockchainNumblocks_subscribe() { | ||
return this.request('blockchain.numblocks.subscribe', []); | ||
return this.request("blockchain.numblocks.subscribe", []); | ||
} | ||
// --------------------------------- | ||
// protocol 1.2 deprecated method | ||
// --------------------------------- | ||
blockchainBlock_getChunk(index) { | ||
return this.request('blockchain.block.get_chunk', [index]); | ||
return this.request("blockchain.block.get_chunk", [index]); | ||
} | ||
blockchainAddress_getBalance(address) { | ||
return this.request('blockchain.address.get_balance', [address]); | ||
return this.request("blockchain.address.get_balance", [address]); | ||
} | ||
blockchainAddress_getHistory(address) { | ||
return this.request('blockchain.address.get_history', [address]); | ||
return this.request("blockchain.address.get_history", [address]); | ||
} | ||
blockchainAddress_getMempool(address) { | ||
return this.request('blockchain.address.get_mempool', [address]); | ||
return this.request("blockchain.address.get_mempool", [address]); | ||
} | ||
blockchainAddress_listunspent(address) { | ||
return this.request('blockchain.address.listunspent', [address]); | ||
return this.request("blockchain.address.listunspent", [address]); | ||
} | ||
blockchainAddress_subscribe(address) { | ||
return this.request('blockchain.address.subscribe', [address]); | ||
return this.request("blockchain.address.subscribe", [address]); | ||
} | ||
} | ||
//# sourceMappingURL=index.js.map |
@@ -1,22 +0,19 @@ | ||
/// <reference types="node" /> | ||
import { EventEmitter } from 'node:events'; | ||
import { Protocol, Callbacks, ElectrumRequestBatchParams, ElectrumRequestParams } from '../types'; | ||
import { EventEmitter } from "node:events"; | ||
import type { Callbacks, ElectrumRequestBatchParams, ElectrumRequestParams, Protocol } from "../types"; | ||
export declare abstract class Client { | ||
private id; | ||
private port; | ||
private host; | ||
private callback_message_queue; | ||
protected subscribe: EventEmitter; | ||
private mp; | ||
private readonly protocol; | ||
private conn; | ||
private status; | ||
private protocol; | ||
private onErrorCallback; | ||
constructor(port: number, host: string, protocol: Protocol, callbacks?: Callbacks); | ||
protected initSocket(protocol?: Protocol): void; | ||
private readonly host; | ||
private readonly port; | ||
private readonly onErrorCallback; | ||
protected constructor(port: number, host: string, protocol: Protocol, callbacks?: Callbacks); | ||
protected initSocket(): void; | ||
protected connect(): Promise<void>; | ||
private connectSocket; | ||
close(): void; | ||
protected request(method: string, params: ElectrumRequestParams): Promise<unknown>; | ||
protected requestBatch(method: string, params: ElectrumRequestParams, secondParam: ElectrumRequestBatchParams): Promise<unknown>; | ||
protected request<T>(method: string, params: ElectrumRequestParams<T>): Promise<unknown>; | ||
protected requestBatch<T>(method: string, params: ElectrumRequestParams<T>, secondParam: ElectrumRequestBatchParams): Promise<unknown>; | ||
private response; | ||
@@ -23,0 +20,0 @@ private onMessage; |
@@ -1,11 +0,12 @@ | ||
import net from 'node:net'; | ||
import { EventEmitter } from 'node:events'; | ||
import { TlsSocketWrapper } from './tls-socket-wrapper.js'; | ||
import * as util from './util.js'; | ||
const TIMEOUT = 5000; | ||
import { EventEmitter } from "node:events"; | ||
import net from "node:net"; | ||
import tls from "node:tls"; | ||
import * as util from "./util.js"; | ||
const TIMEOUT = 60000; | ||
export class Client { | ||
constructor(port, host, protocol, callbacks) { | ||
this.id = 0; | ||
this.host = host; | ||
this.port = port; | ||
this.host = host; | ||
this.protocol = protocol; | ||
this.callback_message_queue = new Map(); | ||
@@ -16,58 +17,40 @@ this.subscribe = new EventEmitter(); | ||
}); | ||
this.conn = null; | ||
this.status = 0; | ||
this.protocol = protocol; | ||
this.onErrorCallback = (callbacks && callbacks.onError) ? callbacks.onError : null; | ||
this.initSocket(protocol); | ||
if (protocol !== "tcp" && protocol !== "tls" && protocol !== "ssl") { | ||
throw new Error("unknown protocol"); | ||
} | ||
this.onErrorCallback = callbacks?.onError ?? null; | ||
this.initSocket(); | ||
} | ||
initSocket(protocol = this.protocol) { | ||
switch (protocol) { | ||
case 'tcp': | ||
this.conn = new net.Socket(); | ||
break; | ||
case 'tls': | ||
case 'ssl': | ||
this.conn = new TlsSocketWrapper(); | ||
break; | ||
default: | ||
throw new Error('unknown protocol'); | ||
} | ||
initSocket() { | ||
this.conn = | ||
this.protocol === "tls" || this.protocol === "ssl" | ||
? tls.connect({ host: this.host, port: this.port, rejectUnauthorized: false }, () => { | ||
this.conn?.setTimeout(0); | ||
this.onConnect(); | ||
}) | ||
: net.connect({ host: this.host, port: this.port }, () => { | ||
this.conn?.setTimeout(0); | ||
this.onConnect(); | ||
}); | ||
this.conn.setTimeout(TIMEOUT); | ||
this.conn.setEncoding('utf8'); | ||
this.conn.setEncoding("utf8"); | ||
this.conn.setKeepAlive(true, 0); | ||
this.conn.setNoDelay(true); | ||
this.conn.on('connect', () => { | ||
this.conn && this.conn.setTimeout(0); | ||
this.onConnect(); | ||
}); | ||
this.conn.on('close', () => { | ||
this.conn.on("close", () => { | ||
this.onClose(); | ||
}); | ||
this.conn.on('data', (chunk) => { | ||
this.conn && this.conn.setTimeout(0); | ||
this.conn.on("data", (chunk) => { | ||
this.conn?.setTimeout(0); | ||
this.onRecv(chunk); | ||
}); | ||
this.conn.on('error', (e) => { | ||
this.conn.on("error", (e) => { | ||
this.onError(e); | ||
}); | ||
this.status = 0; | ||
} | ||
connect() { | ||
if (this.conn) { | ||
if (this.status === 1) { | ||
return Promise.resolve(); | ||
return new Promise((resolve) => { | ||
if (this.conn && this.conn.readyState === "open") { | ||
return resolve(); | ||
} | ||
this.status = 1; | ||
return this.connectSocket(this.conn, this.port, this.host); | ||
} | ||
else { | ||
return Promise.reject(new Error('There is no socket to initialize connection on.')); | ||
} | ||
} | ||
connectSocket(conn, port, host) { | ||
return new Promise((resolve, reject) => { | ||
const errorHandler = (e) => reject(e); | ||
conn.on('error', errorHandler); | ||
conn.connect(port, host, () => { | ||
conn.removeListener('error', errorHandler); | ||
this.conn?.once(this.protocol === "tcp" ? "connect" : "secureConnect", () => { | ||
resolve(); | ||
@@ -78,12 +61,11 @@ }); | ||
close() { | ||
if (this.status === 0) { | ||
if (this.conn && this.conn.readyState === "closed") { | ||
return; | ||
} | ||
this.conn && this.conn.end(); | ||
this.conn && this.conn.destroy(); | ||
this.status = 0; | ||
this.conn?.end(); | ||
this.conn?.destroy(); | ||
} | ||
request(method, params) { | ||
if (this.status === 0) { | ||
return Promise.reject(new Error('Connection to server lost, please retry')); | ||
if (this.conn && this.conn.readyState === "closed") { | ||
return Promise.reject(new Error("Connection to server lost, please retry")); | ||
} | ||
@@ -94,8 +76,8 @@ return new Promise((resolve, reject) => { | ||
this.callback_message_queue.set(id, util.createPromiseResult(resolve, reject)); | ||
this.conn && this.conn.write(`${content}\n`); | ||
this.conn?.write(`${content}\n`); | ||
}); | ||
} | ||
requestBatch(method, params, secondParam) { | ||
if (this.status === 0) { | ||
return Promise.reject(new Error('Connection to server lost, please retry')); | ||
if (this.conn && this.conn.readyState === "closed") { | ||
return Promise.reject(new Error("Connection to server lost, please retry")); | ||
} | ||
@@ -115,5 +97,6 @@ return new Promise((resolve, reject) => { | ||
} | ||
const content = `[${contents.join(',')}]`; | ||
const content = `[${contents.join(",")}]`; | ||
this.callback_message_queue.set(this.id, util.createPromiseResultBatch(resolve, reject, arguments_far_calls)); | ||
this.conn && this.conn.write(`${content}\n`); | ||
// callback will exist only for max id | ||
this.conn?.write(`${content}\n`); | ||
}); | ||
@@ -124,2 +107,3 @@ } | ||
if (!msg.id && msg[0] && msg[0].id) { | ||
// this is a response from batch request | ||
for (const m of msg) { | ||
@@ -146,7 +130,7 @@ if (m.id && this.callback_message_queue.has(m.id)) { | ||
console.log(msg); | ||
throw new Error('Error getting callback while handling response'); | ||
throw new Error("Error getting callback while handling response"); | ||
} | ||
} | ||
onMessage(body, n) { | ||
const msg = JSON.parse(body || ''); | ||
const msg = JSON.parse(body || ""); | ||
if (Array.isArray(msg)) { | ||
@@ -164,5 +148,4 @@ this.response(msg); | ||
onClose() { | ||
this.status = 0; | ||
for (const [key, fn] of this.callback_message_queue.entries()) { | ||
fn(new Error('close connect')); | ||
fn(new Error("close connect")); | ||
this.callback_message_queue.delete(key); | ||
@@ -169,0 +152,0 @@ } |
@@ -1,4 +0,3 @@ | ||
/// <reference types="node" /> | ||
import { ElectrumRequestParams } from '../types'; | ||
export declare const makeRequest: (method: string, params: ElectrumRequestParams, id: number) => string; | ||
import type { ElectrumRequestParams } from "../types"; | ||
export declare const makeRequest: <T>(method: string, params: ElectrumRequestParams<T>, id: number) => string; | ||
export declare const createRecursiveParser: (max_depth: number, delimiter: string) => (n: number, buffer: string, callback: (xs: string | undefined, n: number) => void) => { | ||
@@ -13,4 +12,4 @@ code: number; | ||
private buffer; | ||
private callback; | ||
private recursiveParser; | ||
private readonly callback; | ||
private readonly recursiveParser; | ||
constructor(callback: MessageParserCallback); | ||
@@ -17,0 +16,0 @@ run(chunk: Buffer): void; |
export const makeRequest = (method, params, id) => { | ||
return JSON.stringify({ | ||
jsonrpc: '2.0', | ||
jsonrpc: "2.0", | ||
method: method, | ||
@@ -38,3 +38,4 @@ params: params, | ||
return (err, result) => { | ||
if (result && result[0] && result[0].id) { | ||
if (result?.[0]?.id) { | ||
// this is a batch request response | ||
for (const r of result) { | ||
@@ -52,6 +53,5 @@ r.param = argz[r.id]; | ||
constructor(callback) { | ||
this.recursiveParser = createRecursiveParser(20, '\n'); | ||
this.buffer = ''; | ||
this.buffer = ""; | ||
this.callback = callback; | ||
this.recursiveParser = createRecursiveParser(20, '\n'); | ||
this.recursiveParser = createRecursiveParser(20, "\n"); | ||
} | ||
@@ -58,0 +58,0 @@ run(chunk) { |
@@ -1,3 +0,3 @@ | ||
import { ElectrumClient } from '../index.js'; | ||
export type Protocol = 'tcp' | 'tls' | 'ssl'; | ||
import type { ElectrumClient } from "../index.js"; | ||
export type Protocol = "tcp" | "tls" | "ssl"; | ||
export type Callbacks = { | ||
@@ -19,4 +19,12 @@ onConnect?: (client: ElectrumClient, versionInfo: [string, string]) => void; | ||
}; | ||
export type ElectrumRequestParams = Array<number | string | boolean | Array<any>>; | ||
export type CreateClientParams = { | ||
host: string; | ||
port: number; | ||
protocol: Protocol; | ||
electrumConfig: ElectrumConfig; | ||
callbacks?: Callbacks; | ||
persistencePolicy?: PersistencePolicy; | ||
}; | ||
export type ElectrumRequestParams<T> = Array<number | string | boolean | Array<T>>; | ||
export type ElectrumRequestBatchParams = number | string | boolean | undefined; | ||
//# sourceMappingURL=index.d.ts.map |
{ | ||
"name": "@samouraiwallet/electrum-client", | ||
"version": "1.4.0", | ||
"engines": { | ||
"node": ">=14.0.0" | ||
}, | ||
"description": "Electrum protocol client for Node.js", | ||
"keywords": [ | ||
"bitcoin", | ||
"electrum", | ||
"electrumx" | ||
], | ||
"type": "module", | ||
"exports": "./dist/index.js", | ||
"types": "./dist/index.d.ts", | ||
"scripts": { | ||
"test": "vitest run", | ||
"test:watch": "vitest watch", | ||
"lint": "eslint --ext .ts src/", | ||
"typescript": "tsc --noEmit", | ||
"build:clean": "rm -rf dist", | ||
"build:esm": "tsc -p tsconfig.build.json", | ||
"build": "npm run build:clean && npm run build:esm", | ||
"prepack": "npm run lint && npm run typescript && npm run test", | ||
"prepare": "npm run build" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git://code.samourai.io/dojo/electrum-client.git" | ||
}, | ||
"bugs": { | ||
"url": "https://code.samourai.io/dojo/electrum-client/-/issues" | ||
}, | ||
"author": "Katana Cryptographic Ltd.", | ||
"license": "LGPL-3.0", | ||
"homepage": "https://code.samourai.io/dojo/electrum-client", | ||
"devDependencies": { | ||
"@types/node": "^16.18.32", | ||
"@typescript-eslint/eslint-plugin": "^5.59.7", | ||
"@typescript-eslint/parser": "^5.59.7", | ||
"@vitest/coverage-c8": "^0.31.1", | ||
"eslint": "^8.41.0", | ||
"eslint-plugin-import": "^2.27.5", | ||
"eslint-plugin-unicorn": "^47.0.0", | ||
"typescript": "^5.0.4", | ||
"vitest": "^0.31.1" | ||
} | ||
} | ||
"name": "@samouraiwallet/electrum-client", | ||
"version": "1.5.0", | ||
"engines": { | ||
"node": ">=18.6.0" | ||
}, | ||
"description": "Electrum protocol client for Node.js", | ||
"keywords": [ | ||
"bitcoin", | ||
"electrum", | ||
"electrumx" | ||
], | ||
"type": "module", | ||
"exports": { | ||
".": { | ||
"import": "./dist/index.js", | ||
"types": "./dist/index.d.ts" | ||
} | ||
}, | ||
"types": "./dist/index.d.ts", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/Dojo-Open-Source-Project/electrum-client.git" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/Dojo-Open-Source-Project/electrum-client/issues" | ||
}, | ||
"author": "Katana Cryptographic Ltd.", | ||
"license": "LGPL-3.0", | ||
"homepage": "https://github.com/Dojo-Open-Source-Project/electrum-client", | ||
"devDependencies": { | ||
"@biomejs/biome": "1.9.2", | ||
"@types/node": "^18.19.53", | ||
"@vitest/coverage-v8": "^2.1.1", | ||
"typescript": "^5.0.4", | ||
"vitest": "^2.1.1" | ||
}, | ||
"scripts": { | ||
"test": "vitest run", | ||
"test:watch": "vitest watch", | ||
"lint": "biome lint src/ test/", | ||
"lint:fix": "biome lint --write src/ test/", | ||
"pretty": "biome format --write src/ test/", | ||
"typescript": "tsc --noEmit", | ||
"build:clean": "rm -rf dist", | ||
"build:esm": "tsc -p tsconfig.build.json", | ||
"build": "npm run build:clean && npm run build:esm" | ||
} | ||
} |
# @samouraiwallet/electrum-client | ||
Electrum Protocol client for Node.js. | ||
Efficient and no-dependency Electrum Protocol client for Node.js. | ||
This library uses ESModules, Node.js v14 or higher is required. | ||
This library uses ESModules, Node.js v18 or higher is required. | ||
@@ -16,2 +16,3 @@ # Based on | ||
* No dependencies | ||
* Persistence (ping strategy and reconnection) | ||
@@ -32,12 +33,12 @@ * Batch requests | ||
const run = async () => { | ||
const tcpClient = new ElectrumClient(60001, 'btc.electroncash.dk', 'tcp'); | ||
const tcpClient = await ElectrumClient.createClient({ | ||
port: 60001, | ||
host: "btc.electroncash.dk", | ||
protocol: "tcp", | ||
electrumConfig: { client: "electrum-client-js", version: ["1.2", "1.4"] }, | ||
persistencePolicy: { retryPeriod: 2000 }, | ||
}); | ||
await tcpClient.initElectrum({client: 'electrum-client-js', version: ['1.2', '1.4']}, { | ||
retryPeriod: 5000, | ||
maxRetry: 10, | ||
pingPeriod: 5000, | ||
}); | ||
const rawTx = await tcpClient.blockchainTransaction_get('b270b8a113c048ed0024e470e3c7794565c2b3e18c600d20410ec8f454b7d25a'); | ||
return rawTx; | ||
@@ -44,0 +45,0 @@ // result: 02000000016016c6d039cbdeefa655e4b5ac61ec2b5fe16920529f086a2439f59a5994bed6200000006a4730440220421b5daf5f72e514075d256121d6b66e1d9a8993d37ceb0532baca11f6964da502205333d1c4b9be749180bfa8da4da6a07c0e9e2d853c809a75c4b60ef717a628b20121029139c783aa8f31707a67248a6a6b643855e9d1484dbd53cfe7d9e3adf3ce7098ffffffff02c19a01000000000017a9146eda8b447af853746f04b902fea5b2cd959d866d87692c0200000000001976a914443674ce759f8fa2fe83a6608339da782b890c1988ac00000000 |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
5
0
0
47
37782
13
678