@nxtedition/deepstream.io-client-js 24.3.3 → 24.4.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/.husky/pre-commit CHANGED
@@ -1,3 +1 @@
1
- #!/bin/sh
2
- . "$(dirname "$0")/_/husky.sh"
3
- yarn lint-staged
1
+ npx lint-staged
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxtedition/deepstream.io-client-js",
3
- "version": "24.3.3",
3
+ "version": "24.4.0",
4
4
  "description": "the javascript client for deepstream.io",
5
5
  "homepage": "http://deepstream.io",
6
6
  "type": "module",
@@ -18,9 +18,9 @@
18
18
  "ws": false
19
19
  },
20
20
  "scripts": {
21
- "_postinstall": "husky install",
22
21
  "prepublishOnly": "pinst --disable",
23
- "postpublish": "pinst --enable"
22
+ "postpublish": "pinst --enable",
23
+ "prepare": "husky"
24
24
  },
25
25
  "lint-staged": {
26
26
  "*.{js,jsx,md,ts}": [
@@ -59,30 +59,31 @@
59
59
  "/__tests__"
60
60
  ],
61
61
  "dependencies": {
62
- "@nxtedition/json-path": "^1.0.3",
63
- "bufferutil": "^4.0.7",
62
+ "@nxtedition/json-path": "^1.0.8",
63
+ "bufferutil": "^4.0.8",
64
64
  "component-emitter2": "^1.3.5",
65
65
  "invariant": "^2.2.4",
66
66
  "lodash.clonedeep": "^4.5.0",
67
- "utf-8-validate": "^6.0.3",
67
+ "utf-8-validate": "^6.0.4",
68
68
  "varint": "^6.0.0",
69
- "ws": "^8.13.0",
70
- "xuid": "^4.1.2",
69
+ "ws": "^8.18.0",
70
+ "xuid": "^4.1.3",
71
71
  "xxhash-wasm": "^1.0.2"
72
72
  },
73
73
  "devDependencies": {
74
- "eslint": "^8.42.0",
75
- "eslint-config-prettier": "^8.8.0",
74
+ "eslint": "^8.0.0",
75
+ "eslint-config-prettier": "^9.1.0",
76
76
  "eslint-config-standard": "^17.1.0",
77
- "eslint-plugin-import": "^2.27.5",
78
- "eslint-plugin-n": "^16.0.0",
77
+ "eslint-plugin-import": "^2.29.1",
78
+ "eslint-plugin-n": "^17.10.1",
79
79
  "eslint-plugin-node": "^11.1.0",
80
- "eslint-plugin-promise": "^6.1.1",
81
- "husky": "^8.0.3",
82
- "lint-staged": "^13.2.2",
80
+ "eslint-plugin-promise": "^7.0.0",
81
+ "husky": "^9.1.3",
82
+ "lint-staged": "^15.2.7",
83
83
  "mitata": "^0.1.11",
84
84
  "pinst": "^3.0.0",
85
- "prettier": "^2.8.8"
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,6 +1,6 @@
1
1
  import * as C from '../constants/constants.js'
2
2
  import * as messageBuilder from '../message/message-builder.js'
3
- import messageParser 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'
@@ -1,17 +1,14 @@
1
1
  import * as utils from '../utils/utils.js'
2
- import messageParser 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
7
 
9
- const BrowserWebSocket = globalThis.WebSocket || globalThis.MozWebSocket
10
8
  const NodeWebSocket = utils.isNode ? await import('ws').then((x) => x.default) : null
9
+ const BrowserWebSocket = globalThis.WebSocket || globalThis.MozWebSocket
11
10
 
12
- const HASHER = await xxhash()
13
-
14
- const Connection = function (client, url, options) {
11
+ export default function Connection(client, url, options) {
15
12
  this._client = client
16
13
  this._options = options
17
14
  this._logger = options.logger
@@ -32,6 +29,7 @@ const Connection = function (client, url, options) {
32
29
  this._recvQueue = new FixedQueue()
33
30
  this._reconnectTimeout = null
34
31
  this._reconnectionAttempt = 0
32
+ this._endpoint = null
35
33
 
36
34
  this._processingRecv = false
37
35
  this._recvMessages = this._recvMessages.bind(this)
@@ -40,8 +38,6 @@ const Connection = function (client, url, options) {
40
38
 
41
39
  this._state = C.CONNECTION_STATE.CLOSED
42
40
 
43
- this.hasher = HASHER
44
-
45
41
  this._createEndpoint()
46
42
  }
47
43
 
@@ -92,24 +88,19 @@ Connection.prototype.close = function () {
92
88
  }
93
89
 
94
90
  Connection.prototype._createEndpoint = function () {
95
- if (utils.isNode) {
96
- this._endpoint = new NodeWebSocket(this._url, {
97
- generateMask() {},
98
- })
99
- } else {
100
- this._endpoint = new BrowserWebSocket(this._url)
101
- this._endpoint.binaryType = 'arraybuffer'
102
- }
91
+ this._endpoint = NodeWebSocket
92
+ ? new NodeWebSocket(this._url, {
93
+ generateMask() {},
94
+ })
95
+ : new BrowserWebSocket(this._url)
103
96
  this._corked = false
104
97
 
105
98
  this._endpoint.onopen = this._onOpen.bind(this)
106
99
  this._endpoint.onerror = this._onError.bind(this)
107
100
  this._endpoint.onclose = this._onClose.bind(this)
108
-
109
- const decoder = new TextDecoder()
110
- this._endpoint.onmessage = ({ data }) => {
111
- this._onMessage(typeof data === 'string' ? data : decoder.decode(data))
112
- }
101
+ this._endpoint.onmessage = BrowserWebSocket
102
+ ? ({ data }) => this._onMessage(typeof data === 'string' ? data : Buffer.from(data).toString())
103
+ : ({ data }) => this._onMessage(typeof data === 'string' ? data : data.toString())
113
104
  }
114
105
 
115
106
  Connection.prototype.send = function (message) {
@@ -121,7 +112,7 @@ Connection.prototype.send = function (message) {
121
112
  C.TOPIC.CONNECTION,
122
113
  C.EVENT.CONNECTION_ERROR,
123
114
  err,
124
- message.split(C.MESSAGE_PART_SEPERATOR).map((x) => x.slice(0, 256))
115
+ message.split(C.MESSAGE_PART_SEPERATOR).map((x) => x.slice(0, 256)),
125
116
  )
126
117
  return false
127
118
  }
@@ -151,8 +142,8 @@ Connection.prototype.send = function (message) {
151
142
  Connection.prototype._submit = function (message) {
152
143
  const { maxPacketSize } = this._options
153
144
 
154
- if (message.byteLength > maxPacketSize) {
155
- const err = new Error(`Packet to big: ${message.byteLength} > ${maxPacketSize}`)
145
+ if (message.length > maxPacketSize) {
146
+ const err = new Error(`Packet to big: ${message.length} > ${maxPacketSize}`)
156
147
  this._client._$onError(C.TOPIC.CONNECTION, C.EVENT.CONNECTION_ERROR, err)
157
148
  return false
158
149
  } else if (this._endpoint.readyState === this._endpoint.OPEN) {
@@ -170,7 +161,7 @@ Connection.prototype._sendAuthParams = function () {
170
161
  this._setState(C.CONNECTION_STATE.AUTHENTICATING)
171
162
  const authMessage = messageBuilder.getMsg(C.TOPIC.AUTH, C.ACTIONS.REQUEST, [
172
163
  this._authParams,
173
- '24.3.1', // TODO (fix): How to read from package.json?
164
+ '24.4.0',
174
165
  utils.isNode
175
166
  ? `Node/${process.version}`
176
167
  : globalThis.navigator && globalThis.navigator.userAgent,
@@ -276,7 +267,7 @@ Connection.prototype._handleConnectionResponse = function (message) {
276
267
  } else if (message.action === C.ACTIONS.CHALLENGE) {
277
268
  this._setState(C.CONNECTION_STATE.CHALLENGING)
278
269
  this._submit(
279
- messageBuilder.getMsg(C.TOPIC.CONNECTION, C.ACTIONS.CHALLENGE_RESPONSE, [this._url])
270
+ messageBuilder.getMsg(C.TOPIC.CONNECTION, C.ACTIONS.CHALLENGE_RESPONSE, [this._url]),
280
271
  )
281
272
  } else if (message.action === C.ACTIONS.REJECTION) {
282
273
  this._challengeDenied = true
@@ -344,10 +335,16 @@ Connection.prototype._tryReconnect = function () {
344
335
 
345
336
  if (this._reconnectionAttempt < this._options.maxReconnectAttempts) {
346
337
  this._setState(C.CONNECTION_STATE.RECONNECTING)
347
- this._reconnectTimeout = setTimeout(() => {
348
- this._reconnectTimeout = null
349
- this._createEndpoint()
350
- }, Math.min(this._options.maxReconnectInterval, this._options.reconnectIntervalIncrement * this._reconnectionAttempt))
338
+ this._reconnectTimeout = setTimeout(
339
+ () => {
340
+ this._reconnectTimeout = null
341
+ this._createEndpoint()
342
+ },
343
+ Math.min(
344
+ this._options.maxReconnectInterval,
345
+ this._options.reconnectIntervalIncrement * this._reconnectionAttempt,
346
+ ),
347
+ )
351
348
  this._reconnectionAttempt++
352
349
  } else {
353
350
  this._clearReconnect()
@@ -363,5 +360,3 @@ Connection.prototype._clearReconnect = function () {
363
360
  }
364
361
  this._reconnectionAttempt = 0
365
362
  }
366
-
367
- export default Connection
@@ -1,94 +1,25 @@
1
1
  import * as C from '../constants/constants.js'
2
- import varint from 'varint'
3
2
 
4
- const poolEncoder = new TextEncoder()
5
-
6
- let poolSize
7
- let poolBuffer
8
- let poolView
9
- let poolOffset
10
-
11
- function reallocPool(size) {
12
- poolSize = size || poolSize || 1024 * 1024
13
- poolBuffer = new Uint8Array(new ArrayBuffer(poolSize))
14
- poolView = new DataView(poolBuffer.buffer)
15
- poolOffset = 0
16
- }
17
-
18
- function alignPool() {
19
- // Ensure aligned slices
20
- if (poolOffset & 0x7) {
21
- poolOffset |= 0x7
22
- poolOffset++
23
- }
24
- }
3
+ const SEP = C.MESSAGE_PART_SEPERATOR
25
4
 
26
5
  export function getMsg(topic, action, data) {
27
6
  if (data && !(data instanceof Array)) {
28
7
  throw new Error('data must be an array')
29
8
  }
30
9
 
31
- if (!poolSize || poolOffset + poolSize / 16 >= poolSize) {
32
- reallocPool()
33
- } else {
34
- alignPool()
35
- }
36
-
37
- const start = poolOffset
38
-
39
- const headerSize = 8
40
- poolBuffer[poolOffset++] = 128 + headerSize
41
- let headerPos = poolOffset
42
- poolOffset += headerSize - 1
43
-
44
- poolBuffer[poolOffset++] = topic.charCodeAt(0)
45
- poolBuffer[poolOffset++] = 31
46
- for (let n = 0; n < action.length; n++) {
47
- poolBuffer[poolOffset++] = action.charCodeAt(n)
48
- }
10
+ const sendData = [topic, action]
49
11
 
50
12
  if (data) {
51
13
  for (let i = 0; i < data.length; i++) {
52
- const type = typeof data[i]
53
- let len
54
- if (data[i] == null) {
55
- poolBuffer[poolOffset++] = 31
56
- len = 0
57
- } else if (type === 'object') {
58
- poolBuffer[poolOffset++] = 31
59
- const res = poolEncoder.encodeInto(
60
- JSON.stringify(data[i]),
61
- new Uint8Array(poolBuffer.buffer, poolOffset)
62
- )
63
- len = res.written
64
- } else if (type === 'bigint') {
65
- poolBuffer[poolOffset++] = 31
66
- poolView.setBigUint64(poolOffset, data[i], false)
67
- len = 8
68
- } else if (type === 'string') {
69
- poolBuffer[poolOffset++] = 31
70
- const res = poolEncoder.encodeInto(data[i], new Uint8Array(poolBuffer.buffer, poolOffset))
71
- len = res.written
14
+ if (typeof data[i] === 'object') {
15
+ sendData.push(JSON.stringify(data[i]))
72
16
  } else {
73
- throw new Error('invalid data')
74
- }
75
-
76
- poolOffset += len
77
-
78
- varint.encode(len + 1, poolBuffer, headerPos)
79
- headerPos += varint.encode.bytes
80
- if (headerPos - start >= headerSize) {
81
- throw new Error(`header too large: ${headerPos - start} ${headerSize}`)
82
- }
83
-
84
- if (poolOffset >= poolBuffer.length) {
85
- reallocPool(start === 0 ? poolSize * 2 : poolSize)
86
- return getMsg(topic, action, data)
17
+ sendData.push(data[i])
87
18
  }
88
19
  }
89
20
  }
90
21
 
91
- return new Uint8Array(poolBuffer.buffer, start, poolOffset - start)
22
+ return sendData.join(SEP)
92
23
  }
93
24
 
94
25
  export function typed(value) {
@@ -1,10 +1,12 @@
1
1
  import * as C from '../constants/constants.js'
2
2
 
3
- const MessageParser = function () {
4
- this._actions = this._getActions()
3
+ const actions = {}
4
+
5
+ for (const key in C.ACTIONS) {
6
+ actions[C.ACTIONS[key]] = key
5
7
  }
6
8
 
7
- MessageParser.prototype.convertTyped = function (value, client) {
9
+ export function convertTyped(value, client) {
8
10
  const type = value.charAt(0)
9
11
 
10
12
  if (type === C.TYPES.STRING) {
@@ -45,24 +47,14 @@ MessageParser.prototype.convertTyped = function (value, client) {
45
47
  return undefined
46
48
  }
47
49
 
48
- MessageParser.prototype._getActions = function () {
49
- const actions = {}
50
-
51
- for (const key in C.ACTIONS) {
52
- actions[C.ACTIONS[key]] = key
53
- }
54
-
55
- return actions
56
- }
57
-
58
- MessageParser.prototype.parseMessage = function (message, client, result) {
50
+ export function parseMessage(message, client, result) {
59
51
  const parts = message.split(C.MESSAGE_PART_SEPERATOR)
60
52
 
61
53
  if (parts.length < 2) {
62
54
  client._$onError(
63
55
  C.TOPIC.ERROR,
64
56
  C.EVENT.MESSAGE_PARSE_ERROR,
65
- new Error('Insufficiant message parts')
57
+ new Error('Insufficiant message parts'),
66
58
  )
67
59
  return null
68
60
  }
@@ -72,12 +64,12 @@ MessageParser.prototype.parseMessage = function (message, client, result) {
72
64
  return null
73
65
  }
74
66
 
75
- if (this._actions[parts[1]] === undefined) {
67
+ if (actions[parts[1]] === undefined) {
76
68
  client._$onError(
77
69
  C.TOPIC.ERROR,
78
70
  C.EVENT.MESSAGE_PARSE_ERROR,
79
71
  new Error('Unknown action'),
80
- message
72
+ message,
81
73
  )
82
74
  return null
83
75
  }
@@ -87,5 +79,3 @@ MessageParser.prototype.parseMessage = function (message, client, result) {
87
79
  result.action = parts[1]
88
80
  result.data = parts.splice(2)
89
81
  }
90
-
91
- export default new MessageParser()
@@ -49,8 +49,8 @@ function onTimeout(subscription) {
49
49
  new Error(`timeout state: ${subscription.record.name} [${current}<${expected}]`),
50
50
  {
51
51
  code: 'ETIMEDOUT',
52
- }
53
- )
52
+ },
53
+ ),
54
54
  )
55
55
  }
56
56
 
@@ -101,7 +101,6 @@ class RecordHandler {
101
101
  this._pruning = new Set()
102
102
  this._patching = new Map()
103
103
  this._updating = new Map()
104
- this._encoder = new TextEncoder()
105
104
 
106
105
  this._connected = 0
107
106
  this._stats = {
@@ -207,12 +206,6 @@ class RecordHandler {
207
206
  }
208
207
  }
209
208
 
210
- _getKey(name) {
211
- return name.length <= 8 && this._encoder.encode(name).byteLength === 8
212
- ? name
213
- : this._connection.hasher.h64(name)
214
- }
215
-
216
209
  /**
217
210
  * @param {string} name
218
211
  * @returns {Record}
@@ -220,13 +213,13 @@ class RecordHandler {
220
213
  getRecord(name) {
221
214
  invariant(
222
215
  typeof name === 'string' && name.length > 0 && name !== '[object Object]',
223
- `invalid name ${name}`
216
+ `invalid name ${name}`,
224
217
  )
225
218
 
226
219
  let record = this._records.get(name)
227
220
 
228
221
  if (!record) {
229
- record = new Record(this._getKey(name), name, this)
222
+ record = new Record(name, this)
230
223
  this._stats.records += 1
231
224
  this._stats.created += 1
232
225
  this._records.set(name, record)
@@ -294,17 +287,22 @@ class RecordHandler {
294
287
  const patching = [...this._patching.values()]
295
288
  await Promise.race([
296
289
  Promise.all(
297
- patching.map((callbacks) => new Promise((resolve) => callbacks.push(resolve)))
290
+ patching.map((callbacks) => new Promise((resolve) => callbacks.push(resolve))),
298
291
  ),
299
292
  new Promise((resolve) => {
300
- patchingTimeout = timers.setTimeout(() => {
301
- this._client._$onError(
302
- C.TOPIC.RECORD,
303
- C.EVENT.TIMEOUT,
304
- Object.assign(new Error('sync patching timeout'), { data: { patching, timeout } })
305
- )
306
- resolve(null)
307
- }, timeout ?? 2 * 60e3)
293
+ patchingTimeout = timers.setTimeout(
294
+ () => {
295
+ this._client._$onError(
296
+ C.TOPIC.RECORD,
297
+ C.EVENT.TIMEOUT,
298
+ Object.assign(new Error('sync patching timeout'), {
299
+ data: { patching, timeout },
300
+ }),
301
+ )
302
+ resolve(null)
303
+ },
304
+ timeout ?? 2 * 60e3,
305
+ )
308
306
  }),
309
307
  signalPromise,
310
308
  ]).finally(() => {
@@ -317,17 +315,22 @@ class RecordHandler {
317
315
  const updating = [...this._updating.values()]
318
316
  await Promise.race([
319
317
  Promise.all(
320
- updating.map((callbacks) => new Promise((resolve) => callbacks.push(resolve)))
318
+ updating.map((callbacks) => new Promise((resolve) => callbacks.push(resolve))),
321
319
  ),
322
320
  new Promise((resolve) => {
323
- updatingTimeout = timers.setTimeout(() => {
324
- this._client._$onError(
325
- C.TOPIC.RECORD,
326
- C.EVENT.TIMEOUT,
327
- Object.assign(new Error('sync updating timeout'), { data: { updating, timeout } })
328
- )
329
- resolve(null)
330
- }, timeout ?? 2 * 60e3)
321
+ updatingTimeout = timers.setTimeout(
322
+ () => {
323
+ this._client._$onError(
324
+ C.TOPIC.RECORD,
325
+ C.EVENT.TIMEOUT,
326
+ Object.assign(new Error('sync updating timeout'), {
327
+ data: { updating, timeout },
328
+ }),
329
+ )
330
+ resolve(null)
331
+ },
332
+ timeout ?? 2 * 60e3,
333
+ )
331
334
  }),
332
335
  signalPromise,
333
336
  ]).finally(() => {
@@ -343,14 +346,17 @@ class RecordHandler {
343
346
  this._connection.sendMsg(C.TOPIC.RECORD, C.ACTIONS.SYNC, [token])
344
347
  }),
345
348
  new Promise((resolve) => {
346
- serverTimeout = timers.setTimeout(() => {
347
- this._client._$onError(
348
- C.TOPIC.RECORD,
349
- C.EVENT.TIMEOUT,
350
- Object.assign(new Error('sync server timeout'), { data: { token, timeout } })
351
- )
352
- resolve(null)
353
- }, timeout ?? 2 * 60e3)
349
+ serverTimeout = timers.setTimeout(
350
+ () => {
351
+ this._client._$onError(
352
+ C.TOPIC.RECORD,
353
+ C.EVENT.TIMEOUT,
354
+ Object.assign(new Error('sync server timeout'), { data: { token, timeout } }),
355
+ )
356
+ resolve(null)
357
+ },
358
+ timeout ?? 2 * 60e3,
359
+ )
354
360
  }),
355
361
  signalPromise,
356
362
  ]).finally(() => {
@@ -423,7 +429,7 @@ class RecordHandler {
423
429
  timeout: 2 * 60e3,
424
430
  dataOnly: true,
425
431
  },
426
- ...args
432
+ ...args,
427
433
  )
428
434
  }
429
435
 
@@ -499,7 +505,7 @@ class RecordHandler {
499
505
  {
500
506
  timeout: 2 * 60e3,
501
507
  },
502
- ...args
508
+ ...args,
503
509
  )
504
510
  }
505
511
 
@@ -1,24 +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 messageParser 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) {
16
14
  const connection = handler._connection
17
15
 
18
16
  this._handler = handler
19
-
20
17
  this._name = name
21
- this._key = key
22
18
  this._version = ''
23
19
  this._data = jsonPath.EMPTY
24
20
  this._state = C.RECORD_STATE.VOID
@@ -28,10 +24,7 @@ class Record {
28
24
 
29
25
  /** @type Map? */ this._updating = null
30
26
  /** @type Array? */ this._patching = null
31
- this._subscribed = connection.sendMsg(C.TOPIC.RECORD, C.ACTIONS.SUBSCRIBE, [
32
- this._name,
33
- this._key,
34
- ])
27
+ this._subscribed = connection.sendMsg(C.TOPIC.RECORD, C.ACTIONS.SUBSCRIBE, [this._name])
35
28
  }
36
29
 
37
30
  /** @type {string} */
@@ -69,8 +62,7 @@ class Record {
69
62
  if (this._refs === 1) {
70
63
  this._handler._onPruning(this, false)
71
64
  this._subscribed =
72
- this._subscribed ||
73
- 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])
74
66
  }
75
67
  return this
76
68
  }
@@ -257,7 +249,7 @@ class Record {
257
249
  onDone(
258
250
  Object.assign(new Error(`timeout ${this.name} [${current}<${expected}]`), {
259
251
  code: 'ETIMEDOUT',
260
- })
252
+ }),
261
253
  )
262
254
  }, timeout)
263
255
  }
@@ -332,8 +324,7 @@ class Record {
332
324
 
333
325
  if (connected) {
334
326
  this._subscribed =
335
- this._refs > 0 &&
336
- 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])
337
328
 
338
329
  if (this._updating) {
339
330
  for (const update of this._updating.values()) {
@@ -358,7 +349,7 @@ class Record {
358
349
  invariant(!this._updating, 'must not have updates')
359
350
 
360
351
  if (this._subscribed) {
361
- connection.sendMsg(C.TOPIC.RECORD, C.ACTIONS.UNSUBSCRIBE, [this._key])
352
+ connection.sendMsg(C.TOPIC.RECORD, C.ACTIONS.UNSUBSCRIBE, [this._name])
362
353
  this._subscribed = false
363
354
  }
364
355
 
@@ -380,7 +371,7 @@ class Record {
380
371
  const prevVersion = this._version
381
372
  const nextVersion = this._makeVersion(parseInt(prevVersion) + 1)
382
373
 
383
- const update = [this._key, nextVersion, jsonPath.stringify(nextData), prevVersion]
374
+ const update = [this._name, nextVersion, jsonPath.stringify(nextData), prevVersion]
384
375
 
385
376
  if (!this._updating) {
386
377
  this._onUpdating(true)
@@ -479,8 +470,8 @@ class Record {
479
470
  hasProvider && messageParser.convertTyped(hasProvider, this._handler._client)
480
471
  ? C.RECORD_STATE.PROVIDER
481
472
  : this._version.charAt(0) === 'I'
482
- ? C.RECORD_STATE.STALE
483
- : C.RECORD_STATE.SERVER
473
+ ? C.RECORD_STATE.STALE
474
+ : C.RECORD_STATE.SERVER
484
475
 
485
476
  if (this._state !== prevState) {
486
477
  this._emitUpdate()
@@ -1,6 +1,6 @@
1
1
  import * as C from '../constants/constants.js'
2
2
  import RpcResponse from './rpc-response.js'
3
- import messageParser 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
 
@@ -153,7 +153,7 @@ 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
159
  rpc.callback(null, messageParser.convertTyped(data, this._client))
@@ -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
  }
@@ -101,7 +102,7 @@ class Listener {
101
102
  this._connection.sendMsg(
102
103
  this._topic,
103
104
  accepted ? C.ACTIONS.LISTEN_ACCEPT : C.ACTIONS.LISTEN_REJECT,
104
- [this._pattern, provider.name]
105
+ [this._pattern, provider.name],
105
106
  )
106
107
 
107
108
  provider.version = null
@@ -151,7 +152,7 @@ class Listener {
151
152
  }
152
153
 
153
154
  const body = typeof value !== 'string' ? this._stringify(value) : value
154
- const hash = this._connection.hasher.h64ToString(body)
155
+ const hash = h64ToString(body)
155
156
  const version = `INF-${hash}`
156
157
 
157
158
  if (provider.version !== version) {
@@ -228,5 +229,3 @@ class Listener {
228
229
  this._subscriptions.clear()
229
230
  }
230
231
  }
231
-
232
- 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')
@@ -76,7 +76,7 @@ class Listener {
76
76
  this._subscriptions.delete(name)
77
77
  subscription.unsubscribe()
78
78
  } else {
79
- const version = `INF-${this._connection.hasher.h64ToString(data)}`
79
+ const version = `INF-${h64ToString(data)}`
80
80
  this._connection.sendMsg(this._topic, C.ACTIONS.UPDATE, [name, version, data])
81
81
  }
82
82
  },
@@ -126,5 +126,3 @@ class Listener {
126
126
  this._connection.sendMsg(this._topic, C.ACTIONS.UNLISTEN, [this._pattern])
127
127
  }
128
128
  }
129
-
130
- 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'
@@ -174,3 +176,9 @@ export function removeAbortListener(signal, handler) {
174
176
  }
175
177
  }
176
178
  }
179
+
180
+ const HASHER = await xxhash()
181
+
182
+ export function h64ToString(str) {
183
+ return HASHER.h64ToString(str)
184
+ }