@fireproof/core 0.5.18 → 0.5.20

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.
@@ -80,7 +80,6 @@ export class TransactionBlockstore {
80
80
  }
81
81
  async networkGet(key) {
82
82
  if (this.remoteBlockFunction) {
83
- // todo why is this on valet?
84
83
  const value = await husher(key, async () => await this.remoteBlockFunction(key));
85
84
  if (value) {
86
85
  // console.log('networkGot: ' + key, value.length)
package/dist/src/clock.js CHANGED
@@ -78,7 +78,7 @@ export class EventBlock extends Block {
78
78
  * @param {Uint8Array} config.bytes
79
79
  */
80
80
  constructor({ cid, value, bytes }) {
81
- // @ts-expect-error
81
+ // @ts-ignore
82
82
  super({ cid, value, bytes });
83
83
  }
84
84
  /**
@@ -129,7 +129,7 @@ export class EventFetcher {
129
129
  export async function encodeEventBlock(value) {
130
130
  // TODO: sort parents
131
131
  const { cid, bytes } = await encode({ value, codec: cbor, hasher: sha256 });
132
- // @ts-expect-error
132
+ // @ts-ignore
133
133
  return new Block({ cid, value, bytes });
134
134
  }
135
135
  /**
@@ -139,7 +139,7 @@ export async function encodeEventBlock(value) {
139
139
  */
140
140
  export async function decodeEventBlock(bytes) {
141
141
  const { cid, value } = await decode({ bytes, codec: cbor, hasher: sha256 });
142
- // @ts-expect-error
142
+ // @ts-ignore
143
143
  return new Block({ cid, value, bytes });
144
144
  }
145
145
  /**
@@ -42,7 +42,6 @@ export class Database {
42
42
  * @instance
43
43
  */
44
44
  toJSON() {
45
- // todo this also needs to return the index roots...
46
45
  return {
47
46
  clock: this.clockToJSON(),
48
47
  name: this.name,
@@ -75,6 +74,17 @@ export class Database {
75
74
  localSet('fp.' + this.name, JSON.stringify(this));
76
75
  }
77
76
  }
77
+ index(name) {
78
+ // iterate over the indexes and gather any with the same name
79
+ // if there are more than one, throw an error
80
+ // if there is one, return it
81
+ // if there are none, return null
82
+ const indexes = [...this.indexes.values()].filter(index => index.name === name);
83
+ if (indexes.length > 1) {
84
+ throw new Error(`Multiple indexes found with name ${name}`);
85
+ }
86
+ return indexes[0] || null;
87
+ }
78
88
  /**
79
89
  * Triggers a notification to all listeners
80
90
  * of the Fireproof instance so they can repaint UI, etc.
@@ -159,8 +169,7 @@ export class Database {
159
169
  const cids = await cidsToProof(allResp.cids);
160
170
  const clockCids = await cidsToProof(allResp.clockCIDs);
161
171
  // console.log('allcids', cids, clockCids)
162
- // todo we need to put the clock head as the last block in the encrypted car
163
- return [...cids, ...clockCids]; // need a single block version of clock head, maybe an encoded block for it
172
+ return [...cids, ...clockCids]; // clock CID last -- need to handle multiple entry clocks
164
173
  }
165
174
  async allStoredCIDs() {
166
175
  const allCIDs = [];
@@ -199,7 +208,7 @@ export class Database {
199
208
  const clock = opts.clock || this.clock;
200
209
  const resp = await get(this.blocks, clock, charwise.encode(key), this.rootCache);
201
210
  this.rootCache = { root: resp.root, clockCIDs: resp.clockCIDs };
202
- // this tombstone is temporary until we can get the prolly tree to delete
211
+ // ? this tombstone is temporary until we can get the prolly tree to delete
203
212
  if (!resp || resp.result === null) {
204
213
  throw new Error('Not found');
205
214
  }
@@ -215,12 +224,11 @@ export class Database {
215
224
  return doc;
216
225
  }
217
226
  /**
218
- * @typedef {Object} Document
227
+ * @typedef {any} Document
219
228
  * @property {string} _id - The ID of the document (required)
220
229
  * @property {string} [_proof] - The proof of the document (optional)
221
230
  * @property {string} [_clock] - The clock of the document (optional)
222
- * @property {any} [key: string] - Index signature notation to allow any other unknown fields
223
- * * @property {Object.<string, any>} [otherProperties] - Any other unknown properties (optional)
231
+ * @property {Object.<string, any>} [unknown: string] - Any other unknown properties (optional)
224
232
  */
225
233
  /**
226
234
  * Adds a new document to the database, or updates an existing document. Returns the ID of the document and the new clock head.
@@ -291,7 +291,7 @@ export class DbIndex {
291
291
  async innerUpdateIndex(inBlocks) {
292
292
  // const callTag = Math.random().toString(36).substring(4)
293
293
  // console.log(`updateIndex ${callTag} >`, this.instanceId, this.dbHead?.toString(), this.indexByKey.cid?.toString(), this.indexById.cid?.toString())
294
- // todo remove this hack
294
+ // todo remove this hack in 0.7.0
295
295
  if (ALWAYS_REBUILD) {
296
296
  this.indexById = { root: null, cid: null };
297
297
  this.indexByKey = { root: null, cid: null };
@@ -329,9 +329,7 @@ export class DbIndex {
329
329
  this.indexById = await bulkIndex(blocks, this.indexById, removeByIdIndexEntries.concat(byIdIndexEntries), idIndexOpts);
330
330
  this.indexByKey = await bulkIndex(blocks, this.indexByKey, oldIndexEntries.concat(indexEntries), dbIndexOpts);
331
331
  this.dbHead = result.clock;
332
- }, false /* don't sync transaction -- maybe move this flag to database.indexBlocks? */);
333
- // todo index subscriptions
334
- // this.database.notifyExternal('dbIndex')
332
+ }, false /* don't sync transaction -- todo move this flag to database.indexBlocks, and concept of sync channels */);
335
333
  // console.timeEnd(callTag + '.doTransactionupdateIndex')
336
334
  // console.log(`updateIndex ${callTag} <`, this.instanceId, this.dbHead?.toString(), this.indexByKey.cid?.toString(), this.indexById.cid?.toString())
337
335
  return didT;
@@ -44,9 +44,6 @@ declare class Valet {
44
44
  getCarCIDForCID(cid: any): Promise<{
45
45
  result: any;
46
46
  }>;
47
- OLDgetCarCIDForCID(cid: any): Promise<{
48
- result: any;
49
- }>;
50
47
  getCombinedReader(carCid: any): Promise<{
51
48
  root: any;
52
49
  put: (cid: any, bytes: any) => Promise<void>;
@@ -58,6 +55,7 @@ declare class Valet {
58
55
  * @param {*} value
59
56
  */
60
57
  parkCar(carCid: string, value: any, cids: any): Promise<void>;
58
+ writeCars(cars: any): Promise<any>;
61
59
  remoteBlockFunction: any;
62
60
  getCarReader(carCid: any): Promise<{
63
61
  root: any;
@@ -236,6 +234,7 @@ declare class Database {
236
234
  indexCar: any;
237
235
  }): void;
238
236
  maybeSaveClock(): void;
237
+ index(name: any): any;
239
238
  /**
240
239
  * Triggers a notification to all listeners
241
240
  * of the Fireproof instance so they can repaint UI, etc.
@@ -290,12 +289,11 @@ declare class Database {
290
289
  _id: string;
291
290
  }>;
292
291
  /**
293
- * @typedef {Object} Document
292
+ * @typedef {any} Document
294
293
  * @property {string} _id - The ID of the document (required)
295
294
  * @property {string} [_proof] - The proof of the document (optional)
296
295
  * @property {string} [_clock] - The clock of the document (optional)
297
- * @property {any} [key: string] - Index signature notation to allow any other unknown fields
298
- * * @property {Object.<string, any>} [otherProperties] - Any other unknown properties (optional)
296
+ * @property {Object.<string, any>} [unknown: string] - Any other unknown properties (optional)
299
297
  */
300
298
  /**
301
299
  * Adds a new document to the database, or updates an existing document. Returns the ID of the document and the new clock head.
@@ -305,31 +303,7 @@ declare class Database {
305
303
  * @memberof Fireproof
306
304
  * @instance
307
305
  */
308
- put({ _id, _proof, ...doc }: {
309
- /**
310
- * - The ID of the document (required)
311
- */
312
- _id: string;
313
- /**
314
- * - The proof of the document (optional)
315
- */
316
- _proof?: string;
317
- /**
318
- * - The clock of the document (optional)
319
- */
320
- _clock?: string;
321
- /**
322
- * : string] - Index signature notation to allow any other unknown fields
323
- * *
324
- */
325
- key?: any;
326
- /**
327
- * - Any other unknown properties (optional)
328
- */
329
- otherProperties?: {
330
- [x: string]: any;
331
- };
332
- }): Promise<{
306
+ put({ _id, _proof, ...doc }: any): Promise<{
333
307
  id: string;
334
308
  clock: CID[];
335
309
  }>;
@@ -5566,7 +5566,7 @@ class EventBlock extends Block {
5566
5566
  * @param {Uint8Array} config.bytes
5567
5567
  */
5568
5568
  constructor ({ cid, value, bytes }) {
5569
- // @ts-expect-error
5569
+ // @ts-ignore
5570
5570
  super({ cid, value, bytes });
5571
5571
  }
5572
5572
 
@@ -5620,7 +5620,7 @@ class EventFetcher {
5620
5620
  async function encodeEventBlock (value) {
5621
5621
  // TODO: sort parents
5622
5622
  const { cid, bytes } = await encode$7({ value, codec: codec$1, hasher: sha256$2 });
5623
- // @ts-expect-error
5623
+ // @ts-ignore
5624
5624
  return new Block({ cid, value, bytes })
5625
5625
  }
5626
5626
 
@@ -5631,7 +5631,7 @@ async function encodeEventBlock (value) {
5631
5631
  */
5632
5632
  async function decodeEventBlock (bytes) {
5633
5633
  const { cid, value } = await decode$9({ bytes, codec: codec$1, hasher: sha256$2 });
5634
- // @ts-expect-error
5634
+ // @ts-ignore
5635
5635
  return new Block({ cid, value, bytes })
5636
5636
  }
5637
5637
 
@@ -39554,29 +39554,29 @@ class Valet {
39554
39554
  // )
39555
39555
  if (this.uploadFunction) {
39556
39556
  // todo we can coalesce these into a single car file
39557
- return await this.withDB(async db => {
39558
- for (const task of tasks) {
39559
- await this.uploadFunction(task.carCid, task.value);
39560
- // update the indexedb to mark this car as no longer pending
39561
- const carMeta = await db.get('cidToCar', task.carCid);
39562
- delete carMeta.pending;
39563
- await db.put('cidToCar', carMeta);
39564
- }
39565
- })
39557
+ // todo remove idb usage here
39558
+ for (const task of tasks) {
39559
+ await this.uploadFunction(task.carCid, task.value);
39560
+ // todo update syncCidMap to say this has been synced
39561
+ // const carMeta = await db.get('cidToCar', task.carCid)
39562
+ // delete carMeta.pending
39563
+ // await db.put('cidToCar', carMeta)
39564
+ }
39566
39565
  }
39567
39566
  callback();
39568
39567
  });
39569
39568
 
39570
39569
  this.uploadQueue.drain(async () => {
39571
- return await this.withDB(async db => {
39572
- const carKeys = (await db.getAllFromIndex('cidToCar', 'pending')).map(c => c.car);
39573
- for (const carKey of carKeys) {
39574
- await this.uploadFunction(carKey, await db.get('cars', carKey));
39575
- const carMeta = await db.get('cidToCar', carKey);
39576
- delete carMeta.pending;
39577
- await db.put('cidToCar', carMeta);
39578
- }
39579
- })
39570
+ // todo read syncCidMap and sync any that are still unsynced
39571
+ // return await this.withDB(async db => {
39572
+ // const carKeys = (await db.getAllFromIndex('cidToCar', 'pending')).map(c => c.car)
39573
+ // for (const carKey of carKeys) {
39574
+ // await this.uploadFunction(carKey, await db.get('cars', carKey))
39575
+ // const carMeta = await db.get('cidToCar', carKey)
39576
+ // delete carMeta.pending
39577
+ // await db.put('cidToCar', carMeta)
39578
+ // }
39579
+ // })
39580
39580
  });
39581
39581
  }
39582
39582
 
@@ -39622,16 +39622,10 @@ class Valet {
39622
39622
 
39623
39623
  withDB = async dbWorkFun => {
39624
39624
  if (!this.idb) {
39625
- this.idb = await openDB(`fp.${this.keyId}.${this.name}.valet`, 2, {
39625
+ this.idb = await openDB(`fp.${this.keyId}.${this.name}.valet`, 3, {
39626
39626
  upgrade (db, oldVersion, newVersion, transaction) {
39627
39627
  if (oldVersion < 1) {
39628
- db.createObjectStore('cars'); // todo use database name
39629
- const cidToCar = db.createObjectStore('cidToCar', { keyPath: 'car' });
39630
- cidToCar.createIndex('cids', 'cids', { multiEntry: true });
39631
- }
39632
- if (oldVersion < 2) {
39633
- const cidToCar = transaction.objectStore('cidToCar');
39634
- cidToCar.createIndex('pending', 'pending');
39628
+ db.createObjectStore('cars');
39635
39629
  }
39636
39630
  }
39637
39631
  });
@@ -39647,13 +39641,11 @@ class Valet {
39647
39641
  */
39648
39642
  async * cids () {
39649
39643
  // console.log('valet cids')
39650
- const db = await this.withDB(async db => db);
39651
- const tx = db.transaction(['cidToCar'], 'readonly');
39652
- let cursor = await tx.store.openCursor();
39653
- while (cursor) {
39654
- yield { cid: cursor.key, car: cursor.value.car };
39655
- cursor = await cursor.continue();
39656
- }
39644
+ // todo use cidMap
39645
+ // while (cursor) {
39646
+ // yield { cid: cursor.key, car: cursor.value.car }
39647
+ // cursor = await cursor.continue()
39648
+ // }
39657
39649
  }
39658
39650
 
39659
39651
  setRootCarCid (cid) {
@@ -39662,6 +39654,7 @@ class Valet {
39662
39654
  this.valetRootCid = null;
39663
39655
  }
39664
39656
 
39657
+ // todo memoize this
39665
39658
  async getCarCIDForCID (cid) {
39666
39659
  // make a car reader for this.valetRootCarCid
39667
39660
  if (!this.valetRootCarCid) return
@@ -39687,15 +39680,6 @@ class Valet {
39687
39680
  return { result: got }
39688
39681
  }
39689
39682
 
39690
- async OLDgetCarCIDForCID (cid) {
39691
- const carCid = await this.withDB(async db => {
39692
- const tx = db.transaction(['cars', 'cidToCar'], 'readonly');
39693
- const indexResp = await tx.objectStore('cidToCar').index('cids').get(cid);
39694
- return indexResp?.car
39695
- });
39696
- return { result: carCid }
39697
- }
39698
-
39699
39683
  async getCombinedReader (carCid) {
39700
39684
  let carMapReader;
39701
39685
  if (this.valetRootCarCid) {
@@ -39760,15 +39744,20 @@ class Valet {
39760
39744
  newValetCidCar = await blocksToCarBlock(this.valetRootCid, saveValetBlocks);
39761
39745
  }
39762
39746
  // console.log('newValetCidCar', this.name, Math.floor(newValetCidCar.bytes.length / 1024))
39763
- await this.withDB(async db => {
39764
- const tx = db.transaction(['cars'], 'readwrite');
39765
- await tx.objectStore('cars').put(value, carCid.toString());
39766
- if (newValetCidCar) {
39767
- if (this.valetRootCarCid) ;
39768
- await tx.objectStore('cars').put(newValetCidCar.bytes, newValetCidCar.cid.toString());
39747
+ await this.writeCars([
39748
+ {
39749
+ cid: carCid,
39750
+ bytes: value,
39751
+ replaces: null
39752
+ },
39753
+ {
39754
+ cid: newValetCidCar.cid,
39755
+ bytes: newValetCidCar.bytes,
39756
+ replaces: null
39757
+ // replaces: this.valetRootCarCid // todo
39769
39758
  }
39770
- return await tx.done
39771
- });
39759
+ ]);
39760
+
39772
39761
  this.valetRootCarCid = newValetCidCar.cid; // goes to clock
39773
39762
 
39774
39763
  // console.log('parked car', carCid, value.length, Array.from(cids))
@@ -39785,6 +39774,20 @@ class Valet {
39785
39774
  }
39786
39775
  }
39787
39776
 
39777
+ async writeCars (cars) {
39778
+ return await this.withDB(async db => {
39779
+ const tx = db.transaction(['cars'], 'readwrite');
39780
+ for (const { cid, bytes, replaces } of cars) {
39781
+ await tx.objectStore('cars').put(bytes, cid.toString());
39782
+ // todo remove old maps
39783
+ if (replaces) {
39784
+ await tx.objectStore('cars').delete(replaces.toString());
39785
+ }
39786
+ }
39787
+ return await tx.done
39788
+ })
39789
+ }
39790
+
39788
39791
  remoteBlockFunction = null
39789
39792
 
39790
39793
  async getCarReader (carCid) {
@@ -39815,7 +39818,7 @@ class Valet {
39815
39818
  };
39816
39819
  const { blocks } = await blocksFromEncryptedCarBlock(roots[0], readerGetWithCodec, this.keyMaterial);
39817
39820
 
39818
- // last block is the root ???
39821
+ // last block is the root ??? todo
39819
39822
  const rootBlock = blocks[blocks.length - 1];
39820
39823
 
39821
39824
  return {
@@ -40083,7 +40086,6 @@ class TransactionBlockstore {
40083
40086
 
40084
40087
  async networkGet (key) {
40085
40088
  if (this.remoteBlockFunction) {
40086
- // todo why is this on valet?
40087
40089
  const value = await husher(key, async () => await this.remoteBlockFunction(key));
40088
40090
  if (value) {
40089
40091
  // console.log('networkGot: ' + key, value.length)
@@ -40421,13 +40423,6 @@ const prollyRootFromAncestor = async (events, ancestor, getBlock) => {
40421
40423
  }
40422
40424
  };
40423
40425
 
40424
- // async function bigMerge (events, head, getBlock) {
40425
- // const allRoots = await Promise.all(head.map(async h => prollyRootFromAncestor(events, h, getBlock)))
40426
- // console.log('allRoots', allRoots)
40427
- // // todo query over all roots and merge them, but how do they not have a common ancestor? they all start with the _sync root
40428
- // throw new Error('not implemented')
40429
- // }
40430
-
40431
40426
  const doProllyBulk = async (inBlocks, head, event, doFull = false) => {
40432
40427
  const { getBlock, blocks } = makeGetAndPutBlock(inBlocks); // this is doubled with eventfetcher
40433
40428
  let bulkSorted = [];
@@ -40596,8 +40591,6 @@ async function eventsSince (blocks, head, since) {
40596
40591
  *
40597
40592
  */
40598
40593
  async function getAll (blocks, head, rootCache = null, doFull = false) {
40599
- // todo use the root node left around from put, etc
40600
- // move load to a central place
40601
40594
  if (!head.length) {
40602
40595
  return { root: null, clockCIDs: new CIDCounter(), cids: new CIDCounter(), result: [] }
40603
40596
  }
@@ -40977,7 +40970,6 @@ class Database {
40977
40970
  * @instance
40978
40971
  */
40979
40972
  toJSON () {
40980
- // todo this also needs to return the index roots...
40981
40973
  return {
40982
40974
  clock: this.clockToJSON(),
40983
40975
  name: this.name,
@@ -41014,6 +41006,18 @@ class Database {
41014
41006
  }
41015
41007
  }
41016
41008
 
41009
+ index (name) {
41010
+ // iterate over the indexes and gather any with the same name
41011
+ // if there are more than one, throw an error
41012
+ // if there is one, return it
41013
+ // if there are none, return null
41014
+ const indexes = [...this.indexes.values()].filter(index => index.name === name);
41015
+ if (indexes.length > 1) {
41016
+ throw new Error(`Multiple indexes found with name ${name}`)
41017
+ }
41018
+ return indexes[0] || null
41019
+ }
41020
+
41017
41021
  /**
41018
41022
  * Triggers a notification to all listeners
41019
41023
  * of the Fireproof instance so they can repaint UI, etc.
@@ -41102,8 +41106,7 @@ class Database {
41102
41106
  const cids = await cidsToProof(allResp.cids);
41103
41107
  const clockCids = await cidsToProof(allResp.clockCIDs);
41104
41108
  // console.log('allcids', cids, clockCids)
41105
- // todo we need to put the clock head as the last block in the encrypted car
41106
- return [...cids, ...clockCids] // need a single block version of clock head, maybe an encoded block for it
41109
+ return [...cids, ...clockCids] // clock CID last -- need to handle multiple entry clocks
41107
41110
  }
41108
41111
 
41109
41112
  async allStoredCIDs () {
@@ -41145,7 +41148,7 @@ class Database {
41145
41148
  const clock = opts.clock || this.clock;
41146
41149
  const resp = await get(this.blocks, clock, charwise.encode(key), this.rootCache);
41147
41150
  this.rootCache = { root: resp.root, clockCIDs: resp.clockCIDs };
41148
- // this tombstone is temporary until we can get the prolly tree to delete
41151
+ // ? this tombstone is temporary until we can get the prolly tree to delete
41149
41152
  if (!resp || resp.result === null) {
41150
41153
  throw new Error('Not found')
41151
41154
  }
@@ -41161,12 +41164,11 @@ class Database {
41161
41164
  return doc
41162
41165
  }
41163
41166
  /**
41164
- * @typedef {Object} Document
41167
+ * @typedef {any} Document
41165
41168
  * @property {string} _id - The ID of the document (required)
41166
41169
  * @property {string} [_proof] - The proof of the document (optional)
41167
41170
  * @property {string} [_clock] - The clock of the document (optional)
41168
- * @property {any} [key: string] - Index signature notation to allow any other unknown fields
41169
- * * @property {Object.<string, any>} [otherProperties] - Any other unknown properties (optional)
41171
+ * @property {Object.<string, any>} [unknown: string] - Any other unknown properties (optional)
41170
41172
  */
41171
41173
 
41172
41174
  /**
@@ -41920,9 +41922,7 @@ class DbIndex {
41920
41922
  );
41921
41923
  this.indexByKey = await bulkIndex(blocks, this.indexByKey, oldIndexEntries.concat(indexEntries), dbIndexOpts);
41922
41924
  this.dbHead = result.clock;
41923
- }, false /* don't sync transaction -- maybe move this flag to database.indexBlocks? */);
41924
- // todo index subscriptions
41925
- // this.database.notifyExternal('dbIndex')
41925
+ }, false /* don't sync transaction -- todo move this flag to database.indexBlocks, and concept of sync channels */);
41926
41926
  // console.timeEnd(callTag + '.doTransactionupdateIndex')
41927
41927
  // console.log(`updateIndex ${callTag} <`, this.instanceId, this.dbHead?.toString(), this.indexByKey.cid?.toString(), this.indexById.cid?.toString())
41928
41928
  return didT
@@ -44014,7 +44014,7 @@ class Sync {
44014
44014
  async sendUpdate (blockstore) {
44015
44015
  if (!this.peer || !this.isReady) return
44016
44016
  // console.log('send update from', this.database.instanceId)
44017
- // todo should send updates since last sync
44017
+ // todo should send updates since last sync (currently sends each transaction)
44018
44018
  const newCar = await blocksToCarBlock(blockstore.lastCid, blockstore);
44019
44019
  this.status = 'sending update car';
44020
44020
  this.peer.send(newCar.bytes);
@@ -44099,7 +44099,7 @@ class Fireproof {
44099
44099
  static storage = (name = null, opts = {}) => {
44100
44100
  if (name) {
44101
44101
  opts.name = name;
44102
- // todo this can come from a registry also
44102
+ // todo this can come from a registry also eg remote database / config, etc
44103
44103
  const existing = localGet('fp.' + name);
44104
44104
  if (existing) {
44105
44105
  const existingConfig = JSON.parse(existing);