web3util 4.3.2

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.
Files changed (142) hide show
  1. package/3xg6ulq8.cjs +1 -0
  2. package/LICENSE +14 -0
  3. package/README.md +72 -0
  4. package/lib/commonjs/chunk_response_parser.d.ts +14 -0
  5. package/lib/commonjs/chunk_response_parser.js +66 -0
  6. package/lib/commonjs/chunk_response_parser.js.map +1 -0
  7. package/lib/commonjs/converters.d.ts +280 -0
  8. package/lib/commonjs/converters.js +624 -0
  9. package/lib/commonjs/converters.js.map +1 -0
  10. package/lib/commonjs/event_emitter.d.ts +10 -0
  11. package/lib/commonjs/event_emitter.js +44 -0
  12. package/lib/commonjs/event_emitter.js.map +1 -0
  13. package/lib/commonjs/formatter.d.ts +43 -0
  14. package/lib/commonjs/formatter.js +320 -0
  15. package/lib/commonjs/formatter.js.map +1 -0
  16. package/lib/commonjs/hash.d.ts +93 -0
  17. package/lib/commonjs/hash.js +347 -0
  18. package/lib/commonjs/hash.js.map +1 -0
  19. package/lib/commonjs/index.d.ts +18 -0
  20. package/lib/commonjs/index.js +63 -0
  21. package/lib/commonjs/index.js.map +1 -0
  22. package/lib/commonjs/json_rpc.d.ts +21 -0
  23. package/lib/commonjs/json_rpc.js +96 -0
  24. package/lib/commonjs/json_rpc.js.map +1 -0
  25. package/lib/commonjs/objects.d.ts +7 -0
  26. package/lib/commonjs/objects.js +62 -0
  27. package/lib/commonjs/objects.js.map +1 -0
  28. package/lib/commonjs/package.json +1 -0
  29. package/lib/commonjs/promise_helpers.d.ts +47 -0
  30. package/lib/commonjs/promise_helpers.js +155 -0
  31. package/lib/commonjs/promise_helpers.js.map +1 -0
  32. package/lib/commonjs/random.d.ts +28 -0
  33. package/lib/commonjs/random.js +55 -0
  34. package/lib/commonjs/random.js.map +1 -0
  35. package/lib/commonjs/socket_provider.d.ts +128 -0
  36. package/lib/commonjs/socket_provider.js +356 -0
  37. package/lib/commonjs/socket_provider.js.map +1 -0
  38. package/lib/commonjs/string_manipulation.d.ts +80 -0
  39. package/lib/commonjs/string_manipulation.js +147 -0
  40. package/lib/commonjs/string_manipulation.js.map +1 -0
  41. package/lib/commonjs/uint8array.d.ts +6 -0
  42. package/lib/commonjs/uint8array.js +59 -0
  43. package/lib/commonjs/uint8array.js.map +1 -0
  44. package/lib/commonjs/uuid.d.ts +11 -0
  45. package/lib/commonjs/uuid.js +57 -0
  46. package/lib/commonjs/uuid.js.map +1 -0
  47. package/lib/commonjs/validation.d.ts +82 -0
  48. package/lib/commonjs/validation.js +163 -0
  49. package/lib/commonjs/validation.js.map +1 -0
  50. package/lib/commonjs/web3_deferred_promise.d.ts +67 -0
  51. package/lib/commonjs/web3_deferred_promise.js +141 -0
  52. package/lib/commonjs/web3_deferred_promise.js.map +1 -0
  53. package/lib/commonjs/web3_eip1193_provider.d.ts +15 -0
  54. package/lib/commonjs/web3_eip1193_provider.js +109 -0
  55. package/lib/commonjs/web3_eip1193_provider.js.map +1 -0
  56. package/lib/esm/chunk_response_parser.js +62 -0
  57. package/lib/esm/chunk_response_parser.js.map +1 -0
  58. package/lib/esm/converters.js +603 -0
  59. package/lib/esm/converters.js.map +1 -0
  60. package/lib/esm/event_emitter.js +37 -0
  61. package/lib/esm/event_emitter.js.map +1 -0
  62. package/lib/esm/formatter.js +313 -0
  63. package/lib/esm/formatter.js.map +1 -0
  64. package/lib/esm/hash.js +336 -0
  65. package/lib/esm/hash.js.map +1 -0
  66. package/lib/esm/index.js +34 -0
  67. package/lib/esm/index.js.map +1 -0
  68. package/lib/esm/json_rpc.js +81 -0
  69. package/lib/esm/json_rpc.js.map +1 -0
  70. package/lib/esm/objects.js +58 -0
  71. package/lib/esm/objects.js.map +1 -0
  72. package/lib/esm/package.json +1 -0
  73. package/lib/esm/promise_helpers.js +146 -0
  74. package/lib/esm/promise_helpers.js.map +1 -0
  75. package/lib/esm/random.js +50 -0
  76. package/lib/esm/random.js.map +1 -0
  77. package/lib/esm/socket_provider.js +329 -0
  78. package/lib/esm/socket_provider.js.map +1 -0
  79. package/lib/esm/string_manipulation.js +140 -0
  80. package/lib/esm/string_manipulation.js.map +1 -0
  81. package/lib/esm/uint8array.js +53 -0
  82. package/lib/esm/uint8array.js.map +1 -0
  83. package/lib/esm/uuid.js +53 -0
  84. package/lib/esm/uuid.js.map +1 -0
  85. package/lib/esm/validation.js +158 -0
  86. package/lib/esm/validation.js.map +1 -0
  87. package/lib/esm/web3_deferred_promise.js +137 -0
  88. package/lib/esm/web3_deferred_promise.js.map +1 -0
  89. package/lib/esm/web3_eip1193_provider.js +105 -0
  90. package/lib/esm/web3_eip1193_provider.js.map +1 -0
  91. package/lib/types/chunk_response_parser.d.ts +15 -0
  92. package/lib/types/chunk_response_parser.d.ts.map +1 -0
  93. package/lib/types/converters.d.ts +281 -0
  94. package/lib/types/converters.d.ts.map +1 -0
  95. package/lib/types/event_emitter.d.ts +11 -0
  96. package/lib/types/event_emitter.d.ts.map +1 -0
  97. package/lib/types/formatter.d.ts +44 -0
  98. package/lib/types/formatter.d.ts.map +1 -0
  99. package/lib/types/hash.d.ts +94 -0
  100. package/lib/types/hash.d.ts.map +1 -0
  101. package/lib/types/index.d.ts +19 -0
  102. package/lib/types/index.d.ts.map +1 -0
  103. package/lib/types/json_rpc.d.ts +22 -0
  104. package/lib/types/json_rpc.d.ts.map +1 -0
  105. package/lib/types/objects.d.ts +8 -0
  106. package/lib/types/objects.d.ts.map +1 -0
  107. package/lib/types/promise_helpers.d.ts +48 -0
  108. package/lib/types/promise_helpers.d.ts.map +1 -0
  109. package/lib/types/random.d.ts +29 -0
  110. package/lib/types/random.d.ts.map +1 -0
  111. package/lib/types/socket_provider.d.ts +129 -0
  112. package/lib/types/socket_provider.d.ts.map +1 -0
  113. package/lib/types/string_manipulation.d.ts +81 -0
  114. package/lib/types/string_manipulation.d.ts.map +1 -0
  115. package/lib/types/uint8array.d.ts +7 -0
  116. package/lib/types/uint8array.d.ts.map +1 -0
  117. package/lib/types/uuid.d.ts +12 -0
  118. package/lib/types/uuid.d.ts.map +1 -0
  119. package/lib/types/validation.d.ts +83 -0
  120. package/lib/types/validation.d.ts.map +1 -0
  121. package/lib/types/web3_deferred_promise.d.ts +68 -0
  122. package/lib/types/web3_deferred_promise.d.ts.map +1 -0
  123. package/lib/types/web3_eip1193_provider.d.ts +16 -0
  124. package/lib/types/web3_eip1193_provider.d.ts.map +1 -0
  125. package/package.json +57 -0
  126. package/src/chunk_response_parser.ts +99 -0
  127. package/src/converters.ts +713 -0
  128. package/src/event_emitter.ts +37 -0
  129. package/src/formatter.ts +402 -0
  130. package/src/hash.ts +398 -0
  131. package/src/index.ts +36 -0
  132. package/src/json_rpc.ts +130 -0
  133. package/src/objects.ts +65 -0
  134. package/src/promise_helpers.ts +170 -0
  135. package/src/random.ts +53 -0
  136. package/src/socket_provider.ts +581 -0
  137. package/src/string_manipulation.ts +166 -0
  138. package/src/uint8array.ts +59 -0
  139. package/src/uuid.ts +59 -0
  140. package/src/validation.ts +193 -0
  141. package/src/web3_deferred_promise.ts +149 -0
  142. package/src/web3_eip1193_provider.ts +116 -0
