{"mappings":"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","sources":["lib/index.ts","lib/electrum-client.ts","lib/util.ts","lib/electrum-connection.ts","lib/electrum-protocol.ts","lib/interfaces.ts","lib/constants.ts","lib/enums.ts","lib/electrum-socket.ts","lib/rpc-interfaces.ts","lib/electrum-cluster.ts"],"sourcesContent":["export { default as ElectrumClient } from './electrum-client';\nexport { default as ElectrumCluster } from './electrum-cluster';\n\nexport * from './interfaces';\nexport * from './constants';\nexport * from './enums';\n","import debug from './util';\nimport ElectrumConnection from './electrum-connection';\nimport ElectrumProtocol from './electrum-protocol';\nimport { DefaultParameters } from './constants';\nimport { EventEmitter } from 'events';\nimport { ConnectionStatus } from './enums';\nimport { RPCParameter, isRPCNotification, isRPCErrorResponse, RPCNotification, RPCResponse } from './rpc-interfaces';\nimport type { ResolveFunction, RequestResolver, RequestResponse, TransportScheme } from './interfaces';\nimport { Mutex } from 'async-mutex';\n\n/**\n * Triggers when the underlying connection is established.\n *\n * @event ElectrumClient#connected\n */\n\n/**\n * Triggers when the underlying connection is lost.\n *\n * @event ElectrumClient#disconnected\n */\n\n/**\n * Triggers when the remote server sends data that is not a request response.\n *\n * @event ElectrumClient#notification\n */\n\n/**\n * High-level Electrum client that lets applications send requests and subscribe to notification events from a server.\n */\nclass ElectrumClient extends EventEmitter\n{\n\t// Declare instance variables\n\tconnection: ElectrumConnection;\n\n\t// Initialize an empty list of subscription metadata.\n\tsubscriptionMethods: Record<string, Set<string>> = {};\n\n\t// Start counting the request IDs from 0\n\trequestId = 0;\n\n\t// Initialize an empty dictionary for keeping track of request resolvers\n\trequestResolvers: { [index: number]: RequestResolver } = {};\n\n\t// Mutex lock used to prevent simultaneous connect() and disconnect() calls.\n\tconnectionLock = new Mutex();\n\n\t/**\n\t * Initializes an Electrum client.\n\t *\n\t * @param {string} application       your application name, used to identify to the electrum host.\n\t * @param {string} version           protocol version to use with the host.\n\t * @param {string} host              fully qualified domain name or IP number of the host.\n\t * @param {number} port              the TCP network port of the host.\n\t * @param {TransportScheme} scheme   the transport scheme to use for connection\n\t * @param {number} timeout           how long network delays we will wait for before taking action, in milliseconds.\n\t * @param {number} pingInterval      the time between sending pings to the electrum host, in milliseconds.\n\t * @param {number} reconnectInterval the time between reconnection attempts to the electrum host, in milliseconds.\n\t *\n\t * @throws {Error} if `version` is not a valid version string.\n\t */\n\tconstructor(\n\t\tapplication: string,\n\t\tversion: string,\n\t\thost: string,\n\t\tport: number = DefaultParameters.PORT,\n\t\tscheme: TransportScheme = DefaultParameters.TRANSPORT_SCHEME,\n\t\ttimeout: number = DefaultParameters.TIMEOUT,\n\t\tpingInterval: number = DefaultParameters.PING_INTERVAL,\n\t\treconnectInterval: number = DefaultParameters.RECONNECT,\n\t)\n\t{\n\t\t// Initialize the event emitter.\n\t\tsuper();\n\n\t\t// Set up a connection to an electrum server.\n\t\tthis.connection = new ElectrumConnection(application, version, host, port, scheme, timeout, pingInterval, reconnectInterval);\n\t}\n\n\t/**\n\t * Connects to the remote server.\n\t *\n\t * @throws {Error} if the socket connection fails.\n\t * @returns a promise resolving when the connection is established.\n\t */\n\tasync connect(): Promise<void>\n\t{\n\t\t// Create a lock so that multiple connects/disconnects cannot race each other.\n\t\tconst unlock = await this.connectionLock.acquire();\n\n\t\ttry\n\t\t{\n\t\t\t// If we are already connected, do not attempt to connect again.\n\t\t\tif(this.connection.status === ConnectionStatus.CONNECTED)\n\t\t\t{\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Listen for parsed statements.\n\t\t\tthis.connection.on('statement', this.response.bind(this));\n\n\t\t\t// Hook up resubscription on connection.\n\t\t\tthis.connection.on('connect', this.resubscribeOnConnect.bind(this));\n\n\t\t\t// Relay connect and disconnect events.\n\t\t\tthis.connection.on('connect', this.emit.bind(this, 'connected'));\n\t\t\tthis.connection.on('disconnect', this.onConnectionDisconnect.bind(this));\n\n\t\t\t// Relay error events.\n\t\t\tthis.connection.on('error', this.emit.bind(this, 'error'));\n\n\t\t\t// Connect with the server.\n\t\t\tawait this.connection.connect();\n\t\t}\n\t\t// Always release our lock so that we do not end up in a stuck-state.\n\t\tfinally\n\t\t{\n\t\t\tunlock();\n\t\t}\n\t}\n\n\t/**\n\t * Disconnects from the remote server and removes all event listeners/subscriptions and open requests.\n\t *\n\t * @param {boolean} force                 disconnect even if the connection has not been fully established yet.\n\t * @param {boolean} retainSubscriptions   retain subscription data so they will be restored on reconnection.\n\t *\n\t * @returns true if successfully disconnected, or false if there was no connection.\n\t */\n\tasync disconnect(force: boolean = false, retainSubscriptions: boolean = false): Promise<boolean>\n\t{\n\t\t// Create a lock so that multiple connects/disconnects cannot race each other.\n\t\tconst unlock = await this.connectionLock.acquire();\n\n\t\ttry\n\t\t{\n\t\t\tif(!retainSubscriptions)\n\t\t\t{\n\t\t\t\t// Cancel all event listeners.\n\t\t\t\tthis.removeAllListeners();\n\n\t\t\t\t// Remove all subscription data\n\t\t\t\tthis.subscriptionMethods = {};\n\t\t\t}\n\n\t\t\t// For each pending request..\n\t\t\tfor(const index in this.requestResolvers)\n\t\t\t{\n\t\t\t\t// Reject the request.\n\t\t\t\tconst requestResolver = this.requestResolvers[index];\n\t\t\t\trequestResolver(new Error('Manual disconnection'));\n\n\t\t\t\t// Remove the request.\n\t\t\t\tdelete this.requestResolvers[index];\n\t\t\t}\n\n\t\t\t// Disconnect from the remove server.\n\t\t\treturn await this.connection.disconnect(force);\n\t\t}\n\t\t// Always release our lock so that we do not end up in a stuck-state.\n\t\tfinally\n\t\t{\n\t\t\tunlock();\n\t\t}\n\t}\n\n\t/**\n\t * Calls a method on the remote server with the supplied parameters.\n\t *\n\t * @param {string} method          name of the method to call.\n\t * @param {...string} parameters   one or more parameters for the method.\n\t *\n\t * @throws {Error} if the client is disconnected.\n\t * @returns a promise that resolves with the result of the method or an Error.\n\t */\n\tasync request(method: string, ...parameters: RPCParameter[]): Promise<Error | RequestResponse>\n\t{\n\t\t// If we are not connected to a server..\n\t\tif(this.connection.status !== ConnectionStatus.CONNECTED)\n\t\t{\n\t\t\t// Reject the request with a disconnected error message.\n\t\t\tthrow(new Error(`Unable to send request to a disconnected server '${this.connection.host}'.`));\n\t\t}\n\n\t\t// Increase the request ID by one.\n\t\tthis.requestId += 1;\n\n\t\t// Store a copy of the request id.\n\t\tconst id = this.requestId;\n\n\t\t// Format the arguments as an electrum request object.\n\t\tconst message = ElectrumProtocol.buildRequestObject(method, parameters, id);\n\n\t\t// Define a function to wrap the request in a promise.\n\t\tconst requestResolver = (resolve: ResolveFunction<Error | RequestResponse>): void =>\n\t\t{\n\t\t\t// Add a request resolver for this promise to the list of requests.\n\t\t\tthis.requestResolvers[id] = (error?: Error, data?: RequestResponse) =>\n\t\t\t{\n\t\t\t\t// If the resolution failed..\n\t\t\t\tif(error)\n\t\t\t\t{\n\t\t\t\t\t// Resolve the promise with the error for the application to handle.\n\t\t\t\t\tresolve(error);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// Resolve the promise with the request results.\n\t\t\t\t\tresolve(data as RequestResponse);\n\t\t\t\t}\n\t\t\t};\n\n\t\t\t// Send the request message to the remote server.\n\t\t\tthis.connection.send(message);\n\t\t};\n\n\t\t// Write a log message.\n\t\tdebug.network(`Sending request '${method}' to '${this.connection.host}'`);\n\n\t\t// return a promise to deliver results later.\n\t\treturn new Promise<Error | RequestResponse>(requestResolver);\n\t}\n\n\t/**\n\t * Subscribes to the method and payload at the server.\n\t *\n\t * @note the response for the subscription request is issued as a notification event.\n\t *\n\t * @param {string}    method       one of the subscribable methods the server supports.\n\t * @param {...string} parameters   one or more parameters for the method.\n\t *\n\t * @throws {Error} if the client is disconnected.\n\t * @returns a promise resolving when the subscription is established.\n\t */\n\tasync subscribe(method: string, ...parameters: RPCParameter[]): Promise<void>\n\t{\n\t\t// Initialize an empty list of subscription payloads, if needed.\n\t\tif(!this.subscriptionMethods[method])\n\t\t{\n\t\t\tthis.subscriptionMethods[method] = new Set<string>();\n\t\t}\n\n\t\t// Store the subscription parameters to track what data we have subscribed to.\n\t\tthis.subscriptionMethods[method].add(JSON.stringify(parameters));\n\n\t\t// Send initial subscription request.\n\t\tconst requestData = await this.request(method, ...parameters);\n\n\t\t// Construct a notification structure to package the initial result as a notification.\n\t\tconst notification =\n\t\t{\n\t\t\tjsonrpc: '2.0',\n\t\t\tmethod: method,\n\t\t\tparams: [ ...parameters, requestData ],\n\t\t};\n\n\t\t// Manually emit an event for the initial response.\n\t\tthis.emit('notification', notification);\n\t}\n\n\t/**\n\t * Unsubscribes to the method at the server and removes any callback functions\n\t * when there are no more subscriptions for the method.\n\t *\n\t * @param {string}    method       a previously subscribed to method.\n\t * @param {...string} parameters   one or more parameters for the method.\n\t *\n\t * @throws {Error} if no subscriptions exist for the combination of the provided `method` and `parameters.\n\t * @throws {Error} if the client is disconnected.\n\t * @returns a promise resolving when the subscription is removed.\n\t */\n\tasync unsubscribe(method: string, ...parameters: RPCParameter[]): Promise<void>\n\t{\n\t\t// Throw an error if the client is disconnected.\n\t\tif(this.connection.status !== ConnectionStatus.CONNECTED)\n\t\t{\n\t\t\tthrow(new Error(`Unable to send unsubscribe request to a disconnected server '${this.connection.host}'.`));\n\t\t}\n\n\t\t// If this method has no subscriptions..\n\t\tif(!this.subscriptionMethods[method])\n\t\t{\n\t\t\t// Reject this promise with an explanation.\n\t\t\tthrow(new Error(`Cannot unsubscribe from '${method}' since the method has no subscriptions.`));\n\t\t}\n\n\t\t// Pack up the parameters as a long string.\n\t\tconst subscriptionParameters = JSON.stringify(parameters);\n\n\t\t// If the method payload could not be located..\n\t\tif(!this.subscriptionMethods[method].has(subscriptionParameters))\n\t\t{\n\t\t\t// Reject this promise with an explanation.\n\t\t\tthrow(new Error(`Cannot unsubscribe from '${method}' since it has no subscription with the given parameters.`));\n\t\t}\n\n\t\t// Remove this specific subscription payload from internal tracking.\n\t\tthis.subscriptionMethods[method].delete(subscriptionParameters);\n\n\t\t// Send unsubscription request to the server\n\t\t// NOTE: As a convenience we allow users to define the method as the subscribe or unsubscribe version.\n\t\tawait this.request(method.replace('.subscribe', '.unsubscribe'), ...parameters);\n\n\t\t// Write a log message.\n\t\tdebug.client(`Unsubscribed from '${String(method)}' for the '${subscriptionParameters}' parameters.`);\n\t}\n\n\t/**\n\t * Restores existing subscriptions without updating status or triggering manual callbacks.\n\t *\n\t * @throws {Error} if subscription data cannot be found for all stored event names.\n\t * @throws {Error} if the client is disconnected.\n\t * @returns a promise resolving to true when the subscriptions are restored.\n\t *\n\t * @ignore\n\t */\n\tprivate async resubscribeOnConnect(): Promise<void>\n\t{\n\t\t// Write a log message.\n\t\tdebug.client(`Connected to '${this.connection.hostIdentifier}'.`);\n\n\t\t// Initialize an empty list of resubscription promises.\n\t\tconst resubscriptionPromises = [];\n\n\t\t// For each method we have a subscription for..\n\t\tfor(const method in this.subscriptionMethods)\n\t\t{\n\t\t\t// .. and for each parameter we have previously been subscribed to..\n\t\t\tfor(const parameterJSON of this.subscriptionMethods[method].values())\n\t\t\t{\n\t\t\t\t// restore the parameters from JSON.\n\t\t\t\tconst parameters = JSON.parse(parameterJSON);\n\n\t\t\t\t// Send a subscription request.\n\t\t\t\tresubscriptionPromises.push(this.subscribe(method, ...parameters));\n\t\t\t}\n\n\t\t\t// Wait for all re-subscriptions to complete.\n\t\t\tawait Promise.all(resubscriptionPromises);\n\t\t}\n\n\t\t// Write a log message if there was any subscriptions to restore.\n\t\tif(resubscriptionPromises.length > 0)\n\t\t{\n\t\t\tdebug.client(`Restored ${resubscriptionPromises.length} previous subscriptions for '${this.connection.hostIdentifier}'`);\n\t\t}\n\t}\n\n\t/**\n\t * Parser messages from the remote server to resolve request promises and emit subscription events.\n\t *\n\t * @param {RPCNotification | RPCResponse} message   the response message\n\t *\n\t * @throws {Error} if the message ID does not match an existing request.\n\t * @ignore\n\t */\n\tresponse(message: RPCNotification | RPCResponse): void\n\t{\n\t\t// If the received message is a notification, we forward it to all event listeners\n\t\tif(isRPCNotification(message))\n\t\t{\n\t\t\t// Write a log message.\n\t\t\tdebug.client(`Received notification for '${message.method}' from '${this.connection.host}'`);\n\n\t\t\t// Forward the message content to all event listeners.\n\t\t\tthis.emit('notification', message);\n\n\t\t\t// Return since it does not have an associated request resolver\n\t\t\treturn;\n\t\t}\n\n\t\t// If the response ID is null we cannot use it to index our request resolvers\n\t\tif(message.id === null)\n\t\t{\n\t\t\t// Throw an internal error, this should not happen.\n\t\t\tthrow(new Error('Internal error: Received an RPC response with ID null.'));\n\t\t}\n\n\t\t// Look up which request promise we should resolve this.\n\t\tconst requestResolver = this.requestResolvers[message.id];\n\n\t\t// If we do not have a request resolver for this response message..\n\t\tif(!requestResolver)\n\t\t{\n\t\t\t// Throw an internal error, this should not happen.\n\t\t\tthrow(new Error('Internal error: Callback for response not available.'));\n\t\t}\n\n\t\t// Remove the promise from the request list.\n\t\tdelete this.requestResolvers[message.id];\n\n\t\t// If the message contains an error..\n\t\tif(isRPCErrorResponse(message))\n\t\t{\n\t\t\t// Forward the message error to the request resolver and omit the `result` parameter.\n\t\t\trequestResolver(new Error(message.error.message));\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Forward the message content to the request resolver and omit the `error` parameter\n\t\t\t// (by setting it to undefined).\n\t\t\trequestResolver(undefined, message.result);\n\t\t}\n\t}\n\n\t/**\n\t * Callback function that is called when connection to the Electrum server is lost.\n\t * Aborts all active requests with an error message indicating that connection was lost.\n\t *\n\t * @ignore\n\t */\n\tonConnectionDisconnect(): void\n\t{\n\t\t// Emit a disconnection signal to any listeners.\n\t\tthis.emit('disconnected');\n\n\t\t// Loop over active requests\n\t\tfor(const resolverId in this.requestResolvers)\n\t\t{\n\t\t\t// Extract request resolver for readability\n\t\t\tconst requestResolver = this.requestResolvers[resolverId];\n\n\t\t\t// Resolve the active request with an error indicating that the connection was lost.\n\t\t\trequestResolver(new Error('Connection lost'));\n\n\t\t\t// Remove the promise from the request list.\n\t\t\tdelete this.requestResolvers[resolverId];\n\t\t}\n\t}\n}\n\n// Export the client.\nexport default ElectrumClient;\n","import debugLogger from 'debug';\n\n// Create the debug logs.\nconst debug =\n{\n\tclient:  debugLogger('electrum-cash:client '),\n\tcluster: debugLogger('electrum-cash:cluster'),\n\terrors:  debugLogger('electrum-cash:error  '),\n\twarning: debugLogger('electrum-cash:warning'),\n\tnetwork: debugLogger('electrum-cash:network'),\n\tping:    debugLogger('electrum-cash:pulses '),\n};\n\n// Set log colors.\ndebug.client.color = '2';\ndebug.cluster.color = '3';\ndebug.errors.color = '9';\ndebug.warning.color = '13';\ndebug.network.color = '4';\ndebug.ping.color = '8';\n\n// Export the logs.\nexport default debug;\n","import debug from './util';\nimport ElectrumProtocol from './electrum-protocol';\nimport { ResolveFunction, RejectFunction, VersionRejected, VersionNegotiated, isVersionRejected, TransportScheme } from './interfaces';\nimport { DefaultParameters } from './constants';\nimport { EventEmitter } from 'events';\nimport ElectrumSocket from './electrum-socket';\nimport { ConnectionStatus } from './enums';\n\n/**\n * Wrapper around TLS/WSS sockets that gracefully separates a network stream into Electrum protocol messages.\n *\n * @ignore\n */\nclass ElectrumConnection extends EventEmitter\n{\n\t// Declare an empty socket.\n\tsocket: ElectrumSocket;\n\n\t// Declare empty timestamps\n\tlastReceivedTimestamp: number;\n\n\t// Declare timers for keep-alive pings and reconnection\n\ttimers: {\n\t\t// eslint-disable-next-line no-undef\n\t\tkeepAlive?: NodeJS.Timer;\n\t\t// eslint-disable-next-line no-undef\n\t\treconnect?: NodeJS.Timer;\n\t} = {};\n\n\t// Initialize an empty array of connection verification timers.\n\t// eslint-disable-next-line no-undef\n\tverifications: Array<NodeJS.Timer> = [];\n\n\t// Initialize the connected flag to false to indicate that there is no connection\n\tstatus: ConnectionStatus = ConnectionStatus.DISCONNECTED;\n\n\t// Initialize messageBuffer to an empty string\n\tmessageBuffer = '';\n\n\t/**\n\t * Sets up network configuration for an Electrum client connection.\n\t *\n\t * @param {string} application       your application name, used to identify to the electrum host.\n\t * @param {string} version           protocol version to use with the host.\n\t * @param {string} host              fully qualified domain name or IP number of the host.\n\t * @param {number} port              the network port of the host.\n\t * @param {TransportScheme} scheme   the transport scheme to use for connection\n\t * @param {number} timeout           how long network delays we will wait for before taking action, in milliseconds.\n\t * @param {number} pingInterval      the time between sending pings to the electrum host, in milliseconds.\n\t * @param {number} reconnectInterval the time between reconnection attempts to the electrum host, in milliseconds.\n\t *\n\t * @throws {Error} if `version` is not a valid version string.\n\t */\n\tconstructor(\n\t\tpublic application: string,\n\t\tpublic version: string,\n\t\tpublic host: string,\n\t\tpublic port: number = DefaultParameters.PORT,\n\t\tpublic scheme: TransportScheme = DefaultParameters.TRANSPORT_SCHEME,\n\t\tpublic timeout: number = DefaultParameters.TIMEOUT,\n\t\tpublic pingInterval: number = DefaultParameters.PING_INTERVAL,\n\t\tpublic reconnectInterval: number = DefaultParameters.RECONNECT,\n\t)\n\t{\n\t\t// Initialize the event emitter.\n\t\tsuper();\n\n\t\t// Check if the provided version is a valid version number.\n\t\tif(!ElectrumProtocol.versionRegexp.test(version))\n\t\t{\n\t\t\t// Throw an error since the version number was not valid.\n\t\t\tthrow(new Error(`Provided version string (${version}) is not a valid protocol version number.`));\n\t\t}\n\n\t\t// Create an initial network socket.\n\t\tthis.createSocket();\n\n\t\t// Handle visibility changes when run in a browser environment.\n\t\tif(typeof document !== 'undefined')\n\t\t{\n\t\t\tdocument.addEventListener('visibilitychange', this.handleVisibilityChange.bind(this));\n\t\t}\n\t}\n\n\t/**\n\t * Returns a string for the host identifier for usage in debug messages.\n\t */\n\tget hostIdentifier(): string\n\t{\n\t\treturn `${this.host}:${this.port}`;\n\t}\n\n\t/**\n\t * Create and configures a fresh socket and attaches all relevant listeners.\n\t */\n\tcreateSocket(): void\n\t{\n\t\t// Initialize a new ElectrumSocket\n\t\tthis.socket = new ElectrumSocket();\n\n\t\t// Set up handlers for connection and disconnection.\n\t\tthis.socket.on('connect', this.onSocketConnect.bind(this));\n\t\tthis.socket.on('disconnect', this.onSocketDisconnect.bind(this));\n\n\t\t// Set up handler for incoming data.\n\t\tthis.socket.on('data', this.parseMessageChunk.bind(this));\n\t}\n\n\t/**\n\t * Shuts down and destroys the current socket.\n\t */\n\tdestroySocket(): void\n\t{\n\t\t// Close the socket connection and destroy the socket.\n\t\tthis.socket.disconnect();\n\t}\n\n\t/**\n\t * Assembles incoming data into statements and hands them off to the message parser.\n\t *\n\t * @param {string} data   data to append to the current message buffer, as a string.\n\t *\n\t * @throws {SyntaxError} if the passed statement parts are not valid JSON.\n\t */\n\tparseMessageChunk(data: string): void\n\t{\n\t\t// Update the timestamp for when we last received data.\n\t\tthis.lastReceivedTimestamp = Date.now();\n\n\t\t// Clear and remove all verification timers.\n\t\tthis.verifications.forEach((timer) => clearTimeout(timer));\n\t\tthis.verifications.length = 0;\n\n\t\t// Add the message to the current message buffer.\n\t\tthis.messageBuffer += data;\n\n\t\t// Check if the new message buffer contains the statement delimiter.\n\t\twhile(this.messageBuffer.includes(ElectrumProtocol.statementDelimiter))\n\t\t{\n\t\t\t// Split message buffer into statements.\n\t\t\tconst statementParts = this.messageBuffer.split(ElectrumProtocol.statementDelimiter);\n\n\t\t\t// For as long as we still have statements to parse..\n\t\t\twhile(statementParts.length > 1)\n\t\t\t{\n\t\t\t\t// Move the first statement to its own variable.\n\t\t\t\tconst currentStatementList = String(statementParts.shift());\n\n\t\t\t\t// Parse the statement into an object or list of objects.\n\t\t\t\tlet statementList = JSON.parse(currentStatementList);\n\n\t\t\t\t// Wrap the statement in an array if it is not already a batched statement list.\n\t\t\t\tif(!Array.isArray(statementList))\n\t\t\t\t{\n\t\t\t\t\tstatementList = [ statementList ];\n\t\t\t\t}\n\n\t\t\t\t// For as long as there is statements in the result set..\n\t\t\t\twhile(statementList.length > 0)\n\t\t\t\t{\n\t\t\t\t\t// Move the first statement from the batch to its own variable.\n\t\t\t\t\tconst currentStatement = statementList.shift();\n\n\t\t\t\t\t// If the current statement is a version negotiation response..\n\t\t\t\t\tif(currentStatement.id === 'versionNegotiation')\n\t\t\t\t\t{\n\t\t\t\t\t\tif(currentStatement.error)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Then emit a failed version negotiation response signal.\n\t\t\t\t\t\t\tthis.emit('version', { error: currentStatement.error });\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Emit a successful version negotiation response signal.\n\t\t\t\t\t\t\tthis.emit('version', { software: currentStatement.result[0], protocol: currentStatement.result[1] });\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Consider this statement handled.\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t// If the current statement is a keep-alive response..\n\t\t\t\t\tif(currentStatement.id === 'keepAlive')\n\t\t\t\t\t{\n\t\t\t\t\t\t// Do nothing and consider this statement handled.\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Emit the statements for handling higher up in the stack.\n\t\t\t\t\tthis.emit('statement', currentStatement);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Store the remaining statement as the current message buffer.\n\t\t\tthis.messageBuffer = statementParts.shift() || '';\n\t\t}\n\t}\n\n\t/**\n\t * Sends a keep-alive message to the host.\n\t *\n\t * @returns true if the ping message was fully flushed to the socket, false if\n\t * part of the message is queued in the user memory\n\t */\n\tping(): boolean\n\t{\n\t\t// Write a log message.\n\t\tdebug.ping(`Sending keep-alive ping to '${this.hostIdentifier}'`);\n\n\t\t// Craft a keep-alive message.\n\t\tconst message = ElectrumProtocol.buildRequestObject('server.ping', [], 'keepAlive');\n\n\t\t// Send the keep-alive message.\n\t\tconst status = this.send(message);\n\n\t\t// Return the ping status.\n\t\treturn status;\n\t}\n\n\t/**\n\t * Initiates the network connection negotiates a protocol version. Also emits the 'connect' signal if successful.\n\t *\n\t * @throws {Error} if the socket connection fails.\n\t * @returns a promise resolving when the connection is established\n\t */\n\tasync connect(): Promise<void>\n\t{\n\t\t// If we are already connected return true.\n\t\tif(this.status === ConnectionStatus.CONNECTED)\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\t// Indicate that the connection is connecting\n\t\tthis.status = ConnectionStatus.CONNECTING;\n\n\t\t// Define a function to wrap connection as a promise.\n\t\tconst connectionResolver = (resolve: ResolveFunction<void>, reject: RejectFunction): void =>\n\t\t{\n\t\t\tconst rejector = (error: Error): void =>\n\t\t\t{\n\t\t\t\t// Set the status back to disconnected\n\t\t\t\tthis.status = ConnectionStatus.DISCONNECTED;\n\n\t\t\t\t// Reject with the error as reason\n\t\t\t\treject(error);\n\t\t\t};\n\n\t\t\t// Replace previous error handlers to reject the promise on failure.\n\t\t\tthis.socket.removeAllListeners('error');\n\t\t\tthis.socket.once('error', rejector);\n\n\t\t\t// Define a function to wrap version negotiation as a callback.\n\t\t\tconst versionNegotiator = (): void =>\n\t\t\t{\n\t\t\t\t// Write a log message to show that we have started version negotiation.\n\t\t\t\tdebug.network(`Requesting protocol version ${this.version} with '${this.hostIdentifier}'.`);\n\n\t\t\t\t// remove the one-time error handler since no error was detected.\n\t\t\t\tthis.socket.removeListener('error', rejector);\n\n\t\t\t\t// Build a version negotiation message.\n\t\t\t\tconst versionMessage = ElectrumProtocol.buildRequestObject('server.version', [ this.application, this.version ], 'versionNegotiation');\n\n\t\t\t\t// Define a function to wrap version validation as a function.\n\t\t\t\tconst versionValidator = (version: VersionRejected | VersionNegotiated): void =>\n\t\t\t\t{\n\t\t\t\t\t// Check if version negotiation failed.\n\t\t\t\t\tif(isVersionRejected(version))\n\t\t\t\t\t{\n\t\t\t\t\t\t// Disconnect from the host.\n\t\t\t\t\t\tthis.disconnect(true);\n\n\t\t\t\t\t\t// Declare an error message.\n\t\t\t\t\t\tconst errorMessage = 'unsupported protocol version.';\n\n\t\t\t\t\t\t// Log the error.\n\t\t\t\t\t\tdebug.errors(`Failed to connect with ${this.hostIdentifier} due to ${errorMessage}`);\n\n\t\t\t\t\t\t// Reject the connection with false since version negotiation failed.\n\t\t\t\t\t\treject(errorMessage);\n\t\t\t\t\t}\n\t\t\t\t\t// Check if the host supports our requested protocol version.\n\t\t\t\t\t// NOTE: the server responds with version numbers that truncate 0's, so 1.5.0 turns into 1.5.\n\t\t\t\t\telse if((version.protocol !== this.version) && (`${version.protocol}.0` !== this.version) && (`${version.protocol}.0.0` !== this.version))\n\t\t\t\t\t{\n\t\t\t\t\t\t// Disconnect from the host.\n\t\t\t\t\t\tthis.disconnect(true);\n\n\t\t\t\t\t\t// Declare an error message.\n\t\t\t\t\t\tconst errorMessage = `incompatible protocol version negotiated (${version.protocol} !== ${this.version}).`;\n\n\t\t\t\t\t\t// Log the error.\n\t\t\t\t\t\tdebug.errors(`Failed to connect with ${this.hostIdentifier} due to ${errorMessage}`);\n\n\t\t\t\t\t\t// Reject the connection with false since version negotiation failed.\n\t\t\t\t\t\treject(errorMessage);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// Write a log message.\n\t\t\t\t\t\tdebug.network(`Negotiated protocol version ${version.protocol} with '${this.hostIdentifier}', powered by ${version.software}.`);\n\n\t\t\t\t\t\t// Set connection status to connected\n\t\t\t\t\t\tthis.status = ConnectionStatus.CONNECTED;\n\n\t\t\t\t\t\t// Emit a connect event now that the connection is usable.\n\t\t\t\t\t\tthis.emit('connect');\n\n\t\t\t\t\t\t// Resolve the connection promise since we successfully connected and negotiated protocol version.\n\t\t\t\t\t\tresolve();\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\t// Listen for version negotiation once.\n\t\t\t\tthis.once('version', versionValidator);\n\n\t\t\t\t// Send the version negotiation message.\n\t\t\t\tthis.send(versionMessage);\n\t\t\t};\n\n\t\t\t// Prepare the version negotiation.\n\t\t\tthis.socket.once('connect', versionNegotiator);\n\n\t\t\t// Set up handler for network errors.\n\t\t\tthis.socket.on('error', this.onSocketError.bind(this));\n\n\t\t\t// Connect to the server.\n\t\t\tthis.socket.connect(this.host, this.port, this.scheme, this.timeout);\n\t\t};\n\n\t\t// Wait until connection is established and version negotiation succeeds.\n\t\tawait new Promise<void>(connectionResolver);\n\t}\n\n\t/**\n\t * Restores the network connection.\n\t */\n\tasync reconnect(): Promise<void>\n\t{\n\t\t// If a reconnect timer is set, remove it\n\t\tawait this.clearReconnectTimer();\n\n\t\t// Write a log message.\n\t\tdebug.network(`Trying to reconnect to '${this.hostIdentifier}'..`);\n\n\t\t// Set the status to reconnecting for more accurate log messages.\n\t\tthis.status = ConnectionStatus.RECONNECTING;\n\n\t\t// Destroy and recreate the socket to get a clean slate.\n\t\tthis.destroySocket();\n\t\tthis.createSocket();\n\n\t\ttry\n\t\t{\n\t\t\t// Try to connect again.\n\t\t\tawait this.connect();\n\t\t}\n\t\tcatch(error)\n\t\t{\n\t\t\t// Do nothing as the error should be handled via the disconnect and error signals.\n\t\t}\n\t}\n\n\t/**\n\t * Removes the current reconnect timer.\n\t */\n\tclearReconnectTimer(): void\n\t{\n\t\t// If a reconnect timer is set, remove it\n\t\tif(this.timers.reconnect)\n\t\t{\n\t\t\tclearTimeout(this.timers.reconnect);\n\t\t}\n\n\t\t// Reset the timer reference.\n\t\tthis.timers.reconnect = undefined;\n\t}\n\n\t/**\n\t * Removes the current keep-alive timer.\n\t */\n\tclearKeepAliveTimer(): void\n\t{\n\t\t// If a keep-alive timer is set, remove it\n\t\tif(this.timers.keepAlive)\n\t\t{\n\t\t\tclearTimeout(this.timers.keepAlive);\n\t\t}\n\n\t\t// Reset the timer reference.\n\t\tthis.timers.keepAlive = undefined;\n\t}\n\n\t/**\n\t * Initializes the keep alive timer loop.\n\t */\n\tsetupKeepAliveTimer(): void\n\t{\n\t\t// If the keep-alive timer loop is not currently set up..\n\t\tif(!this.timers.keepAlive)\n\t\t{\n\t\t\t// Set a new keep-alive timer.\n\t\t\tthis.timers.keepAlive = setTimeout(this.ping.bind(this), this.pingInterval);\n\t\t}\n\t}\n\n\t/**\n\t * Tears down the current connection and removes all event listeners on disconnect.\n\t *\n\t * @param {boolean} force         disconnect even if the connection has not been fully established yet.\n\t * @param {boolean} intentional   update connection state if disconnect is intentional.\n\t *\n\t * @returns true if successfully disconnected, or false if there was no connection.\n\t */\n\tasync disconnect(force: boolean = false, intentional: boolean = true): Promise<boolean>\n\t{\n\t\t// Return early when there is nothing to disconnect from\n\t\tif(this.status === ConnectionStatus.DISCONNECTED && !force)\n\t\t{\n\t\t\t// Return false to indicate that there was nothing to disconnect from.\n\t\t\treturn false;\n\t\t}\n\n\t\t// Update connection state if the disconnection is intentional.\n\t\t// NOTE: The state is meant to represent what the client is requesting, but\n\t\t//       is used internally to handle visibility changes in browsers to ensure functional reconnection.\n\t\tif(intentional)\n\t\t{\n\t\t\t// Set connection status to null to indicate tear-down is currently happening.\n\t\t\tthis.status = ConnectionStatus.DISCONNECTING;\n\t\t}\n\n\t\t// If a keep-alive timer is set, remove it.\n\t\tawait this.clearKeepAliveTimer();\n\n\t\t// If a reconnect timer is set, remove it\n\t\tawait this.clearReconnectTimer();\n\n\t\tconst disconnectResolver = (resolve: ResolveFunction<boolean>): void =>\n\t\t{\n\t\t\t// Resolve to true after the connection emits a disconnect\n\t\t\tthis.once('disconnect', () => resolve(true));\n\n\t\t\t// Close the connection and destroy the socket.\n\t\t\tthis.destroySocket();\n\t\t};\n\n\t\t// Return true to indicate that we disconnected.\n\t\treturn new Promise<boolean>(disconnectResolver);\n\t}\n\n\t/**\n\t * Updates connection state based on application visibility.\n\t *\n\t * Some browsers will disconnect network connections when the browser is out of focus,\n\t * which would normally cause our reconnect-on-timeout routines to trigger, but that\n\t * results in a poor user experience since the events are not handled consistently\n\t * and sometimes it can take some time after restoring focus to the browser.\n\t *\n\t * By manually disconnecting when this happens we prevent the default reconnection routines\n\t * and make the behavior consistent across browsers.\n\t */\n\tasync handleVisibilityChange(): Promise<void>\n\t{\n\t\t// Disconnect when application is removed from focus.\n\t\tif(document.visibilityState === 'hidden')\n\t\t{\n\t\t\tconst forceDisconnect = true;\n\t\t\tconst isIntended = false;\n\n\t\t\tthis.disconnect(forceDisconnect, isIntended);\n\t\t}\n\n\t\t// Reconnect when application is returned to focus.\n\t\tif(document.visibilityState === 'visible')\n\t\t{\n\t\t\tthis.reconnect();\n\t\t}\n\t}\n\n\t/**\n\t * Sends an arbitrary message to the server.\n\t *\n\t * @param {string} message   json encoded request object to send to the server, as a string.\n\t *\n\t * @returns true if the message was fully flushed to the socket, false if part of the message\n\t * is queued in the user memory\n\t */\n\tsend(message: string): boolean\n\t{\n\t\t// Remove the current keep-alive timer if it exists.\n\t\tthis.clearKeepAliveTimer();\n\n\t\t// Get the current timestamp in milliseconds.\n\t\tconst currentTime = Date.now();\n\n\t\t// Follow up and verify that the message got sent..\n\t\tconst verificationTimer = setTimeout(this.verifySend.bind(this, currentTime), this.timeout);\n\n\t\t// Store the verification timer locally so that it can be cleared when data has been received.\n\t\tthis.verifications.push(verificationTimer);\n\n\t\t// Set a new keep-alive timer.\n\t\tthis.setupKeepAliveTimer();\n\n\t\t// Write the message to the network socket.\n\t\treturn this.socket.write(message + ElectrumProtocol.statementDelimiter);\n\t}\n\n\t// --- Event managers. --- //\n\n\t/**\n\t * Marks the connection as timed out and schedules reconnection if we have not\n\t * received data within the expected time frame.\n\t */\n\tverifySend(sentTimestamp: number): void\n\t{\n\t\t// If we haven't received any data since we last sent data out..\n\t\tif(Number(this.lastReceivedTimestamp) < sentTimestamp)\n\t\t{\n\t\t\t// If this connection is already disconnected, we do not change anything\n\t\t\tif((this.status === ConnectionStatus.DISCONNECTED) || (this.status === ConnectionStatus.DISCONNECTING))\n\t\t\t{\n\t\t\t\tdebug.errors(`Tried to verify already disconnected connection to '${this.hostIdentifier}'`);\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Remove the current keep-alive timer if it exists.\n\t\t\tthis.clearKeepAliveTimer();\n\n\t\t\t// Write a notification to the logs.\n\t\t\tdebug.network(`Connection to '${this.hostIdentifier}' timed out.`);\n\n\t\t\t// Close the connection to avoid re-use.\n\t\t\t// NOTE: This initiates reconnection routines if the connection has not\n\t\t\t//       been marked as intentionally disconnected.\n\t\t\tthis.socket.disconnect();\n\t\t}\n\t}\n\n\t/**\n\t * Updates the connection status when a connection is confirmed.\n\t */\n\tonSocketConnect(): void\n\t{\n\t\t// If a reconnect timer is set, remove it.\n\t\tthis.clearReconnectTimer();\n\n\t\t// Set up the initial timestamp for when we last received data from the server.\n\t\tthis.lastReceivedTimestamp = Date.now();\n\n\t\t// Set up the initial keep-alive timer.\n\t\tthis.setupKeepAliveTimer();\n\n\t\t// Clear all temporary error listeners.\n\t\tthis.socket.removeAllListeners('error');\n\n\t\t// Set up handler for network errors.\n\t\tthis.socket.on('error', this.onSocketError.bind(this));\n\t}\n\n\t/**\n\t * Updates the connection status when a connection is ended.\n\t */\n\tonSocketDisconnect(): void\n\t{\n\t\t// Send a disconnect signal higher up the stack.\n\t\tthis.emit('disconnect');\n\n\t\t// Remove the current keep-alive timer if it exists.\n\t\tthis.clearKeepAliveTimer();\n\n\t\t// If this is a connection we're trying to tear down..\n\t\tif(this.status === ConnectionStatus.DISCONNECTING)\n\t\t{\n\t\t\t// If a reconnect timer is set, remove it.\n\t\t\tthis.clearReconnectTimer();\n\n\t\t\t// Remove all event listeners\n\t\t\tthis.removeAllListeners();\n\n\t\t\t// Mark the connection as disconnected.\n\t\t\tthis.status = ConnectionStatus.DISCONNECTED;\n\n\t\t\t// Write a log message.\n\t\t\tdebug.network(`Disconnected from '${this.hostIdentifier}'.`);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// If this is for an established connection..\n\t\t\tif(this.status === ConnectionStatus.CONNECTED)\n\t\t\t{\n\t\t\t\t// Write a notification to the logs.\n\t\t\t\tdebug.errors(`Connection with '${this.hostIdentifier}' was closed, trying to reconnect in ${this.reconnectInterval / 1000} seconds.`);\n\t\t\t}\n\t\t\t// If this is a connection that is currently connecting, reconnecting or already disconnected..\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Do nothing\n\n\t\t\t\t// NOTE: This error message is useful during manual debugging of reconnections.\n\t\t\t\t// debug.errors(`Lost connection with reconnecting or already disconnected server '${this.hostIdentifier}'.`);\n\t\t\t}\n\n\t\t\t// Mark the connection as disconnected for now..\n\t\t\tthis.status = ConnectionStatus.DISCONNECTED;\n\n\t\t\t// If we don't have a pending reconnection timer..\n\t\t\tif(!this.timers.reconnect)\n\t\t\t{\n\t\t\t\t// Attempt to reconnect after one keep-alive duration.\n\t\t\t\tthis.timers.reconnect = setTimeout(this.reconnect.bind(this), this.reconnectInterval);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Notify administrator of any unexpected errors.\n\t */\n\tonSocketError(error: any | undefined): void\n\t{\n\t\t// Report a generic error if no error information is present.\n\t\t// NOTE: When using WSS, the error event explicitly\n\t\t//       only allows to send a \"simple\" event without data.\n\t\t//       https://stackoverflow.com/a/18804298\n\t\tif(typeof error === 'undefined')\n\t\t{\n\t\t\t// Do nothing, and instead rely on the socket disconnect event for further information.\n\t\t\treturn;\n\t\t}\n\n\t\t// If the DNS lookup failed.\n\t\tif(error.code === 'EAI_AGAIN')\n\t\t{\n\t\t\tdebug.errors(`Failed to look up DNS records for '${this.host}'.`);\n\n\t\t\treturn;\n\t\t}\n\n\t\t// If the connection timed out..\n\t\tif(error.code === 'ETIMEDOUT')\n\t\t{\n\t\t\t// Log the provided timeout message.\n\t\t\tdebug.errors(error.message);\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Log unknown error\n\t\tdebug.errors(`Unknown network error ('${this.hostIdentifier}'): `, error);\n\t}\n}\n\n// Export the connection.\nexport default ElectrumConnection;\n","import { RPCParameter } from './rpc-interfaces';\n\n/**\n * Grouping of utilities that simplifies implementation of the Electrum protocol.\n *\n * @ignore\n */\nclass ElectrumProtocol\n{\n\t/**\n\t * Helper function that builds an Electrum request object.\n\t *\n\t * @param {string} method       method to call.\n\t * @param {array}  parameters   method parameters for the call.\n\t * @param {string} requestId    unique string or number referencing this request.\n\t *\n\t * @returns a properly formatted Electrum request string.\n\t */\n\tstatic buildRequestObject(method: string, parameters: RPCParameter[], requestId: string | number): string\n\t{\n\t\t// Return the formatted request object.\n\t\t// NOTE: Electrum either uses JsonRPC strictly or loosely.\n\t\t//       If we specify protocol identifier without being 100% compliant, we risk being disconnected/blacklisted.\n\t\t//       For this reason, we omit the protocol identifier to avoid issues.\n\t\treturn JSON.stringify({ method: method, params: parameters, id: requestId });\n\t}\n\n\t/**\n\t * Constant used to verify if a provided string is a valid version number.\n\t *\n\t * @returns a regular expression that matches valid version numbers.\n\t */\n\tstatic get versionRegexp(): RegExp\n\t{\n\t\treturn /^\\d+(\\.\\d+)+$/;\n\t}\n\n\t/**\n\t * Constant used to separate statements/messages in a stream of data.\n\t *\n\t * @returns the delimiter used by Electrum to separate statements.\n\t */\n\tstatic get statementDelimiter(): string\n\t{\n\t\treturn '\\n';\n\t}\n}\n\n// export the protocol.\nexport default ElectrumProtocol;\n","import type { ClientState } from './enums';\nimport type ElectrumClient from './electrum-client';\nimport type { RPCError } from './rpc-interfaces';\n\nexport interface ClientConfig\n{\n\t// Availability of the client's connection\n\tstate: ClientState;\n\n\t// The client's connection\n\tconnection: ElectrumClient;\n}\n\n/**\n * A list of possible responses to requests.\n */\nexport type RequestResponse = object | string | number | boolean | null | RequestResponse[];\n\n// Request resolvers are used to process the response of a request. This takes either\n// an error object or any stringified data, while the other parameter is omitted.\nexport type RequestResolver = (error?: Error, data?: string) => void;\n\n// Promise types\nexport type ResolveFunction<T> = (value: T | PromiseLike<T>) => void;\nexport type RejectFunction = (reason?: any) => void;\n\nexport interface VersionRejected\n{\n\terror: RPCError;\n}\n\nexport interface VersionNegotiated\n{\n\tsoftware: string;\n\tprotocol: string;\n}\n\nexport const isVersionRejected = function(object: any): object is VersionRejected\n{\n\treturn 'error' in object;\n};\n\nexport const isVersionNegotiated = function(object: any): object is VersionNegotiated\n{\n\treturn 'software' in object && 'protocol' in object;\n};\n\n/**\n * Possible Transport Schemes for communication with the Electrum server\n */\nexport type TransportScheme = 'tcp' | 'tcp_tls' | 'ws' | 'wss';\n\n// Connection options used with TLS connections.\nexport interface ConnectionOptions\n{\n\trejectUnauthorized?: boolean;\n\tserverName?: string;\n}\n","import { ClusterDistribution, ClusterOrder } from './enums';\nimport { TransportScheme } from './interfaces';\n\n/**\n * Object containing the commonly used ports and schemes for specific Transports.\n * @example const electrum = new ElectrumClient('Electrum client example', '1.4.1', 'bch.imaginary.cash', Transport.WSS.Port, Transport.WSS.Scheme);\n *\n * @property {object} TCP       Port and Scheme to use unencrypted TCP sockets.\n * @property {object} TCP_TLS   Port and Scheme to use TLS-encrypted TCP sockets.\n * @property {object} WS        Port and Scheme to use unencrypted WebSockets.\n * @property {object} WSS       Port and Scheme to use TLS-encrypted WebSockets.\n */\nexport const ElectrumTransport =\n{\n\tTCP:     { Port: 50001, Scheme: 'tcp' as TransportScheme },\n\tTCP_TLS: { Port: 50002, Scheme: 'tcp_tls' as TransportScheme },\n\tWS:      { Port: 50003, Scheme: 'ws' as TransportScheme },\n\tWSS:     { Port: 50004, Scheme: 'wss' as TransportScheme },\n};\n\nexport const DefaultParameters =\n{\n\t// Port number for TCP TLS connections\n\tPORT: ElectrumTransport.TCP_TLS.Port,\n\n\t// Transport to connect to the Electrum server\n\tTRANSPORT_SCHEME: ElectrumTransport.TCP_TLS.Scheme,\n\n\t// How long to wait before attempting to reconnect, in milliseconds.\n\tRECONNECT: 15 * 1000,\n\n\t// How long to wait for network operations before following up, in milliseconds.\n\tTIMEOUT: 120 * 1000,\n\n\t// Time between ping messages, in milliseconds. Pinging keeps the connection alive.\n\t// The reason for pinging this frequently is to detect connection problems early.\n\tPING_INTERVAL: 3 * 1000,\n\n\t// How many servers are required before we trust information provided.\n\tCLUSTER_CONFIDENCE: 1,\n\n\t// How many servers we send requests to.\n\tCLUSTER_DISTRIBUTION: ClusterDistribution.ALL,\n\n\t// What order we select servers to send requests to.\n\tCLUSTER_ORDER: ClusterOrder.RANDOM,\n};\n","// Disable indent rule for this file because it is broken (https://github.com/typescript-eslint/typescript-eslint/issues/1824)\n/* eslint-disable @typescript-eslint/indent */\n\n/**\n * Enum that denotes the ordering to use in an ElectrumCluster.\n * @enum {number}\n * @property {0} RANDOM     Send requests to randomly selected servers in the cluster.\n * @property {1} PRIORITY   Send requests to servers in the cluster in the order they were added.\n */\nexport enum ClusterOrder\n{\n\tRANDOM = 0,\n\tPRIORITY = 1,\n}\n\n/**\n * Enum that denotes the distribution setting to use in an ElectrumCluster.\n * @enum {number}\n * @property {0} ALL   Send requests to all servers in the cluster.\n */\nexport enum ClusterDistribution\n{\n\tALL = 0,\n}\n\n/**\n * Enum that denotes the ready status of an ElectrumCluster.\n * @enum {number}\n * @property {0} DISABLED    The cluster is disabled and unusable.\n * @property {1} DEGRADED    The cluster is degraded but still usable.\n * @property {2} READY       The cluster is healthy and ready for use.\n */\nexport enum ClusterStatus\n{\n\tDISABLED = 0,\n\tDEGRADED = 1,\n\tREADY = 2,\n}\n\n/**\n * Enum that denotes the availability of an ElectrumClient.\n * @enum {number}\n * @property {0} UNAVAILABLE   The client is currently not available.\n * @property {1} AVAILABLE     The client is available for use.\n */\nexport enum ClientState\n{\n\tUNAVAILABLE = 0,\n\tAVAILABLE = 1,\n}\n\n/**\n * Enum that denotes the connection status of an ElectrumConnection.\n * @enum {number}\n * @property {0} DISCONNECTED    The connection is disconnected.\n * @property {1} AVAILABLE       The connection is connected.\n * @property {2} DISCONNECTING   The connection is disconnecting.\n * @property {3} CONNECTING      The connection is connecting.\n * @property {4} RECONNECTING    The connection is restarting.\n */\nexport enum ConnectionStatus\n{\n\tDISCONNECTED = 0,\n\tCONNECTED = 1,\n\tDISCONNECTING = 2,\n\tCONNECTING = 3,\n\tRECONNECTING = 4,\n}\n","import * as tls from 'tls';\nimport * as net from 'net';\nimport { WebSocket } from '@monsterbitar/isomorphic-ws';\nimport type { MessageEvent, ErrorEvent } from '@monsterbitar/isomorphic-ws';\nimport { EventEmitter } from 'events';\nimport debug from './util';\nimport { ElectrumTransport } from './constants';\nimport { TransportScheme, ConnectionOptions } from './interfaces';\n\n/**\n * Isomorphic Socket interface supporting TCP sockets and WebSockets (Node and browser).\n * The interface is a subset of the TLSSocket interface with some slight modifications.\n * It can be expanded when more socket functionality is needed in the rest of the\n * electrum-cash code. Changes from the TLSSocket interface (besides it being a subset):\n * - Event 'close' -> 'disconnect'\n * - New function socket.disconnect()\n *\n * @ignore\n */\nclass ElectrumSocket extends EventEmitter\n{\n\t// Declare an empty TCP socket.\n\ttcpSocket?: net.Socket;\n\n\t// Declare an empty WebSocket.\n\twebSocket?: WebSocket;\n\n\t// Declare timers for keep-alive pings and reconnection\n\ttimers: {\n\t\t// eslint-disable-next-line no-undef\n\t\tretryConnection?: NodeJS.Timer;\n\t\t// eslint-disable-next-line no-undef\n\t\tdisconnect?: NodeJS.Timer;\n\t} = {};\n\n\t// Initialize boolean that indicates whether the onConnect function has run (initialize to false).\n\tonConnectHasRun = false;\n\n\t// Initialize event forwarding functions.\n\teventForwarders =\n\t{\n\t\tdisconnect: ()                => this.emit('disconnect'),\n\t\ttcpData: (data: string)       => this.emit('data', data),\n\t\twsData: (event: MessageEvent) => this.emit('data', `${event.data}\\n`),\n\t\ttcpError: (err: Error)        => this.emit('error', err),\n\t\twsError: (event: ErrorEvent)  => this.emit('error', event.error),\n\t};\n\n\t/**\n\t * Connect to host:port using the specified transport\n\t *\n\t * @param {string} host              Fully qualified domain name or IP address of the host\n\t * @param {number} port              Network port for the host to connect to\n\t * @param {TransportScheme} scheme   Transport scheme to use\n\t * @param {number} timeout           If no connection is established after `timeout` ms, the connection is terminated\n\t *\n\t * @throws {Error} if an incorrect transport scheme is specified\n\t */\n\tconnect(host: string, port: number, scheme: TransportScheme, timeout: number): void\n\t{\n\t\t// Check that no existing socket exists before initiating a new connection.\n\t\tif(this.tcpSocket || this.webSocket)\n\t\t{\n\t\t\tthrow(new Error('Cannot initiate a new socket connection when an existing connection exists'));\n\t\t}\n\n\t\t// Set a timer to force disconnect after `timeout` seconds\n\t\tthis.timers.disconnect = setTimeout(() => this.disconnectOnTimeout(host, port, timeout), timeout);\n\n\t\t// Remove the timer if a connection is successfully established\n\t\tthis.once('connect', this.clearDisconnectTimerOnTimeout);\n\n\t\t// Define how to refer to the connection scheme in debug output.\n\t\tconst socketTypes =\n\t\t{\n\t\t\t[ElectrumTransport.TCP.Scheme]:     'a TCP Socket',\n\t\t\t[ElectrumTransport.TCP_TLS.Scheme]: 'an encrypted TCP socket',\n\t\t\t[ElectrumTransport.WS.Scheme]:      'a WebSocket',\n\t\t\t[ElectrumTransport.WSS.Scheme]:     'an encrypted WebSocket',\n\t\t};\n\n\t\t// Log that we are trying to establish a connection.\n\t\tdebug.network(`Initiating ${socketTypes[scheme]} connection to '${host}:${port}'.`);\n\n\t\tif(scheme === ElectrumTransport.TCP.Scheme || scheme === ElectrumTransport.TCP_TLS.Scheme)\n\t\t{\n\t\t\tif(scheme === ElectrumTransport.TCP_TLS.Scheme)\n\t\t\t{\n\t\t\t\t// Initialize connection options.\n\t\t\t\tconst connectionOptions: ConnectionOptions = { rejectUnauthorized: false };\n\n\t\t\t\t// If the hostname is not an IP address..\n\t\t\t\tif(!net.isIP(host))\n\t\t\t\t{\n\t\t\t\t\t// Set the servername option which enables support for SNI.\n\t\t\t\t\t// NOTE: SNI enables a server that hosts multiple domains to provide the appropriate TLS certificate.\n\t\t\t\t\tconnectionOptions.serverName = host;\n\t\t\t\t}\n\n\t\t\t\t// Initialize this.tcpSocket (allowing self-signed certificates).\n\t\t\t\tthis.tcpSocket = tls.connect(port, host, connectionOptions);\n\n\t\t\t\t// Add a 'secureConnect' listener that checks the authorization status of\n\t\t\t\t// the socket, and logs a warning when it uses a self signed certificate.\n\t\t\t\tthis.tcpSocket.once('secureConnect', () =>\n\t\t\t\t{\n\t\t\t\t\t// Cannot happen, since this event callback *only* exists on TLSSocket\n\t\t\t\t\tif(!(this.tcpSocket instanceof tls.TLSSocket)) return;\n\n\t\t\t\t\t// Force cast authorizationError from Error to string (through unknown)\n\t\t\t\t\t// because it is incorrectly typed as an Error\n\t\t\t\t\tconst authorizationError = (this.tcpSocket.authorizationError as unknown) as string;\n\t\t\t\t\tif(authorizationError === 'DEPTH_ZERO_SELF_SIGNED_CERT')\n\t\t\t\t\t{\n\t\t\t\t\t\tdebug.warning(`Connection to ${host}:${port} uses a self-signed certificate`);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\t// Trigger successful connection events.\n\t\t\t\tthis.tcpSocket.on('secureConnect', this.onConnect.bind(this, socketTypes[scheme], host, port));\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Initialize this.tcpSocket.\n\t\t\t\tthis.tcpSocket = net.connect({ host, port });\n\n\t\t\t\t// Trigger successful connection events.\n\t\t\t\tthis.tcpSocket.on('connect', this.onConnect.bind(this, socketTypes[scheme], host, port));\n\t\t\t}\n\n\t\t\t// Configure encoding.\n\t\t\tthis.tcpSocket.setEncoding('utf8');\n\n\t\t\t// Enable persistent connections with an initial delay of 0.\n\t\t\tthis.tcpSocket.setKeepAlive(true, 0);\n\n\t\t\t// Disable buffering of outgoing data.\n\t\t\tthis.tcpSocket.setNoDelay(true);\n\n\t\t\t// Forward the encountered errors.\n\t\t\tthis.tcpSocket.on('error', this.eventForwarders.tcpError);\n\t\t}\n\t\telse if(scheme === ElectrumTransport.WS.Scheme || scheme === ElectrumTransport.WSS.Scheme)\n\t\t{\n\t\t\tif(scheme === ElectrumTransport.WSS.Scheme)\n\t\t\t{\n\t\t\t\t// Initialize this.webSocket (rejecting self-signed certificates).\n\t\t\t\t// We reject self-signed certificates to match functionality of browsers.\n\t\t\t\tthis.webSocket = new WebSocket(`wss://${host}:${port}`);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Initialize this.webSocket.\n\t\t\t\tthis.webSocket = new WebSocket(`ws://${host}:${port}`);\n\t\t\t}\n\n\t\t\t// Trigger successful connection events.\n\t\t\tthis.webSocket.addEventListener('open', this.onConnect.bind(this, socketTypes[scheme], host, port));\n\n\t\t\t// Forward the encountered errors.\n\t\t\tthis.webSocket.addEventListener('error', this.eventForwarders.wsError);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Throw an error if an incorrect transport is specified\n\t\t\tthrow(new Error('Incorrect transport specified'));\n\t\t}\n\t}\n\n\t/**\n\t * Sets up forwarding of events related to the connection.\n\t *\n\t * @param {string} connectionType   Name of the connection/transport type, used for logging.\n\t * @param {string} host             Fully qualified domain name or IP address of the host\n\t * @param {number} port             Network port for the host to connect to\n\t */\n\tonConnect(connectionType: string, host: string, port: number): void\n\t{\n\t\t// If the onConnect function has already run, do not execute it again.\n\t\tif(this.onConnectHasRun) return;\n\n\t\t// Log that the connection has been established.\n\t\tdebug.network(`Established ${connectionType} connection with '${host}:${port}'.`);\n\n\t\tif(typeof this.tcpSocket !== 'undefined')\n\t\t{\n\t\t\t// Forward the socket events\n\t\t\tthis.tcpSocket.addListener('close', this.eventForwarders.disconnect);\n\t\t\tthis.tcpSocket.addListener('data', this.eventForwarders.tcpData);\n\t\t}\n\t\telse if(typeof this.webSocket !== 'undefined')\n\t\t{\n\t\t\t// Forward the socket events\n\t\t\tthis.webSocket.addEventListener('close', this.eventForwarders.disconnect);\n\t\t\tthis.webSocket.addEventListener('message', this.eventForwarders.wsData);\n\t\t}\n\n\t\t// Indicate that the onConnect function has run.\n\t\tthis.onConnectHasRun = true;\n\n\t\t// Emit the connect event.\n\t\tthis.emit('connect');\n\t}\n\n\t/**\n\t * Clears the disconnect timer if it is still active.\n\t */\n\tprivate clearDisconnectTimerOnTimeout(): void\n\t{\n\t\t// Clear the retry timer if it is still active.\n\t\tif(this.timers.disconnect)\n\t\t{\n\t\t\tclearTimeout(this.timers.disconnect);\n\t\t}\n\t}\n\n\t/**\n\t * Forcibly terminate the connection.\n\t *\n\t * @throws {Error} if no connection was found\n\t */\n\tdisconnect(): void\n\t{\n\t\t// Clear the disconnect timer so that the socket does not try to disconnect again later.\n\t\tthis.clearDisconnectTimerOnTimeout();\n\n\t\t// Handle disconnect based differently depending on socket type.\n\t\tif(this.tcpSocket)\n\t\t{\n\t\t\t// Remove all event forwarders.\n\t\t\tthis.tcpSocket.removeListener('close', this.eventForwarders.disconnect);\n\t\t\tthis.tcpSocket.removeListener('data', this.eventForwarders.tcpData);\n\t\t\tthis.tcpSocket.removeListener('error', this.eventForwarders.tcpError);\n\n\t\t\t// Terminate the connection.\n\t\t\tthis.tcpSocket.destroy();\n\n\t\t\t// Remove the stored socket.\n\t\t\tthis.tcpSocket = undefined;\n\t\t}\n\t\telse if(this.webSocket)\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\t// Remove all event forwarders.\n\t\t\t\tthis.webSocket.removeEventListener('close', this.eventForwarders.disconnect);\n\t\t\t\tthis.webSocket.removeEventListener('message', this.eventForwarders.wsData);\n\t\t\t\tthis.webSocket.removeEventListener('error', this.eventForwarders.wsError);\n\n\t\t\t\t// Gracefully terminate the connection.\n\t\t\t\tthis.webSocket.close();\n\t\t\t}\n\t\t\tcatch(ignored)\n\t\t\t{\n\t\t\t\t// close() will throw an error if the connection has not been established yet.\n\t\t\t\t// We ignore this error, since no similar error gets thrown in the TLS Socket.\n\t\t\t}\n\t\t\tfinally\n\t\t\t{\n\t\t\t\t// Remove the stored socket regardless of any thrown errors.\n\t\t\t\tthis.webSocket = undefined;\n\t\t\t}\n\t\t}\n\n\t\t// Indicate that the onConnect function has not run and it has to be run again.\n\t\tthis.onConnectHasRun = false;\n\n\t\t// Emit a disconnect event\n\t\tthis.emit('disconnect');\n\t}\n\n\t/**\n\t * Write data to the socket\n\t *\n\t * @param {Uint8Array | string} data   Data to be written to the socket\n\t * @param {function} callback          Callback function to be called when the write has completed\n\t *\n\t * @throws {Error} if no connection was found\n\t * @returns true if the message was fully flushed to the socket, false if part of the message\n\t * is queued in the user memory\n\t */\n\twrite(data: Uint8Array | string, callback?: (err?: Error) => void): boolean\n\t{\n\t\tif(this.tcpSocket)\n\t\t{\n\t\t\t// Write data to the TLS Socket and return the status indicating whether the\n\t\t\t// full message was flushed to the socket\n\t\t\treturn this.tcpSocket.write(data, callback);\n\t\t}\n\t\tif(this.webSocket)\n\t\t{\n\t\t\t// Write data to the WebSocket\n\t\t\tthis.webSocket.send(data, callback);\n\n\t\t\t// WebSockets always fit everything in a single request, so we return true\n\t\t\treturn true;\n\t\t}\n\n\t\t// Throw an error if no active connection is found\n\t\tthrow(new Error('Cannot write to socket when there is no active connection'));\n\t}\n\n\t/**\n\t * Force a disconnection if no connection is established after `timeout` milliseconds.\n\t *\n\t * @param {string} host      Host of the connection that timed out\n\t * @param {number} port      Port of the connection that timed out\n\t * @param {number} timeout   Elapsed milliseconds\n\t */\n\tdisconnectOnTimeout(host: string, port: number, timeout: number): void\n\t{\n\t\t// Remove the connect listener.\n\t\tthis.removeListener('connect', this.clearDisconnectTimerOnTimeout);\n\n\t\t// Create a new timeout error.\n\t\tconst timeoutError = { code: 'ETIMEDOUT', message: `Connection to '${host}:${port}' timed out after ${timeout} milliseconds` };\n\n\t\t// Emit an error event so that connect is rejected upstream.\n\t\tthis.emit('error', timeoutError);\n\n\t\t// Forcibly disconnect to clean up the connection on timeout\n\t\tthis.disconnect();\n\t}\n}\n\n// export the socket.\nexport default ElectrumSocket;\n","// Acceptable parameter types for RPC messages\nexport type RPCParameter = string | number | boolean | null;\n\n// The base type for all RPC messages\nexport interface RPCBase\n{\n\tjsonrpc: string;\n}\n\n// An RPC message that sends a notification requiring no response\nexport interface RPCNotification extends RPCBase\n{\n\tmethod: string;\n\tparams?: RPCParameter[];\n}\n\n// An RPC message that sends a request requiring a response\nexport interface RPCRequest extends RPCBase\n{\n\tid: number | null;\n\tmethod: string;\n\tparams?: RPCParameter[];\n}\n\n// An RPC message that returns the response to a successful request\nexport interface RPCStatement extends RPCBase\n{\n\tid: number | null;\n\tresult: string;\n}\n\nexport interface RPCError\n{\n\tcode: number;\n\tmessage: string;\n\tdata?: any;\n}\n\n// An RPC message that returns the error to an unsuccessful request\nexport interface RPCErrorResponse extends RPCBase\n{\n\tid: number | null;\n\terror: RPCError;\n}\n\n// A response to a request is either a statement (successful) or an error (unsuccessful)\nexport type RPCResponse = RPCErrorResponse | RPCStatement;\n\n// RPC messages are notifications, requests, or responses\nexport type RPCMessage = RPCNotification | RPCRequest | RPCResponse;\n\n// Requests and responses can also be sent in batches\nexport type RPCResponseBatch = RPCResponse[];\nexport type RPCRequestBatch = RPCRequest[];\n\nexport const isRPCErrorResponse = function(message: RPCBase): message is RPCErrorResponse\n{\n\treturn 'id' in message && 'error' in message;\n};\n\nexport const isRPCStatement = function(message: RPCBase): message is RPCStatement\n{\n\treturn 'id' in message && 'result' in message;\n};\n\nexport const isRPCNotification = function(message: RPCBase): message is RPCNotification\n{\n\treturn !('id' in message) && 'method' in message;\n};\n\nexport const isRPCRequest = function(message: RPCBase): message is RPCRequest\n{\n\treturn 'id' in message && 'method' in message;\n};\n","import debug from './util';\nimport ElectrumClient from './electrum-client';\nimport { ClusterOrder, ClusterDistribution, ClusterStatus, ClientState, ConnectionStatus } from './enums';\nimport { DefaultParameters } from './constants';\nimport { Mutex } from 'async-mutex';\nimport { EventEmitter } from 'events';\nimport type { RPCParameter, RPCNotification } from './rpc-interfaces';\nimport type { ClientConfig, ResolveFunction, RejectFunction, RequestResponse, TransportScheme } from './interfaces';\n\n/**\n * Triggers when the cluster connects to enough servers to satisfy both the cluster confidence and distribution policies.\n *\n * @event ElectrumCluster#ready\n */\n\n/**\n * Triggers when the cluster loses a connection and can no longer satisfy the cluster distribution policy.\n *\n * @event ElectrumCluster#degraded\n */\n\n/**\n * Triggers when the cluster loses a connection and can no longer satisfy the cluster confidence policy.\n *\n * @event ElectrumCluster#disabled\n */\n\n/**\n * Triggers when the cluster verifies the integrity of remote server sent data that is not a request responses.\n *\n * @event ElectrumCluster#notification\n */\n\n/**\n * High-level electrum client that provides transparent load balancing, confidence checking and/or low-latency polling.\n */\nclass ElectrumCluster extends EventEmitter\n{\n\t// Initialize an empty dictionary of clients in the cluster\n\tclients: { [index: string]: ClientConfig } = {};\n\n\t// Start at 0 connected clients\n\tconnections = 0;\n\n\t// Set up an empty set of notification data.\n\tnotifications: Record<string, Set<string>> = {};\n\n\t// Start the cluster in DISABLED state\n\tstatus = ClusterStatus.DISABLED;\n\n\t// Start counting request IDs at 0\n\trequestCounter = 0;\n\n\t// Initialize an empty dictionary for keeping track of request resolvers\n\trequestPromises: { [index: number]: Promise<Error | RequestResponse>[] } = {};\n\n\t// Lock to prevent concurrency race conditions when sending requests.\n\trequestLock = new Mutex();\n\n\t// Lock to prevent concurrency race conditions when receiving responses.\n\tresponseLock = new Mutex();\n\n\t/**\n\t * @param {string} application    your application name, used to identify to the electrum hosts.\n\t * @param {string} version        protocol version to use with the hosts.\n\t * @param {number} confidence     wait for this number of hosts to provide identical results.\n\t * @param {number} distribution   request information from this number of hosts.\n\t * @param {ClusterOrder} order    select hosts to communicate with in this order.\n\t * @param {number} timeout        how long network delays we will wait for before taking action, in milliseconds.\n\t * @param {number} pingInterval      the time between sending pings to the electrum host, in milliseconds.\n\t * @param {number} reconnectInterval the time between reconnection attempts to the electrum host, in milliseconds.\n\t */\n\tconstructor(\n\t\tpublic application: string,\n\t\tpublic version: string,\n\t\tpublic confidence: number = DefaultParameters.CLUSTER_CONFIDENCE,\n\t\tpublic distribution: number = DefaultParameters.CLUSTER_DISTRIBUTION,\n\t\tpublic order: ClusterOrder = DefaultParameters.CLUSTER_ORDER,\n\t\tpublic timeout: number = DefaultParameters.TIMEOUT,\n\t\tpublic pingInterval: number = DefaultParameters.PING_INTERVAL,\n\t\tpublic reconnectInterval: number = DefaultParameters.RECONNECT,\n\t)\n\t{\n\t\t// Initialize the event emitter.\n\t\tsuper();\n\n\t\t// Write a log message.\n\t\tdebug.cluster(`Initialized empty cluster (${confidence} of ${distribution || 'ALL'})`);\n\n\t\t// Print out a warning if we cannot guarantee consensus for subscription notifications.\n\t\t// Case 1: we don't know how many servers will be used, so warning just to be safe\n\t\t// Case 2: we know the number of servers needed to trust a response is less than 50%.\n\t\tif((distribution === ClusterDistribution.ALL) || (confidence / distribution <= 0.50))\n\t\t{\n\t\t\tdebug.warning(`Subscriptions might return multiple valid responses when confidence (${confidence}) is less than 51% of distribution.`);\n\t\t}\n\t}\n\n\t/**\n\t * Adds a server to the cluster.\n\t *\n\t * @param {string} host              fully qualified domain name or IP number of the host.\n\t * @param {number} port              the TCP network port of the host.\n\t * @param {TransportScheme} scheme   the transport scheme to use for connection\n\t * @param {boolean} autoConnect      flag indicating whether the server should automatically connect (default true)\n\t *\n\t * @throws {Error} if the cluster's version is not a valid version string.\n\t * @returns a promise that resolves when the connection has been initiated.\n\t */\n\tasync addServer(\n\t\thost: string,\n\t\tport: number = DefaultParameters.PORT,\n\t\tscheme: TransportScheme = DefaultParameters.TRANSPORT_SCHEME,\n\t\tautoConnect: boolean = true,\n\t): Promise<void>\n\t{\n\t\t// Set up a new electrum client.\n\t\tconst client = new ElectrumClient(\n\t\t\tthis.application,\n\t\t\tthis.version,\n\t\t\thost,\n\t\t\tport,\n\t\t\tscheme,\n\t\t\tthis.timeout,\n\t\t\tthis.pingInterval,\n\t\t\tthis.reconnectInterval,\n\t\t);\n\n\t\t// Define the client identity to avoid repetition.\n\t\tconst clientIdentity = `${host}:${port}`;\n\n\t\t// Store this client.\n\t\tthis.clients[clientIdentity] =\n\t\t{\n\t\t\tstate: ClientState.UNAVAILABLE,\n\t\t\tconnection: client,\n\t\t};\n\n\t\t/**\n\t\t * Define a helper function to evaluate and log cluster status.\n\t\t *\n\t\t * @fires ElectrumCluster#ready\n\t\t * @fires ElectrumCluster#degraded\n\t\t * @fires ElectrumCluster#disabled\n\t\t */\n\t\tconst updateClusterStatus = (): void =>\n\t\t{\n\t\t\t// Calculate the required distribution, taking into account that distribution to all is represented with 0.\n\t\t\tconst distribution = Math.max(this.confidence, this.distribution);\n\n\t\t\t// Check if we have enough connections to saturate distribution.\n\t\t\tif(this.connections >= distribution)\n\t\t\t{\n\t\t\t\t// If the cluster is not currently considered ready..\n\t\t\t\tif(this.status !== ClusterStatus.READY)\n\t\t\t\t{\n\t\t\t\t\t// Mark the cluster as ready.\n\t\t\t\t\tthis.status = ClusterStatus.READY;\n\n\t\t\t\t\t// Emit the ready signal to indicate the cluster is running in a ready mode.\n\t\t\t\t\tthis.emit('ready');\n\n\t\t\t\t\t// Write a log message with an update on the current cluster status.\n\t\t\t\t\tdebug.cluster(`Cluster status is ready (currently ${this.connections} of ${distribution} connections available.)`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If we still have enough available connections to reach confidence..\n\t\t\telse if(this.connections >= this.confidence)\n\t\t\t{\n\t\t\t\t// If the cluster is not currently considered degraded..\n\t\t\t\tif(this.status !== ClusterStatus.DEGRADED)\n\t\t\t\t{\n\t\t\t\t\t// Mark the cluster as degraded.\n\t\t\t\t\tthis.status = ClusterStatus.DEGRADED;\n\n\t\t\t\t\t// Emit the degraded signal to indicate the cluster is running in a degraded mode.\n\t\t\t\t\tthis.emit('degraded');\n\n\t\t\t\t\t// Write a log message with an update on the current cluster status.\n\t\t\t\t\tdebug.cluster(`Cluster status is degraded (only ${this.connections} of ${distribution} connections available.)`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If we don't have enough connections to reach confidence..\n\t\t\t// .. and the cluster is not currently considered disabled..\n\t\t\telse if(this.status !== ClusterStatus.DISABLED)\n\t\t\t{\n\t\t\t\t// Mark the cluster as disabled.\n\t\t\t\tthis.status = ClusterStatus.DISABLED;\n\n\t\t\t\t// Emit the degraded signal to indicate the cluster is disabled.\n\t\t\t\tthis.emit('disabled');\n\n\t\t\t\t// Write a log message with an update on the current cluster status.\n\t\t\t\tdebug.cluster(`Cluster status is disabled (only ${this.connections} of the ${distribution} connections are available.)`);\n\t\t\t}\n\t\t};\n\n\t\t// Define a function to run when client has connected.\n\t\tconst onConnect = async (): Promise<void> =>\n\t\t{\n\t\t\t// Wrap in a try-catch so we can ignore errors.\n\t\t\ttry\n\t\t\t{\n\t\t\t\t// Check connection status\n\t\t\t\tconst connectionStatus = client.connection.status;\n\n\t\t\t\t// If the connection is fine..\n\t\t\t\tif(connectionStatus === ConnectionStatus.CONNECTED)\n\t\t\t\t{\n\t\t\t\t\t// If this was from an unavailable connection..\n\t\t\t\t\tif(this.clients[clientIdentity].state === ClientState.UNAVAILABLE)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Update connection counter.\n\t\t\t\t\t\tthis.connections += 1;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Set client state to available.\n\t\t\t\t\tthis.clients[clientIdentity].state = ClientState.AVAILABLE;\n\n\t\t\t\t\t// update the cluster status.\n\t\t\t\t\tupdateClusterStatus();\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch(error)\n\t\t\t{\n\t\t\t\t// Do nothing.\n\t\t\t}\n\t\t};\n\n\t\t// Define a function to run when client disconnects.\n\t\tconst onDisconnect = (): void =>\n\t\t{\n\t\t\t// If this was from an established connection..\n\t\t\tif(this.clients[clientIdentity].state === ClientState.AVAILABLE)\n\t\t\t{\n\t\t\t\t// Update connection counter.\n\t\t\t\tthis.connections -= 1;\n\t\t\t}\n\n\t\t\t// Set client state to unavailable.\n\t\t\tthis.clients[clientIdentity].state = ClientState.UNAVAILABLE;\n\n\t\t\t// update the cluster status.\n\t\t\tupdateClusterStatus();\n\t\t};\n\n\t\t// Set up handlers for connection and disconnection.\n\t\tclient.connection.on('connect', onConnect.bind(this));\n\t\tclient.connection.on('disconnect', onDisconnect.bind(this));\n\n\t\t// Set up handler for notification events, that includes the identity of this client so it can be tracked.\n\t\tclient.on('notification', this.handleSubscriptionNotifications.bind(this, clientIdentity));\n\n\t\t// Connect if auto-connect is set to true, returning the connection result.\n\t\tif(autoConnect)\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\t// Set up the connection.\n\t\t\t\tawait client.connect();\n\t\t\t}\n\t\t\tcatch(error)\n\t\t\t{\n\t\t\t\t// Log a message why the connection failed and move on.\n\t\t\t\tdebug.cluster(`Failed to connect with ${host}: ${error}`);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Calls a method on the remote server with the supplied parameters.\n\t *\n\t * @param {string}    method       name of the method to call.\n\t * @param {...string} parameters   one or more parameters for the method.\n\t *\n\t * @throws {Error} if not enough clients are connected\n\t * @throws {Error} if no response is received with sufficient integrity\n\t * @returns a promise that resolves with the result of the method.\n\t */\n\tasync request(method: string, ...parameters: RPCParameter[]): Promise<Error | RequestResponse>\n\t{\n\t\t// Check if the cluster is unable to serve requests.\n\t\tif(this.status === ClusterStatus.DISABLED)\n\t\t{\n\t\t\tthrow(new Error(`Cannot request '${method}' when available clients (${this.connections}) is less than required confidence (${this.confidence}).`));\n\t\t}\n\n\t\t// Lock this request method temporarily.\n\t\tconst unlock = await this.requestLock.acquire();\n\n\t\t// Declare requestId outside of try-catch scope.\n\t\tlet requestId = 0;\n\n\t\t// NOTE: If this async method is called very rapidly, it's theoretically possible that the parts below could interfere.\n\t\ttry\n\t\t{\n\t\t\t// Increase the current request counter.\n\t\t\tthis.requestCounter += 1;\n\n\t\t\t// Copy the request counter so we can work with the copy and know it won't change\n\t\t\t// even if the request counter is raised from concurrent requests.\n\t\t\trequestId = this.requestCounter;\n\t\t}\n\t\tfinally\n\t\t{\n\t\t\t// Unlock this request method now that the concurrency sensitive condition is completed.\n\t\t\tunlock();\n\t\t}\n\n\t\t// Initialize an empty list of request promises.\n\t\tthis.requestPromises[requestId] = [];\n\n\t\t// Extract all available client IDs\n\t\tconst availableClientIDs = Object.keys(this.clients)\n\t\t\t.filter((clientID) => this.clients[clientID].state === ClientState.AVAILABLE);\n\n\t\t// Initialize a sent counter.\n\t\tlet sentCounter = 0;\n\n\t\t// Determine the number of clients we need to send to, taking ClusterDistribution.ALL (=0) into account.\n\t\tlet requiredDistribution = (this.distribution || availableClientIDs.length);\n\n\t\t// If the cluster is in degraded status, we do not have enough available clients to\n\t\t// match distribution, but still enough to reach consensus, so we use the clients we have.\n\t\tif(this.status === ClusterStatus.DEGRADED)\n\t\t{\n\t\t\trequiredDistribution = availableClientIDs.length;\n\t\t}\n\n\t\t// Repeat until we have sent the request to the desired number of clients.\n\t\twhile(sentCounter < requiredDistribution)\n\t\t{\n\t\t\t// Pick an array index according to our ordering strategy.\n\t\t\tlet currentIndex = 0;\n\n\t\t\t// Use a random array index when cluster order is set to RANDOM\n\t\t\tif(this.order === ClusterOrder.RANDOM)\n\t\t\t{\n\t\t\t\tcurrentIndex = Math.floor(Math.random() * availableClientIDs.length);\n\t\t\t}\n\n\t\t\t// Move a client identity from the client list to its own variable.\n\t\t\tconst [ currentClient ] = availableClientIDs.splice(currentIndex, 1);\n\n\t\t\t// Send the request to the client and store the request promise.\n\t\t\tconst requestPromise = this.clients[currentClient].connection.request(method, ...parameters);\n\t\t\tthis.requestPromises[requestId].push(requestPromise);\n\n\t\t\t// Increase the sent counter.\n\t\t\tsentCounter += 1;\n\t\t}\n\n\t\t// Define a function to poll for request responses.\n\t\tconst pollResponse = (resolve: ResolveFunction<RequestResponse>, reject: RejectFunction): void =>\n\t\t{\n\t\t\t// Define a function to resolve request responses based on integrity.\n\t\t\tconst resolveRequest = async (): Promise<void> =>\n\t\t\t{\n\t\t\t\t// Set up an empty set of response data.\n\t\t\t\tconst responseData: { [index: string]: number } = {};\n\n\t\t\t\t// Set up a counter to keep track of how many responses we have checked.\n\t\t\t\tlet checkedResponses = 0;\n\n\t\t\t\t// For each server we issued a request to..\n\t\t\t\tfor(const currentPromise in this.requestPromises[requestId])\n\t\t\t\t{\n\t\t\t\t\t// Initialize a holder for the response in the required scope to use it.\n\t\t\t\t\tlet response;\n\n\t\t\t\t\t// Race the request promise against a pre-resolved request to determine request status.\n\t\t\t\t\ttry\n\t\t\t\t\t{\n\t\t\t\t\t\t// Arrange an array of the current promise and an empty promise such that..\n\t\t\t\t\t\tconst promises = [ this.requestPromises[requestId][currentPromise], Promise.resolve(undefined) ];\n\n\t\t\t\t\t\t// .. we can get the result of the current promise if it is currently resolved, but don't need to wait for it otherwise.\n\t\t\t\t\t\tresponse = await Promise.race(promises);\n\t\t\t\t\t}\n\t\t\t\t\t// Handle case where the request sent resulted in a thrown error / promise rejection, rather then resolving to a response.\n\t\t\t\t\t// Note that in the worst time case, each request can be expected to  eventually throw an error on timeout.\n\t\t\t\t\tcatch(error)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Increase the counter for checked responses.\n\t\t\t\t\t\tcheckedResponses += 1;\n\n\t\t\t\t\t\t// Continue with the next request.\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t// If the promise is settled..\n\t\t\t\t\tif(response !== undefined)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Calculate a unique identifier for this notification data.\n\t\t\t\t\t\tconst responseDataIdentifier = JSON.stringify(response);\n\n\t\t\t\t\t\t// Increase the counter for checked responses.\n\t\t\t\t\t\tcheckedResponses += 1;\n\n\t\t\t\t\t\t// Either set the response data counter or increase it.\n\t\t\t\t\t\tif(responseData[responseDataIdentifier] === undefined)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tresponseData[responseDataIdentifier] = 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tresponseData[responseDataIdentifier] += 1;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Check if this response has enough integrity according to our confidence strategy.\n\t\t\t\t\t\tif(responseData[responseDataIdentifier] === this.confidence)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Write log entry.\n\t\t\t\t\t\t\tdebug.cluster(`Validated response for '${method}' with sufficient integrity (${this.confidence}).`);\n\n\t\t\t\t\t\t\t// Resolve the request with this response.\n\t\t\t\t\t\t\tresolve(response);\n\n\t\t\t\t\t\t\t// Return after resolving since we do not want to continue the execution.\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// If all clients have responded but we failed to reach desired integrity..\n\t\t\t\tif(checkedResponses === this.requestPromises[requestId].length)\n\t\t\t\t{\n\t\t\t\t\t// Reject this request with an error message.\n\t\t\t\t\treject(new Error(`Unable to complete request for '${method}', response failed to reach sufficient integrity (${this.confidence}).`));\n\n\t\t\t\t\t// Return after rejecting since we do not want to continue the execution.\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// If we are not ready, but have not timed out and should wait more..\n\t\t\t\tsetTimeout(resolveRequest, 1000);\n\t\t\t};\n\n\t\t\t// Attempt the initial resolution of the request.\n\t\t\tresolveRequest();\n\t\t};\n\n\t\t// return some kind of promise that resolves when integrity number of clients results match.\n\t\treturn new Promise(pollResponse);\n\t}\n\n\t/**\n\t * Subscribes to the method at the cluster and attaches the callback function to the event feed.\n\t *\n\t * @note the response for the subscription request is issued as a notification event.\n\t *\n\t * @param {string}    method       one of the subscribable methods the server supports.\n\t * @param {...string} parameters   one or more parameters for the method.\n\t *\n\t * @throws {Error} if not enough clients are connected\n\t * @throws {Error} if no response is received with sufficient integrity for the initial request\n\t */\n\tasync subscribe(method: string, ...parameters: RPCParameter[]): Promise<void>\n\t{\n\t\t// Set up event listener for this subscription.\n\t\tfor(const currentClient in this.clients)\n\t\t{\n\t\t\t// Copy the current client for brevity.\n\t\t\tconst client = this.clients[currentClient].connection;\n\n\t\t\ttry\n\t\t\t{\n\t\t\t\t// Send initial subscription request.\n\t\t\t\t// NOTE: This stores and manages the subscription even if the initial request fails.\n\t\t\t\tawait client.subscribe(method, ...parameters);\n\t\t\t}\n\t\t\tcatch(error)\n\t\t\t{\n\t\t\t\t// Do nothing, as this is handled on a best-effort basis and\n\t\t\t\t// not all servers are expected to be ready at all times.\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Unsubscribes to the method at the cluster and removes any callback functions\n\t * when there are no more subscriptions for the method.\n\t *\n\t * @deprecated\n\t *\n\t * @param {string}    method       one of the subscribable methods the server supports.\n\t * @param {...string} parameters   one or more parameters for the method.\n\t *\n\t * @throws {Error} if, for any of the clients, no subscriptions exist for the combination of the provided `method` and `parameters.\n\t */\n\tasync unsubscribe(method: string, ...parameters: RPCParameter[]): Promise<void>\n\t{\n\t\t// Initialize an empty list to track subscription requests.\n\t\tconst unsubscriptionPromises = [];\n\n\t\t// For each client..\n\t\tfor(const currentClient in this.clients)\n\t\t{\n\t\t\t// Store client in variable for brevity\n\t\t\tconst client = this.clients[currentClient].connection;\n\n\t\t\t// unsubscribe this client.\n\t\t\tunsubscriptionPromises.push(client.unsubscribe(method, ...parameters));\n\t\t}\n\n\t\t// Wait for all unsubscription promises to resolve.\n\t\tawait Promise.all(unsubscriptionPromises);\n\t}\n\n\t/**\n\t * Define a callback function to validate server notifications and pass them to the subscribe callback.\n\t *\n\t * @ignore\n\t */\n\tasync handleSubscriptionNotifications(clientIdentity: string, data: RPCNotification): Promise<void>\n\t{\n\t\t// Lock this response method temporarily.\n\t\tconst unlock = await this.responseLock.acquire();\n\n\t\ttry\n\t\t{\n\t\t\t// Calculate a unique identifier for this notification data.\n\t\t\tconst responseDataIdentifier = JSON.stringify(data);\n\n\t\t\t// Create an empty list of clients who have responded to this notification, if necessary.\n\t\t\tif(this.notifications[responseDataIdentifier] === undefined)\n\t\t\t{\n\t\t\t\tthis.notifications[responseDataIdentifier] = new Set();\n\t\t\t}\n\n\t\t\t// Ensure this client is on the list of clients that have provided this specific notification.\n\t\t\tthis.notifications[responseDataIdentifier].add(clientIdentity);\n\n\t\t\t// Check if this notification has enough integrity according to our confidence strategy.\n\t\t\t// NOTE: We check against === instead of >== in order to ensure that we only emit each notification once.\n\t\t\tif(this.notifications[responseDataIdentifier].size === this.confidence)\n\t\t\t{\n\t\t\t\t// Write log entry.\n\t\t\t\tdebug.cluster(`Validated notification for '${data.method}' with sufficient integrity (${this.confidence}).`);\n\n\t\t\t\t// Emit an event for the notification data.\n\t\t\t\tthis.emit('notification', data);\n\n\t\t\t\t// Dismiss the notification data after all nodes are assumed to have sent their notifications.\n\t\t\t\t// NOTE: This is a redundant mechanic to ensure that even if some nodes don't provide this notification, we still clear this data.\n\t\t\t\t// NOTE: This also introduces a race-condition where if a legit identical notification comes in before/during this timeout, it might get silenced.\n\t\t\t\tsetTimeout(this.dismissSubscriptionNotification.bind(this, responseDataIdentifier), this.timeout);\n\t\t\t}\n\n\t\t\t// Check if this notification has been fully handled.\n\t\t\tif(this.notifications[responseDataIdentifier].size === this.distribution)\n\t\t\t{\n\t\t\t\t// Dismiss existing response data as we know all related parties have provided their input.\n\t\t\t\tthis.dismissSubscriptionNotification(responseDataIdentifier);\n\t\t\t}\n\t\t}\n\t\tfinally\n\t\t{\n\t\t\t// Unlock the response method so it can handle the next set of data.\n\t\t\tunlock();\n\t\t}\n\t}\n\n\t/**\n\t * Forgets/Removes notification data for a specific notification.\n\t *\n\t * This is required in order to allow future identical notifications to be properly processed and emitted.\n\t */\n\tasync dismissSubscriptionNotification(responseDataIdentifier): Promise<void>\n\t{\n\t\tdelete this.notifications[responseDataIdentifier];\n\t}\n\n\t/**\n\t * Provides a method to check or wait for the cluster to become ready.\n\t *\n\t * @returns a promise that resolves when the required servers are available.\n\t */\n\tasync ready(): Promise<boolean>\n\t{\n\t\t// Store the current timestamp.\n\t\tconst readyTimestamp = Date.now();\n\n\t\t// Define a function to poll for availability of the cluster.\n\t\tconst availabilityPoller = (resolve: ResolveFunction<boolean>): void =>\n\t\t{\n\t\t\t// Define a function to check if the cluster is ready to be used.\n\t\t\tconst connectionAvailabilityVerifier = (): void =>\n\t\t\t{\n\t\t\t\t// Check if the cluster is active..\n\t\t\t\tif(this.status === ClusterStatus.READY)\n\t\t\t\t{\n\t\t\t\t\t// Resolve with true to indicate that the cluster is ready to use.\n\t\t\t\t\tresolve(true);\n\n\t\t\t\t\t// Return after resolving since we do not want to continue the execution.\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Calculate how long we have waited, in milliseconds.\n\t\t\t\tconst timeWaited = (Date.now() - readyTimestamp);\n\n\t\t\t\t// Check if we have waited longer than our timeout setting.\n\t\t\t\tif(timeWaited > this.timeout)\n\t\t\t\t{\n\t\t\t\t\t// Resolve with false to indicate that we did not get ready in time.\n\t\t\t\t\tresolve(false);\n\n\t\t\t\t\t// Return after resolving since we do not want to continue the execution.\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// If we are not ready, but have not timed out and should wait more..\n\t\t\t\tsetTimeout(connectionAvailabilityVerifier, 50);\n\t\t\t};\n\n\t\t\t// Run the initial verification.\n\t\t\tconnectionAvailabilityVerifier();\n\t\t};\n\n\t\t// Return a promise that resolves when the available clients is sufficient.\n\t\treturn new Promise(availabilityPoller);\n\t}\n\n\t/**\n\t * Connects all servers from the cluster and attaches event listeners and handlers\n\t * for all underlying clients and connections.\n\t *\n\t * @throws {Error} if the cluster's version is not a valid version string.\n\t */\n\tasync startup(): Promise<void[]>\n\t{\n\t\t// Write a log message.\n\t\tdebug.cluster('Starting up cluster.');\n\n\t\t// Keep track of all connections\n\t\tconst connections = [];\n\n\t\t// Loop over all clients and reconnect them if they're disconnected\n\t\tfor(const clientKey in this.clients)\n\t\t{\n\t\t\t// Retrieve connection information for the client\n\t\t\tconst { host, port, scheme } = this.clients[clientKey].connection.connection;\n\n\t\t\t// Only connect currently unavailable/disconnected clients\n\t\t\tif(this.clients[clientKey].state === ClientState.AVAILABLE)\n\t\t\t{\n\t\t\t\t// Warn when a server is already connected when calling startup()\n\t\t\t\tdebug.warning(`Called startup(), but server ${host}:${port} is already connected`);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Call the addServer() function with the existing connection data\n\t\t\t\t// This effectively reconnects the server and re-instates all event listeners\n\t\t\t\tconnections.push(this.addServer(host, port, scheme));\n\t\t\t}\n\t\t}\n\n\t\t// Await all connections\n\t\treturn Promise.all(connections);\n\t}\n\n\t/**\n\t * Disconnects all servers from the cluster. Removes all event listeners and\n\t * handlers from all underlying clients and connections. This includes all\n\t * active subscriptions, unless retainSubscriptions is set to true.\n\t *\n\t * @param {boolean} retainSubscriptions   retain subscription data so they will be restored on reconnection.\n\t *\n\t * @returns a list with the disconnection result for every client\n\t */\n\tasync shutdown(retainSubscriptions: boolean = false): Promise<boolean[]>\n\t{\n\t\t// Write a log message.\n\t\tdebug.cluster('Shutting down cluster.');\n\n\t\t// Set up a list of disconnections to wait for.\n\t\tconst disconnections: Promise<boolean>[] = [];\n\n\t\tconst disconnectResolver = (resolve: ResolveFunction<boolean[]>): void =>\n\t\t{\n\t\t\t// Resolve once the cluster is marked as disabled\n\t\t\tthis.once('disabled', () => resolve(Promise.all(disconnections)));\n\n\t\t\t// For each client in this cluster..\n\t\t\tfor(const clientIndex in this.clients)\n\t\t\t{\n\t\t\t\t// Force disconnection regardless of current status.\n\t\t\t\tdisconnections.push(this.clients[clientIndex].connection.disconnect(true, retainSubscriptions));\n\t\t\t}\n\t\t};\n\n\t\t// Return a list of booleans indicating disconnections from all clients\n\t\treturn new Promise<boolean[]>(disconnectResolver);\n\t}\n}\n\n// Export the cluster.\nexport default ElectrumCluster;\n"],"names":[],"version":3,"file":"index.cjs.map"}