@electrum-cash/tcp-socket 1.0.0 → 1.1.0-development.12711590191

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.
@@ -0,0 +1,152 @@
1
+ import { EventEmitter } from "eventemitter3";
2
+
3
+ //#region node_modules/@electrum-cash/network/dist/index.d.ts
4
+ /**
5
+ * List of events emitted by the ElectrumSocket.
6
+ * @event
7
+ * @ignore
8
+ */
9
+ interface ElectrumSocketEvents {
10
+ /**
11
+ * Emitted when data has been received over the socket.
12
+ * @eventProperty
13
+ */
14
+ 'data': [string];
15
+ /**
16
+ * Emitted when a socket connects.
17
+ * @eventProperty
18
+ */
19
+ 'connected': [];
20
+ /**
21
+ * Emitted when a socket disconnects.
22
+ * @eventProperty
23
+ */
24
+ 'disconnected': [];
25
+ /**
26
+ * Emitted when the socket has failed in some way.
27
+ * @eventProperty
28
+ */
29
+ 'error': [Error];
30
+ }
31
+ /**
32
+ * Abstract socket used when communicating with Electrum servers.
33
+ */
34
+ interface ElectrumSocket extends EventEmitter<ElectrumSocketEvents>, ElectrumSocketEvents {
35
+ /**
36
+ * Utility function to provide a human accessible host identifier.
37
+ */
38
+ get hostIdentifier(): string;
39
+ /**
40
+ * Fully qualified domain name or IP address of the host
41
+ */
42
+ host: string;
43
+ /**
44
+ * Network port for the host to connect to, defaults to the standard TLS port
45
+ */
46
+ port: number;
47
+ /**
48
+ * If false, uses an unencrypted connection instead of the default on TLS
49
+ */
50
+ encrypted: boolean;
51
+ /**
52
+ * If no connection is established after `timeout` ms, the connection is terminated
53
+ */
54
+ timeout: number;
55
+ /**
56
+ * Connects to an Electrum server using the socket.
57
+ */
58
+ connect(): void;
59
+ /**
60
+ * Disconnects from the Electrum server from the socket.
61
+ */
62
+ disconnect(): void;
63
+ /**
64
+ * Write data to the Electrum server on the socket.
65
+ *
66
+ * @param data - Data to be written to the socket
67
+ * @param callback - Callback function to be called when the write has completed
68
+ */
69
+ write(data: Uint8Array | string, callback?: (err?: Error) => void): boolean;
70
+ }
71
+ //#endregion
72
+ //#region source/tcp.d.ts
73
+ /**
74
+ * TCP Socket used when communicating with Electrum servers.
75
+ */
76
+ declare class ElectrumTcpSocket extends EventEmitter<ElectrumSocketEvents> implements ElectrumSocket {
77
+ host: string;
78
+ port: number;
79
+ encrypted: boolean;
80
+ timeout: number;
81
+ private tcpSocket;
82
+ private disconnectTimer?;
83
+ private onConnectHasRun;
84
+ private eventForwarders;
85
+ /**
86
+ * Creates a socket configured with connection information for a given Electrum server.
87
+ *
88
+ * @param host Fully qualified domain name or IP address of the host
89
+ * @param port Network port for the host to connect to, defaults to the standard TLS port
90
+ * @param encrypted If false, uses an unencrypted connection instead of the default on TLS
91
+ * @param timeout If no connection is established after `timeout` ms, the connection is terminated
92
+ */
93
+ constructor(host: string, port?: number, encrypted?: boolean, timeout?: number);
94
+ /**
95
+ * Returns a string for the host identifier for usage in debug messages.
96
+ */
97
+ get hostIdentifier(): string;
98
+ /**
99
+ * Connect to host:port using the specified transport
100
+ */
101
+ connect(): void;
102
+ /**
103
+ * Internal error handler that helps provide context to some types of errors before passing them up through the stack.
104
+ */
105
+ private onError;
106
+ /**
107
+ * Sets up forwarding of events related to the connection.
108
+ */
109
+ private onConnect;
110
+ /**
111
+ * Clears the disconnect timer if it is still active.
112
+ */
113
+ private clearDisconnectTimerOnTimeout;
114
+ /**
115
+ * Forcibly terminate the connection.
116
+ *
117
+ * @throws {Error} if no connection was found
118
+ */
119
+ disconnect(): void;
120
+ /**
121
+ * Write data to the socket
122
+ *
123
+ * @param data Data to be written to the socket
124
+ * @param callback Callback function to be called when the write has completed
125
+ *
126
+ * @throws {Error} if no connection was found
127
+ * @returns true if the message was fully flushed to the socket, false if part of the message
128
+ * is queued in the user memory
129
+ */
130
+ write(data: Uint8Array | string, callback?: (err?: Error) => void): boolean;
131
+ /**
132
+ * Force a disconnection if no connection is established after `timeout` milliseconds.
133
+ */
134
+ private disconnectOnTimeout;
135
+ readonly connected: [];
136
+ readonly disconnected: [];
137
+ readonly data: [string];
138
+ readonly error: [Error];
139
+ }
140
+ //#endregion
141
+ //#region source/interfaces.d.ts
142
+ /**
143
+ * Connection options used with TLS connections.
144
+ * @ignore
145
+ */
146
+ interface ConnectionOptions {
147
+ rejectUnauthorized?: boolean;
148
+ serverName?: string;
149
+ }
150
+ //#endregion
151
+ export { ConnectionOptions, ElectrumTcpSocket };
152
+ //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs CHANGED
@@ -1,221 +1,152 @@
1
- import {connect as $dvphU$connect, TLSSocket as $dvphU$TLSSocket} from "tls";
2
- import {isIP as $dvphU$isIP, connect as $dvphU$connect1} from "net";
3
- import $dvphU$electrumcashdebuglogs from "@electrum-cash/debug-logs";
4
- import {EventEmitter as $dvphU$EventEmitter} from "eventemitter3";
1
+ import * as tls from "tls";
2
+ import * as net from "net";
3
+ import debug from "@electrum-cash/debug-logs";
4
+ import { EventEmitter } from "eventemitter3";
5
5
 
