@electrum-cash/tcp-socket 1.1.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -44,7 +44,10 @@ var ElectrumTcpSocket = class extends EventEmitter {
44
44
  * Connect to host:port using the specified transport
45
45
  */
46
46
  connect() {
47
- if (this.tcpSocket) throw /* @__PURE__ */ new Error("Cannot initiate a new socket connection when an existing connection exists");
47
+ if (this.tcpSocket) {
48
+ debug.warning("Ignoring connect() request due to connection already existing.");
49
+ return;
50
+ }
48
51
  this.disconnectTimer = setTimeout(() => this.disconnectOnTimeout(), this.timeout);
49
52
  this.once("connected", this.clearDisconnectTimerOnTimeout);
50
53
  const connectionType = this.encrypted ? "an encrypted TCP Socket" : "a TCP Socket";
@@ -108,6 +111,10 @@ var ElectrumTcpSocket = class extends EventEmitter {
108
111
  * @throws {Error} if no connection was found
109
112
  */
110
113
  disconnect() {
114
+ if (!this.tcpSocket) {
115
+ debug.warning("Ignoring disconnect() request due to connection already existing.");
116
+ return;
117
+ }
111
118
  this.clearDisconnectTimerOnTimeout();
112
119
  if (this.tcpSocket) {
113
120
  this.tcpSocket.removeListener("close", this.eventForwarders.disconnect);
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../source/constants.ts","../source/tcp.ts"],"sourcesContent":["// Export a default timeout value of 30 seconds.\nexport const defaultTimeout = 30 * 1000;\n","import * as tls from 'tls';\nimport * as net from 'net';\nimport debug from '@electrum-cash/debug-logs';\nimport { defaultTimeout } from './constants.ts';\n\nimport { EventEmitter } from 'eventemitter3';\nimport type { ElectrumSocket, ElectrumSocketEvents } from '@electrum-cash/network';\n\n/**\n * Connection options used with TLS connections.\n * @ignore\n */\ninterface ConnectionOptions\n{\n\trejectUnauthorized?: boolean;\n\tserverName?: string;\n}\n\n/**\n * TCP Socket used when communicating with Electrum servers.\n */\nexport class ElectrumTcpSocket extends EventEmitter<ElectrumSocketEvents> implements ElectrumSocket\n{\n\t// Declare an empty TCP socket.\n\tprivate tcpSocket: net.Socket;\n\n\t// Used to disconnect after some time if initial connection is too slow.\n\tprivate disconnectTimer?: number;\n\n\t// Initialize boolean that indicates whether the onConnect function has run (initialize to false).\n\tprivate onConnectHasRun = false;\n\n\t// Initialize event forwarding functions.\n\tprivate eventForwarders =\n\t{\n\t\tdisconnect: () => this.emit('disconnected'),\n\t\ttcpData: (data: string) => this.emit('data', data),\n\t};\n\n\t/**\n\t * Creates a socket configured with connection information for a given Electrum server.\n\t *\n\t * @param host Fully qualified domain name or IP address of the host\n\t * @param port Network port for the host to connect to, defaults to the standard TLS port\n\t * @param encrypted If false, uses an unencrypted connection instead of the default on TLS\n\t * @param timeout If no connection is established after `timeout` ms, the connection is terminated\n\t */\n\tpublic constructor\n\t(\n\t\tpublic host: string,\n\t\tpublic port: number = 50002,\n\t\tpublic encrypted: boolean = true,\n\t\tpublic timeout: number = defaultTimeout,\n\t)\n\t{\n\t\t// Initialize the event emitter.\n\t\tsuper();\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 * Connect to host:port using the specified transport\n\t */\n\tpublic connect(): void\n\t{\n\t\t// Check that no existing socket exists before initiating a new connection.\n\t\tif(this.tcpSocket)\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.disconnectTimer = setTimeout(() => this.disconnectOnTimeout(), this.timeout) as unknown as number;\n\n\t\t// Remove the timer if a connection is successfully established\n\t\tthis.once('connected', this.clearDisconnectTimerOnTimeout);\n\n\t\t// Set a named connection type for logging purposes.\n\t\tconst connectionType = (this.encrypted ? 'an encrypted TCP Socket' : 'a TCP Socket');\n\n\t\t// Log that we are trying to establish a connection.\n\t\tdebug.network(`Initiating ${connectionType} connection to '${this.host}:${this.port}'.`);\n\n\t\tif(this.encrypted)\n\t\t{\n\t\t\t// Initialize connection options.\n\t\t\tconst connectionOptions: ConnectionOptions = { rejectUnauthorized: false };\n\n\t\t\t// If the hostname is not an IP address..\n\t\t\tif(!net.isIP(this.host))\n\t\t\t{\n\t\t\t\t// Set the servername option which enables support for SNI.\n\t\t\t\t// NOTE: SNI enables a server that hosts multiple domains to provide the appropriate TLS certificate.\n\t\t\t\tconnectionOptions.serverName = this.host;\n\t\t\t}\n\n\t\t\t// Initialize the socket (allowing self-signed certificates).\n\t\t\tthis.tcpSocket = tls.connect(this.port, this.host, connectionOptions);\n\n\t\t\t// Add a 'secureConnect' listener that checks the authorization status of\n\t\t\t// the socket, and logs a warning when it uses a self signed certificate.\n\t\t\tthis.tcpSocket.once('secureConnect', () =>\n\t\t\t{\n\t\t\t\t// Cannot happen, since this event callback *only* exists on TLSSocket\n\t\t\t\tif(!(this.tcpSocket instanceof tls.TLSSocket)) return;\n\n\t\t\t\t// Force cast authorizationError from Error to string (through unknown)\n\t\t\t\t// because it is incorrectly typed as an Error\n\t\t\t\tconst authorizationError = (this.tcpSocket.authorizationError as unknown) as string;\n\t\t\t\tif(authorizationError === 'DEPTH_ZERO_SELF_SIGNED_CERT')\n\t\t\t\t{\n\t\t\t\t\tdebug.warning(`Connection to ${this.host}:${this.port} uses a self-signed certificate`);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Trigger successful connection events.\n\t\t\tthis.tcpSocket.on('secureConnect', this.onConnect.bind(this));\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Initialize the socket.\n\t\t\tthis.tcpSocket = net.connect({ host: this.host, port: this.port });\n\n\t\t\t// Trigger successful connection events.\n\t\t\tthis.tcpSocket.on('connect', this.onConnect.bind(this));\n\t\t}\n\n\t\t// Configure encoding.\n\t\tthis.tcpSocket.setEncoding('utf8');\n\n\t\t// Enable persistent connections.\n\t\t// NOTE: This will send a non-data message 0.25 second after last activity.\n\t\t// After 10 consecutive such messages with no response, the connection will be cut.\n\t\tthis.tcpSocket.setKeepAlive(true, 250);\n\n\t\t// Disable buffering of outgoing data.\n\t\tthis.tcpSocket.setNoDelay(true);\n\n\t\t// Forward the encountered errors.\n\t\tthis.tcpSocket.on('error', this.onError);\n\t}\n\n\t/**\n\t * Internal error handler that helps provide context to some types of errors before passing them up through the stack.\n\t */\n\tprivate onError(error: NodeJS.ErrnoException): void\n\t{\n\t\tswitch(error.code)\n\t\t{\n\t\t\t// If the DNS lookup failed.\n\t\t\tcase 'EAI_AGAIN':\n\t\t\t\tthis.emit('error', new Error(`Failed to look up DNS records for '${this.host}'.`));\n\t\t\t\tbreak;\n\n\t\t\t// If the connection timed out..\n\t\t\tcase 'ETIMEDOUT':\n\t\t\t\tthis.emit('error', error);\n\t\t\t\tbreak;\n\n\t\t\t// For unknown errors..\n\t\t\tdefault:\n\t\t\t\tthis.emit('error', error);\n\t\t}\n\t}\n\n\t/**\n\t * Sets up forwarding of events related to the connection.\n\t */\n\tprivate onConnect(): 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// Set a named connection type for logging purposes.\n\t\tconst connectionType = (this.encrypted ? 'an encrypted TCP Socket' : 'a TCP Socket');\n\n\t\t// Log that the connection has been established.\n\t\tdebug.network(`Established ${connectionType} connection with '${this.host}:${this.port}'.`);\n\n\t\t// Forward the socket events\n\t\tthis.tcpSocket.addListener('close', this.eventForwarders.disconnect);\n\t\tthis.tcpSocket.addListener('data', this.eventForwarders.tcpData);\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('connected');\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.disconnectTimer)\n\t\t{\n\t\t\tclearTimeout(this.disconnectTimer);\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\tpublic disconnect(): 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\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\n\t\t\t// Also remove the error forwarder, to prevent the following destroy call from generating error messages.\n\t\t\tthis.tcpSocket.removeListener('error', this.onError);\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\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('disconnected');\n\t}\n\n\t/**\n\t * Write data to the socket\n\t *\n\t * @param data Data to be written to the socket\n\t * @param 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\tpublic write(data: Uint8Array | string, callback?: (err?: Error) => void): boolean\n\t{\n\t\t// Throw an error if no active connection is found\n\t\tif(!this.tcpSocket)\n\t\t{\n\t\t\tthrow(new Error('Cannot write to socket when there is no active connection'));\n\t\t}\n\n\t\t// Write data to the TLS Socket and return the status indicating\n\t\t// whether the full message was flushed to the socket\n\t\treturn this.tcpSocket.write(data, callback);\n\t}\n\n\t/**\n\t * Force a disconnection if no connection is established after `timeout` milliseconds.\n\t */\n\tprivate disconnectOnTimeout(): void\n\t{\n\t\t// Remove the connect listener.\n\t\tthis.removeListener('connected', this.clearDisconnectTimerOnTimeout);\n\n\t\t// Emit an error event so that connect is rejected upstream.\n\t\tthis.emit('error', new Error(`Connection to '${this.host}:${this.port}' timed out after ${this.timeout} milliseconds`));\n\n\t\t// Forcibly disconnect to clean up the connection on timeout\n\t\tthis.disconnect();\n\t}\n\n\t// Add magic glue that makes typedoc happy so that we can have the events listed on the class.\n\tpublic readonly connected: [];\n\tpublic readonly disconnected: [];\n\tpublic readonly data: [ string ];\n\tpublic readonly error: [ Error ];\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../source/constants.ts","../source/tcp.ts"],"sourcesContent":["// Export a default timeout value of 30 seconds.\nexport const defaultTimeout = 30 * 1000;\n","import * as tls from 'tls';\nimport * as net from 'net';\nimport debug from '@electrum-cash/debug-logs';\nimport { defaultTimeout } from './constants.ts';\n\nimport { EventEmitter } from 'eventemitter3';\nimport type { ElectrumSocket, ElectrumSocketEvents } from '@electrum-cash/network';\n\n/**\n * Connection options used with TLS connections.\n * @ignore\n */\ninterface ConnectionOptions\n{\n\trejectUnauthorized?: boolean;\n\tserverName?: string;\n}\n\n/**\n * TCP Socket used when communicating with Electrum servers.\n */\nexport class ElectrumTcpSocket extends EventEmitter<ElectrumSocketEvents> implements ElectrumSocket\n{\n\t// Declare an empty TCP socket.\n\tprivate tcpSocket: net.Socket;\n\n\t// Used to disconnect after some time if initial connection is too slow.\n\tprivate disconnectTimer?: number;\n\n\t// Initialize boolean that indicates whether the onConnect function has run (initialize to false).\n\tprivate onConnectHasRun = false;\n\n\t// Initialize event forwarding functions.\n\tprivate eventForwarders =\n\t{\n\t\tdisconnect: () => this.emit('disconnected'),\n\t\ttcpData: (data: string) => this.emit('data', data),\n\t};\n\n\t/**\n\t * Creates a socket configured with connection information for a given Electrum server.\n\t *\n\t * @param host Fully qualified domain name or IP address of the host\n\t * @param port Network port for the host to connect to, defaults to the standard TLS port\n\t * @param encrypted If false, uses an unencrypted connection instead of the default on TLS\n\t * @param timeout If no connection is established after `timeout` ms, the connection is terminated\n\t */\n\tpublic constructor\n\t(\n\t\tpublic host: string,\n\t\tpublic port: number = 50002,\n\t\tpublic encrypted: boolean = true,\n\t\tpublic timeout: number = defaultTimeout,\n\t)\n\t{\n\t\t// Initialize the event emitter.\n\t\tsuper();\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 * Connect to host:port using the specified transport\n\t */\n\tpublic connect(): void\n\t{\n\t\t// Do nothing if we are already connected.\n\t\tif(this.tcpSocket)\n\t\t{\n\t\t\tdebug.warning('Ignoring connect() request due to connection already existing.');\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Set a timer to force disconnect after `timeout` seconds\n\t\tthis.disconnectTimer = setTimeout(() => this.disconnectOnTimeout(), this.timeout) as unknown as number;\n\n\t\t// Remove the timer if a connection is successfully established\n\t\tthis.once('connected', this.clearDisconnectTimerOnTimeout);\n\n\t\t// Set a named connection type for logging purposes.\n\t\tconst connectionType = (this.encrypted ? 'an encrypted TCP Socket' : 'a TCP Socket');\n\n\t\t// Log that we are trying to establish a connection.\n\t\tdebug.network(`Initiating ${connectionType} connection to '${this.host}:${this.port}'.`);\n\n\t\tif(this.encrypted)\n\t\t{\n\t\t\t// Initialize connection options.\n\t\t\tconst connectionOptions: ConnectionOptions = { rejectUnauthorized: false };\n\n\t\t\t// If the hostname is not an IP address..\n\t\t\tif(!net.isIP(this.host))\n\t\t\t{\n\t\t\t\t// Set the servername option which enables support for SNI.\n\t\t\t\t// NOTE: SNI enables a server that hosts multiple domains to provide the appropriate TLS certificate.\n\t\t\t\tconnectionOptions.serverName = this.host;\n\t\t\t}\n\n\t\t\t// Initialize the socket (allowing self-signed certificates).\n\t\t\tthis.tcpSocket = tls.connect(this.port, this.host, connectionOptions);\n\n\t\t\t// Add a 'secureConnect' listener that checks the authorization status of\n\t\t\t// the socket, and logs a warning when it uses a self signed certificate.\n\t\t\tthis.tcpSocket.once('secureConnect', () =>\n\t\t\t{\n\t\t\t\t// Cannot happen, since this event callback *only* exists on TLSSocket\n\t\t\t\tif(!(this.tcpSocket instanceof tls.TLSSocket)) return;\n\n\t\t\t\t// Force cast authorizationError from Error to string (through unknown)\n\t\t\t\t// because it is incorrectly typed as an Error\n\t\t\t\tconst authorizationError = (this.tcpSocket.authorizationError as unknown) as string;\n\t\t\t\tif(authorizationError === 'DEPTH_ZERO_SELF_SIGNED_CERT')\n\t\t\t\t{\n\t\t\t\t\tdebug.warning(`Connection to ${this.host}:${this.port} uses a self-signed certificate`);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Trigger successful connection events.\n\t\t\tthis.tcpSocket.on('secureConnect', this.onConnect.bind(this));\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Initialize the socket.\n\t\t\tthis.tcpSocket = net.connect({ host: this.host, port: this.port });\n\n\t\t\t// Trigger successful connection events.\n\t\t\tthis.tcpSocket.on('connect', this.onConnect.bind(this));\n\t\t}\n\n\t\t// Configure encoding.\n\t\tthis.tcpSocket.setEncoding('utf8');\n\n\t\t// Enable persistent connections.\n\t\t// NOTE: This will send a non-data message 0.25 second after last activity.\n\t\t// After 10 consecutive such messages with no response, the connection will be cut.\n\t\tthis.tcpSocket.setKeepAlive(true, 250);\n\n\t\t// Disable buffering of outgoing data.\n\t\tthis.tcpSocket.setNoDelay(true);\n\n\t\t// Forward the encountered errors.\n\t\tthis.tcpSocket.on('error', this.onError);\n\t}\n\n\t/**\n\t * Internal error handler that helps provide context to some types of errors before passing them up through the stack.\n\t */\n\tprivate onError(error: NodeJS.ErrnoException): void\n\t{\n\t\tswitch(error.code)\n\t\t{\n\t\t\t// If the DNS lookup failed.\n\t\t\tcase 'EAI_AGAIN':\n\t\t\t\tthis.emit('error', new Error(`Failed to look up DNS records for '${this.host}'.`));\n\t\t\t\tbreak;\n\n\t\t\t// If the connection timed out..\n\t\t\tcase 'ETIMEDOUT':\n\t\t\t\tthis.emit('error', error);\n\t\t\t\tbreak;\n\n\t\t\t// For unknown errors..\n\t\t\tdefault:\n\t\t\t\tthis.emit('error', error);\n\t\t}\n\t}\n\n\t/**\n\t * Sets up forwarding of events related to the connection.\n\t */\n\tprivate onConnect(): 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// Set a named connection type for logging purposes.\n\t\tconst connectionType = (this.encrypted ? 'an encrypted TCP Socket' : 'a TCP Socket');\n\n\t\t// Log that the connection has been established.\n\t\tdebug.network(`Established ${connectionType} connection with '${this.host}:${this.port}'.`);\n\n\t\t// Forward the socket events\n\t\tthis.tcpSocket.addListener('close', this.eventForwarders.disconnect);\n\t\tthis.tcpSocket.addListener('data', this.eventForwarders.tcpData);\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('connected');\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.disconnectTimer)\n\t\t{\n\t\t\tclearTimeout(this.disconnectTimer);\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\tpublic disconnect(): void\n\t{\n\t\t// Do nothing if we are already disconnected.\n\t\tif(!this.tcpSocket)\n\t\t{\n\t\t\tdebug.warning('Ignoring disconnect() request due to connection already existing.');\n\n\t\t\treturn;\n\t\t}\n\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\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\n\t\t\t// Also remove the error forwarder, to prevent the following destroy call from generating error messages.\n\t\t\tthis.tcpSocket.removeListener('error', this.onError);\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\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('disconnected');\n\t}\n\n\t/**\n\t * Write data to the socket\n\t *\n\t * @param data Data to be written to the socket\n\t * @param 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\tpublic write(data: Uint8Array | string, callback?: (err?: Error) => void): boolean\n\t{\n\t\t// Throw an error if no active connection is found\n\t\tif(!this.tcpSocket)\n\t\t{\n\t\t\tthrow(new Error('Cannot write to socket when there is no active connection'));\n\t\t}\n\n\t\t// Write data to the TLS Socket and return the status indicating\n\t\t// whether the full message was flushed to the socket\n\t\treturn this.tcpSocket.write(data, callback);\n\t}\n\n\t/**\n\t * Force a disconnection if no connection is established after `timeout` milliseconds.\n\t */\n\tprivate disconnectOnTimeout(): void\n\t{\n\t\t// Remove the connect listener.\n\t\tthis.removeListener('connected', this.clearDisconnectTimerOnTimeout);\n\n\t\t// Emit an error event so that connect is rejected upstream.\n\t\tthis.emit('error', new Error(`Connection to '${this.host}:${this.port}' timed out after ${this.timeout} milliseconds`));\n\n\t\t// Forcibly disconnect to clean up the connection on timeout\n\t\tthis.disconnect();\n\t}\n\n\t// Add magic glue that makes typedoc happy so that we can have the events listed on the class.\n\tpublic readonly connected: [];\n\tpublic readonly disconnected: [];\n\tpublic readonly data: [ string ];\n\tpublic readonly error: [ Error ];\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@electrum-cash/tcp-socket",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "@electrum-cash/web-socket implements the ElectrumSocket interface using nodejs tcp sockets.",
5
5
  "keywords": [
6
6
  "electrum",
@@ -32,7 +32,7 @@
32
32
  "build": "tsdown --clean --sourcemap source/index.ts",
33
33
  "analyze": "tsdown --clean --no-fixed-extension --sourcemap source/index.ts && esbuild-analyzer dist/",
34
34
  "docs": "typedoc --hideGenerator --categorizeByGroup",
35
- "lint": "eslint",
35
+ "style": "eslint",
36
36
  "syntax": "tsc --noEmit",
37
37
  "spellcheck": "cspell 'source/**' 'test/**' 'examples/**'",
38
38
  "test": "vitest --dir test/ --test-timeout=15000 --passWithNoTests --run --coverage"