hypercore 11.14.1 → 11.15.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.
package/README.md CHANGED
@@ -23,11 +23,6 @@ Version 10 is not compatible with earlier versions (9 and earlier), but is consi
23
23
  npm install hypercore
24
24
  ```
25
25
 
26
- > [!NOTE]
27
- > This readme reflects Hypercore 11, our latest major version that is backed by RocksDB for storage and atomicity.
28
- > Whilst we are fully validating that, the npm dist-tag for latest is set to latest version of Hypercore 10, the previous major, to avoid too much disruption.
29
- > It will be updated to 11 in a few weeks.
30
-
31
26
  ## API
32
27
 
33
28
  #### `const core = new Hypercore(storage, [key], [options])`
@@ -50,6 +45,7 @@ Alternatively you can pass a [Hypercore Storage](https://github.com/holepunchto/
50
45
  {
51
46
  createIfMissing: true, // create a new Hypercore key pair if none was present in storage
52
47
  overwrite: false, // overwrite any old Hypercore that might already exist
48
+ force: false, // Advanced option. Will force overwrite even if the header's key & the passed key don't match
53
49
  valueEncoding: 'json' | 'utf-8' | 'binary', // defaults to binary
54
50
  encodeBatch: batch => { ... }, // optionally apply an encoding to complete batches
55
51
  keyPair: kp, // optionally pass the public key and secret key as a key pair
@@ -59,9 +55,14 @@ Alternatively you can pass a [Hypercore Storage](https://github.com/holepunchto/
59
55
  writable: true, // disable appends and truncates
60
56
  inflightRange: null, // Advanced option. Set to [minInflight, maxInflight] to change the min and max inflight blocks per peer when downloading.
61
57
  ongc: (session) => { ... }, // A callback called when the session is garbage collected
58
+ onseq: (index, core) => { ... }, // A callback called when core.get(index) is called.
62
59
  notDownloadingLinger: 20000, // How many milliseconds to wait after downloading finishes keeping the connection open. Defaults to a random number between 20-40s
63
60
  allowFork: true, // Enables updating core when it forks
64
- userData: { foo: 'bar' }, // An object to assign to the local User Uata storage
61
+ userData: { foo: 'bar' }, // An object to assign to the local User Data storage
62
+ manifest: undefined, // Advanced option. Set the manifest when creating the hypercore. See Manifest section for more info
63
+ preload: undefined, // Advanced option. A promise that returns constructor options overrides before the core is opened
64
+ storage: undefined, // An alternative to passing storage as a dedicated argument
65
+ key: null, // An alternative to passing key as a dedicated argument
65
66
  }
66
67
  ```
67
68
 
@@ -79,7 +80,36 @@ Keys are always strings and values can be strings or buffers.
79
80
 
