hypercore 10.0.0-alpha.10 → 10.0.0-alpha.14
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 +13 -0
- package/index.js +100 -77
- package/lib/streams.js +39 -0
- package/package.json +6 -2
- package/.github/workflows/test-node.yml +0 -23
- package/UPGRADE.md +0 -9
- package/__snapshots__/test/storage.js.snapshot.cjs +0 -15
- 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/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 -123
- 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/storage.js +0 -31
- package/test/user-data.js +0 -47
package/README.md
CHANGED
|
@@ -98,6 +98,19 @@ Truncate the core to a smaller length.
|
|
|
98
98
|
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
99
|
Note that the fork id should be monotonely incrementing.
|
|
100
100
|
|
|
101
|
+
#### `const stream = core.createReadStream([options])`
|
|
102
|
+
|
|
103
|
+
Make a read stream. Options include:
|
|
104
|
+
|
|
105
|
+
``` js
|
|
106
|
+
{
|
|
107
|
+
start: 0,
|
|
108
|
+
end: core.length,
|
|
109
|
+
live: false,
|
|
110
|
+
snapshot: true // auto set end to core.length on open or update it on every read
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
101
114
|
#### `const range = core.download([range])`
|
|
102
115
|
|
|
103
116
|
Download a range of data.
|
package/index.js
CHANGED
|
@@ -14,6 +14,7 @@ const Replicator = require('./lib/replicator')
|
|
|
14
14
|
const Extensions = require('./lib/extensions')
|
|
15
15
|
const Core = require('./lib/core')
|
|
16
16
|
const BlockEncryption = require('./lib/block-encryption')
|
|
17
|
+
const { ReadStream } = require('./lib/streams')
|
|
17
18
|
|
|
18
19
|
const promises = Symbol.for('hypercore.promises')
|
|
19
20
|
const inspect = Symbol.for('nodejs.util.inspect.custom')
|
|
@@ -65,7 +66,7 @@ module.exports = class Hypercore extends EventEmitter {
|
|
|
65
66
|
this.autoClose = !!opts.autoClose
|
|
66
67
|
|
|
67
68
|
this.closing = null
|
|
68
|
-
this.opening =
|
|
69
|
+
this.opening = this._openSession(key, storage, opts)
|
|
69
70
|
this.opening.catch(noop)
|
|
70
71
|
|
|
71
72
|
this._preappend = preappend.bind(this)
|
|
@@ -114,31 +115,22 @@ module.exports = class Hypercore extends EventEmitter {
|
|
|
114
115
|
}
|
|
115
116
|
|
|
116
117
|
const Clz = opts.class || Hypercore
|
|
117
|
-
const keyPair = opts.keyPair && opts.keyPair.secretKey && { ...opts.keyPair }
|
|
118
|
-
|
|
119
|
-
// This only works if the hypercore was fully loaded,
|
|
120
|
-
// but we only do this to validate the keypair to help catch bugs so yolo
|
|
121
|
-
if (this.key && keyPair) keyPair.publicKey = this.key
|
|
122
|
-
|
|
123
118
|
const s = new Clz(this.storage, this.key, {
|
|
124
119
|
...opts,
|
|
125
|
-
sign: opts.sign || (keyPair && keyPair.secretKey && Core.createSigner(this.crypto, keyPair)) || this.sign,
|
|
126
|
-
valueEncoding: this.valueEncoding,
|
|
127
120
|
extensions: this.extensions,
|
|
128
121
|
_opening: this.opening,
|
|
129
122
|
_sessions: this.sessions
|
|
130
123
|
})
|
|
131
124
|
|
|
132
|
-
s.
|
|
125
|
+
s._passCapabilities(this)
|
|
133
126
|
this.sessions.push(s)
|
|
134
127
|
|
|
135
128
|
return s
|
|
136
129
|
}
|
|
137
130
|
|
|
138
|
-
|
|
131
|
+
_passCapabilities (o) {
|
|
139
132
|
if (!this.sign) this.sign = o.sign
|
|
140
133
|
this.crypto = o.crypto
|
|
141
|
-
this.opened = o.opened
|
|
142
134
|
this.key = o.key
|
|
143
135
|
this.discoveryKey = o.discoveryKey
|
|
144
136
|
this.core = o.core
|
|
@@ -148,6 +140,98 @@ module.exports = class Hypercore extends EventEmitter {
|
|
|
148
140
|
this.autoClose = o.autoClose
|
|
149
141
|
}
|
|
150
142
|
|
|
143
|
+
async _openFromExisting (from, opts) {
|
|
144
|
+
await from.opening
|
|
145
|
+
|
|
146
|
+
for (const [name, ext] of this.extensions) {
|
|
147
|
+
from.extensions.register(name, null, ext)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
this._passCapabilities(from)
|
|
151
|
+
this.extensions = from.extensions
|
|
152
|
+
this.sessions = from.sessions
|
|
153
|
+
this.storage = from.storage
|
|
154
|
+
|
|
155
|
+
this.sessions.push(this)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
async _openSession (key, storage, opts) {
|
|
159
|
+
const isFirst = !opts._opening
|
|
160
|
+
|
|
161
|
+
if (!isFirst) await opts._opening
|
|
162
|
+
if (opts.preload) opts = { ...opts, ...(await opts.preload()) }
|
|
163
|
+
|
|
164
|
+
const keyPair = (key && opts.keyPair)
|
|
165
|
+
? { ...opts.keyPair, publicKey: key }
|
|
166
|
+
: key
|
|
167
|
+
? { publicKey: key, secretKey: null }
|
|
168
|
+
: opts.keyPair
|
|
169
|
+
|
|
170
|
+
// This only works if the hypercore was fully loaded,
|
|
171
|
+
// but we only do this to validate the keypair to help catch bugs so yolo
|
|
172
|
+
if (this.key && keyPair) keyPair.publicKey = this.key
|
|
173
|
+
|
|
174
|
+
if (opts.sign) {
|
|
175
|
+
this.sign = opts.sign
|
|
176
|
+
} else if (keyPair && keyPair.secretKey) {
|
|
177
|
+
this.sign = Core.createSigner(this.crypto, keyPair)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (isFirst) {
|
|
181
|
+
await this._openCapabilities(keyPair, storage, opts)
|
|
182
|
+
// Only the root session should pass capabilities to other sessions.
|
|
183
|
+
for (let i = 0; i < this.sessions.length; i++) {
|
|
184
|
+
const s = this.sessions[i]
|
|
185
|
+
if (s !== this) s._passCapabilities(this)
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (!this.sign) this.sign = this.core.defaultSign
|
|
190
|
+
this.writable = !!this.sign
|
|
191
|
+
|
|
192
|
+
if (opts.valueEncoding) {
|
|
193
|
+
this.valueEncoding = c.from(codecs(opts.valueEncoding))
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// This is a hidden option that's only used by Corestore.
|
|
197
|
+
// It's required so that corestore can load a name from userData before 'ready' is emitted.
|
|
198
|
+
if (opts._preready) await opts._preready(this)
|
|
199
|
+
|
|
200
|
+
this.opened = true
|
|
201
|
+
this.emit('ready')
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
async _openCapabilities (keyPair, storage, opts) {
|
|
205
|
+
if (opts.from) return this._openFromExisting(opts.from, opts)
|
|
206
|
+
|
|
207
|
+
this.storage = Hypercore.defaultStorage(opts.storage || storage)
|
|
208
|
+
|
|
209
|
+
this.core = await Core.open(this.storage, {
|
|
210
|
+
keyPair,
|
|
211
|
+
crypto: this.crypto,
|
|
212
|
+
onupdate: this._oncoreupdate.bind(this)
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
if (opts.userData) {
|
|
216
|
+
for (const [key, value] of Object.entries(opts.userData)) {
|
|
217
|
+
await this.core.userData(key, value)
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
this.replicator = new Replicator(this.core, {
|
|
222
|
+
onupdate: this._onpeerupdate.bind(this)
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
this.discoveryKey = this.crypto.discoveryKey(this.core.header.signer.publicKey)
|
|
226
|
+
this.key = this.core.header.signer.publicKey
|
|
227
|
+
|
|
228
|
+
if (!this.encryption && opts.encryptionKey) {
|
|
229
|
+
this.encryption = new BlockEncryption(opts.encryptionKey, this.key)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
this.extensions.attach(this.replicator)
|
|
233
|
+
}
|
|
234
|
+
|
|
151
235
|
close () {
|
|
152
236
|
if (this.closing) return this.closing
|
|
153
237
|
this.closing = this._close()
|
|
@@ -236,71 +320,6 @@ module.exports = class Hypercore extends EventEmitter {
|
|
|
236
320
|
return this.opening
|
|
237
321
|
}
|
|
238
322
|
|
|
239
|
-
async _open (key, storage, opts) {
|
|
240
|
-
if (opts.preload) opts = { ...opts, ...(await opts.preload()) }
|
|
241
|
-
|
|
242
|
-
this.valueEncoding = opts.valueEncoding ? c.from(codecs(opts.valueEncoding)) : null
|
|
243
|
-
|
|
244
|
-
const keyPair = (key && opts.keyPair)
|
|
245
|
-
? { ...opts.keyPair, publicKey: key }
|
|
246
|
-
: key
|
|
247
|
-
? { publicKey: key, secretKey: null }
|
|
248
|
-
: opts.keyPair
|
|
249
|
-
|
|
250
|
-
if (opts.from) {
|
|
251
|
-
const from = opts.from
|
|
252
|
-
await from.opening
|
|
253
|
-
for (const [name, ext] of this.extensions) from.extensions.register(name, null, ext)
|
|
254
|
-
this._initSession(from)
|
|
255
|
-
this.extensions = from.extensions
|
|
256
|
-
this.sessions = from.sessions
|
|
257
|
-
this.storage = from.storage
|
|
258
|
-
if (!this.sign) this.sign = opts.sign || ((keyPair && keyPair.secretKey) ? Core.createSigner(this.crypto, keyPair) : null)
|
|
259
|
-
this.writable = !!this.sign
|
|
260
|
-
this.sessions.push(this)
|
|
261
|
-
return
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
if (!this.storage) this.storage = Hypercore.defaultStorage(opts.storage || storage)
|
|
265
|
-
|
|
266
|
-
this.core = await Core.open(this.storage, {
|
|
267
|
-
keyPair,
|
|
268
|
-
crypto: this.crypto,
|
|
269
|
-
onupdate: this._oncoreupdate.bind(this)
|
|
270
|
-
})
|
|
271
|
-
|
|
272
|
-
if (opts.userData) {
|
|
273
|
-
for (const [key, value] of Object.entries(opts.userData)) {
|
|
274
|
-
await this.core.userData(key, value)
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
this.replicator = new Replicator(this.core, {
|
|
279
|
-
onupdate: this._onpeerupdate.bind(this)
|
|
280
|
-
})
|
|
281
|
-
|
|
282
|
-
if (!this.sign) this.sign = opts.sign || this.core.defaultSign
|
|
283
|
-
|
|
284
|
-
this.discoveryKey = this.crypto.discoveryKey(this.core.header.signer.publicKey)
|
|
285
|
-
this.key = this.core.header.signer.publicKey
|
|
286
|
-
this.writable = !!this.sign
|
|
287
|
-
|
|
288
|
-
if (!this.encryption && opts.encryptionKey) {
|
|
289
|
-
this.encryption = new BlockEncryption(opts.encryptionKey, this.key)
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
this.extensions.attach(this.replicator)
|
|
293
|
-
this.opened = true
|
|
294
|
-
|
|
295
|
-
if (opts.postload) await opts.postload(this)
|
|
296
|
-
|
|
297
|
-
for (let i = 0; i < this.sessions.length; i++) {
|
|
298
|
-
const s = this.sessions[i]
|
|
299
|
-
if (s !== this) s._initSession(this)
|
|
300
|
-
s.emit('ready')
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
|
|
304
323
|
_oncoreupdate (status, bitfield, value, from) {
|
|
305
324
|
if (status !== 0) {
|
|
306
325
|
for (let i = 0; i < this.sessions.length; i++) {
|
|
@@ -400,6 +419,10 @@ module.exports = class Hypercore extends EventEmitter {
|
|
|
400
419
|
return this._decode(encoding, block)
|
|
401
420
|
}
|
|
402
421
|
|
|
422
|
+
createReadStream (opts) {
|
|
423
|
+
return new ReadStream(this, opts)
|
|
424
|
+
}
|
|
425
|
+
|
|
403
426
|
download (range) {
|
|
404
427
|
const linear = !!(range && range.linear)
|
|
405
428
|
|
package/lib/streams.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const { Readable } = require('streamx')
|
|
2
|
+
|
|
3
|
+
class ReadStream extends Readable {
|
|
4
|
+
constructor (core, opts = {}) {
|
|
5
|
+
super()
|
|
6
|
+
|
|
7
|
+
this.core = core
|
|
8
|
+
this.start = opts.start || 0
|
|
9
|
+
this.end = typeof opts.end === 'number' ? opts.end : -1
|
|
10
|
+
this.snapshot = !opts.live && opts.snapshot !== false
|
|
11
|
+
this.live = !!opts.live
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
_open (cb) {
|
|
15
|
+
this._openP().then(cb, cb)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
_read (cb) {
|
|
19
|
+
this._readP().then(cb, cb)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async _openP () {
|
|
23
|
+
if (this.end === -1) await this.core.update()
|
|
24
|
+
else await this.core.ready()
|
|
25
|
+
if (this.snapshot && this.end === -1) this.end = this.core.length
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async _readP () {
|
|
29
|
+
const end = this.live ? -1 : (this.end === -1 ? this.core.length : this.end)
|
|
30
|
+
if (end >= 0 && this.start >= end) {
|
|
31
|
+
this.push(null)
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
this.push(await this.core.get(this.start++))
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
exports.ReadStream = ReadStream
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hypercore",
|
|
3
|
-
"version": "10.0.0-alpha.
|
|
3
|
+
"version": "10.0.0-alpha.14",
|
|
4
4
|
"description": "Hypercore 10",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -27,6 +27,10 @@
|
|
|
27
27
|
"url": "https://github.com/hypercore-protocol/hypercore/issues"
|
|
28
28
|
},
|
|
29
29
|
"homepage": "https://github.com/hypercore-protocol/hypercore#readme",
|
|
30
|
+
"files": [
|
|
31
|
+
"index.js",
|
|
32
|
+
"lib/**.js"
|
|
33
|
+
],
|
|
30
34
|
"dependencies": {
|
|
31
35
|
"@hyperswarm/secret-stream": "^5.0.0",
|
|
32
36
|
"b4a": "^1.1.0",
|
|
@@ -35,7 +39,7 @@
|
|
|
35
39
|
"compact-encoding": "^2.5.0",
|
|
36
40
|
"crc32-universal": "^1.0.1",
|
|
37
41
|
"flat-tree": "^1.9.0",
|
|
38
|
-
"hypercore-crypto": "^
|
|
42
|
+
"hypercore-crypto": "^3.1.0",
|
|
39
43
|
"is-options": "^1.0.1",
|
|
40
44
|
"random-access-file": "^2.1.4",
|
|
41
45
|
"random-array-iterator": "^1.0.0",
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
name: Build Status
|
|
2
|
-
on:
|
|
3
|
-
push:
|
|
4
|
-
branches:
|
|
5
|
-
- master
|
|
6
|
-
pull_request:
|
|
7
|
-
branches:
|
|
8
|
-
- master
|
|
9
|
-
jobs:
|
|
10
|
-
build:
|
|
11
|
-
strategy:
|
|
12
|
-
matrix:
|
|
13
|
-
node-version: [lts/*]
|
|
14
|
-
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
15
|
-
runs-on: ${{ matrix.os }}
|
|
16
|
-
steps:
|
|
17
|
-
- uses: actions/checkout@v2
|
|
18
|
-
- name: Use Node.js ${{ matrix.node-version }}
|
|
19
|
-
uses: actions/setup-node@v2
|
|
20
|
-
with:
|
|
21
|
-
node-version: ${{ matrix.node-version }}
|
|
22
|
-
- run: npm install
|
|
23
|
-
- run: npm test
|
package/UPGRADE.md
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
# Upgrade Notes
|
|
2
|
-
|
|
3
|
-
Notes for downstream developers who are upgrading their modules to new, breaking versions of hypercore.
|
|
4
|
-
|
|
5
|
-
## 9.0.0
|
|
6
|
-
|
|
7
|
-
- The format of signatures [has been changed](https://github.com/mafintosh/hypercore/issues/260). This is backwards-compatible (v9 can read v8 signatures), but forward-incompatible (v8 cannot read v9 signatures). If a v8 peer replicates with a v9 peer, it will emit a "REMOTE SIGNTURE INVALID" error on the replication stream.
|
|
8
|
-
- The encryption ([NOISE](https://github.com/emilbayes/noise-protocol)) handshake has been changed in an backwards- and forwards-incompatible way. v8 peers can not handshake with v9 peers, and vice-versa. A NOISE-related error is emitted on the replication stream.
|
|
9
|
-
- There is no way (yet) to detect whether a peer is running an incompatible version of hypercore at the replication level. One workaround for downstream developers is to include their own application-level handshake before piping to the replication stream, to communicate a "app protocol version" (maybe "v8" and "v9") and abort the connection if the peer is running an incompatible version.
|