@fireproof/core 0.5.6 → 0.5.8
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 +18 -0
- package/dist/src/fireproof.d.ts +149 -108
- package/dist/src/fireproof.js +2771 -581
- package/dist/src/fireproof.js.map +1 -1
- package/dist/src/fireproof.mjs +2771 -582
- package/dist/src/fireproof.mjs.map +1 -1
- package/package.json +4 -2
- package/src/blockstore.js +32 -16
- package/src/clock.js +42 -10
- package/src/database.js +52 -13
- package/src/db-index.js +14 -3
- package/src/fireproof.js +2 -40
- package/src/listener.js +1 -1
- package/src/prolly.js +90 -53
- package/src/sync.js +201 -0
- package/src/valet.js +32 -6
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@fireproof/core",
|
3
|
-
"version": "0.5.
|
3
|
+
"version": "0.5.8",
|
4
4
|
"description": "Cloudless database for apps, the browser, and IPFS",
|
5
5
|
"main": "dist/src/fireproof.js",
|
6
6
|
"module": "dist/src/fireproof.mjs",
|
@@ -36,6 +36,7 @@
|
|
36
36
|
"Mikeal Rogers"
|
37
37
|
],
|
38
38
|
"license": "Apache-2.0 OR MIT",
|
39
|
+
"gptdoc": "Fireproof/API/Usage: import { Fireproof, Listener, Index } from '@fireproof/core'; const db = fireproof.storage('app-db-name'); const ok = await db.put({ any: 'json' }); const doc = await db.get(ok.id); await db.del(doc._id); const all = await db.allDocuments(); all.rows.map(({key, value}) => value); const listener = new Listener(db); listener.on('*', updateReactStateFn); const index = new Index(db, (doc, map) => map(doc.any, {custom: Object.keys(doc)})); const result = await index.query({range : ['a', 'z']}); result.rows.map(({ key }) => key);",
|
39
40
|
"dependencies": {
|
40
41
|
"@ipld/car": "^5.1.0",
|
41
42
|
"@ipld/dag-cbor": "^9.0.0",
|
@@ -53,7 +54,8 @@
|
|
53
54
|
"prolly-trees": "1.0.4",
|
54
55
|
"randombytes": "^2.1.0",
|
55
56
|
"rollup-plugin-commonjs": "^10.1.0",
|
56
|
-
"sade": "^1.8.1"
|
57
|
+
"sade": "^1.8.1",
|
58
|
+
"simple-peer": "^9.11.1"
|
57
59
|
},
|
58
60
|
"devDependencies": {
|
59
61
|
"@rollup/plugin-alias": "^5.0.0",
|
package/src/blockstore.js
CHANGED
@@ -34,10 +34,12 @@ export class TransactionBlockstore {
|
|
34
34
|
/** @type {Map<string, Uint8Array>} */
|
35
35
|
committedBlocks = new Map()
|
36
36
|
|
37
|
+
/** @type {Valet} */
|
37
38
|
valet = null
|
38
39
|
|
39
40
|
instanceId = 'blkz.' + Math.random().toString(36).substring(2, 4)
|
40
41
|
inflightTransactions = new Set()
|
42
|
+
syncs = new Set()
|
41
43
|
|
42
44
|
constructor (name, encryptionKey) {
|
43
45
|
if (name) {
|
@@ -75,10 +77,10 @@ export class TransactionBlockstore {
|
|
75
77
|
|
76
78
|
async committedGet (key) {
|
77
79
|
const old = this.committedBlocks.get(key)
|
80
|
+
// console.log('committedGet: ' + key + ' ' + this.instanceId, old.length)
|
78
81
|
if (old) return old
|
79
82
|
if (!this.valet) throw new Error('Missing block: ' + key)
|
80
83
|
const got = await this.valet.getBlock(key)
|
81
|
-
// console.log('committedGet: ' + key)
|
82
84
|
this.committedBlocks.set(key, got)
|
83
85
|
return got
|
84
86
|
}
|
@@ -120,18 +122,24 @@ export class TransactionBlockstore {
|
|
120
122
|
/**
|
121
123
|
* Iterate over all blocks in the store.
|
122
124
|
*
|
123
|
-
* @yields {
|
124
|
-
* @returns {AsyncGenerator<
|
125
|
+
* @yields {{cid: string, bytes: Uint8Array}}
|
126
|
+
* @returns {AsyncGenerator<any, any, any>}
|
125
127
|
*/
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
128
|
+
async * entries () {
|
129
|
+
for (const transaction of this.inflightTransactions) {
|
130
|
+
for (const [str, bytes] of transaction) {
|
131
|
+
yield { cid: str, bytes }
|
132
|
+
}
|
133
|
+
}
|
134
|
+
for (const [str, bytes] of this.committedBlocks) {
|
135
|
+
yield { cid: str, bytes }
|
136
|
+
}
|
137
|
+
if (this.valet) {
|
138
|
+
for await (const { cid } of this.valet.cids()) {
|
139
|
+
yield { cid }
|
140
|
+
}
|
141
|
+
}
|
142
|
+
}
|
135
143
|
|
136
144
|
/**
|
137
145
|
* Begin a transaction. Ensures the uncommited blocks are empty at the begining.
|
@@ -150,8 +158,16 @@ export class TransactionBlockstore {
|
|
150
158
|
* @returns {Promise<void>}
|
151
159
|
* @memberof TransactionBlockstore
|
152
160
|
*/
|
153
|
-
async commit (innerBlockstore) {
|
161
|
+
async commit (innerBlockstore, doSync = true) {
|
162
|
+
// console.log('commit', doSync, innerBlockstore.label)
|
154
163
|
await this.doCommit(innerBlockstore)
|
164
|
+
if (doSync) {
|
165
|
+
// const all =
|
166
|
+
await Promise.all([...this.syncs].map(async sync => sync.sendUpdate(innerBlockstore).catch(e => {
|
167
|
+
console.error('sync error', e)
|
168
|
+
this.syncs.delete(sync)
|
169
|
+
})))
|
170
|
+
}
|
155
171
|
}
|
156
172
|
|
157
173
|
// first get the transaction blockstore from the map of transaction blockstores
|
@@ -170,8 +186,8 @@ export class TransactionBlockstore {
|
|
170
186
|
cids.add(stringCid)
|
171
187
|
}
|
172
188
|
}
|
189
|
+
// console.log(innerBlockstore.label, 'committing', cids.size, 'blocks', [...cids].map(cid => cid.toString()), this.valet)
|
173
190
|
if (cids.size > 0 && this.valet) {
|
174
|
-
// console.log(innerBlockstore.label, 'committing', cids.size, 'blocks')
|
175
191
|
await this.valet.writeTransaction(innerBlockstore, cids)
|
176
192
|
}
|
177
193
|
}
|
@@ -195,7 +211,7 @@ export class TransactionBlockstore {
|
|
195
211
|
* @returns {Promise<any>}
|
196
212
|
* @memberof TransactionBlockstore
|
197
213
|
*/
|
198
|
-
export const doTransaction = async (label, blockstore, doFun) => {
|
214
|
+
export const doTransaction = async (label, blockstore, doFun, doSync = true) => {
|
199
215
|
// @ts-ignore
|
200
216
|
if (!blockstore.commit) return await doFun(blockstore)
|
201
217
|
// @ts-ignore
|
@@ -203,7 +219,7 @@ export const doTransaction = async (label, blockstore, doFun) => {
|
|
203
219
|
try {
|
204
220
|
const result = await doFun(innerBlockstore)
|
205
221
|
// @ts-ignore
|
206
|
-
await blockstore.commit(innerBlockstore)
|
222
|
+
await blockstore.commit(innerBlockstore, doSync)
|
207
223
|
return result
|
208
224
|
} catch (e) {
|
209
225
|
console.error(`Transaction ${label} failed`, e, e.stack)
|
package/src/clock.js
CHANGED
@@ -190,7 +190,11 @@ async function contains (events, a, b) {
|
|
190
190
|
*/
|
191
191
|
export async function * vis (blocks, head, options = {}) {
|
192
192
|
// @ts-ignore
|
193
|
-
const renderNodeLabel = options.renderNodeLabel ?? ((b) =>
|
193
|
+
const renderNodeLabel = options.renderNodeLabel ?? ((b) => {
|
194
|
+
// @ts-ignore
|
195
|
+
const { key, root, type } = b.value.data
|
196
|
+
return b.cid.toString() + '\n' + JSON.stringify({ key, root: root.cid.toString(), type }, null, 2).replace(/"/g, '\'')
|
197
|
+
})
|
194
198
|
const events = new EventFetcher(blocks)
|
195
199
|
yield 'digraph clock {'
|
196
200
|
yield ' node [shape=point fontname="Courier"]; head;'
|
@@ -231,24 +235,29 @@ export async function findEventsToSync (blocks, head) {
|
|
231
235
|
// console.time(callTag + '.contains')
|
232
236
|
const toSync = await asyncFilter(sorted, async (uks) => !(await contains(events, ancestor, uks.cid)))
|
233
237
|
// console.timeEnd(callTag + '.contains')
|
238
|
+
// console.log('toSync.contains', toSync.length)
|
234
239
|
|
235
|
-
return { cids: events
|
240
|
+
return { cids: events, events: toSync }
|
236
241
|
}
|
237
242
|
|
238
243
|
const asyncFilter = async (arr, predicate) =>
|
239
244
|
Promise.all(arr.map(predicate)).then((results) => arr.filter((_v, index) => results[index]))
|
240
245
|
|
241
|
-
export async function findCommonAncestorWithSortedEvents (events, children) {
|
246
|
+
export async function findCommonAncestorWithSortedEvents (events, children, doFull = false) {
|
247
|
+
// console.trace('findCommonAncestorWithSortedEvents')
|
242
248
|
// const callTag = Math.random().toString(36).substring(7)
|
249
|
+
// console.log(callTag + '.children', children.map((c) => c.toString()))
|
243
250
|
// console.time(callTag + '.findCommonAncestor')
|
244
251
|
const ancestor = await findCommonAncestor(events, children)
|
245
252
|
// console.timeEnd(callTag + '.findCommonAncestor')
|
253
|
+
// console.log('ancestor', ancestor.toString())
|
246
254
|
if (!ancestor) {
|
247
255
|
throw new Error('failed to find common ancestor event')
|
248
256
|
}
|
249
257
|
// console.time(callTag + '.findSortedEvents')
|
250
|
-
const sorted = await findSortedEvents(events, children, ancestor)
|
258
|
+
const sorted = await findSortedEvents(events, children, ancestor, doFull)
|
251
259
|
// console.timeEnd(callTag + '.findSortedEvents')
|
260
|
+
// console.log('sorted', sorted.length)
|
252
261
|
return { ancestor, sorted }
|
253
262
|
}
|
254
263
|
|
@@ -261,6 +270,7 @@ export async function findCommonAncestorWithSortedEvents (events, children) {
|
|
261
270
|
*/
|
262
271
|
async function findCommonAncestor (events, children) {
|
263
272
|
if (!children.length) return
|
273
|
+
if (children.length === 1) return children[0]
|
264
274
|
const candidates = children.map((c) => [c])
|
265
275
|
while (true) {
|
266
276
|
let changed = false
|
@@ -281,7 +291,7 @@ async function findCommonAncestor (events, children) {
|
|
281
291
|
* @param {import('./clock').EventLink<EventData>} root
|
282
292
|
*/
|
283
293
|
async function findAncestorCandidate (events, root) {
|
284
|
-
const { value: event } = await events.get(root)
|
294
|
+
const { value: event } = await events.get(root)// .catch(() => ({ value: { parents: [] } }))
|
285
295
|
if (!event.parents.length) return root
|
286
296
|
return event.parents.length === 1 ? event.parents[0] : findCommonAncestor(events, event.parents)
|
287
297
|
}
|
@@ -291,6 +301,7 @@ async function findAncestorCandidate (events, root) {
|
|
291
301
|
* @param {Array<T[]>} arrays
|
292
302
|
*/
|
293
303
|
function findCommonString (arrays) {
|
304
|
+
// console.log('findCommonString', arrays.map((a) => a.map((i) => String(i))))
|
294
305
|
arrays = arrays.map((a) => [...a])
|
295
306
|
for (const arr of arrays) {
|
296
307
|
for (const item of arr) {
|
@@ -308,15 +319,33 @@ function findCommonString (arrays) {
|
|
308
319
|
/**
|
309
320
|
* Find and sort events between the head(s) and the tail.
|
310
321
|
* @param {import('./clock').EventFetcher} events
|
311
|
-
* @param {
|
322
|
+
* @param {any[]} head
|
312
323
|
* @param {import('./clock').EventLink<EventData>} tail
|
313
324
|
*/
|
314
|
-
async function findSortedEvents (events, head, tail) {
|
325
|
+
async function findSortedEvents (events, head, tail, doFull) {
|
315
326
|
// const callTag = Math.random().toString(36).substring(7)
|
316
327
|
// get weighted events - heavier events happened first
|
328
|
+
// const callTag = Math.random().toString(36).substring(7)
|
329
|
+
|
317
330
|
/** @type {Map<string, { event: import('./clock').EventBlockView<EventData>, weight: number }>} */
|
318
331
|
const weights = new Map()
|
332
|
+
head = [...new Set([...head.map((h) => h.toString())])]
|
333
|
+
// console.log(callTag + '.head', head.length)
|
334
|
+
|
335
|
+
const allEvents = new Set([tail.toString(), ...head])
|
336
|
+
if (!doFull && allEvents.size === 1) {
|
337
|
+
// console.log('head contains tail', tail.toString())
|
338
|
+
return []
|
339
|
+
// const event = await events.get(tail)
|
340
|
+
// return [event]
|
341
|
+
}
|
342
|
+
|
343
|
+
// console.log('finding events')
|
344
|
+
// console.log(callTag + '.head', head.length, [...head.map((h) => h.toString())], tail.toString())
|
345
|
+
|
346
|
+
// console.time(callTag + '.findEvents')
|
319
347
|
const all = await Promise.all(head.map((h) => findEvents(events, h, tail)))
|
348
|
+
// console.timeEnd(callTag + '.findEvents')
|
320
349
|
for (const arr of all) {
|
321
350
|
for (const { event, depth } of arr) {
|
322
351
|
// console.log('event value', event.value.data.value)
|
@@ -345,7 +374,7 @@ async function findSortedEvents (events, head, tail) {
|
|
345
374
|
const sorted = Array.from(buckets)
|
346
375
|
.sort((a, b) => b[0] - a[0])
|
347
376
|
.flatMap(([, es]) => es.sort((a, b) => (String(a.cid) < String(b.cid) ? -1 : 1)))
|
348
|
-
// console.log('sorted', sorted.map(s => s.
|
377
|
+
// console.log('sorted', sorted.map(s => s.cid))
|
349
378
|
|
350
379
|
return sorted
|
351
380
|
}
|
@@ -357,11 +386,14 @@ async function findSortedEvents (events, head, tail) {
|
|
357
386
|
* @returns {Promise<Array<{ event: EventBlockView<EventData>, depth: number }>>}
|
358
387
|
*/
|
359
388
|
async function findEvents (events, start, end, depth = 0) {
|
360
|
-
// console.log('findEvents', start)
|
389
|
+
// console.log('findEvents', start.toString(), end.toString(), depth)
|
361
390
|
const event = await events.get(start)
|
391
|
+
const send = String(end)
|
362
392
|
const acc = [{ event, depth }]
|
363
393
|
const { parents } = event.value
|
364
|
-
if (parents.length === 1 && String(parents[0]) ===
|
394
|
+
// if (parents.length === 1 && String(parents[0]) === send) return acc
|
395
|
+
if (parents.findIndex((p) => String(p) === send) !== -1) return acc
|
396
|
+
// if (parents.length === 1) return acc
|
365
397
|
const rest = await Promise.all(parents.map((p) => findEvents(events, p, end, depth + 1)))
|
366
398
|
return acc.concat(...rest)
|
367
399
|
}
|
package/src/database.js
CHANGED
@@ -26,15 +26,16 @@ export const parseCID = cid => (typeof cid === 'string' ? CID.parse(cid) : cid)
|
|
26
26
|
*/
|
27
27
|
export class Database {
|
28
28
|
listeners = new Set()
|
29
|
+
indexes = new Map()
|
30
|
+
rootCache = null
|
31
|
+
eventsCache = new Map()
|
29
32
|
|
30
|
-
// todo refactor this for the next version
|
31
33
|
constructor (blocks, clock, config = {}) {
|
32
34
|
this.name = config.name
|
33
35
|
this.instanceId = `fp.${this.name}.${Math.random().toString(36).substring(2, 7)}`
|
34
36
|
this.blocks = blocks
|
35
37
|
this.clock = clock
|
36
38
|
this.config = config
|
37
|
-
this.indexes = new Map()
|
38
39
|
}
|
39
40
|
|
40
41
|
/**
|
@@ -101,11 +102,22 @@ export class Database {
|
|
101
102
|
* @instance
|
102
103
|
*/
|
103
104
|
async changesSince (event) {
|
105
|
+
// console.log('events for', this.instanceId, event.constructor.name)
|
104
106
|
// console.log('changesSince', this.instanceId, event, this.clock)
|
105
107
|
let rows, dataCIDs, clockCIDs
|
106
108
|
// if (!event) event = []
|
107
109
|
if (event) {
|
108
|
-
|
110
|
+
event = event.map((cid) => cid.toString())
|
111
|
+
const eventKey = JSON.stringify([...event, ...this.clockToJSON()])
|
112
|
+
|
113
|
+
let resp
|
114
|
+
if (this.eventsCache.has(eventKey)) {
|
115
|
+
console.log('events from cache')
|
116
|
+
resp = this.eventsCache.get(eventKey)
|
117
|
+
} else {
|
118
|
+
resp = await eventsSince(this.blocks, this.clock, event)
|
119
|
+
this.eventsCache.set(eventKey, resp)
|
120
|
+
}
|
109
121
|
const docsMap = new Map()
|
110
122
|
for (const { key, type, value } of resp.result.map(decodeEvent)) {
|
111
123
|
if (type === 'del') {
|
@@ -118,7 +130,9 @@ export class Database {
|
|
118
130
|
clockCIDs = resp.clockCIDs
|
119
131
|
// console.log('change rows', this.instanceId, rows)
|
120
132
|
} else {
|
121
|
-
const allResp = await getAll(this.blocks, this.clock)
|
133
|
+
const allResp = await getAll(this.blocks, this.clock, this.rootCache)
|
134
|
+
this.rootCache = { root: allResp.root, clockCIDs: allResp.clockCIDs }
|
135
|
+
|
122
136
|
rows = allResp.result.map(({ key, value }) => decodeEvent({ key, value }))
|
123
137
|
dataCIDs = allResp.cids
|
124
138
|
// console.log('dbdoc rows', this.instanceId, rows)
|
@@ -131,7 +145,9 @@ export class Database {
|
|
131
145
|
}
|
132
146
|
|
133
147
|
async allDocuments () {
|
134
|
-
const allResp = await getAll(this.blocks, this.clock)
|
148
|
+
const allResp = await getAll(this.blocks, this.clock, this.rootCache)
|
149
|
+
this.rootCache = { root: allResp.root, clockCIDs: allResp.clockCIDs }
|
150
|
+
|
135
151
|
const rows = allResp.result
|
136
152
|
.map(({ key, value }) => decodeEvent({ key, value }))
|
137
153
|
.map(({ key, value }) => ({ key, value: { _id: key, ...value } }))
|
@@ -143,7 +159,9 @@ export class Database {
|
|
143
159
|
}
|
144
160
|
|
145
161
|
async allCIDs () {
|
146
|
-
const allResp = await getAll(this.blocks, this.clock)
|
162
|
+
const allResp = await getAll(this.blocks, this.clock, this.rootCache, true)
|
163
|
+
this.rootCache = { root: allResp.root, clockCIDs: allResp.clockCIDs }
|
164
|
+
// console.log('allcids', allResp.cids, allResp.clockCIDs)
|
147
165
|
const cids = await cidsToProof(allResp.cids)
|
148
166
|
const clockCids = await cidsToProof(allResp.clockCIDs)
|
149
167
|
// console.log('allcids', cids, clockCids)
|
@@ -151,6 +169,14 @@ export class Database {
|
|
151
169
|
return [...cids, ...clockCids] // need a single block version of clock head, maybe an encoded block for it
|
152
170
|
}
|
153
171
|
|
172
|
+
async allStoredCIDs () {
|
173
|
+
const allCIDs = []
|
174
|
+
for await (const { cid } of this.blocks.entries()) {
|
175
|
+
allCIDs.push(cid)
|
176
|
+
}
|
177
|
+
return allCIDs
|
178
|
+
}
|
179
|
+
|
154
180
|
/**
|
155
181
|
* Runs validation on the specified document using the Fireproof instance's configuration. Throws an error if the document is invalid.
|
156
182
|
*
|
@@ -180,13 +206,13 @@ export class Database {
|
|
180
206
|
*/
|
181
207
|
async get (key, opts = {}) {
|
182
208
|
const clock = opts.clock || this.clock
|
183
|
-
const resp = await get(this.blocks, clock, charwise.encode(key))
|
184
|
-
|
209
|
+
const resp = await get(this.blocks, clock, charwise.encode(key), this.rootCache)
|
210
|
+
this.rootCache = { root: resp.root, clockCIDs: resp.clockCIDs }
|
185
211
|
// this tombstone is temporary until we can get the prolly tree to delete
|
186
212
|
if (!resp || resp.result === null) {
|
187
213
|
throw new Error('Not found')
|
188
214
|
}
|
189
|
-
const doc = resp.result
|
215
|
+
const doc = { ...resp.result }
|
190
216
|
if (opts.mvcc === true) {
|
191
217
|
doc._clock = this.clockToJSON()
|
192
218
|
}
|
@@ -280,9 +306,20 @@ export class Database {
|
|
280
306
|
}
|
281
307
|
|
282
308
|
applyClock (prevClock, newClock) {
|
283
|
-
// console.log('
|
284
|
-
|
285
|
-
this.clock
|
309
|
+
// console.log('prevClock', prevClock.length, prevClock.map((cid) => cid.toString()))
|
310
|
+
// console.log('newClock', newClock.length, newClock.map((cid) => cid.toString()))
|
311
|
+
// console.log('this.clock', this.clock.length, this.clockToJSON())
|
312
|
+
const stPrev = prevClock.map(cid => cid.toString())
|
313
|
+
const keptPrevClock = this.clock.filter(cid => stPrev.indexOf(cid.toString()) === -1)
|
314
|
+
const merged = keptPrevClock.concat(newClock)
|
315
|
+
const uniquebyCid = new Map()
|
316
|
+
for (const cid of merged) {
|
317
|
+
uniquebyCid.set(cid.toString(), cid)
|
318
|
+
}
|
319
|
+
this.clock = Array.from(uniquebyCid.values()).sort((a, b) => a.toString().localeCompare(b.toString()))
|
320
|
+
this.rootCache = null
|
321
|
+
this.eventsCache.clear()
|
322
|
+
// console.log('afterClock', this.clock.length, this.clockToJSON())
|
286
323
|
}
|
287
324
|
|
288
325
|
// /**
|
@@ -341,7 +378,9 @@ export class Database {
|
|
341
378
|
}
|
342
379
|
|
343
380
|
export async function cidsToProof (cids) {
|
344
|
-
if (!cids
|
381
|
+
if (!cids) return []
|
382
|
+
if (!cids.all) { return [...cids] }
|
383
|
+
|
345
384
|
const all = await cids.all()
|
346
385
|
return [...all].map(cid => cid.toString())
|
347
386
|
}
|
package/src/db-index.js
CHANGED
@@ -7,7 +7,7 @@ import { sha256 as hasher } from 'multiformats/hashes/sha2'
|
|
7
7
|
import { nocache as cache } from 'prolly-trees/cache'
|
8
8
|
// @ts-ignore
|
9
9
|
import { bf, simpleCompare } from 'prolly-trees/utils'
|
10
|
-
import { makeGetBlock } from './prolly.js'
|
10
|
+
import { makeGetBlock, visMerkleTree } from './prolly.js'
|
11
11
|
// eslint-disable-next-line no-unused-vars
|
12
12
|
import { Database, cidsToProof } from './database.js'
|
13
13
|
|
@@ -35,8 +35,8 @@ const refCompare = (aRef, bRef) => {
|
|
35
35
|
return simpleCompare(aRef, bRef)
|
36
36
|
}
|
37
37
|
|
38
|
-
const dbIndexOpts = { cache, chunker: bf(
|
39
|
-
const idIndexOpts = { cache, chunker: bf(
|
38
|
+
const dbIndexOpts = { cache, chunker: bf(30), codec, hasher, compare }
|
39
|
+
const idIndexOpts = { cache, chunker: bf(30), codec, hasher, compare: simpleCompare }
|
40
40
|
|
41
41
|
const makeDoc = ({ key, value }) => ({ _id: key, ...value })
|
42
42
|
|
@@ -93,6 +93,9 @@ const indexEntriesForChanges = (changes, mapFn) => {
|
|
93
93
|
*
|
94
94
|
*/
|
95
95
|
export class DbIndex {
|
96
|
+
/**
|
97
|
+
* @param {Database} database
|
98
|
+
*/
|
96
99
|
constructor (database, name, mapFn, clock = null, opts = {}) {
|
97
100
|
this.database = database
|
98
101
|
if (!database.indexBlocks) {
|
@@ -164,6 +167,14 @@ export class DbIndex {
|
|
164
167
|
return new DbIndex(database, name, code, clock)
|
165
168
|
}
|
166
169
|
|
170
|
+
async visKeyTree () {
|
171
|
+
return await visMerkleTree(this.database.indexBlocks, this.indexById.cid)
|
172
|
+
}
|
173
|
+
|
174
|
+
async visIdTree () {
|
175
|
+
return await visMerkleTree(this.database.indexBlocks, this.indexByKey.cid)
|
176
|
+
}
|
177
|
+
|
167
178
|
/**
|
168
179
|
* JSDoc for Query type.
|
169
180
|
* @typedef {Object} DbQuery
|
package/src/fireproof.js
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
import randomBytes from 'randombytes'
|
2
|
-
|
3
2
|
import { Database, parseCID } from './database.js'
|
4
3
|
import { Listener } from './listener.js'
|
5
4
|
import { DbIndex as Index } from './db-index.js'
|
6
5
|
import { TransactionBlockstore } from './blockstore.js'
|
7
6
|
import { localGet } from './utils.js'
|
8
|
-
import {
|
7
|
+
import { Sync } from './sync.js'
|
9
8
|
|
10
|
-
export { Index, Listener, Database }
|
9
|
+
export { Index, Listener, Database, Sync }
|
11
10
|
|
12
11
|
export class Fireproof {
|
13
12
|
/**
|
@@ -85,41 +84,4 @@ export class Fireproof {
|
|
85
84
|
await database.notifyReset() // hmm... indexes should listen to this? might be more complex than worth it. so far this is the only caller
|
86
85
|
return database
|
87
86
|
}
|
88
|
-
|
89
|
-
// get all the cids
|
90
|
-
// tell valet to make a file
|
91
|
-
static async makeCar (database, key) {
|
92
|
-
const allCIDs = await database.allCIDs()
|
93
|
-
const blocks = database.blocks
|
94
|
-
|
95
|
-
const rootCid = parseCID(allCIDs[allCIDs.length - 1])
|
96
|
-
if (typeof key === 'undefined') {
|
97
|
-
key = blocks.valet?.getKeyMaterial()
|
98
|
-
}
|
99
|
-
if (key) {
|
100
|
-
return blocksToEncryptedCarBlock(
|
101
|
-
rootCid,
|
102
|
-
{
|
103
|
-
entries: () => allCIDs.map(cid => ({ cid })),
|
104
|
-
get: async cid => await blocks.get(cid)
|
105
|
-
},
|
106
|
-
key
|
107
|
-
)
|
108
|
-
} else {
|
109
|
-
const carBlocks = await Promise.all(
|
110
|
-
allCIDs.map(async c => {
|
111
|
-
const b = await blocks.get(c)
|
112
|
-
// console.log('block', b)
|
113
|
-
if (typeof b.cid === 'string') {
|
114
|
-
b.cid = parseCID(b.cid)
|
115
|
-
}
|
116
|
-
// if (b.bytes.constructor.name === 'Buffer') console.log('conver vbuff')
|
117
|
-
return b
|
118
|
-
})
|
119
|
-
)
|
120
|
-
return blocksToCarBlock(rootCid, {
|
121
|
-
entries: () => carBlocks
|
122
|
-
})
|
123
|
-
}
|
124
|
-
}
|
125
87
|
}
|
package/src/listener.js
CHANGED
@@ -41,7 +41,7 @@ export class Listener {
|
|
41
41
|
* @returns {Function} A function to unsubscribe from the topic.
|
42
42
|
* @memberof Listener
|
43
43
|
* @instance
|
44
|
-
* @param {any} [since] - clock to flush from on launch
|
44
|
+
* @param {any} [since] - clock to flush from on launch, pass null for all
|
45
45
|
*/
|
46
46
|
on (topic, subscriber, since = undefined) {
|
47
47
|
const listOfTopicSubscribers = getTopicList(this.subcribers, topic)
|