@tchain/tcabci-read-js-client 2.6.6 → 2.7.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/block.d.ts ADDED
@@ -0,0 +1,13 @@
1
+ import { Transaction } from './transaction'
2
+
3
+ export declare class Block {
4
+ get Height(): number
5
+ get TXS(): number
6
+ get Hash(): string|null
7
+ get Transactions(): Transaction[]
8
+ get ChainName(): string
9
+ get ChainVersion(): string
10
+
11
+ static FromJSON(value: string): { block?: Block, error?: Error }
12
+ static FromObject(obj: Record<string, any>): { block?: Block, error?: Error }
13
+ }
package/block.js ADDED
@@ -0,0 +1,110 @@
1
+ import { Transaction } from './transaction.js'
2
+
3
+ export class Block {
4
+ _height
5
+ _txs
6
+ _hash
7
+ _transactions
8
+ _chainName
9
+ _chainVersion
10
+
11
+ get Height() {
12
+ return this._height
13
+ }
14
+
15
+ get TXS() {
16
+ return this._txs
17
+ }
18
+
19
+ get Hash() {
20
+ return this._hash
21
+ }
22
+
23
+ get Transactions() {
24
+ return this._transactions
25
+ }
26
+
27
+ get ChainName() {
28
+ return this._chainName
29
+ }
30
+
31
+ get ChainVersion() {
32
+ return this._chainVersion
33
+ }
34
+
35
+ /**
36
+ * @param {string} value
37
+ * @return {{block: ?Block, error: ?Error}}
38
+ * @constructor
39
+ */
40
+ static FromJSON(value) {
41
+ try {
42
+ const bl = new Block(),
43
+ parsed = JSON.parse(value)
44
+
45
+ bl._transactions = []
46
+
47
+ if (typeof parsed.height !== 'undefined') bl._height = parsed.height
48
+ if (typeof parsed.txs !== 'undefined') bl._txs = parsed.txs
49
+ if (typeof parsed.hash !== 'undefined') bl._hash = parsed.hash
50
+ if (typeof parsed.chain_name !== 'undefined')
51
+ bl._chainName = parsed.chain_name
52
+ if (typeof parsed.chain_version !== 'undefined')
53
+ bl._chainVersion = parsed.chain_version
54
+
55
+ if (typeof parsed.transactions !== 'undefined') {
56
+ for (let i = 0; i < parsed.transactions.length; i++) {
57
+ const { transaction, error } = Transaction.FromObject(
58
+ parsed.transactions[i],
59
+ )
60
+ if (error) {
61
+ return { block: null, error: error }
62
+ }
63
+
64
+ bl._transactions.push(transaction)
65
+ }
66
+ }
67
+
68
+ return { block: bl, error: null }
69
+ } catch (e) {
70
+ return { block: null, error: e }
71
+ }
72
+ }
73
+
74
+ /**
75
+ * @param {object} obj
76
+ * @return {{block: ?Block, error: ?Error}}
77
+ * @constructor
78
+ */
79
+ static FromObject(obj) {
80
+ try {
81
+ const bl = new Block()
82
+
83
+ bl._transactions = []
84
+
85
+ if (typeof obj.height !== 'undefined') bl._height = obj.height
86
+ if (typeof obj.txs !== 'undefined') bl._txs = obj.txs
87
+ if (typeof obj.hash !== 'undefined') bl._hash = obj.hash
88
+ if (typeof obj.chain_name !== 'undefined') bl._chainName = obj.chain_name
89
+ if (typeof obj.chain_version !== 'undefined')
90
+ bl._chainVersion = obj.chain_version
91
+
92
+ if (typeof obj.transactions !== 'undefined') {
93
+ for (let i = 0; i < obj.transactions.length; i++) {
94
+ const { transaction, error } = Transaction.FromObject(
95
+ obj.transactions[i],
96
+ )
97
+ if (error) {
98
+ return { block: null, error: error }
99
+ }
100
+
101
+ bl._transactions.push(transaction)
102
+ }
103
+ }
104
+
105
+ return { block: bl, error: null }
106
+ } catch (e) {
107
+ return { block: null, error: e }
108
+ }
109
+ }
110
+ }
package/breaker.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export declare class Breaker {
2
+ execute(fn: () => Promise<any>): Promise<any>
3
+ }
package/breaker.js ADDED
@@ -0,0 +1,50 @@
1
+ import {
2
+ ConsecutiveBreaker,
3
+ ExponentialBackoff,
4
+ retry,
5
+ handleType,
6
+ circuitBreaker,
7
+ wrap,
8
+ } from 'cockatiel'
9
+ import { FetchError } from './errors.js'
10
+
11
+ export class Breaker {
12
+ _options = {
13
+ halfOpenAfter: 10 * 1000,
14
+ breaker: new ConsecutiveBreaker(10),
15
+ }
16
+ _retryPolicy = retry(
17
+ handleType(FetchError, (err) =>
18
+ [502, 503, 504].includes(err.status),
19
+ ).orType(Error, (err) => {
20
+ return err.message.toLowerCase().search('failed to fetch') > -1
21
+ }),
22
+ {
23
+ maxAttempts: 10,
24
+ backoff: new ExponentialBackoff({
25
+ initialDelay: 500,
26
+ maxDelay: 15000,
27
+ }),
28
+ },
29
+ )
30
+ _circuitBreakerPolicy = circuitBreaker(
31
+ handleType(FetchError, (err) =>
32
+ [502, 503, 504].includes(err.status),
33
+ ).orType(Error, (err) => {
34
+ return err.message.toLowerCase().search('failed to fetch') > -1
35
+ }),
36
+ this._options,
37
+ )
38
+ _retryWithBreaker = wrap(this._retryPolicy, this._circuitBreakerPolicy)
39
+ constructor() {}
40
+
41
+ /**
42
+ * @param {function} fn
43
+ * @return {Promise<*>}
44
+ */
45
+ execute(fn) {
46
+ return this._retryWithBreaker.execute(fn).catch((err) => {
47
+ return Promise.reject(err)
48
+ })
49
+ }
50
+ }
package/callback.d.ts CHANGED
@@ -1,6 +1,11 @@
1
1
  import { Transaction } from './transaction'
