@tchain/tcabci-read-js-client 2.8.1 → 2.8.3
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/client.d.ts +3 -0
- package/client.js +62 -7
- package/constants.d.ts +3 -1
- package/constants.js +2 -1
- package/http.js +1 -1
- package/message.d.ts +1 -0
- package/message.js +18 -1
- package/package.json +1 -1
- package/passKey.d.ts +4 -0
- package/validation.d.ts +1 -1
- package/validation.js +1 -2
- package/websocketOptions.js +15 -9
package/client.d.ts
CHANGED
|
@@ -21,6 +21,8 @@ export type {
|
|
|
21
21
|
WebSocketConstructor
|
|
22
22
|
} from './types.js'
|
|
23
23
|
|
|
24
|
+
export type Randomizer = (data: Uint8Array) => Uint8Array
|
|
25
|
+
|
|
24
26
|
export interface TxQuery {
|
|
25
27
|
recipientAddrs?: readonly string[]
|
|
26
28
|
senderAddrs?: readonly string[]
|
|
@@ -75,6 +77,7 @@ export default class TCaBCIClient {
|
|
|
75
77
|
|
|
76
78
|
SetIsWeb(isWeb: boolean): this
|
|
77
79
|
SetDebug(debug: boolean): this
|
|
80
|
+
SetRandomizer(randomizer: Randomizer): this
|
|
78
81
|
|
|
79
82
|
SetSuccessCallback(cb: SuccessCallback | null): this
|
|
80
83
|
|
package/client.js
CHANGED
|
@@ -31,6 +31,7 @@ import { Options } from './websocketOptions.js'
|
|
|
31
31
|
import { TWebSocket } from './websocket.js'
|
|
32
32
|
import { Transaction, TX_TYPE_LIST } from './transaction.js'
|
|
33
33
|
import { Block } from './block.js'
|
|
34
|
+
import { passKey } from './passKey.js'
|
|
34
35
|
import { HTTP } from './http.js'
|
|
35
36
|
|
|
36
37
|
/**
|
|
@@ -66,11 +67,12 @@ export default class TCaBCIClient {
|
|
|
66
67
|
_subscribed = false
|
|
67
68
|
_subscribedAddresses = []
|
|
68
69
|
_SubscribedSignedData = {}
|
|
70
|
+
_clientInstanceID = null
|
|
71
|
+
_instanceIDPromise = null
|
|
69
72
|
_listenRequested = false
|
|
70
73
|
_connected = false
|
|
71
74
|
_chainName = 'transferchain'
|
|
72
75
|
_chainVersion = 'v1'
|
|
73
|
-
_version = `v2.8.0`
|
|
74
76
|
/**
|
|
75
77
|
* @type {?SuccessCallback}
|
|
76
78
|
*/
|
|
@@ -99,6 +101,11 @@ export default class TCaBCIClient {
|
|
|
99
101
|
_ws
|
|
100
102
|
_readNodeAddress = READ_NODE_ADDRESS
|
|
101
103
|
_readNodeWSAddress = READ_NODE_WS_ADDRESS
|
|
104
|
+
/**
|
|
105
|
+
* @type {(Uint8Array) => Uint8Array}
|
|
106
|
+
* @private
|
|
107
|
+
*/
|
|
108
|
+
_randomizer = null
|
|
102
109
|
|
|
103
110
|
/**
|
|
104
111
|
* Create an HTTP/WebSocket client. Start initiates connection setup;
|
|
@@ -173,6 +180,15 @@ export default class TCaBCIClient {
|
|
|
173
180
|
return this
|
|
174
181
|
}
|
|
175
182
|
|
|
183
|
+
/**
|
|
184
|
+
* @param {(Uint8Array) => Uint8Array} randomizer
|
|
185
|
+
* @return {TCaBCIClient}
|
|
186
|
+
*/
|
|
187
|
+
SetRandomizer(randomizer) {
|
|
188
|
+
this._randomizer = randomizer
|
|
189
|
+
return this
|
|
190
|
+
}
|
|
191
|
+
|
|
176
192
|
/**
|
|
177
193
|
* @param {SuccessCallback} cb
|
|
178
194
|
* @return {TCaBCIClient}
|
|
@@ -312,7 +328,11 @@ export default class TCaBCIClient {
|
|
|
312
328
|
if (!this.IsConnected()) throw new Error(NOT_CONNECTED)
|
|
313
329
|
|
|
314
330
|
this._ws.send(
|
|
315
|
-
new Message({
|
|
331
|
+
new Message({
|
|
332
|
+
isWeb: this._isWeb,
|
|
333
|
+
type: LISTENMessage,
|
|
334
|
+
clientInstanceID: this._clientInstanceID ?? undefined
|
|
335
|
+
}).ToJSON()
|
|
316
336
|
)
|
|
317
337
|
this._listenRequested = true
|
|
318
338
|
|
|
@@ -323,6 +343,7 @@ export default class TCaBCIClient {
|
|
|
323
343
|
* Subscribe to at most 251 unique addresses, each at most 2048 characters.
|
|
324
344
|
* The combined active address list is bounded. Proof maps are copied;
|
|
325
345
|
* caller objects remain mutable. ACK updates IsSubscribed asynchronously.
|
|
346
|
+
* A random instance ID is retained by this client across reconnects.
|
|
326
347
|
* @param {readonly string[]} addresses
|
|
327
348
|
* @param {Readonly<Record<string, string>>} signedData
|
|
328
349
|
* @param {readonly string[]|null} [txTypes=null]
|
|
@@ -330,7 +351,7 @@ export default class TCaBCIClient {
|
|
|
330
351
|
*/
|
|
331
352
|
Subscribe(addresses, signedData, txTypes = null) {
|
|
332
353
|
const requested = validateAddresses(addresses),
|
|
333
|
-
|
|
354
|
+
suppliedProof = validateSignedData(signedData)
|
|
334
355
|
|
|
335
356
|
if (
|
|
336
357
|
txTypes !== null &&
|
|
@@ -343,13 +364,20 @@ export default class TCaBCIClient {
|
|
|
343
364
|
if (!this.IsConnected()) throw new Error(NOT_CONNECTED)
|
|
344
365
|
|
|
345
366
|
const addrs = validateAddresses([
|
|
346
|
-
|
|
347
|
-
|
|
367
|
+
...new Set([...this._subscribedAddresses, ...requested])
|
|
368
|
+
]),
|
|
369
|
+
proof = Object.fromEntries(
|
|
370
|
+
addrs.map((address) => [
|
|
371
|
+
address,
|
|
372
|
+
suppliedProof[address] ?? this._SubscribedSignedData[address]
|
|
373
|
+
])
|
|
374
|
+
)
|
|
348
375
|
|
|
349
376
|
this._ws.send(
|
|
350
377
|
new Message({
|
|
351
378
|
isWeb: true,
|
|
352
379
|
type: SUBSCRIBEMessage,
|
|
380
|
+
clientInstanceID: this._clientInstanceID,
|
|
353
381
|
addrs: addrs,
|
|
354
382
|
signedData: proof,
|
|
355
383
|
txTypes
|
|
@@ -871,7 +899,13 @@ export default class TCaBCIClient {
|
|
|
871
899
|
this._callCloseCallback(e)
|
|
872
900
|
})
|
|
873
901
|
|
|
874
|
-
const start =
|
|
902
|
+
const start = (async () => {
|
|
903
|
+
await this._prepareInstanceID(this._randomizer)
|
|
904
|
+
|
|
905
|
+
if (!current()) return ws
|
|
906
|
+
|
|
907
|
+
return ws.connect()
|
|
908
|
+
})()
|
|
875
909
|
|
|
876
910
|
this._startPromise = start
|
|
877
911
|
|
|
@@ -886,6 +920,27 @@ export default class TCaBCIClient {
|
|
|
886
920
|
}
|
|
887
921
|
}
|
|
888
922
|
|
|
923
|
+
_prepareInstanceID(randomizer = null) {
|
|
924
|
+
if (this._clientInstanceID !== null)
|
|
925
|
+
return Promise.resolve(this._clientInstanceID)
|
|
926
|
+
|
|
927
|
+
if (this._instanceIDPromise) return this._instanceIDPromise
|
|
928
|
+
|
|
929
|
+
const pending = passKey(randomizer)
|
|
930
|
+
.then((identity) => {
|
|
931
|
+
this._clientInstanceID ??= identity
|
|
932
|
+
|
|
933
|
+
return this._clientInstanceID
|
|
934
|
+
})
|
|
935
|
+
.finally(() => {
|
|
936
|
+
if (this._instanceIDPromise === pending) this._instanceIDPromise = null
|
|
937
|
+
})
|
|
938
|
+
|
|
939
|
+
this._instanceIDPromise = pending
|
|
940
|
+
|
|
941
|
+
return pending
|
|
942
|
+
}
|
|
943
|
+
|
|
889
944
|
async _disconnect(code = 1000) {
|
|
890
945
|
code = closeCode(code)
|
|
891
946
|
|
|
@@ -1031,7 +1086,7 @@ export default class TCaBCIClient {
|
|
|
1031
1086
|
break
|
|
1032
1087
|
case Subscription:
|
|
1033
1088
|
if (_msg.State === OK) {
|
|
1034
|
-
this._setSubscribed(
|
|
1089
|
+
this._setSubscribed(this._subscribedAddresses.length > 0)
|
|
1035
1090
|
} else {
|
|
1036
1091
|
this._clearSubscription()
|
|
1037
1092
|
}
|
package/constants.d.ts
CHANGED
package/constants.js
CHANGED
package/http.js
CHANGED
|
@@ -2,12 +2,12 @@ import { SendThrow } from './util.js'
|
|
|
2
2
|
import { ERR_NETWORK, FetchError, INVALID_ARGUMENTS } from './errors.js'
|
|
3
3
|
import { Breaker } from './breaker.js'
|
|
4
4
|
import {
|
|
5
|
-
CLIENT_VERSION,
|
|
6
5
|
endpoint,
|
|
7
6
|
positiveInteger,
|
|
8
7
|
cloneAndFreeze,
|
|
9
8
|
byteLength
|
|
10
9
|
} from './validation.js'
|
|
10
|
+
import { CLIENT_VERSION } from './constants.js'
|
|
11
11
|
|
|
12
12
|
export class HTTP {
|
|
13
13
|
_baseURL
|
package/message.d.ts
CHANGED
package/message.js
CHANGED
|
@@ -26,6 +26,7 @@ export default class Message {
|
|
|
26
26
|
_txTypes
|
|
27
27
|
_data
|
|
28
28
|
_state
|
|
29
|
+
_clientInstanceID
|
|
29
30
|
|
|
30
31
|
/**
|
|
31
32
|
* @param {boolean} isWeb
|
|
@@ -34,6 +35,7 @@ export default class Message {
|
|
|
34
35
|
* @param {?Object} signedData
|
|
35
36
|
* @param {?Array<string>} txTypes
|
|
36
37
|
* @param {*} data
|
|
38
|
+
* @param {string|undefined} clientInstanceID Optional 64- or 128-character lowercase hex instance ID.
|
|
37
39
|
*/
|
|
38
40
|
constructor({
|
|
39
41
|
isWeb,
|
|
@@ -41,10 +43,12 @@ export default class Message {
|
|
|
41
43
|
addrs,
|
|
42
44
|
signedData = null,
|
|
43
45
|
txTypes = null,
|
|
44
|
-
data = null
|
|
46
|
+
data = null,
|
|
47
|
+
clientInstanceID
|
|
45
48
|
} = {}) {
|
|
46
49
|
this._is_web = isWeb
|
|
47
50
|
this._type = type
|
|
51
|
+
this._clientInstanceID = clientInstanceID
|
|
48
52
|
|
|
49
53
|
if (addrs && Array.isArray(addrs))
|
|
50
54
|
this._addresses = Object.freeze(addresses(addrs))
|
|
@@ -128,6 +132,9 @@ export default class Message {
|
|
|
128
132
|
|
|
129
133
|
if (typeof obj.state !== 'undefined') msg._state = obj.state
|
|
130
134
|
|
|
135
|
+
if (typeof obj.client_instance_id !== 'undefined')
|
|
136
|
+
msg._clientInstanceID = obj.client_instance_id
|
|
137
|
+
|
|
131
138
|
msg._validate()
|
|
132
139
|
|
|
133
140
|
return { message: Object.freeze(msg), error: null }
|
|
@@ -142,6 +149,9 @@ export default class Message {
|
|
|
142
149
|
return JSON.stringify({
|
|
143
150
|
is_web: this._is_web,
|
|
144
151
|
type: this._type,
|
|
152
|
+
...(typeof this._clientInstanceID !== 'undefined'
|
|
153
|
+
? { client_instance_id: this._clientInstanceID }
|
|
154
|
+
: {}),
|
|
145
155
|
...(this._addresses ? { addresses: this._addresses } : {}),
|
|
146
156
|
...(this._signedAddresses
|
|
147
157
|
? { signed_addresses: this._signedAddresses }
|
|
@@ -153,6 +163,13 @@ export default class Message {
|
|
|
153
163
|
}
|
|
154
164
|
|
|
155
165
|
_validate() {
|
|
166
|
+
if (
|
|
167
|
+
typeof this._clientInstanceID !== 'undefined' &&
|
|
168
|
+
(typeof this._clientInstanceID !== 'string' ||
|
|
169
|
+
!/^(?:[0-9a-f]{64}|[0-9a-f]{128})$/.test(this._clientInstanceID))
|
|
170
|
+
)
|
|
171
|
+
throw new Error(INVALID_ARGUMENT_WITH_CS('client_instance_id'))
|
|
172
|
+
|
|
156
173
|
if (
|
|
157
174
|
typeof this._is_web !== 'undefined' &&
|
|
158
175
|
typeof this._is_web !== 'boolean'
|
package/package.json
CHANGED
package/passKey.d.ts
ADDED
package/validation.d.ts
CHANGED
package/validation.js
CHANGED
package/websocketOptions.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createWSAuthorityV3 } from './authority.js'
|
|
2
|
-
import {
|
|
2
|
+
import { endpoint, positiveInteger } from './validation.js'
|
|
3
|
+
import { CLIENT_VERSION } from './constants.js'
|
|
3
4
|
|
|
4
5
|
export const HTTPSPort = 443,
|
|
5
6
|
HTTPPort = 80,
|
|
@@ -332,25 +333,30 @@ export class Options {
|
|
|
332
333
|
make() {
|
|
333
334
|
let WS = this._customWS
|
|
334
335
|
|
|
335
|
-
if (this._authority) {
|
|
336
|
+
if (this._authority || typeof WS?.prototype?.on === 'function') {
|
|
336
337
|
const Base = WS,
|
|
337
|
-
options = this
|
|
338
|
+
options = this,
|
|
339
|
+
requiresAuthority = Boolean(this._authority)
|
|
338
340
|
|
|
339
341
|
WS = class extends Base {
|
|
340
342
|
constructor(url, protocols) {
|
|
341
343
|
const authority = options._authority
|
|
342
344
|
|
|
343
|
-
if (!authority)
|
|
345
|
+
if (requiresAuthority && !authority)
|
|
344
346
|
throw new Error('Websocket authority configuration released')
|
|
345
347
|
|
|
346
348
|
super(url, protocols, {
|
|
347
349
|
followRedirects: false,
|
|
348
350
|
headers: {
|
|
349
351
|
Client: `tcabci-read-js-client/${CLIENT_VERSION}`,
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
352
|
+
...(authority
|
|
353
|
+
? {
|
|
354
|
+
'X-Authority': createWSAuthorityV3(
|
|
355
|
+
authority.address,
|
|
356
|
+
authority.sign
|
|
357
|
+
)
|
|
358
|
+
}
|
|
359
|
+
: {})
|
|
354
360
|
}
|
|
355
361
|
})
|
|
356
362
|
}
|
|
@@ -370,7 +376,7 @@ export class Options {
|
|
|
370
376
|
// ReconnectingWebSocket debug logs outgoing payloads. Never enable it.
|
|
371
377
|
debug: false,
|
|
372
378
|
headers: {
|
|
373
|
-
Client: `
|
|
379
|
+
Client: `tcabci-read-js-client/${this._version}`
|
|
374
380
|
}
|
|
375
381
|
}
|
|
376
382
|
}
|