@tchain/tcabci-read-js-client 2.4.0 → 2.5.0

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_test.js CHANGED
@@ -10,26 +10,30 @@ import {
10
10
  READ_NODE_WS_ADDRESS,
11
11
  TX_TYPE,
12
12
  } from './constants.js'
13
- //
14
- // const {
15
- // TX_TYPE,
16
- // READ_NODE_ADDRESS,
17
- // READ_NODE_WS_ADDRESS,
18
- // } = require('./constants')
19
- //
20
- // const { randomString } = require('./util')
13
+
14
+ const waiter = async (timeout = 1000) => {
15
+ return new Promise((resolve) => setTimeout(resolve, timeout))
16
+ }
21
17
 
22
18
  describe('TCaBCIClient', () => {
23
19
  it('start with valid parameters', (done) => {
24
- const client = new TCaBCIClient([], WebSocket, 'transferchain', 'v1')
20
+ const client = new TCaBCIClient([], WebSocket, 'medusa', 'v2')
25
21
 
26
22
  client
27
23
  .Start()
24
+ .then(() => {
25
+ return waiter(500)
26
+ })
28
27
  .then(() => {
29
28
  const { connected, subscribed } = client.Status()
30
29
 
31
30
  unitJS.assert.equal(connected, true)
32
31
  unitJS.assert.equal(subscribed, false)
32
+ })
33
+ .then(() => {
34
+ return client.Disconnect()
35
+ })
36
+ .then(() => {
33
37
  done()
34
38
  })
35
39
  .catch((err) => {
@@ -41,17 +45,25 @@ describe('TCaBCIClient', () => {
41
45
  const client = new TCaBCIClient(
42
46
  [READ_NODE_ADDRESS, READ_NODE_WS_ADDRESS],
43
47
  WebSocket,
44
- 'transferchain',
45
- 'v1',
48
+ 'medusa',
49
+ 'v2',
46
50
  )
47
51
 
48
52
  client
49
53
  .Start()
54
+ .then(() => {
55
+ return waiter(500)
56
+ })
50
57
  .then(() => {
51
58
  const { connected, subscribed } = client.Status()
52
59
 
53
60
  unitJS.assert.equal(connected, true)
54
61
  unitJS.assert.equal(subscribed, false)
62
+ })
63
+ .then(() => {
64
+ return client.Disconnect()
65
+ })
66
+ .then(() => {
55
67
  done()
56
68
  })
57
69
  .catch((err) => {
@@ -60,34 +72,49 @@ describe('TCaBCIClient', () => {
60
72
  })
61
73
 
62
74
  it('reconnect with start and valid parameters', (done) => {
63
- const client = new TCaBCIClient([], WebSocket, 'transferchain', 'v1')
75
+ const client = new TCaBCIClient([], WebSocket, 'medusa', 'v2')
64
76
 
65
77
  client
66
78
  .Start()
79
+ .then(() => {
80
+ return waiter(500)
81
+ })
67
82
  .then(() => {
68
83
  const { connected, subscribed } = client.Status()
69
84
 
70
85
  unitJS.assert.equal(connected, true)
71
86
  unitJS.assert.equal(subscribed, false)
72
87
 
73
- client.Reconnect(1003)
88
+ return client.Reconnect(1007)
89
+ })
90
+ .then(() => {
74
91
  const { connected: c2, subscribed: b2 } = client.Status()
75
-
76
92
  unitJS.assert.equal(c2, false)
77
93
  unitJS.assert.equal(b2, false)
78
94
 
79
- setTimeout(
80
- (client, done) => {
81
- const { connected, subscribed } = client.Status()
82
-
83
- unitJS.assert.equal(connected, true)
84
- unitJS.assert.equal(subscribed, false)
85
- done()
86
- },
87
- 3100,
88
- client,
89
- done,
90
- )
95
+ return waiter(500)
96
+ })
97
+ .then(() => {
98
+ return new Promise((resolve) => {
99
+ setTimeout(
100
+ (client, res) => {
101
+ const { connected, subscribed } = client.Status()
102
+
103
+ unitJS.assert.equal(connected, true)
104
+ unitJS.assert.equal(subscribed, false)
105
+ res()
106
+ },
107
+ 3100,
108
+ client,
109
+ resolve,
110
+ )
111
+ })
112
+ })
113
+ .then(() => {
114
+ return client.Disconnect()
115
+ })
116
+ .then(() => {
117
+ done()
91
118
  })
92
119
  .catch((err) => {
93
120
  done(err)
@@ -95,16 +122,22 @@ describe('TCaBCIClient', () => {
95
122
  })
96
123
 
97
124
  it('subscribe with valid parameters', (done) => {
98
- const client = new TCaBCIClient([], WebSocket, 'transferchain', 'v1')
125
+ const client = new TCaBCIClient([], WebSocket, 'medusa', 'v2')
99
126
 
100
127
  client
101
128
  .Start()
129
+ .then(() => {
130
+ return waiter(750)
131
+ })
102
132
  .then(() => {
103
133
  client.Subscribe(
104
134
  [
105
135
  '2mSCzresfg8Gwu7LZ9k9BTWkQAcQEkvYHFUSCZE2ubM4QV89PTeSYwQDqBas3ykq2emHEK6VRvxdgoe1vrhBbQGN',
106
136
  ],
107
- [TX_TYPE.TX_TYPE_STORAGE],
137
+ {
138
+ '2mSCzresfg8Gwu7LZ9k9BTWkQAcQEkvYHFUSCZE2ubM4QV89PTeSYwQDqBas3ykq2emHEK6VRvxdgoe1vrhBbQGN':
139
+ '2mSCzresfg8Gwu7LZ9k9BTWkQAcQEkvYHFUSCZE2ubM4QV89PTeSYwQDqBas3ykq2emHEK6VRvxdgoe1vrhBbQGN',
140
+ },
108
141
  )
109
142
 
110
143
  const { connected, subscribed } = client.Status()
@@ -112,6 +145,9 @@ describe('TCaBCIClient', () => {
112
145
  unitJS.assert.equal(connected, true)
113
146
  unitJS.assert.equal(subscribed, true)
114
147
 
148
+ return client.Disconnect()
149
+ })
150
+ .then(() => {
115
151
  done()
116
152
  })
117
153
  .catch((err) => {
@@ -120,17 +156,25 @@ describe('TCaBCIClient', () => {
120
156
  })
121
157
 
122
158
  it('should error subscribe with invalid tx type parameter', (done) => {
123
- const client = new TCaBCIClient([], WebSocket, 'transferchain', 'v1')
159
+ const client = new TCaBCIClient([], WebSocket, 'medusa', 'v2')
124
160
 
125
161
  client
126
162
  .Start()
163
+ .then(() => {
164
+ return waiter(500)
165
+ })
127
166
  .then(() => {
128
167
  client.Subscribe(
129
168
  [
130
169
  '2mSCzresfg8Gwu7LZ9k9BTWkQAcQEkvYHFUSCZE2ubM4QV89PTeSYwQDqBas3ykq2emHEK6VRvxdgoe1vrhBbQGN',
170
+ '2mSCzresfg8Gwu7LZ9k9BTWkQAcQEkvYHFUSCZE2ubM4QV89PTeSYwQDqBas3ykq2emHEK6VRvxdgoe1vrhBbQGU',
131
171
  ],
132
172
  ['invalid'],
133
173
  )
174
+
175
+ return client.Disconnect()
176
+ })
177
+ .then(() => {
134
178
  done(new Error('invalid'))
135
179
  })
136
180
  .catch(() => {
@@ -139,14 +183,23 @@ describe('TCaBCIClient', () => {
139
183
  })
140
184
 
141
185
  it('unsubscribe with valid parameters', (done) => {
142
- const client = new TCaBCIClient([], WebSocket, 'transferchain', 'v1')
186
+ const client = new TCaBCIClient([], WebSocket, 'medusa', 'v2')
143
187
 
144
188
  client
145
189
  .Start()
146
190
  .then(() => {
147
- client.Subscribe([
148
- '2mSCzresfg8Gwu7LZ9k9BTWkQAcQEkvYHFUSCZE2ubM4QV89PTeSYwQDqBas3ykq2emHEK6VRvxdgoe1vrhBbQGN',
149
- ])
191
+ return waiter(500)
192
+ })
193
+ .then(() => {
194
+ client.Subscribe(
195
+ [
196
+ '2mSCzresfg8Gwu7LZ9k9BTWkQAcQEkvYHFUSCZE2ubM4QV89PTeSYwQDqBas3ykq2emHEK6VRvxdgoe1vrhBbQGN',
197
+ ],
198
+ {
199
+ '2mSCzresfg8Gwu7LZ9k9BTWkQAcQEkvYHFUSCZE2ubM4QV89PTeSYwQDqBas3ykq2emHEK6VRvxdgoe1vrhBbQGN':
200
+ '2mSCzresfg8Gwu7LZ9k9BTWkQAcQEkvYHFUSCZE2ubM4QV89PTeSYwQDqBas3ykq2emHEK6VRvxdgoe1vrhBbQGN',
201
+ },
202
+ )
150
203
  const { connected, subscribed } = client.Status()
151
204
 
152
205
  unitJS.assert.equal(connected, true)
@@ -160,6 +213,10 @@ describe('TCaBCIClient', () => {
160
213
 
161
214
  unitJS.assert.equal(connected, true)
162
215
  unitJS.assert.equal(subscribed, false)
216
+
217
+ return client.Disconnect()
218
+ })
219
+ .then(() => {
163
220
  done()
164
221
  })
165
222
  .catch((err) => {
@@ -168,7 +225,7 @@ describe('TCaBCIClient', () => {
168
225
  })
169
226
 
170
227
  it('last block', (done) => {
171
- const client = new TCaBCIClient([], WebSocket, 'transferchain', 'v1')
228
+ const client = new TCaBCIClient([], WebSocket, 'medusa', 'v2')
172
229
 
173
230
  client
174
231
  .LastBlock()
@@ -183,7 +240,7 @@ describe('TCaBCIClient', () => {
183
240
  })
184
241
 
185
242
  it('transaction search result', (done) => {
186
- const client = new TCaBCIClient([], WebSocket, 'transferchain', 'v1')
243
+ const client = new TCaBCIClient([], WebSocket, 'medusa', 'v2')
187
244
 
188
245
  client
189
246
  .TxSearch({
@@ -207,7 +264,7 @@ describe('TCaBCIClient', () => {
207
264
  })
208
265
  //
209
266
  it('transaction summary result', (done) => {
210
- const client = new TCaBCIClient([], WebSocket, 'transferchain', 'v1')
267
+ const client = new TCaBCIClient([], WebSocket, 'medusa', 'v2')
211
268
 
212
269
  client
213
270
  .TxSummary({
@@ -230,7 +287,7 @@ describe('TCaBCIClient', () => {
230
287
  })
231
288
 
232
289
  it('should error not broadcast transaction if type is incorrect', (done) => {
233
- const client = new TCaBCIClient([], WebSocket, 'transferchain', 'v1')
290
+ const client = new TCaBCIClient([], WebSocket, 'medusa', 'v2')
234
291
 
235
292
  try {
236
293
  client.Broadcast({
@@ -248,7 +305,7 @@ describe('TCaBCIClient', () => {
248
305
  })
249
306
 
250
307
  it('should error not broadcast transaction', (done) => {
251
- const client = new TCaBCIClient([], WebSocket, 'transferchain', 'v1')
308
+ const client = new TCaBCIClient([], WebSocket, 'medusa', 'v2')
252
309
 
253
310
  client
254
311
  .Broadcast({
@@ -274,7 +331,7 @@ describe('TCaBCIClient', () => {
274
331
  })
275
332
 
276
333
  it('should error in bulk tx if addresses count is zero', (done) => {
277
- const client = new TCaBCIClient([], WebSocket, 'transferchain', 'v1')
334
+ const client = new TCaBCIClient([], WebSocket, 'medusa', 'v2')
278
335
 
279
336
  client
280
337
  .Bulk([])
@@ -296,7 +353,7 @@ describe('TCaBCIClient', () => {
296
353
  )
297
354
  }
298
355
 
299
- const client = new TCaBCIClient(null, WebSocket, 'transferchain', 'v1')
356
+ const client = new TCaBCIClient(null, WebSocket, 'medusa', 'v2')
300
357
 
301
358
  client
302
359
  .Bulk(addresses)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tchain/tcabci-read-js-client",
3
- "version": "2.4.0",
3
+ "version": "2.5.0",
4
4
  "description": "TransferChain Fastest Read Network WebSocket Client",
5
5
  "main": "client.js",
6
6
  "type": "module",
@@ -23,17 +23,18 @@
23
23
  },
24
24
  "homepage": "https://github.com/TransferChain/tcabci-read-js-client#readme",
25
25
  "devDependencies": {
26
+ "chai": "^5.2.1",
26
27
  "eslint": "^9.15.0",
27
28
  "eslint-config-prettier": "^9.1.0",
28
29
  "eslint-plugin-import": "^2.31.0",
29
30
  "eslint-plugin-node": "^11.1.0",
30
31
  "eslint-plugin-promise": "^7.1.0",
31
- "express": "^4.21.1",
32
- "mocha": "^10.8.2",
32
+ "express": "^5.1.0",
33
+ "mocha": "^11.7.1",
33
34
  "nyc": "^17.1.0",
34
- "prettier": "^3.3.3",
35
+ "prettier": "^3.6.2",
35
36
  "unit.js": "^2.1.1",
36
- "ws": "^8.18.0"
37
+ "ws": "^8.18.3"
37
38
  },
38
39
  "dependencies": {
39
40
  "reconnecting-websocket": "^4.4.0"
package/websocket.js ADDED
@@ -0,0 +1,344 @@
1
+ import { Options } from './websocketOptions.js'
2
+ import ReconnectingWebSocket from 'reconnecting-websocket'
3
+
4
+ export const MaxListenerSize = 100
5
+
6
+ export class TWebSocket {
7
+ /**
8
+ * @private
9
+ * @type {Options}
10
+ */
11
+ _options
12
+
13
+ /**
14
+ * @private
15
+ * @type {ReconnectingWebSocket}
16
+ */
17
+ _client
18
+
19
+ _openListener = () => {}
20
+ _messageListener = () => {}
21
+ _errorListener = () => {}
22
+ _closeListener = () => {}
23
+
24
+ _openCallbacks = []
25
+ _messageCallbacks = []
26
+ _errorCallbacks = []
27
+ _closeCallbacks = []
28
+
29
+ /**
30
+ * @param {Options} options
31
+ * @constructor
32
+ * @throws {Error}
33
+ */
34
+ constructor(options) {
35
+ if (!(options instanceof Options))
36
+ throw new TypeError('options must be a Options')
37
+
38
+ options.check()
39
+ this._options = options
40
+ }
41
+
42
+ /**
43
+ * @return {boolean}
44
+ */
45
+ get ready() {
46
+ if (!this._client) return false
47
+
48
+ return this._client.readyState === WebSocket.OPEN
49
+ }
50
+
51
+ /**
52
+ * @return {Array<string>}
53
+ */
54
+ get openListeners() {
55
+ return this._openCallbacks
56
+ }
57
+
58
+ /**
59
+ * @return {Array<string>}
60
+ */
61
+ get messageListeners() {
62
+ return this._messageCallbacks
63
+ }
64
+
65
+ /**
66
+ * @return {Array<string>}
67
+ */
68
+ get errorListeners() {
69
+ return this._errorCallbacks
70
+ }
71
+
72
+ /**
73
+ * @return {Array<string>}
74
+ */
75
+ get closeListeners() {
76
+ return this._closeCallbacks
77
+ }
78
+
79
+ /**
80
+ * @param {?boolean} force
81
+ * @return {Awaited<TWebSocket>}
82
+ * @throws {Error}
83
+ */
84
+ async connect(force = false) {
85
+ if (!force && this.ready)
86
+ throw new Error('already connect. please use force flag')
87
+
88
+ return this._init(force)
89
+ }
90
+
91
+ /**
92
+ * @param {?number} code
93
+ * @return {Awaited<TWebSocket>}
94
+ * @throws {Error}
95
+ */
96
+ async reconnect(code = null) {
97
+ await this._disconnect(code)
98
+ this._init(true)
99
+
100
+ return this
101
+ }
102
+
103
+ /**
104
+ * @param {number} code
105
+ * @return {Promise<void>}
106
+ */
107
+ async disconnect(code = 1000) {
108
+ return this._disconnect(code)
109
+ }
110
+
111
+ /**
112
+ * @param {string|ArrayBuffer|Blob|ArrayBufferView} msg
113
+ */
114
+ send(msg) {
115
+ if (!this._client) return
116
+
117
+ this._client.send(msg)
118
+ }
119
+
120
+ /**
121
+ * @param {function(Event)} callback
122
+ * @return {TWebSocket}
123
+ * @throws {Error}
124
+ */
125
+ addOpenListener(callback) {
126
+ return this._addListener('_openCallbacks', callback)
127
+ }
128
+
129
+ /**
130
+ * @param {function(Event)} callback
131
+ * @return {TWebSocket}
132
+ */
133
+ removeOpenListener(callback) {
134
+ return this._removeListener('_openCallbacks', callback)
135
+ }
136
+
137
+ /**
138
+ * @param {function(MessageEvent)} callback
139
+ * @return {TWebSocket}
140
+ * @throws {Error}
141
+ */
142
+ addMessageListener(callback) {
143
+ return this._addListener('_messageCallbacks', callback)
144
+ }
145
+
146
+ /**
147
+ * @param {function(MessageEvent)} callback
148
+ * @return {TWebSocket}
149
+ */
150
+ removeMessageListener(callback) {
151
+ return this._removeListener('_messageCallbacks', callback)
152
+ }
153
+
154
+ /**
155
+ * @param {function(ErrorEvent)} callback
156
+ * @return {TWebSocket}
157
+ * @throws {Error}
158
+ */
159
+ addErrorListener(callback) {
160
+ return this._addListener('_errorCallbacks', callback)
161
+ }
162
+
163
+ /**
164
+ * @param {function(ErrorEvent)} callback
165
+ * @return {TWebSocket}
166
+ */
167
+ removeErrorListener(callback) {
168
+ return this._removeListener('_errorCallbacks', callback)
169
+ }
170
+
171
+ /**
172
+ * @param {function(CloseEvent)} callback
173
+ * @return {TWebSocket}
174
+ * @throws {Error}
175
+ */
176
+ addCloseListener(callback) {
177
+ return this._addListener('_closeCallbacks', callback)
178
+ }
179
+
180
+ /**
181
+ * @param {function(CloseEvent)} callback
182
+ * @return {TWebSocket}
183
+ */
184
+ removeCloseListener(callback) {
185
+ return this._removeListener('_closeCallbacks', callback)
186
+ }
187
+
188
+ /**
189
+ * @param {string} name
190
+ * @param {function(any)} callback
191
+ * @throws {Error}
192
+ * @private
193
+ */
194
+ _addListener(name, callback) {
195
+ if (this[name].length >= MaxListenerSize)
196
+ throw new Error(`listener size must be ${MaxListenerSize}`)
197
+
198
+ if (this[name].findIndex((v) => v === callback) > -1) return this
199
+
200
+ this[name].push(callback)
201
+
202
+ return this
203
+ }
204
+
205
+ /**
206
+ * @param {string} name
207
+ * @param {function(any)} callback
208
+ * @private
209
+ */
210
+ _removeListener(name, callback) {
211
+ const idx = this[name].findIndex((v) => v === callback)
212
+
213
+ if (idx > -1) {
214
+ this[name].splice(idx, 1)
215
+ }
216
+
217
+ return this
218
+ }
219
+
220
+ _callListener(name, value) {
221
+ if (!this[name]) return
222
+
223
+ for (const callback of this[name]) {
224
+ setTimeout(
225
+ (callback, value) => {
226
+ callback(value)
227
+ },
228
+ 0,
229
+ callback,
230
+ value,
231
+ )
232
+ }
233
+ }
234
+
235
+ /**
236
+ * @private
237
+ * @param {?boolean} force
238
+ * @return {Awaited<TWebSocket>}
239
+ * @throws {Error}
240
+ */
241
+ async _init(force = false) {
242
+ if (!force && this.ready) return this
243
+
244
+ if (this.ready) {
245
+ await this.disconnect(1000)
246
+ }
247
+
248
+ this._make()
249
+
250
+ return this
251
+ }
252
+
253
+ _make() {
254
+ this._client = new ReconnectingWebSocket(
255
+ this._options.url(),
256
+ this._options.protocols(),
257
+ this._options.make(),
258
+ )
259
+
260
+ this._openListener = (e) => {
261
+ this._onOpen(e)
262
+ }
263
+ this._client.addEventListener('open', this._openListener)
264
+
265
+ this._closeListener = (e) => {
266
+ this._onClose(e)
267
+ }
268
+ this._client.addEventListener('close', this._closeListener)
269
+
270
+ this._messageListener = (e) => {
271
+ this._onMessage(e)
272
+ }
273
+ this._client.addEventListener('message', this._messageListener)
274
+
275
+ this._errorListener = (e) => {
276
+ this._onError(e)
277
+ }
278
+ this._client.addEventListener('error', this._errorListener)
279
+ }
280
+
281
+ /**
282
+ * @private
283
+ * @param {?number} code
284
+ * @return {Promise<void>}
285
+ */
286
+ async _disconnect(code = 1000) {
287
+ if (!this.ready) return
288
+
289
+ this._close(code)
290
+ }
291
+
292
+ _close(code = 1000) {
293
+ if (!code) code = 1000
294
+
295
+ this._client.removeEventListener('open', this._openListener)
296
+ this._client.removeEventListener('close', this._closeListener)
297
+ this._client.removeEventListener('message', this._messageListener)
298
+ this._client.removeEventListener('error', this._errorListener)
299
+
300
+ this._openCallbacks.length = 0
301
+ this._errorCallbacks.length = 0
302
+ this._closeCallbacks.length = 0
303
+ this._messageCallbacks.length = 0
304
+
305
+ this._openListener = () => {}
306
+ this._closeListener = () => {}
307
+ this._closeListener = () => {}
308
+ this._messageListener = () => {}
309
+
310
+ this._client.close(code)
311
+ }
312
+
313
+ /**
314
+ * @param {CloseEvent} event
315
+ * @private
316
+ */
317
+ _onClose(event) {
318
+ this._callListener('_closeCallbacks', event)
319
+ }
320
+
321
+ /**
322
+ * @param {ErrorEvent} event
323
+ * @private
324
+ */
325
+ _onError(event) {
326
+ this._callListener('_errorCallbacks', event)
327
+ }
328
+
329
+ /**
330
+ * @param {MessageEvent} msg
331
+ * @private
332
+ */
333
+ _onMessage(msg) {
334
+ this._callListener('_messageCallbacks', msg)
335
+ }
336
+
337
+ /**
338
+ * @param {Event} event
339
+ * @private
340
+ */
341
+ _onOpen(event) {
342
+ this._callListener('_openCallbacks', event)
343
+ }
344
+ }