@electrum-cash/network 4.0.0-development.8017676278 → 4.0.0-development.8018121991
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/README.md +14 -19
- package/dist/index.d.ts +59 -47
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +54 -89
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -16,43 +16,38 @@ Install the library with NPM:
|
|
|
16
16
|
|
|
17
17
|
## Usage
|
|
18
18
|
|
|
19
|
-
###
|
|
19
|
+
### Importing the library
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
To use the library, import the `ElectrumClient` into your project:
|
|
22
22
|
|
|
23
23
|
```js
|
|
24
24
|
// Load the electrum library.
|
|
25
|
-
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
### Usage on Web
|
|
29
|
-
|
|
30
|
-
To use the library on the web, use the ESM import syntax and include the `ElectrumTransport` import:
|
|
31
|
-
|
|
32
|
-
```js
|
|
33
|
-
// Load the electrum library.
|
|
34
|
-
import { ElectrumClient, ElectrumTransport } from '@electrum-cash/network';
|
|
25
|
+
import { ElectrumClient } from '@electrum-cash/network';
|
|
35
26
|
```
|
|
36
27
|
|
|
37
28
|
### Connecting to a server
|
|
38
29
|
|
|
39
|
-
|
|
30
|
+
Initialize and connect the client with your **application identifier** and **protocol version**, as well as a **hostname** to connect to.
|
|
40
31
|
|
|
41
32
|
```js
|
|
42
33
|
// Initialize an electrum client.
|
|
43
34
|
const electrumClient = new ElectrumClient('Electrum client example', '1.4.1', 'bch.imaginary.cash');
|
|
44
35
|
|
|
45
|
-
// Wait for the client to connect
|
|
36
|
+
// Wait for the client to connect.
|
|
46
37
|
await electrumClient.connect();
|
|
47
38
|
```
|
|
48
39
|
|
|
49
|
-
|
|
40
|
+
Alternatively, you can provide a pre-configured `ElectrumSocket` instead of the hostname:
|
|
50
41
|
|
|
51
42
|
```js
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
43
|
+
// Set up your own socket, somehow.
|
|
44
|
+
const electrumSocket = new MyElectrumSocketClass();
|
|
45
|
+
|
|
46
|
+
// Initialize the electrum client.
|
|
47
|
+
const electrumClient = new ElectrumClient('Electrum client example', '1.4.1', electrumSocket);
|
|
48
|
+
|
|
49
|
+
// Wait for the client to connect.
|
|
50
|
+
await electrumClient.connect();
|
|
56
51
|
```
|
|
57
52
|
|
|
58
53
|
### Request information
|
package/dist/index.d.ts
CHANGED
|
@@ -23,62 +23,81 @@ interface RPCErrorResponse extends RPCBase {
|
|
|
23
23
|
}
|
|
24
24
|
type RPCResponse = RPCErrorResponse | RPCStatement;
|
|
25
25
|
/**
|
|
26
|
-
*
|
|
27
|
-
* @enum {number}
|
|
28
|
-
* @property {0} UNAVAILABLE The client is currently not available.
|
|
29
|
-
* @property {1} AVAILABLE The client is available for use.
|
|
30
|
-
*/
|
|
31
|
-
export enum ClientState {
|
|
32
|
-
UNAVAILABLE = 0,
|
|
33
|
-
AVAILABLE = 1
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Enum that denotes the connection status of an ElectrumConnection.
|
|
37
|
-
* @enum {number}
|
|
38
|
-
* @property {0} DISCONNECTED The connection is disconnected.
|
|
39
|
-
* @property {1} AVAILABLE The connection is connected.
|
|
40
|
-
* @property {2} DISCONNECTING The connection is disconnecting.
|
|
41
|
-
* @property {3} CONNECTING The connection is connecting.
|
|
42
|
-
* @property {4} RECONNECTING The connection is restarting.
|
|
26
|
+
* Optional settings that change the default behavior of the network connection.
|
|
43
27
|
*/
|
|
44
|
-
export
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
connection: ElectrumClient;
|
|
28
|
+
export interface ElectrumNetworkOptions {
|
|
29
|
+
/** If set to true, numbers that can safely be parsed as integers will be `BigInt` rather than `Number`. */
|
|
30
|
+
useBigInt?: boolean;
|
|
31
|
+
/** When connected, send a keep-alive Ping message this often. */
|
|
32
|
+
sendKeepAliveIntervalInMilliSeconds?: number;
|
|
33
|
+
/** When disconnected, attempt to reconnect after this amount of time. */
|
|
34
|
+
reconnectAfterMilliSeconds?: number;
|
|
35
|
+
/** After every send, verify that we have received data after this amount of time. */
|
|
36
|
+
verifyConnectionTimeoutInMilliSeconds?: number;
|
|
54
37
|
}
|
|
55
38
|
/**
|
|
56
39
|
* A list of possible responses to requests.
|
|
40
|
+
* @ignore
|
|
57
41
|
*/
|
|
58
42
|
export type RequestResponse = object | string | number | boolean | null | RequestResponse[];
|
|
43
|
+
/**
|
|
44
|
+
* Request resolvers are used to process the response of a request. This takes either
|
|
45
|
+
* an error object or any stringified data, while the other parameter is omitted.
|
|
46
|
+
* @ignore
|
|
47
|
+
*/
|
|
59
48
|
export type RequestResolver = (error?: Error, data?: string) => void;
|
|
49
|
+
/**
|
|
50
|
+
* Typing for promise resolution.
|
|
51
|
+
* @ignore
|
|
52
|
+
*/
|
|
60
53
|
export type ResolveFunction<T> = (value: T | PromiseLike<T>) => void;
|
|
54
|
+
/**
|
|
55
|
+
* Typing for promise rejection.
|
|
56
|
+
* @ignore
|
|
57
|
+
*/
|
|
61
58
|
export type RejectFunction = (reason?: any) => void;
|
|
59
|
+
/**
|
|
60
|
+
* @ignore
|
|
61
|
+
*/
|
|
62
62
|
export interface VersionRejected {
|
|
63
63
|
error: RPCError;
|
|
64
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* @ignore
|
|
67
|
+
*/
|
|
65
68
|
export interface VersionNegotiated {
|
|
66
69
|
software: string;
|
|
67
70
|
protocol: string;
|
|
68
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* @ignore
|
|
74
|
+
*/
|
|
69
75
|
export const isVersionRejected: (object: any) => object is VersionRejected;
|
|
76
|
+
/**
|
|
77
|
+
* @ignore
|
|
78
|
+
*/
|
|
70
79
|
export const isVersionNegotiated: (object: any) => object is VersionNegotiated;
|
|
71
80
|
/**
|
|
72
|
-
*
|
|
81
|
+
* Enum that denotes the connection status of an ElectrumConnection.
|
|
82
|
+
* @enum {number}
|
|
83
|
+
* @property {0} DISCONNECTED The connection is disconnected.
|
|
84
|
+
* @property {1} AVAILABLE The connection is connected.
|
|
85
|
+
* @property {2} DISCONNECTING The connection is disconnecting.
|
|
86
|
+
* @property {3} CONNECTING The connection is connecting.
|
|
87
|
+
* @property {4} RECONNECTING The connection is restarting.
|
|
73
88
|
*/
|
|
74
|
-
export
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
89
|
+
export enum ConnectionStatus {
|
|
90
|
+
DISCONNECTED = 0,
|
|
91
|
+
CONNECTED = 1,
|
|
92
|
+
DISCONNECTING = 2,
|
|
93
|
+
CONNECTING = 3,
|
|
94
|
+
RECONNECTING = 4
|
|
78
95
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
96
|
+
/**
|
|
97
|
+
* Configure default options.
|
|
98
|
+
* @ignore
|
|
99
|
+
*/
|
|
100
|
+
export const defaultNetworkOptions: ElectrumNetworkOptions;
|
|
82
101
|
/**
|
|
83
102
|
* Triggers when the underlying connection is established.
|
|
84
103
|
*
|
|
@@ -101,9 +120,7 @@ export class ElectrumClient extends EventEmitter {
|
|
|
101
120
|
application: string;
|
|
102
121
|
version: string;
|
|
103
122
|
socketOrHostname: ElectrumSocket | string;
|
|
104
|
-
|
|
105
|
-
reconnectInterval: number;
|
|
106
|
-
useBigInt: boolean;
|
|
123
|
+
options: ElectrumNetworkOptions;
|
|
107
124
|
/**
|
|
108
125
|
* The name and version of the server software indexing the blockchain.
|
|
109
126
|
*/
|
|
@@ -125,25 +142,20 @@ export class ElectrumClient extends EventEmitter {
|
|
|
125
142
|
/**
|
|
126
143
|
* Number corresponding to the underlying connection status.
|
|
127
144
|
*/
|
|
128
|
-
status: ConnectionStatus;
|
|
145
|
+
get status(): ConnectionStatus;
|
|
129
146
|
/**
|
|
130
147
|
* Initializes an Electrum client.
|
|
131
148
|
*
|
|
132
149
|
* @param application - your application name, used to identify to the electrum host.
|
|
133
150
|
* @param version - protocol version to use with the host.
|
|
134
|
-
* @param socketOrHostname - socket fully qualified domain name or IP number of the host
|
|
135
|
-
* @param
|
|
136
|
-
* @param reconnectInterval - the time between reconnection attempts to the electrum host, in milliseconds.
|
|
137
|
-
* @param useBigInt - whether to use bigint for numbers in json response.
|
|
151
|
+
* @param socketOrHostname - pre-configured electrum socket or fully qualified domain name or IP number of the host
|
|
152
|
+
* @param options - ...
|
|
138
153
|
*
|
|
139
154
|
* @throws {Error} if `version` is not a valid version string.
|
|
140
155
|
*/
|
|
141
|
-
constructor(application: string, version: string, socketOrHostname: ElectrumSocket | string,
|
|
156
|
+
constructor(application: string, version: string, socketOrHostname: ElectrumSocket | string, options?: ElectrumNetworkOptions);
|
|
142
157
|
get hostIdentifier(): string;
|
|
143
|
-
get host(): string;
|
|
144
|
-
get port(): number;
|
|
145
158
|
get encrypted(): boolean;
|
|
146
|
-
get timeout(): number;
|
|
147
159
|
/**
|
|
148
160
|
* Connects to the remote server.
|
|
149
161
|
*
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":";;AACA,oBAA2B,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;AAG5D;IAEC,OAAO,EAAE,MAAM,CAAC;CAChB;AAGD,yBAAiC,SAAQ,OAAO;IAE/C,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,YAAY,EAAE,CAAC;CACxB;AAWD,sBAA8B,SAAQ,OAAO;IAE5C,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CACf;AAED;IAEC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,GAAG,CAAC;CACX;AAGD,0BAAkC,SAAQ,OAAO;IAEhD,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB,KAAK,EAAE,QAAQ,CAAC;CAChB;AAGD,mBAA0B,gBAAgB,GAAG,YAAY,CAAC;
|
|
1
|
+
{"mappings":";;AACA,oBAA2B,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;AAG5D;IAEC,OAAO,EAAE,MAAM,CAAC;CAChB;AAGD,yBAAiC,SAAQ,OAAO;IAE/C,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,YAAY,EAAE,CAAC;CACxB;AAWD,sBAA8B,SAAQ,OAAO;IAE5C,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CACf;AAED;IAEC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,GAAG,CAAC;CACX;AAGD,0BAAkC,SAAQ,OAAO;IAEhD,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB,KAAK,EAAE,QAAQ,CAAC;CAChB;AAGD,mBAA0B,gBAAgB,GAAG,YAAY,CAAC;AE5C1D;;GAEG;AACH;IAEC,2GAA2G;IAC3G,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,iEAAiE;IACjE,mCAAmC,CAAC,EAAE,MAAM,CAAC;IAE7C,yEAAyE;IACzE,0BAA0B,CAAC,EAAE,MAAM,CAAC;IAEpC,qFAAqF;IACrF,qCAAqC,CAAC,EAAE,MAAM,CAAC;CAC/C;AAED;;;GAGG;AACH,8BAA8B,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,eAAe,EAAE,CAAC;AAE5F;;;;GAIG;AACH,8BAA8B,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;AAErE;;;GAGG;AACH,4BAA4B,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;AAErE;;;GAGG;AACH,6BAA6B,CAAC,MAAM,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;AAEpD;;GAEG;AACH;IAEC,KAAK,EAAE,QAAQ,CAAC;CAChB;AAED;;GAEG;AACH;IAEC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,OAAO,MAAM,4BAAqC,GAAG,8BAGpD,CAAC;AAEF;;GAEG;AACH,OAAO,MAAM,8BAAuC,GAAG,gCAGtD,CAAC;ACzEF;;;;;;;;GAQG;AACH;IAEC,YAAY,IAAI;IAChB,SAAS,IAAI;IACb,aAAa,IAAI;IACjB,UAAU,IAAI;IACd,YAAY,IAAI;CAChB;AEdD;;;GAGG;AACH,OAAO,MAAM,uBAAuB,sBAanC,CAAC;ACVF;;;;GAIG;AAEH;;;;GAIG;AAEH;;;;GAIG;AAEH;;GAEG;AACH,2BAAqB,SAAQ,YAAY;IA0DhC,WAAW,EAAE,MAAM;IACnB,OAAO,EAAE,MAAM;IACf,gBAAgB,EAAE,cAAc,GAAG,MAAM;IACzC,OAAO,EAAE,sBAAsB;IA3DvC;;OAEG;IACI,QAAQ,EAAE,MAAM,CAAC;IAExB;;;OAGG;IACI,WAAW,EAAE,MAAM,CAAC;IAE3B;;;OAGG;IACI,WAAW,EAAE,MAAM,CAAC;IAE3B;;OAEG;IACI,qBAAqB,EAAE,MAAM,CAAC;IAErC;;OAEG;IACH,IAAW,MAAM,IAAI,gBAAgB,CAGpC;IAiBD;;;;;;;;;OASG;gBAEK,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,gBAAgB,EAAE,cAAc,GAAG,MAAM,EACzC,OAAO,GAAE,sBAA2B;IAc5C,IAAI,cAAc,IAAI,MAAM,CAG3B;IAGD,IAAI,SAAS,IAAI,OAAO,CAGvB;IAED;;;;;OAKG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA0C9B;;;;;;;OAOG;IACG,UAAU,CAAC,KAAK,GAAE,OAAe,EAAE,mBAAmB,GAAE,OAAe,GAAG,OAAO,CAAC,OAAO,CAAC;IAehG;;;;;;;;OAQG;IACG,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,KAAK,GAAG,eAAe,CAAC;IAgD9F;;;;;;;;;;OAUG;IACG,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IA6B7E;;;;;;;;;;OAUG;IACG,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAgF/E;;;;;;;OAOG;IACH,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,WAAW,GAAG,IAAI;IA0DtD;;;;;OAKG;IACG,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC;IAmB7C;;;;OAIG;IACG,oBAAoB,CAAC,gBAAgB,KAAA,GAAG,OAAO,CAAC,IAAI,CAAC;IAa3D;;;;OAIG;IACG,2BAA2B,IAAI,OAAO,CAAC,IAAI,CAAC;IAMlD;;;;;OAKG;IACG,yCAAyC,CAAC,OAAO,KAAA,GAAG,OAAO,CAAC,IAAI,CAAC;IAUvE;;;;;OAKG;IACG,oCAAoC,CAAC,OAAO,KAAA,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBlE;;OAEG;IACG,6BAA6B,CAAC,SAAS,KAAA,GAAG,OAAO,CAAC,IAAI,CAAC;CAK7D","sources":["source/source/rpc-interfaces.ts","source/source/electrum-protocol.ts","source/source/interfaces.ts","source/source/enums.ts","source/source/electrum-connection.ts","source/source/constants.ts","source/source/electrum-client.ts","source/source/index.ts","source/index.ts"],"sourcesContent":[null,null,null,null,null,null,null,null,"export { default as ElectrumClient } from './electrum-client';\n\nexport * from './interfaces';\nexport * from './constants';\nexport * from './enums';\n"],"names":[],"version":3,"file":"index.d.ts.map"}
|
package/dist/index.mjs
CHANGED
|
@@ -66,35 +66,20 @@ const $e83d2e7688025acd$export$9598f0c76aa41d73 = function(object) {
|
|
|
66
66
|
};
|
|
67
67
|
|
|
68
68
|
|
|
69
|
-
var $d801b1f9b7fc3074$exports = {};
|
|
70
|
-
|
|
71
|
-
$parcel$export($d801b1f9b7fc3074$exports, "DEFAULT_PING_INTERVAL", () => $d801b1f9b7fc3074$export$a3a6b8a974871191);
|
|
72
|
-
$parcel$export($d801b1f9b7fc3074$exports, "DEFAULT_RECONNECT_INTERVAL", () => $d801b1f9b7fc3074$export$b2115084b892a79d);
|
|
73
|
-
$parcel$export($d801b1f9b7fc3074$exports, "DEFAULT_BIG_INTEGERS", () => $d801b1f9b7fc3074$export$788e8376894ebb88);
|
|
74
|
-
// Time between ping messages, in milliseconds. Pinging keeps the connection alive.
|
|
75
|
-
// The reason for pinging this frequently is to detect connection problems early.
|
|
76
|
-
const $d801b1f9b7fc3074$export$a3a6b8a974871191 = 1000;
|
|
77
|
-
const $d801b1f9b7fc3074$export$b2115084b892a79d = 5000;
|
|
78
|
-
const $d801b1f9b7fc3074$export$788e8376894ebb88 = false;
|
|
79
|
-
|
|
80
|
-
|
|
81
69
|
|
|
82
70
|
var $db7c797e63383364$exports = {};
|
|
83
71
|
|
|
84
|
-
$parcel$export($db7c797e63383364$exports, "ClientState", () => $db7c797e63383364$export$c4f81c6d30ca200f);
|
|
85
72
|
$parcel$export($db7c797e63383364$exports, "ConnectionStatus", () => $db7c797e63383364$export$7516420eb880ab68);
|
|
86
73
|
// Disable indent rule for this file because it is broken (https://github.com/typescript-eslint/typescript-eslint/issues/1824)
|
|
87
74
|
/* eslint-disable @typescript-eslint/indent */ /**
|
|
88
|
-
* Enum that denotes the
|
|
75
|
+
* Enum that denotes the connection status of an ElectrumConnection.
|
|
89
76
|
* @enum {number}
|
|
90
|
-
* @property {0}
|
|
91
|
-
* @property {1} AVAILABLE
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
})($db7c797e63383364$export$c4f81c6d30ca200f || ($db7c797e63383364$export$c4f81c6d30ca200f = {}));
|
|
97
|
-
var $db7c797e63383364$export$7516420eb880ab68;
|
|
77
|
+
* @property {0} DISCONNECTED The connection is disconnected.
|
|
78
|
+
* @property {1} AVAILABLE The connection is connected.
|
|
79
|
+
* @property {2} DISCONNECTING The connection is disconnecting.
|
|
80
|
+
* @property {3} CONNECTING The connection is connecting.
|
|
81
|
+
* @property {4} RECONNECTING The connection is restarting.
|
|
82
|
+
*/ var $db7c797e63383364$export$7516420eb880ab68;
|
|
98
83
|
(function(ConnectionStatus) {
|
|
99
84
|
ConnectionStatus[ConnectionStatus["DISCONNECTED"] = 0] = "DISCONNECTED";
|
|
100
85
|
ConnectionStatus[ConnectionStatus["CONNECTED"] = 1] = "CONNECTED";
|
|
@@ -113,21 +98,17 @@ var $db7c797e63383364$export$7516420eb880ab68;
|
|
|
113
98
|
*
|
|
114
99
|
* @param application - your application name, used to identify to the electrum host.
|
|
115
100
|
* @param version - protocol version to use with the host.
|
|
116
|
-
* @param socketOrHostname - socket fully qualified domain name or IP number of the host
|
|
117
|
-
* @param
|
|
118
|
-
* @param reconnectInterval - the time between reconnection attempts to the electrum host, in milliseconds.
|
|
119
|
-
* @param useBigInt - whether to use bigint for numbers in json response.
|
|
101
|
+
* @param socketOrHostname - pre-configured electrum socket or fully qualified domain name or IP number of the host
|
|
102
|
+
* @param options - ...
|
|
120
103
|
*
|
|
121
104
|
* @throws {Error} if `version` is not a valid version string.
|
|
122
|
-
*/ constructor(application, version, socketOrHostname,
|
|
105
|
+
*/ constructor(application, version, socketOrHostname, options){
|
|
123
106
|
// Initialize the event emitter.
|
|
124
107
|
super();
|
|
125
108
|
this.application = application;
|
|
126
109
|
this.version = version;
|
|
127
110
|
this.socketOrHostname = socketOrHostname;
|
|
128
|
-
this.
|
|
129
|
-
this.reconnectInterval = reconnectInterval;
|
|
130
|
-
this.useBigInt = useBigInt;
|
|
111
|
+
this.options = options;
|
|
131
112
|
this.status = (0, $db7c797e63383364$export$7516420eb880ab68).DISCONNECTED;
|
|
132
113
|
this.verifications = [];
|
|
133
114
|
this.messageBuffer = "";
|
|
@@ -156,22 +137,10 @@ var $db7c797e63383364$export$7516420eb880ab68;
|
|
|
156
137
|
get hostIdentifier() {
|
|
157
138
|
return this.socket.hostIdentifier;
|
|
158
139
|
}
|
|
159
|
-
// Expose host from the socket.
|
|
160
|
-
get host() {
|
|
161
|
-
return this.socket.host;
|
|
162
|
-
}
|
|
163
|
-
// Expose port from the socket.
|
|
164
|
-
get port() {
|
|
165
|
-
return this.socket.port;
|
|
166
|
-
}
|
|
167
140
|
// Expose port from the socket.
|
|
168
141
|
get encrypted() {
|
|
169
142
|
return this.socket.encrypted;
|
|
170
143
|
}
|
|
171
|
-
// Expose timeout from the socket.
|
|
172
|
-
get timeout() {
|
|
173
|
-
return this.socket.timeout;
|
|
174
|
-
}
|
|
175
144
|
/**
|
|
176
145
|
* Assembles incoming data into statements and hands them off to the message parser.
|
|
177
146
|
*
|
|
@@ -197,7 +166,7 @@ var $db7c797e63383364$export$7516420eb880ab68;
|
|
|
197
166
|
// Move the first statement to its own variable.
|
|
198
167
|
const currentStatementList = String(statementParts.shift());
|
|
199
168
|
// Parse the statement into an object or list of objects.
|
|
200
|
-
let statementList = (0, $dvphU$parse)(currentStatementList, null, this.useBigInt ? (0, $dvphU$parseNumberAndBigInt) : parseFloat);
|
|
169
|
+
let statementList = (0, $dvphU$parse)(currentStatementList, null, this.options.useBigInt ? (0, $dvphU$parseNumberAndBigInt) : parseFloat);
|
|
201
170
|
// Wrap the statement in an array if it is not already a batched statement list.
|
|
202
171
|
if (!Array.isArray(statementList)) statementList = [
|
|
203
172
|
statementList
|
|
@@ -372,7 +341,7 @@ var $db7c797e63383364$export$7516420eb880ab68;
|
|
|
372
341
|
*/ setupKeepAliveTimer() {
|
|
373
342
|
// If the keep-alive timer loop is not currently set up..
|
|
374
343
|
if (!this.keepAliveTimer) // Set a new keep-alive timer.
|
|
375
|
-
this.keepAliveTimer = setTimeout(this.ping.bind(this), this.
|
|
344
|
+
this.keepAliveTimer = setTimeout(this.ping.bind(this), this.options.sendKeepAliveIntervalInMilliSeconds);
|
|
376
345
|
}
|
|
377
346
|
/**
|
|
378
347
|
* Tears down the current connection and removes all event listeners on disconnect.
|
|
@@ -458,7 +427,7 @@ var $db7c797e63383364$export$7516420eb880ab68;
|
|
|
458
427
|
// Get the current timestamp in milliseconds.
|
|
459
428
|
const currentTime = Date.now();
|
|
460
429
|
// Follow up and verify that the message got sent..
|
|
461
|
-
const verificationTimer = setTimeout(this.verifySend.bind(this, currentTime), this.timeout);
|
|
430
|
+
const verificationTimer = setTimeout(this.verifySend.bind(this, currentTime), this.socket.timeout);
|
|
462
431
|
// Store the verification timer locally so that it can be cleared when data has been received.
|
|
463
432
|
this.verifications.push(verificationTimer);
|
|
464
433
|
// Set a new keep-alive timer.
|
|
@@ -520,14 +489,14 @@ var $db7c797e63383364$export$7516420eb880ab68;
|
|
|
520
489
|
} else {
|
|
521
490
|
// If this is for an established connection..
|
|
522
491
|
if (this.status === (0, $db7c797e63383364$export$7516420eb880ab68).CONNECTED) // Write a notification to the logs.
|
|
523
|
-
(0, $dvphU$electrumcashdebuglogs).errors(`Connection with '${this.hostIdentifier}' was closed, trying to reconnect in ${this.
|
|
492
|
+
(0, $dvphU$electrumcashdebuglogs).errors(`Connection with '${this.hostIdentifier}' was closed, trying to reconnect in ${this.options.reconnectAfterMilliSeconds / 1000} seconds.`);
|
|
524
493
|
// Mark the connection as disconnected for now..
|
|
525
494
|
this.status = (0, $db7c797e63383364$export$7516420eb880ab68).DISCONNECTED;
|
|
526
495
|
// Send a disconnect signal higher up the stack.
|
|
527
496
|
this.emit("disconnected");
|
|
528
497
|
// If we don't have a pending reconnection timer..
|
|
529
498
|
if (!this.reconnectTimer) // Attempt to reconnect after one keep-alive duration.
|
|
530
|
-
this.reconnectTimer = setTimeout(this.reconnect.bind(this), this.
|
|
499
|
+
this.reconnectTimer = setTimeout(this.reconnect.bind(this), this.options.reconnectAfterMilliSeconds);
|
|
531
500
|
}
|
|
532
501
|
}
|
|
533
502
|
/**
|
|
@@ -539,19 +508,8 @@ var $db7c797e63383364$export$7516420eb880ab68;
|
|
|
539
508
|
// https://stackoverflow.com/a/18804298
|
|
540
509
|
if (typeof error === "undefined") // Do nothing, and instead rely on the socket disconnect event for further information.
|
|
541
510
|
return;
|
|
542
|
-
//
|
|
543
|
-
|
|
544
|
-
(0, $dvphU$electrumcashdebuglogs).errors(`Failed to look up DNS records for '${this.host}'.`);
|
|
545
|
-
return;
|
|
546
|
-
}
|
|
547
|
-
// If the connection timed out..
|
|
548
|
-
if (error.code === "ETIMEDOUT") {
|
|
549
|
-
// Log the provided timeout message.
|
|
550
|
-
(0, $dvphU$electrumcashdebuglogs).errors(error.message);
|
|
551
|
-
return;
|
|
552
|
-
}
|
|
553
|
-
// Log unknown error
|
|
554
|
-
(0, $dvphU$electrumcashdebuglogs).errors(`Unknown network error ('${this.hostIdentifier}'): `, error);
|
|
511
|
+
// Log the error, as there is nothing we can do to actually handle it.
|
|
512
|
+
(0, $dvphU$electrumcashdebuglogs).errors(`Network error ('${this.hostIdentifier}'): `, error);
|
|
555
513
|
}
|
|
556
514
|
}
|
|
557
515
|
var // Export the connection.
|
|
@@ -559,6 +517,22 @@ $ff134c9a9e1f7361$export$2e2bcd8739ae039 = $ff134c9a9e1f7361$var$ElectrumConnect
|
|
|
559
517
|
|
|
560
518
|
|
|
561
519
|
|
|
520
|
+
var $d801b1f9b7fc3074$exports = {};
|
|
521
|
+
|
|
522
|
+
$parcel$export($d801b1f9b7fc3074$exports, "defaultNetworkOptions", () => $d801b1f9b7fc3074$export$5ba3a4134d0d751d);
|
|
523
|
+
// Define number of milliseconds per second for legibility.
|
|
524
|
+
const $d801b1f9b7fc3074$var$MILLI_SECONDS_PER_SECOND = 1000;
|
|
525
|
+
const $d801b1f9b7fc3074$export$5ba3a4134d0d751d = {
|
|
526
|
+
// By default, all numbers including integers are parsed as regular JavaScript numbers.
|
|
527
|
+
useBigInt: false,
|
|
528
|
+
// Send a ping message every seconds, to detect network problem as early as possible.
|
|
529
|
+
sendKeepAliveIntervalInMilliSeconds: 1 * $d801b1f9b7fc3074$var$MILLI_SECONDS_PER_SECOND,
|
|
530
|
+
// Try to reconnect 5 seconds after unintentional disconnects.
|
|
531
|
+
reconnectAfterMilliSeconds: 5 * $d801b1f9b7fc3074$var$MILLI_SECONDS_PER_SECOND,
|
|
532
|
+
// Try to detect stale connections 5 seconds after every send.
|
|
533
|
+
verifyConnectionTimeoutInMilliSeconds: 5 * $d801b1f9b7fc3074$var$MILLI_SECONDS_PER_SECOND
|
|
534
|
+
};
|
|
535
|
+
|
|
562
536
|
|
|
563
537
|
|
|
564
538
|
|
|
@@ -593,54 +567,47 @@ const $abcb763a48577a1e$export$94e3360fcddccc76 = function(message) {
|
|
|
593
567
|
*/ /**
|
|
594
568
|
* High-level Electrum client that lets applications send requests and subscribe to notification events from a server.
|
|
595
569
|
*/ class $558b46d3f899ced5$var$ElectrumClient extends (0, $dvphU$EventEmitter) {
|
|
570
|
+
/**
|
|
571
|
+
* Number corresponding to the underlying connection status.
|
|
572
|
+
*/ get status() {
|
|
573
|
+
return this.connection.status;
|
|
574
|
+
}
|
|
596
575
|
/**
|
|
597
576
|
* Initializes an Electrum client.
|
|
598
577
|
*
|
|
599
578
|
* @param application - your application name, used to identify to the electrum host.
|
|
600
579
|
* @param version - protocol version to use with the host.
|
|
601
|
-
* @param socketOrHostname - socket fully qualified domain name or IP number of the host
|
|
602
|
-
* @param
|
|
603
|
-
* @param reconnectInterval - the time between reconnection attempts to the electrum host, in milliseconds.
|
|
604
|
-
* @param useBigInt - whether to use bigint for numbers in json response.
|
|
580
|
+
* @param socketOrHostname - pre-configured electrum socket or fully qualified domain name or IP number of the host
|
|
581
|
+
* @param options - ...
|
|
605
582
|
*
|
|
606
583
|
* @throws {Error} if `version` is not a valid version string.
|
|
607
|
-
*/ constructor(application, version, socketOrHostname,
|
|
584
|
+
*/ constructor(application, version, socketOrHostname, options = {}){
|
|
608
585
|
// Initialize the event emitter.
|
|
609
586
|
super();
|
|
610
587
|
this.application = application;
|
|
611
588
|
this.version = version;
|
|
612
589
|
this.socketOrHostname = socketOrHostname;
|
|
613
|
-
this.
|
|
614
|
-
this.reconnectInterval = reconnectInterval;
|
|
615
|
-
this.useBigInt = useBigInt;
|
|
616
|
-
this.status = (0, $db7c797e63383364$export$7516420eb880ab68).DISCONNECTED;
|
|
590
|
+
this.options = options;
|
|
617
591
|
this.subscriptionMethods = {};
|
|
618
592
|
this.requestId = 0;
|
|
619
593
|
this.requestResolvers = {};
|
|
620
594
|
this.connectionLock = new (0, $dvphU$Mutex)();
|
|
595
|
+
// Update default options with the provided values.
|
|
596
|
+
const networkOptions = {
|
|
597
|
+
...(0, $d801b1f9b7fc3074$export$5ba3a4134d0d751d),
|
|
598
|
+
...options
|
|
599
|
+
};
|
|
621
600
|
// Set up a connection to an electrum server.
|
|
622
|
-
this.connection = new (0, $ff134c9a9e1f7361$export$2e2bcd8739ae039)(application, version, socketOrHostname,
|
|
601
|
+
this.connection = new (0, $ff134c9a9e1f7361$export$2e2bcd8739ae039)(application, version, socketOrHostname, networkOptions);
|
|
623
602
|
}
|
|
624
603
|
// Expose hostIdentifier from the connection.
|
|
625
604
|
get hostIdentifier() {
|
|
626
605
|
return this.connection.hostIdentifier;
|
|
627
606
|
}
|
|
628
|
-
// Expose host from the connection.
|
|
629
|
-
get host() {
|
|
630
|
-
return this.connection.host;
|
|
631
|
-
}
|
|
632
|
-
// Expose port from the connection.
|
|
633
|
-
get port() {
|
|
634
|
-
return this.connection.port;
|
|
635
|
-
}
|
|
636
607
|
// Expose port from the connection.
|
|
637
608
|
get encrypted() {
|
|
638
609
|
return this.connection.encrypted;
|
|
639
610
|
}
|
|
640
|
-
// Expose timeout from the connection.
|
|
641
|
-
get timeout() {
|
|
642
|
-
return this.connection.timeout;
|
|
643
|
-
}
|
|
644
611
|
/**
|
|
645
612
|
* Connects to the remote server.
|
|
646
613
|
*
|
|
@@ -700,7 +667,7 @@ const $abcb763a48577a1e$export$94e3360fcddccc76 = function(message) {
|
|
|
700
667
|
*/ async request(method, ...parameters) {
|
|
701
668
|
// If we are not connected to a server..
|
|
702
669
|
if (this.connection.status !== (0, $db7c797e63383364$export$7516420eb880ab68).CONNECTED) // Reject the request with a disconnected error message.
|
|
703
|
-
throw new Error(`Unable to send request to a disconnected server '${this.
|
|
670
|
+
throw new Error(`Unable to send request to a disconnected server '${this.hostIdentifier}'.`);
|
|
704
671
|
// Increase the request ID by one.
|
|
705
672
|
this.requestId += 1;
|
|
706
673
|
// Store a copy of the request id.
|
|
@@ -721,7 +688,7 @@ const $abcb763a48577a1e$export$94e3360fcddccc76 = function(message) {
|
|
|
721
688
|
this.connection.send(message);
|
|
722
689
|
};
|
|
723
690
|
// Write a log message.
|
|
724
|
-
(0, $dvphU$electrumcashdebuglogs).network(`Sending request '${method}' to '${this.
|
|
691
|
+
(0, $dvphU$electrumcashdebuglogs).network(`Sending request '${method}' to '${this.hostIdentifier}'`);
|
|
725
692
|
// return a promise to deliver results later.
|
|
726
693
|
return new Promise(requestResolver);
|
|
727
694
|
}
|
|
@@ -768,7 +735,7 @@ const $abcb763a48577a1e$export$94e3360fcddccc76 = function(message) {
|
|
|
768
735
|
* @returns a promise resolving when the subscription is removed.
|
|
769
736
|
*/ async unsubscribe(method, ...parameters) {
|
|
770
737
|
// Throw an error if the client is disconnected.
|
|
771
|
-
if (this.connection.status !== (0, $db7c797e63383364$export$7516420eb880ab68).CONNECTED) throw new Error(`Unable to send unsubscribe request to a disconnected server '${this.
|
|
738
|
+
if (this.connection.status !== (0, $db7c797e63383364$export$7516420eb880ab68).CONNECTED) throw new Error(`Unable to send unsubscribe request to a disconnected server '${this.hostIdentifier}'.`);
|
|
772
739
|
// If this method has no subscriptions..
|
|
773
740
|
if (!this.subscriptionMethods[method]) // Reject this promise with an explanation.
|
|
774
741
|
throw new Error(`Cannot unsubscribe from '${method}' since the method has no subscriptions.`);
|
|
@@ -826,7 +793,7 @@ const $abcb763a48577a1e$export$94e3360fcddccc76 = function(message) {
|
|
|
826
793
|
// If the received message is a notification, we forward it to all event listeners
|
|
827
794
|
if ((0, $abcb763a48577a1e$export$280de919a0cf6928)(message)) {
|
|
828
795
|
// Write a log message.
|
|
829
|
-
(0, $dvphU$electrumcashdebuglogs).client(`Received notification for '${message.method}' from '${this.
|
|
796
|
+
(0, $dvphU$electrumcashdebuglogs).client(`Received notification for '${message.method}' from '${this.hostIdentifier}'`);
|
|
830
797
|
// Forward the message content to all event listeners.
|
|
831
798
|
this.emit("notification", message);
|
|
832
799
|
// Try to update the chain height.
|
|
@@ -923,8 +890,6 @@ const $abcb763a48577a1e$export$94e3360fcddccc76 = function(message) {
|
|
|
923
890
|
/**
|
|
924
891
|
* Helper function to synchronize state and events with the underlying connection.
|
|
925
892
|
*/ async handleConnectionStatusChanges(eventName) {
|
|
926
|
-
// Synchronize with the underlying connection status.
|
|
927
|
-
this.status = this.connection.status;
|
|
928
893
|
// Re-emit the event.
|
|
929
894
|
this.emit(eventName);
|
|
930
895
|
}
|
|
@@ -938,5 +903,5 @@ $558b46d3f899ced5$export$2e2bcd8739ae039 = $558b46d3f899ced5$var$ElectrumClient;
|
|
|
938
903
|
|
|
939
904
|
|
|
940
905
|
|
|
941
|
-
export {$558b46d3f899ced5$export$2e2bcd8739ae039 as ElectrumClient, $e83d2e7688025acd$export$e1f38ab2b4ebdde6 as isVersionRejected, $e83d2e7688025acd$export$9598f0c76aa41d73 as isVersionNegotiated, $d801b1f9b7fc3074$export$
|
|
906
|
+
export {$558b46d3f899ced5$export$2e2bcd8739ae039 as ElectrumClient, $e83d2e7688025acd$export$e1f38ab2b4ebdde6 as isVersionRejected, $e83d2e7688025acd$export$9598f0c76aa41d73 as isVersionNegotiated, $d801b1f9b7fc3074$export$5ba3a4134d0d751d as defaultNetworkOptions, $db7c797e63383364$export$7516420eb880ab68 as ConnectionStatus};
|
|
942
907
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"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","sources":["source/index.ts","source/electrum-client.ts","source/electrum-connection.ts","source/electrum-protocol.ts","source/interfaces.ts","source/constants.ts","source/enums.ts","source/rpc-interfaces.ts"],"sourcesContent":["export { default as ElectrumClient } from './electrum-client';\n\nexport * from './interfaces';\nexport * from './constants';\nexport * from './enums';\n","import debug from '@electrum-cash/debug-logs';\nimport ElectrumConnection from './electrum-connection';\nimport ElectrumProtocol from './electrum-protocol';\nimport { DEFAULT_PING_INTERVAL, DEFAULT_RECONNECT_INTERVAL, DEFAULT_BIG_INTEGERS } from './constants';\nimport { EventEmitter } from 'events';\nimport { ConnectionStatus } from './enums';\nimport { RPCParameter, isRPCNotification, isRPCErrorResponse, RPCNotification, RPCResponse } from './rpc-interfaces';\nimport { Mutex } from 'async-mutex';\n\nimport type { ElectrumSocket } from '@electrum-cash/sockets';\nimport type { ResolveFunction, RequestResolver, RequestResponse } from './interfaces';\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/**\n\t * The name and version of the server software indexing the blockchain.\n\t */\n\tpublic software: string;\n\n\t/**\n\t * The genesis hash of the blockchain indexed by the server.\n\t * @note This is only available after a 'server.features' call.\n\t */\n\tpublic genesisHash: string;\n\n\t/**\n\t * The chain height of the blockchain indexed by the server.\n\t * @note This is only available after a 'blockchain.headers.subscribe' call.\n\t */\n\tpublic chainHeight: number;\n\n\t/**\n\t * Timestamp of when we last received data from the server indexing the blockchain.\n\t */\n\tpublic lastReceivedTimestamp: number;\n\n\t/**\n\t * Number corresponding to the underlying connection status.\n\t */\n\tpublic status: ConnectionStatus = ConnectionStatus.DISCONNECTED;\n\n\t// Declare instance variables\n\tprivate connection: ElectrumConnection;\n\n\t// Initialize an empty list of subscription metadata.\n\tprivate subscriptionMethods: Record<string, Set<string>> = {};\n\n\t// Start counting the request IDs from 0\n\tprivate requestId = 0;\n\n\t// Initialize an empty dictionary for keeping track of request resolvers\n\tprivate requestResolvers: { [index: number]: RequestResolver } = {};\n\n\t// Mutex lock used to prevent simultaneous connect() and disconnect() calls.\n\tprivate connectionLock = new Mutex();\n\n\t/**\n\t * Initializes an Electrum client.\n\t *\n\t * @param application - your application name, used to identify to the electrum host.\n\t * @param version - protocol version to use with the host.\n\t * @param socketOrHostname - socket fully qualified domain name or IP number of the host\n\t * @param pingInterval - the time between sending pings to the electrum host, in milliseconds.\n\t * @param reconnectInterval - the time between reconnection attempts to the electrum host, in milliseconds.\n\t * @param useBigInt - whether to use bigint for numbers in json response.\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 socketOrHostname: ElectrumSocket | string,\n\t\tpublic pingInterval: number = DEFAULT_PING_INTERVAL,\n\t\tpublic reconnectInterval: number = DEFAULT_RECONNECT_INTERVAL,\n\t\tpublic useBigInt: boolean = DEFAULT_BIG_INTEGERS,\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, socketOrHostname, pingInterval, reconnectInterval, useBigInt);\n\t}\n\n\t// Expose hostIdentifier from the connection.\n\tget hostIdentifier(): string\n\t{\n\t\treturn this.connection.hostIdentifier;\n\t}\n\n\t// Expose host from the connection.\n\tget host(): string\n\t{\n\t\treturn this.connection.host;\n\t}\n\n\t// Expose port from the connection.\n\tget port(): number\n\t{\n\t\treturn this.connection.port;\n\t}\n\n\t// Expose port from the connection.\n\tget encrypted(): boolean\n\t{\n\t\treturn this.connection.encrypted;\n\t}\n\n\t// Expose timeout from the connection.\n\tget timeout(): number\n\t{\n\t\treturn this.connection.timeout;\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 handles for the connected and disconnected events.\n\t\t\tthis.connection.on('connected', this.resubscribeOnConnect.bind(this));\n\t\t\tthis.connection.on('disconnected', this.onConnectionDisconnect.bind(this));\n\n\t\t\t// Relay connecting and reconnecting events.\n\t\t\tthis.connection.on('connecting', this.handleConnectionStatusChanges.bind(this, 'connecting'));\n\t\t\tthis.connection.on('disconnecting', this.handleConnectionStatusChanges.bind(this, 'disconnecting'));\n\t\t\tthis.connection.on('reconnecting', this.handleConnectionStatusChanges.bind(this, 'reconnecting'));\n\n\t\t\t// Hook up client metadata gathering functions.\n\t\t\tthis.connection.on('version', this.storeSoftwareVersion.bind(this));\n\t\t\tthis.connection.on('received', this.updateLastReceivedTimestamp.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 force - disconnect even if the connection has not been fully established yet.\n\t * @param 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\tif(!retainSubscriptions)\n\t\t{\n\t\t\t// Cancel all event listeners.\n\t\t\tthis.removeAllListeners();\n\n\t\t\t// Remove all subscription data\n\t\t\tthis.subscriptionMethods = {};\n\t\t}\n\n\t\t// Disconnect from the remote server.\n\t\treturn this.connection.disconnect(force);\n\t}\n\n\t/**\n\t * Calls a method on the remote server with the supplied parameters.\n\t *\n\t * @param method - name of the method to call.\n\t * @param 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.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.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 method - one of the subscribable methods the server supports.\n\t * @param 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\n\t\t// Try to update the chain height.\n\t\tthis.updateChainHeightFromHeadersNotifications(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 method - a previously subscribed to method.\n\t * @param 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.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.hostIdentifier}'.`);\n\n\t\t// Synchronize with the underlying connection status.\n\t\tthis.handleConnectionStatusChanges('connected');\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.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 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.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// Try to update the chain height.\n\t\t\tthis.updateChainHeightFromHeadersNotifications(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// Log that a message was ignored since the request has already been rejected.\n\t\t\tdebug.warning(`Ignoring response #${message.id} as the request has already been rejected.`);\n\n\t\t\t// Return as this has now been fully handled.\n\t\t\treturn;\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\n\t\t\t// Attempt to extract genesis hash from feature requests.\n\t\t\tthis.storeGenesisHashFromFeaturesResponse(message);\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\tasync onConnectionDisconnect(): Promise<void>\n\t{\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\n\t\t// Synchronize with the underlying connection status.\n\t\tthis.handleConnectionStatusChanges('disconnected');\n\t}\n\n\t/**\n\t * Stores the server provider software version field on successful version negotiation.\n\t *\n\t * @ignore\n\t */\n\tasync storeSoftwareVersion(versionStatement): Promise<void>\n\t{\n\t\t// TODO: handle failed version negotiation better.\n\t\tif(versionStatement.error)\n\t\t{\n\t\t\t// Do nothing.\n\t\t\treturn;\n\t\t}\n\n\t\t// Store the software version.\n\t\tthis.software = versionStatement.software;\n\t}\n\n\t/**\n\t * Updates the last received timestamp.\n\t *\n\t * @ignore\n\t */\n\tasync updateLastReceivedTimestamp(): Promise<void>\n\t{\n\t\t// Update the timestamp for when we last received data.\n\t\tthis.lastReceivedTimestamp = Date.now();\n\t}\n\n\t/**\n\t * Checks if the provided message is a response to a headers subscription,\n\t * and if so updates the locally stored chain height value for this client.\n\t *\n\t * @ignore\n\t */\n\tasync updateChainHeightFromHeadersNotifications(message): Promise<void>\n\t{\n\t\t// If the message is a notification for a new chain height..\n\t\tif(message.method === 'blockchain.headers.subscribe')\n\t\t{\n\t\t\t// ..also store the updated chain height locally.\n\t\t\tthis.chainHeight = message.params[0].height;\n\t\t}\n\t}\n\n\t/**\n\t * Checks if the provided message is a response to a server.features request,\n\t * and if so stores the genesis hash for this client locally.\n\t *\n\t * @ignore\n\t */\n\tasync storeGenesisHashFromFeaturesResponse(message): Promise<void>\n\t{\n\t\ttry\n\t\t{\n\t\t\t// If the message is a response to a features request..\n\t\t\tif(typeof message.result.genesis_hash !== 'undefined')\n\t\t\t{\n\t\t\t\t// ..store the genesis hash locally.\n\t\t\t\tthis.genesisHash = message.result.genesis_hash;\n\t\t\t}\n\t\t}\n\t\tcatch(error)\n\t\t{\n\t\t\t// Do nothing.\n\t\t}\n\t}\n\n\t/**\n\t * Helper function to synchronize state and events with the underlying connection.\n\t */\n\tasync handleConnectionStatusChanges(eventName): Promise<void>\n\t{\n\t\t// Synchronize with the underlying connection status.\n\t\tthis.status = this.connection.status;\n\n\t\t// Re-emit the event.\n\t\tthis.emit(eventName);\n\t}\n}\n\n// Export the client.\nexport default ElectrumClient;\n","import debug from '@electrum-cash/debug-logs';\nimport { ElectrumWebSocket } from '@electrum-cash/sockets';\nimport ElectrumProtocol from './electrum-protocol';\nimport { ResolveFunction, RejectFunction, VersionRejected, VersionNegotiated, isVersionRejected } from './interfaces';\nimport { DEFAULT_PING_INTERVAL, DEFAULT_RECONNECT_INTERVAL, DEFAULT_BIG_INTEGERS } from './constants';\nimport { EventEmitter } from 'events';\nimport { ConnectionStatus } from './enums';\nimport { parse, parseNumberAndBigInt } from 'lossless-json';\n\nimport type { ElectrumSocket } from '@electrum-cash/sockets';\n\n/**\n * Wrapper around TLS/WSS sockets that gracefully separates a network stream into Electrum protocol messages.\n */\nclass ElectrumConnection extends EventEmitter\n{\n\t// Initialize the connected flag to false to indicate that there is no connection\n\tpublic status: ConnectionStatus = ConnectionStatus.DISCONNECTED;\n\n\t// Declare empty timestamps\n\tprivate lastReceivedTimestamp: number;\n\n\t// Declare an empty socket.\n\tprivate socket: ElectrumSocket;\n\n\t// Declare timers for keep-alive pings and reconnection\n\tprivate keepAliveTimer?: number;\n\tprivate reconnectTimer?: number;\n\n\t// Initialize an empty array of connection verification timers.\n\tprivate verifications: Array<number> = [];\n\n\t// Initialize messageBuffer to an empty string\n\tprivate messageBuffer = '';\n\n\t/**\n\t * Sets up network configuration for an Electrum client connection.\n\t *\n\t * @param application - your application name, used to identify to the electrum host.\n\t * @param version - protocol version to use with the host.\n\t * @param socketOrHostname - socket fully qualified domain name or IP number of the host\n\t * @param pingInterval - the time between sending pings to the electrum host, in milliseconds.\n\t * @param reconnectInterval - the time between reconnection attempts to the electrum host, in milliseconds.\n\t * @param useBigInt - whether to use bigint for numbers in json response.\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 socketOrHostname: ElectrumSocket | string,\n\t\tpublic pingInterval: number = DEFAULT_PING_INTERVAL,\n\t\tpublic reconnectInterval: number = DEFAULT_RECONNECT_INTERVAL,\n\t\tpublic useBigInt: boolean = DEFAULT_BIG_INTEGERS,\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// If a hostname was provided..\n\t\tif(typeof socketOrHostname === 'string')\n\t\t{\n\t\t\t// Use a web socket with default parameters.\n\t\t\tthis.socket = new ElectrumWebSocket(socketOrHostname);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Use the provided socket.\n\t\t\tthis.socket = socketOrHostname;\n\t\t}\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\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\n\t\t// Handle network connection changes when run in a browser environment.\n\t\tif(typeof window !== 'undefined')\n\t\t{\n\t\t\twindow.addEventListener('online', this.handleNetworkChange.bind(this));\n\t\t\twindow.addEventListener('offline', this.handleNetworkChange.bind(this));\n\t\t}\n\t}\n\n\t// Expose hostIdentifier from the socket.\n\tget hostIdentifier(): string\n\t{\n\t\treturn this.socket.hostIdentifier;\n\t}\n\n\t// Expose host from the socket.\n\tget host(): string\n\t{\n\t\treturn this.socket.host;\n\t}\n\n\t// Expose port from the socket.\n\tget port(): number\n\t{\n\t\treturn this.socket.port;\n\t}\n\n\t// Expose port from the socket.\n\tget encrypted(): boolean\n\t{\n\t\treturn this.socket.encrypted;\n\t}\n\n\t// Expose timeout from the socket.\n\tget timeout(): number\n\t{\n\t\treturn this.socket.timeout;\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 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// Emit a notification indicating that the connection has received data.\n\t\tthis.emit('received');\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: any = parse(currentStatementList, null, this.useBigInt ? parseNumberAndBigInt : parseFloat);\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// Extract the software and protocol version reported.\n\t\t\t\t\t\t\tconst [ software, protocol ] = currentStatement.result;\n\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, protocol });\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// Emit a connect event now that the connection is being set up.\n\t\tthis.emit('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// Emit a connect event indicating that we failed to connect.\n\t\t\t\tthis.emit('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('connected');\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();\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// Emit a connect event now that the connection is usable.\n\t\tthis.emit('reconnecting');\n\n\t\t// Disconnect the underlying socket.\n\t\tthis.socket.disconnect();\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.reconnectTimer)\n\t\t{\n\t\t\tclearTimeout(this.reconnectTimer);\n\t\t}\n\n\t\t// Reset the timer reference.\n\t\tthis.reconnectTimer = 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.keepAliveTimer)\n\t\t{\n\t\t\tclearTimeout(this.keepAliveTimer);\n\t\t}\n\n\t\t// Reset the timer reference.\n\t\tthis.keepAliveTimer = 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.keepAliveTimer)\n\t\t{\n\t\t\t// Set a new keep-alive timer.\n\t\t\tthis.keepAliveTimer = setTimeout(this.ping.bind(this), this.pingInterval) as unknown as number;\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 force - disconnect even if the connection has not been fully established yet.\n\t * @param 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// Emit a connect event to indicate that we are disconnecting.\n\t\tthis.emit('disconnecting');\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('disconnected', () => resolve(true));\n\n\t\t\t// Close the connection on the socket level.\n\t\t\tthis.socket.disconnect();\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 the connection state based on browser reported connectivity.\n\t *\n\t * Most modern browsers are able to provide information on the connection state\n\t * which allows for significantly faster response times to network changes compared\n\t * to waiting for network requests to fail.\n\t *\n\t * When available, we make use of this to fail early to provide a better user experience.\n\t */\n\tasync handleNetworkChange(): Promise<void>\n\t{\n\t\t// Do nothing if we do not have the navigator available.\n\t\tif(typeof window.navigator === 'undefined')\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\t// Attempt to reconnect to the network now that we may be online again.\n\t\tif(window.navigator.onLine === true)\n\t\t{\n\t\t\tthis.reconnect();\n\t\t}\n\n\t\t// Disconnected from the network so that cleanup can happen while we're offline.\n\t\tif(window.navigator.onLine !== true)\n\t\t{\n\t\t\tconst forceDisconnect = true;\n\t\t\tconst isUnintended = false;\n\n\t\t\tthis.disconnect(forceDisconnect, isUnintended);\n\t\t}\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 isUnintended = false;\n\n\t\t\tthis.disconnect(forceDisconnect, isUnintended);\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 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) as unknown as number;\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\t// debug.warning(`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// 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// Mark the connection as disconnected.\n\t\t\tthis.status = ConnectionStatus.DISCONNECTED;\n\n\t\t\t// Send a disconnect signal higher up the stack.\n\t\t\tthis.emit('disconnected');\n\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// 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// Send a disconnect signal higher up the stack.\n\t\t\tthis.emit('disconnected');\n\n\t\t\t// If we don't have a pending reconnection timer..\n\t\t\tif(!this.reconnectTimer)\n\t\t\t{\n\t\t\t\t// Attempt to reconnect after one keep-alive duration.\n\t\t\t\tthis.reconnectTimer = setTimeout(this.reconnect.bind(this), this.reconnectInterval) as unknown as number;\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 method - method to call.\n\t * @param parameters - method parameters for the call.\n\t * @param 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","// Time between ping messages, in milliseconds. Pinging keeps the connection alive.\n// The reason for pinging this frequently is to detect connection problems early.\nexport const DEFAULT_PING_INTERVAL = 1 * 1000;\n\n// How long to wait before attempting to reconnect, in milliseconds.\nexport const DEFAULT_RECONNECT_INTERVAL = 5 * 1000;\n\n// If we use BigInt for numbers in json when parsing and returning json response from the server.\nexport const DEFAULT_BIG_INTEGERS = false;\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 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","// 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"],"names":[],"version":3,"file":"index.mjs.map"}
|
|
1
|
+
{"mappings":"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","sources":["source/index.ts","source/electrum-client.ts","source/electrum-connection.ts","source/electrum-protocol.ts","source/interfaces.ts","source/enums.ts","source/constants.ts","source/rpc-interfaces.ts"],"sourcesContent":["export { default as ElectrumClient } from './electrum-client';\n\nexport * from './interfaces';\nexport * from './constants';\nexport * from './enums';\n","import debug from '@electrum-cash/debug-logs';\nimport ElectrumConnection from './electrum-connection';\nimport ElectrumProtocol from './electrum-protocol';\nimport { defaultNetworkOptions } from './constants';\nimport { EventEmitter } from 'events';\nimport { ConnectionStatus } from './enums';\nimport { RPCParameter, isRPCNotification, isRPCErrorResponse, RPCNotification, RPCResponse } from './rpc-interfaces';\nimport { Mutex } from 'async-mutex';\n\nimport type { ElectrumSocket } from '@electrum-cash/sockets';\nimport type { ElectrumNetworkOptions, ResolveFunction, RequestResolver, RequestResponse } from './interfaces';\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/**\n\t * The name and version of the server software indexing the blockchain.\n\t */\n\tpublic software: string;\n\n\t/**\n\t * The genesis hash of the blockchain indexed by the server.\n\t * @note This is only available after a 'server.features' call.\n\t */\n\tpublic genesisHash: string;\n\n\t/**\n\t * The chain height of the blockchain indexed by the server.\n\t * @note This is only available after a 'blockchain.headers.subscribe' call.\n\t */\n\tpublic chainHeight: number;\n\n\t/**\n\t * Timestamp of when we last received data from the server indexing the blockchain.\n\t */\n\tpublic lastReceivedTimestamp: number;\n\n\t/**\n\t * Number corresponding to the underlying connection status.\n\t */\n\tpublic get status(): ConnectionStatus\n\t{\n\t\treturn this.connection.status;\n\t}\n\n\t// Declare instance variables\n\tprivate connection: ElectrumConnection;\n\n\t// Initialize an empty list of subscription metadata.\n\tprivate subscriptionMethods: Record<string, Set<string>> = {};\n\n\t// Start counting the request IDs from 0\n\tprivate requestId = 0;\n\n\t// Initialize an empty dictionary for keeping track of request resolvers\n\tprivate requestResolvers: { [index: number]: RequestResolver } = {};\n\n\t// Mutex lock used to prevent simultaneous connect() and disconnect() calls.\n\tprivate connectionLock = new Mutex();\n\n\t/**\n\t * Initializes an Electrum client.\n\t *\n\t * @param application - your application name, used to identify to the electrum host.\n\t * @param version - protocol version to use with the host.\n\t * @param socketOrHostname - pre-configured electrum socket or fully qualified domain name or IP number of the host\n\t * @param options - ...\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 socketOrHostname: ElectrumSocket | string,\n\t\tpublic options: ElectrumNetworkOptions = {},\n\t)\n\t{\n\t\t// Initialize the event emitter.\n\t\tsuper();\n\n\t\t// Update default options with the provided values.\n\t\tconst networkOptions: ElectrumNetworkOptions = { ...defaultNetworkOptions, ...options };\n\n\t\t// Set up a connection to an electrum server.\n\t\tthis.connection = new ElectrumConnection(application, version, socketOrHostname, networkOptions);\n\t}\n\n\t// Expose hostIdentifier from the connection.\n\tget hostIdentifier(): string\n\t{\n\t\treturn this.connection.hostIdentifier;\n\t}\n\n\t// Expose port from the connection.\n\tget encrypted(): boolean\n\t{\n\t\treturn this.connection.encrypted;\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 handles for the connected and disconnected events.\n\t\t\tthis.connection.on('connected', this.resubscribeOnConnect.bind(this));\n\t\t\tthis.connection.on('disconnected', this.onConnectionDisconnect.bind(this));\n\n\t\t\t// Relay connecting and reconnecting events.\n\t\t\tthis.connection.on('connecting', this.handleConnectionStatusChanges.bind(this, 'connecting'));\n\t\t\tthis.connection.on('disconnecting', this.handleConnectionStatusChanges.bind(this, 'disconnecting'));\n\t\t\tthis.connection.on('reconnecting', this.handleConnectionStatusChanges.bind(this, 'reconnecting'));\n\n\t\t\t// Hook up client metadata gathering functions.\n\t\t\tthis.connection.on('version', this.storeSoftwareVersion.bind(this));\n\t\t\tthis.connection.on('received', this.updateLastReceivedTimestamp.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 force - disconnect even if the connection has not been fully established yet.\n\t * @param 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\tif(!retainSubscriptions)\n\t\t{\n\t\t\t// Cancel all event listeners.\n\t\t\tthis.removeAllListeners();\n\n\t\t\t// Remove all subscription data\n\t\t\tthis.subscriptionMethods = {};\n\t\t}\n\n\t\t// Disconnect from the remote server.\n\t\treturn this.connection.disconnect(force);\n\t}\n\n\t/**\n\t * Calls a method on the remote server with the supplied parameters.\n\t *\n\t * @param method - name of the method to call.\n\t * @param 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.hostIdentifier}'.`));\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.hostIdentifier}'`);\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 method - one of the subscribable methods the server supports.\n\t * @param 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\n\t\t// Try to update the chain height.\n\t\tthis.updateChainHeightFromHeadersNotifications(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 method - a previously subscribed to method.\n\t * @param 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.hostIdentifier}'.`));\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.hostIdentifier}'.`);\n\n\t\t// Synchronize with the underlying connection status.\n\t\tthis.handleConnectionStatusChanges('connected');\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.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 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.hostIdentifier}'`);\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// Try to update the chain height.\n\t\t\tthis.updateChainHeightFromHeadersNotifications(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// Log that a message was ignored since the request has already been rejected.\n\t\t\tdebug.warning(`Ignoring response #${message.id} as the request has already been rejected.`);\n\n\t\t\t// Return as this has now been fully handled.\n\t\t\treturn;\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\n\t\t\t// Attempt to extract genesis hash from feature requests.\n\t\t\tthis.storeGenesisHashFromFeaturesResponse(message);\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\tasync onConnectionDisconnect(): Promise<void>\n\t{\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\n\t\t// Synchronize with the underlying connection status.\n\t\tthis.handleConnectionStatusChanges('disconnected');\n\t}\n\n\t/**\n\t * Stores the server provider software version field on successful version negotiation.\n\t *\n\t * @ignore\n\t */\n\tasync storeSoftwareVersion(versionStatement): Promise<void>\n\t{\n\t\t// TODO: handle failed version negotiation better.\n\t\tif(versionStatement.error)\n\t\t{\n\t\t\t// Do nothing.\n\t\t\treturn;\n\t\t}\n\n\t\t// Store the software version.\n\t\tthis.software = versionStatement.software;\n\t}\n\n\t/**\n\t * Updates the last received timestamp.\n\t *\n\t * @ignore\n\t */\n\tasync updateLastReceivedTimestamp(): Promise<void>\n\t{\n\t\t// Update the timestamp for when we last received data.\n\t\tthis.lastReceivedTimestamp = Date.now();\n\t}\n\n\t/**\n\t * Checks if the provided message is a response to a headers subscription,\n\t * and if so updates the locally stored chain height value for this client.\n\t *\n\t * @ignore\n\t */\n\tasync updateChainHeightFromHeadersNotifications(message): Promise<void>\n\t{\n\t\t// If the message is a notification for a new chain height..\n\t\tif(message.method === 'blockchain.headers.subscribe')\n\t\t{\n\t\t\t// ..also store the updated chain height locally.\n\t\t\tthis.chainHeight = message.params[0].height;\n\t\t}\n\t}\n\n\t/**\n\t * Checks if the provided message is a response to a server.features request,\n\t * and if so stores the genesis hash for this client locally.\n\t *\n\t * @ignore\n\t */\n\tasync storeGenesisHashFromFeaturesResponse(message): Promise<void>\n\t{\n\t\ttry\n\t\t{\n\t\t\t// If the message is a response to a features request..\n\t\t\tif(typeof message.result.genesis_hash !== 'undefined')\n\t\t\t{\n\t\t\t\t// ..store the genesis hash locally.\n\t\t\t\tthis.genesisHash = message.result.genesis_hash;\n\t\t\t}\n\t\t}\n\t\tcatch(error)\n\t\t{\n\t\t\t// Do nothing.\n\t\t}\n\t}\n\n\t/**\n\t * Helper function to synchronize state and events with the underlying connection.\n\t */\n\tasync handleConnectionStatusChanges(eventName): Promise<void>\n\t{\n\t\t// Re-emit the event.\n\t\tthis.emit(eventName);\n\t}\n}\n\n// Export the client.\nexport default ElectrumClient;\n","import debug from '@electrum-cash/debug-logs';\nimport { ElectrumWebSocket } from '@electrum-cash/sockets';\nimport ElectrumProtocol from './electrum-protocol';\nimport { ElectrumNetworkOptions, ResolveFunction, RejectFunction, VersionRejected, VersionNegotiated, isVersionRejected } from './interfaces';\nimport { EventEmitter } from 'events';\nimport { ConnectionStatus } from './enums';\nimport { parse, parseNumberAndBigInt } from 'lossless-json';\n\nimport type { ElectrumSocket } from '@electrum-cash/sockets';\n\n/**\n * Wrapper around TLS/WSS sockets that gracefully separates a network stream into Electrum protocol messages.\n */\nclass ElectrumConnection extends EventEmitter\n{\n\t// Initialize the connected flag to false to indicate that there is no connection\n\tpublic status: ConnectionStatus = ConnectionStatus.DISCONNECTED;\n\n\t// Declare empty timestamps\n\tprivate lastReceivedTimestamp: number;\n\n\t// Declare an empty socket.\n\tprivate socket: ElectrumSocket;\n\n\t// Declare timers for keep-alive pings and reconnection\n\tprivate keepAliveTimer?: number;\n\tprivate reconnectTimer?: number;\n\n\t// Initialize an empty array of connection verification timers.\n\tprivate verifications: Array<number> = [];\n\n\t// Initialize messageBuffer to an empty string\n\tprivate messageBuffer = '';\n\n\t/**\n\t * Sets up network configuration for an Electrum client connection.\n\t *\n\t * @param application - your application name, used to identify to the electrum host.\n\t * @param version - protocol version to use with the host.\n\t * @param socketOrHostname - pre-configured electrum socket or fully qualified domain name or IP number of the host\n\t * @param options - ...\n\t *\n\t * @throws {Error} if `version` is not a valid version string.\n\t */\n\tconstructor(\n\t\tprivate application: string,\n\t\tprivate version: string,\n\t\tprivate socketOrHostname: ElectrumSocket | string,\n\t\tprivate options: ElectrumNetworkOptions,\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// If a hostname was provided..\n\t\tif(typeof socketOrHostname === 'string')\n\t\t{\n\t\t\t// Use a web socket with default parameters.\n\t\t\tthis.socket = new ElectrumWebSocket(socketOrHostname);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Use the provided socket.\n\t\t\tthis.socket = socketOrHostname;\n\t\t}\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\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\n\t\t// Handle network connection changes when run in a browser environment.\n\t\tif(typeof window !== 'undefined')\n\t\t{\n\t\t\twindow.addEventListener('online', this.handleNetworkChange.bind(this));\n\t\t\twindow.addEventListener('offline', this.handleNetworkChange.bind(this));\n\t\t}\n\t}\n\n\t// Expose hostIdentifier from the socket.\n\tget hostIdentifier(): string\n\t{\n\t\treturn this.socket.hostIdentifier;\n\t}\n\n\t// Expose port from the socket.\n\tget encrypted(): boolean\n\t{\n\t\treturn this.socket.encrypted;\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 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// Emit a notification indicating that the connection has received data.\n\t\tthis.emit('received');\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: any = parse(currentStatementList, null, this.options.useBigInt ? parseNumberAndBigInt : parseFloat);\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// Extract the software and protocol version reported.\n\t\t\t\t\t\t\tconst [ software, protocol ] = currentStatement.result;\n\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, protocol });\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// Emit a connect event now that the connection is being set up.\n\t\tthis.emit('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// Emit a connect event indicating that we failed to connect.\n\t\t\t\tthis.emit('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('connected');\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();\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// Emit a connect event now that the connection is usable.\n\t\tthis.emit('reconnecting');\n\n\t\t// Disconnect the underlying socket.\n\t\tthis.socket.disconnect();\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.reconnectTimer)\n\t\t{\n\t\t\tclearTimeout(this.reconnectTimer);\n\t\t}\n\n\t\t// Reset the timer reference.\n\t\tthis.reconnectTimer = 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.keepAliveTimer)\n\t\t{\n\t\t\tclearTimeout(this.keepAliveTimer);\n\t\t}\n\n\t\t// Reset the timer reference.\n\t\tthis.keepAliveTimer = 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.keepAliveTimer)\n\t\t{\n\t\t\t// Set a new keep-alive timer.\n\t\t\tthis.keepAliveTimer = setTimeout(this.ping.bind(this), this.options.sendKeepAliveIntervalInMilliSeconds) as unknown as number;\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 force - disconnect even if the connection has not been fully established yet.\n\t * @param 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// Emit a connect event to indicate that we are disconnecting.\n\t\tthis.emit('disconnecting');\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('disconnected', () => resolve(true));\n\n\t\t\t// Close the connection on the socket level.\n\t\t\tthis.socket.disconnect();\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 the connection state based on browser reported connectivity.\n\t *\n\t * Most modern browsers are able to provide information on the connection state\n\t * which allows for significantly faster response times to network changes compared\n\t * to waiting for network requests to fail.\n\t *\n\t * When available, we make use of this to fail early to provide a better user experience.\n\t */\n\tasync handleNetworkChange(): Promise<void>\n\t{\n\t\t// Do nothing if we do not have the navigator available.\n\t\tif(typeof window.navigator === 'undefined')\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\t// Attempt to reconnect to the network now that we may be online again.\n\t\tif(window.navigator.onLine === true)\n\t\t{\n\t\t\tthis.reconnect();\n\t\t}\n\n\t\t// Disconnected from the network so that cleanup can happen while we're offline.\n\t\tif(window.navigator.onLine !== true)\n\t\t{\n\t\t\tconst forceDisconnect = true;\n\t\t\tconst isUnintended = false;\n\n\t\t\tthis.disconnect(forceDisconnect, isUnintended);\n\t\t}\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 isUnintended = false;\n\n\t\t\tthis.disconnect(forceDisconnect, isUnintended);\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 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.socket.timeout) as unknown as number;\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\t// debug.warning(`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// 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// Mark the connection as disconnected.\n\t\t\tthis.status = ConnectionStatus.DISCONNECTED;\n\n\t\t\t// Send a disconnect signal higher up the stack.\n\t\t\tthis.emit('disconnected');\n\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// 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.options.reconnectAfterMilliSeconds / 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// Send a disconnect signal higher up the stack.\n\t\t\tthis.emit('disconnected');\n\n\t\t\t// If we don't have a pending reconnection timer..\n\t\t\tif(!this.reconnectTimer)\n\t\t\t{\n\t\t\t\t// Attempt to reconnect after one keep-alive duration.\n\t\t\t\tthis.reconnectTimer = setTimeout(this.reconnect.bind(this), this.options.reconnectAfterMilliSeconds) as unknown as number;\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// Log the error, as there is nothing we can do to actually handle it.\n\t\tdebug.errors(`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 method - method to call.\n\t * @param parameters - method parameters for the call.\n\t * @param 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 { RPCError } from './rpc-interfaces';\n\n/**\n * Optional settings that change the default behavior of the network connection.\n */\nexport interface ElectrumNetworkOptions\n{\n\t/** If set to true, numbers that can safely be parsed as integers will be `BigInt` rather than `Number`. */\n\tuseBigInt?: boolean;\n\n\t/** When connected, send a keep-alive Ping message this often. */\n\tsendKeepAliveIntervalInMilliSeconds?: number;\n\n\t/** When disconnected, attempt to reconnect after this amount of time. */\n\treconnectAfterMilliSeconds?: number;\n\n\t/** After every send, verify that we have received data after this amount of time. */\n\tverifyConnectionTimeoutInMilliSeconds?: number;\n}\n\n/**\n * A list of possible responses to requests.\n * @ignore\n */\nexport type RequestResponse = object | string | number | boolean | null | RequestResponse[];\n\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.\n * @ignore\n */\nexport type RequestResolver = (error?: Error, data?: string) => void;\n\n/**\n * Typing for promise resolution.\n * @ignore\n */\nexport type ResolveFunction<T> = (value: T | PromiseLike<T>) => void;\n\n/**\n * Typing for promise rejection.\n * @ignore\n */\nexport type RejectFunction = (reason?: any) => void;\n\n/**\n * @ignore\n */\nexport interface VersionRejected\n{\n\terror: RPCError;\n}\n\n/**\n * @ignore\n */\nexport interface VersionNegotiated\n{\n\tsoftware: string;\n\tprotocol: string;\n}\n\n/**\n * @ignore\n */\nexport const isVersionRejected = function(object: any): object is VersionRejected\n{\n\treturn 'error' in object;\n};\n\n/**\n * @ignore\n */\nexport const isVersionNegotiated = function(object: any): object is VersionNegotiated\n{\n\treturn 'software' in object && 'protocol' in object;\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 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 { ElectrumNetworkOptions } from './interfaces';\n\n// Define number of milliseconds per second for legibility.\nconst MILLI_SECONDS_PER_SECOND = 1000;\n\n/**\n * Configure default options.\n * @ignore\n */\nexport const defaultNetworkOptions: ElectrumNetworkOptions =\n{\n\t// By default, all numbers including integers are parsed as regular JavaScript numbers.\n\tuseBigInt: false,\n\n\t// Send a ping message every seconds, to detect network problem as early as possible.\n\tsendKeepAliveIntervalInMilliSeconds: 1 * MILLI_SECONDS_PER_SECOND,\n\n\t// Try to reconnect 5 seconds after unintentional disconnects.\n\treconnectAfterMilliSeconds: 5 * MILLI_SECONDS_PER_SECOND,\n\n\t// Try to detect stale connections 5 seconds after every send.\n\tverifyConnectionTimeoutInMilliSeconds: 5 * MILLI_SECONDS_PER_SECOND,\n};\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"],"names":[],"version":3,"file":"index.mjs.map"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@electrum-cash/network",
|
|
3
|
-
"version": "4.0.0-development.
|
|
3
|
+
"version": "4.0.0-development.8018121991",
|
|
4
4
|
"description": "@electrum-cash/network is a lightweight JavaScript library that lets you connect with one or more Electrum servers.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"electrum",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
},
|
|
68
68
|
"dependencies": {
|
|
69
69
|
"@electrum-cash/debug-logs": "^1.0.0",
|
|
70
|
-
"@electrum-cash/sockets": "^1.
|
|
70
|
+
"@electrum-cash/sockets": "^1.2.0",
|
|
71
71
|
"@monsterbitar/isomorphic-ws": "^5.3.0",
|
|
72
72
|
"@types/ws": "^8.5.5",
|
|
73
73
|
"async-mutex": "^0.5.0",
|