@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 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({ isWeb: this._isWeb, type: LISTENMessage }).ToJSON()
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
- proof = validateSignedData(signedData)
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
- ...new Set([...this._subscribedAddresses, ...requested])
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 = ws.connect()
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(true)
1089
+ this._setSubscribed(this._subscribedAddresses.length > 0)
1035
1090
  } else {
1036
1091
  this._clearSubscription()
1037
1092
  }
package/constants.d.ts CHANGED
@@ -1 +1,3 @@
1
- export declare const READ_NODE_ADDRESS: string, READ_NODE_WS_ADDRESS: string
1
+ export declare const CLIENT_VERSION: string,
2
+ READ_NODE_ADDRESS: string,
3
+ READ_NODE_WS_ADDRESS: string
package/constants.js CHANGED
@@ -1,2 +1,3 @@
1
- export const READ_NODE_ADDRESS = 'https://read-node-01.transferchain.io',
1
+ export const CLIENT_VERSION = '2.8.3',
2
+ READ_NODE_ADDRESS = 'https://read-node-01.transferchain.io',
2
3
  READ_NODE_WS_ADDRESS = 'wss://read-node-01.transferchain.io/ws'
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
@@ -34,6 +34,7 @@ export default class Message {
34
34
  signedData?: Readonly<Record<string, string>> | null
35
35
  txTypes?: readonly TXType[] | null
36
36
  data?: JSONValue
37
+ clientInstanceID?: string
37
38
  })
38
39
 
39
40
  get IsWeb(): boolean | undefined
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tchain/tcabci-read-js-client",
3
- "version": "2.8.1",
3
+ "version": "2.8.3",
4
4
  "description": "TransferChain Fastest Read Network WebSocket Client",
5
5
  "homepage": "https://github.com/TransferChain/tcabci-read-js-client#readme",
6
6
  "bugs": {
package/passKey.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ export declare type Randomizer = (data: Uint8Array) => Uint8Array
2
+
3
+ /** Four UUID-v4 ASCII identifiers hashed with SHA-512; owned bytes are cleared. */
4
+ export declare function passKey(randomizer?: Randomizer): Promise<string>
package/validation.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { JSONValue } from './types.js'
2
2
 
3
- export declare const CLIENT_VERSION: string, MAX_ADDRESSES: number
3
+ export declare const MAX_ADDRESSES: number
4
4
 
5
5
  export declare function positiveInteger(value: number, name: string): number
6
6
 
package/validation.js CHANGED
@@ -1,5 +1,4 @@
1
- export const CLIENT_VERSION = '2.8.0',
2
- MAX_ADDRESSES = 251
1
+ export const MAX_ADDRESSES = 251
3
2
 
4
3
  export function positiveInteger(value, name) {
5
4
  if (!Number.isSafeInteger(value) || value <= 0)
@@ -1,5 +1,6 @@
1
1
  import { createWSAuthorityV3 } from './authority.js'
2
- import { CLIENT_VERSION, endpoint, positiveInteger } from './validation.js'
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
- 'X-Authority': createWSAuthorityV3(
351
- authority.address,
352
- authority.sign
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: `tcabaci-read-js-client/${this._version}`
379
+ Client: `tcabci-read-js-client/${this._version}`
374
380
  }
375
381
  }
376
382
  }