@fireproof/core 0.5.12 → 0.5.14

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.
@@ -5499,17 +5499,17 @@ class CIDCounter {
5499
5499
 
5500
5500
  /**
5501
5501
  * @typedef {{
5502
- * type: 'put'|'del'
5503
- * key: string
5504
- * value: import('./link').AnyLink
5505
- * root: import('./link').AnyLink
5506
- * }} EventData
5507
- * @typedef {{
5508
- * root: import('./link').AnyLink
5509
- * head: import('./clock').EventLink<EventData>[]
5510
- * event: import('./clock').EventBlockView<EventData>
5511
- * }} Result
5512
- */
5502
+ * type: 'put'|'del'
5503
+ * key: string
5504
+ * value: import('./link').AnyLink
5505
+ * root: import('./link').AnyLink
5506
+ * }} EventData
5507
+ * @typedef {{
5508
+ * root: import('./link').AnyLink
5509
+ * head: import('./clock').EventLink<EventData>[]
5510
+ * event: import('./clock').EventBlockView<EventData>
5511
+ * }} Result
5512
+ */
5513
5513
 
5514
5514
  /**
5515
5515
  * Advance the clock by adding an event.
@@ -5523,7 +5523,7 @@ class CIDCounter {
5523
5523
  async function advance (blocks, head, event) {
5524
5524
  /** @type {EventFetcher<T>} */
5525
5525
  const events = new EventFetcher(blocks);
5526
- const headmap = new Map(head.map((cid) => [cid.toString(), cid]));
5526
+ const headmap = new Map(head.map(cid => [cid.toString(), cid]));
5527
5527
 
5528
5528
  // Check if the headmap already includes the event, return head if it does
5529
5529
  if (headmap.has(event.toString())) return { head, cids: await events.all() }
