@nxtedition/deepstream.io-client-js 27.0.2 → 28.0.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.
@@ -0,0 +1,80 @@
1
+ import eslint from '@eslint/js'
2
+ import tseslint from 'typescript-eslint'
3
+ import eslintConfigPrettier from 'eslint-config-prettier'
4
+ import eslintPluginImport from 'eslint-plugin-import'
5
+ import eslintPluginN from 'eslint-plugin-n'
6
+ import eslintPluginPromise from 'eslint-plugin-promise'
7
+ import typescriptEslintParser from '@typescript-eslint/parser'
8
+ import globals from 'globals'
9
+
10
+ const reactFiles = [
11
+ 'app/src/renderer/**/*{js,ts,tsx}',
12
+ 'hub/src/client/**/*.{js,ts,tsx}',
13
+ 'hub/.storybook/**/*.{js,ts,tsx}',
14
+ 'plugins/adobe/**/*{js,ts,tsx}',
15
+ ]
16
+
17
+ export default tseslint.config(
18
+ eslint.configs.recommended,
19
+ ...tseslint.configs.recommended,
20
+
21
+ {
22
+ ignores: [
23
+ 'tmp*',
24
+ 'benchmarks/**/*',
25
+ ],
26
+ },
27
+
28
+ // Base config:
29
+ {
30
+ plugins: {
31
+ import: eslintPluginImport,
32
+ promise: eslintPluginPromise,
33
+ },
34
+ languageOptions: {
35
+ parser: typescriptEslintParser,
36
+ parserOptions: {
37
+ tsconfigRootDir: import.meta.dirname,
38
+ },
39
+ },
40
+ rules: {
41
+ 'prefer-const': [
42
+ 'error',
43
+ {
44
+ destructuring: 'all',
45
+ },
46
+ ],
47
+ 'no-empty': ['error', { allowEmptyCatch: true }],
48
+ 'no-constant-condition': ['error', { checkLoops: false }],
49
+ '@typescript-eslint/no-unused-vars': [
50
+ 'error',
51
+ {
52
+ args: 'none',
53
+ ignoreRestSiblings: true,
54
+ },
55
+ ],
56
+ 'getter-return': 'off',
57
+ 'object-shorthand': ['warn', 'properties'],
58
+ },
59
+ },
60
+
61
+ // Node specific
62
+ {
63
+ ignores: [...reactFiles],
64
+ languageOptions: {
65
+ globals: {
66
+ ...globals.node,
67
+ },
68
+ },
69
+ plugins: {
70
+ n: eslintPluginN,
71
+ },
72
+ rules: {
73
+ 'no-redeclare': 'warn',
74
+ 'require-yield': 'off',
75
+ },
76
+ },
77
+
78
+ // Prettier:
79
+ eslintConfigPrettier
80
+ )
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxtedition/deepstream.io-client-js",
3
- "version": "27.0.2",
3
+ "version": "28.0.1",
4
4
  "description": "the javascript client for deepstream.io",
5
5
  "homepage": "http://deepstream.io",
6
6
  "type": "module",
@@ -33,31 +33,6 @@
33
33
  "semi": false,
34
34
  "singleQuote": true
35
35
  },
36
- "eslintConfig": {
37
- "parserOptions": {
38
- "ecmaFeatures": {
39
- "ecmaVersion": 2020
40
- }
41
- },
42
- "extends": [
43
- "standard",
44
- "prettier",
45
- "prettier/prettier"
46
- ],
47
- "rules": {
48
- "quotes": [
49
- "error",
50
- "single",
51
- {
52
- "avoidEscape": true,
53
- "allowTemplateLiterals": true
54
- }
55
- ]
56
- }
57
- },
58
- "eslintIgnore": [
59
- "/__tests__"
60
- ],
61
36
  "dependencies": {
62
37
  "@nxtedition/json-path": "^1.0.8",
63
38
  "bufferutil": "^4.0.8",
@@ -65,27 +40,26 @@
65
40
  "invariant": "^2.2.4",
66
41
  "lodash.clonedeep": "^4.5.0",
67
42
  "utf-8-validate": "^6.0.4",
68
- "varint": "^6.0.0",
69
43
  "ws": "^8.18.0",
70
44
  "xuid": "^4.1.3",
71
45
  "xxhash-wasm": "^1.0.2"
72
46
  },