6
+ //#region source/constants.ts
7
+ const defaultTimeout = 30 * 1e3;
6
8
 
7
- function $parcel$export(e, n, v, s) {
8
- Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});
9
- }
10
- var $bcb32cbeddeae7b2$exports = {};
11
-
12
- $parcel$export($bcb32cbeddeae7b2$exports, "ElectrumTcpSocket", () => $bcb32cbeddeae7b2$export$22c0ca2c816c3e08);
13
-
14
-
15
-
16
- // Export a default timeout value of 30 seconds.
17
- const $d801b1f9b7fc3074$export$1bddf2b96e25d075 = 30000;
18
-
19
-
20
-
21
- class $bcb32cbeddeae7b2$export$22c0ca2c816c3e08 extends (0, $dvphU$EventEmitter) {
22
- host;
23
- port;
24
- encrypted;
25
- timeout;
26
- // Declare an empty TCP socket.
27
- tcpSocket;
28
- // Used to disconnect after some time if initial connection is too slow.
29
- disconnectTimer;
30
- // Initialize boolean that indicates whether the onConnect function has run (initialize to false).
31
- onConnectHasRun;
32
- // Initialize event forwarding functions.
33
- eventForwarders;
34
- /**
35
- * Creates a socket configured with connection information for a given Electrum server.
36
- *
37
- * @param host Fully qualified domain name or IP address of the host
38
- * @param port Network port for the host to connect to, defaults to the standard TLS port
39
- * @param encrypted If false, uses an unencrypted connection instead of the default on TLS
40
- * @param timeout If no connection is established after `timeout` ms, the connection is terminated
41
- */ constructor(host, port = 50002, encrypted = true, timeout = (0, $d801b1f9b7fc3074$export$1bddf2b96e25d075)){
42
- // Initialize the event emitter.
43
- super();
44
- this.host = host;
45
- this.port = port;
46
- this.encrypted = encrypted;
47
- this.timeout = timeout;
48
- this.onConnectHasRun = false;
49
- this.eventForwarders = {
50
- disconnect: ()=>this.emit("disconnected"),
51
- tcpData: (data)=>this.emit("data", data)
52
- };
53
- }
54
- /**
55
- * Returns a string for the host identifier for usage in debug messages.
56
- */ get hostIdentifier() {
57
- return `${this.host}:${this.port}`;
58
- }
59
- /**
60
- * Connect to host:port using the specified transport
61
- */ connect() {
62
- // Check that no existing socket exists before initiating a new connection.
63
- if (this.tcpSocket) throw new Error("Cannot initiate a new socket connection when an existing connection exists");
64
- // Set a timer to force disconnect after `timeout` seconds
65
- this.disconnectTimer = setTimeout(()=>this.disconnectOnTimeout(), this.timeout);
66
- // Remove the timer if a connection is successfully established
67
- this.once("connected", this.clearDisconnectTimerOnTimeout);
68
- // Set a named connection type for logging purposes.
69
- const connectionType = this.encrypted ? "an encrypted TCP Socket" : "a TCP Socket";
70
- // Log that we are trying to establish a connection.
71
- (0, $dvphU$electrumcashdebuglogs).network(`Initiating ${connectionType} connection to '${this.host}:${this.port}'.`);
72
- if (this.encrypted) {
73
- // Initialize connection options.
74
- const connectionOptions = {
75
- rejectUnauthorized: false
76
- };
77
- // If the hostname is not an IP address..
78
- if (!$dvphU$isIP(this.host)) // Set the servername option which enables support for SNI.
79
- // NOTE: SNI enables a server that hosts multiple domains to provide the appropriate TLS certificate.
80
- connectionOptions.serverName = this.host;
81
- // Initialize the socket (allowing self-signed certificates).
82
- this.tcpSocket = $dvphU$connect(this.port, this.host, connectionOptions);
83
- // Add a 'secureConnect' listener that checks the authorization status of
84
- // the socket, and logs a warning when it uses a self signed certificate.
85
- this.tcpSocket.once("secureConnect", ()=>{
86
- // Cannot happen, since this event callback *only* exists on TLSSocket
87
- if (!(this.tcpSocket instanceof $dvphU$TLSSocket)) return;
88
- // Force cast authorizationError from Error to string (through unknown)
89
- // because it is incorrectly typed as an Error
90
- const authorizationError = this.tcpSocket.authorizationError;
91
- if (authorizationError === "DEPTH_ZERO_SELF_SIGNED_CERT") (0, $dvphU$electrumcashdebuglogs).warning(`Connection to ${this.host}:${this.port} uses a self-signed certificate`);
92
- });
93
- // Trigger successful connection events.
94
- this.tcpSocket.on("secureConnect", this.onConnect.bind(this));
95
- } else {
96
- // Initialize the socket.
97
- this.tcpSocket = $dvphU$connect1({
98
- host: this.host,
99
- port: this.port
100
- });
101
- // Trigger successful connection events.
102
- this.tcpSocket.on("connect", this.onConnect.bind(this));
103
- }
104
- // Configure encoding.
105
- this.tcpSocket.setEncoding("utf8");
106
- // Enable persistent connections.
107
- // NOTE: This will send a non-data message 0.25 second after last activity.
108
- // After 10 consecutive such messages with no response, the connection will be cut.
109
- this.tcpSocket.setKeepAlive(true, 250);
110
- // Disable buffering of outgoing data.
111
- this.tcpSocket.setNoDelay(true);
112
- // Forward the encountered errors.
113
- this.tcpSocket.on("error", this.onError);
114
- }
115
- /**
116
- * Internal error handler that helps provide context to some types of errors before passing them up through the stack.
117
- */ onError(error) {
118
- switch(error.code){
119
- // If the DNS lookup failed.
120
- case "EAI_AGAIN":
121
- this.emit("error", new Error(`Failed to look up DNS records for '${this.host}'.`));
122
- break;
123
- // If the connection timed out..
124
- case "ETIMEDOUT":
125
- this.emit("error", error);
126
- break;
127
- // For unknown errors..
128
- default:
129
- this.emit("error", error);
130
- }
131
- }
132
- /**
133
- * Sets up forwarding of events related to the connection.
134
- */ onConnect() {
135
- // If the onConnect function has already run, do not execute it again.
136
- if (this.onConnectHasRun) return;
137
- // Set a named connection type for logging purposes.
138
- const connectionType = this.encrypted ? "an encrypted TCP Socket" : "a TCP Socket";
139
- // Log that the connection has been established.
140
- (0, $dvphU$electrumcashdebuglogs).network(`Established ${connectionType} connection with '${this.host}:${this.port}'.`);
141
- // Forward the socket events
142
- this.tcpSocket.addListener("close", this.eventForwarders.disconnect);
143
- this.tcpSocket.addListener("data", this.eventForwarders.tcpData);
144
- // Indicate that the onConnect function has run.
145
- this.onConnectHasRun = true;
146
- // Emit the connect event.
147
- this.emit("connected");
148
- }
149
- /**
150
- * Clears the disconnect timer if it is still active.
151
- */ clearDisconnectTimerOnTimeout() {
152
- // Clear the retry timer if it is still active.
153
- if (this.disconnectTimer) clearTimeout(this.disconnectTimer);
154
- }
155
- /**
156
- * Forcibly terminate the connection.
157
- *
158
- * @throws {Error} if no connection was found
159
- */ disconnect() {
160
- // Clear the disconnect timer so that the socket does not try to disconnect again later.
161
- this.clearDisconnectTimerOnTimeout();
162
- if (this.tcpSocket) {
163
- // Remove all event forwarders.
164
- this.tcpSocket.removeListener("close", this.eventForwarders.disconnect);
165
- this.tcpSocket.removeListener("data", this.eventForwarders.tcpData);
166
- // Also remove the error forwarder, to prevent the following destroy call from generating error messages.
167
- this.tcpSocket.removeListener("error", this.onError);
168
- // Terminate the connection.
169
- this.tcpSocket.destroy();
170
- // Remove the stored socket.
171
- this.tcpSocket = undefined;
172
- }
173
- // Indicate that the onConnect function has not run and it has to be run again.
174
- this.onConnectHasRun = false;
175
- // Emit a disconnect event
176
- this.emit("disconnected");
177
- }
178
- /**
179
- * Write data to the socket
180
- *
181
- * @param data Data to be written to the socket
182
- * @param callback Callback function to be called when the write has completed
183
- *
184
- * @throws {Error} if no connection was found
185
- * @returns true if the message was fully flushed to the socket, false if part of the message
186
- * is queued in the user memory
187
- */ write(data, callback) {
188
- // Throw an error if no active connection is found
189
- if (!this.tcpSocket) throw new Error("Cannot write to socket when there is no active connection");
190
- // Write data to the TLS Socket and return the status indicating
191
- // whether the full message was flushed to the socket
192
- return this.tcpSocket.write(data, callback);
193
- }
194
- /**
195
- * Force a disconnection if no connection is established after `timeout` milliseconds.
196
- */ disconnectOnTimeout() {
197
- // Remove the connect listener.
198
- this.removeListener("connected", this.clearDisconnectTimerOnTimeout);
199
- // Emit an error event so that connect is rejected upstream.
200
- this.emit("error", new Error(`Connection to '${this.host}:${this.port}' timed out after ${this.timeout} milliseconds`));
201
- // Forcibly disconnect to clean up the connection on timeout
202
- this.disconnect();
203
- }
204
- // Add magic glue that makes typedoc happy so that we can have the events listed on the class.
205
- connected;
206
- disconnected;
207
- data;
208
- error;
209
- }
210
-
211
-
212
- var $e83d2e7688025acd$exports = {};
9
+ //#endregion
10
+ //#region source/tcp.ts
213
11
  /**
214
- * Connection options used with TLS connections.
215
- * @ignore
216
- */
217
-
218
-
12
+ * TCP Socket used when communicating with Electrum servers.
13
+ */
14
+ var ElectrumTcpSocket = class extends EventEmitter {
15
+ tcpSocket;
16
+ disconnectTimer;
17
+ onConnectHasRun = false;
18
+ eventForwarders = {
19
+ disconnect: () => this.emit("disconnected"),
20
+ tcpData: (data) => this.emit("data", data)
21
+ };
22
+ /**
23
+ * Creates a socket configured with connection information for a given Electrum server.
24
+ *
25
+ * @param host Fully qualified domain name or IP address of the host
26
+ * @param port Network port for the host to connect to, defaults to the standard TLS port
27
+ * @param encrypted If false, uses an unencrypted connection instead of the default on TLS
28
+ * @param timeout If no connection is established after `timeout` ms, the connection is terminated
29
+ */
30
+ constructor(host, port = 50002, encrypted = true, timeout = defaultTimeout) {
31
+ super();
32
+ this.host = host;
33
+ this.port = port;
34
+ this.encrypted = encrypted;
35
+ this.timeout = timeout;
36
+ }
37
+ /**
38
+ * Returns a string for the host identifier for usage in debug messages.
39
+ */
40
+ get hostIdentifier() {
41
+ return `${this.host}:${this.port}`;
42
+ }
43
+ /**
44
+ * Connect to host:port using the specified transport
45
+ */
46
+ connect() {
47
+ if (this.tcpSocket) throw /* @__PURE__ */ new Error("Cannot initiate a new socket connection when an existing connection exists");
48
+ this.disconnectTimer = setTimeout(() => this.disconnectOnTimeout(), this.timeout);
49
+ this.once("connected", this.clearDisconnectTimerOnTimeout);
50
+ const connectionType = this.encrypted ? "an encrypted TCP Socket" : "a TCP Socket";
51
+ debug.network(`Initiating ${connectionType} connection to '${this.host}:${this.port}'.`);
52
+ if (this.encrypted) {
53
+ const connectionOptions = { rejectUnauthorized: false };
54
+ if (!net.isIP(this.host)) connectionOptions.serverName = this.host;
55
+ this.tcpSocket = tls.connect(this.port, this.host, connectionOptions);
56
+ this.tcpSocket.once("secureConnect", () => {
57
+ if (!(this.tcpSocket instanceof tls.TLSSocket)) return;
58
+ if (this.tcpSocket.authorizationError === "DEPTH_ZERO_SELF_SIGNED_CERT") debug.warning(`Connection to ${this.host}:${this.port} uses a self-signed certificate`);
59
+ });
60
+ this.tcpSocket.on("secureConnect", this.onConnect.bind(this));
61
+ } else {
62
+ this.tcpSocket = net.connect({
63
+ host: this.host,
64
+ port: this.port
65
+ });
66
+ this.tcpSocket.on("connect", this.onConnect.bind(this));
67
+ }
68
+ this.tcpSocket.setEncoding("utf8");
69
+ this.tcpSocket.setKeepAlive(true, 250);
70
+ this.tcpSocket.setNoDelay(true);
71
+ this.tcpSocket.on("error", this.onError);
72
+ }
73
+ /**
74
+ * Internal error handler that helps provide context to some types of errors before passing them up through the stack.
75
+ */
76
+ onError(error) {
77
+ switch (error.code) {
78
+ case "EAI_AGAIN":
79
+ this.emit("error", /* @__PURE__ */ new Error(`Failed to look up DNS records for '${this.host}'.`));
80
+ break;
81
+ case "ETIMEDOUT":
82
+ this.emit("error", error);
83
+ break;
84
+ default: this.emit("error", error);
85
+ }
86
+ }
87
+ /**
88
+ * Sets up forwarding of events related to the connection.
89
+ */
90
+ onConnect() {
91
+ if (this.onConnectHasRun) return;
92
+ const connectionType = this.encrypted ? "an encrypted TCP Socket" : "a TCP Socket";
93
+ debug.network(`Established ${connectionType} connection with '${this.host}:${this.port}'.`);
94
+ this.tcpSocket.addListener("close", this.eventForwarders.disconnect);
95
+ this.tcpSocket.addListener("data", this.eventForwarders.tcpData);
96
+ this.onConnectHasRun = true;
97
+ this.emit("connected");
98
+ }
99
+ /**
100
+ * Clears the disconnect timer if it is still active.
101
+ */
102
+ clearDisconnectTimerOnTimeout() {
103
+ if (this.disconnectTimer) clearTimeout(this.disconnectTimer);
104
+ }
105
+ /**
106
+ * Forcibly terminate the connection.
107
+ *
108
+ * @throws {Error} if no connection was found
109
+ */
110
+ disconnect() {
111
+ this.clearDisconnectTimerOnTimeout();
112
+ if (this.tcpSocket) {
113
+ this.tcpSocket.removeListener("close", this.eventForwarders.disconnect);
114
+ this.tcpSocket.removeListener("data", this.eventForwarders.tcpData);
115
+ this.tcpSocket.removeListener("error", this.onError);
116
+ this.tcpSocket.destroy();
117
+ this.tcpSocket = void 0;
118
+ }
119
+ this.onConnectHasRun = false;
120
+ this.emit("disconnected");
121
+ }
122
+ /**
123
+ * Write data to the socket
124
+ *
125
+ * @param data Data to be written to the socket
126
+ * @param callback Callback function to be called when the write has completed
127
+ *
128
+ * @throws {Error} if no connection was found
129
+ * @returns true if the message was fully flushed to the socket, false if part of the message
130
+ * is queued in the user memory
131
+ */
132
+ write(data, callback) {
133
+ if (!this.tcpSocket) throw /* @__PURE__ */ new Error("Cannot write to socket when there is no active connection");
134
+ return this.tcpSocket.write(data, callback);
135
+ }
136
+ /**
137
+ * Force a disconnection if no connection is established after `timeout` milliseconds.
138
+ */
139
+ disconnectOnTimeout() {
140
+ this.removeListener("connected", this.clearDisconnectTimerOnTimeout);
141
+ this.emit("error", /* @__PURE__ */ new Error(`Connection to '${this.host}:${this.port}' timed out after ${this.timeout} milliseconds`));
142
+ this.disconnect();
143
+ }
144
+ connected;
145
+ disconnected;
146
+ data;
147
+ error;
148
+ };
219
149
 