@@ -5645,14 +5645,16 @@ async function decodeEventBlock (bytes) {
5645
5645
  async function contains (events, a, b) {
5646
5646
  if (a.toString() === b.toString()) return true
5647
5647
  const [{ value: aevent }, { value: bevent }] = await Promise.all([events.get(a), events.get(b)]);
5648
- const links = [...aevent.parents];
5648
+ // const links = [...aevent.parents]
5649
+ // console.log('aevent', aevent.parents)
5650
+ const links = [...(aevent.parents || [])];
5649
5651
  while (links.length) {
5650
5652
  const link = links.shift();
5651
5653
  if (!link) break
5652
5654
  if (link.toString() === b.toString()) return true
5653
5655
  // if any of b's parents are this link, then b cannot exist in any of the
5654
5656
  // tree below, since that would create a cycle.
5655
- if (bevent.parents.some((p) => link.toString() === p.toString())) continue
5657
+ if (bevent.parents.some(p => link.toString() === p.toString())) continue
5656
5658
  const { value: event } = await events.get(link);
5657
5659
  links.push(...event.parents);
5658
5660
  }
@@ -5668,15 +5670,19 @@ async function contains (events, a, b) {
5668
5670
  */
5669
5671
  async function * vis$1 (blocks, head, options = {}) {
5670
5672
  // @ts-ignore
5671
- const renderNodeLabel = options.renderNodeLabel ?? ((b) => {
5672
- // @ts-ignore
5673
- const { key, root, type } = b.value.data;
5674
- return b.cid.toString() + '\n' + JSON.stringify({ key, root: root.cid.toString(), type }, null, 2).replace(/"/g, '\'')
5675
- });
5673
+ const renderNodeLabel =
5674
+ options.renderNodeLabel ??
5675
+ (b => {
5676
+ // @ts-ignore
5677
+ const { key, root, type } = b.value.data;
5678
+ return (
5679
+ b.cid.toString() + '\n' + JSON.stringify({ key, root: root.cid.toString(), type }, null, 2).replace(/"/g, "'")
5680
+ )
5681
+ });
5676
5682
  const events = new EventFetcher(blocks);
5677
5683
  yield 'digraph clock {';
5678
5684
  yield ' node [shape=point fontname="Courier"]; head;';
5679
- const hevents = await Promise.all(head.map((link) => events.get(link)));
5685
+ const hevents = await Promise.all(head.map(link => events.get(link)));
5680
5686
  const links = [];
5681
5687
  const nodes = new Set();
5682
5688
  for (const e of hevents) {
@@ -5709,17 +5715,18 @@ async function findEventsToSync (blocks, head) {
5709
5715
  // console.time(callTag + '.findCommonAncestorWithSortedEvents')
5710
5716
  const { ancestor, sorted } = await findCommonAncestorWithSortedEvents(events, head);
5711
5717
  // console.timeEnd(callTag + '.findCommonAncestorWithSortedEvents')
5712
- // console.log('sorted', sorted.length)
5718
+ // console.log('sorted', !!ancestor, sorted.length)
5713
5719
  // console.time(callTag + '.contains')
5714
- const toSync = await asyncFilter(sorted, async (uks) => !(await contains(events, ancestor, uks.cid)));
5720
+
5721
+ const toSync = ancestor ? await asyncFilter(sorted, async uks => !(await contains(events, ancestor, uks.cid))) : sorted;
5715
5722
  // console.timeEnd(callTag + '.contains')
5716
- // console.log('toSync.contains', toSync.length)
5723
+ console.log('toSync', !!ancestor, sorted.length - toSync.length);
5717
5724
 
5718
5725
  return { cids: events, events: toSync }
5719
5726
  }
5720
5727
 
5721
5728
  const asyncFilter = async (arr, predicate) =>
5722
- Promise.all(arr.map(predicate)).then((results) => arr.filter((_v, index) => results[index]));
5729
+ Promise.all(arr.map(predicate)).then(results => arr.filter((_v, index) => results[index]));
5723
5730
 
5724
5731
  async function findCommonAncestorWithSortedEvents (events, children, doFull = false) {
5725
5732
  // console.trace('findCommonAncestorWithSortedEvents')
@@ -5730,12 +5737,16 @@ async function findCommonAncestorWithSortedEvents (events, children, doFull = fa
5730
5737
  // console.timeEnd(callTag + '.findCommonAncestor')
5731
5738
  // console.log('ancestor', ancestor.toString())
5732
5739
  if (!ancestor) {
5733
- throw new Error('failed to find common ancestor event')
5740
+ console.log('no common ancestor', children);
5741
+ // throw new Error('no common ancestor')
5742
+ const sorted = await findSortedEvents(events, children, children, doFull);
5743
+ return { ancestor: null, sorted }
5734
5744
  }
5735
5745
  // console.time(callTag + '.findSortedEvents')
5736
- const sorted = await findSortedEvents(events, children, ancestor, doFull);
5746
+ const sorted = await findSortedEvents(events, children, [ancestor], doFull);
5737
5747
  // console.timeEnd(callTag + '.findSortedEvents')
5738
5748
  // console.log('sorted', sorted.length)
5749
+ // console.log('ancestor', JSON.stringify(ancestor, null, 2))
5739
5750
  return { ancestor, sorted }
5740
5751
  }
5741
5752
 
@@ -5746,17 +5757,58 @@ async function findCommonAncestorWithSortedEvents (events, children, doFull = fa
5746
5757
  * @param {import('./clock').EventFetcher} events
5747
5758
  * @param {import('./clock').EventLink<EventData>[]} children
5748
5759
  */
5760
+ // async function NEWfindCommonAncestor (events, children) {
5761
+ // if (!children.length) return
5762
+ // if (children.length === 1) return children[0]
5763
+
5764
+ // const candidates = children.map(c => [c])
5765
+ // const visited = new Set()
5766
+
5767
+ // while (true) {
5768
+ // let changed = false
5769
+ // for (const c of candidates) {
5770
+ // const candidate = await findAncestorCandidate(events, c[c.length - 1])
5771
+
5772
+ // if (!candidate) continue
5773
+
5774
+ // if (visited.has(candidate)) {
5775
+ // return candidate // Common ancestor found
5776
+ // }
5777
+
5778
+ // visited.add(candidate)
5779
+ // changed = true
5780
+ // c.push(candidate)
5781
+ // }
5782
+
5783
+ // if (!changed) {
5784
+ // // No common ancestor found, exhausted candidates
5785
+ // return null
5786
+ // }
5787
+ // }
5788
+ // }
5789
+
5749
5790
  async function findCommonAncestor (events, children) {
5750
5791
  if (!children.length) return
5792
+ children = [...new Set(children)];
5751
5793
  if (children.length === 1) return children[0]
5752
5794
  const candidates = children.map((c) => [c]);
5795
+ // console.log(
5796
+ // 'og candidates',
5797
+ // candidates.map((c) => c.toString())
5798
+ // )
5753
5799
  while (true) {
5754
5800
  let changed = false;
5755
5801
  for (const c of candidates) {
5756
5802
  const candidate = await findAncestorCandidate(events, c[c.length - 1]);
5757
5803
  if (!candidate) continue
5804
+
5805
+ // Check if the candidate is already in the list, and if so, skip it.
5806
+ if (c.includes(candidate)) continue
5807
+
5808
+ // if set size is all cids, then no common ancestor
5758
5809
  changed = true;
5759
- c.push(candidate);
5810
+ c.push(candidate); // make set?
5811
+ // console.log('candidate', candidates.map((c) => c.toString()))
5760
5812
  const ancestor = findCommonString(candidates);
5761
5813
  if (ancestor) return ancestor
5762
5814
  }
@@ -5764,12 +5816,45 @@ async function findCommonAncestor (events, children) {
5764
5816
  }
5765
5817
  }
5766
5818
 
5819
+ // async function OGfindCommonAncestor (events, children) {
5820
+ // if (!children.length) return
5821
+ // if (children.length === 1) return children[0]
5822
+ // const candidates = children.map(c => [c])
5823
+ // console.log(
5824
+ // 'og candidates',
5825
+ // candidates.map(c => c.toString())
5826
+ // )
5827
+ // while (true) {
5828
+ // let changed = false
5829
+ // for (const c of candidates) {
5830
+ // const candidate = await findAncestorCandidate(events, c[c.length - 1])
5831
+ // if (!candidate) continue
5832
+ // // if set size is all cids, then no common ancestor
5833
+ // changed = true
5834
+ // c.push(candidate) // make set?
5835
+ // console.log(
5836
+ // 'candidate',
5837
+ // candidates.map(c => c.toString())
5838
+ // )
5839
+ // const ancestor = findCommonString(candidates)
5840
+ // if (ancestor) return ancestor
5841
+ // }
5842
+ // if (!changed) return
5843
+ // }
5844
+ // }
5845
+
5767
5846
  /**
5768
5847
  * @param {import('./clock').EventFetcher} events
5769
5848
  * @param {import('./clock').EventLink<EventData>} root
5770
5849
  */
5771
5850
  async function findAncestorCandidate (events, root) {
5772
- const { value: event } = await events.get(root);// .catch(() => ({ value: { parents: [] } }))
5851
+ const { value: event } = await events.get(root); // .catch(() => ({ value: { parents: [] } }))
5852
+ // console.log(
5853
+ // 'findAncestorCandidate',
5854
+ // root.toString(),
5855
+ // 'parents',
5856
+ // event.parents.map(p => p.toString())
5857
+ // )
5773
5858
  if (!event.parents.length) return root
5774
5859
  return event.parents.length === 1 ? event.parents[0] : findCommonAncestor(events, event.parents)
5775
5860
  }
@@ -5780,13 +5865,13 @@ async function findAncestorCandidate (events, root) {
5780
5865
  */
5781
5866
  function findCommonString (arrays) {
5782
5867
  // console.log('findCommonString', arrays.map((a) => a.map((i) => String(i))))
5783
- arrays = arrays.map((a) => [...a]);
5868
+ arrays = arrays.map(a => [...a]);
5784
5869
  for (const arr of arrays) {
5785
5870
  for (const item of arr) {
5786
5871
  let matched = true;
5787
5872
  for (const other of arrays) {
5788
5873
  if (arr === other) continue
5789
- matched = other.some((i) => String(i) === String(item));
5874
+ matched = other.some(i => String(i) === String(item));
5790
5875
  if (!matched) break
5791
5876
  }
5792
5877
  if (matched) return item
@@ -5798,19 +5883,19 @@ function findCommonString (arrays) {
5798
5883
  * Find and sort events between the head(s) and the tail.
5799
5884
  * @param {import('./clock').EventFetcher} events
5800
5885
  * @param {any[]} head
5801
- * @param {import('./clock').EventLink<EventData>} tail
5886
+ * @param {import('./clock').EventLink<EventData>[]} tails
5802
5887
  */
5803
- async function findSortedEvents (events, head, tail, doFull) {
5888
+ async function findSortedEvents (events, head, tails, doFull) {
5804
5889
  // const callTag = Math.random().toString(36).substring(7)
5805
5890
  // get weighted events - heavier events happened first
5806
5891
  // const callTag = Math.random().toString(36).substring(7)
5807
5892
 
5808
5893
  /** @type {Map<string, { event: import('./clock').EventBlockView<EventData>, weight: number }>} */
5809
5894
  const weights = new Map();
5810
- head = [...new Set([...head.map((h) => h.toString())])];
5895
+ head = [...new Set([...head.map(h => h.toString())])];
5811
5896
  // console.log(callTag + '.head', head.length)
5812
5897
 
5813
- const allEvents = new Set([tail.toString(), ...head]);
5898
+ const allEvents = new Set([tails.map((t) => t.toString()).toString(), ...head]);
5814
5899
  if (!doFull && allEvents.size === 1) {
5815
5900
  // console.log('head contains tail', tail.toString())
5816
5901
  return []
@@ -5822,7 +5907,8 @@ async function findSortedEvents (events, head, tail, doFull) {
5822
5907
  // console.log(callTag + '.head', head.length, [...head.map((h) => h.toString())], tail.toString())
5823
5908
 
5824
5909
  // console.time(callTag + '.findEvents')
5825
- const all = await Promise.all(head.map((h) => findEvents(events, h, tail)));
5910
+ const all = await (await Promise.all(tails.map((t) => Promise.all(head.map(h => findEvents(events, h, t)))))).flat();
5911
+ // console.log('all', all.length)
5826
5912
  // console.timeEnd(callTag + '.findEvents')
5827
5913
  for (const arr of all) {
5828
5914
  for (const { event, depth } of arr) {
@@ -5870,9 +5956,9 @@ async function findEvents (events, start, end, depth = 0) {
5870
5956
  const acc = [{ event, depth }];
5871
5957
  const { parents } = event.value;
5872
5958
  // if (parents.length === 1 && String(parents[0]) === send) return acc
5873
- if (parents.findIndex((p) => String(p) === send) !== -1) return acc
5959
+ if (parents.findIndex(p => String(p) === send) !== -1) return acc
5874
5960
  // if (parents.length === 1) return acc
5875
- const rest = await Promise.all(parents.map((p) => findEvents(events, p, end, depth + 1)));
5961
+ const rest = await Promise.all(parents.map(p => findEvents(events, p, end, depth + 1)));
5876
5962
  return acc.concat(...rest)
5877
5963
  }
5878
5964
 
@@ -36828,7 +36914,7 @@ const decrypt = async function * ({ root, get, key, cache, chunker, hasher }) {
36828
36914
  const { result: nodes } = await cidset.getAllEntries();
36829
36915
  const unwrap = async (eblock) => {
36830
36916
  const { bytes, cid } = await decrypt$1({ ...eblock, key }).catch(e => {
36831
- console.log('ekey', e);
36917
+ // console.log('ekey', e)
36832
36918
  throw new Error('bad key: ' + key.toString('hex'))
36833
36919
  });
36834
36920
  const block = await createBlock(bytes, cid);
@@ -36949,11 +37035,11 @@ class Valet {
36949
37035
  this.name = name;
36950
37036
  this.setKeyMaterial(keyMaterial);
36951
37037
  this.uploadQueue = cargoQueue(async (tasks, callback) => {
36952
- console.log(
36953
- 'queue worker',
36954
- tasks.length,
36955
- tasks.reduce((acc, t) => acc + t.value.length, 0)
36956
- );
37038
+ // console.log(
37039
+ // 'queue worker',
37040
+ // tasks.length,
37041
+ // tasks.reduce((acc, t) => acc + t.value.length, 0)
37042
+ // )
36957
37043
  if (this.uploadFunction) {
36958
37044
  // todo we can coalesce these into a single car file
36959
37045
  return await this.withDB(async db => {
@@ -37375,6 +37461,7 @@ class TransactionBlockstore {
37375
37461
  await this.doCommit(innerBlockstore);
37376
37462
  if (doSync) {
37377
37463
  // const all =
37464
+ // console.log('syncing', innerBlockstore.label)
37378
37465
  await Promise.all([...this.syncs].map(async sync => sync.sendUpdate(innerBlockstore).catch(e => {
37379
37466
  console.error('sync error, cancelling', e);
37380
37467
  sync.destroy();
@@ -37487,6 +37574,8 @@ class InnerBlockstore {
37487
37574
 
37488
37575
  const blockOpts = { cache: nocache, chunker: bf(30), codec: codec$1, hasher: sha256$2, compare: simpleCompare };
37489
37576
 
37577
+ // const SYNC_ROOT = 'fireproof' // change this if you want to break sync
37578
+
37490
37579
  /**
37491
37580
  * @typedef {import('./blockstore.js').TransactionBlockstore} TransactionBlockstore
37492
37581
  */
@@ -37520,13 +37609,11 @@ const makeGetBlock = blocks => {
37520
37609
  async function createAndSaveNewEvent ({ inBlocks, bigPut, root, event: inEvent, head, additions, removals = [] }) {
37521
37610
  let cids;
37522
37611
  const { key, value, del } = inEvent;
37612
+ // console.log('createAndSaveNewEvent', root.constructor.name, root.entryList)
37613
+ // root = await root.block
37523
37614
  const data = {
37524
37615
  root: root
37525
- ? {
37526
- cid: root.cid,
37527
- bytes: root.bytes, // can we remove this?
37528
- value: root.value // can we remove this?
37529
- }
37616
+ ? (await root.address)
37530
37617
  : null,
37531
37618
  key
37532
37619
  };
@@ -37538,6 +37625,29 @@ async function createAndSaveNewEvent ({ inBlocks, bigPut, root, event: inEvent,
37538
37625
  data.value = value;
37539
37626
  data.type = 'put';
37540
37627
  }
37628
+ // console.log('head', head)
37629
+ // if (head.length === 0) {
37630
+ // // create an empty prolly root
37631
+ // let emptyRoot
37632
+
37633
+ // for await (const node of create({ get: getBlock, list: [{ key: '_sync', value: SYNC_ROOT }], ...blockOpts })) {
37634
+ // emptyRoot = await node.block
37635
+ // bigPut(emptyRoot)
37636
+ // }
37637
+ // console.log('emptyRoot', emptyRoot)
37638
+ // const first = await EventBlock.create(
37639
+ // {
37640
+ // root: emptyRoot.cid,
37641
+ // key: null,
37642
+ // value: null,
37643
+ // type: 'del'
37644
+ // },
37645
+ // []
37646
+ // )
37647
+ // bigPut(first)
37648
+ // head = [first.cid]
37649
+ // }
37650
+
37541
37651
  /** @type {import('./clock').EventData} */
37542
37652
  // @ts-ignore
37543
37653
  const event = await EventBlock.create(data, head);
@@ -37606,16 +37716,23 @@ const prollyRootFromAncestor = async (events, ancestor, getBlock) => {
37606
37716
  // console.log('prollyRootFromAncestor', ancestor)
37607
37717
  const event = await events.get(ancestor);
37608
37718
  const { root } = event.value.data;
37609
- // console.log('prollyRootFromAncestor', root.cid, JSON.stringify(root.value))
37610
37719
  if (root) {
37611
- return load$2({ cid: root.cid, get: getBlock, ...blockOpts })
37720
+ return load$2({ cid: root, get: getBlock, ...blockOpts })
37612
37721
  } else {
37613
- return null
37722
+ // console.log('no root', root) // false means no common ancestor. null means empty database.
37723
+ return root
37614
37724
  }
37615
37725
  };
37616
37726
 
37727
+ // async function bigMerge (events, head, getBlock) {
37728
+ // const allRoots = await Promise.all(head.map(async h => prollyRootFromAncestor(events, h, getBlock)))
37729
+ // console.log('allRoots', allRoots)
37730
+ // // todo query over all roots and merge them, but how do they not have a common ancestor? they all start with the _sync root
37731
+ // throw new Error('not implemented')
37732
+ // }
37733
+
37617
37734
  const doProllyBulk = async (inBlocks, head, event, doFull = false) => {
37618
- const { getBlock, blocks } = makeGetAndPutBlock(inBlocks);
37735
+ const { getBlock, blocks } = makeGetAndPutBlock(inBlocks); // this is doubled with eventfetcher
37619
37736
  let bulkSorted = [];
37620
37737
  let prollyRootNode = null;
37621
37738
  const events = new EventFetcher(blocks);
@@ -37623,14 +37740,22 @@ const doProllyBulk = async (inBlocks, head, event, doFull = false) => {
37623
37740
  if (!doFull && head.length === 1) {
37624
37741
  prollyRootNode = await prollyRootFromAncestor(events, head[0], getBlock);
37625
37742
  } else {
37626
- // Otherwise, we find the common ancestor and update the root and other blocks
37627
- // todo this is returning more events than necessary, lets define the desired semantics from the top down
37628
- // good semantics mean we can cache the results of this call
37743
+ // Otherwise, we find the common ancestor and update the root and other blocks
37744
+ // todo this is returning more events than necessary, lets define the desired semantics from the top down
37745
+ // good semantics mean we can cache the results of this call
37746
+ // const {cids, events : bulkSorted } = await findEventsToSync(blocks, head)
37629
37747
  const { ancestor, sorted } = await findCommonAncestorWithSortedEvents(events, head, doFull);
37748
+
37630
37749
  bulkSorted = sorted;
37631
- // console.log('sorted', JSON.stringify(sorted.map(({ value: { data: { key, value } } }) => ({ key, value }))))
37632
- prollyRootNode = await prollyRootFromAncestor(events, ancestor, getBlock);
37633
- // console.log('event', event)
37750
+ // console.log('sorted', !!ancestor, JSON.stringify(sorted.map(({ value: { data: { key, value } } }) => ({ key, value }))))
37751
+ if (ancestor) {
37752
+ prollyRootNode = await prollyRootFromAncestor(events, ancestor, getBlock);
37753
+ // if (!prollyRootNode) {
37754
+ // prollyRootNode = await bigMerge(events, head, getBlock)
37755
+ // // throw new Error('no common ancestor')
37756
+ // }
37757
+ }
37758
+ // console.log('event', event)
37634
37759
  }
37635
37760
  }
37636
37761
 
@@ -37638,16 +37763,23 @@ const doProllyBulk = async (inBlocks, head, event, doFull = false) => {
37638
37763
 
37639
37764
  // if prolly root node is null, we need to create a new one
37640
37765
  if (!prollyRootNode) {
37766
+ // console.log('make new root', bulkOperations.length)
37641
37767
  let root;
37768
+ // let rootNode
37642
37769
  const newBlocks = [];
37643
37770
  // if all operations are deletes, we can just return an empty root
37644
37771
  if (bulkOperations.every(op => op.del)) {
37645
37772
  return { root: null, blocks: [], clockCIDs: await events.all() }
37646
37773
  }
37647
37774
  for await (const node of create$3({ get: getBlock, list: bulkOperations, ...blockOpts })) {
37648
- root = await node.block;
37649
- newBlocks.push(root);
37775
+ // root = await node.block
37776
+ root = node;
37777
+ newBlocks.push(await node.block);
37650
37778
  }
37779
+ // throw new Error('not root time')
37780
+ // root.isThisOne = 'yes'
37781
+ // console.log('made new root', root.constructor.name, root.block.cid.toString())
37782
+
37651
37783
  return { root, blocks: newBlocks, clockCIDs: await events.all() }
37652
37784
  } else {
37653
37785
  const writeResp = await prollyRootNode.bulk(bulkOperations); // { root: newProllyRootNode, blocks: newBlocks }
@@ -37667,7 +37799,7 @@ const doProllyBulk = async (inBlocks, head, event, doFull = false) => {
37667
37799
  */
37668
37800
  async function put (inBlocks, head, event, options) {
37669
37801
  const { bigPut } = makeGetAndPutBlock(inBlocks);
37670
-
37802
+ // console.log('major put')
37671
37803
  // If the head is empty, we create a new event and return the root and addition blocks
37672
37804
  if (!head.length) {
37673
37805
  const additions = new Map();
@@ -37699,7 +37831,7 @@ async function put (inBlocks, head, event, options) {
37699
37831
  return createAndSaveNewEvent({
37700
37832
  inBlocks,
37701
37833
  bigPut,
37702
- root: prollyRootBlock,
37834
+ root: newProllyRootNode, // Block
37703
37835
  event,
37704
37836
  head,
37705
37837
  additions: Array.from(additions.values()) /*, todo? Array.from(removals.values()) */
@@ -37718,20 +37850,25 @@ async function root (inBlocks, head, doFull = false) {
37718
37850
  throw new Error('no head')
37719
37851
  }
37720
37852
  // console.log('root', head.map(h => h.toString()))
37721
- const { root: newProllyRootNode, blocks: newBlocks, clockCIDs } = await doProllyBulk(inBlocks, head, null, doFull);
37722
37853
  // todo maybe these should go to a temp blockstore?
37723
- await doTransaction(
37854
+ return await doTransaction(
37724
37855
  'root',
37725
37856
  inBlocks,
37726
37857
  async transactionBlocks => {
37727
37858
  const { bigPut } = makeGetAndPutBlock(transactionBlocks);
37859
+ const { root: newProllyRootNode, blocks: newBlocks, clockCIDs } = await doProllyBulk(inBlocks, head, null, doFull);
37860
+ //
37861
+ // const rootBlock = await newProllyRootNode.block
37862
+ // bigPut(rootBlock)
37728
37863
  for (const nb of newBlocks) {
37729
37864
  bigPut(nb);
37730
37865
  }
37866
+ // console.log('root root', newProllyRootNode.constructor.name, newProllyRootNode)
37867
+ return { clockCIDs, node: newProllyRootNode }
37731
37868
  },
37732
37869
  false
37733
- );
37734
- return { clockCIDs, node: newProllyRootNode }
37870
+ )
37871
+ // return { clockCIDs, node: newProllyRootNode }
37735
37872
  }
37736
37873
 
37737
37874
  /**
@@ -37747,7 +37884,8 @@ async function eventsSince (blocks, head, since) {
37747
37884
  return { clockCIDs: [], result: [] }
37748
37885
  }
37749
37886
  // @ts-ignore
37750
- const sinceHead = [...since, ...head]; // ?
37887
+ const sinceHead = [...since, ...head].map(h => h.toString()); // ?
37888
+ // console.log('eventsSince', sinceHead.map(h => h.toString()))
37751
37889
  const { cids, events: unknownSorted3 } = await findEventsToSync(blocks, sinceHead);
37752
37890
  return { clockCIDs: cids, result: unknownSorted3.map(({ value: { data } }) => data) }
37753
37891
  }
@@ -37784,8 +37922,12 @@ async function rootOrCache (blocks, head, rootCache, doFull = false) {
37784
37922
  clockCIDs = rootCache.clockCIDs;
37785
37923
  } else {
37786
37924
  ({ node, clockCIDs } = await root(blocks, head, doFull));
37925
+
37926
+ // this.applyClock(prevClock, result.head)
37927
+ // await this.notifyListeners([decodedEvent])
37928
+
37787
37929
  // console.timeEnd(callTag + '.root')
37788
- // console.log('found root')
37930
+ // console.log('found root', node.entryList)
37789
37931
  }
37790
37932
  return { node, clockCIDs }
37791
37933
  }
@@ -38153,8 +38295,8 @@ class Database {
38153
38295
  * @memberof Fireproof
38154
38296
  * @instance
38155
38297
  */
38156
- clockToJSON () {
38157
- return this.clock.map(cid => cid.toString())
38298
+ clockToJSON (clock = null) {
38299
+ return (clock || this.clock).map(cid => cid.toString())
38158
38300
  }
38159
38301
 
38160
38302
  hydrate ({ clock, name, key }) {
@@ -38194,21 +38336,21 @@ class Database {
38194
38336
  * @memberof Fireproof
38195
38337
  * @instance
38196
38338
  */
38197
- async changesSince (event) {
38198
- // console.log('events for', this.instanceId, event.constructor.name)
38199
- // console.log('changesSince', this.instanceId, event, this.clock)
38339
+ async changesSince (aClock) {
38340
+ // console.log('events for', this.instanceId, aClock?.constructor.name)
38341
+ // console.log('changesSince', this.instanceId, this.clockToJSON(aClock), this.clockToJSON())
38200
38342
  let rows, dataCIDs, clockCIDs;
38201
- // if (!event) event = []
38202
- if (event) {
38203
- event = event.map((cid) => cid.toString());
38204
- const eventKey = JSON.stringify([...event, ...this.clockToJSON()]);
38343
+ // if (!aClock) aClock = []
38344
+ if (aClock && aClock.length > 0) {
38345
+ aClock = aClock.map((cid) => cid.toString());
38346
+ const eventKey = JSON.stringify([...this.clockToJSON(aClock), ...this.clockToJSON()]);
38205
38347
 
38206
38348
  let resp;
38207
38349
  if (this.eventsCache.has(eventKey)) {
38208
- console.log('events from cache');
38350
+ // console.log('events from cache')
38209
38351
  resp = this.eventsCache.get(eventKey);
38210
38352
  } else {
38211
- resp = await eventsSince(this.blocks, this.clock, event);
38353
+ resp = await eventsSince(this.blocks, this.clock, aClock);
38212
38354
  this.eventsCache.set(eventKey, resp);
38213
38355
  }
38214
38356
  const docsMap = new Map();
@@ -38369,7 +38511,9 @@ class Database {
38369
38511
  */
38370
38512
  async putToProllyTree (decodedEvent, clock = null) {
38371
38513
  const event = encodeEvent(decodedEvent);
38372
- if (clock && JSON.stringify(clock) !== JSON.stringify(this.clockToJSON())) {
38514
+ if (clock && JSON.stringify(this.clockToJSON(clock)) !== JSON.stringify(this.clockToJSON())) {
38515
+ // console.log('this.clock', this.clockToJSON())
38516
+ // console.log('that.clock', this.clockToJSON(clock))
38373
38517
  // we need to check and see what version of the document exists at the clock specified
38374
38518
  // if it is the same as the one we are trying to put, then we can proceed
38375
38519
  const resp = await eventsSince(this.blocks, this.clock, event.value._clock);
@@ -38379,6 +38523,7 @@ class Database {
38379
38523
  }
38380
38524
  }
38381
38525
  const prevClock = [...this.clock];
38526
+ // console.log('putToProllyTree', this.clockToJSON(), decodedEvent)
38382
38527
  const result = await doTransaction(
38383
38528
  'putToProllyTree',
38384
38529
  this.blocks,
@@ -39068,7 +39213,7 @@ class DbIndex {
39068
39213
  );
39069
39214
  this.indexByKey = await bulkIndex(blocks, this.indexByKey, oldIndexEntries.concat(indexEntries), dbIndexOpts);
39070
39215
  this.dbHead = result.clock;
39071
- });
39216
+ }, false /* don't sync transaction -- maybe move this flag to database.indexBlocks? */);
39072
39217
  // todo index subscriptions
39073
39218
  // this.database.notifyExternal('dbIndex')
39074
39219
  // console.timeEnd(callTag + '.doTransactionupdateIndex')
@@ -41023,10 +41168,15 @@ class Sync {
41023
41168
  this.pushBacklogResolve = resolve;
41024
41169
  this.pushBacklogReject = reject;
41025
41170
  });
41171
+ this.isReady = false;
41026
41172
  // this.pushBacklog.then(() => {
41027
41173
  // // console.log('sync backlog resolved')
41028
41174
  // this.database.notifyReset()
41029
41175
  // })
41176
+ // this.connected = new Promise((resolve, reject) => {
41177
+ // this.readyResolve = resolve
41178
+ // this.readyReject = reject
41179
+ // })
41030
41180
  }
41031
41181
 
41032
41182
  async offer () {
@@ -41075,6 +41225,7 @@ class Sync {
41075
41225
  // console.log('not a car', data.toString())
41076
41226
  }
41077
41227
  if (reader) {
41228
+ // console.log('got car')
41078
41229
  this.status = 'parking car';
41079
41230
  const blz = new Set();
41080
41231
  for await (const block of reader.blocks()) {
@@ -41087,7 +41238,7 @@ class Sync {
41087
41238
  // this.database.clock.map(c => c.toString())
41088
41239
  // )
41089
41240
  // console.log(
41090
- // 'got blocks',
41241
+ // 'got blocks!',
41091
41242
  // [...blz].map(({ cid }) => cid.toString())
41092
41243
  // )
41093
41244
  // @ts-ignore
@@ -41128,7 +41279,7 @@ class Sync {
41128
41279
  } else if (message.clock) {
41129
41280
  const reqCidDiff = message;
41130
41281
  // this might be a CID diff
41131
- console.log('got diff', reqCidDiff);
41282
+ // console.log('got diff', reqCidDiff)
41132
41283
  const carBlock = await Sync.makeCar(this.database, null, reqCidDiff.cids);
41133
41284
  if (!carBlock) {
41134
41285
  // we are full synced
@@ -41137,9 +41288,10 @@ class Sync {
41137
41288
  this.peer.send(JSON.stringify({ ok: true }));
41138
41289
  // this.pushBacklogResolve({ ok: true })
41139
41290
  } else {
41140
- // console.log('do send', carBlock.bytes.length)
41291
+ // console.log('do send diff', carBlock.bytes.length)
41141
41292
  this.status = 'sending diff car';
41142
41293
  this.peer.send(carBlock.bytes);
41294
+ // console.log('sent diff car')
41143
41295
  // this.pushBacklogResolve({ ok: true })
41144
41296
  }
41145
41297
  }
@@ -41153,7 +41305,7 @@ class Sync {
41153
41305
  }
41154
41306
 
41155
41307
  async sendUpdate (blockstore) {
41156
- if (!this.peer) return
41308
+ if (!this.peer || !this.isReady) return
41157
41309
  // console.log('send update from', this.database.instanceId)
41158
41310
  // todo should send updates since last sync
41159
41311
  const newCar = await blocksToCarBlock(blockstore.lastCid, blockstore);
@@ -41163,6 +41315,7 @@ class Sync {
41163
41315
 
41164
41316
  async startSync () {
41165
41317
  // console.log('start sync', this.peer.initiator)
41318
+ this.isReady = true;
41166
41319
  const allCIDs = await this.database.allStoredCIDs();
41167
41320
  // console.log('allCIDs', allCIDs)
41168
41321
  const reqCidDiff = {