@nxtedition/deepstream.io-client-js 26.0.3 → 26.0.5

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": "26.0.3",
3
+ "version": "26.0.5",
4
4
  "description": "the javascript client for deepstream.io",
5
5
  "homepage": "http://deepstream.io",
6
6
  "type": "module",
package/src/client.js CHANGED
@@ -36,13 +36,13 @@ const Client = function (url, options) {
36
36
  Emitter(Client.prototype)
37
37
 
38
38
  Object.defineProperty(Client.prototype, 'stats', {
39
- get: function stats() {
39
+ get: function stats () {
40
40
  return {
41
41
  record: this.record.stats,
42
42
  rpc: this.rpc.stats,
43
- event: this.event.stats,
43
+ event: this.event.stats
44
44
  }
45
- },
45
+ }
46
46
  })
47
47
 
48
48
  Client.prototype.login = function (authParamsOrCallback, callback) {
@@ -127,7 +127,7 @@ Client.prototype._getOptions = function (options) {
127
127
  return mergedOptions
128
128
  }
129
129
 
130
- function createDeepstream(url, options) {
130
+ function createDeepstream (url, options) {
131
131
  return new Client(url, options)
132
132
  }
133
133
 
@@ -5,5 +5,5 @@ export default {
5
5
  maxPacketSize: 1024 * 1024,
6
6
  batchSize: 4096,
7
7
  schedule: null,
8
- logger: null,
8
+ logger: null
9
9
  }
@@ -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 { convertTyped } from '../message/message-parser.js'
3
+ import 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'
@@ -13,7 +13,7 @@ const EventHandler = function (options, connection, client) {
13
13
  this._emitter = new EventEmitter()
14
14
  this._listeners = new Map()
15
15
  this._stats = {
16
- emitted: 0,
16
+ emitted: 0
17
17
  }
18
18
 
19
19
  this.subscribe = this.subscribe.bind(this)
@@ -26,19 +26,19 @@ const EventHandler = function (options, connection, client) {
26
26
  }
27
27
 
28
28
  Object.defineProperty(EventHandler.prototype, 'connected', {
29
- get: function connected() {
29
+ get: function connected () {
30
30
  return this._client.getConnectionState() === C.CONNECTION_STATE.OPEN
31
- },
31
+ }
32
32
  })
33
33
 
34
34
  Object.defineProperty(EventHandler.prototype, 'stats', {
35
- get: function stats() {
35
+ get: function stats () {
36
36
  return {
37
37
  ...this._stats,
38
38
  listeners: this._listeners.size,
39
- events: this._emitter.eventNames().length,
39
+ events: this._emitter.eventNames().length
40
40
  }
41
- },
41
+ }
42
42
  })
43
43
 
44
44
  EventHandler.prototype.subscribe = function (name, callback) {
@@ -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,11 +1,10 @@
1
1
  import * as utils from '../utils/utils.js'
2
- import { convertTyped } from './message-parser.js'
2
+ import messageParser from './message-parser.js'
3
3
  import * as messageBuilder from './message-builder.js'
4
4
  import * as C from '../constants/constants.js'
5
5
  import xxhash from 'xxhash-wasm'
6
6
  import FixedQueue from '../utils/fixed-queue.js'
7
7
  import Emitter from 'component-emitter2'
8
- import varint from 'varint'
9
8
 
10
9
  const BrowserWebSocket = globalThis.WebSocket || globalThis.MozWebSocket
11
10
  const NodeWebSocket = utils.isNode ? await import('ws').then((x) => x.default) : null
@@ -24,8 +23,12 @@ const Connection = function (client, url, options) {
24
23
  this._tooManyAuthAttempts = false
25
24
  this._connectionAuthenticationTimeout = false
26
25
  this._challengeDenied = false
27
- this._decoder = new TextDecoder()
28
- this._encoder = new TextEncoder()
26
+ this._message = {
27
+ raw: null,
28
+ topic: null,
29
+ action: null,
30
+ data: null,
31
+ }
29
32
  this._recvQueue = new FixedQueue()
30
33
  this._reconnectTimeout = null
31
34
  this._reconnectionAttempt = 0
@@ -103,8 +106,9 @@ Connection.prototype._createEndpoint = function () {
103
106
  this._endpoint.onerror = this._onError.bind(this)
104
107
  this._endpoint.onclose = this._onClose.bind(this)
105
108
 
109
+ const decoder = new TextDecoder()
106
110
  this._endpoint.onmessage = ({ data }) => {
107
- this._onMessage(data)
111
+ this._onMessage(typeof data === 'string' ? data : decoder.decode(data))
108
112
  }
109
113
  }
110
114
 
@@ -113,7 +117,12 @@ Connection.prototype.send = function (message) {
113
117
 
114
118
  if (message.length > maxPacketSize) {
115
119
  const err = new Error(`Packet to big: ${message.length} > ${maxPacketSize}`)
116
- this._client._$onError(C.TOPIC.CONNECTION, C.EVENT.CONNECTION_ERROR, err, message)
120
+ this._client._$onError(
121
+ C.TOPIC.CONNECTION,
122
+ C.EVENT.CONNECTION_ERROR,
123
+ err,
124
+ message.split(C.MESSAGE_PART_SEPERATOR).map((x) => x.slice(0, 256)),
125
+ )
117
126
  return false
118
127
  }
119
128
 
@@ -161,7 +170,7 @@ Connection.prototype._sendAuthParams = function () {
161
170
  this._setState(C.CONNECTION_STATE.AUTHENTICATING)
162
171
  const authMessage = messageBuilder.getMsg(C.TOPIC.AUTH, C.ACTIONS.REQUEST, [
163
172
  this._authParams,
164
- '26.0.0', // TODO (fix): How to read from package.json?
173
+ '26.0.5', // TODO (fix): How to read from package.json?
165
174
  utils.isNode
166
175
  ? `Node/${process.version}`
167
176
  : globalThis.navigator && globalThis.navigator.userAgent,
@@ -206,60 +215,13 @@ Connection.prototype._onClose = function () {
206
215
  }
207
216
  }
208
217
 
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
- }
215
-
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++])
218
+ Connection.prototype._onMessage = function (data) {
219
+ // Remove MESSAGE_SEPERATOR if exists.
220
+ if (data.charCodeAt(data.length - 1) === 30) {
221
+ data = data.slice(0, -1)
236
222
  }
237
- pos++
238
223
 
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 })
224
+ this._recvQueue.push(data)
263
225
  if (!this._processingRecv) {
264
226
  this._processingRecv = true
265
227
  this._schedule(this._recvMessages)
@@ -283,19 +245,20 @@ Connection.prototype._recvMessages = function (deadline) {
283
245
  continue
284
246
  }
285
247
 
286
- if (message === C.TOPIC.ERROR) {
287
- this._client._$onError(C.TOPIC.ERROR, message.action, new Error('Message error'), message)
288
- continue
248
+ if (this._logger) {
249
+ this._logger.trace(message, 'receive')
289
250
  }
290
251
 
291
- this.emit('recv', message)
252
+ messageParser.parseMessage(message, this._client, this._message)
253
+
254
+ this.emit('recv', this._message)
292
255
 
293
- if (message.topic === C.TOPIC.CONNECTION) {
294
- this._handleConnectionResponse(message)
295
- } else if (message.topic === C.TOPIC.AUTH) {
296
- this._handleAuthResponse(message)
256
+ if (this._message.topic === C.TOPIC.CONNECTION) {
257
+ this._handleConnectionResponse(this._message)
258
+ } else if (this._message.topic === C.TOPIC.AUTH) {
259
+ this._handleAuthResponse(this._message)
297
260
  } else {
298
- this._client._$onMessage(message)
261
+ this._client._$onMessage(this._message)
299
262
  }
300
263
  }
301
264
 
@@ -352,7 +315,7 @@ Connection.prototype._getAuthData = function (data) {
352
315
  if (data === undefined) {
353
316
  return null
354
317
  } else {
355
- return convertTyped(data, this._client)
318
+ return messageParser.convertTyped(data, this._client)
356
319
  }
357
320
  }
358
321
 
@@ -9,7 +9,7 @@ let poolBuffer
9
9
  let poolView
10
10
  let poolOffset
11
11
 
12
- function allocPool(size) {
12
+ function allocPool (size) {
13
13
  poolSize = size || poolSize || 1024 * 1024
14
14
  poolBuffer = utils.isNode
15
15
  ? globalThis.Buffer.allocUnsafe(poolSize)
@@ -18,7 +18,7 @@ function allocPool(size) {
18
18
  poolOffset = 0
19
19
  }
20
20
 
21
- function alignPool() {
21
+ function alignPool () {
22
22
  // Ensure aligned slices
23
23
  if (poolOffset & 0x7) {
24
24
  poolOffset |= 0x7
@@ -26,7 +26,7 @@ function alignPool() {
26
26
  }
27
27
  }
28
28
 
29
- function writeString(dst, str, offset) {
29
+ function writeString (dst, str, offset) {
30
30
  if (utils.isNode) {
31
31
  return dst.write(str, offset)
32
32
  } else {
@@ -35,7 +35,7 @@ function writeString(dst, str, offset) {
35
35
  }
36
36
  }
37
37
 
38
- export function getMsg(topic, action, data) {
38
+ export function getMsg (topic, action, data) {
39
39
  if (data && !(data instanceof Array)) {
40
40
  throw new Error('data must be an array')
41
41
  }
@@ -79,6 +79,7 @@ export function getMsg(topic, action, data) {
79
79
  } else {
80
80
  throw new Error('invalid data')
81
81
  }
82
+
82
83
  poolOffset += len
83
84
 
84
85
  varint.encode(len + 1, poolBuffer, headerPos)
@@ -97,7 +98,7 @@ export function getMsg(topic, action, data) {
97
98
  return new Uint8Array(poolBuffer.buffer, start, poolOffset - start)
98
99
  }
99
100
 
100
- export function typed(value) {
101
+ export function typed (value) {
101
102
  const type = typeof value
102
103
 
103
104
  if (type === 'string') {
@@ -1,6 +1,10 @@
1
1
  import * as C from '../constants/constants.js'
2
2
 
3
- export function convertTyped(value, client) {
3
+ const MessageParser = function () {
4
+ this._actions = this._getActions()
5
+ }
6
+
7
+ MessageParser.prototype.convertTyped = function (value, client) {
4
8
  const type = value.charAt(0)
5
9
 
6
10
  if (type === C.TYPES.STRING) {
@@ -40,3 +44,48 @@ export function convertTyped(value, client) {
40
44
 
41
45
  return undefined
42
46
  }
47
+
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) {
59
+ const parts = message.split(C.MESSAGE_PART_SEPERATOR)
60
+
61
+ if (parts.length < 2) {
62
+ client._$onError(
63
+ C.TOPIC.ERROR,
64
+ C.EVENT.MESSAGE_PARSE_ERROR,
65
+ new Error('Insufficiant message parts')
66
+ )
67
+ return null
68
+ }
69
+
70
+ if (parts[0] === C.TOPIC.ERROR) {
71
+ client._$onError(C.TOPIC.ERROR, parts[1], new Error('Message error'), message)
72
+ return null
73
+ }
74
+
75
+ if (this._actions[parts[1]] === undefined) {
76
+ client._$onError(
77
+ C.TOPIC.ERROR,
78
+ C.EVENT.MESSAGE_PARSE_ERROR,
79
+ new Error('Unknown action'),
80
+ message
81
+ )
82
+ return null
83
+ }
84
+
85
+ result.raw = message
86
+ result.topic = parts[0]
87
+ result.action = parts[1]
88
+ result.data = parts.splice(2)
89
+ }
90
+
91
+ export default new MessageParser()
@@ -13,7 +13,7 @@ import * as timers from '../utils/timers.js'
13
13
 
14
14
  const kEmpty = Symbol('kEmpty')
15
15
 
16
- function onUpdate(record, subscription) {
16
+ function onUpdate (record, subscription) {
17
17
  if (subscription.state && record.state < subscription.state) {
18
18
  return
19
19
  }
@@ -35,12 +35,12 @@ function onUpdate(record, subscription) {
35
35
  name: record.name,
36
36
  version: record.version,
37
37
  state: record.state,
38
- data,
38
+ data
39
39
  })
40
40
  }
41
41
  }
42
42
 
43
- function onTimeout(subscription) {
43
+ function onTimeout (subscription) {
44
44
  const expected = C.RECORD_STATE_NAME[subscription.state]
45
45
  const current = C.RECORD_STATE_NAME[subscription.record.state]
46
46
 
@@ -48,13 +48,13 @@ function onTimeout(subscription) {
48
48
  Object.assign(
49
49
  new Error(`timeout state: ${subscription.record.name} [${current}<${expected}]`),
50
50
  {
51
- code: 'ETIMEDOUT',
52
- },
53
- ),
51
+ code: 'ETIMEDOUT'
52
+ }
53
+ )
54
54
  )
55
55
  }
56
56
 
57
- function onUpdateFast(rec, opaque) {
57
+ function onUpdateFast (rec, opaque) {
58
58
  const { timeout, resolve, synced, state } = opaque
59
59
 
60
60
  if (rec.state >= state && synced) {
@@ -65,12 +65,12 @@ function onUpdateFast(rec, opaque) {
65
65
  }
66
66
  }
67
67
 
68
- function onSyncFast(opaque) {
68
+ function onSyncFast (opaque) {
69
69
  opaque.synced = true
70
70
  onUpdateFast(opaque.rec, opaque)
71
71
  }
72
72
 
73
- function onTimeoutFast(opaque) {
73
+ function onTimeoutFast (opaque) {
74
74
  const { rec, synced, resolve } = opaque
75
75
  rec.unsubscribe(onUpdateFast, opaque)
76
76
  rec.unref()
@@ -88,7 +88,7 @@ function onTimeoutFast(opaque) {
88
88
  }
89
89
 
90
90
  class RecordHandler {
91
- constructor(options, connection, client) {
91
+ constructor (options, connection, client) {
92
92
  this.JSON = jsonPath
93
93
  this.STATE = C.RECORD_STATE
94
94
  Object.assign(this, C.RECORD_STATE)
@@ -110,7 +110,7 @@ class RecordHandler {
110
110
  destroyed: 0,
111
111
  records: 0,
112
112
  pruning: 0,
113
- patching: 0,
113
+ patching: 0
114
114
  }
115
115
 
116
116
  this._syncQueue = []
@@ -147,7 +147,7 @@ class RecordHandler {
147
147
  this._pruningTimeout = timers.setTimeout(_prune, 1e3)
148
148
  }
149
149
 
150
- _onPruning(rec, value) {
150
+ _onPruning (rec, value) {
151
151
  if (value) {
152
152
  this._stats.pruning += 1
153
153
  } else {
@@ -161,7 +161,7 @@ class RecordHandler {
161
161
  }
162
162
  }
163
163
 
164
- _onUpdating(rec, value) {
164
+ _onUpdating (rec, value) {
165
165
  if (value) {
166
166
  this._stats.updating += 1
167
167
  this._updating.set(rec, [])
@@ -176,7 +176,7 @@ class RecordHandler {
176
176
  }
177
177
  }
178
178
 
179
- _onPatching(rec, value) {
179
+ _onPatching (rec, value) {
180
180
  if (value) {
181
181
  this._stats.patching += 1
182
182
  this._patching.set(rec, [])
@@ -191,11 +191,11 @@ class RecordHandler {
191
191
  }
192
192
  }
193
193
 
194
- get connected() {
194
+ get connected () {
195
195
  return Boolean(this._connected)
196
196
  }
197
197
 
198
- get stats() {
198
+ get stats () {
199
199
  let subscriptions = 0
200
200
  for (const listener of this._listeners.values()) {
201
201
  subscriptions += listener.subscriptions ?? 0
@@ -203,11 +203,11 @@ class RecordHandler {
203
203
 
204
204
  return {
205
205
  ...this._stats,
206
- subscriptions,
206
+ subscriptions
207
207
  }
208
208
  }
209
209
 
210
- getKey(name) {
210
+ getKey (name) {
211
211
  if (name.length > 8) {
212
212
  return this._connection.hasher.h64(name)
213
213
  }
@@ -219,10 +219,10 @@ class RecordHandler {
219
219
  * @param {string} name
220
220
  * @returns {Record}
221
221
  */
222
- getRecord(name) {
222
+ getRecord (name) {
223
223
  invariant(
224
224
  typeof name === 'string' && name.length > 0 && name !== '[object Object]',
225
- `invalid name ${name}`,
225
+ `invalid name ${name}`
226
226
  )
227
227
 
228
228
  let record = this._records.get(name)
@@ -237,7 +237,7 @@ class RecordHandler {
237
237
  return record.ref()
238
238
  }
239
239
 
240
- provide(pattern, callback, options) {
240
+ provide (pattern, callback, options) {
241
241
  if (typeof pattern !== 'string' || pattern.length === 0) {
242
242
  throw new Error('invalid argument pattern')
243
243
  }
@@ -272,7 +272,7 @@ class RecordHandler {
272
272
  }
273
273
  }
274
274
 
275
- async sync(opts) {
275
+ async sync (opts) {
276
276
  // TODO (fix): Sync pending? What about VOID state?
277
277
 
278
278
  let onAbort
@@ -282,11 +282,11 @@ class RecordHandler {
282
282
 
283
283
  const signalPromise = signal
284
284
  ? new Promise((resolve, reject) => {
285
- onAbort = () => {
286
- reject(signal.reason ?? new utils.AbortError())
287
- }
288
- signal.addEventListener('abort', onAbort)
289
- })
285
+ onAbort = () => {
286
+ reject(signal.reason ?? new utils.AbortError())
287
+ }
288
+ signal.addEventListener('abort', onAbort)
289
+ })
290
290
  : null
291
291
  signalPromise?.catch(() => {})
292
292
 
@@ -296,7 +296,7 @@ class RecordHandler {
296
296
  const patching = [...this._patching.values()]
297
297
  await Promise.race([
298
298
  Promise.all(
299
- patching.map((callbacks) => new Promise((resolve) => callbacks.push(resolve))),
299
+ patching.map((callbacks) => new Promise((resolve) => callbacks.push(resolve)))
300
300
  ),
301
301
  new Promise((resolve) => {
302
302
  patchingTimeout = timers.setTimeout(
@@ -305,15 +305,15 @@ class RecordHandler {
305
305
  C.TOPIC.RECORD,
306
306
  C.EVENT.TIMEOUT,
307
307
  Object.assign(new Error('sync patching timeout'), {
308
- data: { patching, timeout },
309
- }),
308
+ data: { patching, timeout }
309
+ })
310
310
  )
311
311
  resolve(null)
312
312
  },
313
- timeout ?? 2 * 60e3,
313
+ timeout ?? 2 * 60e3
314
314
  )
315
315
  }),
316
- signalPromise,
316
+ signalPromise
317
317
  ]).finally(() => {
318
318
  timers.clearTimeout(patchingTimeout)
319
319
  })
@@ -324,7 +324,7 @@ class RecordHandler {
324
324
  const updating = [...this._updating.values()]
325
325
  await Promise.race([
326
326
  Promise.all(
327
- updating.map((callbacks) => new Promise((resolve) => callbacks.push(resolve))),
327
+ updating.map((callbacks) => new Promise((resolve) => callbacks.push(resolve)))
328
328
  ),
329
329
  new Promise((resolve) => {
330
330
  updatingTimeout = timers.setTimeout(
@@ -333,15 +333,15 @@ class RecordHandler {
333
333
  C.TOPIC.RECORD,
334
334
  C.EVENT.TIMEOUT,
335
335
  Object.assign(new Error('sync updating timeout'), {
336
- data: { updating, timeout },
337
- }),
336
+ data: { updating, timeout }
337
+ })
338
338
  )
339
339
  resolve(null)
340
340
  },
341
- timeout ?? 2 * 60e3,
341
+ timeout ?? 2 * 60e3
342
342
  )
343
343
  }),
344
- signalPromise,
344
+ signalPromise
345
345
  ]).finally(() => {
346
346
  timers.clearTimeout(updatingTimeout)
347
347
  })
@@ -360,14 +360,14 @@ class RecordHandler {
360
360
  this._client._$onError(
361
361
  C.TOPIC.RECORD,
362
362
  C.EVENT.TIMEOUT,
363
- Object.assign(new Error('sync server timeout'), { data: { token, timeout } }),
363
+ Object.assign(new Error('sync server timeout'), { data: { token, timeout } })
364
364
  )
365
365
  resolve(null)
366
366
  },
367
- timeout ?? 2 * 60e3,
367
+ timeout ?? 2 * 60e3
368
368
  )
369
369
  }),
370
- signalPromise,
370
+ signalPromise
371
371
  ]).finally(() => {
372
372
  timers.clearTimeout(serverTimeout)
373
373
  })
@@ -378,7 +378,7 @@ class RecordHandler {
378
378
  }
379
379
  }
380
380
 
381
- _sync(callback, opaque) {
381
+ _sync (callback, opaque) {
382
382
  this._syncQueue.push(callback, opaque)
383
383
 
384
384
  if (this._syncQueue.length > 2) {
@@ -399,7 +399,7 @@ class RecordHandler {
399
399
  }, 1)
400
400
  }
401
401
 
402
- set(name, ...args) {
402
+ set (name, ...args) {
403
403
  const record = this.getRecord(name)
404
404
  try {
405
405
  return record.set(...args)
@@ -414,7 +414,7 @@ class RecordHandler {
414
414
  * @param {...any} args
415
415
  * @returns {Promise}
416
416
  */
417
- update(name, ...args) {
417
+ update (name, ...args) {
418
418
  try {
419
419
  const record = this.getRecord(name)
420
420
  try {
@@ -431,14 +431,14 @@ class RecordHandler {
431
431
  * @param {...any} args
432
432
  * @returns {rxjs.Observable}
433
433
  */
434
- observe(...args) {
434
+ observe (...args) {
435
435
  return this._observe(
436
436
  {
437
437
  state: C.RECORD_STATE.SERVER,
438
438
  timeout: 2 * 60e3,
439
- dataOnly: true,
439
+ dataOnly: true
440
440
  },
441
- ...args,
441
+ ...args
442
442
  )
443
443
  }
444
444
 
@@ -446,7 +446,7 @@ class RecordHandler {
446
446
  * @param {...any} args
447
447
  * @returns {Promise}
448
448
  */
449
- get(...args) {
449
+ get (...args) {
450
450
  if (args.length === 1 || (args.length === 2 && typeof args[1] === 'number')) {
451
451
  return new Promise((resolve) => {
452
452
  const rec = this.getRecord(args[0])
@@ -466,7 +466,7 @@ class RecordHandler {
466
466
  state,
467
467
  resolve,
468
468
  timeout: null,
469
- synced,
469
+ synced
470
470
  }
471
471
  opaque.timeout = timers.setTimeout(onTimeoutFast, 2 * 60e3, opaque)
472
472
  rec.subscribe(onUpdateFast, opaque)
@@ -484,7 +484,7 @@ class RecordHandler {
484
484
  .pipe(rx.first())
485
485
  .subscribe({
486
486
  next: resolve,
487
- error: reject,
487
+ error: reject
488
488
  })
489
489
  })
490
490
  }
@@ -494,13 +494,13 @@ class RecordHandler {
494
494
  * @param {...any} args
495
495
  * @returns {Promise}
496
496
  */
497
- get2(...args) {
497
+ get2 (...args) {
498
498
  return new Promise((resolve, reject) => {
499
499
  this.observe2(...args)
500
500
  .pipe(rx.first())
501
501
  .subscribe({
502
502
  next: resolve,
503
- error: reject,
503
+ error: reject
504
504
  })
505
505
  })
506
506
  }
@@ -509,12 +509,12 @@ class RecordHandler {
509
509
  * @param {...any} args
510
510
  * @returns {rxjs.Observable<{ name: string, version: string, state: Number, data: any}>}
511
511
  */
512
- observe2(...args) {
512
+ observe2 (...args) {
513
513
  return this._observe(
514
514
  {
515
- timeout: 2 * 60e3,
515
+ timeout: 2 * 60e3
516
516
  },
517
- ...args,
517
+ ...args
518
518
  )
519
519
  }
520
520
 
@@ -522,7 +522,7 @@ class RecordHandler {
522
522
  * @returns {rxjs.Observable}
523
523
  */
524
524
  // TODO (perf): Avoid rest parameters.
525
- _observe(defaults, name, ...args) {
525
+ _observe (defaults, name, ...args) {
526
526
  let path
527
527
  let state = defaults ? defaults.state : undefined
528
528
  let signal
@@ -585,7 +585,7 @@ class RecordHandler {
585
585
  timeout: null,
586
586
  /** @type {Record?} */ record: null,
587
587
  /** @type {Function?} */ abort: null,
588
- unsubscribe() {
588
+ unsubscribe () {
589
589
  if (this.timeout) {
590
590
  timers.clearTimeout(this.timeout)
591
591
  this.timeout = null
@@ -602,7 +602,7 @@ class RecordHandler {
602
602
  this.record.unref()
603
603
  this.record = null
604
604
  }
605
- },
605
+ }
606
606
  }
607
607
 
608
608
  const record = (subscription.record = this.getRecord(name).subscribe(onUpdate, subscription))
@@ -626,7 +626,7 @@ class RecordHandler {
626
626
  })
627
627
  }
628
628
 
629
- _$handle(message) {
629
+ _$handle (message) {
630
630
  let name
631
631
  if (message.action === C.ACTIONS.ERROR) {
632
632
  name = message.data[1]
@@ -652,7 +652,7 @@ class RecordHandler {
652
652
  return false
653
653
  }
654
654
 
655
- _onConnectionStateChange(connected) {
655
+ _onConnectionStateChange (connected) {
656
656
  for (const listener of this._listeners.values()) {
657
657
  listener._$onConnectionStateChange(connected)
658
658
  }
@@ -1,7 +1,7 @@
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 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'
@@ -28,11 +28,6 @@ class Record {
28
28
  this._subscribed = false
29
29
  }
30
30
 
31
- /** @type {bigint} */
32
- get key() {
33
- return this._key
34
- }
35
-
36
31
  /** @type {string} */
37
32
  get name() {
38
33
  return this._name
@@ -434,8 +429,8 @@ class Record {
434
429
  this._state = this._version.charAt(0) === 'I' ? C.RECORD_STATE.STALE : C.RECORD_STATE.SERVER
435
430
  }
436
431
 
437
- if (hasProvider != null) {
438
- this._state = convertTyped(hasProvider, this._handler._client)
432
+ if (hasProvider) {
433
+ this._state = messageParser.convertTyped(hasProvider, this._handler._client)
439
434
  ? C.RECORD_STATE.PROVIDER
440
435
  : this._version.charAt(0) === 'I'
441
436
  ? C.RECORD_STATE.STALE
@@ -483,7 +478,7 @@ class Record {
483
478
  const prevState = this._state
484
479
 
485
480
  this._state =
486
- hasProvider && convertTyped(hasProvider, this._handler._client)
481
+ hasProvider && messageParser.convertTyped(hasProvider, this._handler._client)
487
482
  ? C.RECORD_STATE.PROVIDER
488
483
  : this._version.charAt(0) === 'I'
489
484
  ? 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 messageParser from '../message/message-parser.js'
4
4
  import * as messageBuilder from '../message/message-builder.js'
5
5
  import xuid from 'xuid'
6
6
 
@@ -20,19 +20,19 @@ const RpcHandler = function (options, connection, client) {
20
20
  }
21
21
 
22
22
  Object.defineProperty(RpcHandler.prototype, 'connected', {
23
- get: function connected() {
23
+ get: function connected () {
24
24
  return this._client.getConnectionState() === C.CONNECTION_STATE.OPEN
25
- },
25
+ }
26
26
  })
27
27
 
28
28
  Object.defineProperty(RpcHandler.prototype, 'stats', {
29
- get: function stats() {
29
+ get: function stats () {
30
30
  return {
31
31
  ...this._stats,
32
32
  listeners: this._providers.size,
33
- rpcs: this._rpcs.size,
33
+ rpcs: this._rpcs.size
34
34
  }
35
- },
35
+ }
36
36
  })
37
37
 
38
38
  RpcHandler.prototype.provide = function (name, callback) {
@@ -95,7 +95,7 @@ RpcHandler.prototype.make = function (name, data, callback) {
95
95
  id,
96
96
  name,
97
97
  data,
98
- callback,
98
+ callback
99
99
  })
100
100
  this._connection.sendMsg(C.TOPIC.RPC, C.ACTIONS.REQUEST, [name, id, messageBuilder.typed(data)])
101
101
 
@@ -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
  }
@@ -152,11 +152,11 @@ RpcHandler.prototype._$handle = function (message) {
152
152
  Object.assign(new Error(data), {
153
153
  rpcId: rpc.id,
154
154
  rpcName: rpc.name,
155
- rpcData: rpc.data,
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
  }
@@ -27,7 +27,7 @@ RpcResponse.prototype.error = function (error) {
27
27
  this._name,
28
28
  this._id,
29
29
  error.message || error,
30
- true,
30
+ true
31
31
  ])
32
32
  }
33
33
 
@@ -40,7 +40,7 @@ RpcResponse.prototype.send = function (data) {
40
40
  this._connection.sendMsg(C.TOPIC.RPC, C.ACTIONS.RESPONSE, [
41
41
  this._name,
42
42
  this._id,
43
- messageBuilder.typed(data),
43
+ messageBuilder.typed(data)
44
44
  ])
45
45
  }
46
46
 
@@ -51,27 +51,27 @@ const kMask = kSize - 1
51
51
  // but allows much quicker checks.
52
52
 
53
53
  class FixedCircularBuffer {
54
- constructor() {
54
+ constructor () {
55
55
  this.bottom = 0
56
56
  this.top = 0
57
57
  this.list = new Array(kSize)
58
58
  this.next = null
59
59
  }
60
60
 
61
- isEmpty() {
61
+ isEmpty () {
62
62
  return this.top === this.bottom
63
63
  }
64
64
 
65
- isFull() {
65
+ isFull () {
66
66
  return ((this.top + 1) & kMask) === this.bottom
67
67
  }
68
68
 
69
- push(data) {
69
+ push (data) {
70
70
  this.list[this.top] = data
71
71
  this.top = (this.top + 1) & kMask
72
72
  }
73
73
 
74
- shift() {
74
+ shift () {
75
75
  const nextItem = this.list[this.bottom]
76
76
  if (nextItem === undefined) return null
77
77
  this.list[this.bottom] = undefined
@@ -81,15 +81,15 @@ class FixedCircularBuffer {
81
81
  }
82
82
 
83
83
  export default class FixedQueue {
84
- constructor() {
84
+ constructor () {
85
85
  this.head = this.tail = new FixedCircularBuffer()
86
86
  }
87
87
 
88
- isEmpty() {
88
+ isEmpty () {
89
89
  return this.head.isEmpty()
90
90
  }
91
91
 
92
- push(data) {
92
+ push (data) {
93
93
  if (this.head.isFull()) {
94
94
  // Head is full: Creates a new queue, sets the old queue's `.next` to it,
95
95
  // and sets it as the new main queue.
@@ -98,7 +98,7 @@ export default class FixedQueue {
98
98
  this.head.push(data)
99
99
  }
100
100
 
101
- shift() {
101
+ shift () {
102
102
  const tail = this.tail
103
103
  const next = tail.shift()
104
104
  if (tail.isEmpty() && tail.next !== null) {
@@ -2,7 +2,7 @@ import * as C from '../constants/constants.js'
2
2
  import rxjs from 'rxjs'
3
3
 
4
4
  class Listener {
5
- constructor(topic, pattern, callback, handler, { recursive = false, stringify = null } = {}) {
5
+ constructor (topic, pattern, callback, handler, { recursive = false, stringify = null } = {}) {
6
6
  this._topic = topic
7
7
  this._pattern = pattern
8
8
  this._callback = callback
@@ -13,20 +13,20 @@ class Listener {
13
13
  this._recursive = recursive
14
14
  this._stringify = stringify || JSON.stringify
15
15
 
16
- this._connection.sendMsg(this._topic, C.ACTIONS.LISTEN, [this._pattern])
16
+ this._$onConnectionStateChange()
17
17
  }
18
18
 
19
- get connected() {
19
+ get connected () {
20
20
  return this._connection.connected
21
21
  }
22
22
 
23
- get stats() {
23
+ get stats () {
24
24
  return {
25
- subscriptions: this._subscriptions.size,
25
+ subscriptions: this._subscriptions.size
26
26
  }
27
27
  }
28
28
 
29
- _$destroy() {
29
+ _$destroy () {
30
30
  this._reset()
31
31
 
32
32
  if (this.connected) {
@@ -34,13 +34,13 @@ class Listener {
34
34
  }
35
35
  }
36
36
 
37
- _$onMessage(message) {
37
+ _$onMessage (message) {
38
38
  if (!this.connected) {
39
39
  this._client._$onError(
40
40
  C.TOPIC.RECORD,
41
41
  C.EVENT.NOT_CONNECTED,
42
42
  new Error('received message while not connected'),
43
- message,
43
+ message
44
44
  )
45
45
  return
46
46
  }
@@ -63,13 +63,13 @@ class Listener {
63
63
  version: null,
64
64
  timeout: null,
65
65
  patternSubscription: null,
66
- valueSubscription: null,
66
+ valueSubscription: null
67
67
  }
68
68
  provider.stop = () => {
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.key
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.key]
106
106
  )
107
107
 
108
108
  provider.version = null
@@ -160,12 +160,12 @@ class Listener {
160
160
  this._connection.sendMsg(C.TOPIC.RECORD, C.ACTIONS.UPDATE, [
161
161
  provider.key,
162
162
  version,
163
- body,
163
+ body
164
164
  ])
165
165
  }
166
166
  }
167
167
  },
168
- error: provider.error,
168
+ error: provider.error
169
169
  }
170
170
  provider.start = () => {
171
171
  try {
@@ -211,7 +211,7 @@ class Listener {
211
211
  return true
212
212
  }
213
213
 
214
- _$onConnectionStateChange() {
214
+ _$onConnectionStateChange () {
215
215
  if (this.connected) {
216
216
  this._connection.sendMsg(this._topic, C.ACTIONS.LISTEN, [this._pattern])
217
217
  } else {
@@ -219,15 +219,11 @@ class Listener {
219
219
  }
220
220
  }
221
221
 
222
- _error(name, err) {
223
- this._client._$onError(this._topic, C.EVENT.LISTENER_ERROR, err, [
224
- this._pattern,
225
- name,
226
- this._handler.getKey(name).toString(),
227
- ])
222
+ _error (name, err) {
223
+ this._client._$onError(this._topic, C.EVENT.LISTENER_ERROR, err, [this._pattern, name])
228
224
  }
229
225
 
230
- _reset() {
226
+ _reset () {
231
227
  for (const provider of this._subscriptions.values()) {
232
228
  provider.stop()
233
229
  }
@@ -3,7 +3,7 @@ let fastNowTimeout
3
3
 
4
4
  const fastTimers = []
5
5
 
6
- function onTimeout() {
6
+ function onTimeout () {
7
7
  fastNow = Date.now()
8
8
 
9
9
  let len = fastTimers.length
@@ -36,7 +36,7 @@ function onTimeout() {
36
36
  }
37
37
  }
38
38
 
39
- function refreshTimeout() {
39
+ function refreshTimeout () {
40
40
  if (fastNowTimeout && fastNowTimeout.refresh) {
41
41
  fastNowTimeout.refresh()
42
42
  } else {
@@ -49,7 +49,7 @@ function refreshTimeout() {
49
49
  }
50
50
 
51
51
  class Timeout {
52
- constructor(callback, delay, opaque) {
52
+ constructor (callback, delay, opaque) {
53
53
  this.callback = callback
54
54
  this.delay = delay
55
55
  this.opaque = opaque
@@ -63,7 +63,7 @@ class Timeout {
63
63
  this.refresh()
64
64
  }
65
65
 
66
- refresh() {
66
+ refresh () {
67
67
  if (this.state === -2) {
68
68
  fastTimers.push(this)
69
69
  if (!fastNowTimeout || fastTimers.length === 1) {
@@ -74,18 +74,18 @@ class Timeout {
74
74
  this.state = 0
75
75
  }
76
76
 
77
- clear() {
77
+ clear () {
78
78
  this.state = -1
79
79
  }
80
80
  }
81
81
 
82
- export function setTimeout(callback, delay, opaque) {
82
+ export function setTimeout (callback, delay, opaque) {
83
83
  return delay < 1e3
84
84
  ? globalThis.setTimeout(callback, delay, opaque)
85
85
  : new Timeout(callback, delay, opaque)
86
86
  }
87
87
 
88
- export function clearTimeout(timeout) {
88
+ export function clearTimeout (timeout) {
89
89
  if (timeout instanceof Timeout) {
90
90
  timeout.clear()
91
91
  } else {
@@ -18,11 +18,11 @@ const PIPE = rxjs.pipe(
18
18
 
19
19
  return data
20
20
  }),
21
- rx.distinctUntilChanged(),
21
+ rx.distinctUntilChanged()
22
22
  )
23
23
 
24
24
  class Listener {
25
- constructor(topic, pattern, callback, handler, opts) {
25
+ constructor (topic, pattern, callback, handler, opts) {
26
26
  if (opts.recursive) {
27
27
  throw new Error('invalid argument: recursive')
28
28
  }
@@ -42,17 +42,17 @@ class Listener {
42
42
  this._connection.sendMsg(this._topic, C.ACTIONS.LISTEN, [this._pattern, 'U'])
43
43
  }
44
44
 
45
- get stats() {
45
+ get stats () {
46
46
  return {
47
- subscriptions: this._subscriptions.size,
47
+ subscriptions: this._subscriptions.size
48
48
  }
49
49
  }
50
50
 
51
- _$destroy() {
51
+ _$destroy () {
52
52
  this._reset()
53
53
  }
54
54
 
55
- _$onMessage(message) {
55
+ _$onMessage (message) {
56
56
  const name = message.data[1]
57
57
 
58
58
  if (message.action === C.ACTIONS.LISTEN_ACCEPT) {
@@ -86,7 +86,7 @@ class Listener {
86
86
  this._error(name, err)
87
87
  this._connection.sendMsg(this._topic, C.ACTIONS.LISTEN_REJECT, [this._pattern, key])
88
88
  this._subscriptions.delete(name)
89
- },
89
+ }
90
90
  })
91
91
  this._subscriptions.set(name, subscription)
92
92
  } else {
@@ -107,7 +107,7 @@ class Listener {
107
107
  return true
108
108
  }
109
109
 
110
- _$onConnectionStateChange(connected) {
110
+ _$onConnectionStateChange (connected) {
111
111
  if (connected) {
112
112
  this._connection.sendMsg(this._topic, C.ACTIONS.LISTEN, [this._pattern, 'U'])
113
113
  } else {
@@ -115,15 +115,11 @@ class Listener {
115
115
  }
116
116
  }
117
117
 
118
- _error(name, err) {
119
- this._client._$onError(this._topic, C.EVENT.LISTENER_ERROR, err, [
120
- this._pattern,
121
- name,
122
- this._handler.getKey(name).toString(),
123
- ])
118
+ _error (name, err) {
119
+ this._client._$onError(this._topic, C.EVENT.LISTENER_ERROR, err, [this._pattern, name])
124
120
  }
125
121
 
126
- _reset() {
122
+ _reset () {
127
123
  for (const subscription of this._subscriptions.values()) {
128
124
  subscription.unsubscribe()
129
125
  }
@@ -2,7 +2,7 @@ const NODE_ENV = typeof process !== 'undefined' && process.env && process.env.NO
2
2
  export const isNode = typeof process !== 'undefined' && process.toString() === '[object process]'
3
3
  export const isProduction = NODE_ENV === 'production'
4
4
 
5
- export function deepFreeze(o) {
5
+ export function deepFreeze (o) {
6
6
  if (isProduction) {
7
7
  return o
8
8
  }
@@ -18,7 +18,7 @@ export function deepFreeze(o) {
18
18
  return o
19
19
  }
20
20
 
21
- export function splitRev(s) {
21
+ export function splitRev (s) {
22
22
  if (!s) {
23
23
  return [-1, '00000000000000']
24
24
  }
@@ -29,7 +29,7 @@ export function splitRev(s) {
29
29
  return [ver.charAt(0) === 'I' ? Infinity : parseInt(ver, 10), s.slice(i + 1)]
30
30
  }
31
31
 
32
- export function isPlainObject(value, isPlainJSON) {
32
+ export function isPlainObject (value, isPlainJSON) {
33
33
  if (isPlainJSON) {
34
34
  return value && typeof value === 'object' && !Array.isArray(value)
35
35
  }
@@ -50,13 +50,13 @@ export function isPlainObject(value, isPlainJSON) {
50
50
  return Object.getPrototypeOf(value) === proto
51
51
  }
52
52
 
53
- export function isSameOrNewer(a, b) {
53
+ export function isSameOrNewer (a, b) {
54
54
  const [av, ar] = splitRev(a)
55
55
  const [bv, br] = splitRev(b)
56
56
  return av > bv || (av === bv && ar >= br)
57
57
  }
58
58
 
59
- export function shallowCopy(obj) {
59
+ export function shallowCopy (obj) {
60
60
  if (Array.isArray(obj)) {
61
61
  return obj.slice(0)
62
62
  }
@@ -69,7 +69,7 @@ export function shallowCopy(obj) {
69
69
  return copy
70
70
  }
71
71
 
72
- export function setTimeout(callback, timeoutDuration) {
72
+ export function setTimeout (callback, timeoutDuration) {
73
73
  if (timeoutDuration !== null) {
74
74
  return globalThis.setTimeout(callback, timeoutDuration)
75
75
  } else {
@@ -77,7 +77,7 @@ export function setTimeout(callback, timeoutDuration) {
77
77
  }
78
78
  }
79
79
 
80
- export function setInterval(callback, intervalDuration) {
80
+ export function setInterval (callback, intervalDuration) {
81
81
  if (intervalDuration !== null) {
82
82
  return setInterval(callback, intervalDuration)
83
83
  } else {
@@ -85,7 +85,7 @@ export function setInterval(callback, intervalDuration) {
85
85
  }
86
86
  }
87
87
 
88
- export function compareRev(a, b) {
88
+ export function compareRev (a, b) {
89
89
  if (!a) {
90
90
  return b ? -1 : 0
91
91
  }
@@ -116,14 +116,14 @@ export function compareRev(a, b) {
116
116
  }
117
117
 
118
118
  export class AbortError extends Error {
119
- constructor() {
119
+ constructor () {
120
120
  super('The operation was aborted')
121
121
  this.code = 'ABORT_ERR'
122
122
  this.name = 'AbortError'
123
123
  }
124
124
  }
125
125
 
126
- function defaultSchedule(fn) {
126
+ function defaultSchedule (fn) {
127
127
  setTimeout(fn, 0)
128
128
  }
129
129
 
@@ -139,7 +139,7 @@ const onAbort = function () {
139
139
  }
140
140
  }
141
141
 
142
- export function addAbortListener(signal, handler) {
142
+ export function addAbortListener (signal, handler) {
143
143
  if (!signal) {
144
144
  return
145
145
  }
@@ -157,7 +157,7 @@ export function addAbortListener(signal, handler) {
157
157
  }
158
158
  }
159
159
 
160
- export function removeAbortListener(signal, handler) {
160
+ export function removeAbortListener (signal, handler) {
161
161
  if (!signal) {
162
162
  return
163
163
  }
@@ -175,7 +175,7 @@ export function removeAbortListener(signal, handler) {
175
175
  }
176
176
  }
177
177
 
178
- export function readBigUInt64BE(buf, offset = 0) {
178
+ export function readBigUInt64BE (buf, offset = 0) {
179
179
  const first = buf[offset]
180
180
  const last = buf[offset + 7]
181
181