@fireproof/core 0.5.7 → 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/dist/src/fireproof.d.ts +109 -104
- package/dist/src/fireproof.js +188 -84
- package/dist/src/fireproof.js.map +1 -1
- package/dist/src/fireproof.mjs +188 -84
- package/dist/src/fireproof.mjs.map +1 -1
- package/package.json +1 -1
- package/src/blockstore.js +4 -1
- package/src/clock.js +41 -9
- package/src/database.js +33 -12
- package/src/db-index.js +14 -3
- package/src/prolly.js +82 -48
- package/src/sync.js +18 -11
- package/src/valet.js +1 -1
package/dist/src/fireproof.mjs
CHANGED
@@ -5666,7 +5666,11 @@ async function contains (events, a, b) {
|
|
5666
5666
|
*/
|
5667
5667
|
async function * vis$1 (blocks, head, options = {}) {
|
5668
5668
|
// @ts-ignore
|
5669
|
-
const renderNodeLabel = options.renderNodeLabel ?? ((b) =>
|
5669
|
+
const renderNodeLabel = options.renderNodeLabel ?? ((b) => {
|
5670
|
+
// @ts-ignore
|
5671
|
+
const { key, root, type } = b.value.data;
|
5672
|
+
return b.cid.toString() + '\n' + JSON.stringify({ key, root: root.cid.toString(), type }, null, 2).replace(/"/g, '\'')
|
5673
|
+
});
|
5670
5674
|
const events = new EventFetcher(blocks);
|
5671
5675
|
yield 'digraph clock {';
|
5672
5676
|
yield ' node [shape=point fontname="Courier"]; head;';
|
@@ -5707,6 +5711,7 @@ async function findEventsToSync (blocks, head) {
|
|
5707
5711
|
// console.time(callTag + '.contains')
|
5708
5712
|
const toSync = await asyncFilter(sorted, async (uks) => !(await contains(events, ancestor, uks.cid)));
|
5709
5713
|
// console.timeEnd(callTag + '.contains')
|
5714
|
+
// console.log('toSync.contains', toSync.length)
|
5710
5715
|
|
5711
5716
|
return { cids: events, events: toSync }
|
5712
5717
|
}
|
@@ -5714,17 +5719,21 @@ async function findEventsToSync (blocks, head) {
|
|
5714
5719
|
const asyncFilter = async (arr, predicate) =>
|
5715
5720
|
Promise.all(arr.map(predicate)).then((results) => arr.filter((_v, index) => results[index]));
|
5716
5721
|
|
5717
|
-
async function findCommonAncestorWithSortedEvents (events, children) {
|
5722
|
+
async function findCommonAncestorWithSortedEvents (events, children, doFull = false) {
|
5723
|
+
// console.trace('findCommonAncestorWithSortedEvents')
|
5718
5724
|
// const callTag = Math.random().toString(36).substring(7)
|
5725
|
+
// console.log(callTag + '.children', children.map((c) => c.toString()))
|
5719
5726
|
// console.time(callTag + '.findCommonAncestor')
|
5720
5727
|
const ancestor = await findCommonAncestor(events, children);
|
5721
5728
|
// console.timeEnd(callTag + '.findCommonAncestor')
|
5729
|
+
// console.log('ancestor', ancestor.toString())
|
5722
5730
|
if (!ancestor) {
|
5723
5731
|
throw new Error('failed to find common ancestor event')
|
5724
5732
|
}
|
5725
5733
|
// console.time(callTag + '.findSortedEvents')
|
5726
|
-
const sorted = await findSortedEvents(events, children, ancestor);
|
5734
|
+
const sorted = await findSortedEvents(events, children, ancestor, doFull);
|
5727
5735
|
// console.timeEnd(callTag + '.findSortedEvents')
|
5736
|
+
// console.log('sorted', sorted.length)
|
5728
5737
|
return { ancestor, sorted }
|
5729
5738
|
}
|
5730
5739
|
|
@@ -5737,6 +5746,7 @@ async function findCommonAncestorWithSortedEvents (events, children) {
|
|
5737
5746
|
*/
|
5738
5747
|
async function findCommonAncestor (events, children) {
|
5739
5748
|
if (!children.length) return
|
5749
|
+
if (children.length === 1) return children[0]
|
5740
5750
|
const candidates = children.map((c) => [c]);
|
5741
5751
|
while (true) {
|
5742
5752
|
let changed = false;
|
@@ -5757,7 +5767,7 @@ async function findCommonAncestor (events, children) {
|
|
5757
5767
|
* @param {import('./clock').EventLink<EventData>} root
|
5758
5768
|
*/
|
5759
5769
|
async function findAncestorCandidate (events, root) {
|
5760
|
-
const { value: event } = await events.get(root)
|
5770
|
+
const { value: event } = await events.get(root);// .catch(() => ({ value: { parents: [] } }))
|
5761
5771
|
if (!event.parents.length) return root
|
5762
5772
|
return event.parents.length === 1 ? event.parents[0] : findCommonAncestor(events, event.parents)
|
5763
5773
|
}
|
@@ -5767,6 +5777,7 @@ async function findAncestorCandidate (events, root) {
|
|
5767
5777
|
* @param {Array<T[]>} arrays
|
5768
5778
|
*/
|
5769
5779
|
function findCommonString (arrays) {
|
5780
|
+
// console.log('findCommonString', arrays.map((a) => a.map((i) => String(i))))
|
5770
5781
|
arrays = arrays.map((a) => [...a]);
|
5771
5782
|
for (const arr of arrays) {
|
5772
5783
|
for (const item of arr) {
|
@@ -5784,15 +5795,33 @@ function findCommonString (arrays) {
|
|
5784
5795
|
/**
|
5785
5796
|
* Find and sort events between the head(s) and the tail.
|
5786
5797
|
* @param {import('./clock').EventFetcher} events
|
5787
|
-
* @param {
|
5798
|
+
* @param {any[]} head
|
5788
5799
|
* @param {import('./clock').EventLink<EventData>} tail
|
5789
5800
|
*/
|
5790
|
-
async function findSortedEvents (events, head, tail) {
|
5801
|
+
async function findSortedEvents (events, head, tail, doFull) {
|
5791
5802
|
// const callTag = Math.random().toString(36).substring(7)
|
5792
5803
|
// get weighted events - heavier events happened first
|
5804
|
+
// const callTag = Math.random().toString(36).substring(7)
|
5805
|
+
|
5793
5806
|
/** @type {Map<string, { event: import('./clock').EventBlockView<EventData>, weight: number }>} */
|
5794
5807
|
const weights = new Map();
|
5808
|
+
head = [...new Set([...head.map((h) => h.toString())])];
|
5809
|
+
// console.log(callTag + '.head', head.length)
|
5810
|
+
|
5811
|
+
const allEvents = new Set([tail.toString(), ...head]);
|
5812
|
+
if (!doFull && allEvents.size === 1) {
|
5813
|
+
// console.log('head contains tail', tail.toString())
|
5814
|
+
return []
|
5815
|
+
// const event = await events.get(tail)
|
5816
|
+
// return [event]
|
5817
|
+
}
|
5818
|
+
|
5819
|
+
// console.log('finding events')
|
5820
|
+
// console.log(callTag + '.head', head.length, [...head.map((h) => h.toString())], tail.toString())
|
5821
|
+
|
5822
|
+
// console.time(callTag + '.findEvents')
|
5795
5823
|
const all = await Promise.all(head.map((h) => findEvents(events, h, tail)));
|
5824
|
+
// console.timeEnd(callTag + '.findEvents')
|
5796
5825
|
for (const arr of all) {
|
5797
5826
|
for (const { event, depth } of arr) {
|
5798
5827
|
// console.log('event value', event.value.data.value)
|
@@ -5821,7 +5850,7 @@ async function findSortedEvents (events, head, tail) {
|
|
5821
5850
|
const sorted = Array.from(buckets)
|
5822
5851
|
.sort((a, b) => b[0] - a[0])
|
5823
5852
|
.flatMap(([, es]) => es.sort((a, b) => (String(a.cid) < String(b.cid) ? -1 : 1)));
|
5824
|
-
// console.log('sorted', sorted.map(s => s.
|
5853
|
+
// console.log('sorted', sorted.map(s => s.cid))
|
5825
5854
|
|
5826
5855
|
return sorted
|
5827
5856
|
}
|
@@ -5833,11 +5862,14 @@ async function findSortedEvents (events, head, tail) {
|
|
5833
5862
|
* @returns {Promise<Array<{ event: EventBlockView<EventData>, depth: number }>>}
|
5834
5863
|
*/
|
5835
5864
|
async function findEvents (events, start, end, depth = 0) {
|
5836
|
-
// console.log('findEvents', start)
|
5865
|
+
// console.log('findEvents', start.toString(), end.toString(), depth)
|
5837
5866
|
const event = await events.get(start);
|
5867
|
+
const send = String(end);
|
5838
5868
|
const acc = [{ event, depth }];
|
5839
5869
|
const { parents } = event.value;
|
5840
|
-
if (parents.length === 1 && String(parents[0]) ===
|
5870
|
+
// if (parents.length === 1 && String(parents[0]) === send) return acc
|
5871
|
+
if (parents.findIndex((p) => String(p) === send) !== -1) return acc
|
5872
|
+
// if (parents.length === 1) return acc
|
5841
5873
|
const rest = await Promise.all(parents.map((p) => findEvents(events, p, end, depth + 1)));
|
5842
5874
|
return acc.concat(...rest)
|
5843
5875
|
}
|
@@ -36926,7 +36958,7 @@ function rawSha1 (b) {
|
|
36926
36958
|
return new Uint8Array(H.buffer, H.byteOffset, H.byteLength)
|
36927
36959
|
}
|
36928
36960
|
|
36929
|
-
const chunker = bf(
|
36961
|
+
const chunker = bf(30);
|
36930
36962
|
|
36931
36963
|
const NO_ENCRYPT = typeof process !== 'undefined' && !!process.env?.NO_ENCRYPT;
|
36932
36964
|
// ? process.env.NO_ENCRYPT : import.meta && import.meta.env.VITE_NO_ENCRYPT
|
@@ -37375,7 +37407,10 @@ class TransactionBlockstore {
|
|
37375
37407
|
await this.doCommit(innerBlockstore);
|
37376
37408
|
if (doSync) {
|
37377
37409
|
// const all =
|
37378
|
-
await Promise.all([...this.syncs].map(async sync => sync.sendUpdate(innerBlockstore)
|
37410
|
+
await Promise.all([...this.syncs].map(async sync => sync.sendUpdate(innerBlockstore).catch(e => {
|
37411
|
+
console.error('sync error', e);
|
37412
|
+
this.syncs.delete(sync);
|
37413
|
+
})));
|
37379
37414
|
}
|
37380
37415
|
}
|
37381
37416
|
|
@@ -37482,23 +37517,24 @@ class InnerBlockstore {
|
|
37482
37517
|
}
|
37483
37518
|
}
|
37484
37519
|
|
37485
|
-
const blockOpts = { cache: nocache, chunker: bf(
|
37520
|
+
const blockOpts = { cache: nocache, chunker: bf(30), codec: codec$1, hasher: sha256$2, compare: simpleCompare };
|
37486
37521
|
|
37487
37522
|
/**
|
37488
37523
|
* @typedef {import('./blockstore.js').TransactionBlockstore} TransactionBlockstore
|
37489
37524
|
*/
|
37490
37525
|
|
37491
|
-
const withLog = async (label, fn) => {
|
37492
|
-
|
37493
|
-
|
37494
|
-
|
37495
|
-
}
|
37526
|
+
// const withLog = async (label, fn) => {
|
37527
|
+
// const resp = await fn()
|
37528
|
+
// // console.log('withLog', label, !!resp)
|
37529
|
+
// return resp
|
37530
|
+
// }
|
37496
37531
|
|
37497
37532
|
// should also return a CIDCounter
|
37498
|
-
const makeGetBlock =
|
37533
|
+
const makeGetBlock = blocks => {
|
37499
37534
|
// const cids = new CIDCounter() // this could be used for proofs of mutations
|
37500
|
-
const getBlockFn = async
|
37501
|
-
const { cid, bytes } = await withLog(address, () => blocks.get(address))
|
37535
|
+
const getBlockFn = async address => {
|
37536
|
+
// const { cid, bytes } = await withLog(address, () => blocks.get(address))
|
37537
|
+
const { cid, bytes } = await blocks.get(address);
|
37502
37538
|
// cids.add({ address: cid })
|
37503
37539
|
return create$5({ cid, bytes, hasher: sha256$2, codec: codec$1 })
|
37504
37540
|
};
|
@@ -37513,25 +37549,17 @@ const makeGetBlock = (blocks) => {
|
|
37513
37549
|
* @param {*} param0
|
37514
37550
|
* @returns
|
37515
37551
|
*/
|
37516
|
-
async function createAndSaveNewEvent ({
|
37517
|
-
inBlocks,
|
37518
|
-
bigPut,
|
37519
|
-
root,
|
37520
|
-
event: inEvent,
|
37521
|
-
head,
|
37522
|
-
additions,
|
37523
|
-
removals = []
|
37524
|
-
}) {
|
37552
|
+
async function createAndSaveNewEvent ({ inBlocks, bigPut, root, event: inEvent, head, additions, removals = [] }) {
|
37525
37553
|
let cids;
|
37526
37554
|
const { key, value, del } = inEvent;
|
37527
37555
|
const data = {
|
37528
|
-
root:
|
37556
|
+
root: root
|
37529
37557
|
? {
|
37530
37558
|
cid: root.cid,
|
37531
37559
|
bytes: root.bytes, // can we remove this?
|
37532
37560
|
value: root.value // can we remove this?
|
37533
37561
|
}
|
37534
|
-
: null
|
37562
|
+
: null,
|
37535
37563
|
key
|
37536
37564
|
};
|
37537
37565
|
// import('./clock').EventLink<import('./clock').EventData>
|
@@ -37559,7 +37587,7 @@ async function createAndSaveNewEvent ({
|
|
37559
37587
|
}
|
37560
37588
|
}
|
37561
37589
|
|
37562
|
-
const makeGetAndPutBlock =
|
37590
|
+
const makeGetAndPutBlock = inBlocks => {
|
37563
37591
|
// const mblocks = new MemoryBlockstore()
|
37564
37592
|
// const blocks = new MultiBlockFetcher(mblocks, inBlocks)
|
37565
37593
|
const { getBlock, cids } = makeGetBlock(inBlocks);
|
@@ -37618,20 +37646,24 @@ const prollyRootFromAncestor = async (events, ancestor, getBlock) => {
|
|
37618
37646
|
}
|
37619
37647
|
};
|
37620
37648
|
|
37621
|
-
const doProllyBulk = async (inBlocks, head, event) => {
|
37649
|
+
const doProllyBulk = async (inBlocks, head, event, doFull = false) => {
|
37622
37650
|
const { getBlock, blocks } = makeGetAndPutBlock(inBlocks);
|
37623
37651
|
let bulkSorted = [];
|
37624
37652
|
let prollyRootNode = null;
|
37625
37653
|
const events = new EventFetcher(blocks);
|
37626
37654
|
if (head.length) {
|
37627
|
-
|
37655
|
+
if (!doFull && head.length === 1) {
|
37656
|
+
prollyRootNode = await prollyRootFromAncestor(events, head[0], getBlock);
|
37657
|
+
} else {
|
37658
|
+
// Otherwise, we find the common ancestor and update the root and other blocks
|
37628
37659
|
// todo this is returning more events than necessary, lets define the desired semantics from the top down
|
37629
37660
|
// good semantics mean we can cache the results of this call
|
37630
|
-
|
37631
|
-
|
37632
|
-
|
37633
|
-
|
37661
|
+
const { ancestor, sorted } = await findCommonAncestorWithSortedEvents(events, head, doFull);
|
37662
|
+
bulkSorted = sorted;
|
37663
|
+
// console.log('sorted', JSON.stringify(sorted.map(({ value: { data: { key, value } } }) => ({ key, value }))))
|
37664
|
+
prollyRootNode = await prollyRootFromAncestor(events, ancestor, getBlock);
|
37634
37665
|
// console.log('event', event)
|
37666
|
+
}
|
37635
37667
|
}
|
37636
37668
|
|
37637
37669
|
const bulkOperations = bulkFromEvents(bulkSorted, event);
|
@@ -37641,7 +37673,7 @@ const doProllyBulk = async (inBlocks, head, event) => {
|
|
37641
37673
|
let root;
|
37642
37674
|
const newBlocks = [];
|
37643
37675
|
// if all operations are deletes, we can just return an empty root
|
37644
|
-
if (bulkOperations.every(
|
37676
|
+
if (bulkOperations.every(op => op.del)) {
|
37645
37677
|
return { root: null, blocks: [], clockCIDs: await events.all() }
|
37646
37678
|
}
|
37647
37679
|
for await (const node of create$3({ get: getBlock, list: bulkOperations, ...blockOpts })) {
|
@@ -37661,7 +37693,7 @@ const doProllyBulk = async (inBlocks, head, event) => {
|
|
37661
37693
|
*
|
37662
37694
|
* @param {import('./blockstore.js').Blockstore} inBlocks Bucket block storage.
|
37663
37695
|
* @param {import('./clock').EventLink<import('./clock').EventData>[]} head Merkle clock head.
|
37664
|
-
* @param {{key: string, value: import('./clock').EventLink<import('./clock').EventData>}} event The key of the value to put.
|
37696
|
+
* @param {{key: string, value: import('./clock').EventLink<import('./clock').EventData>}} event The key of the value to put.
|
37665
37697
|
* @param {object} [options]
|
37666
37698
|
* @returns {Promise<any>}
|
37667
37699
|
*/
|
@@ -37713,18 +37745,24 @@ async function put (inBlocks, head, event, options) {
|
|
37713
37745
|
* @param {TransactionBlockstore} inBlocks Bucket block storage.
|
37714
37746
|
* @param {import('./clock').EventLink<import('./clock').EventData>[]} head Merkle clock head.
|
37715
37747
|
*/
|
37716
|
-
async function root (inBlocks, head) {
|
37748
|
+
async function root (inBlocks, head, doFull = false) {
|
37717
37749
|
if (!head.length) {
|
37718
37750
|
throw new Error('no head')
|
37719
37751
|
}
|
37720
|
-
|
37752
|
+
// console.log('root', head.map(h => h.toString()))
|
37753
|
+
const { root: newProllyRootNode, blocks: newBlocks, clockCIDs } = await doProllyBulk(inBlocks, head, null, doFull);
|
37721
37754
|
// todo maybe these should go to a temp blockstore?
|
37722
|
-
await doTransaction(
|
37723
|
-
|
37724
|
-
|
37725
|
-
|
37726
|
-
|
37727
|
-
|
37755
|
+
await doTransaction(
|
37756
|
+
'root',
|
37757
|
+
inBlocks,
|
37758
|
+
async transactionBlocks => {
|
37759
|
+
const { bigPut } = makeGetAndPutBlock(transactionBlocks);
|
37760
|
+
for (const nb of newBlocks) {
|
37761
|
+
bigPut(nb);
|
37762
|
+
}
|
37763
|
+
},
|
37764
|
+
false
|
37765
|
+
);
|
37728
37766
|
return { clockCIDs, node: newProllyRootNode }
|
37729
37767
|
}
|
37730
37768
|
|
@@ -37751,22 +37789,37 @@ async function eventsSince (blocks, head, since) {
|
|
37751
37789
|
* @param {TransactionBlockstore} blocks Bucket block storage.
|
37752
37790
|
* @param {import('./clock').EventLink<import('./clock').EventData>[]} head Merkle clock head.
|
37753
37791
|
*
|
37754
|
-
* @returns {Promise<{cids: CIDCounter, clockCIDs: CIDCounter, result: import('./clock').EventData[]}>}
|
37792
|
+
* @returns {Promise<{root: any, cids: CIDCounter, clockCIDs: CIDCounter, result: import('./clock').EventData[]}>}
|
37755
37793
|
*
|
37756
37794
|
*/
|
37757
|
-
async function getAll (blocks, head) {
|
37795
|
+
async function getAll (blocks, head, rootCache = null, doFull = false) {
|
37758
37796
|
// todo use the root node left around from put, etc
|
37759
37797
|
// move load to a central place
|
37760
37798
|
if (!head.length) {
|
37761
|
-
return { clockCIDs: new CIDCounter(), cids: new CIDCounter(), result: [] }
|
37799
|
+
return { root: null, clockCIDs: new CIDCounter(), cids: new CIDCounter(), result: [] }
|
37762
37800
|
}
|
37763
|
-
const { node: prollyRootNode, clockCIDs } = await
|
37801
|
+
const { node: prollyRootNode, clockCIDs } = await rootOrCache(blocks, head, rootCache, doFull);
|
37764
37802
|
|
37765
37803
|
if (!prollyRootNode) {
|
37766
|
-
return { clockCIDs, cids: new CIDCounter(), result: [] }
|
37804
|
+
return { root: null, clockCIDs, cids: new CIDCounter(), result: [] }
|
37767
37805
|
}
|
37768
37806
|
const { result, cids } = await prollyRootNode.getAllEntries(); // todo params
|
37769
|
-
return { clockCIDs, cids, result: result.map(({ key, value }) => ({ key, value })) }
|
37807
|
+
return { root: prollyRootNode, clockCIDs, cids, result: result.map(({ key, value }) => ({ key, value })) }
|
37808
|
+
}
|
37809
|
+
|
37810
|
+
async function rootOrCache (blocks, head, rootCache, doFull = false) {
|
37811
|
+
let node;
|
37812
|
+
let clockCIDs;
|
37813
|
+
if (!doFull && rootCache && rootCache.root) {
|
37814
|
+
// console.log('get root from cache', rootCache)
|
37815
|
+
node = rootCache.root;
|
37816
|
+
clockCIDs = rootCache.clockCIDs;
|
37817
|
+
} else {
|
37818
|
+
({ node, clockCIDs } = await root(blocks, head, doFull));
|
37819
|
+
// console.timeEnd(callTag + '.root')
|
37820
|
+
// console.log('found root')
|
37821
|
+
}
|
37822
|
+
return { node, clockCIDs }
|
37770
37823
|
}
|
37771
37824
|
|
37772
37825
|
/**
|
@@ -37774,17 +37827,19 @@ async function getAll (blocks, head) {
|
|
37774
37827
|
* @param {import('./clock').EventLink<import('./clock').EventData>[]} head Merkle clock head.
|
37775
37828
|
* @param {string} key The key of the value to retrieve.
|
37776
37829
|
*/
|
37777
|
-
async function get (blocks, head, key) {
|
37830
|
+
async function get (blocks, head, key, rootCache = null) {
|
37778
37831
|
// instead pass root from db? and always update on change
|
37779
37832
|
if (!head.length) {
|
37780
37833
|
return { cids: new CIDCounter(), result: null }
|
37781
37834
|
}
|
37782
|
-
|
37835
|
+
|
37836
|
+
const { node: prollyRootNode, clockCIDs } = await rootOrCache(blocks, head, rootCache);
|
37837
|
+
|
37783
37838
|
if (!prollyRootNode) {
|
37784
37839
|
return { clockCIDs, cids: new CIDCounter(), result: null }
|
37785
37840
|
}
|
37786
37841
|
const { result, cids } = await prollyRootNode.get(key);
|
37787
|
-
return { result, cids, clockCIDs }
|
37842
|
+
return { result, cids, clockCIDs, root: prollyRootNode }
|
37788
37843
|
}
|
37789
37844
|
|
37790
37845
|
async function * vis (blocks, head) {
|
@@ -37801,8 +37856,19 @@ async function * vis (blocks, head) {
|
|
37801
37856
|
}
|
37802
37857
|
|
37803
37858
|
async function visMerkleTree (blocks, head) {
|
37804
|
-
if (!head
|
37805
|
-
|
37859
|
+
// if (!head) return
|
37860
|
+
if (head && !Array.isArray(head)) {
|
37861
|
+
const getBl = makeGetBlock(blocks);
|
37862
|
+
const prollyRootNode = await load$2({
|
37863
|
+
cid: head,
|
37864
|
+
get: getBl.getBlock,
|
37865
|
+
...blockOpts
|
37866
|
+
});
|
37867
|
+
const lines = [];
|
37868
|
+
for await (const line of prollyRootNode.vis()) {
|
37869
|
+
lines.push(line);
|
37870
|
+
}
|
37871
|
+
return { vis: lines.join('\n'), cids: new CIDCounter() }
|
37806
37872
|
}
|
37807
37873
|
const { node: prollyRootNode, cids } = await root(blocks, head);
|
37808
37874
|
const lines = [];
|
@@ -38085,15 +38151,16 @@ const parseCID = cid => (typeof cid === 'string' ? CID$1.parse(cid) : cid);
|
|
38085
38151
|
*/
|
38086
38152
|
class Database {
|
38087
38153
|
listeners = new Set()
|
38154
|
+
indexes = new Map()
|
38155
|
+
rootCache = null
|
38156
|
+
eventsCache = new Map()
|
38088
38157
|
|
38089
|
-
// todo refactor this for the next version
|
38090
38158
|
constructor (blocks, clock, config = {}) {
|
38091
38159
|
this.name = config.name;
|
38092
38160
|
this.instanceId = `fp.${this.name}.${Math.random().toString(36).substring(2, 7)}`;
|
38093
38161
|
this.blocks = blocks;
|
38094
38162
|
this.clock = clock;
|
38095
38163
|
this.config = config;
|
38096
|
-
this.indexes = new Map();
|
38097
38164
|
}
|
38098
38165
|
|
38099
38166
|
/**
|
@@ -38160,11 +38227,22 @@ class Database {
|
|
38160
38227
|
* @instance
|
38161
38228
|
*/
|
38162
38229
|
async changesSince (event) {
|
38230
|
+
// console.log('events for', this.instanceId, event.constructor.name)
|
38163
38231
|
// console.log('changesSince', this.instanceId, event, this.clock)
|
38164
38232
|
let rows, dataCIDs, clockCIDs;
|
38165
38233
|
// if (!event) event = []
|
38166
38234
|
if (event) {
|
38167
|
-
|
38235
|
+
event = event.map((cid) => cid.toString());
|
38236
|
+
const eventKey = JSON.stringify([...event, ...this.clockToJSON()]);
|
38237
|
+
|
38238
|
+
let resp;
|
38239
|
+
if (this.eventsCache.has(eventKey)) {
|
38240
|
+
console.log('events from cache');
|
38241
|
+
resp = this.eventsCache.get(eventKey);
|
38242
|
+
} else {
|
38243
|
+
resp = await eventsSince(this.blocks, this.clock, event);
|
38244
|
+
this.eventsCache.set(eventKey, resp);
|
38245
|
+
}
|
38168
38246
|
const docsMap = new Map();
|
38169
38247
|
for (const { key, type, value } of resp.result.map(decodeEvent)) {
|
38170
38248
|
if (type === 'del') {
|
@@ -38177,7 +38255,9 @@ class Database {
|
|
38177
38255
|
clockCIDs = resp.clockCIDs;
|
38178
38256
|
// console.log('change rows', this.instanceId, rows)
|
38179
38257
|
} else {
|
38180
|
-
const allResp = await getAll(this.blocks, this.clock);
|
38258
|
+
const allResp = await getAll(this.blocks, this.clock, this.rootCache);
|
38259
|
+
this.rootCache = { root: allResp.root, clockCIDs: allResp.clockCIDs };
|
38260
|
+
|
38181
38261
|
rows = allResp.result.map(({ key, value }) => decodeEvent({ key, value }));
|
38182
38262
|
dataCIDs = allResp.cids;
|
38183
38263
|
// console.log('dbdoc rows', this.instanceId, rows)
|
@@ -38190,7 +38270,9 @@ class Database {
|
|
38190
38270
|
}
|
38191
38271
|
|
38192
38272
|
async allDocuments () {
|
38193
|
-
const allResp = await getAll(this.blocks, this.clock);
|
38273
|
+
const allResp = await getAll(this.blocks, this.clock, this.rootCache);
|
38274
|
+
this.rootCache = { root: allResp.root, clockCIDs: allResp.clockCIDs };
|
38275
|
+
|
38194
38276
|
const rows = allResp.result
|
38195
38277
|
.map(({ key, value }) => decodeEvent({ key, value }))
|
38196
38278
|
.map(({ key, value }) => ({ key, value: { _id: key, ...value } }));
|
@@ -38202,7 +38284,8 @@ class Database {
|
|
38202
38284
|
}
|
38203
38285
|
|
38204
38286
|
async allCIDs () {
|
38205
|
-
const allResp = await getAll(this.blocks, this.clock);
|
38287
|
+
const allResp = await getAll(this.blocks, this.clock, this.rootCache, true);
|
38288
|
+
this.rootCache = { root: allResp.root, clockCIDs: allResp.clockCIDs };
|
38206
38289
|
// console.log('allcids', allResp.cids, allResp.clockCIDs)
|
38207
38290
|
const cids = await cidsToProof(allResp.cids);
|
38208
38291
|
const clockCids = await cidsToProof(allResp.clockCIDs);
|
@@ -38248,13 +38331,13 @@ class Database {
|
|
38248
38331
|
*/
|
38249
38332
|
async get (key, opts = {}) {
|
38250
38333
|
const clock = opts.clock || this.clock;
|
38251
|
-
const resp = await get(this.blocks, clock, charwise.encode(key));
|
38252
|
-
|
38334
|
+
const resp = await get(this.blocks, clock, charwise.encode(key), this.rootCache);
|
38335
|
+
this.rootCache = { root: resp.root, clockCIDs: resp.clockCIDs };
|
38253
38336
|
// this tombstone is temporary until we can get the prolly tree to delete
|
38254
38337
|
if (!resp || resp.result === null) {
|
38255
38338
|
throw new Error('Not found')
|
38256
38339
|
}
|
38257
|
-
const doc = resp.result;
|
38340
|
+
const doc = { ...resp.result };
|
38258
38341
|
if (opts.mvcc === true) {
|
38259
38342
|
doc._clock = this.clockToJSON();
|
38260
38343
|
}
|
@@ -38348,7 +38431,9 @@ class Database {
|
|
38348
38431
|
}
|
38349
38432
|
|
38350
38433
|
applyClock (prevClock, newClock) {
|
38351
|
-
// console.log('
|
38434
|
+
// console.log('prevClock', prevClock.length, prevClock.map((cid) => cid.toString()))
|
38435
|
+
// console.log('newClock', newClock.length, newClock.map((cid) => cid.toString()))
|
38436
|
+
// console.log('this.clock', this.clock.length, this.clockToJSON())
|
38352
38437
|
const stPrev = prevClock.map(cid => cid.toString());
|
38353
38438
|
const keptPrevClock = this.clock.filter(cid => stPrev.indexOf(cid.toString()) === -1);
|
38354
38439
|
const merged = keptPrevClock.concat(newClock);
|
@@ -38356,8 +38441,10 @@ class Database {
|
|
38356
38441
|
for (const cid of merged) {
|
38357
38442
|
uniquebyCid.set(cid.toString(), cid);
|
38358
38443
|
}
|
38359
|
-
this.clock = Array.from(uniquebyCid.values());
|
38360
|
-
|
38444
|
+
this.clock = Array.from(uniquebyCid.values()).sort((a, b) => a.toString().localeCompare(b.toString()));
|
38445
|
+
this.rootCache = null;
|
38446
|
+
this.eventsCache.clear();
|
38447
|
+
// console.log('afterClock', this.clock.length, this.clockToJSON())
|
38361
38448
|
}
|
38362
38449
|
|
38363
38450
|
// /**
|
@@ -38693,8 +38780,8 @@ const refCompare = (aRef, bRef) => {
|
|
38693
38780
|
return simpleCompare(aRef, bRef)
|
38694
38781
|
};
|
38695
38782
|
|
38696
|
-
const dbIndexOpts = { cache: nocache, chunker: bf(
|
38697
|
-
const idIndexOpts = { cache: nocache, chunker: bf(
|
38783
|
+
const dbIndexOpts = { cache: nocache, chunker: bf(30), codec: codec$1, hasher: sha256$2, compare };
|
38784
|
+
const idIndexOpts = { cache: nocache, chunker: bf(30), codec: codec$1, hasher: sha256$2, compare: simpleCompare };
|
38698
38785
|
|
38699
38786
|
const makeDoc = ({ key, value }) => ({ _id: key, ...value });
|
38700
38787
|
|
@@ -38751,6 +38838,9 @@ const indexEntriesForChanges = (changes, mapFn) => {
|
|
38751
38838
|
*
|
38752
38839
|
*/
|
38753
38840
|
class DbIndex {
|
38841
|
+
/**
|
38842
|
+
* @param {Database} database
|
38843
|
+
*/
|
38754
38844
|
constructor (database, name, mapFn, clock = null, opts = {}) {
|
38755
38845
|
this.database = database;
|
38756
38846
|
if (!database.indexBlocks) {
|
@@ -38822,6 +38912,14 @@ class DbIndex {
|
|
38822
38912
|
return new DbIndex(database, name, code, clock)
|
38823
38913
|
}
|
38824
38914
|
|
38915
|
+
async visKeyTree () {
|
38916
|
+
return await visMerkleTree(this.database.indexBlocks, this.indexById.cid)
|
38917
|
+
}
|
38918
|
+
|
38919
|
+
async visIdTree () {
|
38920
|
+
return await visMerkleTree(this.database.indexBlocks, this.indexByKey.cid)
|
38921
|
+
}
|
38922
|
+
|
38825
38923
|
/**
|
38826
38924
|
* JSDoc for Query type.
|
38827
38925
|
* @typedef {Object} DbQuery
|
@@ -40875,7 +40973,7 @@ class Sync {
|
|
40875
40973
|
*/
|
40876
40974
|
constructor (database, PeerClass = simplePeer) {
|
40877
40975
|
this.database = database;
|
40878
|
-
this.database.blocks.syncs.add(this);
|
40976
|
+
this.database.blocks.syncs.add(this); // should this happen during setup?
|
40879
40977
|
this.PeerClass = PeerClass;
|
40880
40978
|
this.pushBacklog = new Promise((resolve, reject) => {
|
40881
40979
|
this.pushBacklogResolve = resolve;
|
@@ -40923,8 +41021,13 @@ class Sync {
|
|
40923
41021
|
|
40924
41022
|
async gotData (data) {
|
40925
41023
|
// console.log('got data', data.toString())
|
41024
|
+
let reader = null;
|
40926
41025
|
try {
|
40927
|
-
|
41026
|
+
reader = await CarReader.fromBytes(data);
|
41027
|
+
} catch (e) {
|
41028
|
+
// console.log('not a car', data.toString())
|
41029
|
+
}
|
41030
|
+
if (reader) {
|
40928
41031
|
const blz = new Set();
|
40929
41032
|
for await (const block of reader.blocks()) {
|
40930
41033
|
blz.add(block);
|
@@ -40947,17 +41050,18 @@ class Sync {
|
|
40947
41050
|
get: async cid => await reader.get(cid),
|
40948
41051
|
lastCid: [...blz][0].cid // doesn't matter
|
40949
41052
|
}, false);
|
40950
|
-
|
41053
|
+
// first arg could be the roots parents?
|
41054
|
+
// get the roots parents
|
41055
|
+
const parents = await Promise.all(roots.map(async (cid) => {
|
41056
|
+
const rbl = await reader.get(cid);
|
41057
|
+
const block = await decodeEventBlock(rbl.bytes);
|
41058
|
+
return block.value.parents
|
41059
|
+
}));
|
41060
|
+
this.database.applyClock(parents.flat(), roots);
|
40951
41061
|
this.database.notifyReset();
|
40952
41062
|
// console.log('after', this.database.clockToJSON())
|
40953
41063
|
this.pushBacklogResolve({ ok: true });
|
40954
|
-
}
|
40955
|
-
// console.error(e)
|
40956
|
-
// if e.message matche 'CBOR' we can ignore it
|
40957
|
-
if (!e.message.match(/CBOR|fromBytes/)) {
|
40958
|
-
throw e
|
40959
|
-
}
|
40960
|
-
|
41064
|
+
} else {
|
40961
41065
|
// data is a json string, parse it
|
40962
41066
|
const message = JSON.parse(data.toString());
|
40963
41067
|
// console.log('got message', message)
|
@@ -40983,7 +41087,7 @@ class Sync {
|
|
40983
41087
|
}
|
40984
41088
|
|
40985
41089
|
async sendUpdate (blockstore) {
|
40986
|
-
console.log('send update from', this.database.instanceId)
|
41090
|
+
// console.log('send update from', this.database.instanceId)
|
40987
41091
|
// todo should send updates since last sync
|
40988
41092
|
const newCar = await blocksToCarBlock(blockstore.lastCid, blockstore);
|
40989
41093
|
this.peer.send(newCar.bytes);
|