@tchain/tcabci-read-js-client 2.7.13 → 2.8.1
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/authority.d.ts +15 -0
- package/authority.js +63 -0
- package/client.d.ts +6 -0
- package/client.js +49 -2
- package/message.d.ts +10 -1
- package/message.js +2 -0
- package/package.json +17 -15
- package/types.d.ts +3 -0
- package/validation.js +1 -1
- package/websocketOptions.d.ts +3 -0
- package/websocketOptions.js +61 -1
package/authority.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Caller-owned result; the input is valid only during the synchronous call. */
|
|
2
|
+
export type WSAuthoritySigner = (payload: Uint8Array) => Uint8Array
|
|
3
|
+
export type Randomizer = (data: Uint8Array) => Uint8Array
|
|
4
|
+
|
|
5
|
+
export interface WSAuthorityOptions {
|
|
6
|
+
address: string
|
|
7
|
+
sign: WSAuthoritySigner
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/** Fresh v3 header for one trusted WS handshake; never log or cache it. */
|
|
11
|
+
export declare function createWSAuthorityV3(
|
|
12
|
+
address: string,
|
|
13
|
+
sign: WSAuthoritySigner,
|
|
14
|
+
randomizer?: Randomizer
|
|
15
|
+
): string
|
package/authority.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { SendThrow } from './util.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Create a fresh read-node WS authority v3 header, valid for ten seconds and one
|
|
5
|
+
* handshake. Use only with trusted endpoints; never log or cache the result.
|
|
6
|
+
* The signer is synchronous, receives an owned Uint8Array valid during its
|
|
7
|
+
* call, and returns caller-owned signature bytes. No private key is retained.
|
|
8
|
+
* @param {string} address Configured TransferChain public address.
|
|
9
|
+
* @param {(payload: Uint8Array) => Uint8Array} sign Synchronous signer.
|
|
10
|
+
* @param {(Uint8Array) => Uint8Array} randomizer
|
|
11
|
+
* @returns {string}
|
|
12
|
+
*/
|
|
13
|
+
export function createWSAuthorityV3(address, sign, randomizer = null) {
|
|
14
|
+
if (
|
|
15
|
+
typeof address !== 'string' ||
|
|
16
|
+
address.length === 0 ||
|
|
17
|
+
address.length > 2048 ||
|
|
18
|
+
/[;\r\n]/.test(address) ||
|
|
19
|
+
typeof sign !== 'function'
|
|
20
|
+
)
|
|
21
|
+
throw new TypeError('Invalid websocket authority configuration')
|
|
22
|
+
|
|
23
|
+
const nonce = new Uint8Array(32),
|
|
24
|
+
hex = (bytes) =>
|
|
25
|
+
Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join('')
|
|
26
|
+
let payload, signature
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
if (!randomizer) globalThis.crypto.getRandomValues(nonce)
|
|
30
|
+
else randomizer(nonce)
|
|
31
|
+
|
|
32
|
+
const timestamp = (BigInt(Date.now()) * 1000000n).toString(),
|
|
33
|
+
nonceHex = hex(nonce)
|
|
34
|
+
|
|
35
|
+
payload = new TextEncoder().encode(
|
|
36
|
+
`read-node/ws-authority/v3\n${address}\n${timestamp}\n${nonceHex}`
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
const result = sign(payload)
|
|
40
|
+
|
|
41
|
+
if (result && typeof result.then === 'function') {
|
|
42
|
+
Promise.resolve(result).catch(() => {})
|
|
43
|
+
SendThrow(new TypeError('Authority signer must be synchronous'))
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (
|
|
47
|
+
!(result instanceof Uint8Array) ||
|
|
48
|
+
result.length === 0 ||
|
|
49
|
+
result.length > 8192
|
|
50
|
+
)
|
|
51
|
+
SendThrow(new TypeError('Invalid websocket authority signature'))
|
|
52
|
+
|
|
53
|
+
signature = new Uint8Array(result)
|
|
54
|
+
|
|
55
|
+
return `${address};v3;${timestamp};${nonceHex};${hex(signature)}`
|
|
56
|
+
} catch {
|
|
57
|
+
throw new Error('Websocket authority creation failed')
|
|
58
|
+
} finally {
|
|
59
|
+
nonce.fill(0)
|
|
60
|
+
payload?.fill(0)
|
|
61
|
+
signature?.fill(0)
|
|
62
|
+
}
|
|
63
|
+
}
|
package/client.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export { createWSAuthorityV3 } from './authority.js'
|
|
2
|
+
export type { WSAuthoritySigner, WSAuthorityOptions } from './authority.js'
|
|
1
3
|
import { Transaction, TXType } from './transaction.js'
|
|
2
4
|
import { TWebSocket } from './websocket.js'
|
|
3
5
|
import {
|
|
@@ -71,6 +73,7 @@ export default class TCaBCIClient {
|
|
|
71
73
|
options?: ClientOptions
|
|
72
74
|
)
|
|
73
75
|
|
|
76
|
+
SetIsWeb(isWeb: boolean): this
|
|
74
77
|
SetDebug(debug: boolean): this
|
|
75
78
|
|
|
76
79
|
SetSuccessCallback(cb: SuccessCallback | null): this
|
|
@@ -109,6 +112,9 @@ export default class TCaBCIClient {
|
|
|
109
112
|
txTypes?: readonly TXType[] | null
|
|
110
113
|
): this
|
|
111
114
|
|
|
115
|
+
/** Explicit Listen; requires a valid authority and repeats after reconnect. */
|
|
116
|
+
Listen(): this
|
|
117
|
+
|
|
112
118
|
Unsubscribe(): this
|
|
113
119
|
|
|
114
120
|
LastBlock(
|
package/client.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { createWSAuthorityV3 } from './authority.js'
|
|
1
2
|
import {
|
|
2
3
|
addresses as validateAddresses,
|
|
3
4
|
signedData as validateSignedData,
|
|
@@ -21,6 +22,8 @@ import Message, {
|
|
|
21
22
|
Transaction as MTransaction,
|
|
22
23
|
SUBSCRIBEMessage,
|
|
23
24
|
UNSUBSCRIBEMessage,
|
|
25
|
+
LISTENMessage,
|
|
26
|
+
Listen as MListen,
|
|
24
27
|
Subscription,
|
|
25
28
|
OK
|
|
26
29
|
} from './message.js'
|
|
@@ -63,10 +66,11 @@ export default class TCaBCIClient {
|
|
|
63
66
|
_subscribed = false
|
|
64
67
|
_subscribedAddresses = []
|
|
65
68
|
_SubscribedSignedData = {}
|
|
69
|
+
_listenRequested = false
|
|
66
70
|
_connected = false
|
|
67
71
|
_chainName = 'transferchain'
|
|
68
72
|
_chainVersion = 'v1'
|
|
69
|
-
_version = `v2.
|
|
73
|
+
_version = `v2.8.0`
|
|
70
74
|
/**
|
|
71
75
|
* @type {?SuccessCallback}
|
|
72
76
|
*/
|
|
@@ -135,11 +139,15 @@ export default class TCaBCIClient {
|
|
|
135
139
|
).href
|
|
136
140
|
}
|
|
137
141
|
|
|
142
|
+
this._isWeb = true
|
|
138
143
|
this._httpClient = new HTTP(this._readNodeAddress, options)
|
|
139
144
|
this._options = new Options(this._readNodeWSAddress)
|
|
140
145
|
.setAllowInsecure(options.allowInsecure)
|
|
141
146
|
.setCustomWS(this._wsLibrary)
|
|
142
147
|
|
|
148
|
+
if (typeof options.authority !== 'undefined')
|
|
149
|
+
this._options.setAuthority(options.authority)
|
|
150
|
+
|
|
143
151
|
if (typeof options.maxMessageBytes !== 'undefined')
|
|
144
152
|
this._options.setMaxMessageBytes(options.maxMessageBytes)
|
|
145
153
|
|
|
@@ -154,6 +162,11 @@ export default class TCaBCIClient {
|
|
|
154
162
|
if (chainVersion) this._chainVersion = chainVersion
|
|
155
163
|
}
|
|
156
164
|
|
|
165
|
+
SetIsWeb(isWeb) {
|
|
166
|
+
this._isWeb = isWeb
|
|
167
|
+
return isWeb
|
|
168
|
+
}
|
|
169
|
+
|
|
157
170
|
SetDebug(debug) {
|
|
158
171
|
this._options.setDebug(debug)
|
|
159
172
|
|
|
@@ -268,6 +281,7 @@ export default class TCaBCIClient {
|
|
|
268
281
|
* @returns {Promise<TCaBCIClient>}
|
|
269
282
|
*/
|
|
270
283
|
async Stop(code = 1000) {
|
|
284
|
+
this._listenRequested = false
|
|
271
285
|
this._httpClient.abort()
|
|
272
286
|
await this._disconnect(code)
|
|
273
287
|
this._setConnected(false)
|
|
@@ -289,6 +303,22 @@ export default class TCaBCIClient {
|
|
|
289
303
|
})
|
|
290
304
|
}
|
|
291
305
|
|
|
306
|
+
/**
|
|
307
|
+
* Explicitly request privileged Listen with a configured authority handshake.
|
|
308
|
+
* The request is repeated after reconnect. Rejection stops automatic retries.
|
|
309
|
+
* @returns {TCaBCIClient}
|
|
310
|
+
*/
|
|
311
|
+
Listen() {
|
|
312
|
+
if (!this.IsConnected()) throw new Error(NOT_CONNECTED)
|
|
313
|
+
|
|
314
|
+
this._ws.send(
|
|
315
|
+
new Message({ isWeb: this._isWeb, type: LISTENMessage }).ToJSON()
|
|
316
|
+
)
|
|
317
|
+
this._listenRequested = true
|
|
318
|
+
|
|
319
|
+
return this
|
|
320
|
+
}
|
|
321
|
+
|
|
292
322
|
/**
|
|
293
323
|
* Subscribe to at most 251 unique addresses, each at most 2048 characters.
|
|
294
324
|
* The combined active address list is bounded. Proof maps are copied;
|
|
@@ -325,6 +355,7 @@ export default class TCaBCIClient {
|
|
|
325
355
|
txTypes
|
|
326
356
|
}).ToJSON()
|
|
327
357
|
)
|
|
358
|
+
this._listenRequested = false
|
|
328
359
|
this._setSubscribeAddresses(addrs)._setSubscribeSignedData(proof)
|
|
329
360
|
|
|
330
361
|
return this
|
|
@@ -334,7 +365,7 @@ export default class TCaBCIClient {
|
|
|
334
365
|
* @return {TCaBCIClient}
|
|
335
366
|
*/
|
|
336
367
|
Unsubscribe() {
|
|
337
|
-
if (!this.IsSubscribed()) {
|
|
368
|
+
if (!this.IsSubscribed() && !this._listenRequested) {
|
|
338
369
|
throw new Error(NOT_SUBSCRIBED)
|
|
339
370
|
}
|
|
340
371
|
|
|
@@ -347,6 +378,7 @@ export default class TCaBCIClient {
|
|
|
347
378
|
}).ToJSON()
|
|
348
379
|
)
|
|
349
380
|
} finally {
|
|
381
|
+
this._listenRequested = false
|
|
350
382
|
this._clearSubscription()
|
|
351
383
|
}
|
|
352
384
|
|
|
@@ -820,6 +852,9 @@ export default class TCaBCIClient {
|
|
|
820
852
|
if (!current()) return
|
|
821
853
|
|
|
822
854
|
this._setConnected(true)
|
|
855
|
+
|
|
856
|
+
if (this._listenRequested) this.Listen()
|
|
857
|
+
|
|
823
858
|
this._callSuccessCallback(e)
|
|
824
859
|
})
|
|
825
860
|
ws.addMessageListener((message) => {
|
|
@@ -878,6 +913,7 @@ export default class TCaBCIClient {
|
|
|
878
913
|
*/
|
|
879
914
|
async Dispose() {
|
|
880
915
|
await this.Stop()
|
|
916
|
+
this._options.setAuthority(null)
|
|
881
917
|
this._successCb = null
|
|
882
918
|
this._errorCb = null
|
|
883
919
|
this._closeCb = null
|
|
@@ -981,6 +1017,17 @@ export default class TCaBCIClient {
|
|
|
981
1017
|
|
|
982
1018
|
if (this._listenCb) this._listenCb(null, msg.transaction, null)
|
|
983
1019
|
|
|
1020
|
+
break
|
|
1021
|
+
case MListen:
|
|
1022
|
+
if (_msg.State !== OK) {
|
|
1023
|
+
void this.Stop().catch(() => {})
|
|
1024
|
+
this._callErrorCallback(new Error('Listen rejected'))
|
|
1025
|
+
|
|
1026
|
+
return
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
if (this._listenCb) this._listenCb(null, null, _msg)
|
|
1030
|
+
|
|
984
1031
|
break
|
|
985
1032
|
case Subscription:
|
|
986
1033
|
if (_msg.State === OK) {
|
package/message.d.ts
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import { TXType } from './transaction.js'
|
|
2
2
|
import { JSONValue, ParseResult } from './types.js'
|
|
3
3
|
|
|
4
|
-
export type MessageType =
|
|
4
|
+
export type MessageType =
|
|
5
|
+
| 'subscribe'
|
|
6
|
+
| 'unsubscribe'
|
|
7
|
+
| 'listen'
|
|
8
|
+
| 0
|
|
9
|
+
| 1
|
|
10
|
+
| 2
|
|
11
|
+
| 3
|
|
12
|
+
| 4
|
|
5
13
|
|
|
6
14
|
export type MType = 0 | 1 | 2 | 3 | 4
|
|
7
15
|
|
|
@@ -9,6 +17,7 @@ export type MState = 1 | 2
|
|
|
9
17
|
|
|
10
18
|
export declare const SUBSCRIBEMessage: 'subscribe',
|
|
11
19
|
UNSUBSCRIBEMessage: 'unsubscribe',
|
|
20
|
+
LISTENMessage: 'listen',
|
|
12
21
|
Block: 0,
|
|
13
22
|
Transaction: 1,
|
|
14
23
|
Subscription: 2,
|
package/message.js
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
|
|
10
10
|
export const SUBSCRIBEMessage = 'subscribe',
|
|
11
11
|
UNSUBSCRIBEMessage = 'unsubscribe',
|
|
12
|
+
LISTENMessage = 'listen',
|
|
12
13
|
Block = 0,
|
|
13
14
|
Transaction = 1,
|
|
14
15
|
Subscription = 2,
|
|
@@ -163,6 +164,7 @@ export default class Message {
|
|
|
163
164
|
![
|
|
164
165
|
SUBSCRIBEMessage,
|
|
165
166
|
UNSUBSCRIBEMessage,
|
|
167
|
+
LISTENMessage,
|
|
166
168
|
Block,
|
|
167
169
|
Transaction,
|
|
168
170
|
Subscription,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tchain/tcabci-read-js-client",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.8.1",
|
|
4
4
|
"description": "TransferChain Fastest Read Network WebSocket Client",
|
|
5
5
|
"homepage": "https://github.com/TransferChain/tcabci-read-js-client#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -26,11 +26,24 @@
|
|
|
26
26
|
"websocket.js",
|
|
27
27
|
"websocketOptions.js",
|
|
28
28
|
"bytea.js",
|
|
29
|
-
"validation.js"
|
|
29
|
+
"validation.js",
|
|
30
|
+
"authority.js"
|
|
30
31
|
],
|
|
31
32
|
"type": "module",
|
|
32
33
|
"main": "client.js",
|
|
33
34
|
"types": "client.d.ts",
|
|
35
|
+
"scripts": {
|
|
36
|
+
"format": "oxfmt ./",
|
|
37
|
+
"lint": "oxfmt ./ && oxlint --fix ./",
|
|
38
|
+
"lint:check": "oxfmt --check ./ && oxlint ./",
|
|
39
|
+
"test": "pnpm run test:unit && pnpm run test:security && pnpm run test:types",
|
|
40
|
+
"test:all": "pnpm test",
|
|
41
|
+
"test:coverage": "node --experimental-test-coverage --test test/security.test.js",
|
|
42
|
+
"test:unit": "mocha --timeout 5000 test/errors_test.js test/websocketOptions_test.js test/websocket_test.js",
|
|
43
|
+
"test:security": "node --test test/security.test.js",
|
|
44
|
+
"test:types": "tsc --noEmit --strict --module NodeNext --moduleResolution NodeNext --target ES2022 test/consumer.ts",
|
|
45
|
+
"test:integration": "mocha --timeout 7000 test/client_test.js"
|
|
46
|
+
},
|
|
34
47
|
"dependencies": {
|
|
35
48
|
"cockatiel": "^4.0.0",
|
|
36
49
|
"reconnecting-websocket": "^4.4.0"
|
|
@@ -48,16 +61,5 @@
|
|
|
48
61
|
"engines": {
|
|
49
62
|
"node": ">=24.0.0"
|
|
50
63
|
},
|
|
51
|
-
"
|
|
52
|
-
|
|
53
|
-
"lint": "oxfmt ./ && oxlint --fix ./",
|
|
54
|
-
"lint:check": "oxfmt --check ./ && oxlint ./",
|
|
55
|
-
"test": "pnpm run test:unit && pnpm run test:security && pnpm run test:types",
|
|
56
|
-
"test:all": "pnpm test",
|
|
57
|
-
"test:coverage": "node --experimental-test-coverage --test test/security.test.js",
|
|
58
|
-
"test:unit": "mocha --timeout 5000 test/errors_test.js test/websocketOptions_test.js test/websocket_test.js",
|
|
59
|
-
"test:security": "node --test test/security.test.js",
|
|
60
|
-
"test:types": "tsc --noEmit --strict --module NodeNext --moduleResolution NodeNext --target ES2022 test/consumer.ts",
|
|
61
|
-
"test:integration": "mocha --timeout 7000 test/client_test.js"
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
+
"packageManager": "pnpm@12.5.1"
|
|
65
|
+
}
|
package/types.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { WSAuthorityOptions } from './authority.js'
|
|
2
|
+
|
|
1
3
|
/** Immutable JSON snapshot; byte buffers are not JSON values. */
|
|
2
4
|
export type JSONValue =
|
|
3
5
|
| null
|
|
@@ -19,6 +21,7 @@ export interface RequestOptions {
|
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
export interface ClientOptions {
|
|
24
|
+
authority?: WSAuthorityOptions
|
|
22
25
|
allowInsecure?: boolean
|
|
23
26
|
timeoutMs?: number
|
|
24
27
|
maxResponseBytes?: number
|
package/validation.js
CHANGED
package/websocketOptions.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { WSAuthorityOptions } from './authority.js'
|
|
1
2
|
import { WebSocketConstructor } from './types.js'
|
|
2
3
|
|
|
3
4
|
export declare type Timeout = number
|
|
@@ -71,6 +72,8 @@ export declare class Options {
|
|
|
71
72
|
|
|
72
73
|
get customWS(): WebSocketConstructor | undefined
|
|
73
74
|
|
|
75
|
+
setAuthority(authority: WSAuthorityOptions | null): this
|
|
76
|
+
|
|
74
77
|
get url(): string
|
|
75
78
|
|
|
76
79
|
make(): {
|
package/websocketOptions.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createWSAuthorityV3 } from './authority.js'
|
|
1
2
|
import { CLIENT_VERSION, endpoint, positiveInteger } from './validation.js'
|
|
2
3
|
|
|
3
4
|
export const HTTPSPort = 443,
|
|
@@ -13,6 +14,7 @@ export class Options {
|
|
|
13
14
|
_longpoll = false
|
|
14
15
|
_protocols = []
|
|
15
16
|
_customWS
|
|
17
|
+
_authority = null
|
|
16
18
|
_endpoints = ['ws', 'longpoll']
|
|
17
19
|
_version = CLIENT_VERSION
|
|
18
20
|
_allowInsecure = false
|
|
@@ -280,6 +282,37 @@ export class Options {
|
|
|
280
282
|
return this._customWS
|
|
281
283
|
}
|
|
282
284
|
|
|
285
|
+
/**
|
|
286
|
+
* Configure a synchronous v3 signer. Requires a Node ws-compatible constructor
|
|
287
|
+
* supporting handshake headers; browser WebSocket cannot send these headers.
|
|
288
|
+
* @param {import('./authority.js').WSAuthorityOptions|null} authority
|
|
289
|
+
* @returns {Options}
|
|
290
|
+
*/
|
|
291
|
+
setAuthority(authority) {
|
|
292
|
+
if (authority === null) {
|
|
293
|
+
this._authority = null
|
|
294
|
+
|
|
295
|
+
return this
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (
|
|
299
|
+
!authority ||
|
|
300
|
+
typeof authority.address !== 'string' ||
|
|
301
|
+
authority.address.length === 0 ||
|
|
302
|
+
authority.address.length > 2048 ||
|
|
303
|
+
/[;\r\n]/.test(authority.address) ||
|
|
304
|
+
typeof authority.sign !== 'function' ||
|
|
305
|
+
typeof this._customWS?.prototype?.on !== 'function'
|
|
306
|
+
)
|
|
307
|
+
throw new TypeError(
|
|
308
|
+
'Authority requires a Node ws-compatible constructor and signer'
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
this._authority = { address: authority.address, sign: authority.sign }
|
|
312
|
+
|
|
313
|
+
return this
|
|
314
|
+
}
|
|
315
|
+
|
|
283
316
|
/**
|
|
284
317
|
* @return {string}
|
|
285
318
|
*/
|
|
@@ -297,8 +330,35 @@ export class Options {
|
|
|
297
330
|
* @return {{WebSocket: ?any, maxReconnectionDelay: number, minReconnectionDelay: number, reconnectionDelayGrowFactor: number, minUptime: number, connectionTimeout: number, maxRetries: number, maxEnqueuedMessages: number, startClosed: boolean, debug: boolean }}
|
|
298
331
|
*/
|
|
299
332
|
make() {
|
|
333
|
+
let WS = this._customWS
|
|
334
|
+
|
|
335
|
+
if (this._authority) {
|
|
336
|
+
const Base = WS,
|
|
337
|
+
options = this
|
|
338
|
+
|
|
339
|
+
WS = class extends Base {
|
|
340
|
+
constructor(url, protocols) {
|
|
341
|
+
const authority = options._authority
|
|
342
|
+
|
|
343
|
+
if (!authority)
|
|
344
|
+
throw new Error('Websocket authority configuration released')
|
|
345
|
+
|
|
346
|
+
super(url, protocols, {
|
|
347
|
+
followRedirects: false,
|
|
348
|
+
headers: {
|
|
349
|
+
Client: `tcabci-read-js-client/${CLIENT_VERSION}`,
|
|
350
|
+
'X-Authority': createWSAuthorityV3(
|
|
351
|
+
authority.address,
|
|
352
|
+
authority.sign
|
|
353
|
+
)
|
|
354
|
+
}
|
|
355
|
+
})
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
300
360
|
return {
|
|
301
|
-
...(
|
|
361
|
+
...(WS ? { WebSocket: WS } : {}),
|
|
302
362
|
maxReconnectionDelay: this._maxConnectionDelay,
|
|
303
363
|
minReconnectionDelay: this._minReconnectionDelay,
|
|
304
364
|
reconnectionDelayGrowFactor: this._reconnectionDelayGrowFactor,
|