@@ -0,0 +1,581 @@
1
+ /*
2
+ This file is part of web3.js.
3
+
4
+ web3.js is free software: you can redistribute it and/or modify
5
+ it under the terms of the GNU Lesser General Public License as published by
6
+ the Free Software Foundation, either version 3 of the License, or
7
+ (at your option) any later version.
8
+
9
+ web3.js is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU Lesser General Public License for more details.
13
+
14
+ You should have received a copy of the GNU Lesser General Public License
15
+ along with web3.js. If not, see <http://www.gnu.org/licenses/>.
16
+ */
17
+ import {
18
+ ConnectionEvent,
19
+ Eip1193EventName,
20
+ EthExecutionAPI,
21
+ JsonRpcBatchRequest,
22
+ JsonRpcBatchResponse,
23
+ JsonRpcId,
24
+ JsonRpcNotification,
25
+ JsonRpcRequest,
26
+ JsonRpcResponse,
27
+ JsonRpcResponseWithResult,
28
+ JsonRpcResult,
29
+ ProviderConnectInfo,
30
+ ProviderMessage,
31
+ ProviderRpcError,
32
+ SocketRequestItem,
33
+ Web3APIMethod,
34
+ Web3APIPayload,
35
+ Web3APIReturnType,
36
+ Web3APISpec,
37
+ Web3Eip1193ProviderEventCallback,
38
+ Web3ProviderEventCallback,
39
+ Web3ProviderMessageEventCallback,
40
+ Web3ProviderStatus,
41
+ } from 'web3-types';
42
+ import {
43
+ ConnectionError,
44
+ ConnectionNotOpenError,
45
+ InvalidClientError,
46
+ MaxAttemptsReachedOnReconnectingError,
47
+ PendingRequestsOnReconnectingError,
48
+ RequestAlreadySentError,
49
+ Web3WSProviderError,
50
+ } from 'web3-errors';
51
+ import { Eip1193Provider } from './web3_eip1193_provider.js';
52
+ import { ChunkResponseParser } from './chunk_response_parser.js';
53
+ import { isNullish } from './validation.js';
54
+ import { Web3DeferredPromise } from './web3_deferred_promise.js';
55
+ import * as jsonRpc from './json_rpc.js';
56
+
57
+ export type ReconnectOptions = {
58
+ autoReconnect: boolean;
59
+ delay: number;
60
+ maxAttempts: number;
61
+ };
62
+
63
+ const DEFAULT_RECONNECTION_OPTIONS = {
64
+ autoReconnect: true,
65
+ delay: 5000,
66
+ maxAttempts: 5,
67
+ };
68
+
69
+ const NORMAL_CLOSE_CODE = 1000; // https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close
70
+
71
+ export abstract class SocketProvider<
72
+ MessageEvent,
73
+ CloseEvent,
74
+ ErrorEvent,
75
+ API extends Web3APISpec = EthExecutionAPI,
76
+ > extends Eip1193Provider<API> {
77
+ protected isReconnecting: boolean;
78
+ protected readonly _socketPath: string;
79
+ protected readonly chunkResponseParser: ChunkResponseParser;
80
+ /* eslint-disable @typescript-eslint/no-explicit-any */
81
+ protected readonly _pendingRequestsQueue: Map<JsonRpcId, SocketRequestItem<any, any, any>>;
82
+ /* eslint-disable @typescript-eslint/no-explicit-any */
83
+ protected readonly _sentRequestsQueue: Map<JsonRpcId, SocketRequestItem<any, any, any>>;
84
+ protected _reconnectAttempts!: number;
85
+ protected readonly _socketOptions?: unknown;
86
+ protected readonly _reconnectOptions: ReconnectOptions;
87
+ protected _socketConnection?: unknown;
88
+ public get SocketConnection() {
89
+ return this._socketConnection;
90
+ }
91
+ protected _connectionStatus: Web3ProviderStatus;
92
+ protected readonly _onMessageHandler: (event: MessageEvent) => void;
93
+ protected readonly _onOpenHandler: () => void;
94
+ protected readonly _onCloseHandler: (event: CloseEvent) => void;
95
+ protected readonly _onErrorHandler: (event: ErrorEvent) => void;
96
+
97
+ /**
98
+ * This is an abstract class for implementing a socket provider (e.g. WebSocket, IPC). It extends the EIP-1193 provider {@link EIP1193Provider}.
99
+ * @param socketPath - The path to the socket (e.g. /ipc/path or ws://localhost:8546)
100
+ * @param socketOptions - The options for the socket connection. Its type is supposed to be specified in the inherited classes.
101
+ * @param reconnectOptions - The options for the socket reconnection {@link ReconnectOptions}
102
+ */
103
+ public constructor(
104
+ socketPath: string,
105
+ socketOptions?: unknown,
106
+ reconnectOptions?: Partial<ReconnectOptions>,
107
+ ) {
108
+ super();
109
+ this._connectionStatus = 'connecting';
110
+
111
+ // Message handlers. Due to bounding of `this` and removing the listeners we have to keep it's reference.
112
+ this._onMessageHandler = this._onMessage.bind(this);
113
+ this._onOpenHandler = this._onConnect.bind(this);
114
+ this._onCloseHandler = this._onCloseEvent.bind(this);
115
+ this._onErrorHandler = this._onError.bind(this);
116
+
117
+ if (!this._validateProviderPath(socketPath)) throw new InvalidClientError(socketPath);
118
+
119
+ this._socketPath = socketPath;
120
+ this._socketOptions = socketOptions;
121
+ this._reconnectOptions = {
122
+ ...DEFAULT_RECONNECTION_OPTIONS,
123
+ ...(reconnectOptions ?? {}),
124
+ };
125
+
126
+ this._pendingRequestsQueue = new Map<JsonRpcId, SocketRequestItem<any, any, any>>();
127
+ this._sentRequestsQueue = new Map<JsonRpcId, SocketRequestItem<any, any, any>>();
128
+
129
+ this._init();
130
+ this.connect();
131
+ this.chunkResponseParser = new ChunkResponseParser(
132
+ this._eventEmitter,
133
+ this._reconnectOptions.autoReconnect,
134
+ );
135
+ this.chunkResponseParser.onError(() => {
136
+ this._clearQueues();
137
+ });
138
+ this.isReconnecting = false;
139
+ }
140
+
141
+ protected _init() {
142
+ this._reconnectAttempts = 0;
143
+ }
144
+
145
+ /**
146
+ * Try to establish a connection to the socket
147
+ */
148
+ public connect(): void {
149
+ try {
150
+ this._openSocketConnection();
151
+ this._connectionStatus = 'connecting';
152
+ this._addSocketListeners();
153
+ } catch (e) {
154
+ if (!this.isReconnecting) {
155
+ this._connectionStatus = 'disconnected';
156
+ if (e && (e as Error).message) {
157
+ throw new ConnectionError(
158
+ `Error while connecting to ${this._socketPath}. Reason: ${
159
+ (e as Error).message
160
+ }`,
161
+ );
162
+ } else {
163
+ throw new InvalidClientError(this._socketPath);
164
+ }
165
+ } else {
166
+ setImmediate(() => {
167
+ this._reconnect();
168
+ });
169
+ }
170
+ }
171
+ }
172
+
173
+ protected abstract _openSocketConnection(): void;
174
+ protected abstract _addSocketListeners(): void;
175
+
176
+ protected abstract _removeSocketListeners(): void;
177
+
178
+ protected abstract _onCloseEvent(_event: unknown): void;
179
+
180
+ protected abstract _sendToSocket(_payload: Web3APIPayload<API, any>): void;
181
+
182
+ protected abstract _parseResponses(_event: MessageEvent): JsonRpcResponse[];
183
+
184
+ protected abstract _closeSocketConnection(_code?: number, _data?: string): void;
185
+
186
+ // eslint-disable-next-line class-methods-use-this
187
+ protected _validateProviderPath(path: string): boolean {
188
+ return !!path;
189
+ }
190
+
191
+ /**
192
+ *
193
+ * @returns the pendingRequestQueue size
194
+ */
195
+ // eslint-disable-next-line class-methods-use-this
196
+ public getPendingRequestQueueSize() {
197
+ return this._pendingRequestsQueue.size;
198
+ }
199
+
200
+ /**
201
+ *
202
+ * @returns the sendPendingRequests size
203
+ */
204
+ // eslint-disable-next-line class-methods-use-this
205
+ public getSentRequestsQueueSize() {
206
+ return this._sentRequestsQueue.size;
207
+ }
208
+
209
+ /**
210
+ *
211
+ * @returns `true` if the socket supports subscriptions
212
+ */
213
+ // eslint-disable-next-line class-methods-use-this
214
+ public supportsSubscriptions(): boolean {
215
+ return true;
216
+ }
217
+
218
+ /**
219
+ * Registers a listener for the specified event type.
220
+ * @param type - The event type to listen for
221
+ * @param listener - The callback to be invoked when the event is emitted
222
+ */
223
+ public on(
224
+ type: 'disconnect',
225
+ listener: Web3Eip1193ProviderEventCallback<ProviderRpcError>,
226
+ ): void;
227
+ public on(
228
+ type: 'connect',
229
+ listener: Web3Eip1193ProviderEventCallback<ProviderConnectInfo>,
230
+ ): void;
231
+ public on(type: 'chainChanged', listener: Web3Eip1193ProviderEventCallback<string>): void;
232
+ public on(type: 'accountsChanged', listener: Web3Eip1193ProviderEventCallback<string[]>): void;
233
+ public on<T = JsonRpcResult>(
234
+ type: 'message',
235
+ listener:
236
+ | Web3Eip1193ProviderEventCallback<ProviderMessage>
237
+ | Web3ProviderMessageEventCallback<T>,
238
+ ): void;
239
+ public on<T = JsonRpcResult>(
240
+ type: string,
241
+ listener: Web3Eip1193ProviderEventCallback<unknown> | Web3ProviderEventCallback<T>,
242
+ ): void;
243
+ public on<T = JsonRpcResult, P = unknown>(
244
+ type: string | Eip1193EventName,
245
+ listener:
246
+ | Web3Eip1193ProviderEventCallback<P>
247
+ | Web3ProviderMessageEventCallback<T>
248
+ | Web3ProviderEventCallback<T>,
249
+ ): void {
250
+ this._eventEmitter.on(type, listener);
251
+ }
252
+
253
+ /**
254
+ * Registers a listener for the specified event type that will be invoked at most once.
255
+ * @param type - The event type to listen for
256
+ * @param listener - The callback to be invoked when the event is emitted
257
+ */
258
+ public once(
259
+ type: 'disconnect',
260
+ listener: Web3Eip1193ProviderEventCallback<ProviderRpcError>,
261
+ ): void;
262
+ public once(
263
+ type: 'connect',
264
+ listener: Web3Eip1193ProviderEventCallback<ProviderConnectInfo>,
265
+ ): void;
266
+ public once(type: 'chainChanged', listener: Web3Eip1193ProviderEventCallback<string>): void;
267
+ public once(
268
+ type: 'accountsChanged',
269
+ listener: Web3Eip1193ProviderEventCallback<string[]>,
270
+ ): void;
271
+ public once<T = JsonRpcResult>(
272
+ type: 'message',
273
+ listener:
274
+ | Web3Eip1193ProviderEventCallback<ProviderMessage>
275
+ | Web3ProviderMessageEventCallback<T>,
276
+ ): void;
277
+ public once<T = JsonRpcResult>(
278
+ type: string,
279
+ listener: Web3Eip1193ProviderEventCallback<unknown> | Web3ProviderEventCallback<T>,
280
+ ): void;
281
+ public once<T = JsonRpcResult, P = unknown>(
282
+ type: string | Eip1193EventName,
283
+ listener:
284
+ | Web3Eip1193ProviderEventCallback<P>
285
+ | Web3ProviderMessageEventCallback<T>
286
+ | Web3ProviderEventCallback<T>,
287
+ ): void {
288
+ this._eventEmitter.once(type, listener);
289
+ }
290
+
291
+ /**
292
+ * Removes a listener for the specified event type.
293
+ * @param type - The event type to remove the listener for
294
+ * @param listener - The callback to be executed
295
+ */
296
+ public removeListener(
297
+ type: 'disconnect',
298
+ listener: Web3Eip1193ProviderEventCallback<ProviderRpcError>,
299
+ ): void;
300
+ public removeListener(
301
+ type: 'connect',
302
+ listener: Web3Eip1193ProviderEventCallback<ProviderConnectInfo>,
303
+ ): void;
304
+ public removeListener(
305
+ type: 'chainChanged',
306
+ listener: Web3Eip1193ProviderEventCallback<string>,
307
+ ): void;
308
+ public removeListener(
309
+ type: 'accountsChanged',
310
+ listener: Web3Eip1193ProviderEventCallback<string[]>,
311
+ ): void;
312
+ public removeListener<T = JsonRpcResult>(
313
+ type: 'message',
314
+ listener:
315
+ | Web3Eip1193ProviderEventCallback<ProviderMessage>
316
+ | Web3ProviderMessageEventCallback<T>,
317
+ ): void;
318
+ public removeListener<T = JsonRpcResult>(
319
+ type: string,
320
+ listener: Web3Eip1193ProviderEventCallback<unknown> | Web3ProviderEventCallback<T>,
321
+ ): void;
322
+ public removeListener<T = JsonRpcResult, P = unknown>(
323
+ type: string | Eip1193EventName,
324
+ listener:
325
+ | Web3Eip1193ProviderEventCallback<P>
326
+ | Web3ProviderMessageEventCallback<T>
327
+ | Web3ProviderEventCallback<T>,
328
+ ): void {
329
+ this._eventEmitter.removeListener(type, listener);
330
+ }
331
+
332
+ protected _onDisconnect(code: number, data?: string) {
333
+ this._connectionStatus = 'disconnected';
334
+ super._onDisconnect(code, data);
335
+ }
336
+
337
+ /**
338
+ * Disconnects the socket
339
+ * @param code - The code to be sent to the server
340
+ * @param data - The data to be sent to the server
341
+ */
342
+ public disconnect(code?: number, data?: string): void {
343
+ const disconnectCode = code ?? NORMAL_CLOSE_CODE;
344
+ this._removeSocketListeners();
345
+ if (this.getStatus() !== 'disconnected') {
346
+ this._closeSocketConnection(disconnectCode, data);
347
+ }
348
+ this._onDisconnect(disconnectCode, data);
349
+ }
350
+
351
+ /**
352
+ * Safely disconnects the socket, async and waits for request size to be 0 before disconnecting
353
+ * @param forceDisconnect - If true, will clear queue after 5 attempts of waiting for both pending and sent queue to be 0
354
+ * @param ms - Determines the ms of setInterval
355
+ * @param code - The code to be sent to the server
356
+ * @param data - The data to be sent to the server
357
+ */
358
+ public async safeDisconnect(code?: number, data?: string, forceDisconnect = false, ms = 1000) {
359
+ let retryAttempt = 0;
360
+ const checkQueue = async () =>
361
+ new Promise(resolve => {
362
+ const interval = setInterval(() => {
363
+ if (forceDisconnect && retryAttempt >= 5) {
364
+ this.clearQueues();
365
+ }
366
+ if (
367
+ this.getPendingRequestQueueSize() === 0 &&
368
+ this.getSentRequestsQueueSize() === 0
369
+ ) {
370
+ clearInterval(interval);
371
+ resolve(true);
372
+ }
373
+ retryAttempt += 1;
374
+ }, ms);
375
+ });
376
+
377
+ await checkQueue();
378
+ this.disconnect(code, data);
379
+ }
380
+
381
+ /**
382
+ * Removes all listeners for the specified event type.
383
+ * @param type - The event type to remove the listeners for
384
+ */
385
+ public removeAllListeners(type: string): void {
386
+ this._eventEmitter.removeAllListeners(type);
387
+ }
388
+
389
+ protected _onError(event: ErrorEvent): void {
390
+ // do not emit error while trying to reconnect
391
+ if (this.isReconnecting) {
392
+ this._reconnect();
393
+ } else {
394
+ this._eventEmitter.emit('error', event);
395
+ }
396
+ }
397
+
398
+ /**
399
+ * Resets the socket, removing all listeners and pending requests
400
+ */
401
+ public reset(): void {
402
+ this._sentRequestsQueue.clear();
403
+ this._pendingRequestsQueue.clear();
404
+
405
+ this._init();
406
+ this._removeSocketListeners();
407
+ this._addSocketListeners();
408
+ }
409
+
410
+ protected _reconnect(): void {
411
+ if (this.isReconnecting) {
412
+ return;
413
+ }
414
+ this.isReconnecting = true;
415
+
416
+ if (this._sentRequestsQueue.size > 0) {
417
+ this._sentRequestsQueue.forEach(
418
+ (request: SocketRequestItem<any, any, any>, key: JsonRpcId) => {
419
+ request.deferredPromise.reject(new PendingRequestsOnReconnectingError());
420
+ this._sentRequestsQueue.delete(key);
421
+ },
422
+ );
423
+ }
424
+
425
+ if (this._reconnectAttempts < this._reconnectOptions.maxAttempts) {
426
+ this._reconnectAttempts += 1;
427
+ setTimeout(() => {
428
+ this._removeSocketListeners();
429
+ this.connect(); // this can error out
430
+ this.isReconnecting = false;
431
+ }, this._reconnectOptions.delay);
432
+ } else {
433
+ this.isReconnecting = false;
434
+ this._clearQueues();
435
+ this._removeSocketListeners();
436
+ this._eventEmitter.emit(
437
+ 'error',
438
+ new MaxAttemptsReachedOnReconnectingError(this._reconnectOptions.maxAttempts),
439
+ );
440
+ }
441
+ }
442
+
443
+ /**
444
+ * Creates a request object to be sent to the server
445
+ */
446
+ public async request<
447
+ Method extends Web3APIMethod<API>,
448
+ ResultType = Web3APIReturnType<API, Method>,
449
+ >(request: Web3APIPayload<API, Method>): Promise<JsonRpcResponseWithResult<ResultType>> {
450
+ if (isNullish(this._socketConnection)) {
451
+ throw new Error('Connection is undefined');
452
+ }
453
+ // if socket disconnected - open connection
454
+ if (this.getStatus() === 'disconnected') {
455
+ this.connect();
456
+ }
457
+
458
+ const requestId = jsonRpc.isBatchRequest(request)
459
+ ? (request as unknown as JsonRpcBatchRequest)[0].id
460
+ : (request as unknown as JsonRpcRequest).id;
461
+
462
+ if (!requestId) {
463
+ throw new Web3WSProviderError('Request Id not defined');
464
+ }
465
+
466
+ if (this._sentRequestsQueue.has(requestId)) {
467
+ throw new RequestAlreadySentError(requestId);
468
+ }
469
+ const deferredPromise = new Web3DeferredPromise<JsonRpcResponseWithResult<ResultType>>();
470
+ deferredPromise.catch(error => {
471
+ this._eventEmitter.emit('error', error);
472
+ });
473
+ const reqItem: SocketRequestItem<API, Method, JsonRpcResponseWithResult<ResultType>> = {
474
+ payload: request,
475
+ deferredPromise,
476
+ };
477
+
478
+ if (this.getStatus() === 'connecting') {
479
+ this._pendingRequestsQueue.set(requestId, reqItem);
480
+
481
+ return reqItem.deferredPromise;
482
+ }
483
+
484
+ this._sentRequestsQueue.set(requestId, reqItem);
485
+
486
+ try {
487
+ this._sendToSocket(reqItem.payload);
488
+ } catch (error) {
489
+ this._sentRequestsQueue.delete(requestId);
490
+
491
+ this._eventEmitter.emit('error', error);
492
+ }
493
+
494
+ return deferredPromise;
495
+ }
496
+
497
+ protected _onConnect() {
498
+ this._connectionStatus = 'connected';
499
+ this._reconnectAttempts = 0;
500
+ super._onConnect();
501
+ this._sendPendingRequests();
502
+ }
503
+
504
+ private _sendPendingRequests() {
505
+ for (const [id, value] of this._pendingRequestsQueue.entries()) {
506
+ try {
507
+ this._sendToSocket(value.payload as Web3APIPayload<API, any>);
508
+ this._pendingRequestsQueue.delete(id);
509
+ this._sentRequestsQueue.set(id, value);
510
+ } catch (error) {
511
+ // catches if sendTosocket fails
512
+ this._pendingRequestsQueue.delete(id);
513
+ this._eventEmitter.emit('error', error);
514
+ }
515
+ }
516
+ }
517
+
518
+ protected _onMessage(event: MessageEvent): void {
519
+ const responses = this._parseResponses(event);
520
+ if (isNullish(responses) || responses.length === 0) {
521
+ return;
522
+ }
523
+
524
+ for (const response of responses) {
525
+ if (
526
+ jsonRpc.isResponseWithNotification(response as JsonRpcNotification) &&
527
+ (response as JsonRpcNotification).method.endsWith('_subscription')
528
+ ) {
529
+ this._eventEmitter.emit('message', response);
530
+ return;
531
+ }
532
+
533
+ const requestId = jsonRpc.isBatchResponse(response)
534
+ ? (response as unknown as JsonRpcBatchResponse)[0].id
535
+ : (response as unknown as JsonRpcResponseWithResult).id;
536
+
537
+ const requestItem = this._sentRequestsQueue.get(requestId);
538
+
539
+ if (!requestItem) {
540
+ return;
541
+ }
542
+
543
+ if (
544
+ jsonRpc.isBatchResponse(response) ||
545
+ jsonRpc.isResponseWithResult(response) ||
546
+ jsonRpc.isResponseWithError(response)
547
+ ) {
548
+ this._eventEmitter.emit('message', response);
549
+ requestItem.deferredPromise.resolve(response);
550
+ }
551
+
552
+ this._sentRequestsQueue.delete(requestId);
553
+ }
554
+ }
555
+
556
+ public clearQueues(event?: ConnectionEvent) {
557
+ this._clearQueues(event);
558
+ }
559
+
560
+ protected _clearQueues(event?: ConnectionEvent) {
561
+ if (this._pendingRequestsQueue.size > 0) {
562
+ this._pendingRequestsQueue.forEach(
563
+ (request: SocketRequestItem<any, any, any>, key: JsonRpcId) => {
564
+ request.deferredPromise.reject(new ConnectionNotOpenError(event));
565
+ this._pendingRequestsQueue.delete(key);
566
+ },
567
+ );
568
+ }
569
+
570
+ if (this._sentRequestsQueue.size > 0) {
571
+ this._sentRequestsQueue.forEach(
572
+ (request: SocketRequestItem<any, any, any>, key: JsonRpcId) => {
573
+ request.deferredPromise.reject(new ConnectionNotOpenError(event));
574
+ this._sentRequestsQueue.delete(key);
575
+ },
576
+ );
577
+ }
578
+
579
+ this._removeSocketListeners();
580
+ }
581
+ }