@nxtedition/deepstream.io-client-js 24.3.4 → 24.4.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/.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.4",
3
+ "version": "24.4.1",
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,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 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) {
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,7 +24,7 @@ class Record {
25
24
 
26
25
  /** @type Map? */ this._updating = null
27
26
  /** @type Array? */ this._patching = null
28
- this._subscribed = false
27
+ this._subscribed = connection.sendMsg(C.TOPIC.RECORD, C.ACTIONS.SUBSCRIBE, [this._name])
29
28
  }
30
29
 
31
30
  /** @type {string} */
@@ -63,8 +62,7 @@ class Record {
63
62
  if (this._refs === 1) {
64
63
  this._handler._onPruning(this, false)
65
64
  this._subscribed =
66
- this._subscribed ||
67
- 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])
68
66
  }
69
67
  return this
70
68
  }
@@ -251,7 +249,7 @@ class Record {
251
249
  onDone(
252
250
  Object.assign(new Error(`timeout ${this.name} [${current}<${expected}]`), {
253
251
  code: 'ETIMEDOUT',
254
- })
252
+ }),
255
253
  )
256
254
  }, timeout)
257
255
  }
@@ -326,8 +324,7 @@ class Record {
326
324
 
327
325
  if (connected) {
328
326
  this._subscribed =
329
- this._refs > 0 &&
330
- 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])
331
328
 
332
329
  if (this._updating) {
333
330
  for (const update of this._updating.values()) {
@@ -352,7 +349,7 @@ class Record {
352
349
  invariant(!this._updating, 'must not have updates')
353
350
 
354
351
  if (this._subscribed) {
355
- connection.sendMsg(C.TOPIC.RECORD, C.ACTIONS.UNSUBSCRIBE, [this._key])
352
+ connection.sendMsg(C.TOPIC.RECORD, C.ACTIONS.UNSUBSCRIBE, [this._name])
356
353
  this._subscribed = false
357
354
  }
358
355
 
@@ -374,7 +371,7 @@ class Record {
374
371
  const prevVersion = this._version
375
372
  const nextVersion = this._makeVersion(parseInt(prevVersion) + 1)
376
373
 
377
- const update = [this._key, nextVersion, jsonPath.stringify(nextData), prevVersion]
374
+ const update = [this._name, nextVersion, jsonPath.stringify(nextData), prevVersion]
378
375
 
379
376
  if (!this._updating) {
380
377
  this._onUpdating(true)
@@ -473,8 +470,8 @@ class Record {
473
470
  hasProvider && messageParser.convertTyped(hasProvider, this._handler._client)
474
471
  ? C.RECORD_STATE.PROVIDER
475
472
  : this._version.charAt(0) === 'I'
476
- ? C.RECORD_STATE.STALE
477
- : C.RECORD_STATE.SERVER
473
+ ? C.RECORD_STATE.STALE
474
+ : C.RECORD_STATE.SERVER
478
475
 
479
476
  if (this._state !== prevState) {
480
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
  }
@@ -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'
@@ -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
+ }