80
81
  See [`core.setUserData(key, value)`](#await-coresetuserdatakey-value) and [`core.getUserData(key)`](#const-value--await-coregetuserdatakey) for updating User Data.
81
82
 
82
- #### `const { length, byteLength } = await core.append(block)`
83
+ ##### Manifest
84
+
85
+ The manifest is metadata about authenticating a hypercore including things like the signers (only one by default) and the prologue. Manifest has the following structure:
86
+
87
+ ```
88
+ {
89
+ version: 1, // Version of the manifest format
90
+ hash: 'blake2b', // Only Blake2b is supported currently
91
+ allowPatch: false, // Whether the hypercore can be "patched" to change the signers
92
+ quorum: (signers.length / 2) + 1, // How many signers needed to verify a block
93
+ signers, // Array of signers for the core
94
+ prologue: null, // The tree hash and length of the core
95
+ linked: null, // Array of associated core keys. Only supported in versions >= 2
96
+ userData: null // Arbitrary buffer for User Data integral to the core. Only supported in versions >= 2
97
+ }
98
+ ```
99
+
100
+ The `linked` property in the manifest is used to reference other hypercores that are associated with the current core. For example in `autobase` the encryption view is loaded from the `linked` property in the system view core. Note, as with everything in the manifest, changing the `linked` property changes the core's `key`.
101
+
102
+ Signers are an array of objects with the following structure:
103
+
104
+ ```
105
+ {
106
+ signature: 'ed25519', // The signature method
107
+ namespace: caps.DEFAULT_NAMESPACE, // A cryptographic namespace for the signature
108
+ publicKey: Buffer // Signer's public key
109
+ }
110
+ ```
111
+
112
+ #### `const { length, byteLength } = await core.append(block, options = {})`
83
113
 
84
114
  Append a block of data (or an array of blocks) to the core.
85
115
  Returns the new length and byte length of the core.
@@ -92,6 +122,17 @@ await core.append(Buffer.from('I am a block of data'))
92
122
  await core.append([Buffer.from('batch block 1'), Buffer.from('batch block 2')])
93
123
  ```
94
124
 
125
+ `options` include:
126
+
127
+ ```
128
+ {
129
+ writable: false // Enabled ignores writable check. Does not override whether core is writable.
130
+ maxLength: undefined // The maximum resulting length of the core after appending
131
+ keyPair: core.keyPair // KeyPair used to sign the block(s)
132
+ signature: null // Set signature for block(s)
133
+ }
134
+ ```
135
+
95
136
  #### `const block = await core.get(index, [options])`
96
137
 
97
138
  Get a block of data.
@@ -115,8 +156,10 @@ const blockLocal = await core.get(44, { wait: false })
115
156
  wait: true, // wait for block to be downloaded
116
157
  onwait: () => {}, // hook that is called if the get is waiting for download
117
158
  timeout: 0, // wait at max some milliseconds (0 means no timeout)
159
+ activeRequests: undefined, // Advanced option. Pass BlockRequest for replicating the block
118
160
  valueEncoding: 'json' | 'utf-8' | 'binary', // defaults to the core's valueEncoding
119
- decrypt: true // automatically decrypts the block if encrypted
161
+ decrypt: true, // automatically decrypts the block if encrypted
162
+ raw: false, // Return block without decoding
120
163
  }
121
164
  ```
122
165
 
@@ -138,7 +181,9 @@ console.log('core was updated?', updated, 'length is', core.length)
138
181
 
139
182
  ``` js
140
183
  {
141
- wait: false
184
+ wait: false,
185
+ activeRequests: undefined, // Advanced option. Pass requests for replicating blocks
186
+ force: false, // Force an update even if core is writable.
142
187
  }
143
188
  ```
144
189
 
@@ -162,7 +207,8 @@ const third = await core.seek(5) // returns [2, 1]
162
207
  ``` js
163
208
  {
164
209
  wait: true, // wait for data to be downloaded
165
- timeout: 0 // wait at max some milliseconds (0 means no timeout)
210
+ timeout: 0, // wait at max some milliseconds (0 means no timeout)
211
+ activeRequests: undefined // Advanced option. Pass requests for replicating blocks
166
212
  }
167
213
  ```
168
214
 
@@ -191,7 +237,9 @@ for await (const data of fullStream) {
191
237
  {
192
238
  start: 0,
193
239
  end: core.length,
194
- live: false,
240
+ wait: core.wait, // Whether to wait for updates from peers
241
+ timeout: core.timeout, // How long to wait for updates from peers
242
+ live: false, // Wait for next block keeping stream open / live
195
243
  snapshot: true // auto set end to core.length on open or update it on every read
196
244
  }
197
245
  ```
@@ -220,12 +268,31 @@ partialStream.pipe(process.stdout)
220
268
 
221
269
  ``` js
222
270
  {
223
- byteOffset: 0,
224
- byteLength: core.byteLength - options.byteOffset,
225
- prefetch: 32
271
+ byteOffset: 0, // Offset where to start from
272
+ byteLength: core.byteLength - options.byteOffset, // How many bytes to read
273
+ prefetch: 32 // How many bytes to download at a time
226
274
  }
227
275
  ```
228
276
 
277
+ #### `const stream = core.createWriteStream()`
278
+
279
+ Make a write stream to append chunks as blocks.
280
+
281
+ ``` js
282
+ const ws = core.createWriteStream()
283
+
284
+ // Listen for stream finishing
285
+ const done = new Promise(resolve => ws.on('finish', resolve))
286
+
287
+ for (const data of ['hello', 'world']) ws.write(data)
288
+ ws.end()
289
+
290
+ await done
291
+
292
+ console.log(await core.get(core.length - 2)) // 'hello'
293
+ console.log(await core.get(core.length - 1)) // 'world'
294
+ ```
295
+
229
296
  #### `const cleared = await core.clear(start, [end], [options])`
230
297
 
231
298
  Clear stored blocks between `start` and `end`, reclaiming storage when possible.
@@ -244,17 +311,55 @@ The core will also gossip to peers it is connected to, that is no longer has the
244
311
  }
245
312
  ```
246
313
 
247
- #### `await core.truncate(newLength, [forkId])`
314
+ #### `await core.truncate(newLength, [options])`
248
315
 
249
316
  Truncate the core to a smaller length.
250
317
 
251
- Per default this will update the fork id of the core to `+ 1`, but you can set the fork id you prefer with the option.
318
+ Per default this will update the fork id of the core to `+ 1`, but you can set the fork id you prefer with the option `fork`.
252
319
  Note that the fork id should be monotonely incrementing.
253
320
 
321
+ `options` include:
322
+ ```js
323
+ {
324
+ fork: core.fork + 1, // The new fork id after truncating
325
+ keyPair: core.keyPair, // Key pair used for signing the truncation
326
+ signature: null, // Set signature for truncation
327
+ }
328
+ ```
329
+
330
+ If `options` is a number, it will be used as the `fork` id.
331
+
254
332
  #### `const hash = await core.treeHash([length])`
255
333
 
256
334
  Get the Merkle Tree hash of the core at a given length, defaulting to the current length of the core.
257
335
 
336
+ #### `const proof = await core.proof(opts)`
337
+
338
+ Generate a proof (a `TreeProof` instance) for the request `opts`.
339
+
340
+ `opts` include:
341
+
342
+ ```
343
+ {
344
+ block: { index, nodes }, // Block request
345
+ hash: { index, nodes }, // Hash Request
346
+ seek: { bytes, padding }, // Seek Request
347
+ upgrade: { start, length } // Upgrade request
348
+ }
349
+ ```
350
+
351
+ Note that you cannot seek & provide a block / hash request when upgrading.
352
+
353
+ #### `const batch = await core.verifyFullyRemote(proof)`
354
+
355
+ Return the merkle tree batch from the proof. Will throw if the proof cannot be verified.
356
+
357
+ Note that you cannot seek & provide a block / hash request when upgrading.
358
+
359
+ #### `const buffer = await core.signable([length], [fork])`
360
+
361
+ Return a buffer which encodes the core's `key`, tree hash (`core.treeHash()`), `length`, & `fork`. If the `length` & `fork` arguments are not provided, the current values for the core are used by default.
362
+
258
363
  #### `const range = core.download([range])`
259
364
 
260
365
  Download a range of data.
@@ -272,7 +377,8 @@ A range can have the following properties:
272
377
  start: startIndex,
273
378
  end: nonInclusiveEndIndex,
274
379
  blocks: [index1, index2, ...],
275
- linear: false // download range linearly and not randomly
380
+ linear: false, // download range linearly and not randomly
381
+ activeRequests: undefined // Advanced option. Pass requests for replicating blocks
276
382
  }
277
383
  ```
278
384
 
@@ -297,6 +403,31 @@ To cancel downloading a range simply destroy the range instance.
297
403
  range.destroy()
298
404
  ```
299
405
 
406
+ #### `const ext = core.registerExtension(name, handlers = {})`
407
+
408
+ Register a custom protocol extension. This is a legacy implementation and is no longer recommended. Creating a [`Protomux`](https://github.com/holepunchto/protomux) protocol is recommended instead.
409
+
410
+ `handlers` include:
411
+
412
+ ```
413
+ {
414
+ encoding: 'json' | 'utf-8' | 'binary', // Compact encoding to use for messages. Defaults to buffer
415
+ onmessage: (message, peer) => { ... } // Callback for when a message for the extension is receive
416
+ }
417
+ ```
418
+
419
+ ##### ext.send(message, peer)
420
+
421
+ Sends the `message` to a specific `peer`.
422
+
423
+ ##### ext.broadcast(message)
424
+
425
+ Sends the `message` to all peers.
426
+
427
+ ##### ext.destroy()
428
+
429
+ Unregister and remove extension from the hypercore.
430
+
300
431
  #### `const session = core.session([options])`
301
432
 
302
433
  Creates a new Hypercore instance that shares the same underlying core.
@@ -342,9 +473,20 @@ Attempt to apply blocks from the session to the `core`. `core` must be a default
342
473
 
343
474
  Returns `null` if committing failed.
344
475
 
476
+ `opts` includes:
477
+
478
+ ```
479
+ {
480
+ length: session.length, // the core's length after committing the blocks
481
+ treeLength: core.length, // The expected length of the core's merkle tree prior to commit
482
+ keyPair: core.keyPair, // The keypair to use when committing
483
+ signature: undefined, // The signature for the blocks being committed
484
+ }
485
+ ```
486
+
345
487
  #### `const snapshot = core.snapshot([options])`
346
488
 
347
- Same as above, but backed by a storage snapshot so will not truncate nor append.
489
+ Same as [`core.session(options)`](#const-session--coresessionoptions), but backed by a storage snapshot so will not truncate nor append.
348
490
 
349
491
  #### `const info = await core.info([options])`
350
492
 
@@ -378,9 +520,9 @@ Info {
378
520
  }
379
521
  ```
380
522
 
381
- #### `await core.close()`
523
+ #### `await core.close([{ error }])`
382
524
 
383
- Fully close this core.
525
+ Fully close this core. Passing an error via `{ error }` is optional and all pending replicator requests will be rejected with the error.
384
526
 
385
527
  #### `core.on('close')`
386
528
 
@@ -401,7 +543,7 @@ Emitted after the core has initially opened all its internal state.
401
543
 
402
544
  #### `core.writable`
403
545
 
404
- Can we append to this core?
546
+ Can we append to or truncate this core?
405
547
 
406
548
  Populated after `ready` has been emitted. Will be `false` before the event.
407
549
 
@@ -464,6 +606,36 @@ Populated after `ready` has been emitted. Will be `0` before the event.
464
606
 
465
607
  How much padding is applied to each block of this core? Will be `0` unless block encryption is enabled.
466
608
 
609
+ #### `core.peers`
610
+
611
+ Array of current peers the core is replicating with.
612
+
613
+ #### `await core.setEncryption(encryption)`
614
+
615
+ Set the encryption, which should satisfy the [HypercoreEncryption](https://github.com/holepunchto/hypercore-encryption) interface.
616
+
617
+ #### `await core.setEncryptionKey(key, [opts])`
618
+
619
+ Set the encryption key.
620
+
621
+ `opts` includes:
622
+
623
+ ```
624
+ {
625
+ block: false, // Whether the key is for block encryption
626
+ }
627
+ ```
628
+
629
+ #### `core.setKeyPair(keyPair)`
630
+
631
+ Update the core's `keyPair`. Advanced as the `keyPair` is used throughout Hypercore, e.g. verifying blocks, identifying the core, etc.
632
+
633
+ #### `core.setActive(active)`
634
+
635
+ Set the core to be active or not. A core is considered 'active' if it should linger to download blocks from peers.
636
+
637
+ When calling `core.setActive(true)` make sure to later call `core.setActive(false)` to mark it as inactive otherwise the core's activity tracking will be inaccurate and keep replication channels open.
638
+
467
639
  #### `await core.setUserData(key, value)`
468
640
 
469
641
  Set a key in the User Data key-value store.
@@ -476,7 +648,7 @@ Return the value for a key in the User Data key-value store.
476
648
 
477
649
  `key` is a string.
478
650
 
479
- #### `const stream = core.replicate(isInitiatorOrReplicationStream)`
651
+ #### `const stream = core.replicate(isInitiatorOrReplicationStream, opts = {})`
480
652
 
481
653
  Create a replication stream. You should pipe this to another Hypercore instance.
482
654
 
@@ -501,6 +673,8 @@ const socket = net.connect(...)
501
673
  socket.pipe(localCore.replicate(true)).pipe(socket)
502
674
  ```
503
675
 
676
+ `opts` are same as [`Hypercore.createProtocolStream()`](#const-stream--hypercorecreateprotocolstreamisinitiator-opts--).
677
+
504
678
  #### `const done = core.findingPeers()`
505
679
 
506
680
  Create a hook that tells Hypercore you are finding peers for this core in the background. Call `done` when your current discovery iteration is done.
@@ -531,3 +705,56 @@ Emitted when a block is uploaded to a peer.
531
705
  #### `core.on('download', index, byteLength, peer)`
532
706
 
533
707
  Emitted when a block is downloaded from a peer.
708
+
709
+ #### `Hypercore.MAX_SUGGESTED_BLOCK_SIZE`
710
+
711
+ The constant for max size (15MB) for blocks appended to Hypercore. This max ensures blocks are replicated smoothly.
712
+
713
+ #### `const key = Hypercore.key(manifest, options = {})`
714
+
715
+ Returns the key for a given manifest.
716
+
717
+ `options` include:
718
+
719
+ ```
720
+ {
721
+ compat: false, // Whether the manifest has a single singer whose public key is the key
722
+ version, // Manifest version if the manifest argument is the public key of a single singer
723
+ namespace // The signer namespace if the manifest argument is the public key of a single singer
724
+ }
725
+ ```
726
+
727
+ #### `const dKey = Hypercore.discoveryKey(key)`
728
+
729
+ Returns the discovery key for the provided `key`.
730
+
731
+ #### `const bkey = Hypercore.blockEncryptionKey(key, encryptionKey)`
732
+
733
+ Returns a block encryption key derived from the `key` and `encryptionKey`.
734
+
735
+ #### `const mux = Hypercore.getProtocolMuxer(stream)`
736
+
737
+ Returns a protomux instance from the provided `stream` Hypercore protocol stream.
738
+
739
+ #### `const core = Hypercore.createCore(storage, opts)`
740
+
741
+ Returns the internal core using the `storage` and `opts` without creating a full Hypercore instance.
742
+
743
+ #### `const stream = Hypercore.createProtocolStream(isInitiator, opts = {})`
744
+
745
+ Create an encrypted noise stream with a protomux instance attached used for Hypercore's replication protocol.
746
+
747
+ `isInitiator` can be a framed stream, a protomux or a boolean for whether the stream should be the initiator in the noise handshake.
748
+
749
+ `opts` can include:
750
+
751
+ ```
752
+ {
753
+ keepAlive: true, // Whether to keep the stream alive
754
+ ondiscoverykey: () => {}, // A handler for when a discovery key is set over the stream for corestore management
755
+ }
756
+ ```
757
+
758
+ #### `const storage = Hypercore.defaultStorage(storage, opts = {})`
759
+
760
+ Returns a default hypercore storage. The `storage` argument can be a path where to create the `hypercore-storage` instance or an existing `hypercore-storage` instance. If an existing instance, it is immediately returned.
package/index.js CHANGED
@@ -15,6 +15,7 @@ const Info = require('./lib/info')
15
15
  const Download = require('./lib/download')
16
16
  const DefaultEncryption = require('./lib/default-encryption')
17
17
  const caps = require('./lib/caps')
18
+ const Replicator = require('./lib/replicator')
18
19
  const { manifestHash, createManifest } = require('./lib/verifier')
19
20
  const { ReadStream, WriteStream, ByteStream } = require('./lib/streams')
20
21
  const { MerkleTree } = require('./lib/merkle-tree')
@@ -203,6 +204,10 @@ class Hypercore extends EventEmitter {
203
204
  return new CoreStorage(directory, opts)
204
205
  }
205
206
 
207
+ static clearRequests (session, err) {
208
+ return Replicator.clearRequests(session, err)
209
+ }
210
+
206
211
  snapshot (opts) {
207
212
  return this.session({ ...opts, snapshot: true })
208
213
  }
@@ -241,10 +246,10 @@ class Hypercore extends EventEmitter {
241
246
  async setEncryptionKey (key, opts) {
242
247
  if (!this.opened) await this.opening
243
248
  const encryption = this._getEncryptionProvider({ key, block: !!(opts && opts.block) })
244
- return this.setEncryption(encryption, opts)
249
+ return this.setEncryption(encryption)
245
250
  }
246
251
 
247
- async setEncryption (encryption, opts) {
252
+ async setEncryption (encryption) {
248
253
  if (!this.opened) await this.opening
249
254
 
250
255
  if (encryption === null) {
@@ -516,7 +521,7 @@ class Hypercore extends EventEmitter {
516
521
  replicate (isInitiator, opts = {}) {
517
522
  // Only limitation here is that ondiscoverykey doesn't work atm when passing a muxer directly,
518
523
  // because it doesn't really make a lot of sense.
519
- if (Protomux.isProtomux(isInitiator)) return this._attachToMuxer(isInitiator, opts)
524
+ if (Protomux.isProtomux(isInitiator)) return this._attachToMuxer(isInitiator)
520
525
 
521
526
  // if same stream is passed twice, ignore the 2nd one before we make sessions etc
522
527
  if (isStream(isInitiator) && this._isAttached(isInitiator)) return isInitiator
@@ -883,8 +888,8 @@ class Hypercore extends EventEmitter {
883
888
  return new ReadStream(this, opts)
884
889
  }
885
890
 
886
- createWriteStream (opts) {
887
- return new WriteStream(this, opts)
891
+ createWriteStream () {
892
+ return new WriteStream(this)
888
893
  }
889
894
 
890
895
  createByteStream (opts) {
package/lib/replicator.js CHANGED
@@ -57,7 +57,8 @@ const PRIORITY = {
57
57
  }
58
58
 
59
59
  class Attachable {
60
- constructor () {
60
+ constructor (replicator) {
61
+ this.replicator = replicator
61
62
  this.resolved = false
62
63
  this.processing = false
63
64
  this.refs = []
@@ -147,8 +148,8 @@ class Attachable {
147
148
  }
148
149
 
149
150
  class BlockRequest extends Attachable {
150
- constructor (tracker, index, priority) {
151
- super()
151
+ constructor (replicator, tracker, index, priority) {
152
+ super(replicator)
152
153
 
153
154
  this.index = index
154
155
  this.priority = priority
@@ -171,8 +172,8 @@ class BlockRequest extends Attachable {
171
172
  }
172
173
 
173
174
  class RangeRequest extends Attachable {
174
- constructor (ranges, start, end, linear, ifAvailable, blocks) {
175
- super()
175
+ constructor (replicator, ranges, start, end, linear, ifAvailable, blocks) {
176
+ super(replicator)
176
177
 
177
178
  this.start = start
178
179
  this.end = end
@@ -200,12 +201,11 @@ class RangeRequest extends Attachable {
200
201
 
201
202
  class UpgradeRequest extends Attachable {
202
203
  constructor (replicator, fork, length) {
203
- super()
204
+ super(replicator)
204
205
 
205
206
  this.fork = fork
206
207
  this.length = length
207
208
  this.inflight = []
208
- this.replicator = replicator
209
209
  }
210
210
 
211
211
  _unref () {
@@ -219,8 +219,8 @@ class UpgradeRequest extends Attachable {
219
219
  }
220
220
 
221
221
  class SeekRequest extends Attachable {
222
- constructor (seeks, seeker) {
223
- super()
222
+ constructor (replicator, seeks, seeker) {
223
+ super(replicator)
224
224
 
225
225
  this.seeker = seeker
226
226
  this.inflight = []
@@ -278,7 +278,8 @@ class InflightTracker {
278
278
  }
279
279
 
280
280
  class BlockTracker {
281
- constructor () {
281
+ constructor (replicator) {
282
+ this._replicator = replicator
282
283
  this._map = new Map()
283
284
  }
284
285
 
@@ -302,7 +303,7 @@ class BlockTracker {
302
303
  let b = this._map.get(index)
303
304
  if (b) return b
304
305
 
305
- b = new BlockRequest(this, index, priority)
306
+ b = new BlockRequest(this._replicator, this, index, priority)
306
307
  this._map.set(index, b)
307
308
 
308
309
  return b
@@ -1534,8 +1535,8 @@ module.exports = class Replicator {
1534
1535
 
1535
1536
  this._attached = new Set()
1536
1537
  this._inflight = new InflightTracker()
1537
- this._blocks = new BlockTracker()
1538
- this._hashes = new BlockTracker()
1538
+ this._blocks = new BlockTracker(this)
1539
+ this._hashes = new BlockTracker(this)
1539
1540
 
1540
1541
  this._queued = []
1541
1542
 
@@ -1697,7 +1698,7 @@ module.exports = class Replicator {
1697
1698
  }
1698
1699
 
1699
1700
  addSeek (session, seeker) {
1700
- const s = new SeekRequest(this._seeks, seeker)
1701
+ const s = new SeekRequest(this, this._seeks, seeker)
1701
1702
  const ref = s.attach(session)
1702
1703
 
1703
1704
  this._seeks.push(s)
@@ -1713,6 +1714,7 @@ module.exports = class Replicator {
1713
1714
  }
1714
1715
 
1715
1716
  const r = new RangeRequest(
1717
+ this,
1716
1718
  this._ranges,
1717
1719
  start,
1718
1720
  length === -1 ? -1 : start + length,
@@ -1743,6 +1745,22 @@ module.exports = class Replicator {
1743
1745
  ref.context.detach(ref, null)
1744
1746
  }
1745
1747
 
1748
+ static clearRequests (session, err) {
1749
+ if (session.length === 0) return
1750
+
1751
+ const updated = new Set()
1752
+
1753
+ while (session.length > 0) {
1754
+ const ref = session[session.length - 1]
1755
+ ref.context.detach(ref, err)
1756
+ updated.add(ref.context.replicator)
1757
+ }
1758
+
1759
+ for (const replicator of updated) {
1760
+ replicator.updateAll()
1761
+ }
1762
+ }
1763
+
1746
1764
  clearRequests (session, err = null) {
1747
1765
  let cleared = false
1748
1766
  while (session.length > 0) {
@@ -832,7 +832,7 @@ module.exports = class SessionState {
832
832
  return { tree, flushed }
833
833
  }
834
834
 
835
- async commit (state, { signature, keyPair, length = state.length, treeLength = -1, overwrite = false } = {}) {
835
+ async commit (state, { signature, keyPair, length = state.length, treeLength = -1 } = {}) {
836
836
  assert(this.isDefault() || (this.parent && this.parent.isDefault()), 'Can only commit into default state')
837
837
 
838
838
  let srcLocked = false
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hypercore",
3
- "version": "11.14.1",
3
+ "version": "11.15.0",
4
4
  "description": "Hypercore is a secure, distributed append-only log",
5
5
  "main": "index.js",
6
6
  "scripts": {