@nxtedition/deepstream.io-client-js 25.1.2 → 25.6.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxtedition/deepstream.io-client-js",
3
- "version": "25.1.2",
3
+ "version": "25.6.0",
4
4
  "description": "the javascript client for deepstream.io",
5
5
  "homepage": "http://deepstream.io",
6
6
  "type": "module",
@@ -75,14 +75,15 @@
75
75
  "eslint-config-prettier": "^9.1.0",
76
76
  "eslint-config-standard": "^17.1.0",
77
77
  "eslint-plugin-import": "^2.29.1",
78
- "eslint-plugin-n": "^17.9.0",
78
+ "eslint-plugin-n": "^17.10.1",
79
79
  "eslint-plugin-node": "^11.1.0",
80
80
  "eslint-plugin-promise": "^7.0.0",
81
- "husky": "^9.1.1",
81
+ "husky": "^9.1.3",
82
82
  "lint-staged": "^15.2.7",
83
83
  "mitata": "^0.1.11",
84
84
  "pinst": "^3.0.0",
85
- "prettier": "^3.3.3"
85
+ "prettier": "^3.3.3",
86
+ "rxjs": "^7.8.1"
86
87
  },
87
88
  "peerDependencies": {
88
89
  "rxjs": ">=6.x"
package/src/client.js CHANGED
@@ -81,7 +81,7 @@ Client.prototype._$onMessage = function (message) {
81
81
  this._$onError(
82
82
  message.topic,
83
83
  C.EVENT.MESSAGE_PARSE_ERROR,
84
- `Received message for unknown topic ${message.topic}`
84
+ `Received message for unknown topic ${message.topic}`,
85
85
  )
86
86
  }
87
87
 
@@ -127,12 +127,10 @@ Client.prototype._getOptions = function (options) {
127
127
  return mergedOptions
128
128
  }
129
129
 
130
- function createDeepstream(url, options) {
130
+ export default function createDeepstream(url, options) {
131
131
  return new Client(url, options)
132
132
  }
133
133
 
134
134
  Client.prototype.isSameOrNewer = utils.isSameOrNewer
135
135
  Client.prototype.CONSTANTS = C
136
136
  createDeepstream.CONSTANTS = C
137
-
138
- export default createDeepstream
@@ -1,10 +1,10 @@
1
1
  import * as C from '../constants/constants.js'
2
2
  import * as messageBuilder from '../message/message-builder.js'
3
- import { convertTyped } from '../message/message-parser.js'
3
+ import * as messageParser from '../message/message-parser.js'
4
4
  import MulticastListener from '../utils/multicast-listener.js'
5
5
  import UnicastListener from '../utils/unicast-listener.js'
6
6
  import EventEmitter from 'component-emitter2'
7
- import rxjs from 'rxjs'
7
+ import * as rxjs from 'rxjs'
8
8
 
9
9
  const EventHandler = function (options, connection, client) {
10
10
  this._options = options
@@ -143,7 +143,7 @@ EventHandler.prototype._$handle = function (message) {
143
143
 
144
144
  if (message.action === C.ACTIONS.EVENT) {
145
145
  if (message.data && message.data.length === 2) {
146
- this._emitter.emit(name, convertTyped(data, this._client))
146
+ this._emitter.emit(name, messageParser.convertTyped(data, this._client))
147
147
  } else {
148
148
  this._emitter.emit(name)
149
149
  }
@@ -1,18 +1,14 @@
1
1
  import * as utils from '../utils/utils.js'
2
- import { convertTyped } from './message-parser.js'
2
+ import * as messageParser from './message-parser.js'
3
3
  import * as messageBuilder from './message-builder.js'
4
4
  import * as C from '../constants/constants.js'
5
- import xxhash from 'xxhash-wasm'
6
5
  import FixedQueue from '../utils/fixed-queue.js'
7
6
  import Emitter from 'component-emitter2'
8
- import varint from 'varint'
9
7
 
10
- const BrowserWebSocket = globalThis.WebSocket || globalThis.MozWebSocket
11
8
  const NodeWebSocket = utils.isNode ? await import('ws').then((x) => x.default) : null
9
+ const BrowserWebSocket = globalThis.WebSocket || globalThis.MozWebSocket
12
10
 
13
- const HASHER = await xxhash()
14
-
15
- const Connection = function (client, url, options) {
11
+ export default function Connection(client, url, options) {
16
12
  this._client = client
17
13
  this._options = options
18
14
  this._logger = options.logger
@@ -24,11 +20,17 @@ const Connection = function (client, url, options) {
24
20
  this._tooManyAuthAttempts = false
25
21
  this._connectionAuthenticationTimeout = false
26
22
  this._challengeDenied = false
27
- this._decoder = new TextDecoder()
28
- this._encoder = new TextEncoder()
23
+ this._message = {
24
+ raw: null,
25
+ topic: null,
26
+ action: null,
27
+ data: null,
28
+ }
29
+ this._decoder = new globalThis.TextDecoder()
29
30
  this._recvQueue = new FixedQueue()
30
31
  this._reconnectTimeout = null
31
32
  this._reconnectionAttempt = 0
33
+ this._endpoint = null
32
34
 
33
35
  this._processingRecv = false
34
36
  this._recvMessages = this._recvMessages.bind(this)
@@ -37,8 +39,6 @@ const Connection = function (client, url, options) {
37
39
 
38
40
  this._state = C.CONNECTION_STATE.CLOSED
39
41
 
40
- this.hasher = HASHER
41
-
42
42
  this._createEndpoint()
43
43
  }
44
44
 
@@ -93,19 +93,19 @@ Connection.prototype._createEndpoint = function () {
93
93
  this._endpoint = new NodeWebSocket(this._url, {
94
94
  generateMask() {},
95
95
  })
96
+ this._endpoint.binaryType = 'nodebuffer'
96
97
  } else {
97
98
  this._endpoint = new BrowserWebSocket(this._url)
98
99
  this._endpoint.binaryType = 'arraybuffer'
99
100
  }
101
+
100
102
  this._corked = false
101
103
 
102
104
  this._endpoint.onopen = this._onOpen.bind(this)
103
105
  this._endpoint.onerror = this._onError.bind(this)
104
106
  this._endpoint.onclose = this._onClose.bind(this)
105
-
106
- this._endpoint.onmessage = ({ data }) => {
107
- this._onMessage(data)
108
- }
107
+ this._endpoint.onmessage = ({ data }) =>
108
+ this._onMessage(typeof data === 'string' ? data : this._decoder.decode(data))
109
109
  }
110
110
 
111
111
  Connection.prototype.send = function (message) {
@@ -113,7 +113,12 @@ Connection.prototype.send = function (message) {
113
113
 
114
114
  if (message.length > maxPacketSize) {
115
115
  const err = new Error(`Packet to big: ${message.length} > ${maxPacketSize}`)
116
- this._client._$onError(C.TOPIC.CONNECTION, C.EVENT.CONNECTION_ERROR, err, message)
116
+ this._client._$onError(
117
+ C.TOPIC.CONNECTION,
118
+ C.EVENT.CONNECTION_ERROR,
119
+ err,
120
+ message.split(C.MESSAGE_PART_SEPERATOR).map((x) => x.slice(0, 256)),
121
+ )
117
122
  return false
118
123
  }
119
124
 
@@ -142,8 +147,8 @@ Connection.prototype.send = function (message) {
142
147
  Connection.prototype._submit = function (message) {
143
148
  const { maxPacketSize } = this._options
144
149
 
145
- if (message.byteLength > maxPacketSize) {
146
- const err = new Error(`Packet to big: ${message.byteLength} > ${maxPacketSize}`)
150
+ if (message.length > maxPacketSize) {
151
+ const err = new Error(`Packet to big: ${message.length} > ${maxPacketSize}`)
147
152
  this._client._$onError(C.TOPIC.CONNECTION, C.EVENT.CONNECTION_ERROR, err)
148
153
  return false
149
154
  } else if (this._endpoint.readyState === this._endpoint.OPEN) {
@@ -161,7 +166,7 @@ Connection.prototype._sendAuthParams = function () {
161
166
  this._setState(C.CONNECTION_STATE.AUTHENTICATING)
162
167
  const authMessage = messageBuilder.getMsg(C.TOPIC.AUTH, C.ACTIONS.REQUEST, [
163
168
  this._authParams,
164
- '25.1.0', // TODO (fix): How to read from package.json?
169
+ '24.4.4',
165
170
  utils.isNode
166
171
  ? `Node/${process.version}`
167
172
  : globalThis.navigator && globalThis.navigator.userAgent,
@@ -206,60 +211,13 @@ Connection.prototype._onClose = function () {
206
211
  }
207
212
  }
208
213
 
209
- Connection.prototype._onMessage = function (raw) {
210
- if (typeof raw === 'string') {
211
- raw = this._encoder.encode(raw)
212
- } else if (!utils.isNode) {
213
- raw = new Uint8Array(raw)
214
+ Connection.prototype._onMessage = function (data) {
215
+ // Remove MESSAGE_SEPERATOR if exists.
216
+ if (data.charCodeAt(data.length - 1) === 30) {
217
+ data = data.slice(0, -1)
214
218
  }
215
219
 
216
- const len = raw.byteLength
217
-
218
- const start = 0
219
-
220
- let pos = start
221
-
222
- let headerSize = 0
223
- if (raw[pos] >= 128) {
224
- headerSize = raw[pos] - 128
225
- pos += headerSize
226
- }
227
-
228
- // TODO (perf): Use numbers instead of string..
229
- const topic = String.fromCharCode(raw[pos++])
230
- pos++
231
-
232
- let action = ''
233
- while (pos < len && raw[pos] !== 31) {
234
- // TODO (perf): Use numbers instead of string..
235
- action += String.fromCharCode(raw[pos++])
236
- }
237
- pos++
238
-
239
- // TODO (fix): Validate topic and action
240
-
241
- let data
242
-
243
- // TODO (fix): Don't stringify binary data...
244
-
245
- if (headerSize > 0) {
246
- data = []
247
- let headerPos = start + 1
248
- while (headerPos < headerSize) {
249
- const len = varint.decode(raw, headerPos)
250
- headerPos += varint.decode.bytes
251
- if (len === 0) {
252
- break
253
- }
254
- data.push(this._decoder.decode(raw.subarray(pos, pos + len - 1)))
255
- pos += len
256
- }
257
- } else {
258
- data =
259
- pos < len ? this._decoder.decode(raw.subarray(pos, len)).split(C.MESSAGE_PART_SEPERATOR) : []
260
- }
261
-
262
- this._recvQueue.push({ topic, action, data })
220
+ this._recvQueue.push(data)
263
221
  if (!this._processingRecv) {
264
222
  this._processingRecv = true
265
223
  this._schedule(this._recvMessages)
@@ -283,19 +241,20 @@ Connection.prototype._recvMessages = function (deadline) {
283
241
  continue
284
242
  }
285
243
 
286
- if (message === C.TOPIC.ERROR) {
287
- this._client._$onError(C.TOPIC.ERROR, message.action, new Error('Message error'), message)
288
- continue
244
+ if (this._logger) {
245
+ this._logger.trace(message, 'receive')
289
246
  }
290
247
 
291
- this.emit('recv', message)
248
+ messageParser.parseMessage(message, this._client, this._message)
249
+
250
+ this.emit('recv', this._message)
292
251
 
293
- if (message.topic === C.TOPIC.CONNECTION) {
294
- this._handleConnectionResponse(message)
295
- } else if (message.topic === C.TOPIC.AUTH) {
296
- this._handleAuthResponse(message)
252
+ if (this._message.topic === C.TOPIC.CONNECTION) {
253
+ this._handleConnectionResponse(this._message)
254
+ } else if (this._message.topic === C.TOPIC.AUTH) {
255
+ this._handleAuthResponse(this._message)
297
256
  } else {
298
- this._client._$onMessage(message)
257
+ this._client._$onMessage(this._message)
299
258
  }
300
259
  }
301
260
 
@@ -352,7 +311,7 @@ Connection.prototype._getAuthData = function (data) {
352
311
  if (data === undefined) {
353
312
  return null
354
313
  } else {
355
- return convertTyped(data, this._client)
314
+ return messageParser.convertTyped(data, this._client)
356
315
  }
357
316
  }
358
317
 
@@ -406,5 +365,3 @@ Connection.prototype._clearReconnect = function () {
406
365
  }
407
366
  this._reconnectionAttempt = 0
408
367
  }
409
-
410
- export default Connection
@@ -1,100 +1,25 @@
1
1
  import * as C from '../constants/constants.js'
2
- import varint from 'varint'
3
- import * as utils from '../utils/utils.js'
4
2
 
5
- const poolEncoder = new TextEncoder()
6
-
7
- let poolSize
8
- let poolBuffer
9
- let poolView
10
- let poolOffset
11
-
12
- function allocPool(size) {
13
- poolSize = size || poolSize || 1024 * 1024
14
- poolBuffer = utils.isNode
15
- ? globalThis.Buffer.allocUnsafe(poolSize)
16
- : new Uint8Array(new ArrayBuffer(poolSize))
17
- poolView = new DataView(poolBuffer.buffer)
18
- poolOffset = 0
19
- }
20
-
21
- function alignPool() {
22
- // Ensure aligned slices
23
- if (poolOffset & 0x7) {
24
- poolOffset |= 0x7
25
- poolOffset++
26
- }
27
- }
28
-
29
- function writeString(dst, str, offset) {
30
- if (utils.isNode) {
31
- return dst.write(str, offset)
32
- } else {
33
- const res = poolEncoder.encodeInto(str, new Uint8Array(dst.buffer, offset))
34
- return res.written
35
- }
36
- }
3
+ const SEP = C.MESSAGE_PART_SEPERATOR
37
4
 
38
5
  export function getMsg(topic, action, data) {
39
6
  if (data && !(data instanceof Array)) {
40
7
  throw new Error('data must be an array')
41
8
  }
42
9
 
43
- if (!poolSize || poolOffset + poolSize / 16 >= poolSize) {
44
- allocPool()
45
- } else {
46
- alignPool()
47
- }
48
-
49
- const start = poolOffset
50
-
51
- const headerSize = 8
52
- poolBuffer[poolOffset++] = 128 + headerSize
53
- let headerPos = poolOffset
54
- poolOffset += headerSize - 1
55
-
56
- poolBuffer[poolOffset++] = topic.charCodeAt(0)
57
- poolBuffer[poolOffset++] = 31
58
- for (let n = 0; n < action.length; n++) {
59
- poolBuffer[poolOffset++] = action.charCodeAt(n)
60
- }
10
+ const sendData = [topic, action]
61
11
 
62
12
  if (data) {
63
13
  for (let i = 0; i < data.length; i++) {
64
- const type = typeof data[i]
65
- let len
66
- if (data[i] == null) {
67
- poolBuffer[poolOffset++] = 31
68
- len = 0
69
- } else if (type === 'object') {
70
- poolBuffer[poolOffset++] = 31
71
- len = writeString(poolBuffer, JSON.stringify(data[i]), poolOffset)
72
- } else if (type === 'bigint') {
73
- poolBuffer[poolOffset++] = 31
74
- poolView.setBigUint64(poolOffset, data[i], false)
75
- len = 8
76
- } else if (type === 'string') {
77
- poolBuffer[poolOffset++] = 31
78
- len = writeString(poolBuffer, data[i], poolOffset)
14
+ if (typeof data[i] === 'object') {
15
+ sendData.push(JSON.stringify(data[i]))
79
16
  } else {
80
- throw new Error('invalid data')
81
- }
82
- poolOffset += len
83
-
84
- varint.encode(len + 1, poolBuffer, headerPos)
85
- headerPos += varint.encode.bytes
86
- if (headerPos - start >= headerSize) {
87
- throw new Error(`header too large: ${headerPos - start} ${headerSize}`)
88
- }
89
-
90
- if (poolOffset >= poolBuffer.length) {
91
- allocPool(start === 0 ? poolSize * 2 : poolSize)
92
- return getMsg(topic, action, data)
17
+ sendData.push(data[i])
93
18
  }
94
19
  }
95
20
  }
96
21
 
97
- return new Uint8Array(poolBuffer.buffer, start, poolOffset - start)
22
+ return sendData.join(SEP)
98
23
  }
99
24
 
100
25
  export function typed(value) {
@@ -1,5 +1,11 @@
1
1
  import * as C from '../constants/constants.js'
2
2
 
3
+ const actions = {}
4
+
5
+ for (const key in C.ACTIONS) {
6
+ actions[C.ACTIONS[key]] = key
7
+ }
8
+
3
9
  export function convertTyped(value, client) {
4
10
  const type = value.charAt(0)
5
11
 
@@ -40,3 +46,36 @@ export function convertTyped(value, client) {
40
46
 
41
47
  return undefined
42
48
  }
49
+
50
+ export function parseMessage(message, client, result) {
51
+ const parts = message.split(C.MESSAGE_PART_SEPERATOR)
52
+
53
+ if (parts.length < 2) {
54
+ client._$onError(
55
+ C.TOPIC.ERROR,
56
+ C.EVENT.MESSAGE_PARSE_ERROR,
57
+ new Error('Insufficiant message parts'),
58
+ )
59
+ return null
60
+ }
61
+
62
+ if (parts[0] === C.TOPIC.ERROR) {
63
+ client._$onError(C.TOPIC.ERROR, parts[1], new Error('Message error'), message)
64
+ return null
65
+ }
66
+
67
+ if (actions[parts[1]] === undefined) {
68
+ client._$onError(
69
+ C.TOPIC.ERROR,
70
+ C.EVENT.MESSAGE_PARSE_ERROR,
71
+ new Error('Unknown action'),
72
+ message,
73
+ )
74
+ return null
75
+ }
76
+
77
+ result.raw = message
78
+ result.topic = parts[0]
79
+ result.action = parts[1]
80
+ result.data = parts.splice(2)
81
+ }
@@ -2,12 +2,11 @@ import Record from './record.js'
2
2
  import MulticastListener from '../utils/multicast-listener.js'
3
3
  import UnicastListener from '../utils/unicast-listener.js'
4
4
  import * as C from '../constants/constants.js'
5
- import rxjs from 'rxjs'
5
+ import * as rxjs from 'rxjs'
6
6
  import invariant from 'invariant'
7
7
  import EventEmitter from 'component-emitter2'
8
8
  import jsonPath from '@nxtedition/json-path'
9
9
  import * as utils from '../utils/utils.js'
10
- import rx from 'rxjs/operators'
11
10
  import xuid from 'xuid'
12
11
  import * as timers from '../utils/timers.js'
13
12
 
@@ -101,7 +100,6 @@ class RecordHandler {
101
100
  this._pruning = new Set()
102
101
  this._patching = new Map()
103
102
  this._updating = new Map()
104
- this._encoder = new TextEncoder()
105
103
 
106
104
  this._connected = 0
107
105
  this._stats = {
@@ -207,14 +205,6 @@ class RecordHandler {
207
205
  }
208
206
  }
209
207
 
210
- _getKey(name) {
211
- if (name.length > 8) {
212
- return this._connection.hasher.h64(name)
213
- }
214
- const buf = this._encoder.encode(name)
215
- return buf.byteLength === 8 ? utils.readBigUInt64BE(buf) : this._connection.hasher.h64Raw(buf)
216
- }
217
-
218
208
  /**
219
209
  * @param {string} name
220
210
  * @returns {Record}
@@ -228,7 +218,7 @@ class RecordHandler {
228
218
  let record = this._records.get(name)
229
219
 
230
220
  if (!record) {
231
- record = new Record(this._getKey(name), name, this)
221
+ record = new Record(name, this)
232
222
  this._stats.records += 1
233
223
  this._stats.created += 1
234
224
  this._records.set(name, record)
@@ -481,7 +471,7 @@ class RecordHandler {
481
471
  // TODO (fix): Missing sync..
482
472
  return new Promise((resolve, reject) => {
483
473
  this.observe(...args)
484
- .pipe(rx.first())
474
+ .pipe(rxjs.first())
485
475
  .subscribe({
486
476
  next: resolve,
487
477
  error: reject,
@@ -497,7 +487,7 @@ class RecordHandler {
497
487
  get2(...args) {
498
488
  return new Promise((resolve, reject) => {
499
489
  this.observe2(...args)
500
- .pipe(rx.first())
490
+ .pipe(rxjs.first())
501
491
  .subscribe({
502
492
  next: resolve,
503
493
  error: reject,
@@ -1,21 +1,20 @@
1
1
  import jsonPath from '@nxtedition/json-path'
2
2
  import * as utils from '../utils/utils.js'
3
3
  import * as C from '../constants/constants.js'
4
- import { convertTyped } from '../message/message-parser.js'
4
+ import * as messageParser from '../message/message-parser.js'
5
5
  import xuid from 'xuid'
6
6
  import invariant from 'invariant'
7
7
  import cloneDeep from 'lodash.clonedeep'
8
8
  import * as timers from '../utils/timers.js'
9
9
 
10
- // const encoder = new TextEncoder()
11
-
12
10
  class Record {
13
11
  static STATE = C.RECORD_STATE
14
12
 
15
- constructor(key, name, handler) {
13
+ constructor(name, handler) {
14
+ const connection = handler._connection
15
+
16
16
  this._handler = handler
17
17
  this._name = name
18
- this._key = key
19
18
  this._version = ''
20
19
  this._data = jsonPath.EMPTY
21
20
  this._state = C.RECORD_STATE.VOID
@@ -25,12 +24,7 @@ class Record {
25
24
 
26
25
  /** @type Map? */ this._updating = null
27
26
  /** @type Array? */ this._patching = null
28
- this._subscribed = false
29
- }
30
-
31
- /** @type {bigint} */
32
- get key() {
33
- return this._key
27
+ this._subscribed = connection.sendMsg(C.TOPIC.RECORD, C.ACTIONS.SUBSCRIBE, [this._name])
34
28
  }
35
29
 
36
30
  /** @type {string} */
@@ -68,8 +62,7 @@ class Record {
68
62
  if (this._refs === 1) {
69
63
  this._handler._onPruning(this, false)
70
64
  this._subscribed =
71
- this._subscribed ||
72
- connection.sendMsg(C.TOPIC.RECORD, C.ACTIONS.SUBSCRIBE, [this._name, this._key])
65
+ this._subscribed || connection.sendMsg(C.TOPIC.RECORD, C.ACTIONS.SUBSCRIBE, [this._name])
73
66
  }
74
67
  return this
75
68
  }
@@ -331,8 +324,7 @@ class Record {
331
324
 
332
325
  if (connected) {
333
326
  this._subscribed =
334
- this._refs > 0 &&
335
- connection.sendMsg(C.TOPIC.RECORD, C.ACTIONS.SUBSCRIBE, [this._name, this._key])
327
+ this._refs > 0 && connection.sendMsg(C.TOPIC.RECORD, C.ACTIONS.SUBSCRIBE, [this._name])
336
328
 
337
329
  if (this._updating) {
338
330
  for (const update of this._updating.values()) {
@@ -357,7 +349,7 @@ class Record {
357
349
  invariant(!this._updating, 'must not have updates')
358
350
 
359
351
  if (this._subscribed) {
360
- connection.sendMsg(C.TOPIC.RECORD, C.ACTIONS.UNSUBSCRIBE, [this._key])
352
+ connection.sendMsg(C.TOPIC.RECORD, C.ACTIONS.UNSUBSCRIBE, [this._name])
361
353
  this._subscribed = false
362
354
  }
363
355
 
@@ -379,7 +371,7 @@ class Record {
379
371
  const prevVersion = this._version
380
372
  const nextVersion = this._makeVersion(parseInt(prevVersion) + 1)
381
373
 
382
- const update = [this._key, nextVersion, jsonPath.stringify(nextData), prevVersion]
374
+ const update = [this._name, nextVersion, jsonPath.stringify(nextData), prevVersion]
383
375
 
384
376
  if (!this._updating) {
385
377
  this._onUpdating(true)
@@ -434,14 +426,6 @@ class Record {
434
426
  this._state = this._version.charAt(0) === 'I' ? C.RECORD_STATE.STALE : C.RECORD_STATE.SERVER
435
427
  }
436
428
 
437
- // if (hasProvider != null ) {
438
- // this._state = convertTyped(hasProvider, this._handler._client)
439
- // ? C.RECORD_STATE.PROVIDER
440
- // : this._version.charAt(0) === 'I'
441
- // ? C.RECORD_STATE.STALE
442
- // : C.RECORD_STATE.SERVER
443
- // }
444
-
445
429
  if (this._state !== prevState || this._data !== prevData || this._version !== prevVersion) {
446
430
  this._emitUpdate()
447
431
  }
@@ -483,7 +467,7 @@ class Record {
483
467
  const prevState = this._state
484
468
 
485
469
  this._state =
486
- hasProvider && convertTyped(hasProvider, this._handler._client)
470
+ hasProvider && messageParser.convertTyped(hasProvider, this._handler._client)
487
471
  ? C.RECORD_STATE.PROVIDER
488
472
  : this._version.charAt(0) === 'I'
489
473
  ? C.RECORD_STATE.STALE
@@ -1,6 +1,6 @@
1
1
  import * as C from '../constants/constants.js'
2
2
  import RpcResponse from './rpc-response.js'
3
- import { convertTyped } from '../message/message-parser.js'
3
+ import * as messageParser from '../message/message-parser.js'
4
4
  import * as messageBuilder from '../message/message-builder.js'
5
5
  import xuid from 'xuid'
6
6
 
@@ -111,7 +111,7 @@ RpcHandler.prototype._respond = function (message) {
111
111
  if (callback) {
112
112
  let promise
113
113
  try {
114
- promise = Promise.resolve(callback(convertTyped(data, this._client), response))
114
+ promise = Promise.resolve(callback(messageParser.convertTyped(data, this._client), response))
115
115
  } catch (err) {
116
116
  promise = Promise.reject(err)
117
117
  }
@@ -153,10 +153,10 @@ RpcHandler.prototype._$handle = function (message) {
153
153
  rpcId: rpc.id,
154
154
  rpcName: rpc.name,
155
155
  rpcData: rpc.data,
156
- })
156
+ }),
157
157
  )
158
158
  } else {
159
- rpc.callback(null, convertTyped(data, this._client))
159
+ rpc.callback(null, messageParser.convertTyped(data, this._client))
160
160
  }
161
161
  }
162
162
  }
@@ -1,7 +1,8 @@
1
+ import * as rxjs from 'rxjs'
1
2
  import * as C from '../constants/constants.js'
2
- import rxjs from 'rxjs'
3
+ import { h64ToString } from '../utils/utils.js'
3
4
 
4
- class Listener {
5
+ export default class Listener {
5
6
  constructor(topic, pattern, callback, handler, { recursive = false, stringify = null } = {}) {
6
7
  this._topic = topic
7
8
  this._pattern = pattern
@@ -40,7 +41,7 @@ class Listener {
40
41
  C.TOPIC.RECORD,
41
42
  C.EVENT.NOT_CONNECTED,
42
43
  new Error('received message while not connected'),
43
- message
44
+ message,
44
45
  )
45
46
  return
46
47
  }
@@ -56,7 +57,6 @@ class Listener {
56
57
  // TODO (refactor): Move to class
57
58
  const provider = {
58
59
  name,
59
- key: this._handler.getKey(name),
60
60
  value$: null,
61
61
  sending: false,
62
62
  accepted: false,
@@ -69,7 +69,7 @@ class Listener {
69
69
  if (this.connected && provider.accepted) {
70
70
  this._connection.sendMsg(this._topic, C.ACTIONS.LISTEN_REJECT, [
71
71
  this._pattern,
72
- provider.key,
72
+ provider.name,
73
73
  ])
74
74
  }
75
75
 
@@ -102,7 +102,7 @@ class Listener {
102
102
  this._connection.sendMsg(
103
103
  this._topic,
104
104
  accepted ? C.ACTIONS.LISTEN_ACCEPT : C.ACTIONS.LISTEN_REJECT,
105
- [this._pattern, provider.key]
105
+ [this._pattern, provider.name],
106
106
  )
107
107
 
108
108
  provider.version = null
@@ -152,13 +152,13 @@ class Listener {
152
152
  }
153
153
 
154
154
  const body = typeof value !== 'string' ? this._stringify(value) : value
155
- const hash = this._connection.hasher.h64ToString(body)
155
+ const hash = h64ToString(body)
156
156
  const version = `INF-${hash}`
157
157
 
158
158
  if (provider.version !== version) {
159
159
  provider.version = version
160
160
  this._connection.sendMsg(C.TOPIC.RECORD, C.ACTIONS.UPDATE, [
161
- provider.key,
161
+ provider.name,
162
162
  version,
163
163
  body,
164
164
  ])
@@ -219,11 +219,7 @@ class Listener {
219
219
  }
220
220
 
221
221
  _error(name, err) {
222
- this._client._$onError(this._topic, C.EVENT.LISTENER_ERROR, err, [
223
- this._pattern,
224
- name,
225
- this._handler.getKey(name),
226
- ])
222
+ this._client._$onError(this._topic, C.EVENT.LISTENER_ERROR, err, [this._pattern, name])
227
223
  }
228
224
 
229
225
  _reset() {
@@ -233,5 +229,3 @@ class Listener {
233
229
  this._subscriptions.clear()
234
230
  }
235
231
  }
236
-
237
- export default Listener
@@ -1,10 +1,11 @@
1
- let fastNow = Date.now()
1
+ const fastNowInterval = 1e3
2
+ let fastNow = 0
2
3
  let fastNowTimeout
3
4
 
4
5
  const fastTimers = []
5
6
 
6
7
  function onTimeout() {
7
- fastNow = Date.now()
8
+ fastNow += fastNowInterval
8
9
 
9
10
  let len = fastTimers.length
10
11
  let idx = 0
@@ -41,7 +42,7 @@ function refreshTimeout() {
41
42
  fastNowTimeout.refresh()
42
43
  } else {
43
44
  globalThis.clearTimeout(fastNowTimeout)
44
- fastNowTimeout = globalThis.setTimeout(onTimeout, 1e3)
45
+ fastNowTimeout = globalThis.setTimeout(onTimeout, fastNowInterval)
45
46
  if (fastNowTimeout.unref) {
46
47
  fastNowTimeout.unref()
47
48
  }
@@ -80,7 +81,7 @@ class Timeout {
80
81
  }
81
82
 
82
83
  export function setTimeout(callback, delay, opaque) {
83
- return delay < 1e3
84
+ return delay < fastNowInterval
84
85
  ? globalThis.setTimeout(callback, delay, opaque)
85
86
  : new Timeout(callback, delay, opaque)
86
87
  }
@@ -1,9 +1,9 @@
1
+ import * as rxjs from 'rxjs'
1
2
  import * as C from '../constants/constants.js'
2
- import rx from 'rxjs/operators'
3
- import rxjs from 'rxjs'
3
+ import { h64ToString } from '../utils/utils.js'
4
4
 
5
5
  const PIPE = rxjs.pipe(
6
- rx.map((value) => {
6
+ rxjs.map((value) => {
7
7
  let data
8
8
  if (value && typeof value === 'string') {
9
9
  if (value.charAt(0) !== '{' && value.charAt(0) !== '[') {
@@ -18,10 +18,10 @@ const PIPE = rxjs.pipe(
18
18
 
19
19
  return data
20
20
  }),
21
- rx.distinctUntilChanged()
21
+ rxjs.distinctUntilChanged(),
22
22
  )
23
23
 
24
- class Listener {
24
+ export default class Listener {
25
25
  constructor(topic, pattern, callback, handler, opts) {
26
26
  if (opts.recursive) {
27
27
  throw new Error('invalid argument: recursive')
@@ -68,29 +68,27 @@ class Listener {
68
68
  value$ = rxjs.throwError(() => err)
69
69
  }
70
70
 
71
- const key = this._handler.getKey(name)
72
-
73
71
  if (value$) {
74
72
  const subscription = value$.pipe(PIPE).subscribe({
75
73
  next: (data) => {
76
74
  if (data == null) {
77
- this._connection.sendMsg(this._topic, C.ACTIONS.LISTEN_REJECT, [this._pattern, key])
75
+ this._connection.sendMsg(this._topic, C.ACTIONS.LISTEN_REJECT, [this._pattern, name])
78
76
  this._subscriptions.delete(name)
79
77
  subscription.unsubscribe()
80
78
  } else {
81
- const version = `INF-${this._connection.hasher.h64ToString(data)}`
82
- this._connection.sendMsg(this._topic, C.ACTIONS.UPDATE, [key, version, data])
79
+ const version = `INF-${h64ToString(data)}`
80
+ this._connection.sendMsg(this._topic, C.ACTIONS.UPDATE, [name, version, data])
83
81
  }
84
82
  },
85
83
  error: (err) => {
86
84
  this._error(name, err)
87
- this._connection.sendMsg(this._topic, C.ACTIONS.LISTEN_REJECT, [this._pattern, key])
85
+ this._connection.sendMsg(this._topic, C.ACTIONS.LISTEN_REJECT, [this._pattern, name])
88
86
  this._subscriptions.delete(name)
89
87
  },
90
88
  })
91
89
  this._subscriptions.set(name, subscription)
92
90
  } else {
93
- this._connection.sendMsg(this._topic, C.ACTIONS.LISTEN_REJECT, [this._pattern, key])
91
+ this._connection.sendMsg(this._topic, C.ACTIONS.LISTEN_REJECT, [this._pattern, name])
94
92
  }
95
93
  } else if (message.action === C.ACTIONS.LISTEN_REJECT) {
96
94
  const subscription = this._subscriptions.get(name)
@@ -128,5 +126,3 @@ class Listener {
128
126
  this._connection.sendMsg(this._topic, C.ACTIONS.UNLISTEN, [this._pattern])
129
127
  }
130
128
  }
131
-
132
- export default Listener
@@ -1,3 +1,5 @@
1
+ import xxhash from 'xxhash-wasm'
2
+
1
3
  const NODE_ENV = typeof process !== 'undefined' && process.env && process.env.NODE_ENV
2
4
  export const isNode = typeof process !== 'undefined' && process.toString() === '[object process]'
3
5
  export const isProduction = NODE_ENV === 'production'
@@ -175,13 +177,8 @@ export function removeAbortListener(signal, handler) {
175
177
  }
176
178
  }
177
179
 
178
- export function readBigUInt64BE(buf, offset = 0) {
179
- const first = buf[offset]
180
- const last = buf[offset + 7]
181
-
182
- const hi = first * 2 ** 24 + buf[++offset] * 2 ** 16 + buf[++offset] * 2 ** 8 + buf[++offset]
183
-
184
- const lo = buf[++offset] * 2 ** 24 + buf[++offset] * 2 ** 16 + buf[++offset] * 2 ** 8 + last
180
+ const HASHER = await xxhash()
185
181
 
186
- return (BigInt(hi) << 32n) + BigInt(lo)
182
+ export function h64ToString(str) {
183
+ return HASHER.h64ToString(str)
187
184
  }