@fireproof/core 0.5.8 → 0.5.10

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.
@@ -38214,9 +38214,9 @@ class Database {
38214
38214
  }
38215
38215
 
38216
38216
  // used be indexes etc to notify database listeners of new availability
38217
- async notifyExternal (source = 'unknown') {
38218
- await this.notifyListeners({ _external: source, _clock: this.clockToJSON() });
38219
- }
38217
+ // async notifyExternal (source = 'unknown') {
38218
+ // // await this.notifyListeners({ _external: source, _clock: this.clockToJSON() })
38219
+ // }
38220
38220
 
38221
38221
  /**
38222
38222
  * Returns the changes made to the Fireproof instance since the specified event.
@@ -38476,13 +38476,23 @@ class Database {
38476
38476
  * @returns {Function} - A function that can be called to unregister the listener.
38477
38477
  * @memberof Fireproof
38478
38478
  */
38479
- registerListener (listener) {
38479
+ subscribe (listener) {
38480
38480
  this.listeners.add(listener);
38481
38481
  return () => {
38482
38482
  this.listeners.delete(listener);
38483
38483
  }
38484
38484
  }
38485
38485
 
38486
+ /**
38487
+ * @deprecated 0.7.0 - renamed subscribe(listener)
38488
+ * @param {Function} listener - The listener to be called when the clock is updated.
38489
+ * @returns {Function} - A function that can be called to unregister the listener.
38490
+ * @memberof Fireproof
38491
+ */
38492
+ registerListener (listener) {
38493
+ return this.subscribe(listener)
38494
+ }
38495
+
38486
38496
  async notifyListeners (changes) {
38487
38497
  // await sleep(10)
38488
38498
  await this.maybeSaveClock();
@@ -38531,7 +38541,9 @@ function encodeEvent (event) {
38531
38541
  * @param {Function} routingFn - The routing function to apply to each entry in the database.
38532
38542
  */
38533
38543
  // import { ChangeEvent } from './db-index'
38534
-
38544
+ /**
38545
+ * @deprecated since version 0.7.0
38546
+ */
38535
38547
  class Listener {
38536
38548
  subcribers = new Map()
38537
38549
  doStopListening = null
@@ -38815,14 +38827,23 @@ const makeDoc = ({ key, value }) => ({ _id: key, ...value });
38815
38827
  const indexEntriesForChanges = (changes, mapFn) => {
38816
38828
  const indexEntries = [];
38817
38829
  changes.forEach(({ key, value, del }) => {
38830
+ // key is _id, value is the document
38818
38831
  if (del || !value) return
38819
- mapFn(makeDoc({ key, value }), (k, v) => {
38832
+ let mapCalled = false;
38833
+ const mapReturn = mapFn(makeDoc({ key, value }), (k, v) => {
38834
+ mapCalled = true;
38820
38835
  if (typeof k === 'undefined') return
38821
38836
  indexEntries.push({
38822
38837
  key: [charwise.encode(k), key],
38823
38838
  value: v || null
38824
38839
  });
38825
38840
  });
38841
+ if (!mapCalled && mapReturn) {
38842
+ indexEntries.push({
38843
+ key: [charwise.encode(mapReturn), key],
38844
+ value: null
38845
+ });
38846
+ }
38826
38847
  });
38827
38848
  return indexEntries
38828
38849
  };
@@ -38844,7 +38865,10 @@ class DbIndex {
38844
38865
  constructor (database, name, mapFn, clock = null, opts = {}) {
38845
38866
  this.database = database;
38846
38867
  if (!database.indexBlocks) {
38847
- database.indexBlocks = new TransactionBlockstore(database?.name + '.indexes', database.blocks.valet?.getKeyMaterial());
38868
+ database.indexBlocks = new TransactionBlockstore(
38869
+ database?.name + '.indexes',
38870
+ database.blocks.valet?.getKeyMaterial()
38871
+ );
38848
38872
  }
38849
38873
  if (typeof name === 'function') {
38850
38874
  // app is using deprecated API, remove in 0.7
@@ -38853,13 +38877,8 @@ class DbIndex {
38853
38877
  mapFn = name;
38854
38878
  name = null;
38855
38879
  }
38856
- if (typeof mapFn === 'string') {
38857
- this.mapFnString = mapFn;
38858
- } else {
38859
- this.mapFn = mapFn;
38860
- this.mapFnString = mapFn.toString();
38861
- }
38862
- this.name = name || this.makeName();
38880
+ this.applyMapFn(mapFn, name);
38881
+
38863
38882
  this.indexById = { root: null, cid: null };
38864
38883
  this.indexByKey = { root: null, cid: null };
38865
38884
  this.dbHead = null;
@@ -38870,13 +38889,34 @@ class DbIndex {
38870
38889
  }
38871
38890
  this.instanceId = this.database.instanceId + `.DbIndex.${Math.random().toString(36).substring(2, 7)}`;
38872
38891
  this.updateIndexPromise = null;
38873
- if (!opts.temporary) { DbIndex.registerWithDatabase(this, this.database); }
38892
+ if (!opts.temporary) {
38893
+ DbIndex.registerWithDatabase(this, this.database);
38894
+ }
38895
+ }
38896
+
38897
+ applyMapFn (mapFn, name) {
38898
+ if (typeof mapFn === 'string') {
38899
+ this.mapFnString = mapFn;
38900
+ } else {
38901
+ this.mapFn = mapFn;
38902
+ this.mapFnString = mapFn.toString();
38903
+ }
38904
+ this.name = name || this.makeName();
38874
38905
  }
38875
38906
 
38876
38907
  makeName () {
38877
38908
  const regex = /\(([^,()]+,\s*[^,()]+|\[[^\]]+\],\s*[^,()]+)\)/g;
38878
- const matches = Array.from(this.mapFnString.matchAll(regex), match => match[1].trim());
38879
- return matches[1]
38909
+ let matches = Array.from(this.mapFnString.matchAll(regex), match => match[1].trim());
38910
+ if (matches.length === 0) {
38911
+ matches = /=>\s*(.*)/.exec(this.mapFnString);
38912
+ }
38913
+ if (matches.length === 0) {
38914
+ return this.mapFnString
38915
+ } else {
38916
+ // it's a consise arrow function, match everythign after the arrow
38917
+ this.includeDocsDefault = true;
38918
+ return matches[1]
38919
+ }
38880
38920
  }
38881
38921
 
38882
38922
  static registerWithDatabase (inIndex, database) {
@@ -38886,7 +38926,8 @@ class DbIndex {
38886
38926
  // merge our inIndex code with the inIndex clock or vice versa
38887
38927
  const existingIndex = database.indexes.get(inIndex.mapFnString);
38888
38928
  // keep the code instance, discard the clock instance
38889
- if (existingIndex.mapFn) { // this one also has other config
38929
+ if (existingIndex.mapFn) {
38930
+ // this one also has other config
38890
38931
  existingIndex.dbHead = inIndex.dbHead;
38891
38932
  existingIndex.indexById.cid = inIndex.indexById.cid;
38892
38933
  existingIndex.indexByKey.cid = inIndex.indexByKey.cid;
@@ -38930,7 +38971,7 @@ class DbIndex {
38930
38971
  /**
38931
38972
  * Query object can have {range}
38932
38973
  * @param {DbQuery} query - the query range to use
38933
- * @returns {Promise<{proof: {}, rows: Array<{id: string, key: string, value: any}>}>}
38974
+ * @returns {Promise<{proof: {}, rows: Array<{id: string, key: string, value: any, doc?: any}>}>}
38934
38975
  * @memberof DbIndex
38935
38976
  * @instance
38936
38977
  */
@@ -38938,20 +38979,63 @@ class DbIndex {
38938
38979
  // const callId = Math.random().toString(36).substring(2, 7)
38939
38980
  // todo pass a root to query a snapshot
38940
38981
  // console.time(callId + '.updateIndex')
38941
- update && await this.updateIndex(this.database.indexBlocks);
38982
+ update && (await this.updateIndex(this.database.indexBlocks));
38942
38983
  // console.timeEnd(callId + '.updateIndex')
38943
38984
  // console.time(callId + '.doIndexQuery')
38944
38985
  // console.log('query', query)
38945
- const response = await doIndexQuery(this.database.indexBlocks, this.indexByKey, query);
38986
+ const response = await this.doIndexQuery(query);
38946
38987
  // console.timeEnd(callId + '.doIndexQuery')
38947
38988
  return {
38948
38989
  proof: { index: await cidsToProof(response.cids) },
38949
- rows: response.result.map(({ id, key, row }) => {
38950
- return ({ id, key: charwise.decode(key), value: row })
38990
+ rows: response.result.map(({ id, key, row, doc }) => {
38991
+ return { id, key: charwise.decode(key), value: row, doc }
38951
38992
  })
38952
38993
  }
38953
38994
  }
38954
38995
 
38996
+ /**
38997
+ *
38998
+ * @param {any} resp
38999
+ * @param {any} query
39000
+ * @returns
39001
+ */
39002
+ async applyQuery (resp, query) {
39003
+ if (query.descending) {
39004
+ resp.result = resp.result.reverse();
39005
+ }
39006
+ if (query.limit) {
39007
+ resp.result = resp.result.slice(0, query.limit);
39008
+ }
39009
+ if (query.includeDocs) {
39010
+ resp.result = await Promise.all(
39011
+ resp.result.map(async row => {
39012
+ const doc = await this.database.get(row.id);
39013
+ return { ...row, doc }
39014
+ })
39015
+ );
39016
+ }
39017
+ return resp
39018
+ }
39019
+
39020
+ async doIndexQuery (query = {}) {
39021
+ await loadIndex(this.database.indexBlocks, this.indexByKey, dbIndexOpts);
39022
+ if (!this.indexByKey.root) return { result: [] }
39023
+ if (query.includeDocs === undefined) query.includeDocs = this.includeDocsDefault;
39024
+ if (query.range) {
39025
+ const encodedRange = query.range.map(key => charwise.encode(key));
39026
+ return await this.applyQuery(await this.indexByKey.root.range(...encodedRange), query)
39027
+ } else if (query.key) {
39028
+ const encodedKey = charwise.encode(query.key);
39029
+ return await this.applyQuery(this.indexByKey.root.get(encodedKey), query)
39030
+ } else {
39031
+ const { result, ...all } = await this.indexByKey.root.getAllEntries();
39032
+ return await this.applyQuery(
39033
+ { result: result.map(({ key: [k, id], value }) => ({ key: k, id, row: value })), ...all },
39034
+ query
39035
+ )
39036
+ }
39037
+ }
39038
+
38955
39039
  /**
38956
39040
  * Update the DbIndex with the latest changes
38957
39041
  * @private
@@ -38968,7 +39052,9 @@ class DbIndex {
38968
39052
  })
38969
39053
  }
38970
39054
  this.updateIndexPromise = this.innerUpdateIndex(blocks);
38971
- this.updateIndexPromise.finally(() => { this.updateIndexPromise = null; });
39055
+ this.updateIndexPromise.finally(() => {
39056
+ this.updateIndexPromise = null;
39057
+ });
38972
39058
  return this.updateIndexPromise
38973
39059
  }
38974
39060
 
@@ -38987,7 +39073,7 @@ class DbIndex {
38987
39073
  this.dbHead = result.clock;
38988
39074
  return
38989
39075
  }
38990
- const didT = await doTransaction('updateIndex', inBlocks, async (blocks) => {
39076
+ const didT = await doTransaction('updateIndex', inBlocks, async blocks => {
38991
39077
  let oldIndexEntries = [];
38992
39078
  let removeByIdIndexEntries = [];
38993
39079
  await loadIndex(blocks, this.indexById, idIndexOpts);
@@ -38995,19 +39081,28 @@ class DbIndex {
38995
39081
  // console.log('head', this.dbHead, this.indexById)
38996
39082
  if (this.indexById.root) {
38997
39083
  const oldChangeEntries = await this.indexById.root.getMany(result.rows.map(({ key }) => key));
38998
- oldIndexEntries = oldChangeEntries.result.map((key) => ({ key, del: true }));
39084
+ oldIndexEntries = oldChangeEntries.result.map(key => ({ key, del: true }));
38999
39085
  removeByIdIndexEntries = oldIndexEntries.map(({ key }) => ({ key: key[1], del: true }));
39000
39086
  }
39001
39087
  if (!this.mapFn) {
39002
- throw new Error('No live map function installed for index, cannot update. Make sure your index definition runs before any queries.' + (this.mapFnString ? ' Your code should match the stored map function source:\n' + this.mapFnString : ''))
39088
+ throw new Error(
39089
+ 'No live map function installed for index, cannot update. Make sure your index definition runs before any queries.' +
39090
+ (this.mapFnString ? ' Your code should match the stored map function source:\n' + this.mapFnString : '')
39091
+ )
39003
39092
  }
39004
39093
  const indexEntries = indexEntriesForChanges(result.rows, this.mapFn);
39005
39094
  const byIdIndexEntries = indexEntries.map(({ key }) => ({ key: key[1], value: key }));
39006
- this.indexById = await bulkIndex(blocks, this.indexById, removeByIdIndexEntries.concat(byIdIndexEntries), idIndexOpts);
39095
+ this.indexById = await bulkIndex(
39096
+ blocks,
39097
+ this.indexById,
39098
+ removeByIdIndexEntries.concat(byIdIndexEntries),
39099
+ idIndexOpts
39100
+ );
39007
39101
  this.indexByKey = await bulkIndex(blocks, this.indexByKey, oldIndexEntries.concat(indexEntries), dbIndexOpts);
39008
39102
  this.dbHead = result.clock;
39009
39103
  });
39010
- this.database.notifyExternal('dbIndex');
39104
+ // todo index subscriptions
39105
+ // this.database.notifyExternal('dbIndex')
39011
39106
  // console.timeEnd(callTag + '.doTransactionupdateIndex')
39012
39107
  // console.log(`updateIndex ${callTag} <`, this.instanceId, this.dbHead?.toString(), this.indexByKey.cid?.toString(), this.indexById.cid?.toString())
39013
39108
  return didT
@@ -39069,26 +39164,6 @@ async function loadIndex (blocks, index, indexOpts) {
39069
39164
  return index.root
39070
39165
  }
39071
39166
 
39072
- async function applyLimit (results, limit) {
39073
- results.result = results.result.slice(0, limit);
39074
- return results
39075
- }
39076
-
39077
- async function doIndexQuery (blocks, indexByKey, query = {}) {
39078
- await loadIndex(blocks, indexByKey, dbIndexOpts);
39079
- if (!indexByKey.root) return { result: [] }
39080
- if (query.range) {
39081
- const encodedRange = query.range.map((key) => charwise.encode(key));
39082
- return applyLimit(await indexByKey.root.range(...encodedRange), query.limit)
39083
- } else if (query.key) {
39084
- const encodedKey = charwise.encode(query.key);
39085
- return indexByKey.root.get(encodedKey)
39086
- } else {
39087
- const { result, ...all } = await indexByKey.root.getAllEntries();
39088
- return applyLimit({ result: result.map(({ key: [k, id], value }) => ({ key: k, id, row: value })), ...all }, query.limit)
39089
- }
39090
- }
39091
-
39092
39167
  var browserExports = {};
39093
39168
  var browser = {
39094
39169
  get exports(){ return browserExports; },
@@ -41054,6 +41129,10 @@ class Sync {
41054
41129
  // get the roots parents
41055
41130
  const parents = await Promise.all(roots.map(async (cid) => {
41056
41131
  const rbl = await reader.get(cid);
41132
+ if (!rbl) {
41133
+ console.log('missing root block', cid.toString(), reader);
41134
+ throw new Error('missing root block')
41135
+ }
41057
41136
  const block = await decodeEventBlock(rbl.bytes);
41058
41137
  return block.value.parents
41059
41138
  }));
@@ -41070,7 +41149,7 @@ class Sync {
41070
41149
  } else if (message.clock) {
41071
41150
  const reqCidDiff = message;
41072
41151
  // this might be a CID diff
41073
- // console.log('got diff', reqCidDiff)
41152
+ console.log('got diff', reqCidDiff);
41074
41153
  const carBlock = await Sync.makeCar(this.database, null, reqCidDiff.cids);
41075
41154
  if (!carBlock) {
41076
41155
  // we are full synced
@@ -41173,7 +41252,7 @@ class Fireproof {
41173
41252
  if (existing) {
41174
41253
  const existingConfig = JSON.parse(existing);
41175
41254
  const fp = new Database(new TransactionBlockstore(name, existingConfig.key), [], opts);
41176
- return this.fromJSON(existingConfig, fp)
41255
+ return Fireproof.fromJSON(existingConfig, fp)
41177
41256
  } else {
41178
41257
  const instanceKey = browserExports$1(32).toString('hex'); // pass null to disable encryption
41179
41258
  return new Database(new TransactionBlockstore(name, instanceKey), [], opts)
@@ -41216,7 +41295,7 @@ class Fireproof {
41216
41295
  index.clock.db = null;
41217
41296
  });
41218
41297
  }
41219
- const snappedDb = this.fromJSON(definition, withBlocks)
41298
+ const snappedDb = Fireproof.fromJSON(definition, withBlocks)
41220
41299
  ;[...database.indexes.values()].forEach(index => {
41221
41300
  snappedDb.indexes.get(index.mapFnString).mapFn = index.mapFn;
41222
41301
  });