corestore 7.4.8 → 7.6.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 +22 -5
- package/index.js +117 -80
- package/lib/audit.js +1 -1
- package/package.json +6 -4
package/README.md
CHANGED
|
@@ -5,12 +5,14 @@
|
|
|
5
5
|
Corestore is a Hypercore factory that makes it easier to manage large collections of named Hypercores.
|
|
6
6
|
|
|
7
7
|
Corestore provides:
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
|
|
9
|
+
1. **Key Derivation** - All writable Hypercore keys are derived from a single master key and a user-provided name.
|
|
10
|
+
2. **Session Handling** - If a single Hypercore is loaded multiple times through the `get` method, the underlying resources will only be opened once (using Hypercore 10's new session feature). Once all sessions are closed, the resources will be released.
|
|
11
|
+
3. **Storage Management** - Hypercores can be stored in any `hypercore-storage` instance, where they will be keyed by their discovery keys.
|
|
12
|
+
4. **Namespacing** - You can share a single Corestore instance between multiple applications or components without worrying about naming collisions by creating "namespaces" (e.g. `corestore.namespace('my-app').get({ name: 'main' })`)
|
|
12
13
|
|
|
13
14
|
### Installation
|
|
15
|
+
|
|
14
16
|
`npm install corestore`
|
|
15
17
|
|
|
16
18
|
> [!NOTE]
|
|
@@ -19,7 +21,9 @@ Corestore provides:
|
|
|
19
21
|
> It will be updated to 11 in a few weeks.
|
|
20
22
|
|
|
21
23
|
### Usage
|
|
24
|
+
|
|
22
25
|
A corestore instance can be constructed with a `hypercore-storage` instance, or a string. If a string is specified, it will be assumed to be a path to a local storage directory:
|
|
26
|
+
|
|
23
27
|
```js
|
|
24
28
|
const Corestore = require('corestore')
|
|
25
29
|
|
|
@@ -46,6 +50,7 @@ Options:
|
|
|
46
50
|
```
|
|
47
51
|
|
|
48
52
|
#### `const core = store.get(key | { name: 'a-name', ...hypercoreOpts})`
|
|
53
|
+
|
|
49
54
|
Loads a Hypercore, either by name (if the `name` option is provided), or from the provided key (if the first argument is a Buffer or String with hex/z32 key, or if the `key` options is set).
|
|
50
55
|
|
|
51
56
|
If that Hypercore has previously been loaded, subsequent calls to `get` will return a new Hypercore session on the existing core.
|
|
@@ -53,6 +58,7 @@ If that Hypercore has previously been loaded, subsequent calls to `get` will ret
|
|
|
53
58
|
All other options besides `name` and `key` will be forwarded to the Hypercore constructor.
|
|
54
59
|
|
|
55
60
|
#### `const stream = store.replicate(optsOrStream)`
|
|
61
|
+
|
|
56
62
|
Creates a replication stream that's capable of replicating all Hypercores that are managed by the Corestore, assuming the remote peer has the correct capabilities.
|
|
57
63
|
|
|
58
64
|
`opts` will be forwarded to Hypercore's `replicate` function.
|
|
@@ -63,7 +69,7 @@ If the remote side dynamically adds a new Hypercore to the replication stream, C
|
|
|
63
69
|
|
|
64
70
|
Using [Hyperswarm](https://github.com/holepunchto/hyperswarm) you can easily replicate corestores
|
|
65
71
|
|
|
66
|
-
```
|
|
72
|
+
```js
|
|
67
73
|
const swarm = new Hyperswarm()
|
|
68
74
|
|
|
69
75
|
// join the relevant topic
|
|
@@ -74,12 +80,15 @@ swarm.on('connection', (connection) => store.replicate(connection))
|
|
|
74
80
|
```
|
|
75
81
|
|
|
76
82
|
#### `const storeB = storeA.session()`
|
|
83
|
+
|
|
77
84
|
Create a new Corestore session. Closing a session will close all cores made from this session.
|
|
78
85
|
|
|
79
86
|
#### `const store = store.namespace(name)`
|
|
87
|
+
|
|
80
88
|
Create a new namespaced Corestore session. Namespacing is useful if you're going to be sharing a single Corestore instance between many applications or components, as it prevents name collisions.
|
|
81
89
|
|
|
82
90
|
Namespaces can be chained:
|
|
91
|
+
|
|
83
92
|
```js
|
|
84
93
|
const ns1 = store.namespace('a')
|
|
85
94
|
const ns2 = ns1.namespace('b')
|
|
@@ -88,9 +97,11 @@ const core2 = ns2.get({ name: 'main' })
|
|
|
88
97
|
```
|
|
89
98
|
|
|
90
99
|
#### `const stream = store.list(namespace)`
|
|
100
|
+
|
|
91
101
|
Creates a discovery key stream of all cores within a namespace or all cores in general if no namespace is provided.
|
|
92
102
|
|
|
93
103
|
#### `store.watch((core) => {})`
|
|
104
|
+
|
|
94
105
|
Register a callback called when new Hypercores are opened. `core` is the internal core for the opened Hypercore. It can be used to create weak references to a Hypercore like so:
|
|
95
106
|
|
|
96
107
|
```
|
|
@@ -100,21 +111,27 @@ store.watch(function (core) {
|
|
|
100
111
|
```
|
|
101
112
|
|
|
102
113
|
#### `store.unwatch(callback)`
|
|
114
|
+
|
|
103
115
|
Unregister a callback used with `store.watch(callback)` so it no longer fires.
|
|
104
116
|
|
|
105
117
|
#### `await store.suspend()`
|
|
118
|
+
|
|
106
119
|
Suspend the underlying storage for the Corestore.
|
|
107
120
|
|
|
108
121
|
#### `await store.resume()`
|
|
122
|
+
|
|
109
123
|
Resume a suspended Corestore.
|
|
110
124
|
|
|
111
125
|
#### `const keypair = await store.createKeyPair(name, ns = this.ns)`
|
|
126
|
+
|
|
112
127
|
Generate a key pair seeded with the Corestore's primary key using a `name` and a `ns` aka namespace. `ns` defaults to the current namespace.
|
|
113
128
|
|
|
114
129
|
This is useful for creating deterministic key pairs that are unique to a peer.
|
|
115
130
|
|
|
116
131
|
#### `await store.close()`
|
|
132
|
+
|
|
117
133
|
Fully close this Corestore instance.
|
|
118
134
|
|
|
119
135
|
### License
|
|
136
|
+
|
|
120
137
|
MIT
|
package/index.js
CHANGED
|
@@ -5,7 +5,7 @@ const sodium = require('sodium-universal')
|
|
|
5
5
|
const crypto = require('hypercore-crypto')
|
|
6
6
|
const ID = require('hypercore-id-encoding')
|
|
7
7
|
const { isAndroid } = require('which-runtime')
|
|
8
|
-
const { STORAGE_EMPTY } = require('hypercore-errors')
|
|
8
|
+
const { STORAGE_EMPTY, ASSERTION } = require('hypercore-errors')
|
|
9
9
|
|
|
10
10
|
const auditStore = require('./lib/audit.js')
|
|
11
11
|
|
|
@@ -13,23 +13,23 @@ const [NS] = crypto.namespace('corestore', 1)
|
|
|
13
13
|
const DEFAULT_NAMESPACE = b4a.alloc(32) // This is meant to be 32 0-bytes
|
|
14
14
|
|
|
15
15
|
class StreamTracker {
|
|
16
|
-
constructor
|
|
16
|
+
constructor() {
|
|
17
17
|
this.records = []
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
add
|
|
20
|
+
add(stream, isExternal) {
|
|
21
21
|
const record = { index: 0, stream, isExternal }
|
|
22
22
|
record.index = this.records.push(record) - 1
|
|
23
23
|
return record
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
remove
|
|
26
|
+
remove(record) {
|
|
27
27
|
const popped = this.records.pop()
|
|
28
28
|
if (popped === record) return
|
|
29
29
|
this.records[(popped.index = record.index)] = popped
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
attachAll
|
|
32
|
+
attachAll(core) {
|
|
33
33
|
for (let i = 0; i < this.records.length; i++) {
|
|
34
34
|
const record = this.records[i]
|
|
35
35
|
const muxer = record.stream.noiseStream.userData
|
|
@@ -37,7 +37,7 @@ class StreamTracker {
|
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
destroy
|
|
40
|
+
destroy() {
|
|
41
41
|
// reverse is safer cause we delete mb
|
|
42
42
|
for (let i = this.records.length - 1; i >= 0; i--) {
|
|
43
43
|
const record = this.records[i]
|
|
@@ -47,15 +47,15 @@ class StreamTracker {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
class SessionTracker {
|
|
50
|
-
constructor
|
|
50
|
+
constructor() {
|
|
51
51
|
this.map = new Map()
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
get size
|
|
54
|
+
get size() {
|
|
55
55
|
return this.map.size
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
get
|
|
58
|
+
get(id) {
|
|
59
59
|
const existing = this.map.get(id)
|
|
60
60
|
if (existing !== undefined) return existing
|
|
61
61
|
const fresh = []
|
|
@@ -63,23 +63,23 @@ class SessionTracker {
|
|
|
63
63
|
return fresh
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
gc
|
|
66
|
+
gc(id) {
|
|
67
67
|
this.map.delete(id)
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
list
|
|
71
|
-
return id ?
|
|
70
|
+
list(id) {
|
|
71
|
+
return id ? this.map.get(id) || [] : [...this]
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
*
|
|
74
|
+
*[Symbol.iterator]() {
|
|
75
75
|
for (const sessions of this.map.values()) {
|
|
76
|
-
yield
|
|
76
|
+
yield* sessions[Symbol.iterator]()
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
class CoreTracker {
|
|
82
|
-
constructor
|
|
82
|
+
constructor() {
|
|
83
83
|
this.map = new Map()
|
|
84
84
|
this.watching = []
|
|
85
85
|
|
|
@@ -88,23 +88,23 @@ class CoreTracker {
|
|
|
88
88
|
this._gcCycleBound = this._gcCycle.bind(this)
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
get size
|
|
91
|
+
get size() {
|
|
92
92
|
return this.map.size
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
watch
|
|
95
|
+
watch(store) {
|
|
96
96
|
if (store.watchIndex !== -1) return
|
|
97
97
|
store.watchIndex = this.watching.push(store) - 1
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
unwatch
|
|
100
|
+
unwatch(store) {
|
|
101
101
|
if (store.watchIndex === -1) return
|
|
102
102
|
const head = this.watching.pop()
|
|
103
103
|
if (head !== store) this.watching[(head.watchIndex = store.watchIndex)] = head
|
|
104
104
|
store.watchIndex = -1
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
-
resume
|
|
107
|
+
resume(id) {
|
|
108
108
|
const core = this.map.get(id)
|
|
109
109
|
|
|
110
110
|
if (!core) return null
|
|
@@ -121,12 +121,12 @@ class CoreTracker {
|
|
|
121
121
|
return core
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
opened
|
|
124
|
+
opened(id) {
|
|
125
125
|
const core = this.map.get(id)
|
|
126
126
|
return !!(core && core.opened && !core.closing)
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
get
|
|
129
|
+
get(id) {
|
|
130
130
|
// we allow you do call this from the outside, so support normal buffers also
|
|
131
131
|
if (b4a.isBuffer(id)) id = b4a.toString(id, 'hex')
|
|
132
132
|
const core = this.map.get(id)
|
|
@@ -134,24 +134,24 @@ class CoreTracker {
|
|
|
134
134
|
return core
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
-
set
|
|
137
|
+
set(id, core) {
|
|
138
138
|
this.map.set(id, core)
|
|
139
139
|
if (this.watching.length > 0) this._emit(core)
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
_emit
|
|
142
|
+
_emit(core) {
|
|
143
143
|
for (let i = this.watching.length - 1; i >= 0; i--) {
|
|
144
144
|
const store = this.watching[i]
|
|
145
145
|
for (const fn of store.watchers) fn(core)
|
|
146
146
|
}
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
-
_gc
|
|
149
|
+
_gc(core) {
|
|
150
150
|
const id = toHex(core.discoveryKey)
|
|
151
151
|
if (this.map.get(id) === core) this.map.delete(id)
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
_gcCycle
|
|
154
|
+
_gcCycle() {
|
|
155
155
|
for (const core of this._gcing) {
|
|
156
156
|
if (++core.gc < 4) continue
|
|
157
157
|
const gc = this._gc.bind(this, core)
|
|
@@ -162,24 +162,24 @@ class CoreTracker {
|
|
|
162
162
|
if (this._gcing.size === 0) this._stopGC()
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
-
gc
|
|
165
|
+
gc(core) {
|
|
166
166
|
core.gc = 1 // first strike
|
|
167
167
|
this._gcing.add(core)
|
|
168
168
|
if (this._gcing.size === 1) this._startGC()
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
-
_stopGC
|
|
171
|
+
_stopGC() {
|
|
172
172
|
clearInterval(this._gcInterval)
|
|
173
173
|
this._gcInterval = null
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
-
_startGC
|
|
176
|
+
_startGC() {
|
|
177
177
|
if (this._gcInterval) return
|
|
178
178
|
this._gcInterval = setInterval(this._gcCycleBound, 2000)
|
|
179
179
|
if (this._gcInterval.unref) this._gcInterval.unref()
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
-
close
|
|
182
|
+
close() {
|
|
183
183
|
this._stopGC()
|
|
184
184
|
this._gcing.clear()
|
|
185
185
|
|
|
@@ -193,7 +193,7 @@ class CoreTracker {
|
|
|
193
193
|
return Promise.all(all)
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
-
*
|
|
196
|
+
*[Symbol.iterator]() {
|
|
197
197
|
for (const core of this.map.values()) {
|
|
198
198
|
if (!core.closing) yield core
|
|
199
199
|
}
|
|
@@ -201,17 +201,17 @@ class CoreTracker {
|
|
|
201
201
|
}
|
|
202
202
|
|
|
203
203
|
class FindingPeers {
|
|
204
|
-
constructor
|
|
204
|
+
constructor() {
|
|
205
205
|
this.count = 0
|
|
206
206
|
this.pending = []
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
-
add
|
|
209
|
+
add(core) {
|
|
210
210
|
if (this.count === 0) return
|
|
211
211
|
this.pending.push(core.findingPeers())
|
|
212
212
|
}
|
|
213
213
|
|
|
214
|
-
inc
|
|
214
|
+
inc(sessions) {
|
|
215
215
|
if (++this.count !== 1) return
|
|
216
216
|
|
|
217
217
|
for (const core of sessions) {
|
|
@@ -219,25 +219,31 @@ class FindingPeers {
|
|
|
219
219
|
}
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
-
dec
|
|
222
|
+
dec(sessions) {
|
|
223
223
|
if (--this.count !== 0) return
|
|
224
224
|
while (this.pending.length > 0) this.pending.pop()()
|
|
225
225
|
}
|
|
226
226
|
}
|
|
227
227
|
|
|
228
228
|
class Corestore extends ReadyResource {
|
|
229
|
-
constructor
|
|
229
|
+
constructor(storage, opts = {}) {
|
|
230
230
|
super()
|
|
231
231
|
|
|
232
232
|
this.root = opts.root || null
|
|
233
|
-
this.storage = this.root
|
|
233
|
+
this.storage = this.root
|
|
234
|
+
? this.root.storage
|
|
235
|
+
: Hypercore.defaultStorage(storage, {
|
|
236
|
+
id: opts.id,
|
|
237
|
+
allowBackup: opts.allowBackup,
|
|
238
|
+
readOnly: opts.readOnly
|
|
239
|
+
})
|
|
234
240
|
this.streamTracker = this.root ? this.root.streamTracker : new StreamTracker()
|
|
235
241
|
this.cores = this.root ? this.root.cores : new CoreTracker()
|
|
236
242
|
this.sessions = new SessionTracker()
|
|
237
243
|
this.corestores = this.root ? this.root.corestores : new Set()
|
|
238
244
|
this.readOnly = opts.writable === false || !!opts.readOnly
|
|
239
|
-
this.globalCache = this.root ? this.root.globalCache :
|
|
240
|
-
this.primaryKey = this.root ? this.root.primaryKey :
|
|
245
|
+
this.globalCache = this.root ? this.root.globalCache : opts.globalCache || null
|
|
246
|
+
this.primaryKey = this.root ? this.root.primaryKey : opts.primaryKey || null
|
|
241
247
|
this.ns = opts.namespace || DEFAULT_NAMESPACE
|
|
242
248
|
this.manifestVersion = opts.manifestVersion || 1
|
|
243
249
|
this.shouldSuspend = isAndroid ? !!opts.suspend : opts.suspend !== false
|
|
@@ -249,12 +255,18 @@ class Corestore extends ReadyResource {
|
|
|
249
255
|
this._findingPeers = null // here for legacy
|
|
250
256
|
this._ongcBound = this._ongc.bind(this)
|
|
251
257
|
|
|
258
|
+
if (opts.primaryKey && !this.root && !opts.unsafe) {
|
|
259
|
+
throw ASSERTION(
|
|
260
|
+
'Passing the primary key is unsafe unless you know what you are doing. Set unsafe: true to acknowledge that'
|
|
261
|
+
)
|
|
262
|
+
}
|
|
263
|
+
|
|
252
264
|
if (this.root) this.corestores.add(this)
|
|
253
265
|
|
|
254
266
|
this.ready().catch(noop)
|
|
255
267
|
}
|
|
256
268
|
|
|
257
|
-
watch
|
|
269
|
+
watch(fn) {
|
|
258
270
|
if (this.watchers === null) {
|
|
259
271
|
this.watchers = new Set()
|
|
260
272
|
this.cores.watch(this)
|
|
@@ -263,7 +275,7 @@ class Corestore extends ReadyResource {
|
|
|
263
275
|
this.watchers.add(fn)
|
|
264
276
|
}
|
|
265
277
|
|
|
266
|
-
unwatch
|
|
278
|
+
unwatch(fn) {
|
|
267
279
|
if (this.watchers === null) return
|
|
268
280
|
|
|
269
281
|
this.watchers.delete(fn)
|
|
@@ -274,7 +286,7 @@ class Corestore extends ReadyResource {
|
|
|
274
286
|
}
|
|
275
287
|
}
|
|
276
288
|
|
|
277
|
-
findingPeers
|
|
289
|
+
findingPeers() {
|
|
278
290
|
if (this._findingPeers === null) this._findingPeers = new FindingPeers()
|
|
279
291
|
this._findingPeers.inc(this.sessions)
|
|
280
292
|
let done = false
|
|
@@ -285,51 +297,59 @@ class Corestore extends ReadyResource {
|
|
|
285
297
|
}
|
|
286
298
|
}
|
|
287
299
|
|
|
288
|
-
audit
|
|
300
|
+
audit(opts = {}) {
|
|
289
301
|
return auditStore(this, opts)
|
|
290
302
|
}
|
|
291
303
|
|
|
292
|
-
async suspend
|
|
304
|
+
async suspend({ log = noop } = {}) {
|
|
293
305
|
await log('Flushing db...')
|
|
294
|
-
|
|
306
|
+
// If readOnly we don't need to flush
|
|
307
|
+
if (!this.storage.readOnly) await this.storage.db.flush()
|
|
295
308
|
if (!this.shouldSuspend) return
|
|
296
309
|
await log('Suspending db...')
|
|
297
|
-
await this.storage.
|
|
310
|
+
await this.storage.suspend()
|
|
298
311
|
}
|
|
299
312
|
|
|
300
|
-
resume
|
|
301
|
-
return this.storage.
|
|
313
|
+
resume() {
|
|
314
|
+
return this.storage.resume()
|
|
302
315
|
}
|
|
303
316
|
|
|
304
|
-
session
|
|
317
|
+
session(opts) {
|
|
305
318
|
this._maybeClosed()
|
|
306
319
|
const root = this.root || this
|
|
307
|
-
return new Corestore(null, {
|
|
320
|
+
return new Corestore(null, {
|
|
321
|
+
manifestVersion: this.manifestVersion,
|
|
322
|
+
...opts,
|
|
323
|
+
root
|
|
324
|
+
})
|
|
308
325
|
}
|
|
309
326
|
|
|
310
|
-
namespace
|
|
311
|
-
return this.session({
|
|
327
|
+
namespace(name, opts) {
|
|
328
|
+
return this.session({
|
|
329
|
+
...opts,
|
|
330
|
+
namespace: generateNamespace(this.ns, name)
|
|
331
|
+
})
|
|
312
332
|
}
|
|
313
333
|
|
|
314
|
-
list
|
|
334
|
+
list(namespace) {
|
|
315
335
|
return this.storage.createDiscoveryKeyStream(namespace)
|
|
316
336
|
}
|
|
317
337
|
|
|
318
|
-
getAuth
|
|
338
|
+
getAuth(discoveryKey) {
|
|
319
339
|
return this.storage.getAuth(discoveryKey)
|
|
320
340
|
}
|
|
321
341
|
|
|
322
|
-
_ongc
|
|
342
|
+
_ongc(session) {
|
|
323
343
|
if (session.sessions.length === 0) this.sessions.gc(session.id)
|
|
324
344
|
}
|
|
325
345
|
|
|
326
|
-
async _getOrSetSeed
|
|
346
|
+
async _getOrSetSeed() {
|
|
327
347
|
const seed = await this.storage.getSeed()
|
|
328
348
|
if (seed !== null) return seed
|
|
329
349
|
return await this.storage.setSeed(this.primaryKey || crypto.randomBytes(32))
|
|
330
350
|
}
|
|
331
351
|
|
|
332
|
-
async _open
|
|
352
|
+
async _open() {
|
|
333
353
|
if (this.root !== null) {
|
|
334
354
|
if (this.root.opened === false) await this.root.ready()
|
|
335
355
|
this.primaryKey = this.root.primaryKey
|
|
@@ -348,7 +368,7 @@ class Corestore extends ReadyResource {
|
|
|
348
368
|
}
|
|
349
369
|
}
|
|
350
370
|
|
|
351
|
-
async _close
|
|
371
|
+
async _close() {
|
|
352
372
|
const closing = []
|
|
353
373
|
const hanging = [...this.sessions]
|
|
354
374
|
for (const sess of hanging) closing.push(sess.close())
|
|
@@ -370,9 +390,13 @@ class Corestore extends ReadyResource {
|
|
|
370
390
|
await this.storage.close()
|
|
371
391
|
}
|
|
372
392
|
|
|
373
|
-
async _attachMaybe
|
|
393
|
+
async _attachMaybe(muxer, discoveryKey) {
|
|
374
394
|
if (this.opened === false) await this.ready()
|
|
375
|
-
if (
|
|
395
|
+
if (
|
|
396
|
+
!this.cores.opened(toHex(discoveryKey)) &&
|
|
397
|
+
!(await this.storage.hasCore(discoveryKey, { ifMigrated: true }))
|
|
398
|
+
)
|
|
399
|
+
return
|
|
376
400
|
if (this.closing) return
|
|
377
401
|
|
|
378
402
|
const core = this._openCore(discoveryKey, { createIfMissing: false })
|
|
@@ -387,13 +411,19 @@ class Corestore extends ReadyResource {
|
|
|
387
411
|
core.checkIfIdle()
|
|
388
412
|
}
|
|
389
413
|
|
|
390
|
-
|
|
414
|
+
_shouldReplicate(core, muxer) {
|
|
415
|
+
return (
|
|
416
|
+
core.replicator.downloading && !core.replicator.attached(muxer) && core.opened && this.active
|
|
417
|
+
)
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
replicate(isInitiator, opts) {
|
|
391
421
|
this._maybeClosed()
|
|
392
422
|
|
|
393
423
|
const isExternal = isStream(isInitiator)
|
|
394
424
|
const stream = Hypercore.createProtocolStream(isInitiator, {
|
|
395
425
|
...opts,
|
|
396
|
-
ondiscoverykey: discoveryKey => {
|
|
426
|
+
ondiscoverykey: (discoveryKey) => {
|
|
397
427
|
if (this.closing) return
|
|
398
428
|
const muxer = stream.noiseStream.userData
|
|
399
429
|
return this._attachMaybe(muxer, discoveryKey)
|
|
@@ -406,7 +436,9 @@ class Corestore extends ReadyResource {
|
|
|
406
436
|
muxer.cork()
|
|
407
437
|
|
|
408
438
|
for (const core of this.cores) {
|
|
409
|
-
if (!
|
|
439
|
+
if (!this._shouldReplicate(core, muxer)) {
|
|
440
|
+
continue
|
|
441
|
+
}
|
|
410
442
|
core.replicator.attachTo(muxer)
|
|
411
443
|
}
|
|
412
444
|
|
|
@@ -418,13 +450,13 @@ class Corestore extends ReadyResource {
|
|
|
418
450
|
return stream
|
|
419
451
|
}
|
|
420
452
|
|
|
421
|
-
_maybeClosed
|
|
453
|
+
_maybeClosed() {
|
|
422
454
|
if (this.closing || (this.root !== null && this.root.closing)) {
|
|
423
455
|
throw new Error('Corestore is closed')
|
|
424
456
|
}
|
|
425
457
|
}
|
|
426
458
|
|
|
427
|
-
get
|
|
459
|
+
get(opts) {
|
|
428
460
|
this._maybeClosed()
|
|
429
461
|
|
|
430
462
|
if (b4a.isBuffer(opts) || typeof opts === 'string') opts = { key: opts }
|
|
@@ -473,28 +505,30 @@ class Corestore extends ReadyResource {
|
|
|
473
505
|
return this._makeSession(conf)
|
|
474
506
|
}
|
|
475
507
|
|
|
476
|
-
_makeSession
|
|
508
|
+
_makeSession(conf) {
|
|
477
509
|
const session = new Hypercore(null, null, conf)
|
|
478
510
|
if (this._findingPeers !== null) this._findingPeers.add(session)
|
|
479
511
|
return session
|
|
480
512
|
}
|
|
481
513
|
|
|
482
|
-
async createKeyPair
|
|
514
|
+
async createKeyPair(name, ns = this.ns) {
|
|
483
515
|
if (this.opened === false) await this.ready()
|
|
484
516
|
return createKeyPair(this.primaryKey, ns, name)
|
|
485
517
|
}
|
|
486
518
|
|
|
487
|
-
async _preloadCheckIfExists
|
|
488
|
-
const has = await this.storage.
|
|
519
|
+
async _preloadCheckIfExists(opts) {
|
|
520
|
+
const has = await this.storage.hasCore(opts.discoveryKey)
|
|
489
521
|
if (!has) throw STORAGE_EMPTY('No Hypercore is stored here')
|
|
490
522
|
return this._preload(opts)
|
|
491
523
|
}
|
|
492
524
|
|
|
493
|
-
async _preload
|
|
525
|
+
async _preload(opts) {
|
|
494
526
|
if (opts.preload) opts = { ...opts, ...(await opts.preload) }
|
|
495
527
|
if (this.opened === false) await this.ready()
|
|
496
528
|
|
|
497
|
-
const discoveryKey = opts.name
|
|
529
|
+
const discoveryKey = opts.name
|
|
530
|
+
? await this.storage.getAlias({ name: opts.name, namespace: this.ns })
|
|
531
|
+
: null
|
|
498
532
|
this._maybeClosed()
|
|
499
533
|
|
|
500
534
|
const core = this._openCore(discoveryKey, opts)
|
|
@@ -509,7 +543,7 @@ class Corestore extends ReadyResource {
|
|
|
509
543
|
}
|
|
510
544
|
}
|
|
511
545
|
|
|
512
|
-
_auth
|
|
546
|
+
_auth(discoveryKey, opts) {
|
|
513
547
|
const result = {
|
|
514
548
|
keyPair: null,
|
|
515
549
|
key: null,
|
|
@@ -526,7 +560,10 @@ class Corestore extends ReadyResource {
|
|
|
526
560
|
if (opts.manifest) {
|
|
527
561
|
result.manifest = opts.manifest
|
|
528
562
|
} else if (result.keyPair && !result.discoveryKey) {
|
|
529
|
-
result.manifest = {
|
|
563
|
+
result.manifest = {
|
|
564
|
+
version: this.manifestVersion,
|
|
565
|
+
signers: [{ publicKey: result.keyPair.publicKey }]
|
|
566
|
+
}
|
|
530
567
|
}
|
|
531
568
|
|
|
532
569
|
if (opts.key) result.key = ID.decode(opts.key)
|
|
@@ -541,7 +578,7 @@ class Corestore extends ReadyResource {
|
|
|
541
578
|
return result
|
|
542
579
|
}
|
|
543
580
|
|
|
544
|
-
_openCore
|
|
581
|
+
_openCore(discoveryKey, opts) {
|
|
545
582
|
const auth = this._auth(discoveryKey, opts)
|
|
546
583
|
|
|
547
584
|
const id = toHex(auth.discoveryKey)
|
|
@@ -549,7 +586,7 @@ class Corestore extends ReadyResource {
|
|
|
549
586
|
if (existing && !existing.closing) return existing
|
|
550
587
|
|
|
551
588
|
const core = Hypercore.createCore(this.storage, {
|
|
552
|
-
preopen:
|
|
589
|
+
preopen: existing && existing.opened ? existing.closing : null, // always wait for the prev one to close first in any case...
|
|
553
590
|
eagerUpgrade: true,
|
|
554
591
|
notDownloadingLinger: opts.notDownloadingLinger,
|
|
555
592
|
allowFork: opts.allowFork !== false,
|
|
@@ -582,25 +619,25 @@ class Corestore extends ReadyResource {
|
|
|
582
619
|
|
|
583
620
|
module.exports = Corestore
|
|
584
621
|
|
|
585
|
-
function isStream
|
|
622
|
+
function isStream(s) {
|
|
586
623
|
return typeof s === 'object' && s && typeof s.pipe === 'function'
|
|
587
624
|
}
|
|
588
625
|
|
|
589
|
-
function generateNamespace
|
|
626
|
+
function generateNamespace(namespace, name) {
|
|
590
627
|
if (!b4a.isBuffer(name)) name = b4a.from(name)
|
|
591
628
|
const out = b4a.allocUnsafeSlow(32)
|
|
592
629
|
sodium.crypto_generichash_batch(out, [namespace, name])
|
|
593
630
|
return out
|
|
594
631
|
}
|
|
595
632
|
|
|
596
|
-
function deriveSeed
|
|
633
|
+
function deriveSeed(primaryKey, namespace, name) {
|
|
597
634
|
if (!b4a.isBuffer(name)) name = b4a.from(name)
|
|
598
635
|
const out = b4a.alloc(32)
|
|
599
636
|
sodium.crypto_generichash_batch(out, [NS, namespace, name], primaryKey)
|
|
600
637
|
return out
|
|
601
638
|
}
|
|
602
639
|
|
|
603
|
-
function createKeyPair
|
|
640
|
+
function createKeyPair(primaryKey, namespace, name) {
|
|
604
641
|
const seed = deriveSeed(primaryKey, namespace, name)
|
|
605
642
|
const buf = b4a.alloc(sodium.crypto_sign_PUBLICKEYBYTES + sodium.crypto_sign_SECRETKEYBYTES)
|
|
606
643
|
const keyPair = {
|
|
@@ -611,8 +648,8 @@ function createKeyPair (primaryKey, namespace, name) {
|
|
|
611
648
|
return keyPair
|
|
612
649
|
}
|
|
613
650
|
|
|
614
|
-
function noop
|
|
651
|
+
function noop() {}
|
|
615
652
|
|
|
616
|
-
function toHex
|
|
653
|
+
function toHex(discoveryKey) {
|
|
617
654
|
return b4a.toString(discoveryKey, 'hex')
|
|
618
655
|
}
|
package/lib/audit.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
module.exports = async function
|
|
1
|
+
module.exports = async function* audit(store, { dryRun = false } = {}) {
|
|
2
2
|
for await (const { discoveryKey, core } of store.storage.createCoreStream()) {
|
|
3
3
|
if (core.version < 1) continue // not migrated, ignore
|
|
4
4
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "corestore",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.6.0",
|
|
4
4
|
"description": "A Hypercore factory that simplifies managing collections of cores.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"files": [
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
],
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"b4a": "^1.6.7",
|
|
12
|
-
"hypercore": "^11.
|
|
12
|
+
"hypercore": "^11.19.0",
|
|
13
13
|
"hypercore-crypto": "^3.4.2",
|
|
14
14
|
"hypercore-errors": "^1.4.0",
|
|
15
15
|
"hypercore-id-encoding": "^1.3.0",
|
|
@@ -19,12 +19,14 @@
|
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"brittle": "^3.7.0",
|
|
22
|
+
"prettier": "^3.6.2",
|
|
23
|
+
"prettier-config-holepunch": "^2.0.0",
|
|
22
24
|
"rache": "^1.0.0",
|
|
23
|
-
"standard": "^17.1.2",
|
|
24
25
|
"test-tmp": "^1.3.0"
|
|
25
26
|
},
|
|
26
27
|
"scripts": {
|
|
27
|
-
"
|
|
28
|
+
"format": "prettier --write .",
|
|
29
|
+
"test": "prettier --check . && brittle test/*.js",
|
|
28
30
|
"test:bare": "bare test/basic.js"
|
|
29
31
|
},
|
|
30
32
|
"repository": {
|