hypercore 10.0.0-alpha.11 → 10.0.0-alpha.15

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
@@ -63,6 +63,7 @@ Note that `tree`, `data`, and `bitfield` are normally heavily sparse files.
63
63
  createIfMissing: true, // create a new Hypercore key pair if none was present in storage
64
64
  overwrite: false, // overwrite any old Hypercore that might already exist
65
65
  valueEncoding: 'json' | 'utf-8' | 'binary', // defaults to binary
66
+ encodeBatch: batch => { ... }, // optionally apply an encoding to complete batches
66
67
  keyPair: kp, // optionally pass the public key and secret key as a key pair
67
68
  encryptionKey: k // optionally pass an encryption key to enable block encryption
68
69
  }
@@ -70,6 +71,8 @@ Note that `tree`, `data`, and `bitfield` are normally heavily sparse files.
70
71
 
71
72
  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
73
 
74
+ 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`.
75
+
73
76
  #### `const seq = await core.append(block)`
74
77
 
75
78
  Append a block of data (or an array of blocks) to the core.
package/index.js CHANGED
@@ -55,6 +55,8 @@ module.exports = class Hypercore extends EventEmitter {
55
55
  this.cache = opts.cache === true ? new Xache({ maxSize: 65536, maxAge: 0 }) : (opts.cache || null)
56
56
 
57
57
  this.valueEncoding = null
58
+ this.encodeBatch = null
59
+
58
60
  this.key = key || null
59
61
  this.discoveryKey = null
60
62
  this.readable = true
@@ -66,7 +68,7 @@ module.exports = class Hypercore extends EventEmitter {
66
68
  this.autoClose = !!opts.autoClose
67
69
 
68
70
  this.closing = null
69
- this.opening = opts._opening || this._open(key, storage, opts)
71
+ this.opening = this._openSession(key, storage, opts)
70
72
  this.opening.catch(noop)
71
73
 
72
74
  this._preappend = preappend.bind(this)
@@ -115,31 +117,22 @@ module.exports = class Hypercore extends EventEmitter {
115
117
  }
116
118
 
117
119
  const Clz = opts.class || Hypercore
118
- const keyPair = opts.keyPair && opts.keyPair.secretKey && { ...opts.keyPair }
119
-
120
- // This only works if the hypercore was fully loaded,
121
- // but we only do this to validate the keypair to help catch bugs so yolo
122
- if (this.key && keyPair) keyPair.publicKey = this.key
123
-
124
120
  const s = new Clz(this.storage, this.key, {
125
121
  ...opts,
126
- sign: opts.sign || (keyPair && keyPair.secretKey && Core.createSigner(this.crypto, keyPair)) || this.sign,
127
- valueEncoding: this.valueEncoding,
128
122
  extensions: this.extensions,
129
123
  _opening: this.opening,
130
124
  _sessions: this.sessions
131
125
  })
132
126
 
133
- s._initSession(this)
127
+ s._passCapabilities(this)
134
128
  this.sessions.push(s)
135
129
 
136
130
  return s
137
131
  }
138
132
 
139
- _initSession (o) {
133
+ _passCapabilities (o) {
140
134
  if (!this.sign) this.sign = o.sign
141
135
  this.crypto = o.crypto
142
- this.opened = o.opened
143
136
  this.key = o.key
144
137
  this.discoveryKey = o.discoveryKey
145
138
  this.core = o.core
@@ -149,6 +142,101 @@ module.exports = class Hypercore extends EventEmitter {
149
142
  this.autoClose = o.autoClose
150
143
  }
151
144
 
145
+ async _openFromExisting (from, opts) {
146
+ await from.opening
147
+
148
+ for (const [name, ext] of this.extensions) {
149
+ from.extensions.register(name, null, ext)
150
+ }
151
+
152
+ this._passCapabilities(from)
153
+ this.extensions = from.extensions
154
+ this.sessions = from.sessions
155
+ this.storage = from.storage
156
+
157
+ this.sessions.push(this)
158
+ }
159
+
160
+ async _openSession (key, storage, opts) {
161
+ const isFirst = !opts._opening
162
+
163
+ if (!isFirst) await opts._opening
164
+ if (opts.preload) opts = { ...opts, ...(await opts.preload()) }
165
+
166
+ const keyPair = (key && opts.keyPair)
167
+ ? { ...opts.keyPair, publicKey: key }
168
+ : key
169
+ ? { publicKey: key, secretKey: null }
170
+ : opts.keyPair
171
+
172
+ // This only works if the hypercore was fully loaded,
173
+ // but we only do this to validate the keypair to help catch bugs so yolo
174
+ if (this.key && keyPair) keyPair.publicKey = this.key
175
+
176
+ if (opts.sign) {
177
+ this.sign = opts.sign
178
+ } else if (keyPair && keyPair.secretKey) {
179
+ this.sign = Core.createSigner(this.crypto, keyPair)
180
+ }
181
+
182
+ if (isFirst) {
183
+ await this._openCapabilities(keyPair, storage, opts)
184
+ // Only the root session should pass capabilities to other sessions.
185
+ for (let i = 0; i < this.sessions.length; i++) {
186
+ const s = this.sessions[i]
187
+ if (s !== this) s._passCapabilities(this)
188
+ }
189
+ }
190
+
191
+ if (!this.sign) this.sign = this.core.defaultSign
192
+ this.writable = !!this.sign
193
+
194
+ if (opts.valueEncoding) {
195
+ this.valueEncoding = c.from(codecs(opts.valueEncoding))
196
+ }
197
+ if (opts.encodeBatch) {
198
+ this.encodeBatch = opts.encodeBatch
199
+ }
200
+
201
+ // This is a hidden option that's only used by Corestore.
202
+ // It's required so that corestore can load a name from userData before 'ready' is emitted.
203
+ if (opts._preready) await opts._preready(this)
204
+
205
+ this.opened = true
206
+ this.emit('ready')
207
+ }
208
+
209
+ async _openCapabilities (keyPair, storage, opts) {
210
+ if (opts.from) return this._openFromExisting(opts.from, opts)
211
+
212
+ this.storage = Hypercore.defaultStorage(opts.storage || storage)
213
+
214
+ this.core = await Core.open(this.storage, {
215
+ keyPair,
216
+ crypto: this.crypto,
217
+ onupdate: this._oncoreupdate.bind(this)
218
+ })
219
+
220
+ if (opts.userData) {
221
+ for (const [key, value] of Object.entries(opts.userData)) {
222
+ await this.core.userData(key, value)
223
+ }
224
+ }
225
+
226
+ this.replicator = new Replicator(this.core, {
227
+ onupdate: this._onpeerupdate.bind(this)
228
+ })
229
+
230
+ this.discoveryKey = this.crypto.discoveryKey(this.core.header.signer.publicKey)
231
+ this.key = this.core.header.signer.publicKey
232
+
233
+ if (!this.encryption && opts.encryptionKey) {
234
+ this.encryption = new BlockEncryption(opts.encryptionKey, this.key)
235
+ }
236
+
237
+ this.extensions.attach(this.replicator)
238
+ }
239
+
152
240
  close () {
153
241
  if (this.closing) return this.closing
154
242
  this.closing = this._close()
@@ -237,71 +325,6 @@ module.exports = class Hypercore extends EventEmitter {
237
325
  return this.opening
238
326
  }
239
327
 
240
- async _open (key, storage, opts) {
241
- if (opts.preload) opts = { ...opts, ...(await opts.preload()) }
242
-
243
- this.valueEncoding = opts.valueEncoding ? c.from(codecs(opts.valueEncoding)) : null
244
-
245
- const keyPair = (key && opts.keyPair)
246
- ? { ...opts.keyPair, publicKey: key }
247
- : key
248
- ? { publicKey: key, secretKey: null }
249
- : opts.keyPair
250
-
251
- if (opts.from) {
252
- const from = opts.from
253
- await from.opening
254
- for (const [name, ext] of this.extensions) from.extensions.register(name, null, ext)
255
- this._initSession(from)
256
- this.extensions = from.extensions
257
- this.sessions = from.sessions
258
- this.storage = from.storage
259
- if (!this.sign) this.sign = opts.sign || ((keyPair && keyPair.secretKey) ? Core.createSigner(this.crypto, keyPair) : null)
260
- this.writable = !!this.sign
261
- this.sessions.push(this)
262
- return
263
- }
264
-
265
- if (!this.storage) this.storage = Hypercore.defaultStorage(opts.storage || storage)
266
-
267
- this.core = await Core.open(this.storage, {
268
- keyPair,
269
- crypto: this.crypto,
270
- onupdate: this._oncoreupdate.bind(this)
271
- })
272
-
273
- if (opts.userData) {
274
- for (const [key, value] of Object.entries(opts.userData)) {
275
- await this.core.userData(key, value)
276
- }
277
- }
278
-
279
- this.replicator = new Replicator(this.core, {
280
- onupdate: this._onpeerupdate.bind(this)
281
- })
282
-
283
- if (!this.sign) this.sign = opts.sign || this.core.defaultSign
284
-
285
- this.discoveryKey = this.crypto.discoveryKey(this.core.header.signer.publicKey)
286
- this.key = this.core.header.signer.publicKey
287
- this.writable = !!this.sign
288
-
289
- if (!this.encryption && opts.encryptionKey) {
290
- this.encryption = new BlockEncryption(opts.encryptionKey, this.key)
291
- }
292
-
293
- this.extensions.attach(this.replicator)
294
- this.opened = true
295
-
296
- if (opts.postload) await opts.postload(this)
297
-
298
- for (let i = 0; i < this.sessions.length; i++) {
299
- const s = this.sessions[i]
300
- if (s !== this) s._initSession(this)
301
- s.emit('ready')
302
- }
303
- }
304
-
305
328
  _oncoreupdate (status, bitfield, value, from) {
306
329
  if (status !== 0) {
307
330
  for (let i = 0; i < this.sessions.length; i++) {
@@ -462,10 +485,13 @@ module.exports = class Hypercore extends EventEmitter {
462
485
  blocks = Array.isArray(blocks) ? blocks : [blocks]
463
486
 
464
487
  const preappend = this.encryption && this._preappend
465
- const buffers = new Array(blocks.length)
466
488
 
467
- for (let i = 0; i < blocks.length; i++) {
468
- buffers[i] = this._encode(this.valueEncoding, blocks[i])
489
+ const buffers = this.encodeBatch !== null ? this.encodeBatch(blocks) : new Array(blocks.length)
490
+
491
+ if (this.encodeBatch === null) {
492
+ for (let i = 0; i < blocks.length; i++) {
493
+ buffers[i] = this._encode(this.valueEncoding, blocks[i])
494
+ }
469
495
  }
470
496
 
471
497
  return await this.core.append(buffers, this.sign, { preappend })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hypercore",
3
- "version": "10.0.0-alpha.11",
3
+ "version": "10.0.0-alpha.15",
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",
@@ -34,8 +38,9 @@
34
38
  "codecs": "^2.2.0",
35
39
  "compact-encoding": "^2.5.0",
36
40
  "crc32-universal": "^1.0.1",
41
+ "events": "^3.3.0",
37
42
  "flat-tree": "^1.9.0",
38
- "hypercore-crypto": "^2.1.1",
43
+ "hypercore-crypto": "^3.1.0",
39
44
  "is-options": "^1.0.1",
40
45
  "random-access-file": "^2.1.4",
41
46
  "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.