2
+ import { Block } from './block'
2
3
 
3
4
  export declare type SuccessCallback = (event: Event) => void
4
5
  export declare type ErrorCallback = (event: Event) => void
5
6
  export declare type CloseCallback = (event: Event) => void
6
- export declare type ListenCallback = (tx: Transaction) => void
7
+ export declare type ListenCallback = (
8
+ block: Block | null,
9
+ tx: Transaction | null,
10
+ msg: any | null,
11
+ ) => void
package/client.js CHANGED
@@ -1,8 +1,6 @@
1
1
  import {
2
- FetchError,
3
2
  ALREADY_CONNECTED,
4
3
  BLOCK_NOT_FOUND,
5
- ERR_NETWORK,
6
4
  INVALID_ARGUMENT_WITH_CS,
7
5
  INVALID_ARGUMENTS,
8
6
  NOT_CONNECTED,
@@ -11,10 +9,19 @@ import {
11
9
  TRANSACTION_TYPE_NOT_VALID,
12
10
  } from './errors.js'
13
11
  import { READ_NODE_ADDRESS, READ_NODE_WS_ADDRESS } from './constants.js'
14
- import Message, { SUBSCRIBEMessage, UNSUBSCRIBEMessage } from './message.js'
12
+ import Message, {
13
+ Block as MBlock,
14
+ Transaction as MTransaction,
15
+ SUBSCRIBEMessage,
16
+ UNSUBSCRIBEMessage,
17
+ Subscription,
18
+ OK,
19
+ } from './message.js'
15
20
  import { Options } from './websocketOptions.js'
16
21
  import { TWebSocket } from './websocket.js'
17
22
  import { Transaction, TX_TYPE_LIST } from './transaction.js'
23
+ import { Block } from './block.js'
24
+ import { HTTP } from './http.js'
18
25
 
19
26
  /**
20
27
  * @callback SuccessCallback
@@ -36,18 +43,21 @@ import { Transaction, TX_TYPE_LIST } from './transaction.js'
36
43
 
37
44
  /**
38
45
  * @callback ListenCallback
39
- * @param {*} message
46
+ * @param {?Block} block
47
+ * @param {?Transaction} transaction
48
+ * @param {?*} msg
40
49
  * @return void
41
50
  */
42
51
 
43
52
  export default class TCaBCIClient {
53
+ _httpClient = new HTTP()
44
54
  _subscribed = false
45
55
  _subscribedAddresses = []
46
56
  _SubscribedSignedData = {}
47
57
  _connected = false
48
58
  _chainName = 'transferchain'
49
59
  _chainVersion = 'v1'
50
- _version = `v2.6.6`
60
+ _version = `v2.7.1`
51
61
  /**
52
62
  * @type {?SuccessCallback}
53
63
  */
@@ -100,6 +110,7 @@ export default class TCaBCIClient {
100
110
 
101
111
  this._readNodeAddress = readNodeAddresses[0]
102
112
  this._readNodeWSAddress = readNodeAddresses[1]
113
+ this._httpClient.setBaseURL(readNodeAddresses[0])
103
114
  }
104
115
 
105
116
  this._options = new Options(this._readNodeWSAddress)
@@ -258,18 +269,16 @@ export default class TCaBCIClient {
258
269
  addrs.push(...newAddress)
259
270
  }
260
271
 
261
- const message = new Message(
262
- true,
263
- SUBSCRIBEMessage,
264
- addrs,
265
- _signedData,
266
- txTypes,
272
+ this._ws.send(
273
+ new Message({
274
+ isWeb: true,
275
+ type: SUBSCRIBEMessage,
276
+ addrs: addrs,
277
+ signedData: _signedData,
278
+ txTypes,
279
+ }).ToJSON(),
267
280
  )
268
-
269
- this._ws.send(message.ToJSON())
270
- this._setSubscribeAddresses(addrs, true)
271
- ._setSubscribeSignedData(signedData)
272
- ._setSubscribed(true)
281
+ this._setSubscribeAddresses(addrs, true)._setSubscribeSignedData(signedData)
273
282
 
274
283
  return this
275
284
  }
@@ -282,7 +291,11 @@ export default class TCaBCIClient {
282
291
  throw new Error(NOT_SUBSCRIBED)
283
292
  }
284
293
  this._ws.send(
285
- new Message(true, UNSUBSCRIBEMessage, this.SubscribeAddresses).ToJSON(),
294
+ new Message({
295
+ isWeb: true,
296
+ type: UNSUBSCRIBEMessage,
297
+ addrs: this.SubscribeAddresses,
298
+ }).ToJSON(),
286
299
  )
287
300
  this._setSubscribed(false)
288
301
  this._setSubscribeAddresses([])
@@ -297,12 +310,13 @@ export default class TCaBCIClient {
297
310
  * @return {Promise<{blocks: Transaction[], total_count: number}>}
298
311
  */
299
312
  LastBlock(chainName = null, chainVersion = null) {
300
- return this._httpClient(
301
- `/v1/blocks?chain_name=${chainName ?? this._chainName}&chain_version=${chainVersion ?? this._chainVersion}&limit=1&offset=0`,
302
- {
303
- method: 'GET',
304
- },
305
- )
313
+ return this._httpClient
314
+ .request(
315
+ `/v1/blocks?chain_name=${chainName ?? this._chainName}&chain_version=${chainVersion ?? this._chainVersion}&limit=1&offset=0`,
316
+ {
317
+ method: 'GET',
318
+ },
319
+ )
306
320
  .then((res) => {
307
321
  const data = []
308
322
 
@@ -314,7 +328,7 @@ export default class TCaBCIClient {
314
328
 
315
329
  return { blocks: data, total_count: res.total_count }
316
330
  })
317
- .catch((e) => this._handleRestError(e, new Error(BLOCK_NOT_FOUND)))
331
+ .catch((e) => this._httpClient.handleError(e, new Error(BLOCK_NOT_FOUND)))
318
332
  }
319
333
 
320
334
  /**
@@ -327,17 +341,18 @@ export default class TCaBCIClient {
327
341
  return Promise.reject(new Error(INVALID_ARGUMENTS))
328
342
  }
329
343
 
330
- return this._httpClient(`/v1/tx/${id}`, {
331
- method: 'GET',
332
- headers: { 'X-Signature': signature },
333
- })
344
+ return this._httpClient
345
+ .request(`/v1/tx/${id}`, {
346
+ method: 'GET',
347
+ headers: { 'X-Signature': signature },
348
+ })
334
349
  .then((res) => {
335
350
  const { transaction, error } = Transaction.FromObject(res.data)
336
351
  if (error) return Promise.reject(error)
337
352
 
338
353
  return { tx: transaction }
339
354
  })
340
- .catch((e) => this._handleRestError(e))
355
+ .catch((e) => this._httpClient.handleError(e))
341
356
  }
342
357
 
343
358
  /**
@@ -371,17 +386,18 @@ export default class TCaBCIClient {
371
386
  return Promise.reject(new Error(INVALID_ARGUMENTS))
372
387
  }
373
388
 
374
- return this._httpClient('/v1/tx_summary', {
375
- method: 'POST',
376
- body: JSON.stringify({
377
- chain_name: chainName ?? this._chainName,
378
- chain_version: chainVersion ?? this._chainVersion,
379
- recipient_addrs: recipientAddrs,
380
- sender_addrs: senderAddrs,
381
- signed_addrs: signedData,
382
- ...(types ? { types: types } : { typ: typ }),
383
- }),
384
- })
389
+ return this._httpClient
390
+ .request('/v1/tx_summary', {
391
+ method: 'POST',
392
+ body: JSON.stringify({
393
+ chain_name: chainName ?? this._chainName,
394
+ chain_version: chainVersion ?? this._chainVersion,
395
+ recipient_addrs: recipientAddrs,
396
+ sender_addrs: senderAddrs,
397
+ signed_addrs: signedData,
398
+ ...(types ? { types: types } : { typ: typ }),
399
+ }),
400
+ })
385
401
  .then((res) => {
386
402
  let firstTransaction, lastTransaction
387
403
 
@@ -411,7 +427,7 @@ export default class TCaBCIClient {
411
427
  total_count: res.total_count,
412
428
  }
413
429
  })
414
- .catch((e) => this._handleRestError(e))
430
+ .catch((e) => this._httpClient.handleError(e))
415
431
  }
416
432
 
417
433
  /**
@@ -451,25 +467,26 @@ export default class TCaBCIClient {
451
467
  chainName = null,
452
468
  chainVersion = null,
453
469
  }) {
454
- return this._httpClient('/v1/tx_search/p', {
455
- method: 'POST',
456
- body: JSON.stringify({
457
- chain_name: chainName ?? this._chainName,
458
- chain_version: chainVersion ?? this._chainVersion,
459
- height: `${heightOperator} ${height}`,
460
- ...(maxHeight ? { max_height: maxHeight } : {}),
461
- ...(lastOrder ? { last_order: lastOrder } : {}),
462
- ...(recipientAddrs ? { recipient_addrs: recipientAddrs } : {}),
463
- ...(senderAddrs ? { sender_addrs: senderAddrs } : {}),
464
- ...(signedData ? { signed_addrs: signedData } : {}),
465
- ...(hashes ? { hashes: hashes } : {}),
466
- ...(limit ? { limit: limit } : {}),
467
- ...(offset ? { offset: offset } : {}),
468
- ...(orderField ? { order_field: orderField } : {}),
469
- ...(orderBy ? { order_by: orderBy } : {}),
470
- ...(types ? { types: types } : typ ? { typ: typ } : {}),
471
- }),
472
- })
470
+ return this._httpClient
471
+ .request('/v1/tx_search/p', {
472
+ method: 'POST',
473
+ body: JSON.stringify({
474
+ chain_name: chainName ?? this._chainName,
475
+ chain_version: chainVersion ?? this._chainVersion,
476
+ height: `${heightOperator} ${height}`,
477
+ ...(maxHeight ? { max_height: maxHeight } : {}),
478
+ ...(lastOrder ? { last_order: lastOrder } : {}),
479
+ ...(recipientAddrs ? { recipient_addrs: recipientAddrs } : {}),
480
+ ...(senderAddrs ? { sender_addrs: senderAddrs } : {}),
481
+ ...(signedData ? { signed_addrs: signedData } : {}),
482
+ ...(hashes ? { hashes: hashes } : {}),
483
+ ...(limit ? { limit: limit } : {}),
484
+ ...(offset ? { offset: offset } : {}),
485
+ ...(orderField ? { order_field: orderField } : {}),
486
+ ...(orderBy ? { order_by: orderBy } : {}),
487
+ ...(types ? { types: types } : typ ? { typ: typ } : {}),
488
+ }),
489
+ })
473
490
  .then((res) => {
474
491
  const data = []
475
492
 
@@ -484,7 +501,7 @@ export default class TCaBCIClient {
484
501
  total_count: res.total_count,
485
502
  }
486
503
  })
487
- .catch((e) => this._handleRestError(e))
504
+ .catch((e) => this._httpClient.handleError(e))
488
505
  }
489
506
 
490
507
  /**
@@ -630,9 +647,8 @@ export default class TCaBCIClient {
630
647
  throw new Error(TRANSACTION_TYPE_NOT_VALID)
631
648
  }
632
649
 
633
- return this._httpClient(
634
- commit ? '/v1/tx/commit' : sync ? '/v1/tx/sync' : '/v1/tx',
635
- {
650
+ return this._httpClient
651
+ .request(commit ? '/v1/tx/commit' : sync ? '/v1/tx/sync' : '/v1/tx', {
636
652
  method: 'POST',
637
653
  body: JSON.stringify({
638
654
  id,
@@ -646,13 +662,14 @@ export default class TCaBCIClient {
646
662
  sign,
647
663
  fee,
648
664
  }),
649
- },
650
- )
665
+ })
651
666
  .then((res) => {
652
667
  return { data: res.data }
653
668
  })
654
669
  .catch((e) =>
655
- this._handleRestError(e, { 400: new Error(TRANSACTION_NOT_BROADCAST) }),
670
+ this._httpClient.handleError(e, {
671
+ 400: new Error(TRANSACTION_NOT_BROADCAST),
672
+ }),
656
673
  )
657
674
  }
658
675
 
@@ -672,7 +689,7 @@ export default class TCaBCIClient {
672
689
  chainName = null,
673
690
  chainVersion = null,
674
691
  ) {
675
- return this._httpClient('/v1/bulk_tx', {
692
+ return this._httpClient.request('/v1/bulk_tx', {
676
693
  method: 'POST',
677
694
  body: JSON.stringify({
678
695
  chain_name: chainName ?? this._chainName,
@@ -708,10 +725,6 @@ export default class TCaBCIClient {
708
725
  })
709
726
 
710
727
  this._ws.addMessageListener((message) => {
711
- if (message.data === 'OK' && message.data.length < 10) {
712
- return { status: message.data }
713
- }
714
-
715
728
  this._callListenCallback(message.data)
716
729
  })
717
730
 
@@ -788,73 +801,48 @@ export default class TCaBCIClient {
788
801
  }
789
802
 
790
803
  _callListenCallback(message) {
791
- const { transaction, error } = Transaction.FromJSON(message)
792
- if (error) this._callErrorCallback(error)
793
- else if (this._listenCb) this._listenCb(transaction)
794
- }
795
-
796
- /**
797
- * @param {string} uri
798
- * @param {RequestInit} req
799
- * @return {Promise<Record<string, any>>}
800
- */
801
- _httpClient(uri, req) {
802
- req.cache = 'no-cache'
803
- req.headers = {
804
- Client: `tcabaci-read-js-client/${this._version}`,
805
- }
806
- req.priority = 'high'
807
-
808
- return fetch(this._readNodeAddress + uri, req).then((response) =>
809
- this._handleRestResponse(response),
810
- )
811
- }
812
-
813
- /**
814
- * @param {Response} response
815
- * @return {Promise<*>}
816
- */
817
- async _handleRestResponse(response) {
818
- if (response.status >= 200 && response.status < 400) {
819
- return response.json()
820
- }
821
-
822
- try {
823
- const data = JSON.parse(await response.text())
824
-
825
- return Promise.reject(
826
- new FetchError(data.message)
827
- .setStatus(response.status)
828
- .setResponse(data),
829
- )
830
- } catch (e) {
831
- return Promise.reject(
832
- new FetchError(response.statusText).setOriginError(e),
833
- )
834
- }
835
- }
836
-
837
- /**
838
- * @param {Error} err
839
- * @param {?Object|Error} custom
840
- * @throws Error
841
- */
842
- _handleRestError(err, custom = null) {
843
- const code = err.code
844
-
845
- if (custom && typeof custom === 'object' && custom[code]) {
846
- throw custom[code]
847
- } else if (custom instanceof Error) {
848
- throw custom
849
- }
804
+ let msg
805
+
806
+ const { transaction, error: e1 } = Transaction.FromJSON(message)
807
+ if (e1) {
808
+ const { message: _msg, error: e2 } = Message.FromJSON(message)
809
+ if (e2) {
810
+ this._callErrorCallback(e2)
811
+ return
812
+ }
850
813
 
851
- switch (code) {
852
- case 400:
853
- throw new Error(INVALID_ARGUMENTS)
854
- case 'ERR_NETWORK':
855
- throw new Error(ERR_NETWORK)
856
- default:
857
- throw err
814
+ switch (_msg.type) {
815
+ case MBlock:
816
+ msg = Block.FromObject(_msg.data)
817
+ if (msg.error) {
818
+ this._callErrorCallback(msg.error)
819
+ return
820
+ }
821
+
822
+ if (this._listenCb) this._listenCb(msg.block, null, null)
823
+ break
824
+ case MTransaction:
825
+ msg = Transaction.FromObject(_msg.data)
826
+ if (msg.error) {
827
+ this._callErrorCallback(msg.error)
828
+ return
829
+ }
830
+
831
+ if (this._listenCb) this._listenCb(null, msg.transaction, null)
832
+ break
833
+ case Subscription:
834
+ if (message.state === OK) {
835
+ this._setSubscribed(true)
836
+ } else {
837
+ this._setSubscribed(false)
838
+ }
839
+ break
840
+ default:
841
+ if (this._listenCb) this._listenCb(null, null, _msg)
842
+ break
843
+ }
844
+ } else {
845
+ if (this._listenCb) this._listenCb(null, transaction, null)
858
846
  }
859
847
  }
860
848
  }
package/constants.d.ts CHANGED
@@ -1,8 +1,2 @@
1
- export declare type MessageType = string
2
-
3
- export declare const SUBSCRIBEMessage: MessageType,
4
- UNSUBSCRIBEMessage: MessageType
5
-
6
- export declare const CHARACTERS: string,
7
- READ_NODE_ADDRESS: string,
1
+ export declare const READ_NODE_ADDRESS: string,
8
2
  READ_NODE_WS_ADDRESS: string
package/errors.js CHANGED
@@ -12,6 +12,24 @@ export const ALREADY_CONNECTED = 'Already connected',
12
12
  TRANSACTION_TYPE_NOT_VALID = 'Transaction type is not valid',
13
13
  TRANSACTION_NOT_BROADCAST = 'Transaction can not be broadcast'
14
14
 
15
+ export class CopiedError extends Error {
16
+ originName
17
+ originError
18
+ originStack
19
+
20
+ /**
21
+ * @param {Error} err
22
+ */
23
+ constructor(err) {
24
+ super(err.message)
25
+ this.name = 'CopiedError'
26
+ this.originName = err.name
27
+ this.originError = err
28
+ this.stack = err.stack
29
+ this.originStack = err.stack
30
+ }
31
+ }
32
+
15
33
  export class FetchError extends Error {
16
34
  status = -1
17
35
  response
package/http.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ import { Request } from 'express'
2
+
3
+ export declare class HTTP {
4
+ constructor(baseURL: string)
5
+ setBaseURL(baseURL: string): HTTP
6
+ request(uri: string, req: Request): Promise<Record<string, any>>
7
+ handleResponse(response: Response): Promise<any>
8
+ handleError(err: Error, custom: Record<string, any>|Error): Promise<any>
9
+ }
package/http.js ADDED
@@ -0,0 +1,81 @@
1
+ import { ERR_NETWORK, FetchError, INVALID_ARGUMENTS } from './errors.js'
2
+ import { Breaker } from './breaker.js'
3
+
4
+ export class HTTP {
5
+ _baseURL
6
+ _version = 'v2.7.1'
7
+ _breaker = new Breaker()
8
+ constructor(baseURL = null) {
9
+ this._baseURL = baseURL
10
+ }
11
+ setBaseURL(baseURL) {
12
+ this._baseURL = baseURL
13
+ return this
14
+ }
15
+ /**
16
+ * @param {string} uri
17
+ * @param {RequestInit} req
18
+ * @return {Promise<Record<string, any>>}
19
+ */
20
+ async request(uri, req) {
21
+ req.cache = 'no-cache'
22
+ req.headers = {
23
+ Client: `tcabaci-read-js-client/${this._version}`,
24
+ }
25
+ req.priority = 'high'
26
+
27
+ return this._breaker
28
+ .execute(() => {
29
+ return fetch(this._baseURL + uri, req)
30
+ })
31
+ .then((response) => this.handleResponse(response))
32
+ }
33
+
34
+ /**
35
+ * @param {Response} response
36
+ * @return {Promise<*>}
37
+ */
38
+ async handleResponse(response) {
39
+ if (response.status >= 200 && response.status < 400) {
40
+ return response.json()
41
+ }
42
+
43
+ try {
44
+ const data = JSON.parse(await response.text())
45
+
46
+ return Promise.reject(
47
+ new FetchError(data.message)
48
+ .setStatus(response.status)
49
+ .setResponse(data),
50
+ )
51
+ } catch (e) {
52
+ return Promise.reject(
53
+ new FetchError(response.statusText).setOriginError(e),
54
+ )
55
+ }
56
+ }
57
+
58
+ /**
59
+ * @param {Error} err
60
+ * @param {?Object|Error} custom
61
+ * @return {Promise<Error>}
62
+ */
63
+ async handleError(err, custom = null) {
64
+ const code = err.code
65
+
66
+ if (custom && typeof custom === 'object' && custom[code]) {
67
+ return Promise.reject(custom[code])
68
+ } else if (custom instanceof Error) {
69
+ return Promise.reject(custom)
70
+ }
71
+
72
+ switch (code) {
73
+ case 400:
74
+ return Promise.reject(new Error(INVALID_ARGUMENTS))
75
+ case 'ERR_NETWORK':
76
+ return Promise.reject(new Error(ERR_NETWORK))
77
+ default:
78
+ return Promise.reject(err)
79
+ }
80
+ }
81
+ }
package/message.d.ts CHANGED
@@ -1,13 +1,46 @@
1
- import { MessageType } from './constants'
2
1
  import { TXType } from './transaction'
3
2
 
3
+ export declare type MessageType = string
4
+
5
+ export declare const SUBSCRIBEMessage: MessageType,
6
+ UNSUBSCRIBEMessage: MessageType
7
+
8
+ export declare type MType = number
9
+
10
+ export declare const Block: MessageType,
11
+ Transaction: MessageType,
12
+ Subscription: MessageType,
13
+ Listen: MessageType,
14
+ MSG: MessageType
15
+
16
+ export declare type MState = number
17
+
18
+ export declare const OK: MState,
19
+ FAIL: MState
20
+
4
21
  export declare class Message {
5
- constructor(
6
- isWeb: boolean,
7
- type: MessageType,
8
- addrs: string[],
9
- signedData?: Record<string, string>,
10
- txTypes?: TXType[],
11
- )
22
+ constructor({
23
+ isWeb,
24
+ type,
25
+ addrs,
26
+ signedData,
27
+ txTypes,
28
+ }?: {
29
+ isWeb: boolean
30
+ type: MessageType
31
+ addrs: string[]
32
+ signedData?: Record<string, string>
33
+ txTypes?: TXType[]
34
+ })
35
+ get IsWeb(): boolean
36
+ get Type(): MessageType
37
+ get Addresses(): string[] | null
38
+ get SignedAddresses(): Record<string, string> | null
39
+ get TXTypes(): TXType[] | null
40
+ get Data(): any | null
41
+ get State(): MState | null
42
+
43
+ static FromJSON(value: string): { message?: Message; error?: Error }
44
+ static FromObject(obj: Record<string, any>): { message?: Message; error?: Error }
12
45
  ToJSON(): string
13
46
  }
package/message.js CHANGED
@@ -1,29 +1,115 @@
1
- import { INVALID_ARGUMENTS, INVALID_ARGUMENT_WITH_CS } from './errors.js'
1
+ import { INVALID_ARGUMENT_WITH_CS } from './errors.js'
2
2
  import { TX_TYPE_LIST } from './transaction.js'
3
3
 
4
4
  export const SUBSCRIBEMessage = 'subscribe',
5
5
  UNSUBSCRIBEMessage = 'unsubscribe'
6
6
 
7
+ export const Block = 0,
8
+ Transaction = 1,
9
+ Subscription = 2,
10
+ Listen = 3,
11
+ MSG = 4
12
+
13
+ export const OK = 1,
14
+ FAIL = 2
15
+
7
16
  export default class Message {
8
17
  _is_web = false
9
- _type = ''
10
- _addrs = []
11
- _signedData = {}
12
- _txTypes = []
18
+ _type
19
+ _addresses
20
+ _signedAddresses
21
+ _txTypes
22
+ _data
23
+ _state
13
24
 
14
25
  /**
15
26
  * @param {boolean} isWeb
16
- * @param {string} type
27
+ * @param {string|number} type
17
28
  * @param {Array<string>} addrs
18
29
  * @param {?Object} signedData
19
30
  * @param {?Array<string>} txTypes
31
+ * @param {*} data
20
32
  */
21
- constructor(isWeb, type, addrs, signedData = null, txTypes = null) {
33
+ constructor({
34
+ isWeb,
35
+ type,
36
+ addrs,
37
+ signedData = null,
38
+ txTypes = null,
39
+ data = null,
40
+ } = {}) {
22
41
  this._is_web = isWeb
23
42
  this._type = type
24
- if (addrs && Array.isArray(addrs)) this._addrs = addrs
25
- if (typeof signedData === 'object') this._signedData = signedData
43
+ if (addrs && Array.isArray(addrs)) this._addresses = addrs
44
+ if (typeof signedData === 'object') this._signedAddresses = signedData
26
45
  if (txTypes && Array.isArray(txTypes)) this._txTypes = txTypes
46
+ if (data) this._data = data
47
+ }
48
+
49
+ get IsWeb() {
50
+ return this._is_web
51
+ }
52
+
53
+ get Type() {
54
+ return this._type
55
+ }
56
+
57
+ get Addresses() {
58
+ return this._addresses
59
+ }
60
+
61
+ get SignedAddresses() {
62
+ return this._signedAddresses
63
+ }
64
+
65
+ get Data() {
66
+ return this._data
67
+ }
68
+
69
+ get State() {
70
+ return this._state
71
+ }
72
+
73
+ static FromJSON(value) {
74
+ try {
75
+ const msg = new Message(),
76
+ parsed = JSON.parse(value)
77
+
78
+ msg._type = parsed.type
79
+ if (typeof parsed.addresses !== 'undefined')
80
+ msg._addresses = parsed.addresses
81
+ if (typeof parsed.signed_addresses !== 'undefined')
82
+ msg._signedAddresses = parsed.signed_addresses
83
+ if (typeof parsed.data !== 'undefined') msg._data = parsed.data
84
+ if (typeof parsed.tx_types !== 'undefined') msg._txTypes = parsed.tx_types
85
+ if (typeof parsed.state !== 'undefined') msg._state = parsed.state
86
+
87
+ msg._validate()
88
+
89
+ return { message: this, error: null }
90
+ } catch (e) {
91
+ return { message: null, error: e }
92
+ }
93
+ }
94
+
95
+ static FromObject(obj) {
96
+ try {
97
+ const msg = new Message()
98
+
99
+ msg._type = obj.type
100
+ if (typeof obj.addresses !== 'undefined') msg._addresses = obj.addresses
101
+ if (typeof obj.signed_addresses !== 'undefined')
102
+ msg._signedAddresses = obj.signed_addresses
103
+ if (typeof obj.data !== 'undefined') msg._data = obj.data
104
+ if (typeof obj.tx_types !== 'undefined') msg._txTypes = obj.tx_types
105
+ if (typeof obj.state !== 'undefined') msg._state = obj.state
106
+
107
+ msg._validate()
108
+
109
+ return { message: this, error: null }
110
+ } catch (e) {
111
+ return { message: null, error: e }
112
+ }
27
113
  }
28
114
 
29
115
  ToJSON() {
@@ -32,39 +118,66 @@ export default class Message {
32
118
  return JSON.stringify({
33
119
  is_web: this._is_web,
34
120
  type: this._type,
35
- addrs: this._addrs,
36
- signed_addrs: this._signedData,
37
- ...(this._txTypes.length > 0 ? { tx_types: this._txTypes } : {}),
121
+ ...(this._addresses ? { addresses: this._addresses } : {}),
122
+ ...(this._signedAddresses
123
+ ? { signed_addresses: this._signedAddresses }
124
+ : {}),
125
+ ...(this._txTypes ? { tx_types: this._txTypes } : {}),
126
+ ...(this._data ? { data: this._data } : {}),
38
127
  })
39
128
  }
40
129
 
41
130
  _validate() {
42
- if (typeof this._is_web !== 'boolean') {
131
+ if (
132
+ typeof this._is_web !== 'undefined' &&
133
+ typeof this._is_web !== 'boolean'
134
+ ) {
43
135
  throw new Error(INVALID_ARGUMENT_WITH_CS('is_web'))
44
136
  }
45
137
 
46
- if (typeof this._type !== 'string') {
138
+ if (typeof this._type === 'undefined') {
47
139
  throw new Error(INVALID_ARGUMENT_WITH_CS('type'))
140
+ } else {
141
+ if (
142
+ typeof this._type === 'string' &&
143
+ ![SUBSCRIBEMessage, UNSUBSCRIBEMessage].includes(this._type)
144
+ ) {
145
+ throw new Error(INVALID_ARGUMENT_WITH_CS('type'))
146
+ } else if (
147
+ typeof this._type === 'number' &&
148
+ ![Block, Transaction, Subscription, Listen, MSG].includes(this._type)
149
+ ) {
150
+ throw new Error(INVALID_ARGUMENT_WITH_CS('type'))
151
+ }
48
152
  }
49
153
 
50
- if (!Array.isArray(this._addrs)) {
51
- throw new Error(INVALID_ARGUMENT_WITH_CS('addrs'))
52
- }
53
-
54
- if (typeof this._signedData !== 'object') {
55
- throw new Error(INVALID_ARGUMENT_WITH_CS('signedData'))
154
+ if (
155
+ typeof this._addresses !== 'undefined' &&
156
+ !Array.isArray(this._addresses)
157
+ ) {
158
+ throw new Error(INVALID_ARGUMENT_WITH_CS('addresses'))
56
159
  }
57
160
 
58
- if (![SUBSCRIBEMessage, UNSUBSCRIBEMessage].includes(this._type)) {
59
- throw new Error(INVALID_ARGUMENTS)
161
+ if (
162
+ typeof this._signedAddresses !== 'undefined' &&
163
+ typeof this._signedAddresses !== 'object'
164
+ ) {
165
+ throw new Error(INVALID_ARGUMENT_WITH_CS('signedAddresses'))
60
166
  }
61
167
 
62
- if (this._txTypes.length) {
168
+ if (typeof this._txTypes !== 'undefined' && this._txTypes.length) {
63
169
  for (let i = 0; i < this._txTypes.length; i++) {
64
170
  if (!TX_TYPE_LIST.includes(this._txTypes[i])) {
65
171
  throw new Error(INVALID_ARGUMENT_WITH_CS('tx_types'))
66
172
  }
67
173
  }
68
174
  }
175
+
176
+ if (
177
+ typeof this._state !== 'undefined' &&
178
+ ![OK, FAIL].includes(this._state)
179
+ ) {
180
+ throw new Error(INVALID_ARGUMENT_WITH_CS('state'))
181
+ }
69
182
  }
70
183
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tchain/tcabci-read-js-client",
3
- "version": "2.6.6",
3
+ "version": "2.7.1",
4
4
  "description": "TransferChain Fastest Read Network WebSocket Client",
5
5
  "main": "client.js",
6
6
  "type": "module",
@@ -11,6 +11,9 @@
11
11
  "files": [
12
12
  "*.d.ts",
13
13
  "constants.js",
14
+ "breaker.js",
15
+ "http.js",
16
+ "block.js",
14
17
  "client.js",
15
18
  "errors.js",
16
19
  "message.js",
@@ -42,6 +45,7 @@
42
45
  "ws": "^8.20.0"
43
46
  },
44
47
  "dependencies": {
48
+ "cockatiel": "^3.2.1",
45
49
  "reconnecting-websocket": "^4.4.0"
46
50
  },
47
51
  "scripts": {
package/transaction.js CHANGED
@@ -275,6 +275,8 @@ export class Transaction {
275
275
  if (typeof parsed.chain_version !== 'undefined')
276
276
  this._chainVersion = parsed.chain_version
277
277
 
278
+ tx.Validate()
279
+
278
280
  return { transaction: tx, error: null }
279
281
  } catch (e) {
280
282
  return { transaction: null, error: e }
@@ -309,10 +311,11 @@ export class Transaction {
309
311
  tx._hash = obj.hash
310
312
  if (typeof obj.inserted_at !== 'undefined')
311
313
  tx._inserted_at = new Date(obj.inserted_at)
312
- if (typeof obj.chain_name !== 'undefined')
313
- this._chainName = obj.chain_name
314
+ if (typeof obj.chain_name !== 'undefined') tx._chainName = obj.chain_name
314
315
  if (typeof obj.chain_version !== 'undefined')
315
- this._chainVersion = obj.chain_version
316
+ tx._chainVersion = obj.chain_version
317
+
318
+ tx.Validate()
316
319
 
317
320
  return { transaction: tx, error: null }
318
321
  } catch (e) {
@@ -13,7 +13,7 @@ export class Options {
13
13
  _protocols = []
14
14
  _customWS
15
15
  _endpoints = ['ws', 'longpoll']
16
- _version = `v2.6.6`
16
+ _version = `v2.7.1`
17
17
 
18
18
  _maxConnectionDelay = 10000
19
19
  _minReconnectionDelay = 1000 + Math.random() * 4000