hypercore 10.0.0-alpha.9 → 10.0.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 +83 -22
- package/index.js +583 -212
- package/lib/bitfield.js +109 -41
- package/lib/block-encryption.js +3 -2
- package/lib/block-store.js +6 -4
- package/lib/caps.js +32 -0
- package/lib/core.js +166 -35
- package/lib/errors.js +50 -0
- package/lib/info.js +23 -0
- package/lib/merkle-tree.js +181 -105
- package/lib/messages.js +249 -168
- package/lib/oplog.js +4 -3
- package/lib/remote-bitfield.js +28 -7
- package/lib/replicator.js +1415 -624
- package/lib/streams.js +56 -0
- package/package.json +20 -15
- package/.github/workflows/test-node.yml +0 -23
- package/CHANGELOG.md +0 -37
- package/UPGRADE.md +0 -9
- package/examples/announce.js +0 -19
- package/examples/basic.js +0 -10
- package/examples/http.js +0 -123
- package/examples/lookup.js +0 -20
- package/lib/extensions.js +0 -76
- package/lib/protocol.js +0 -524
- package/lib/random-iterator.js +0 -46
- package/test/basic.js +0 -90
- package/test/bitfield.js +0 -71
- package/test/core.js +0 -290
- package/test/encodings.js +0 -18
- package/test/encryption.js +0 -121
- package/test/extension.js +0 -71
- package/test/helpers/index.js +0 -23
- package/test/merkle-tree.js +0 -518
- package/test/mutex.js +0 -137
- package/test/oplog.js +0 -399
- package/test/preload.js +0 -72
- package/test/replicate.js +0 -372
- package/test/sessions.js +0 -173
- package/test/user-data.js +0 -47
package/README.md
CHANGED
|
@@ -1,21 +1,24 @@
|
|
|
1
|
-
# Hypercore
|
|
1
|
+
# Hypercore
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Hypercore is a secure, distributed append-only log.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Built for sharing large datasets and streams of real time data
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
* Fork recovery
|
|
9
|
-
* Promises
|
|
10
|
-
* Simplications and performance/scaling improvements
|
|
11
|
-
* Internal oplog design
|
|
7
|
+
## Features
|
|
12
8
|
|
|
13
|
-
|
|
9
|
+
* **Sparse replication.** Only download the data you are interested in.
|
|
10
|
+
* **Realtime.** Get the latest updates to the log fast and securely.
|
|
11
|
+
* **Performant.** Uses a simple flat file structure to maximize I/O performance.
|
|
12
|
+
* **Secure.** Uses signed merkle trees to verify log integrity in real time.
|
|
13
|
+
* **Modular.** Hypercore aims to do one thing and one thing well - distributing a stream of data.
|
|
14
|
+
|
|
15
|
+
Note that the latest release is Hypercore 10, which adds support for truncate and many other things.
|
|
16
|
+
Version 10 is not compatible with earlier versions (9 and earlier), but is considered LTS, meaning the storage format and wire protocol is forward compatible with future versions.
|
|
14
17
|
|
|
15
|
-
Install
|
|
18
|
+
## Install
|
|
16
19
|
|
|
17
20
|
```sh
|
|
18
|
-
npm install hypercore
|
|
21
|
+
npm install hypercore
|
|
19
22
|
```
|
|
20
23
|
|
|
21
24
|
## API
|
|
@@ -33,13 +36,13 @@ const core = new Hypercore('./directory') // store data in ./directory
|
|
|
33
36
|
Alternatively you can pass a function instead that is called with every filename Hypercore needs to function and return your own [abstract-random-access](https://github.com/random-access-storage/abstract-random-access) instance that is used to store the data.
|
|
34
37
|
|
|
35
38
|
``` js
|
|
36
|
-
const
|
|
39
|
+
const RAM = require('random-access-memory')
|
|
37
40
|
const core = new Hypercore((filename) => {
|
|
38
41
|
// filename will be one of: data, bitfield, tree, signatures, key, secret_key
|
|
39
42
|
// the data file will contain all your data concatenated.
|
|
40
43
|
|
|
41
44
|
// just store all files in ram by returning a random-access-memory instance
|
|
42
|
-
return
|
|
45
|
+
return new RAM()
|
|
43
46
|
})
|
|
44
47
|
```
|
|
45
48
|
|
|
@@ -62,18 +65,23 @@ Note that `tree`, `data`, and `bitfield` are normally heavily sparse files.
|
|
|
62
65
|
{
|
|
63
66
|
createIfMissing: true, // create a new Hypercore key pair if none was present in storage
|
|
64
67
|
overwrite: false, // overwrite any old Hypercore that might already exist
|
|
68
|
+
sparse: true, // enable sparse mode, counting unavailable blocks towards core.length and core.byteLength
|
|
65
69
|
valueEncoding: 'json' | 'utf-8' | 'binary', // defaults to binary
|
|
70
|
+
encodeBatch: batch => { ... }, // optionally apply an encoding to complete batches
|
|
66
71
|
keyPair: kp, // optionally pass the public key and secret key as a key pair
|
|
67
|
-
encryptionKey: k // optionally pass an encryption key to enable block encryption
|
|
72
|
+
encryptionKey: k, // optionally pass an encryption key to enable block encryption
|
|
73
|
+
onwait: () => {} // hook that is called if gets are waiting for download
|
|
68
74
|
}
|
|
69
75
|
```
|
|
70
76
|
|
|
71
77
|
You can also set valueEncoding to any [abstract-encoding](https://github.com/mafintosh/abstract-encoding) or [compact-encoding](https://github.com/compact-encoding) instance.
|
|
72
78
|
|
|
73
|
-
|
|
79
|
+
valueEncodings will be applied to individually blocks, even if you append batches. If you want to control encoding at the batch-level, you can use the `encodeBatch` option, which is a function that takes a batch and returns a binary-encoded batch. If you provide a custom valueEncoding, it will not be applied prior to `encodeBatch`.
|
|
80
|
+
|
|
81
|
+
#### `const { length, byteLength } = await core.append(block)`
|
|
74
82
|
|
|
75
83
|
Append a block of data (or an array of blocks) to the core.
|
|
76
|
-
Returns the
|
|
84
|
+
Returns the new length and byte length of the core.
|
|
77
85
|
|
|
78
86
|
#### `const block = await core.get(index, [options])`
|
|
79
87
|
|
|
@@ -84,7 +92,7 @@ Options include
|
|
|
84
92
|
|
|
85
93
|
``` js
|
|
86
94
|
{
|
|
87
|
-
wait: true, // wait for
|
|
95
|
+
wait: true, // wait for block to be downloaded
|
|
88
96
|
onwait: () => {}, // hook that is called if the get is waiting for download
|
|
89
97
|
timeout: 0, // wait at max some milliseconds (0 means no timeout)
|
|
90
98
|
valueEncoding: 'json' | 'utf-8' | 'binary' // defaults to the core's valueEncoding
|
|
@@ -98,6 +106,23 @@ Truncate the core to a smaller length.
|
|
|
98
106
|
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.
|
|
99
107
|
Note that the fork id should be monotonely incrementing.
|
|
100
108
|
|
|
109
|
+
#### `const hash = await core.treeHash([length])`
|
|
110
|
+
|
|
111
|
+
Get the Merkle Tree hash of the core at a given length, defaulting to the current length of the core.
|
|
112
|
+
|
|
113
|
+
#### `const stream = core.createReadStream([options])`
|
|
114
|
+
|
|
115
|
+
Make a read stream. Options include:
|
|
116
|
+
|
|
117
|
+
``` js
|
|
118
|
+
{
|
|
119
|
+
start: 0,
|
|
120
|
+
end: core.length,
|
|
121
|
+
live: false,
|
|
122
|
+
snapshot: true // auto set end to core.length on open or update it on every read
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
101
126
|
#### `const range = core.download([range])`
|
|
102
127
|
|
|
103
128
|
Download a range of data.
|
|
@@ -130,7 +155,7 @@ core.download({ start: 0, end: -1 })
|
|
|
130
155
|
To downloaded a discrete range of blocks pass a list of indices.
|
|
131
156
|
|
|
132
157
|
```js
|
|
133
|
-
core.download({ blocks: [4, 9, 7] })
|
|
158
|
+
core.download({ blocks: [4, 9, 7] })
|
|
134
159
|
```
|
|
135
160
|
|
|
136
161
|
To cancel downloading a range simply destroy the range instance.
|
|
@@ -157,6 +182,23 @@ const updated = await core.update()
|
|
|
157
182
|
console.log('core was updated?', updated, 'length is', core.length)
|
|
158
183
|
```
|
|
159
184
|
|
|
185
|
+
#### `const info = await core.info()`
|
|
186
|
+
|
|
187
|
+
Get information about this core, such as its total size in bytes.
|
|
188
|
+
|
|
189
|
+
The object will look like this:
|
|
190
|
+
|
|
191
|
+
```js
|
|
192
|
+
Info {
|
|
193
|
+
key: Buffer(...),
|
|
194
|
+
length: 18,
|
|
195
|
+
contiguousLength: 16,
|
|
196
|
+
byteLength: 742,
|
|
197
|
+
fork: 0,
|
|
198
|
+
padding: 8
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
160
202
|
#### `await core.close()`
|
|
161
203
|
|
|
162
204
|
Fully close this core.
|
|
@@ -196,6 +238,12 @@ Buffer containing the public key identifying this core.
|
|
|
196
238
|
|
|
197
239
|
Populated after `ready` has been emitted. Will be `null` before the event.
|
|
198
240
|
|
|
241
|
+
#### `core.keyPair`
|
|
242
|
+
|
|
243
|
+
Object containing buffers of the core's public and secret key
|
|
244
|
+
|
|
245
|
+
Populated after `ready` has been emitted. Will be `null` before the event.
|
|
246
|
+
|
|
199
247
|
#### `core.discoveryKey`
|
|
200
248
|
|
|
201
249
|
Buffer containing a key derived from the core's public key.
|
|
@@ -209,13 +257,19 @@ Buffer containing the optional block encryption key of this core. Will be `null`
|
|
|
209
257
|
|
|
210
258
|
#### `core.length`
|
|
211
259
|
|
|
212
|
-
How many blocks of data are available on this core?
|
|
260
|
+
How many blocks of data are available on this core? If `sparse: false`, this will equal `core.contiguousLength`.
|
|
213
261
|
|
|
214
262
|
Populated after `ready` has been emitted. Will be `0` before the event.
|
|
215
263
|
|
|
216
|
-
#### `core.
|
|
264
|
+
#### `core.contiguousLength`
|
|
217
265
|
|
|
218
|
-
How
|
|
266
|
+
How many blocks are contiguously available starting from the first block of this core?
|
|
267
|
+
|
|
268
|
+
Populated after `ready` has been emitted. Will be `0` before the event.
|
|
269
|
+
|
|
270
|
+
#### `core.contiguousByteLength`
|
|
271
|
+
|
|
272
|
+
How much data is contiguously available starting from the first block of this core?
|
|
219
273
|
|
|
220
274
|
Populated after `ready` has been emitted. Will be `0` before the event.
|
|
221
275
|
|
|
@@ -254,10 +308,17 @@ const socket = net.connect(...)
|
|
|
254
308
|
socket.pipe(localCore.replicate(true)).pipe(socket)
|
|
255
309
|
```
|
|
256
310
|
|
|
311
|
+
#### `const done = core.findingPeers()`
|
|
312
|
+
|
|
313
|
+
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.
|
|
314
|
+
If you're using Hyperswarm, you'd normally call this after a `swarm.flush()` finishes.
|
|
315
|
+
|
|
316
|
+
This allows `core.update` to wait for either the `findingPeers` hook to finish or one peer to appear before deciding whether it should wait for a merkle tree update before returning.
|
|
317
|
+
|
|
257
318
|
#### `core.on('append')`
|
|
258
319
|
|
|
259
320
|
Emitted when the core has been appended to (i.e. has a new length / byteLength), either locally or remotely.
|
|
260
321
|
|
|
261
|
-
#### `core.on('truncate')`
|
|
322
|
+
#### `core.on('truncate', ancestors, forkId)`
|
|
262
323
|
|
|
263
324
|
Emitted when the core has been truncated, either locally or remotely.
|