corestore 6.18.4 → 7.0.1
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 +12 -38
- package/index.js +310 -457
- package/package.json +29 -30
- package/LICENSE +0 -21
package/README.md
CHANGED
|
@@ -13,6 +13,11 @@ Corestore provides:
|
|
|
13
13
|
### Installation
|
|
14
14
|
`npm install corestore`
|
|
15
15
|
|
|
16
|
+
> [!NOTE]
|
|
17
|
+
> This readme reflects Corestore 7, our latest major version that is backed by RocksDB for storage and atomicity.
|
|
18
|
+
> Whilst we are fully validating that, the npm dist-tag for latest is set to latest version of Corestore 7, the previous major, to avoid too much disruption.
|
|
19
|
+
> It will be updated to 11 in a few weeks.
|
|
20
|
+
|
|
16
21
|
### Usage
|
|
17
22
|
A corestore instance can be constructed with a random-access-storage module, a function that returns a random-access-storage module given a path, or a string. If a string is specified, it will be assumed to be a path to a local storage directory:
|
|
18
23
|
```js
|
|
@@ -24,27 +29,17 @@ const core2 = store.get({ name: 'core-2' })
|
|
|
24
29
|
```
|
|
25
30
|
|
|
26
31
|
### API
|
|
27
|
-
#### `const store = new Corestore(storage
|
|
32
|
+
#### `const store = new Corestore(storage)`
|
|
28
33
|
Create a new Corestore instance.
|
|
29
34
|
|
|
30
35
|
`storage` can be either a random-access-storage module, a string, or a function that takes a path and returns an random-access-storage instance.
|
|
31
36
|
|
|
32
|
-
|
|
33
|
-
```js
|
|
34
|
-
{
|
|
35
|
-
inflightRange: null // Advanced option. Forwarded to the Hypercores created by corestore.get(...)
|
|
36
|
-
}
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
#### `const core = store.get(key | { name: 'a-name', exclusive, ...hypercoreOpts})`
|
|
37
|
+
#### `const core = store.get(key | { name: 'a-name', ...hypercoreOpts})`
|
|
40
38
|
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).
|
|
41
39
|
|
|
42
40
|
If that Hypercore has previously been loaded, subsequent calls to `get` will return a new Hypercore session on the existing core.
|
|
43
41
|
|
|
44
|
-
|
|
45
|
-
opening the Hypercore effectively meaning any op on the core will wait until its exclusive.
|
|
46
|
-
|
|
47
|
-
All other options besides `name` and `key` and `exclusive` will be forwarded to the Hypercore constructor.
|
|
42
|
+
All other options besides `name` and `key` will be forwarded to the Hypercore constructor.
|
|
48
43
|
|
|
49
44
|
#### `const stream = store.replicate(optsOrStream)`
|
|
50
45
|
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.
|
|
@@ -67,8 +62,11 @@ swarm.join(...)
|
|
|
67
62
|
swarm.on('connection', (connection) => store.replicate(connection))
|
|
68
63
|
```
|
|
69
64
|
|
|
65
|
+
#### `const storeB = storeA.session()`
|
|
66
|
+
Create a new Corestore session. Closing a session will close all cores made from this session.
|
|
67
|
+
|
|
70
68
|
#### `const store = store.namespace(name)`
|
|
71
|
-
Create a new namespaced Corestore. Namespacing is useful if you're going to be sharing a single Corestore instance between many applications or components, as it prevents name collisions.
|
|
69
|
+
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.
|
|
72
70
|
|
|
73
71
|
Namespaces can be chained:
|
|
74
72
|
```js
|
|
@@ -78,32 +76,8 @@ const core1 = ns1.get({ name: 'main' }) // These will load different Hypercores
|
|
|
78
76
|
const core2 = ns2.get({ name: 'main' })
|
|
79
77
|
```
|
|
80
78
|
|
|
81
|
-
#### `const storeB = storeA.session(opts)`
|
|
82
|
-
Create a new Corestore that shares resources with the original, like cache, cores, replication streams, and storage, while optionally resetting the namespace, overriding `primaryKey`.
|
|
83
|
-
Useful when an application wants to accept an optional Corestore, but needs to maintain a predictable key derivation.
|
|
84
|
-
|
|
85
|
-
`opts` are the same as the constructor options:
|
|
86
|
-
|
|
87
|
-
```js
|
|
88
|
-
{
|
|
89
|
-
primaryKey, // Overrides the primaryKey for this session
|
|
90
|
-
namespace, // If set to null it will reset to the DEFAULT_NAMESPACE
|
|
91
|
-
detach: true, // By disabling this, closing the session will also close the store that created the session
|
|
92
|
-
inflightRange: null // Advanced option. Forwarded to the Hypercores created by `session.get(...)
|
|
93
|
-
}
|
|
94
|
-
```
|
|
95
|
-
|
|
96
79
|
#### `await store.close()`
|
|
97
80
|
Fully close this Corestore instance.
|
|
98
81
|
|
|
99
|
-
#### `store.on('core-open', core)`
|
|
100
|
-
Emitted when the first session for a core is opened.
|
|
101
|
-
|
|
102
|
-
*Note: This core may close at any time, so treat it as a weak reference*
|
|
103
|
-
|
|
104
|
-
#### `store.on('core-close', core)`
|
|
105
|
-
Emitted when the last session for a core is closed.
|
|
106
|
-
|
|
107
82
|
### License
|
|
108
83
|
MIT
|
|
109
|
-
|
package/index.js
CHANGED
|
@@ -1,562 +1,415 @@
|
|
|
1
|
-
const safetyCatch = require('safety-catch')
|
|
2
|
-
const crypto = require('hypercore-crypto')
|
|
3
|
-
const sodium = require('sodium-universal')
|
|
4
|
-
const Hypercore = require('hypercore')
|
|
5
|
-
const hypercoreId = require('hypercore-id-encoding')
|
|
6
|
-
const Xache = require('xache')
|
|
7
1
|
const b4a = require('b4a')
|
|
2
|
+
const Hypercore = require('hypercore')
|
|
8
3
|
const ReadyResource = require('ready-resource')
|
|
9
|
-
const
|
|
4
|
+
const EventEmitter = require('events')
|
|
5
|
+
const sodium = require('sodium-universal')
|
|
6
|
+
const crypto = require('hypercore-crypto')
|
|
7
|
+
const ID = require('hypercore-id-encoding')
|
|
10
8
|
|
|
11
9
|
const [NS] = crypto.namespace('corestore', 1)
|
|
12
10
|
const DEFAULT_NAMESPACE = b4a.alloc(32) // This is meant to be 32 0-bytes
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const POOL_SIZE = 512 // how many open fds to aim for before cycling them
|
|
19
|
-
const DEFAULT_MANIFEST = 0 // bump to 1 when this is more widely deployed
|
|
20
|
-
const DEFAULT_COMPAT = true
|
|
21
|
-
|
|
22
|
-
module.exports = class Corestore extends ReadyResource {
|
|
23
|
-
constructor (storage, opts = {}) {
|
|
24
|
-
super()
|
|
25
|
-
|
|
26
|
-
const root = opts._root
|
|
27
|
-
|
|
28
|
-
this.storage = Hypercore.defaultStorage(storage, { lock: PRIMARY_KEY_FILE_NAME, poolSize: opts.poolSize || POOL_SIZE, rmdir: true })
|
|
29
|
-
this.cores = root ? root.cores : new Map()
|
|
30
|
-
this.cache = !!opts.cache
|
|
31
|
-
this.primaryKey = opts.primaryKey || null
|
|
32
|
-
this.passive = !!opts.passive
|
|
33
|
-
this.manifestVersion = typeof opts.manifestVersion === 'number' ? opts.manifestVersion : (root ? root.manifestVersion : DEFAULT_MANIFEST)
|
|
34
|
-
this.compat = typeof opts.compat === 'boolean' ? opts.compat : (root ? root.compat : DEFAULT_COMPAT)
|
|
35
|
-
this.inflightRange = opts.inflightRange || null
|
|
36
|
-
this.globalCache = opts.globalCache || null
|
|
37
|
-
|
|
38
|
-
this._keyStorage = null
|
|
39
|
-
this._bootstrap = opts._bootstrap || null
|
|
40
|
-
this._namespace = opts.namespace || DEFAULT_NAMESPACE
|
|
41
|
-
this._noCoreCache = root ? root._noCoreCache : new Xache({ maxSize: 65536 })
|
|
42
|
-
|
|
43
|
-
this._root = root || this
|
|
44
|
-
this._replicationStreams = root ? root._replicationStreams : []
|
|
45
|
-
this._overwrite = opts.overwrite === true
|
|
46
|
-
this._readonly = opts.writable === false
|
|
47
|
-
this._attached = opts._attached || null
|
|
48
|
-
this._notDownloadingLinger = opts.notDownloadingLinger
|
|
49
|
-
|
|
50
|
-
this._sessions = new Set() // sessions for THIS namespace
|
|
51
|
-
this._rootStoreSessions = new Set()
|
|
52
|
-
this._locks = root ? root._locks : new Map()
|
|
12
|
+
class StreamTracker {
|
|
13
|
+
constructor () {
|
|
14
|
+
this.records = []
|
|
15
|
+
}
|
|
53
16
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
this.
|
|
17
|
+
add (stream, isExternal) {
|
|
18
|
+
const record = { index: 0, stream, isExternal }
|
|
19
|
+
this.records.push(record)
|
|
20
|
+
return record
|
|
21
|
+
}
|
|
57
22
|
|
|
58
|
-
|
|
59
|
-
this.
|
|
23
|
+
remove (record) {
|
|
24
|
+
const popped = this.records.pop()
|
|
25
|
+
if (popped === record) return
|
|
26
|
+
this.records[popped.index = record.index] = popped
|
|
60
27
|
}
|
|
61
28
|
|
|
62
|
-
|
|
63
|
-
|
|
29
|
+
attachAll (core) {
|
|
30
|
+
for (let i = 0; i < this.records.length; i++) {
|
|
31
|
+
const record = this.records[i]
|
|
32
|
+
const muxer = record.stream.noiseStream.userData
|
|
33
|
+
if (!core.replicator.attached(muxer)) core.replicator.attachTo(muxer)
|
|
34
|
+
}
|
|
64
35
|
}
|
|
65
36
|
|
|
66
|
-
|
|
67
|
-
|
|
37
|
+
destroy () {
|
|
38
|
+
// reverse is safer cause we delete mb
|
|
39
|
+
for (let i = this.records.length - 1; i >= 0; i--) {
|
|
40
|
+
const record = this.records[i]
|
|
41
|
+
if (!record.isExternal) record.stream.destroy()
|
|
42
|
+
}
|
|
68
43
|
}
|
|
44
|
+
}
|
|
69
45
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
46
|
+
class SessionTracker {
|
|
47
|
+
constructor () {
|
|
48
|
+
this.map = new Map()
|
|
49
|
+
}
|
|
73
50
|
|
|
74
|
-
|
|
51
|
+
get size () {
|
|
52
|
+
return this.map.size
|
|
53
|
+
}
|
|
75
54
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
})
|
|
83
|
-
}
|
|
55
|
+
get (id) {
|
|
56
|
+
const existing = this.map.get(id)
|
|
57
|
+
if (existing !== undefined) return existing
|
|
58
|
+
const fresh = []
|
|
59
|
+
this.map.set(id, fresh)
|
|
60
|
+
return fresh
|
|
84
61
|
}
|
|
85
62
|
|
|
86
|
-
|
|
87
|
-
|
|
63
|
+
gc (id) {
|
|
64
|
+
this.map.delete(id)
|
|
65
|
+
}
|
|
88
66
|
|
|
89
|
-
|
|
67
|
+
list (id) {
|
|
68
|
+
return id ? (this.map.get(id) || []) : [...this]
|
|
69
|
+
}
|
|
90
70
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
if (err) return reject(err)
|
|
95
|
-
resolve()
|
|
96
|
-
})
|
|
97
|
-
})
|
|
71
|
+
* [Symbol.iterator] () {
|
|
72
|
+
for (const sessions of this.map.values()) {
|
|
73
|
+
yield * sessions[Symbol.iterator]()
|
|
98
74
|
}
|
|
99
75
|
}
|
|
76
|
+
}
|
|
100
77
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
78
|
+
class CoreTracker extends EventEmitter {
|
|
79
|
+
constructor () {
|
|
80
|
+
super()
|
|
81
|
+
this.map = new Map()
|
|
82
|
+
this.watching = []
|
|
83
|
+
}
|
|
104
84
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
done = true
|
|
108
|
-
this._decFindingPeers()
|
|
109
|
-
}
|
|
85
|
+
get size () {
|
|
86
|
+
return this.map.size
|
|
110
87
|
}
|
|
111
88
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
if (session !== this) {
|
|
116
|
-
session.emit(name, core)
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
if (this !== this._root) this._root.emit(name, core)
|
|
89
|
+
watch (store) {
|
|
90
|
+
if (store.watchIndex !== -1) return
|
|
91
|
+
store.watchIndex = this.watching.push(store) - 1
|
|
120
92
|
}
|
|
121
93
|
|
|
122
|
-
|
|
123
|
-
if (
|
|
94
|
+
unwatch (store) {
|
|
95
|
+
if (store.watchIndex === -1) return
|
|
96
|
+
const head = this.watching.pop()
|
|
97
|
+
if (head !== store) this.watching[(head.watchIndex = store.watchIndex)] = head
|
|
98
|
+
store.watchIndex = -1
|
|
99
|
+
}
|
|
124
100
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
101
|
+
get (id) {
|
|
102
|
+
// we allow you do call this from the outside, so support normal buffers also
|
|
103
|
+
if (b4a.isBuffer(id)) id = b4a.toString(id, 'hex')
|
|
104
|
+
return this.map.get(id) || null
|
|
128
105
|
}
|
|
129
106
|
|
|
130
|
-
|
|
131
|
-
|
|
107
|
+
set (id, core) {
|
|
108
|
+
this.map.set(id, core)
|
|
109
|
+
this.emit('add', core) // TODO: will be removed
|
|
110
|
+
if (this.watching.length > 0) this._emit(core)
|
|
111
|
+
}
|
|
132
112
|
|
|
133
|
-
|
|
134
|
-
|
|
113
|
+
_emit (core) {
|
|
114
|
+
for (let i = this.watching.length - 1; i >= 0; i--) {
|
|
115
|
+
const store = this.watching[i]
|
|
116
|
+
for (const fn of store.watchers) fn(core)
|
|
135
117
|
}
|
|
136
118
|
}
|
|
137
119
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
this._namespace = ns
|
|
142
|
-
}
|
|
120
|
+
delete (id, core) {
|
|
121
|
+
this.map.delete(id)
|
|
122
|
+
this.emit('remove', core) // TODO: will be removed
|
|
143
123
|
}
|
|
144
124
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
if (this._bootstrap) await this._openNamespaceFromBootstrap()
|
|
150
|
-
return
|
|
151
|
-
}
|
|
125
|
+
[Symbol.iterator] () {
|
|
126
|
+
return this.map.values()
|
|
127
|
+
}
|
|
128
|
+
}
|
|
152
129
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
this._keyStorage.stat((err, st) => {
|
|
157
|
-
if (err && err.code !== 'ENOENT') return reject(err)
|
|
158
|
-
if (err || st.size < 32 || this._overwrite) {
|
|
159
|
-
const key = this.primaryKey || crypto.randomBytes(32)
|
|
160
|
-
return this._keyStorage.write(0, key, err => {
|
|
161
|
-
if (err) return reject(err)
|
|
162
|
-
return resolve(key)
|
|
163
|
-
})
|
|
164
|
-
}
|
|
165
|
-
this._keyStorage.read(0, 32, (err, key) => {
|
|
166
|
-
if (err) return reject(err)
|
|
167
|
-
if (this.primaryKey) return resolve(this.primaryKey)
|
|
168
|
-
return resolve(key)
|
|
169
|
-
})
|
|
170
|
-
})
|
|
171
|
-
})
|
|
130
|
+
class Corestore extends ReadyResource {
|
|
131
|
+
constructor (storage, opts = {}) {
|
|
132
|
+
super()
|
|
172
133
|
|
|
173
|
-
|
|
174
|
-
|
|
134
|
+
this.root = opts.root || null
|
|
135
|
+
this.storage = this.root ? this.root.storage : Hypercore.defaultStorage(storage)
|
|
136
|
+
this.streamTracker = this.root ? this.root.streamTracker : new StreamTracker()
|
|
137
|
+
this.cores = this.root ? this.root.cores : new CoreTracker()
|
|
138
|
+
this.sessions = new SessionTracker()
|
|
139
|
+
this.globalCache = this.root ? this.root.globalCache : (opts.globalCache || null)
|
|
140
|
+
this.primaryKey = this.root ? this.root.primaryKey : (opts.primaryKey || null)
|
|
141
|
+
this.ns = opts.namespace || DEFAULT_NAMESPACE
|
|
175
142
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
const storageRoot = getStorageRoot(id)
|
|
143
|
+
this.watchers = null
|
|
144
|
+
this.watchIndex = -1
|
|
179
145
|
|
|
180
|
-
|
|
146
|
+
this.manifestVersion = 1 // just compat
|
|
181
147
|
|
|
182
|
-
|
|
183
|
-
await new Promise(resolve => st.close(resolve))
|
|
148
|
+
this._ongcBound = this._ongc.bind(this)
|
|
184
149
|
|
|
185
|
-
|
|
150
|
+
this.ready().catch(noop)
|
|
186
151
|
}
|
|
187
152
|
|
|
188
|
-
|
|
189
|
-
if (
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
keyPair: null,
|
|
193
|
-
key: null,
|
|
194
|
-
discoveryKey: opts._discoveryKey
|
|
195
|
-
}
|
|
153
|
+
watch (fn) {
|
|
154
|
+
if (this.watchers === null) {
|
|
155
|
+
this.watchers = new Set()
|
|
156
|
+
this.cores.watch(this)
|
|
196
157
|
}
|
|
197
158
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
: (opts.secretKey)
|
|
201
|
-
? { secretKey: opts.secretKey, publicKey: opts.publicKey }
|
|
202
|
-
: null
|
|
159
|
+
this.watchers.add(fn)
|
|
160
|
+
}
|
|
203
161
|
|
|
204
|
-
|
|
205
|
-
|
|
162
|
+
unwatch (fn) {
|
|
163
|
+
if (this.watchers === null) return
|
|
206
164
|
|
|
207
|
-
|
|
208
|
-
manifest: opts.manifest,
|
|
209
|
-
keyPair,
|
|
210
|
-
key,
|
|
211
|
-
discoveryKey: crypto.discoveryKey(key)
|
|
212
|
-
}
|
|
213
|
-
}
|
|
165
|
+
this.watchers.delete(fn)
|
|
214
166
|
|
|
215
|
-
if (
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
keyPair,
|
|
219
|
-
key: opts.key,
|
|
220
|
-
discoveryKey: crypto.discoveryKey(opts.key)
|
|
221
|
-
}
|
|
167
|
+
if (this.watchers.size === 0) {
|
|
168
|
+
this.watchers = null
|
|
169
|
+
this.cores.unwatch(this)
|
|
222
170
|
}
|
|
171
|
+
}
|
|
223
172
|
|
|
224
|
-
|
|
173
|
+
session (opts) {
|
|
174
|
+
const root = this.root || this
|
|
175
|
+
return new Corestore(null, { ...opts, root })
|
|
176
|
+
}
|
|
225
177
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
let discoveryKey = crypto.discoveryKey(key)
|
|
178
|
+
namespace (name, opts) {
|
|
179
|
+
return this.session({ ...opts, namespace: generateNamespace(this.ns, name) })
|
|
180
|
+
}
|
|
230
181
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
const discoveryKeyV0 = crypto.discoveryKey(keyV0)
|
|
182
|
+
_ongc (session) {
|
|
183
|
+
if (session.sessions.length === 0) this.sessions.gc(session.id)
|
|
184
|
+
}
|
|
235
185
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
}
|
|
186
|
+
async _getOrSetSeed () {
|
|
187
|
+
const seed = await this.storage.getSeed()
|
|
188
|
+
if (seed !== null) return seed
|
|
189
|
+
return await this.storage.setSeed(this.primaryKey || crypto.randomBytes(32))
|
|
190
|
+
}
|
|
242
191
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
}
|
|
192
|
+
async _open () {
|
|
193
|
+
if (this.root !== null) {
|
|
194
|
+
if (this.root.opened === false) await this.root.ready()
|
|
195
|
+
this.primaryKey = this.root.primaryKey
|
|
196
|
+
return
|
|
249
197
|
}
|
|
250
198
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
199
|
+
const primaryKey = await this._getOrSetSeed()
|
|
200
|
+
|
|
201
|
+
if (this.primaryKey === null) {
|
|
202
|
+
this.primaryKey = primaryKey
|
|
203
|
+
return
|
|
256
204
|
}
|
|
257
|
-
}
|
|
258
205
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
for (const { key: savedKey, value } of core.core.header.userData) {
|
|
262
|
-
if (key === savedKey) return value
|
|
206
|
+
if (!b4a.equals(primaryKey, this.primaryKey)) {
|
|
207
|
+
throw new Error('Another corestore is stored here')
|
|
263
208
|
}
|
|
264
|
-
return null
|
|
265
209
|
}
|
|
266
210
|
|
|
267
|
-
async
|
|
268
|
-
const
|
|
269
|
-
|
|
211
|
+
async _close () {
|
|
212
|
+
const sessions = []
|
|
213
|
+
const hanging = [...this.sessions]
|
|
214
|
+
for (const sess of hanging) sessions.push(sess.close())
|
|
270
215
|
|
|
271
|
-
|
|
272
|
-
const keyPair = await this.createKeyPair(b4a.toString(name), namespace)
|
|
273
|
-
core.setKeyPair(keyPair)
|
|
274
|
-
}
|
|
216
|
+
if (this.watchers !== null) this.cores.unwatch(this)
|
|
275
217
|
|
|
276
|
-
|
|
277
|
-
|
|
218
|
+
await Promise.all(sessions)
|
|
219
|
+
if (this.root !== null) return
|
|
278
220
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
return rw
|
|
221
|
+
const cores = []
|
|
222
|
+
for (const core of this.cores) cores.push(core.close())
|
|
223
|
+
await Promise.all(cores)
|
|
224
|
+
await this.storage.close()
|
|
285
225
|
}
|
|
286
226
|
|
|
287
|
-
async
|
|
288
|
-
|
|
227
|
+
async _attachMaybe (muxer, discoveryKey) {
|
|
228
|
+
if (this.opened === false) await this.ready()
|
|
229
|
+
if (this.cores.get(toHex(discoveryKey)) === null && !(await this.storage.has(discoveryKey))) return
|
|
289
230
|
|
|
290
|
-
|
|
291
|
-
const existing = this.cores.get(id)
|
|
292
|
-
if (existing.opened && !existing.closing) return { from: existing, keyPair, manifest, cache: !!opts.cache }
|
|
293
|
-
if (existing.closing) {
|
|
294
|
-
await existing.close()
|
|
295
|
-
} else {
|
|
296
|
-
await existing.ready().catch(safetyCatch)
|
|
297
|
-
}
|
|
298
|
-
}
|
|
231
|
+
const core = this._getCore(discoveryKey, { createIfMissing: false })
|
|
299
232
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
if (opts.name) {
|
|
303
|
-
userData[USERDATA_NAME_KEY] = b4a.from(opts.name)
|
|
304
|
-
userData[USERDATA_NAMESPACE_KEY] = this._namespace
|
|
305
|
-
}
|
|
233
|
+
if (!core) return
|
|
234
|
+
if (!core.opened) await core.ready()
|
|
306
235
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
const storageRoot = getStorageRoot(id)
|
|
310
|
-
const core = new Hypercore(p => this.storage(storageRoot + '/' + p), {
|
|
311
|
-
_preready: this._preready.bind(this),
|
|
312
|
-
notDownloadingLinger: this._notDownloadingLinger,
|
|
313
|
-
inflightRange: this.inflightRange,
|
|
314
|
-
autoClose: true,
|
|
315
|
-
active: false,
|
|
316
|
-
encryptionKey: opts.encryptionKey || null,
|
|
317
|
-
isBlockKey: !!opts.isBlockKey,
|
|
318
|
-
userData,
|
|
319
|
-
manifest,
|
|
320
|
-
key,
|
|
321
|
-
compat: opts.compat,
|
|
322
|
-
cache: opts.cache,
|
|
323
|
-
globalCache: this.globalCache,
|
|
324
|
-
createIfMissing: opts.createIfMissing === false ? false : !opts._discoveryKey,
|
|
325
|
-
keyPair: hasKeyPair ? keyPair : null
|
|
326
|
-
})
|
|
327
|
-
|
|
328
|
-
if (this._root.closing) {
|
|
329
|
-
try {
|
|
330
|
-
await core.close()
|
|
331
|
-
} catch {}
|
|
332
|
-
throw new Error('The corestore is closed')
|
|
236
|
+
if (!core.replicator.attached(muxer)) {
|
|
237
|
+
core.replicator.attachTo(muxer)
|
|
333
238
|
}
|
|
239
|
+
}
|
|
334
240
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
const ondownloading = () => {
|
|
344
|
-
for (const { stream } of this._replicationStreams) {
|
|
345
|
-
core.replicate(stream, { session: true })
|
|
346
|
-
}
|
|
241
|
+
replicate (isInitiator, opts) {
|
|
242
|
+
const isExternal = isStream(isInitiator)
|
|
243
|
+
const stream = Hypercore.createProtocolStream(isInitiator, {
|
|
244
|
+
...opts,
|
|
245
|
+
ondiscoverykey: discoveryKey => {
|
|
246
|
+
if (this.closing) return
|
|
247
|
+
const muxer = stream.noiseStream.userData
|
|
248
|
+
return this._attachMaybe(muxer, discoveryKey)
|
|
347
249
|
}
|
|
348
|
-
// when the replicator says we are downloading, answer the call
|
|
349
|
-
core.replicator.ondownloading = ondownloading
|
|
350
|
-
// trigger once if the condition is already true
|
|
351
|
-
if (core.replicator.downloading) ondownloading()
|
|
352
|
-
}, () => {
|
|
353
|
-
this._noCoreCache.set(id, true)
|
|
354
|
-
this.cores.delete(id)
|
|
355
|
-
})
|
|
356
|
-
core.once('close', () => {
|
|
357
|
-
this._emitCore('core-close', core)
|
|
358
|
-
this.cores.delete(id)
|
|
359
|
-
})
|
|
360
|
-
core.on('conflict', (len, fork, proof) => {
|
|
361
|
-
this.emit('conflict', core, len, fork, proof)
|
|
362
250
|
})
|
|
363
251
|
|
|
364
|
-
|
|
365
|
-
|
|
252
|
+
if (this.cores.size > 0) {
|
|
253
|
+
const muxer = stream.noiseStream.userData
|
|
254
|
+
const uncork = muxer.uncork.bind(muxer)
|
|
255
|
+
muxer.cork()
|
|
366
256
|
|
|
367
|
-
|
|
368
|
-
|
|
257
|
+
for (const core of this.cores) {
|
|
258
|
+
if (!core.replicator.downloading || core.replicator.attached(muxer) || !core.opened) continue
|
|
259
|
+
core.replicator.attachTo(muxer)
|
|
260
|
+
}
|
|
369
261
|
|
|
370
|
-
|
|
371
|
-
publicKey: b4a.allocUnsafeSlow(sodium.crypto_sign_PUBLICKEYBYTES),
|
|
372
|
-
secretKey: b4a.alloc(sodium.crypto_sign_SECRETKEYBYTES)
|
|
262
|
+
stream.noiseStream.opened.then(uncork)
|
|
373
263
|
}
|
|
374
264
|
|
|
375
|
-
const
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
return keyPair
|
|
265
|
+
const record = this.streamTracker.add(stream, isExternal)
|
|
266
|
+
stream.once('close', () => this.streamTracker.remove(record))
|
|
267
|
+
return stream
|
|
379
268
|
}
|
|
380
269
|
|
|
381
|
-
get (opts
|
|
382
|
-
if (
|
|
383
|
-
opts =
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
270
|
+
get (opts) {
|
|
271
|
+
if (b4a.isBuffer(opts) || typeof opts === 'string') opts = { key: opts }
|
|
272
|
+
if (!opts) opts = {}
|
|
273
|
+
|
|
274
|
+
const conf = {
|
|
275
|
+
preload: null,
|
|
276
|
+
parent: opts.parent || null,
|
|
277
|
+
sessions: null,
|
|
278
|
+
ongc: null,
|
|
279
|
+
core: null,
|
|
280
|
+
active: opts.active !== false,
|
|
281
|
+
encryptionKey: opts.encryptionKey || null,
|
|
282
|
+
isBlockKey: !!opts.isBlockKey,
|
|
283
|
+
valueEncoding: opts.valueEncoding || null,
|
|
284
|
+
exclusive: !!opts.exclusive,
|
|
285
|
+
manifest: opts.manifest || null,
|
|
286
|
+
keyPair: opts.keyPair || null,
|
|
287
|
+
onwait: opts.onwait || null,
|
|
288
|
+
wait: opts.wait !== false,
|
|
289
|
+
timeout: opts.timeout || 0,
|
|
290
|
+
draft: !!opts.draft,
|
|
291
|
+
writable: opts.writable
|
|
390
292
|
}
|
|
391
293
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
globalCache: this.globalCache,
|
|
398
|
-
name: null,
|
|
399
|
-
preload: async () => {
|
|
400
|
-
if (opts.preload) opts = { ...opts, ...(await opts.preload()) }
|
|
401
|
-
if (!this.opened) await this.ready()
|
|
402
|
-
|
|
403
|
-
const keys = await this._generateKeys(opts)
|
|
404
|
-
|
|
405
|
-
id = b4a.toString(keys.discoveryKey, 'hex')
|
|
406
|
-
rw = (opts.exclusive && opts.writable !== false) ? this._getLock(id) : null
|
|
407
|
-
|
|
408
|
-
if (rw) await rw.write.lock()
|
|
409
|
-
return await this._preload(id, keys, opts)
|
|
410
|
-
}
|
|
411
|
-
})
|
|
412
|
-
|
|
413
|
-
this._sessions.add(core)
|
|
414
|
-
if (this._findingPeersCount > 0) {
|
|
415
|
-
this._findingPeers.push(core.findingPeers())
|
|
294
|
+
// name requires us to rt to storage + ready, so needs preload
|
|
295
|
+
// same goes if user has defined async preload obvs
|
|
296
|
+
if (opts.name || opts.preload) {
|
|
297
|
+
conf.preload = this._preload(opts)
|
|
298
|
+
return new Hypercore(null, null, conf)
|
|
416
299
|
}
|
|
417
300
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
// as _decFindingPeers clear them all.
|
|
422
|
-
this._sessions.delete(core)
|
|
301
|
+
// if not not we can sync create it, which just is easier for the
|
|
302
|
+
// upstream user in terms of guarantees (key is there etc etc)
|
|
303
|
+
const core = this._getCore(null, opts)
|
|
423
304
|
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
}
|
|
305
|
+
conf.core = core
|
|
306
|
+
conf.sessions = this.sessions.get(core.id)
|
|
307
|
+
conf.ongc = this._ongcBound
|
|
428
308
|
|
|
429
|
-
|
|
430
|
-
|
|
309
|
+
return new Hypercore(null, null, conf)
|
|
310
|
+
}
|
|
431
311
|
|
|
432
|
-
|
|
312
|
+
async createKeyPair (name, ns = this.ns) {
|
|
313
|
+
if (this.opened === false) await this.ready()
|
|
314
|
+
return createKeyPair(this.primaryKey, ns, name)
|
|
433
315
|
}
|
|
434
316
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
...opts,
|
|
439
|
-
ondiscoverykey: async discoveryKey => {
|
|
440
|
-
if (this.closing) return
|
|
317
|
+
async _preload (opts) {
|
|
318
|
+
if (opts.preload) opts = { ...opts, ...(await opts.preload) }
|
|
319
|
+
if (this.opened === false) await this.ready()
|
|
441
320
|
|
|
442
|
-
|
|
443
|
-
|
|
321
|
+
const discoveryKey = opts.name ? await this.storage.getAlias({ name: opts.name, namespace: this.ns }) : null
|
|
322
|
+
const core = this._getCore(discoveryKey, opts)
|
|
444
323
|
|
|
445
|
-
|
|
324
|
+
return {
|
|
325
|
+
parent: opts.parent || null,
|
|
326
|
+
core,
|
|
327
|
+
sessions: this.sessions.get(core.id),
|
|
328
|
+
ongc: this._ongcBound,
|
|
329
|
+
encryptionKey: opts.encryptionKey || null,
|
|
330
|
+
isBlockKey: !!opts.isBlockKey
|
|
331
|
+
}
|
|
332
|
+
}
|
|
446
333
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
334
|
+
_auth (discoveryKey, opts) {
|
|
335
|
+
const result = {
|
|
336
|
+
keyPair: null,
|
|
337
|
+
key: null,
|
|
338
|
+
discoveryKey,
|
|
339
|
+
manifest: null
|
|
340
|
+
}
|
|
452
341
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
}
|
|
342
|
+
if (opts.name) {
|
|
343
|
+
result.keyPair = createKeyPair(this.primaryKey, this.ns, opts.name)
|
|
344
|
+
} else if (opts.keyPair) {
|
|
345
|
+
result.keyPair = opts.keyPair
|
|
346
|
+
}
|
|
458
347
|
|
|
459
|
-
if (
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
// If the core is not opened, it will be replicated in preload.
|
|
464
|
-
if (!core.opened || core.closing || !core.replicator.downloading) continue
|
|
465
|
-
core.replicate(stream, { session: true })
|
|
466
|
-
}
|
|
467
|
-
stream.noiseStream.opened.then(() => muxer.uncork())
|
|
348
|
+
if (opts.manifest) {
|
|
349
|
+
result.manifest = opts.manifest
|
|
350
|
+
} else if (result.keyPair && !result.discoveryKey) {
|
|
351
|
+
result.manifest = { version: 1, signers: [{ publicKey: result.keyPair.publicKey }] }
|
|
468
352
|
}
|
|
469
353
|
|
|
470
|
-
|
|
471
|
-
|
|
354
|
+
if (opts.key) result.key = ID.decode(opts.key)
|
|
355
|
+
else if (result.manifest) result.key = Hypercore.key(result.manifest)
|
|
472
356
|
|
|
473
|
-
|
|
474
|
-
this._replicationStreams.splice(this._replicationStreams.indexOf(streamRecord), 1)
|
|
475
|
-
})
|
|
357
|
+
if (result.discoveryKey) return result
|
|
476
358
|
|
|
477
|
-
|
|
359
|
+
if (opts.discoveryKey) result.discoveryKey = ID.decode(opts.discoveryKey)
|
|
360
|
+
else if (result.key) result.discoveryKey = crypto.discoveryKey(result.key)
|
|
361
|
+
else throw new Error('Could not derive discovery from input')
|
|
362
|
+
|
|
363
|
+
return result
|
|
478
364
|
}
|
|
479
365
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
return this.session({ ...opts, _bootstrap: name })
|
|
483
|
-
}
|
|
484
|
-
return this.session({ ...opts, namespace: generateNamespace(this._namespace, name) })
|
|
366
|
+
_hasCore (discoveryKey) {
|
|
367
|
+
return this.cores.get(toHex(discoveryKey)) !== null
|
|
485
368
|
}
|
|
486
369
|
|
|
487
|
-
|
|
488
|
-
const
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
370
|
+
_getCore (discoveryKey, opts) {
|
|
371
|
+
const auth = this._auth(discoveryKey, opts)
|
|
372
|
+
|
|
373
|
+
const id = toHex(auth.discoveryKey)
|
|
374
|
+
const existing = this.cores.get(id)
|
|
375
|
+
if (existing) return existing
|
|
376
|
+
|
|
377
|
+
const core = Hypercore.createCore(this.storage, {
|
|
378
|
+
eagerUpgrade: true,
|
|
379
|
+
notDownloadingLinger: opts.notDownloadingLinger,
|
|
380
|
+
allowFork: opts.allowFork !== false,
|
|
381
|
+
inflightRange: opts.inflightRange,
|
|
382
|
+
compat: false, // no compat for now :)
|
|
383
|
+
force: opts.force,
|
|
384
|
+
createIfMissing: opts.createIfMissing,
|
|
385
|
+
discoveryKey: auth.discoveryKey,
|
|
386
|
+
overwrite: opts.overwrite,
|
|
387
|
+
key: auth.key,
|
|
388
|
+
keyPair: auth.keyPair,
|
|
389
|
+
legacy: opts.legacy,
|
|
390
|
+
manifest: auth.manifest,
|
|
391
|
+
globalCache: opts.globalCache || this.globalCache || null,
|
|
392
|
+
alias: opts.name ? { name: opts.name, namespace: this.ns } : null
|
|
497
393
|
})
|
|
498
|
-
if (this === this._root) this._rootStoreSessions.add(session)
|
|
499
|
-
return session
|
|
500
|
-
}
|
|
501
394
|
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
closePromises.push(session.close())
|
|
395
|
+
core.onidle = () => {
|
|
396
|
+
core.destroy()
|
|
397
|
+
this.cores.delete(id, core)
|
|
506
398
|
}
|
|
507
|
-
return Promise.allSettled(closePromises)
|
|
508
|
-
}
|
|
509
399
|
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
// At this point, the primary namespace is closing.
|
|
513
|
-
for (const { stream, isExternal } of this._replicationStreams) {
|
|
514
|
-
// Only close streams that were created by the Corestore
|
|
515
|
-
if (!isExternal) stream.destroy()
|
|
400
|
+
core.replicator.ondownloading = () => {
|
|
401
|
+
this.streamTracker.attachAll(core)
|
|
516
402
|
}
|
|
517
|
-
for (const core of this.cores.values()) {
|
|
518
|
-
closePromises.push(forceClose(core))
|
|
519
|
-
}
|
|
520
|
-
await Promise.allSettled(closePromises)
|
|
521
|
-
await new Promise((resolve, reject) => {
|
|
522
|
-
this._keyStorage.close(err => {
|
|
523
|
-
if (err) return reject(err)
|
|
524
|
-
return resolve(null)
|
|
525
|
-
})
|
|
526
|
-
})
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
async _close () {
|
|
530
|
-
this._root._rootStoreSessions.delete(this)
|
|
531
403
|
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
if (this._root === this) {
|
|
535
|
-
await this._closePrimaryNamespace()
|
|
536
|
-
} else if (this._attached) {
|
|
537
|
-
await this._attached.close()
|
|
538
|
-
}
|
|
404
|
+
this.cores.set(id, core)
|
|
405
|
+
return core
|
|
539
406
|
}
|
|
540
407
|
}
|
|
541
408
|
|
|
542
|
-
|
|
543
|
-
const key = (b4a.isBuffer(opts) || typeof opts === 'string') ? hypercoreId.decode(opts) : null
|
|
544
|
-
if (key) return { key }
|
|
545
|
-
|
|
546
|
-
if (opts.key) {
|
|
547
|
-
opts.key = hypercoreId.decode(opts.key)
|
|
548
|
-
}
|
|
549
|
-
if (opts.keyPair) {
|
|
550
|
-
opts.publicKey = opts.keyPair.publicKey
|
|
551
|
-
opts.secretKey = opts.keyPair.secretKey
|
|
552
|
-
}
|
|
409
|
+
module.exports = Corestore
|
|
553
410
|
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
if (opts.publicKey && !b4a.isBuffer(opts.publicKey)) throw new Error('publicKey option must be a Buffer or Uint8Array')
|
|
557
|
-
if (opts.secretKey && !b4a.isBuffer(opts.secretKey)) throw new Error('secretKey option must be a Buffer or Uint8Array')
|
|
558
|
-
if (!opts._discoveryKey && (!opts.name && !opts.publicKey && !opts.manifest && !opts.key && !opts.preload)) throw new Error('Must provide either a name or a publicKey')
|
|
559
|
-
return opts
|
|
411
|
+
function isStream (s) {
|
|
412
|
+
return typeof s === 'object' && s && typeof s.pipe === 'function'
|
|
560
413
|
}
|
|
561
414
|
|
|
562
415
|
function generateNamespace (namespace, name) {
|
|
@@ -573,19 +426,19 @@ function deriveSeed (primaryKey, namespace, name) {
|
|
|
573
426
|
return out
|
|
574
427
|
}
|
|
575
428
|
|
|
576
|
-
function
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
429
|
+
function createKeyPair (primaryKey, namespace, name) {
|
|
430
|
+
const seed = deriveSeed(primaryKey, namespace, name)
|
|
431
|
+
const buf = b4a.alloc(sodium.crypto_sign_PUBLICKEYBYTES + sodium.crypto_sign_SECRETKEYBYTES)
|
|
432
|
+
const keyPair = {
|
|
433
|
+
publicKey: buf.subarray(0, sodium.crypto_sign_PUBLICKEYBYTES),
|
|
434
|
+
secretKey: buf.subarray(sodium.crypto_sign_PUBLICKEYBYTES)
|
|
435
|
+
}
|
|
436
|
+
sodium.crypto_sign_seed_keypair(keyPair.publicKey, keyPair.secretKey, seed)
|
|
437
|
+
return keyPair
|
|
582
438
|
}
|
|
583
439
|
|
|
584
|
-
|
|
585
|
-
await core.ready()
|
|
586
|
-
return Promise.all(core.sessions.map(s => s.close()))
|
|
587
|
-
}
|
|
440
|
+
function noop () {}
|
|
588
441
|
|
|
589
|
-
function
|
|
590
|
-
return
|
|
442
|
+
function toHex (discoveryKey) {
|
|
443
|
+
return b4a.toString(discoveryKey, 'hex')
|
|
591
444
|
}
|
package/package.json
CHANGED
|
@@ -1,44 +1,43 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "corestore",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.1",
|
|
4
4
|
"description": "A Hypercore factory that simplifies managing collections of cores.",
|
|
5
5
|
"main": "index.js",
|
|
6
|
+
"files": [
|
|
7
|
+
"index.js"
|
|
8
|
+
],
|
|
9
|
+
"dependencies": {
|
|
10
|
+
"b4a": "^1.6.7",
|
|
11
|
+
"bare-events": "^2.5.0",
|
|
12
|
+
"hypercore": "^11.0.0",
|
|
13
|
+
"hypercore-crypto": "^3.4.2",
|
|
14
|
+
"hypercore-id-encoding": "^1.3.0",
|
|
15
|
+
"ready-resource": "^1.1.1",
|
|
16
|
+
"sodium-universal": "^4.0.1"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"brittle": "^3.7.0",
|
|
20
|
+
"rache": "^1.0.0",
|
|
21
|
+
"standard": "^17.1.2",
|
|
22
|
+
"test-tmp": "^1.3.0"
|
|
23
|
+
},
|
|
6
24
|
"scripts": {
|
|
7
25
|
"test": "standard && brittle test/*.js"
|
|
8
26
|
},
|
|
27
|
+
"imports": {
|
|
28
|
+
"events": {
|
|
29
|
+
"bare": "bare-events",
|
|
30
|
+
"default": "events"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
9
33
|
"repository": {
|
|
10
34
|
"type": "git",
|
|
11
|
-
"url": "
|
|
35
|
+
"url": "https://github.com/holepunchto/corestore2.git"
|
|
12
36
|
},
|
|
13
|
-
"
|
|
14
|
-
"corestore"
|
|
15
|
-
],
|
|
16
|
-
"author": "Andrew Osheroff <andrewosh@gmail.com>",
|
|
37
|
+
"author": "Holepunch Inc",
|
|
17
38
|
"license": "MIT",
|
|
18
39
|
"bugs": {
|
|
19
|
-
"url": "https://github.com/holepunchto/
|
|
40
|
+
"url": "https://github.com/holepunchto/corestore2/issues"
|
|
20
41
|
},
|
|
21
|
-
"homepage": "https://github.com/holepunchto/
|
|
22
|
-
"files": [
|
|
23
|
-
"index.js",
|
|
24
|
-
"lib/**.js"
|
|
25
|
-
],
|
|
26
|
-
"devDependencies": {
|
|
27
|
-
"brittle": "^3.2.2",
|
|
28
|
-
"rache": "^1.0.0",
|
|
29
|
-
"random-access-memory": "^6.2.0",
|
|
30
|
-
"standard": "^17.1.0",
|
|
31
|
-
"test-tmp": "^1.0.2"
|
|
32
|
-
},
|
|
33
|
-
"dependencies": {
|
|
34
|
-
"b4a": "^1.6.4",
|
|
35
|
-
"hypercore": "^10.37.10",
|
|
36
|
-
"hypercore-crypto": "^3.4.0",
|
|
37
|
-
"hypercore-id-encoding": "^1.2.0",
|
|
38
|
-
"read-write-mutexify": "^2.1.0",
|
|
39
|
-
"ready-resource": "^1.0.0",
|
|
40
|
-
"safety-catch": "^1.0.1",
|
|
41
|
-
"sodium-universal": "^4.0.0",
|
|
42
|
-
"xache": "^1.1.0"
|
|
43
|
-
}
|
|
42
|
+
"homepage": "https://github.com/holepunchto/corestore2"
|
|
44
43
|
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
The MIT License (MIT)
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2023 Holepunch Inc
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in
|
|
13
|
-
all copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
-
THE SOFTWARE.
|