@nxtedition/deepstream.io-client-js 32.0.18 → 32.0.19

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": "32.0.18",
3
+ "version": "32.0.19",
4
4
  "description": "the javascript client for deepstream.io",
5
5
  "homepage": "http://deepstream.io",
6
6
  "type": "module",
@@ -1,7 +1,7 @@
1
1
  import * as C from '../constants/constants.js'
2
2
  import * as messageBuilder from '../message/message-builder.js'
3
3
  import * as messageParser from '../message/message-parser.js'
4
- import LegacyListener from '../utils/legacy-listener.js'
4
+ import MulticastListener from '../utils/multicast-listener.js'
5
5
  import UnicastListener from '../utils/unicast-listener.js'
6
6
  import EventEmitter from 'component-emitter2'
7
7
  import * as rxjs from 'rxjs'
@@ -78,7 +78,7 @@ EventHandler.on = function (name, callback) {
78
78
 
79
79
  EventHandler.once = function (name, callback) {
80
80
  const fn = (...args) => {
81
- this.unsubscribe(fn)
81
+ this.unsubscribe(name, fn)
82
82
  callback(...args)
83
83
  }
84
84
  this.subscribe(name, fn)
@@ -126,7 +126,7 @@ EventHandler.prototype.provide = function (pattern, callback, options) {
126
126
  const listener =
127
127
  options.mode?.toLowerCase() === 'unicast'
128
128
  ? new UnicastListener(C.TOPIC.EVENT, pattern, callback, this, options)
129
- : new LegacyListener(C.TOPIC.EVENT, pattern, callback, this, options)
129
+ : new MulticastListener(C.TOPIC.EVENT, pattern, callback, this, options)
130
130
 
131
131
  this._listeners.set(pattern, listener)
132
132
  return () => {
@@ -1,5 +1,5 @@
1
1
  import Record from './record.js'
2
- import LegacyListener from '../utils/legacy-listener.js'
2
+ import MulticastListener from '../utils/multicast-listener.js'
3
3
  import UnicastListener from '../utils/unicast-listener.js'
4
4
  import * as C from '../constants/constants.js'
5
5
  import * as rxjs from 'rxjs'
@@ -35,7 +35,7 @@ const GET2_DEFAULTS = {
35
35
 
36
36
  function onSync(subscription) {
37
37
  subscription.synced = true
38
- onUpdate(null, subscription)
38
+ onUpdate(subscription.record, subscription)
39
39
  }
40
40
 
41
41
  function onUpdate(record, subscription) {
@@ -84,18 +84,9 @@ function onTimeout(subscription) {
84
84
 
85
85
  subscription.subscriber.error(
86
86
  Object.assign(
87
- new Error(
88
- !subscription.synced
89
- ? `timeout sync: ${subscription.record.name}`
90
- : `timeout state: ${subscription.record.name} [${current}<${expected}]`,
91
- ),
87
+ new Error(`timeout state: ${subscription.record.name} [${current}<${expected}]`),
92
88
  {
93
89
  code: 'ETIMEDOUT',
94
- timeout: subscription.timeoutValue,
95
- expected,
96
- current,
97
- synced: subscription.synced,
98
- name: subscription.record.name,
99
90
  },
100
91
  ),
101
92
  )
@@ -128,7 +119,7 @@ class RecordHandler {
128
119
  }
129
120
 
130
121
  this._syncQueue = []
131
- this._syncMap = new Map()
122
+ this._syncMap = {}
132
123
 
133
124
  this.set = this.set.bind(this)
134
125
  this.get = this.get.bind(this)
@@ -228,18 +219,13 @@ class RecordHandler {
228
219
  * @returns {Record}
229
220
  */
230
221
  getRecord(name) {
231
- if (typeof name !== 'string' || name.length === 0) {
232
- throw new Error('invalid argument: name')
233
- }
234
-
235
- if (name.startsWith('null') || name.startsWith('undefined') || name === '[object Object]') {
236
- this._client._$onError(
237
- C.TOPIC.RECORD,
238
- C.EVENT.USER_ERROR,
239
- 'name should not start with null or undefined',
240
- name,
241
- )
242
- }
222
+ invariant(
223
+ typeof name === 'string' &&
224
+ name.length > 0 &&
225
+ name !== '[object Object]' &&
226
+ name.length <= 4096,
227
+ `invalid name ${name}`,
228
+ )
243
229
 
244
230
  let record = this._records.get(name)
245
231
 
@@ -275,7 +261,7 @@ class RecordHandler {
275
261
  const listener =
276
262
  options.mode?.toLowerCase() === 'unicast'
277
263
  ? new UnicastListener(C.TOPIC.RECORD, pattern, callback, this, options)
278
- : new LegacyListener(C.TOPIC.RECORD, pattern, callback, this, options)
264
+ : new MulticastListener(C.TOPIC.RECORD, pattern, callback, this, options)
279
265
 
280
266
  this._stats.listeners += 1
281
267
  this._listeners.set(pattern, listener)
@@ -296,7 +282,7 @@ class RecordHandler {
296
282
  // TODO (perf): Slow implementation...
297
283
 
298
284
  const signal = opts?.signal
299
- const timeout = opts?.timeout ?? 10 * 60e3
285
+ const timeout = opts?.timeout
300
286
 
301
287
  let disposers
302
288
  try {
@@ -312,17 +298,18 @@ class RecordHandler {
312
298
  signalPromise?.catch(noop)
313
299
 
314
300
  if (this._patching.size) {
315
- const promises = []
301
+ let promises
316
302
 
317
303
  {
318
304
  const patchingPromises = []
319
305
  for (const callbacks of this._patching.values()) {
320
306
  patchingPromises.push(new Promise((resolve) => callbacks.push(resolve)))
321
307
  }
308
+ promises ??= []
322
309
  promises.push(Promise.all(patchingPromises))
323
310
  }
324
311
 
325
- if (timeout && promises.length) {
312
+ if (timeout) {
326
313
  promises.push(
327
314
  new Promise((resolve) => {
328
315
  const patchingTimeout = timers.setTimeout(() => {
@@ -339,28 +326,30 @@ class RecordHandler {
339
326
  )
340
327
  }
341
328
 
342
- if (signalPromise && promises.length) {
329
+ if (signalPromise) {
330
+ promises ??= []
343
331
  promises.push(signalPromise)
344
332
  }
345
333
 
346
- if (promises.length) {
334
+ if (promises) {
347
335
  await Promise.race(promises)
348
- signal?.throwIfAborted()
349
336
  }
350
337
  }
351
338
 
352
339
  if (this._updating.size) {
353
- const promises = []
340
+ let promises
354
341
 
355
342
  {
356
343
  const updatingPromises = []
357
344
  for (const callbacks of this._updating.values()) {
358
345
  updatingPromises.push(new Promise((resolve) => callbacks.push(resolve)))
359
346
  }
347
+ promises ??= []
360
348
  promises.push(Promise.all(updatingPromises))
361
349
  }
362
350
 
363
- if (timeout && promises.length) {
351
+ if (timeout) {
352
+ promises ??= []
364
353
  promises.push(
365
354
  new Promise((resolve) => {
366
355
  const updatingTimeout = timers.setTimeout(() => {
@@ -377,22 +366,18 @@ class RecordHandler {
377
366
  )
378
367
  }
379
368
 
380
- if (signalPromise && promises.length) {
381
- promises.push(signalPromise)
382
- }
383
-
384
- if (promises.length) {
369
+ if (promises) {
385
370
  await Promise.race(promises)
386
- signal?.throwIfAborted()
387
371
  }
388
372
  }
389
373
 
390
374
  {
391
- const promises = []
375
+ const syncPromise = new Promise((resolve) => this._sync(resolve))
392
376
 
393
- promises.push(new Promise((resolve) => this._sync(resolve)))
377
+ let promises
394
378
 
395
379
  if (timeout) {
380
+ promises ??= []
396
381
  promises.push(
397
382
  new Promise((resolve, reject) => {
398
383
  const serverTimeout = timers.setTimeout(() => {
@@ -405,12 +390,15 @@ class RecordHandler {
405
390
  }
406
391
 
407
392
  if (signalPromise) {
393
+ promises ??= []
408
394
  promises.push(signalPromise)
409
395
  }
410
396
 
411
- if (promises.length) {
397
+ if (promises) {
398
+ promises.push(syncPromise)
412
399
  await Promise.race(promises)
413
- signal?.throwIfAborted()
400
+ } else {
401
+ await syncPromise
414
402
  }
415
403
  }
416
404
  } finally {
@@ -566,78 +554,78 @@ class RecordHandler {
566
554
  * @returns {rxjs.Observable}
567
555
  */
568
556
  _observe(defaults, name, ...args) {
569
- let path
570
- let state = defaults?.state ?? C.RECORD_STATE.CLIENT
571
- let signal = null
572
- let timeout = defaults?.timeout ?? 0
573
- let dataOnly = defaults?.dataOnly ?? false
574
- let sync = defaults?.sync ?? false
557
+ return new rxjs.Observable((subscriber) => {
558
+ let path
559
+ let state = defaults?.state ?? C.RECORD_STATE.CLIENT
560
+ let signal = null
561
+ let timeout = defaults?.timeout ?? 0
562
+ let dataOnly = defaults?.dataOnly ?? false
563
+ let sync = defaults?.sync ?? false
564
+
565
+ let idx = 0
566
+
567
+ if (
568
+ idx < args.length &&
569
+ (args[idx] == null ||
570
+ typeof args[idx] === 'string' ||
571
+ Array.isArray(args[idx]) ||
572
+ typeof args[idx] === 'function')
573
+ ) {
574
+ path = args[idx++]
575
+ }
575
576
 
576
- let idx = 0
577
+ if (idx < args.length && (args[idx] == null || typeof args[idx] === 'number')) {
578
+ state = args[idx++]
579
+ }
577
580
 
578
- if (
579
- idx < args.length &&
580
- (args[idx] == null ||
581
- typeof args[idx] === 'string' ||
582
- Array.isArray(args[idx]) ||
583
- typeof args[idx] === 'function')
584
- ) {
585
- path = args[idx++]
586
- }
581
+ if (idx < args.length && (args[idx] == null || typeof args[idx] === 'object')) {
582
+ const options = args[idx++] || {}
587
583
 
588
- if (idx < args.length && (args[idx] == null || typeof args[idx] === 'number')) {
589
- state = args[idx++]
590
- }
584
+ if (options.signal !== undefined) {
585
+ signal = options.signal
586
+ }
591
587
 
592
- if (idx < args.length && (args[idx] == null || typeof args[idx] === 'object')) {
593
- const options = args[idx++] || {}
588
+ if (options.timeout !== undefined) {
589
+ timeout = options.timeout
590
+ }
594
591
 
595
- if (options.signal !== undefined) {
596
- signal = options.signal
597
- }
592
+ if (options.path !== undefined) {
593
+ path = options.path
594
+ }
598
595
 
599
- if (options.timeout !== undefined) {
600
- timeout = options.timeout
601
- }
596
+ if (options.state !== undefined) {
597
+ state = options.state
598
+ }
602
599
 
603
- if (options.path !== undefined) {
604
- path = options.path
605
- }
600
+ if (options.dataOnly !== undefined) {
601
+ dataOnly = options.dataOnly
602
+ }
606
603
 
607
- if (options.state !== undefined) {
608
- state = options.state
604
+ if (options.sync !== undefined) {
605
+ sync = options.sync
606
+ }
609
607
  }
610
608
 
611
- if (options.dataOnly !== undefined) {
612
- dataOnly = options.dataOnly
609
+ if (typeof state === 'string') {
610
+ state = C.RECORD_STATE[state.toUpperCase()]
613
611
  }
614
612
 
615
- if (options.sync !== undefined) {
616
- sync = options.sync
613
+ if (!Number.isInteger(state) || state < 0) {
614
+ throw new Error('invalid argument: state')
617
615
  }
618
- }
619
616
 
620
- if (typeof state === 'string') {
621
- state = C.RECORD_STATE[state.toUpperCase()]
622
- }
623
-
624
- if (!Number.isInteger(state) || state < 0) {
625
- throw new Error('invalid argument: state')
626
- }
627
-
628
- if (!Number.isInteger(timeout) || timeout < 0) {
629
- throw new Error('invalid argument: timeout')
630
- }
617
+ if (!Number.isInteger(timeout) || timeout < 0) {
618
+ throw new Error('invalid argument: timeout')
619
+ }
631
620
 
632
- if (typeof dataOnly !== 'boolean') {
633
- throw new Error('invalid argument: dataOnly')
634
- }
621
+ if (typeof dataOnly !== 'boolean') {
622
+ throw new Error('invalid argument: dataOnly')
623
+ }
635
624
 
636
- if (typeof sync !== 'boolean') {
637
- throw new Error('invalid argument: sync')
638
- }
625
+ if (typeof sync !== 'boolean') {
626
+ throw new Error('invalid argument: sync')
627
+ }
639
628
 
640
- return new rxjs.Observable((subscriber) => {
641
629
  // TODO (perf): Make a class
642
630
  const subscription = {
643
631
  /** @readonly @type {unknown} */
@@ -663,9 +651,6 @@ class RecordHandler {
663
651
  data: kEmpty,
664
652
  /** @type {boolean} */
665
653
  synced: false,
666
-
667
- index: -1,
668
- onUpdate,
669
654
  }
670
655
 
671
656
  subscriber.add(() => {
@@ -681,7 +666,7 @@ class RecordHandler {
681
666
  }
682
667
 
683
668
  if (subscription.record) {
684
- subscription.record._unobserve(subscription)
669
+ subscription.record.unsubscribe(onUpdate, subscription)
685
670
  subscription.record.unref()
686
671
  subscription.record = null
687
672
  }
@@ -692,11 +677,11 @@ class RecordHandler {
692
677
  utils.addAbortListener(subscription.signal, subscription.abort)
693
678
  }
694
679
 
695
- subscription.record = this.getRecord(name)
696
- subscription.record._observe(subscription)
680
+ subscription.record = this.getRecord(name).subscribe(onUpdate, subscription)
697
681
 
698
682
  if (sync) {
699
- this._sync(onSync, sync, subscription)
683
+ // TODO (fix): What about sync timeout?
684
+ this._sync(onSync, sync === true ? 'WEAK' : sync, subscription)
700
685
  } else {
701
686
  onSync(subscription)
702
687
  }
@@ -717,8 +702,8 @@ class RecordHandler {
717
702
  return true
718
703
  }
719
704
 
720
- const sync = this._syncMap.get(token)
721
- this._syncMap.delete(token)
705
+ const sync = this._syncMap[token]
706
+ delete this._syncMap[token]
722
707
 
723
708
  if (!sync) {
724
709
  return true
@@ -761,10 +746,10 @@ class RecordHandler {
761
746
  this._connection.sendMsg(C.TOPIC.RECORD, C.ACTIONS.PUT, update)
762
747
  }
763
748
 
764
- const syncMap = new Map()
765
- for (const sync of this._syncMap.values()) {
749
+ const syncMap = {}
750
+ for (const sync of Object.values(this._syncMap)) {
766
751
  const token = xuid()
767
- syncMap.set(token, sync)
752
+ syncMap[token] = sync
768
753
  this._connection.sendMsg(
769
754
  C.TOPIC.RECORD,
770
755
  C.ACTIONS.SYNC,
@@ -799,7 +784,7 @@ class RecordHandler {
799
784
  const token = xuid()
800
785
  const queue = this._syncQueue.splice(0)
801
786
 
802
- this._syncMap.set(token, { queue, type })
787
+ this._syncMap[token] = { queue, type }
803
788
  this._connection.sendMsg(C.TOPIC.RECORD, C.ACTIONS.SYNC, type ? [token, type] : [token])
804
789
  }, 1)
805
790
  }
@@ -20,13 +20,7 @@ class Record {
20
20
  this._state = C.RECORD_STATE.VOID
21
21
  this._refs = 0
22
22
  this._subscriptions = []
23
-
24
- /** @type {Array|null} */
25
- this._emittingArr = null
26
- /** @type {number} */
27
- this._emittingIndex = -1
28
-
29
- this._observers = []
23
+ this._emitting = false
30
24
 
31
25
  /** @type Map? */ this._updating = null
32
26
  /** @type Array? */ this._patching = null
@@ -94,8 +88,9 @@ class Record {
94
88
  * @returns {Record}
95
89
  */
96
90
  subscribe(fn, opaque = null) {
97
- if (this._emittingArr == this._subscriptions) {
91
+ if (this._emitting) {
98
92
  this._subscriptions = this._subscriptions.slice()
93
+ this._emitting = false
99
94
  }
100
95
 
101
96
  this._subscriptions.push(fn, opaque)
@@ -110,8 +105,9 @@ class Record {
110
105
  * @returns {Record}
111
106
  */
112
107
  unsubscribe(fn, opaque = null) {
113
- if (this._emittingArr == this._subscriptions) {
108
+ if (this._emitting) {
114
109
  this._subscriptions = this._subscriptions.slice()
110
+ this._emitting = false
115
111
  }
116
112
 
117
113
  let idx = -1
@@ -132,41 +128,6 @@ class Record {
132
128
  return this
133
129
  }
134
130
 
135
- /**
136
- * @note Subscribers are unordered.
137
- * @param {{ index: number, onUpdate: (Record) => void}} subscription
138
- */
139
- _observe(subscription) {
140
- if (subscription.index != null && subscription.index !== -1) {
141
- throw new Error('already observing')
142
- }
143
-
144
- subscription.index = this._observers.push(subscription) - 1
145
- }
146
-
147
- /**
148
- * @param {{ index: number, onUpdate: (Record) => void}} subscription
149
- */
150
- _unobserve(subscription) {
151
- if (subscription.index == null || subscription.index === -1) {
152
- throw new Error('not observing')
153
- }
154
-
155
- if (this._emittingArr === this._observers) {
156
- // TODO (perf): Shift from start if emitting?
157
- this._observers = this._observers.slice()
158
- }
159
-
160
- const idx = subscription.index
161
- const tmp = this._observers.pop()
162
- subscription.index = -1
163
-
164
- if (tmp !== subscription) {
165
- this._observers[idx] = tmp
166
- this._observers[idx].index = idx
167
- }
168
- }
169
-
170
131
  get(path) {
171
132
  if (!path) {
172
133
  return this._data
@@ -554,41 +515,18 @@ class Record {
554
515
  }
555
516
 
556
517
  _emitUpdate() {
557
- if (this._emittingArr != null) {
558
- throw new Error('cannot reenter emitUpdate')
559
- }
560
-
561
- try {
562
- const arr = this._subscriptions
563
- const len = arr.length
564
-
565
- this._emittingArr = arr
566
- for (let n = 0; n < len; n += 2) {
567
- this._emittingIndex = n
568
- // TODO (fix): What if this throws?
569
- arr[n + 0](this, arr[n + 1])
570
- }
571
- } finally {
572
- this._emittingArr = null
573
- this._emittingIndex = -1
574
- }
518
+ this._emitting = true
575
519
 
576
- try {
577
- const arr = this._observers
578
- const len = arr.length
520
+ const arr = this._subscriptions
521
+ const len = arr.length
579
522
 
580
- this._emittingArr = arr
581
- for (let n = 0; n < len; n++) {
582
- this._emittingIndex = n
583
- // TODO (fix): What if this throws?
584
- arr[n].onUpdate(this, arr[n])
585
- }
586
- } finally {
587
- this._emittingArr = null
588
- this._emittingIndex = -1
523
+ for (let n = 0; n < len; n += 2) {
524
+ arr[n + 0](this, arr[n + 1])
589
525
  }
590
526
 
591
527
  this._handler._client.emit('recordUpdated', this)
528
+
529
+ this._emitting = false
592
530
  }
593
531
  }
594
532
 
@@ -1,6 +1,6 @@
1
1
  import * as rxjs from 'rxjs'
2
2
  import * as C from '../constants/constants.js'
3
- import { h64ToString, findBigIntPaths } from './utils.js'
3
+ import { h64ToString, findBigIntPaths } from '../utils/utils.js'
4
4
 
5
5
  export default class Listener {
6
6
  constructor(topic, pattern, callback, handler, { recursive = false, stringify = null } = {}) {
@@ -3,8 +3,6 @@ import xxhash from 'xxhash-wasm'
3
3
  const NODE_ENV = typeof process !== 'undefined' && process.env && process.env.NODE_ENV
4
4
  const HASHER = await xxhash()
5
5
 
6
- // This is a hack to avoid top-level await
7
- // const HASHER = await xxhash()
8
6
  export const isNode = typeof process !== 'undefined' && process.toString() === '[object process]'
9
7
  export const isProduction = NODE_ENV === 'production'
10
8