corestore 7.9.1 → 7.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/index.js +72 -8
  2. package/lib/notify.js +27 -0
  3. package/package.json +13 -6
package/index.js CHANGED
@@ -8,6 +8,7 @@ const { isAndroid } = require('which-runtime')
8
8
  const { STORAGE_EMPTY, ASSERTION } = require('hypercore-errors')
9
9
 
10
10
  const auditStore = require('./lib/audit.js')
11
+ const GroupNotifyHandle = require('./lib/notify.js')
11
12
 
12
13
  const [NS] = crypto.namespace('corestore', 1)
13
14
  const DEFAULT_NAMESPACE = b4a.alloc(32) // This is meant to be 32 0-bytes
@@ -204,6 +205,7 @@ class FindingPeers {
204
205
  constructor() {
205
206
  this.count = 0
206
207
  this.pending = []
208
+ this.destroyed = false
207
209
  }
208
210
 
209
211
  add(core) {
@@ -212,7 +214,7 @@ class FindingPeers {
212
214
  }
213
215
 
214
216
  inc(sessions) {
215
- if (++this.count !== 1) return
217
+ if (this.destroyed || ++this.count !== 1) return
216
218
 
217
219
  for (const core of sessions) {
218
220
  this.pending.push(core.findingPeers())
@@ -220,7 +222,12 @@ class FindingPeers {
220
222
  }
221
223
 
222
224
  dec(sessions) {
223
- if (--this.count !== 0) return
225
+ if (this.destroyed || --this.count !== 0) return
226
+ while (this.pending.length > 0) this.pending.pop()()
227
+ }
228
+
229
+ destroy() {
230
+ this.destroyed = true
224
231
  while (this.pending.length > 0) this.pending.pop()()
225
232
  }
226
233
  }
@@ -253,8 +260,10 @@ class Corestore extends ReadyResource {
253
260
  this.watchers = null
254
261
  this.watchIndex = -1
255
262
 
263
+ this._groupNotifiers = new Map() // group notifications
256
264
  this._findingPeers = null // here for legacy
257
265
  this._ongcBound = this._ongc.bind(this)
266
+ this._onGroupActiveBound = this._onGroupActive.bind(this)
258
267
 
259
268
  if (opts.primaryKey && !this.root && !opts.unsafe) {
260
269
  throw ASSERTION(
@@ -262,8 +271,6 @@ class Corestore extends ReadyResource {
262
271
  )
263
272
  }
264
273
 
265
- if (this.root) this.corestores.add(this)
266
-
267
274
  this.ready().catch(noop)
268
275
  }
269
276
 
@@ -287,12 +294,50 @@ class Corestore extends ReadyResource {
287
294
  }
288
295
  }
289
296
 
297
+ _onGroupActive(topic) {
298
+ this.emit('group-active', topic)
299
+
300
+ const topicHex = b4a.toString(topic, 'hex')
301
+ const handles = this._groupNotifiers.get(topicHex)
302
+ if (!handles) return
303
+ for (const handle of handles) handle.emit('update')
304
+ }
305
+
306
+ notifyGroup(topic) {
307
+ const topicHex = b4a.toString(topic, 'hex')
308
+ let handles = this._groupNotifiers.get(topicHex)
309
+
310
+ if (!handles) {
311
+ handles = []
312
+ this._groupNotifiers.set(topicHex, handles)
313
+ }
314
+
315
+ const handle = new GroupNotifyHandle(this, topic)
316
+ const length = handles.push(handle)
317
+ handle.index = length - 1
318
+
319
+ return handle
320
+ }
321
+
322
+ _removeGroupNotify(handle) {
323
+ if (handle.index === -1) return
324
+
325
+ const topicHex = b4a.toString(handle._topic, 'hex')
326
+ const handles = this._groupNotifiers.get(topicHex)
327
+ if (!handles) return
328
+
329
+ const popped = handles.pop()
330
+ if (popped !== handle) handles[(popped.index = handle.index)] = popped
331
+ if (handles.length === 0) this._groupNotifiers.delete(topicHex)
332
+ handle.index = -1
333
+ }
334
+
290
335
  findingPeers() {
291
336
  if (this._findingPeers === null) this._findingPeers = new FindingPeers()
292
337
  this._findingPeers.inc(this.sessions)
293
338
  let done = false
294
339
  return () => {
295
- if (done) return
340
+ if (done || !this._findingPeers) return
296
341
  done = true
297
342
  this._findingPeers.dec(this.sessions)
298
343
  }
@@ -352,6 +397,7 @@ class Corestore extends ReadyResource {
352
397
 
353
398
  async _open() {
354
399
  if (this.root !== null) {
400
+ this.corestores.add(this)
355
401
  if (this.root.opened === false) await this.root.ready()
356
402
  this.primaryKey = this.root.primaryKey
357
403
  return
@@ -374,10 +420,19 @@ class Corestore extends ReadyResource {
374
420
  const hanging = [...this.sessions]
375
421
  for (const sess of hanging) closing.push(sess.close())
376
422
 
377
- if (this.watchers !== null) this.cores.unwatch(this)
423
+ if (this.watchers !== null) {
424
+ this.cores.unwatch(this)
425
+ this.watchers = null
426
+ }
427
+
428
+ if (this._findingPeers !== null) {
429
+ this._findingPeers.destroy()
430
+ this._findingPeers = null
431
+ }
378
432
 
379
433
  if (this.root !== null) {
380
434
  await Promise.all(closing)
435
+ this.corestores.delete(this)
381
436
  return
382
437
  }
383
438
 
@@ -554,6 +609,7 @@ class Corestore extends ReadyResource {
554
609
 
555
610
  _makeSession(conf) {
556
611
  const session = new Hypercore(null, null, conf)
612
+
557
613
  if (this._findingPeers !== null) this._findingPeers.add(session)
558
614
  return session
559
615
  }
@@ -596,7 +652,8 @@ class Corestore extends ReadyResource {
596
652
  keyPair: null,
597
653
  key: null,
598
654
  discoveryKey,
599
- manifest: null
655
+ manifest: null,
656
+ group: null
600
657
  }
601
658
 
602
659
  if (opts.name) {
@@ -614,6 +671,10 @@ class Corestore extends ReadyResource {
614
671
  }
615
672
  }
616
673
 
674
+ if (opts.group) {
675
+ result.group = opts.group
676
+ }
677
+
617
678
  if (opts.key) result.key = ID.decode(opts.key)
618
679
  else if (result.manifest) result.key = Hypercore.key(result.manifest)
619
680
 
@@ -630,7 +691,7 @@ class Corestore extends ReadyResource {
630
691
  const auth = this._auth(discoveryKey, opts)
631
692
 
632
693
  const id = toHex(auth.discoveryKey)
633
- const existing = this.cores.resume(id)
694
+ const existing = this.cores.resume(id, auth.group)
634
695
  if (existing && !existing.closing) return existing
635
696
 
636
697
  const core = Hypercore.createCore(this.storage, {
@@ -649,6 +710,7 @@ class Corestore extends ReadyResource {
649
710
  keyPair: auth.keyPair,
650
711
  legacy: opts.legacy,
651
712
  manifest: auth.manifest,
713
+ group: auth.group,
652
714
  globalCache: opts.globalCache || this.globalCache || null,
653
715
  alias: opts.name ? { name: opts.name, namespace: this.ns } : null
654
716
  })
@@ -657,6 +719,8 @@ class Corestore extends ReadyResource {
657
719
  this.cores.gc(core)
658
720
  }
659
721
 
722
+ core.ongroupupdate = this._onGroupActiveBound
723
+
660
724
  core.replicator.ondownloading = () => {
661
725
  if (this.active) this.streamTracker.attachAll(core)
662
726
  }
package/lib/notify.js ADDED
@@ -0,0 +1,27 @@
1
+ const { EventEmitter } = require('events')
2
+ const { Readable } = require('streamx')
3
+
4
+ class GroupNotifyHandle extends EventEmitter {
5
+ constructor(store, topic) {
6
+ super()
7
+ this._store = store
8
+ this._topic = topic
9
+ this.index = -1
10
+ }
11
+
12
+ updates(opts) {
13
+ return Readable.deferred(async () => {
14
+ const groupId = await this._store.storage.getGroup(this._topic).catch(noop)
15
+ if (groupId === null) return null
16
+ return this._store.storage.createGroupUpdateStream(groupId, opts)
17
+ })
18
+ }
19
+
20
+ destroy() {
21
+ this._store._removeGroupNotify(this)
22
+ }
23
+ }
24
+
25
+ module.exports = GroupNotifyHandle
26
+
27
+ function noop() {}
package/package.json CHANGED
@@ -1,20 +1,28 @@
1
1
  {
2
2
  "name": "corestore",
3
- "version": "7.9.1",
3
+ "version": "7.10.0",
4
4
  "description": "A Hypercore factory that simplifies managing collections of cores.",
5
5
  "main": "index.js",
6
6
  "files": [
7
7
  "index.js",
8
8
  "lib/*"
9
9
  ],
10
+ "imports": {
11
+ "events": {
12
+ "bare": "bare-events",
13
+ "default": "events"
14
+ }
15
+ },
10
16
  "dependencies": {
11
17
  "b4a": "^1.6.7",
12
- "hypercore": "^11.19.0",
18
+ "bare-events": "^2.8.3",
19
+ "hypercore": "^11.32.0",
13
20
  "hypercore-crypto": "^3.4.2",
14
21
  "hypercore-errors": "^1.4.0",
15
22
  "hypercore-id-encoding": "^1.3.0",
16
23
  "ready-resource": "^1.1.1",
17
24
  "sodium-universal": "^5.0.1",
25
+ "streamx": "^2.26.0",
18
26
  "which-runtime": "^1.2.1"
19
27
  },
20
28
  "devDependencies": {
@@ -22,15 +30,14 @@
22
30
  "lunte": "^1.3.0",
23
31
  "prettier": "^3.6.2",
24
32
  "prettier-config-holepunch": "^2.0.0",
25
- "rache": "^1.0.0",
26
- "test-tmp": "^1.3.0"
33
+ "rache": "^1.0.0"
27
34
  },
28
35
  "scripts": {
29
36
  "format": "prettier --write .",
30
37
  "test": "npm run test:node && npm run test:bare",
31
- "test:bare": "brittle-bare --coverage test/*.js",
38
+ "test:bare": "brittle-bare --coverage test/all.js",
32
39
  "lint": "prettier --check . && lunte",
33
- "test:node": "brittle-node --coverage test/*.js"
40
+ "test:node": "brittle-node --coverage test/all.js"
34
41
  },
35
42
  "repository": {
36
43
  "type": "git",