73
47
  "devDependencies": {
74
- "@types/node": "^22.0.0",
75
- "eslint": "^8.0.0",
48
+ "eslint": "^9.9.0",
76
49
  "eslint-config-prettier": "^9.1.0",
77
50
  "eslint-config-standard": "^17.1.0",
78
51
  "eslint-plugin-import": "^2.29.1",
79
- "eslint-plugin-n": "^17.10.1",
52
+ "eslint-plugin-n": "^17.10.2",
80
53
  "eslint-plugin-node": "^11.1.0",
81
- "eslint-plugin-promise": "^7.0.0",
82
- "husky": "^9.1.3",
83
- "lint-staged": "^15.2.7",
54
+ "eslint-plugin-promise": "^7.1.0",
55
+ "husky": "^9.1.4",
56
+ "lint-staged": "^15.2.8",
84
57
  "mitata": "^0.1.11",
85
58
  "pinst": "^3.0.0",
86
59
  "prettier": "^3.3.3",
87
60
  "rxjs": "^7.8.1",
88
- "tinybench": "^2.8.0"
61
+ "typescript": "^5.5.4",
62
+ "typescript-eslint": "^8.0.1"
89
63
  },
90
64
  "peerDependencies": {
91
65
  "rxjs": ">=6.x"
@@ -4,7 +4,7 @@ import * as messageParser from '../message/message-parser.js'
4
4
  import MulticastListener from '../utils/multicast-listener.js'
5
5
  import UnicastListener from '../utils/unicast-listener.js'
6
6
  import EventEmitter from 'component-emitter2'
7
- import rxjs from 'rxjs'
7
+ import * as rxjs from 'rxjs'
8
8
 
9
9
  const EventHandler = function (options, connection, client) {
10
10
  this._options = options
@@ -79,7 +79,7 @@ EventHandler.on = function (name, callback) {
79
79
  EventHandler.once = function (name, callback) {
80
80
  const fn = (...args) => {
81
81
  this.unsubscribe(fn)
82
- callback(...args) // eslint-disable-line
82
+ callback(...args)
83
83
  }
84
84
  this.subscribe(name, fn)
85
85
  return this
@@ -4,8 +4,9 @@ import * as messageBuilder from './message-builder.js'
4
4
  import * as C from '../constants/constants.js'
5
5
  import FixedQueue from '../utils/fixed-queue.js'
6
6
  import Emitter from 'component-emitter2'
7
+ import pkg from '../../package.json' with { type: 'json' }
8
+ import NodeWebSocket from 'ws'
7
9
 
8
- const NodeWebSocket = utils.isNode ? await import('ws').then((x) => x.default) : null
9
10
  const BrowserWebSocket = globalThis.WebSocket || globalThis.MozWebSocket
10
11
 
11
12
  export default function Connection(client, url, options) {
@@ -26,6 +27,7 @@ export default function Connection(client, url, options) {
26
27
  action: null,
27
28
  data: null,
28
29
  }
30
+ this._decoder = new globalThis.TextDecoder()
29
31
  this._recvQueue = new FixedQueue()
30
32
  this._reconnectTimeout = null
31
33
  this._reconnectionAttempt = 0
@@ -88,19 +90,23 @@ Connection.prototype.close = function () {
88
90
  }
89
91
 
90
92
  Connection.prototype._createEndpoint = function () {
91
- this._endpoint = NodeWebSocket
92
- ? new NodeWebSocket(this._url, {
93
- generateMask() {},
94
- })
95
- : new BrowserWebSocket(this._url)
93
+ if (utils.isNode) {
94
+ this._endpoint = new NodeWebSocket(this._url, {
95
+ generateMask() {},
96
+ })
97
+ this._endpoint.binaryType = 'nodebuffer'
98
+ } else {
99
+ this._endpoint = new BrowserWebSocket(this._url)
100
+ this._endpoint.binaryType = 'arraybuffer'
101
+ }
102
+
96
103
  this._corked = false
97
104
 
98
105
  this._endpoint.onopen = this._onOpen.bind(this)
99
106
  this._endpoint.onerror = this._onError.bind(this)
100
107
  this._endpoint.onclose = this._onClose.bind(this)
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())
108
+ this._endpoint.onmessage = ({ data }) =>
109
+ this._onMessage(typeof data === 'string' ? data : this._decoder.decode(data))
104
110
  }
105
111
 
106
112
  Connection.prototype.send = function (message) {
@@ -117,6 +123,10 @@ Connection.prototype.send = function (message) {
117
123
  return false
118
124
  }
119
125
 
126
+ if (!this._endpoint) {
127
+ return false
128
+ }
129
+
120
130
  if (
121
131
  this._state !== C.CONNECTION_STATE.OPEN ||
122
132
  this._endpoint.readyState !== this._endpoint.OPEN
@@ -134,6 +144,7 @@ Connection.prototype.send = function (message) {
134
144
  }
135
145
 
136
146
  this.emit('send', message)
147
+
137
148
  this._endpoint.send(message)
138
149
 
139
150
  return true
@@ -146,7 +157,7 @@ Connection.prototype._submit = function (message) {
146
157
  const err = new Error(`Packet to big: ${message.length} > ${maxPacketSize}`)
147
158
  this._client._$onError(C.TOPIC.CONNECTION, C.EVENT.CONNECTION_ERROR, err)
148
159
  return false
149
- } else if (this._endpoint.readyState === this._endpoint.OPEN) {
160
+ } else if (this._endpoint != null && this._endpoint.readyState === this._endpoint.OPEN) {
150
161
  this.emit('send', message)
151
162
  this._endpoint.send(message)
152
163
  return true
@@ -161,7 +172,7 @@ Connection.prototype._sendAuthParams = function () {
161
172
  this._setState(C.CONNECTION_STATE.AUTHENTICATING)
162
173
  const authMessage = messageBuilder.getMsg(C.TOPIC.AUTH, C.ACTIONS.REQUEST, [
163
174
  this._authParams,
164
- '27.0.0',
175
+ pkg.version,
165
176
  utils.isNode
166
177
  ? `Node/${process.version}`
167
178
  : globalThis.navigator && globalThis.navigator.userAgent,
@@ -222,7 +233,6 @@ Connection.prototype._onMessage = function (data) {
222
233
  Connection.prototype._recvMessages = function (deadline) {
223
234
  for (
224
235
  let n = 0;
225
- // eslint-disable-next-line no-unmodified-loop-condition
226
236
  deadline ? deadline.didTimeout || deadline.timeRemaining() : n < this._batchSize;
227
237
  ++n
228
238
  ) {
@@ -1,22 +1,19 @@
1
1
  import * as C from '../constants/constants.js'
2
2
  import * as utils from '../utils/utils.js'
3
- import varint from 'varint'
4
3
 
5
4
  const poolEncoder = new globalThis.TextEncoder()
6
5
 
7
6
  // TODO (fix): Don't assume maxMesageSize is 1MB
8
7
  const maxMessageSize = 1024 * 1024
9
- const poolSize = maxMessageSize * 4
8
+ const poolSize = maxMessageSize * 8
10
9
 
11
10
  let poolBuffer
12
- let poolView
13
11
  let poolOffset
14
12
 
15
13
  function reallocPool() {
16
14
  poolBuffer = utils.isNode
17
15
  ? globalThis.Buffer.allocUnsafe(poolSize)
18
16
  : new Uint8Array(new ArrayBuffer(poolSize))
19
- poolView = new DataView(poolBuffer.buffer)
20
17
  poolOffset = 0
21
18
  }
22
19
 
@@ -50,14 +47,6 @@ export function getMsg(topic, action, data) {
50
47
 
51
48
  const start = poolOffset
52
49
 
53
- const headerSize = 8
54
- for (let n = 0; n < headerSize; n++) {
55
- poolBuffer[poolOffset++] = 0
56
- }
57
-
58
- let headerPos = start
59
- poolBuffer[headerPos++] = 128 + headerSize
60
-
61
50
  poolBuffer[poolOffset++] = topic.charCodeAt(0)
62
51
  poolBuffer[poolOffset++] = 31
63
52
  for (let n = 0; n < action.length; n++) {
@@ -67,30 +56,18 @@ export function getMsg(topic, action, data) {
67
56
  if (data) {
68
57
  for (let i = 0; i < data.length; i++) {
69
58
  const type = typeof data[i]
70
- let len
71
59
  if (data[i] == null) {
72
60
  poolBuffer[poolOffset++] = 31
73
- len = 0
61
+ poolOffset += 0
74
62
  } else if (type === 'object') {
75
63
  poolBuffer[poolOffset++] = 31
76
- len = writeString(poolBuffer, JSON.stringify(data[i]), poolOffset)
77
- } else if (type === 'bigint') {
78
- poolBuffer[poolOffset++] = 31
79
- poolView.setBigUint64(poolOffset, data[i], false)
80
- len = 8
64
+ poolOffset += writeString(poolBuffer, JSON.stringify(data[i]), poolOffset)
81
65
  } else if (type === 'string') {
82
66
  poolBuffer[poolOffset++] = 31
83
- len = writeString(poolBuffer, data[i], poolOffset)
67
+ poolOffset += writeString(poolBuffer, data[i], poolOffset)
84
68
  } else {
85
69
  throw new Error('invalid data')
86
70
  }
87
- poolOffset += len
88
-
89
- varint.encode(len + 1, poolBuffer, headerPos)
90
- headerPos += varint.encode.bytes
91
- if (headerPos - start >= headerSize) {
92
- throw new Error('header too large')
93
- }
94
71
 
95
72
  if (poolOffset >= poolSize) {
96
73
  throw new Error('message too large')
@@ -2,12 +2,11 @@ import Record from './record.js'
2
2
  import MulticastListener from '../utils/multicast-listener.js'
3
3
  import UnicastListener from '../utils/unicast-listener.js'
4
4
  import * as C from '../constants/constants.js'
5
- import rxjs from 'rxjs'
5
+ import * as rxjs from 'rxjs'
6
6
  import invariant from 'invariant'
7
7
  import EventEmitter from 'component-emitter2'
8
8
  import jsonPath from '@nxtedition/json-path'
9
9
  import * as utils from '../utils/utils.js'
10
- import rx from 'rxjs/operators'
11
10
  import xuid from 'xuid'
12
11
  import * as timers from '../utils/timers.js'
13
12
 
@@ -97,19 +96,11 @@ class RecordHandler {
97
96
  this._connection = connection
98
97
  this._client = client
99
98
  this._records = new Map()
100
- this._cache = new Map()
101
99
  this._listeners = new Map()
102
100
  this._pruning = new Set()
103
101
  this._patching = new Map()
104
102
  this._updating = new Map()
105
103
 
106
- this._registry = new FinalizationRegistry((name) => {
107
- const entry = this._cache.get(name)
108
- if (entry && entry.deref && entry.deref() === undefined) {
109
- this._cache.delete(name)
110
- }
111
- })
112
-
113
104
  this._connected = 0
114
105
  this._stats = {
115
106
  updating: 0,
@@ -142,11 +133,6 @@ class RecordHandler {
142
133
  for (const rec of pruning) {
143
134
  rec._$dispose()
144
135
  this._records.delete(rec.name)
145
-
146
- if (!this._cache.has(rec.name)) {
147
- this._cache.set(rec.name, new WeakRef(rec))
148
- this._registry.register(rec, rec.name)
149
- }
150
136
  }
151
137
 
152
138
  this._stats.pruning -= pruning.size
@@ -232,7 +218,7 @@ class RecordHandler {
232
218
  let record = this._records.get(name)
233
219
 
234
220
  if (!record) {
235
- record = this._cache.get(name)?.deref() ?? new Record(name, this)
221
+ record = new Record(name, this)
236
222
  this._stats.records += 1
237
223
  this._stats.created += 1
238
224
  this._records.set(name, record)
@@ -485,7 +471,7 @@ class RecordHandler {
485
471
  // TODO (fix): Missing sync..
486
472
  return new Promise((resolve, reject) => {
487
473
  this.observe(...args)
488
- .pipe(rx.first())
474
+ .pipe(rxjs.first())
489
475
  .subscribe({
490
476
  next: resolve,
491
477
  error: reject,
@@ -501,7 +487,7 @@ class RecordHandler {
501
487
  get2(...args) {
502
488
  return new Promise((resolve, reject) => {
503
489
  this.observe2(...args)
504
- .pipe(rx.first())
490
+ .pipe(rxjs.first())
505
491
  .subscribe({
506
492
  next: resolve,
507
493
  error: reject,
@@ -7,7 +7,7 @@ import invariant from 'invariant'
7
7
  import cloneDeep from 'lodash.clonedeep'
8
8
  import * as timers from '../utils/timers.js'
9
9
 
10
- export default class Record {
10
+ class Record {
11
11
  static STATE = C.RECORD_STATE
12
12
 
13
13
  constructor(name, handler) {
@@ -15,7 +15,6 @@ export default class Record {
15
15
 
16
16
  this._handler = handler
17
17
  this._name = name
18
- this._key = utils.h64(name)
19
18
  this._version = ''
20
19
  this._data = jsonPath.EMPTY
21
20
  this._state = C.RECORD_STATE.VOID
@@ -25,15 +24,7 @@ export default class Record {
25
24
 
26
25
  /** @type Map? */ this._updating = null
27
26
  /** @type Array? */ this._patching = null
28
- this._subscribed = connection.sendMsg(C.TOPIC.RECORD, C.ACTIONS.SUBSCRIBE, [
29
- this._key,
30
- this._name,
31
- ])
32
- }
33
-
34
- /** @type {bigint} */
35
- get key() {
36
- return this._key
27
+ this._subscribed = connection.sendMsg(C.TOPIC.RECORD, C.ACTIONS.SUBSCRIBE, [this._name])
37
28
  }
38
29
 
39
30
  /** @type {string} */
@@ -71,8 +62,7 @@ export default class Record {
71
62
  if (this._refs === 1) {
72
63
  this._handler._onPruning(this, false)
73
64
  this._subscribed =
74
- this._subscribed ||
75
- connection.sendMsg(C.TOPIC.RECORD, C.ACTIONS.SUBSCRIBE, [this._key, this._name])
65
+ this._subscribed || connection.sendMsg(C.TOPIC.RECORD, C.ACTIONS.SUBSCRIBE, [this._name])
76
66
  }
77
67
  return this
78
68
  }
@@ -334,8 +324,7 @@ export default class Record {
334
324
 
335
325
  if (connected) {
336
326
  this._subscribed =
337
- this._refs > 0 &&
338
- connection.sendMsg(C.TOPIC.RECORD, C.ACTIONS.SUBSCRIBE, [this._key, this._name])
327
+ this._refs > 0 && connection.sendMsg(C.TOPIC.RECORD, C.ACTIONS.SUBSCRIBE, [this._name])
339
328
 
340
329
  if (this._updating) {
341
330
  for (const update of this._updating.values()) {
@@ -360,7 +349,7 @@ export default class Record {
360
349
  invariant(!this._updating, 'must not have updates')
361
350
 
362
351
  if (this._subscribed) {
363
- connection.sendMsg(C.TOPIC.RECORD, C.ACTIONS.UNSUBSCRIBE, [this._key])
352
+ connection.sendMsg(C.TOPIC.RECORD, C.ACTIONS.UNSUBSCRIBE, [this._name])
364
353
  this._subscribed = false
365
354
  }
366
355
 
@@ -382,7 +371,7 @@ export default class Record {
382
371
  const prevVersion = this._version
383
372
  const nextVersion = this._makeVersion(parseInt(prevVersion) + 1)
384
373
 
385
- const update = [this._key, nextVersion, jsonPath.stringify(nextData), prevVersion]
374
+ const update = [this._name, nextVersion, jsonPath.stringify(nextData), prevVersion]
386
375
 
387
376
  if (!this._updating) {
388
377
  this._onUpdating(true)
@@ -584,3 +573,5 @@ Object.defineProperty(Record.prototype, 'hasProvider', {
584
573
  return this.state >= C.RECORD_STATE.PROVIDER
585
574
  },
586
575
  })
576
+
577
+ export default Record
@@ -1,6 +1,6 @@
1
1
  import * as rxjs from 'rxjs'
2
2
  import * as C from '../constants/constants.js'
3
- import { h64, h64ToString } from '../utils/utils.js'
3
+ import { h64ToString } from '../utils/utils.js'
4
4
 
5
5
  export default class Listener {
6
6
  constructor(topic, pattern, callback, handler, { recursive = false, stringify = null } = {}) {
@@ -48,12 +48,8 @@ export default class Listener {
48
48
 
49
49
  const name = message.data[1]
50
50
 
51
- // TOOD (fix): Validate name
52
-
53
- const key = h64(name)
54
-
55
51
  if (message.action === C.ACTIONS.SUBSCRIPTION_FOR_PATTERN_FOUND) {
56
- if (this._subscriptions.has(key)) {
52
+ if (this._subscriptions.has(name)) {
57
53
  this._error(name, 'invalid add: listener exists')
58
54
  return
59
55
  }
@@ -61,7 +57,6 @@ export default class Listener {
61
57
  // TODO (refactor): Move to class
62
58
  const provider = {
63
59
  name,
64
- key,
65
60
  value$: null,
66
61
  sending: false,
67
62
  accepted: false,
@@ -74,7 +69,7 @@ export default class Listener {
74
69
  if (this.connected && provider.accepted) {
75
70
  this._connection.sendMsg(this._topic, C.ACTIONS.LISTEN_REJECT, [
76
71
  this._pattern,
77
- provider.key,
72
+ provider.name,
78
73
  ])
79
74
  }
80
75
 
@@ -107,7 +102,7 @@ export default class Listener {
107
102
  this._connection.sendMsg(
108
103
  this._topic,
109
104
  accepted ? C.ACTIONS.LISTEN_ACCEPT : C.ACTIONS.LISTEN_REJECT,
110
- [this._pattern, provider.key],
105
+ [this._pattern, provider.name],
111
106
  )
112
107
 
113
108
  provider.version = null
@@ -163,7 +158,7 @@ export default class Listener {
163
158
  if (provider.version !== version) {
164
159
  provider.version = version
165
160
  this._connection.sendMsg(C.TOPIC.RECORD, C.ACTIONS.UPDATE, [
166
- provider.key,
161
+ provider.name,
167
162
  version,
168
163
  body,
169
164
  ])
@@ -187,9 +182,9 @@ export default class Listener {
187
182
 
188
183
  provider.start()
189
184
 
190
- this._subscriptions.set(provider.key, provider)
185
+ this._subscriptions.set(provider.name, provider)
191
186
  } else if (message.action === C.ACTIONS.LISTEN_ACCEPT) {
192
- const provider = this._subscriptions.get(key)
187
+ const provider = this._subscriptions.get(name)
193
188
  if (!provider?.value$) {
194
189
  return
195
190
  }
@@ -201,13 +196,13 @@ export default class Listener {
201
196
  provider.valueSubscription = provider.value$.subscribe(provider.observer)
202
197
  }
203
198
  } else if (message.action === C.ACTIONS.SUBSCRIPTION_FOR_PATTERN_REMOVED) {
204
- const provider = this._subscriptions.get(key)
199
+ const provider = this._subscriptions.get(name)
205
200
 
206
201
  if (!provider) {
207
202
  this._error(name, 'invalid remove: listener missing')
208
203
  } else {
209
204
  provider.stop()
210
- this._subscriptions.delete(provider.key)
205
+ this._subscriptions.delete(provider.name)
211
206
  }
212
207
  } else {
213
208
  return false
@@ -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,8 +1,8 @@
1
1
  import * as rxjs from 'rxjs'
2
2
  import * as C from '../constants/constants.js'
3
- import { h64, h64ToString } from '../utils/utils.js'
3
+ import { h64ToString } from '../utils/utils.js'
4
4
 
5
- const valuePipe = rxjs.pipe(
5
+ const PIPE = rxjs.pipe(
6
6
  rxjs.map((value) => {
7
7
  let data
8
8
  if (value && typeof value === 'string') {
@@ -55,12 +55,8 @@ export default class Listener {
55
55
  _$onMessage(message) {
56
56
  const name = message.data[1]
57
57
 
58
- // TODO (fix): Validate name
59
-
60
- const key = h64(name)
61
-
62
58
  if (message.action === C.ACTIONS.LISTEN_ACCEPT) {
63
- if (this._subscriptions.has(key)) {
59
+ if (this._subscriptions.has(name)) {
64
60
  this._error(name, 'invalid accept: listener exists')
65
61
  return
66
62
  }
@@ -73,32 +69,32 @@ export default class Listener {
73
69
  }
74
70
 
75
71
  if (value$) {
76
- const subscription = value$.pipe(valuePipe).subscribe({
72
+ const subscription = value$.pipe(PIPE).subscribe({
77
73
  next: (data) => {
78
74
  if (data == null) {
79
- this._connection.sendMsg(this._topic, C.ACTIONS.LISTEN_REJECT, [this._pattern, key])
80
- this._subscriptions.delete(key)
75
+ this._connection.sendMsg(this._topic, C.ACTIONS.LISTEN_REJECT, [this._pattern, name])
76
+ this._subscriptions.delete(name)
81
77
  subscription.unsubscribe()
82
78
  } else {
83
79
  const version = `INF-${h64ToString(data)}`
84
- this._connection.sendMsg(this._topic, C.ACTIONS.UPDATE, [key, version, data])
80
+ this._connection.sendMsg(this._topic, C.ACTIONS.UPDATE, [name, version, data])
85
81
  }
86
82
  },
87
83
  error: (err) => {
88
84
  this._error(name, err)
89
- this._connection.sendMsg(this._topic, C.ACTIONS.LISTEN_REJECT, [this._pattern, key])
90
- this._subscriptions.delete(key)
85
+ this._connection.sendMsg(this._topic, C.ACTIONS.LISTEN_REJECT, [this._pattern, name])
86
+ this._subscriptions.delete(name)
91
87
  },
92
88
  })
93
- this._subscriptions.set(key, subscription)
89
+ this._subscriptions.set(name, subscription)
94
90
  } else {
95
- 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])
96
92
  }
97
93
  } else if (message.action === C.ACTIONS.LISTEN_REJECT) {
98
- const subscription = this._subscriptions.get(key)
94
+ const subscription = this._subscriptions.get(name)
99
95
 
100
96
  if (subscription) {
101
- this._subscriptions.delete(key)
97
+ this._subscriptions.delete(name)
102
98
  subscription.unsubscribe()
103
99
  } else {
104
100
  this._error(name, 'invalid remove: listener missing')
@@ -129,7 +129,7 @@ function defaultSchedule(fn) {
129
129
  setTimeout(fn, 0)
130
130
  }
131
131
 
132
- export const schedule = isNode ? defaultSchedule : window.requestIdleCallback
132
+ export const schedule = isNode ? defaultSchedule : globalThis.requestIdleCallback
133
133
 
134
134
  const abortSignals = new WeakMap()
135
135
  const onAbort = function () {
@@ -177,16 +177,11 @@ export function removeAbortListener(signal, handler) {
177
177
  }
178
178
  }
179
179
 
180
- const HASHER = await xxhash()
181
-
182
- export function h64(str) {
183
- return HASHER.h64(str)
184
- }
180
+ // This is a hack to avoid top-level await
181
+ // const HASHER = await xxhash()
182
+ let HASHER
183
+ xxhash().then((hasher) => (HASHER = hasher))
185
184
 
186
185
  export function h64ToString(str) {
187
186
  return HASHER.h64ToString(str)
188
187
  }
189
-
190
- export function h64Raw(str) {
191
- return HASHER.h64Raw(str)
192
- }