@fireproof/core 0.3.22 → 0.4.1

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.
@@ -37225,7 +37225,10 @@ class TransactionBlockstore {
37225
37225
  inflightTransactions = new Set()
37226
37226
 
37227
37227
  constructor (name, encryptionKey) {
37228
- this.valet = new Valet(name, encryptionKey);
37228
+ if (name) {
37229
+ this.valet = new Valet(name, encryptionKey);
37230
+ }
37231
+ this.remoteBlockFunction = null;
37229
37232
  }
37230
37233
 
37231
37234
  /**
@@ -37258,6 +37261,7 @@ class TransactionBlockstore {
37258
37261
  async committedGet (key) {
37259
37262
  const old = this.committedBlocks.get(key);
37260
37263
  if (old) return old
37264
+ if (!this.valet) throw new Error('Missing block: ' + key)
37261
37265
  const got = await this.valet.getBlock(key);
37262
37266
  // console.log('committedGet: ' + key)
37263
37267
  this.committedBlocks.set(key, got);
@@ -37269,9 +37273,9 @@ class TransactionBlockstore {
37269
37273
  }
37270
37274
 
37271
37275
  async networkGet (key) {
37272
- if (this.valet.remoteBlockFunction) {
37276
+ if (this.remoteBlockFunction) {
37273
37277
  // todo why is this on valet?
37274
- const value = await husher(key, async () => await this.valet.remoteBlockFunction(key));
37278
+ const value = await husher(key, async () => await this.remoteBlockFunction(key));
37275
37279
  if (value) {
37276
37280
  // console.log('networkGot: ' + key, value.length)
37277
37281
  doTransaction('networkGot: ' + key, this, async innerBlockstore => {
@@ -37349,7 +37353,7 @@ class TransactionBlockstore {
37349
37353
  cids.add(stringCid);
37350
37354
  }
37351
37355
  }
37352
- if (cids.size > 0) {
37356
+ if (cids.size > 0 && this.valet) {
37353
37357
  // console.log(innerBlockstore.label, 'committing', cids.size, 'blocks')
37354
37358
  await this.valet.writeTransaction(innerBlockstore, cids);
37355
37359
  }
@@ -37440,6 +37444,10 @@ class InnerBlockstore {
37440
37444
 
37441
37445
  const blockOpts = { cache: nocache, chunker: bf(3), codec: codec$1, hasher: sha256$2, compare: simpleCompare };
37442
37446
 
37447
+ /**
37448
+ * @typedef {import('./blockstore.js').TransactionBlockstore} TransactionBlockstore
37449
+ */
37450
+
37443
37451
  const withLog = async (label, fn) => {
37444
37452
  const resp = await fn();
37445
37453
  // console.log('withLog', label, !!resp)
@@ -37660,7 +37668,7 @@ async function put (inBlocks, head, event, options) {
37660
37668
  /**
37661
37669
  * Determine the effective prolly root given the current merkle clock head.
37662
37670
  *
37663
- * @param {import('./blockstore.js').TransactionBlockstore} inBlocks Bucket block storage.
37671
+ * @param {TransactionBlockstore} inBlocks Bucket block storage.
37664
37672
  * @param {import('./clock').EventLink<import('./clock').EventData>[]} head Merkle clock head.
37665
37673
  */
37666
37674
  async function root (inBlocks, head) {
@@ -37669,8 +37677,8 @@ async function root (inBlocks, head) {
37669
37677
  }
37670
37678
  const { root: newProllyRootNode, blocks: newBlocks, cids } = await doProllyBulk(inBlocks, head);
37671
37679
  // todo maybe these should go to a temp blockstore?
37672
- await doTransaction('root', inBlocks, async (transactionBlockstore) => {
37673
- const { bigPut } = makeGetAndPutBlock(transactionBlockstore);
37680
+ await doTransaction('root', inBlocks, async (transactionBlocks) => {
37681
+ const { bigPut } = makeGetAndPutBlock(transactionBlocks);
37674
37682
  for (const nb of newBlocks) {
37675
37683
  bigPut(nb);
37676
37684
  }
@@ -37680,7 +37688,7 @@ async function root (inBlocks, head) {
37680
37688
 
37681
37689
  /**
37682
37690
  * Get the list of events not known by the `since` event
37683
- * @param {import('./blockstore.js').TransactionBlockstore} blocks Bucket block storage.
37691
+ * @param {TransactionBlockstore} blocks Bucket block storage.
37684
37692
  * @param {import('./clock').EventLink<import('./clock').EventData>[]} head Merkle clock head.
37685
37693
  * @param {import('./clock').EventLink<import('./clock').EventData>} since Event to compare against.
37686
37694
  * @returns {Promise<{clockCIDs: CIDCounter, result: import('./clock').EventData[]}>}
@@ -37697,7 +37705,7 @@ async function eventsSince (blocks, head, since) {
37697
37705
 
37698
37706
  /**
37699
37707
  *
37700
- * @param {import('./blockstore.js').TransactionBlockstore} blocks Bucket block storage.
37708
+ * @param {TransactionBlockstore} blocks Bucket block storage.
37701
37709
  * @param {import('./clock').EventLink<import('./clock').EventData>[]} head Merkle clock head.
37702
37710
  *
37703
37711
  * @returns {Promise<{cids: CIDCounter, clockCIDs: CIDCounter, result: import('./clock').EventData[]}>}
@@ -37718,7 +37726,7 @@ async function getAll (blocks, head) {
37718
37726
  }
37719
37727
 
37720
37728
  /**
37721
- * @param {import('./blockstore.js').TransactionBlockstore} blocks Bucket block storage.
37729
+ * @param {TransactionBlockstore} blocks Bucket block storage.
37722
37730
  * @param {import('./clock').EventLink<import('./clock').EventData>[]} head Merkle clock head.
37723
37731
  * @param {string} key The key of the value to retrieve.
37724
37732
  */
@@ -38000,6 +38008,22 @@ object.factory = function (codec) {
38000
38008
  exports.type = 'charwise';
38001
38009
  } (charwise));
38002
38010
 
38011
+ /* global localStorage */
38012
+ let storageSupported = false;
38013
+ try {
38014
+ storageSupported = window.localStorage && true;
38015
+ } catch (e) {}
38016
+ function localGet (key) {
38017
+ if (storageSupported) {
38018
+ return localStorage && localStorage.getItem(key)
38019
+ }
38020
+ }
38021
+ function localSet (key, value) {
38022
+ if (storageSupported) {
38023
+ return localStorage && localStorage.setItem(key, value)
38024
+ }
38025
+ }
38026
+
38003
38027
  // @ts-nocheck
38004
38028
 
38005
38029
  /**
@@ -38014,31 +38038,16 @@ object.factory = function (codec) {
38014
38038
  * @param {object} [authCtx] - Optional authorization context object to use for any authentication checks.
38015
38039
  *
38016
38040
  */
38017
- class Fireproof {
38041
+ class Database {
38018
38042
  listeners = new Set()
38019
38043
 
38020
- /**
38021
- * @function storage
38022
- * @memberof Fireproof
38023
- * Creates a new Fireproof instance with default storage settings
38024
- * Most apps should use this and not worry about the details.
38025
- * @static
38026
- * @returns {Fireproof} - a new Fireproof instance
38027
- */
38028
- static storage = (name = 'global') => {
38029
- const instanceKey = browserExports(32).toString('hex'); // pass null to disable encryption
38030
- // pick a random key from const validatedKeys
38031
- // const instanceKey = validatedKeys[Math.floor(Math.random() * validatedKeys.length)]
38032
- return new Fireproof(new TransactionBlockstore(name, instanceKey), [], { name })
38033
- }
38034
-
38035
- constructor (blocks, clock, config, authCtx = {}) {
38036
- this.name = config?.name || 'global';
38044
+ // todo refactor this for the next version
38045
+ constructor (blocks, clock, config = {}) {
38046
+ this.name = config.name;
38037
38047
  this.instanceId = `fp.${this.name}.${Math.random().toString(36).substring(2, 7)}`;
38038
38048
  this.blocks = blocks;
38039
38049
  this.clock = clock;
38040
38050
  this.config = config;
38041
- this.authCtx = authCtx;
38042
38051
  this.indexes = new Map();
38043
38052
  }
38044
38053
 
@@ -38053,7 +38062,7 @@ class Fireproof {
38053
38062
  return {
38054
38063
  clock: this.clockToJSON(),
38055
38064
  name: this.name,
38056
- key: this.blocks.valet.getKeyMaterial(),
38065
+ key: this.blocks.valet?.getKeyMaterial(),
38057
38066
  indexes: [...this.indexes.values()].map(index => index.toJSON())
38058
38067
  }
38059
38068
  }
@@ -38071,10 +38080,16 @@ class Fireproof {
38071
38080
  hydrate ({ clock, name, key }) {
38072
38081
  this.name = name;
38073
38082
  this.clock = clock;
38074
- this.blocks.valet.setKeyMaterial(key);
38083
+ this.blocks.valet?.setKeyMaterial(key);
38075
38084
  this.indexBlocks = null;
38076
38085
  }
38077
38086
 
38087
+ maybeSaveClock () {
38088
+ if (this.name && this.blocks.valet) {
38089
+ localSet('fp.' + this.name, JSON.stringify(this));
38090
+ }
38091
+ }
38092
+
38078
38093
  /**
38079
38094
  * Triggers a notification to all listeners
38080
38095
  * of the Fireproof instance so they can repaint UI, etc.
@@ -38185,14 +38200,19 @@ class Fireproof {
38185
38200
  doc._id = key;
38186
38201
  return doc
38187
38202
  }
38203
+ /**
38204
+ * @typedef {Object} Document
38205
+ * @property {string} _id - The ID of the document (required)
38206
+ * @property {string} [_proof] - The proof of the document (optional)
38207
+ * @property {string} [_clock] - The clock of the document (optional)
38208
+ * @property {any} [key: string] - Index signature notation to allow any other unknown fields
38209
+ * * @property {Object.<string, any>} [otherProperties] - Any other unknown properties (optional)
38210
+ */
38188
38211
 
38189
38212
  /**
38190
38213
  * Adds a new document to the database, or updates an existing document. Returns the ID of the document and the new clock head.
38191
38214
  *
38192
- * @param {Object} doc - the document to be added
38193
- * @param {string} doc._id - the document ID. If not provided, a random ID will be generated.
38194
- * @param {CID[]} doc._clock - the document ID. If not provided, a random ID will be generated.
38195
- * @param {Proof} doc._proof - CIDs referenced by the update
38215
+ * @param {Document} doc - the document to be added
38196
38216
  * @returns {Promise<{ id: string, clock: CID[] }>} - The result of adding the document to the database
38197
38217
  * @memberof Fireproof
38198
38218
  * @instance
@@ -38300,6 +38320,7 @@ class Fireproof {
38300
38320
 
38301
38321
  async notifyListeners (changes) {
38302
38322
  // await sleep(10)
38323
+ await this.maybeSaveClock();
38303
38324
  for (const listener of this.listeners) {
38304
38325
  await listener(changes);
38305
38326
  }
@@ -38312,8 +38333,7 @@ class Fireproof {
38312
38333
  }
38313
38334
 
38314
38335
  setRemoteBlockReader (remoteBlockReaderFn) {
38315
- // console.log('registering remote block reader')
38316
- this.blocks.valet.remoteBlockFunction = remoteBlockReaderFn;
38336
+ this.blocks.remoteBlockFunction = remoteBlockReaderFn;
38317
38337
  }
38318
38338
  }
38319
38339
 
@@ -38334,6 +38354,124 @@ function encodeEvent (event) {
38334
38354
  return { ...event, key: encodedKey }
38335
38355
  }
38336
38356
 
38357
+ /**
38358
+ * A Fireproof database Listener allows you to react to events in the database.
38359
+ *
38360
+ * @class Listener
38361
+ * @classdesc An listener attaches to a Fireproof database and runs a routing function on each change, sending the results to subscribers.
38362
+ *
38363
+ * @param {import('./database.js').Database} database - The Database database instance to index.
38364
+ * @param {Function} routingFn - The routing function to apply to each entry in the database.
38365
+ */
38366
+ // import { ChangeEvent } from './db-index'
38367
+
38368
+ class Listener {
38369
+ subcribers = new Map()
38370
+ doStopListening = null
38371
+
38372
+ /**
38373
+ * @param {import('./database.js').Database} database
38374
+ * @param {(_: any, emit: any) => void} routingFn
38375
+ */
38376
+ constructor (
38377
+ database,
38378
+ routingFn = function (/** @type {any} */ _, /** @type {(arg0: string) => void} */ emit) {
38379
+ emit('*');
38380
+ }
38381
+ ) {
38382
+ this.database = database;
38383
+ this.doStopListening = database.registerListener((/** @type {any} */ changes) => this.onChanges(changes));
38384
+ /**
38385
+ * The map function to apply to each entry in the database.
38386
+ * @type {Function}
38387
+ */
38388
+ this.routingFn = routingFn;
38389
+
38390
+ this.dbHead = null;
38391
+ }
38392
+
38393
+ /**
38394
+ * Subscribe to a topic emitted by the event function.
38395
+ * @param {string} topic - The topic to subscribe to.
38396
+ * @param {Function} subscriber - The function to call when the topic is emitted.
38397
+ * @returns {Function} A function to unsubscribe from the topic.
38398
+ * @memberof Listener
38399
+ * @instance
38400
+ * @param {any} since
38401
+ */
38402
+ on (topic, subscriber, since) {
38403
+ const listOfTopicSubscribers = getTopicList(this.subcribers, topic);
38404
+ listOfTopicSubscribers.push(subscriber);
38405
+ if (typeof since !== 'undefined') {
38406
+ this.database.changesSince(since).then(({ rows: changes }) => {
38407
+ const keys = topicsForChanges(changes, this.routingFn).get(topic);
38408
+ if (keys) keys.forEach((/** @type {any} */ key) => subscriber(key));
38409
+ });
38410
+ }
38411
+ return () => {
38412
+ const index = listOfTopicSubscribers.indexOf(subscriber);
38413
+ if (index > -1) listOfTopicSubscribers.splice(index, 1);
38414
+ }
38415
+ }
38416
+
38417
+ /**
38418
+ * @typedef {import('./db-index').ChangeEvent} ChangeEvent
38419
+ */
38420
+
38421
+ /**
38422
+ * @param {ChangeEvent[]} changes
38423
+ */
38424
+ onChanges (changes) {
38425
+ if (Array.isArray(changes)) {
38426
+ const seenTopics = topicsForChanges(changes, this.routingFn);
38427
+ for (const [topic, keys] of seenTopics) {
38428
+ const listOfTopicSubscribers = getTopicList(this.subcribers, topic);
38429
+ listOfTopicSubscribers.forEach((/** @type {(arg0: any) => any} */ subscriber) =>
38430
+ keys.forEach((/** @type {any} */ key) => subscriber(key))
38431
+ );
38432
+ }
38433
+ } else {
38434
+ // non-arrays go to all subscribers
38435
+ for (const [, listOfTopicSubscribers] of this.subcribers) {
38436
+ listOfTopicSubscribers.forEach((/** @type {(arg0: any) => any} */ subscriber) => subscriber(changes));
38437
+ }
38438
+ }
38439
+ }
38440
+ }
38441
+
38442
+ /**
38443
+ * @param {Map<any, any>} subscribersMap
38444
+ * @param {string} name
38445
+ */
38446
+ function getTopicList (subscribersMap, name) {
38447
+ let topicList = subscribersMap.get(name);
38448
+ if (!topicList) {
38449
+ topicList = [];
38450
+ subscribersMap.set(name, topicList);
38451
+ }
38452
+ return topicList
38453
+ }
38454
+
38455
+ /**
38456
+ * Transforms a set of changes to events using an emitter function.
38457
+ *
38458
+ * @param {ChangeEvent[]} changes
38459
+ * @param {Function} routingFn
38460
+ * @returns {Map<string,string[]>} The topics emmitted by the event function.
38461
+ * @private
38462
+ */
38463
+ const topicsForChanges = (changes, routingFn) => {
38464
+ const seenTopics = new Map();
38465
+ changes.forEach(({ key, value, del }) => {
38466
+ if (del || !value) value = { _deleted: true };
38467
+ routingFn({ _id: key, ...value }, (/** @type {any} */ t) => {
38468
+ const topicList = getTopicList(seenTopics, t);
38469
+ topicList.push(key);
38470
+ });
38471
+ });
38472
+ return seenTopics
38473
+ };
38474
+
38337
38475
  const compare$1 = (a, b) => {
38338
38476
  const [aKey, aRef] = a;
38339
38477
  const [bKey, bRef] = b;
@@ -38528,7 +38666,7 @@ const indexEntriesForChanges = (changes, mapFn) => {
38528
38666
  * @class DbIndex
38529
38667
  * @classdesc An DbIndex can be used to order and filter the documents in a Fireproof database.
38530
38668
  *
38531
- * @param {Fireproof} database - The Fireproof database instance to DbIndex.
38669
+ * @param {Database} database - The Fireproof database instance to DbIndex.
38532
38670
  * @param {Function} mapFn - The map function to apply to each entry in the database.
38533
38671
  *
38534
38672
  */
@@ -38536,7 +38674,7 @@ class DbIndex {
38536
38674
  constructor (database, mapFn, clock, opts = {}) {
38537
38675
  this.database = database;
38538
38676
  if (!database.indexBlocks) {
38539
- database.indexBlocks = new TransactionBlockstore(database.name + '.indexes', database.blocks.valet.getKeyMaterial());
38677
+ database.indexBlocks = new TransactionBlockstore(database?.name + '.indexes', database.blocks.valet?.getKeyMaterial());
38540
38678
  }
38541
38679
  /**
38542
38680
  * The map function to apply to each entry in the database.
@@ -38755,125 +38893,34 @@ async function doIndexQuery (blocks, indexByKey, query = {}) {
38755
38893
  }
38756
38894
  }
38757
38895
 
38758
- /**
38759
- * A Fireproof database Listener allows you to react to events in the database.
38760
- *
38761
- * @class Listener
38762
- * @classdesc An listener attaches to a Fireproof database and runs a routing function on each change, sending the results to subscribers.
38763
- *
38764
- * @param {import('./fireproof.js').Fireproof} database - The Fireproof database instance to index.
38765
- * @param {Function} routingFn - The routing function to apply to each entry in the database.
38766
- */
38767
- // import { ChangeEvent } from './db-index'
38768
-
38769
- class Listener {
38770
- subcribers = new Map()
38771
- doStopListening = null
38772
-
38773
- /**
38774
- * @param {import('./fireproof.js').Fireproof} database
38775
- * @param {(_: any, emit: any) => void} routingFn
38776
- */
38777
- constructor (database, routingFn) {
38778
- this.database = database;
38779
- this.doStopListening = database.registerListener((/** @type {any} */ changes) => this.onChanges(changes));
38780
- /**
38781
- * The map function to apply to each entry in the database.
38782
- * @type {Function}
38783
- */
38784
- this.routingFn =
38785
- routingFn ||
38786
- function (/** @type {any} */ _, /** @type {(arg0: string) => void} */ emit) {
38787
- emit('*');
38788
- };
38789
- this.dbHead = null;
38790
- }
38791
-
38792
- /**
38793
- * Subscribe to a topic emitted by the event function.
38794
- * @param {string} topic - The topic to subscribe to.
38795
- * @param {Function} subscriber - The function to call when the topic is emitted.
38796
- * @returns {Function} A function to unsubscribe from the topic.
38797
- * @memberof Listener
38798
- * @instance
38799
- * @param {any} since
38800
- */
38801
- on (topic, subscriber, since) {
38802
- const listOfTopicSubscribers = getTopicList(this.subcribers, topic);
38803
- listOfTopicSubscribers.push(subscriber);
38804
- if (typeof since !== 'undefined') {
38805
- this.database.changesSince(since).then(({ rows: changes }) => {
38806
- const keys = topicsForChanges(changes, this.routingFn).get(topic);
38807
- if (keys) keys.forEach((/** @type {any} */ key) => subscriber(key));
38808
- });
38809
- }
38810
- return () => {
38811
- const index = listOfTopicSubscribers.indexOf(subscriber);
38812
- if (index > -1) listOfTopicSubscribers.splice(index, 1);
38813
- }
38814
- }
38815
-
38816
- /**
38817
- * @typedef {import('./db-index').ChangeEvent} ChangeEvent
38818
- */
38896
+ const parseCID = cid => typeof cid === 'string' ? CID$1.parse(cid) : cid;
38819
38897
 
38898
+ class Fireproof {
38820
38899
  /**
38821
- * @param {ChangeEvent[]} changes
38900
+ * @function storage
38901
+ * @memberof Fireproof
38902
+ * Creates a new Fireproof instance with default storage settings
38903
+ * Most apps should use this and not worry about the details.
38904
+ * @static
38905
+ * @returns {Database} - a new Fireproof instance
38822
38906
  */
38823
- onChanges (changes) {
38824
- if (Array.isArray(changes)) {
38825
- const seenTopics = topicsForChanges(changes, this.routingFn);
38826
- for (const [topic, keys] of seenTopics) {
38827
- const listOfTopicSubscribers = getTopicList(this.subcribers, topic);
38828
- listOfTopicSubscribers.forEach((/** @type {(arg0: any) => any} */ subscriber) =>
38829
- keys.forEach((/** @type {any} */ key) => subscriber(key))
38830
- );
38907
+ static storage = (name = null, opts = {}) => {
38908
+ if (name) {
38909
+ opts.name = name;
38910
+ const existing = localGet('fp.' + name);
38911
+ if (existing) {
38912
+ const existingConfig = JSON.parse(existing);
38913
+ const fp = new Database(new TransactionBlockstore(name, existingConfig.key), [], opts);
38914
+ return this.fromJSON(existingConfig, fp)
38915
+ } else {
38916
+ const instanceKey = browserExports(32).toString('hex'); // pass null to disable encryption
38917
+ return new Database(new TransactionBlockstore(name, instanceKey), [], opts)
38831
38918
  }
38832
38919
  } else {
38833
- // non-arrays go to all subscribers
38834
- for (const [, listOfTopicSubscribers] of this.subcribers) {
38835
- listOfTopicSubscribers.forEach((/** @type {(arg0: any) => any} */ subscriber) => subscriber(changes));
38836
- }
38920
+ return new Database(new TransactionBlockstore(), [], opts)
38837
38921
  }
38838
38922
  }
38839
- }
38840
-
38841
- /**
38842
- * @param {Map<any, any>} subscribersMap
38843
- * @param {string} name
38844
- */
38845
- function getTopicList (subscribersMap, name) {
38846
- let topicList = subscribersMap.get(name);
38847
- if (!topicList) {
38848
- topicList = [];
38849
- subscribersMap.set(name, topicList);
38850
- }
38851
- return topicList
38852
- }
38853
-
38854
- /**
38855
- * Transforms a set of changes to events using an emitter function.
38856
- *
38857
- * @param {ChangeEvent[]} changes
38858
- * @param {Function} routingFn
38859
- * @returns {Map<string,string[]>} The topics emmitted by the event function.
38860
- * @private
38861
- */
38862
- const topicsForChanges = (changes, routingFn) => {
38863
- const seenTopics = new Map();
38864
- changes.forEach(({ key, value, del }) => {
38865
- if (del || !value) value = { _deleted: true };
38866
- routingFn({ _id: key, ...value }, (/** @type {any} */ t) => {
38867
- const topicList = getTopicList(seenTopics, t);
38868
- topicList.push(key);
38869
- });
38870
- });
38871
- return seenTopics
38872
- };
38873
-
38874
- const parseCID = cid => typeof cid === 'string' ? CID$1.parse(cid) : cid;
38875
38923
 
38876
- class Hydrator {
38877
38924
  static fromJSON (json, database) {
38878
38925
  database.hydrate({ clock: json.clock.map(c => parseCID(c)), name: json.name, key: json.key });
38879
38926
  if (json.indexes) {
@@ -38894,7 +38941,7 @@ class Hydrator {
38894
38941
 
38895
38942
  static snapshot (database, clock) {
38896
38943
  const definition = database.toJSON();
38897
- const withBlocks = new Fireproof(database.blocks);
38944
+ const withBlocks = new Database(database.blocks);
38898
38945
  if (clock) {
38899
38946
  definition.clock = clock.map(c => parseCID(c));
38900
38947
  definition.indexes.forEach(index => {
@@ -38922,5 +38969,5 @@ class Hydrator {
38922
38969
  }
38923
38970
  }
38924
38971
 
38925
- export { Fireproof, Hydrator, DbIndex as Index, Listener };
38926
- //# sourceMappingURL=index.mjs.map
38972
+ export { Fireproof, DbIndex as Index, Listener };
38973
+ //# sourceMappingURL=fireproof.mjs.map