220
- export {$bcb32cbeddeae7b2$export$22c0ca2c816c3e08 as ElectrumTcpSocket};
221
- //# sourceMappingURL=index.mjs.map
150
+ //#endregion
151
+ export { ElectrumTcpSocket };
152
+ //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"mappings":"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","sources":["source/index.ts","source/tcp.ts","source/constants.ts","source/interfaces.ts"],"sourcesContent":["export * from './tcp.ts';\nexport * from './interfaces';\n","import * as tls from 'tls';\nimport * as net from 'net';\nimport debug from '@electrum-cash/debug-logs';\nimport { defaultTimeout } from './constants';\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","// Export a default timeout value of 30 seconds.\nexport const defaultTimeout = 30 * 1000;\n","/**\n * Connection options used with TLS connections.\n * @ignore\n */\nexport interface ConnectionOptions\n{\n\trejectUnauthorized?: boolean;\n\tserverName?: string;\n}\n"],"names":[],"version":3,"file":"index.mjs.map"}
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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@electrum-cash/tcp-socket",
3
- "version": "1.0.0",
3
+ "version": "1.1.0-development.12711590191",
4
4
  "description": "@electrum-cash/web-socket implements the ElectrumSocket interface using nodejs tcp sockets.",
5
5
  "keywords": [
6
6
  "electrum",
@@ -19,43 +19,42 @@
19
19
  "license": "MIT",
20
20
  "source": "./source/index.ts",
21
21
  "type": "module",
22
- "types": "./dist/index.d.ts",
22
+ "types": "./dist/index.d.mts",
23
23
  "module": "./dist/index.mjs",
24
24
  "exports": {
25
- "types": "./dist/index.d.ts",
25
+ "types": "./dist/index.d.mts",
26
26
  "default": "./dist/index.mjs"
27
27
  },
28
28
  "files": [
29
29
  "dist"
30
30
  ],
31
31
  "scripts": {
32
- "clean": "del ./dist",
33
- "build": "npm run clean && parcel build",
34
- "analyze": "parcel build --reporter @parcel/reporter-bundle-analyzer",
32
+ "build": "tsdown --clean --sourcemap source/index.ts",
33
+ "analyze": "tsdown --clean --no-fixed-extension --sourcemap source/index.ts && esbuild-analyzer dist/",
35
34
  "docs": "typedoc --hideGenerator --categorizeByGroup",
36
- "lint": "eslint . --ext .ts",
35
+ "lint": "eslint",
37
36
  "syntax": "tsc --noEmit",
38
37
  "spellcheck": "cspell 'source/**' 'test/**' 'examples/**'",
39
38
  "test": "vitest --dir test/ --test-timeout=15000 --passWithNoTests --run --coverage"
40
39
  },
41
40
  "devDependencies": {
42
- "@electrum-cash/network": "^4.0.2-development.8063220996",
43
- "@generalprotocols/cspell-dictionary": "git+https://gitlab.com/GeneralProtocols/cspell-dictionary.git",
44
- "@generalprotocols/eslint-config": "git+https://gitlab.com/GeneralProtocols/eslint-config.git",
45
- "@parcel/packager-ts": "^2.12.0",
46
- "@parcel/transformer-typescript-types": "^2.12.0",
41
+ "@chalp/eslint-airbnb": "^1.3.0",
42
+ "@electrum-cash/eslint-config": "^1.1.0",
43
+ "@electrum-cash/network": "^4.1.4",
44
+ "@stylistic/eslint-plugin": "^5.7.0",
47
45
  "@types/debug": "^4.1.6",
48
- "@typescript-eslint/eslint-plugin": "^6.8.0",
49
- "@vitest/coverage-v8": "^1.3.1",
46
+ "@typescript-eslint/eslint-plugin": "^8.53.0",
47
+ "@typescript-eslint/parser": "^8.53.0",
48
+ "@vitest/coverage-v8": "^3.2.4",
49
+ "@viz-kit/esbuild-analyzer": "^1.0.0",
50
50
  "cspell": "^8.6.0",
51
- "del-cli": "^5.0.0",
52
- "eslint": "^8.42.0",
53
- "eslint-plugin-import": "^2.23.4",
54
- "parcel": "^2.12.0",
51
+ "eslint": "^9.39.2",
52
+ "tsdown": "^0.20.0-beta.3",
55
53
  "typedoc": "^0.25.12",
56
54
  "typedoc-plugin-coverage": "^3.1.0",
57
55
  "typescript": "^5.1.3",
58
- "vitest": "^1.3.1"
56
+ "typescript-eslint": "^8.53.0",
57
+ "vitest": "^3.2.4"
59
58
  },
60
59
  "dependencies": {
61
60
  "@electrum-cash/debug-logs": "^1.0.0",
package/dist/index.d.ts DELETED
@@ -1,59 +0,0 @@
1
- import { EventEmitter } from "eventemitter3";
2
- import { ElectrumSocket, ElectrumSocketEvents } from "@electrum-cash/network";
3
- /**
4
- * TCP Socket used when communicating with Electrum servers.
5
- */
6
- export class ElectrumTcpSocket extends EventEmitter<ElectrumSocketEvents> implements ElectrumSocket {
7
- host: string;
8
- port: number;
9
- encrypted: boolean;
10
- timeout: number;
11
- /**
12
- * Creates a socket configured with connection information for a given Electrum server.
13
- *
14
- * @param host Fully qualified domain name or IP address of the host
15
- * @param port Network port for the host to connect to, defaults to the standard TLS port
16
- * @param encrypted If false, uses an unencrypted connection instead of the default on TLS
17
- * @param timeout If no connection is established after `timeout` ms, the connection is terminated
18
- */
19
- constructor(host: string, port?: number, encrypted?: boolean, timeout?: number);
20
- /**
21
- * Returns a string for the host identifier for usage in debug messages.
22
- */
23
- get hostIdentifier(): string;
24
- /**
25
- * Connect to host:port using the specified transport
26
- */
27
- connect(): void;
28
- /**
29
- * Forcibly terminate the connection.
30
- *
31
- * @throws {Error} if no connection was found
32
- */
33
- disconnect(): void;
34
- /**
35
- * Write data to the socket
36
- *
37
- * @param data Data to be written to the socket
38
- * @param callback Callback function to be called when the write has completed
39
- *
40
- * @throws {Error} if no connection was found
41
- * @returns true if the message was fully flushed to the socket, false if part of the message
42
- * is queued in the user memory
43
- */
44
- write(data: Uint8Array | string, callback?: (err?: Error) => void): boolean;
45
- readonly connected: [];
46
- readonly disconnected: [];
47
- readonly data: [string];
48
- readonly error: [Error];
49
- }
50
- /**
51
- * Connection options used with TLS connections.
52
- * @ignore
53
- */
54
- export interface ConnectionOptions {
55
- rejectUnauthorized?: boolean;
56
- serverName?: string;
57
- }
58
-
59
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"mappings":";;ACkBA;;GAEG;AACH,8BAA+B,SAAQ,aAAa,oBAAoB,CAAE,YAAW,cAAc;IA4B1F,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,SAAS,EAAE,OAAO;IAClB,OAAO,EAAE,MAAM;IAbvB;;;;;;;OAOG;gBAGK,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,MAAc,EACpB,SAAS,GAAE,OAAc,EACzB,OAAO,GAAE,MAAuB;IAOxC;;OAEG;IACH,IAAI,cAAc,IAAI,MAAM,CAG3B;IAED;;OAEG;IACI,OAAO,IAAI,IAAI;IA2ItB;;;;OAIG;IACI,UAAU,IAAI,IAAI;IA4BzB;;;;;;;;;OASG;IACI,KAAK,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,KAAK,IAAI,GAAG,OAAO;IA6BlF,SAAgB,SAAS,EAAE,EAAE,CAAC;IAC9B,SAAgB,YAAY,EAAE,EAAE,CAAC;IACjC,SAAgB,IAAI,EAAE,CAAE,MAAM,CAAE,CAAC;IACjC,SAAgB,KAAK,EAAE,CAAE,KAAK,CAAE,CAAC;CACjC;AC7RD;;;GAGG;AACH;IAEC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB","sources":["source/source/constants.ts","source/source/tcp.ts","source/source/interfaces.ts","source/source/index.ts","source/index.ts"],"sourcesContent":[null,null,null,null,"export * from './tcp.ts';\nexport * from './interfaces';\n"],"names":[],"version":3,"file":"index.d.ts.map"}