@fireproof/core 0.20.0-dev-preview-39 → 0.20.0-dev-preview-41

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.
Files changed (38) hide show
  1. package/README.md +6 -4
  2. package/deno/index.js +2 -2
  3. package/deno/index.js.map +1 -1
  4. package/index.cjs +499 -370
  5. package/index.cjs.map +1 -1
  6. package/index.d.cts +162 -64
  7. package/index.d.ts +162 -64
  8. package/index.js +473 -344
  9. package/index.js.map +1 -1
  10. package/metafile-cjs.json +1 -1
  11. package/metafile-esm.json +1 -1
  12. package/package.json +3 -3
  13. package/react/index.cjs +28 -11
  14. package/react/index.cjs.map +1 -1
  15. package/react/index.d.cts +2 -1
  16. package/react/index.d.ts +2 -1
  17. package/react/index.js +29 -12
  18. package/react/index.js.map +1 -1
  19. package/react/metafile-cjs.json +1 -1
  20. package/react/metafile-esm.json +1 -1
  21. package/tests/blockstore/interceptor-gateway.test.ts +5 -1
  22. package/tests/blockstore/keyed-crypto-indexeddb-file.test.ts +8 -18
  23. package/tests/blockstore/keyed-crypto.test.ts +7 -30
  24. package/tests/blockstore/loader.test.ts +19 -17
  25. package/tests/blockstore/store.test.ts +48 -51
  26. package/tests/blockstore/transaction.test.ts +13 -11
  27. package/tests/fireproof/all-gateway.test.ts +49 -46
  28. package/tests/fireproof/attachable.test.ts +82 -0
  29. package/tests/fireproof/crdt.test.ts +49 -48
  30. package/tests/fireproof/database.test.ts +40 -40
  31. package/tests/fireproof/fireproof.test.ts +43 -42
  32. package/tests/fireproof/hello.test.ts +4 -4
  33. package/tests/fireproof/indexer.test.ts +44 -44
  34. package/tests/fireproof/utils.test.ts +4 -3
  35. package/tests/gateway/file/loader-config.test.ts +17 -17
  36. package/tests/gateway/indexeddb/loader-config.test.ts +4 -4
  37. package/tests/helpers.ts +80 -2
  38. package/tests/react/useFireproof.test.tsx +79 -4
package/index.cjs CHANGED
@@ -31,6 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
33
  CRDTImpl: () => CRDTImpl,
34
+ DataAndMetaAndWalAndBaseStore: () => DataAndMetaAndWalAndBaseStore,
34
35
  DatabaseImpl: () => DatabaseImpl,
35
36
  Index: () => Index,
36
37
  LedgerFactory: () => LedgerFactory,
@@ -116,6 +117,18 @@ function falsyToUndef(value) {
116
117
  }
117
118
  return value;
118
119
  }
120
+ var DataAndMetaAndWalAndBaseStore = class {
121
+ constructor(dam) {
122
+ this.wal = dam.wal;
123
+ this.file = dam.file;
124
+ this.car = dam.car;
125
+ this.meta = dam.meta;
126
+ this.baseStores = [this.file, this.car, this.meta];
127
+ if (this.wal) {
128
+ this.baseStores.push(this.wal);
129
+ }
130
+ }
131
+ };
119
132
 
120
133
  // src/utils.ts
121
134
  var import_base58 = require("multiformats/bases/base58");
@@ -1285,7 +1298,7 @@ var MemoryGateway = class {
1285
1298
  get(url) {
1286
1299
  const x = this.memorys.get(url.toString());
1287
1300
  if (!x) {
1288
- return Promise.resolve(import_cement6.Result.Err(new NotFoundError("not found")));
1301
+ return Promise.resolve(import_cement6.Result.Err(new NotFoundError(`not found: ${url.getParam(PARAM.STORE)}`)));
1289
1302
  }
1290
1303
  return Promise.resolve(import_cement6.Result.Ok(x));
1291
1304
  }
@@ -1391,9 +1404,6 @@ async function decode2DbMetaEvents(sthis, rserializedMeta) {
1391
1404
  if (!Array.isArray(serializedMeta)) {
1392
1405
  return sthis.logger.Debug().Any("metaEntries", serializedMeta).Msg("No data in MetaEntries").ResultError();
1393
1406
  }
1394
- if (!serializedMeta.length) {
1395
- return sthis.logger.Debug().Msg("No MetaEntries found").ResultError();
1396
- }
1397
1407
  return import_cement8.Result.Ok(
1398
1408
  await Promise.all(
1399
1409
  serializedMeta.map(async (metaEntry) => {
@@ -2080,6 +2090,9 @@ var DatabaseImpl = class {
2080
2090
  this.id = ledger.id;
2081
2091
  this.logger = ensureLogger(this.sthis, "Database");
2082
2092
  }
2093
+ attach(a) {
2094
+ return this.ledger.attach(a);
2095
+ }
2083
2096
  get name() {
2084
2097
  return this.ledger.name;
2085
2098
  }
@@ -2175,11 +2188,11 @@ var import_cement19 = require("@adviser/cement");
2175
2188
  // src/blockstore/index.ts
2176
2189
  var blockstore_exports = {};
2177
2190
  __export(blockstore_exports, {
2191
+ AttachedRemotesImpl: () => AttachedRemotesImpl,
2178
2192
  BaseBlockstoreImpl: () => BaseBlockstoreImpl,
2179
2193
  Car2FPMsg: () => Car2FPMsg,
2180
2194
  CarTransactionImpl: () => CarTransactionImpl,
2181
2195
  CompactionFetcher: () => CompactionFetcher,
2182
- ConnectionBase: () => ConnectionBase,
2183
2196
  DbMetaEventEqual: () => DbMetaEventEqual,
2184
2197
  DbMetaEventsEqual: () => DbMetaEventsEqual,
2185
2198
  EncryptedBlockstore: () => EncryptedBlockstore,
@@ -2188,6 +2201,7 @@ __export(blockstore_exports, {
2188
2201
  InterceptorGateway: () => InterceptorGateway,
2189
2202
  Loader: () => Loader,
2190
2203
  PassThroughGateway: () => PassThroughGateway,
2204
+ createAttachedStores: () => createAttachedStores,
2191
2205
  createDbMetaEvent: () => createDbMetaEvent,
2192
2206
  defaultGatewayFactoryItem: () => defaultGatewayFactoryItem,
2193
2207
  ensureStoreEnDeFile: () => ensureStoreEnDeFile,
@@ -2212,15 +2226,15 @@ function DbMetaEventsEqual(a, b) {
2212
2226
  }
2213
2227
 
2214
2228
  // src/blockstore/store-factory.ts
2215
- var import_cement16 = require("@adviser/cement");
2229
+ var import_cement17 = require("@adviser/cement");
2216
2230
 
2217
2231
  // src/blockstore/store.ts
2218
- var import_cement15 = require("@adviser/cement");
2232
+ var import_cement16 = require("@adviser/cement");
2219
2233
 
2220
2234
  // src/blockstore/loader.ts
2221
2235
  var import_p_limit = __toESM(require("p-limit"), 1);
2222
2236
  var import_reader = require("@ipld/car/reader");
2223
- var import_cement13 = require("@adviser/cement");
2237
+ var import_cement14 = require("@adviser/cement");
2224
2238
 
2225
2239
  // src/blockstore/loader-helpers.ts
2226
2240
  var import_sha22 = require("multiformats/hashes/sha2");
@@ -2381,7 +2395,7 @@ var EncryptedBlockstore = class extends BaseBlockstoreImpl {
2381
2395
  if (!this.loader) {
2382
2396
  return;
2383
2397
  }
2384
- return falsyToUndef(await this.loader.getBlock(cid));
2398
+ return falsyToUndef(await this.loader.getBlock(cid, this.loader.attachedStores.local()));
2385
2399
  }
2386
2400
  async transaction(fn, opts = { noLoader: false }) {
2387
2401
  this.logger.Debug().Msg("enter transaction");
@@ -2401,10 +2415,7 @@ var EncryptedBlockstore = class extends BaseBlockstoreImpl {
2401
2415
  async getFile(car, cid) {
2402
2416
  await this.ready();
2403
2417
  if (!this.loader) throw this.logger.Error().Msg("loader required to get file, ledger must be named").AsError();
2404
- const reader = await this.loader.loadFileCar(
2405
- car
2406
- /*, isPublic */
2407
- );
2418
+ const reader = await this.loader.loadFileCar(car, this.loader.attachedStores.local());
2408
2419
  const block = await reader.get(cid);
2409
2420
  if (!block) throw this.logger.Error().Str("cid", cid.toString()).Msg(`Missing block`).AsError();
2410
2421
  return block.bytes;
@@ -2625,11 +2636,11 @@ var TaskManager = class {
2625
2636
  this.logger = ensureLogger(sthis, "TaskManager");
2626
2637
  this.callback = callback;
2627
2638
  }
2628
- async handleEvent(cid, parents, dbMeta) {
2639
+ async handleEvent(cid, parents, dbMeta, store) {
2629
2640
  for (const parent of parents) {
2630
2641
  this.eventsWeHandled.add(parent.toString());
2631
2642
  }
2632
- this.queue.push({ cid: cid.toString(), dbMeta, retries: 0 });
2643
+ this.queue.push({ cid: cid.toString(), dbMeta, retries: 0, store });
2633
2644
  this.queue = this.queue.filter(({ cid: cid2 }) => !this.eventsWeHandled.has(cid2));
2634
2645
  void this.processQueue();
2635
2646
  }
@@ -2643,7 +2654,7 @@ var TaskManager = class {
2643
2654
  return;
2644
2655
  }
2645
2656
  try {
2646
- await this.callback(first.dbMeta);
2657
+ await this.callback(first.dbMeta, first.store);
2647
2658
  this.eventsWeHandled.add(first.cid);
2648
2659
  this.queue = this.queue.filter(({ cid }) => !this.eventsWeHandled.has(cid));
2649
2660
  } catch (err) {
@@ -2662,6 +2673,237 @@ var TaskManager = class {
2662
2673
  }
2663
2674
  };
2664
2675
 
2676
+ // src/blockstore/attachable-store.ts
2677
+ var import_cement13 = require("@adviser/cement");
2678
+ var AttachedImpl = class {
2679
+ constructor(gws, stores, unreg) {
2680
+ this.gatewayUrls = gws;
2681
+ this.stores = new DataAndMetaAndWalAndBaseStore(stores);
2682
+ this.unreg = unreg;
2683
+ }
2684
+ async detach() {
2685
+ const toClose = [this.stores.car.close(), this.stores.file.close(), this.stores.meta.close()];
2686
+ if (this.stores.wal) {
2687
+ toClose.push(this.stores.wal.close());
2688
+ }
2689
+ await Promise.all(toClose);
2690
+ this.unreg();
2691
+ }
2692
+ status() {
2693
+ return "attached";
2694
+ }
2695
+ };
2696
+ var DataActiveStoreImpl = class {
2697
+ constructor(ref, active, attached) {
2698
+ this.ref = ref;
2699
+ this.active = active;
2700
+ this.attached = attached;
2701
+ }
2702
+ };
2703
+ var CarAttachedStoresImpl = class {
2704
+ constructor(attached) {
2705
+ this.attached = attached;
2706
+ }
2707
+ local() {
2708
+ return this.attached.local().active.car;
2709
+ }
2710
+ remotes() {
2711
+ return this.attached.remotes().map(({ active }) => active.car);
2712
+ }
2713
+ };
2714
+ var FileAttachedStoresImpl = class {
2715
+ constructor(attached) {
2716
+ this.attached = attached;
2717
+ }
2718
+ local() {
2719
+ return this.attached.local().active.file;
2720
+ }
2721
+ remotes() {
2722
+ return this.attached.remotes().map(({ active }) => active.file);
2723
+ }
2724
+ };
2725
+ var MetaActiveStoreImpl = class {
2726
+ constructor(ref, active, attached) {
2727
+ this.ref = ref;
2728
+ this.active = active;
2729
+ this.attached = attached;
2730
+ }
2731
+ };
2732
+ var MetaAttachedStoresImpl = class {
2733
+ constructor(attached) {
2734
+ this.attached = attached;
2735
+ }
2736
+ local() {
2737
+ return this.attached.local().active.meta;
2738
+ }
2739
+ remotes() {
2740
+ return this.attached.remotes().map(({ active }) => active.meta);
2741
+ }
2742
+ };
2743
+ var WALActiveStoreImpl = class {
2744
+ constructor(ref, active, attached) {
2745
+ this.ref = ref;
2746
+ this.active = active;
2747
+ this.attached = attached;
2748
+ }
2749
+ };
2750
+ var WALAttachedStoresImpl = class {
2751
+ constructor(attached) {
2752
+ this.attached = attached;
2753
+ }
2754
+ local() {
2755
+ return this.attached.local().active.wal;
2756
+ }
2757
+ remotes() {
2758
+ return this.attached.remotes().filter(({ active }) => active.wal).map(({ active }) => active.wal);
2759
+ }
2760
+ };
2761
+ var ActiveStoreImpl = class {
2762
+ constructor(active, attached) {
2763
+ this.active = active;
2764
+ this.attached = attached;
2765
+ }
2766
+ baseStores() {
2767
+ const bs = [this.active.car, this.active.file, this.active.meta];
2768
+ if (this.active.wal) {
2769
+ bs.push(this.active.wal);
2770
+ }
2771
+ return bs;
2772
+ }
2773
+ carStore() {
2774
+ return new DataActiveStoreImpl(this, this.active.car, new CarAttachedStoresImpl(this.attached));
2775
+ }
2776
+ fileStore() {
2777
+ return new DataActiveStoreImpl(this, this.active.file, new FileAttachedStoresImpl(this.attached));
2778
+ }
2779
+ metaStore() {
2780
+ return new MetaActiveStoreImpl(this, this.active.meta, new MetaAttachedStoresImpl(this.attached));
2781
+ }
2782
+ walStore() {
2783
+ if (!this.active.wal) {
2784
+ throw this.attached.loadable.sthis.logger.Error().Msg("wal store not set").AsError();
2785
+ }
2786
+ return new WALActiveStoreImpl(this, this.active.wal, new WALAttachedStoresImpl(this.attached));
2787
+ }
2788
+ };
2789
+ function isLoadable(unknown) {
2790
+ return !!unknown.sthis && !!unknown.attachedStores;
2791
+ }
2792
+ async function createAttachedStores(urlOrGup, arOrLoadable, name = "local") {
2793
+ let ar;
2794
+ if (!isLoadable(arOrLoadable)) {
2795
+ ar = arOrLoadable;
2796
+ } else {
2797
+ ar = arOrLoadable.attachedStores;
2798
+ }
2799
+ let gup;
2800
+ if (!urlOrGup) {
2801
+ throw new Error("urlOrGup is required");
2802
+ }
2803
+ if ((0, import_cement13.isCoerceURI)(urlOrGup)) {
2804
+ const url = urlOrGup;
2805
+ gup = {
2806
+ car: { url },
2807
+ file: { url },
2808
+ meta: { url },
2809
+ wal: { url }
2810
+ };
2811
+ } else {
2812
+ gup = urlOrGup;
2813
+ }
2814
+ return await ar.attach({
2815
+ name,
2816
+ prepare: async () => gup
2817
+ });
2818
+ }
2819
+ var AttachedRemotesImpl = class {
2820
+ constructor(loadable) {
2821
+ this._remotes = new import_cement13.KeyedResolvOnce();
2822
+ this.loadable = loadable;
2823
+ }
2824
+ forRemotes(action) {
2825
+ return Promise.all(this.remotes().map((i) => action(i))).then(() => void 0);
2826
+ }
2827
+ remotes() {
2828
+ return this._remotes.values().filter(({ value }) => value.isOk() && !value.Ok().stores.wal).map(({ value }) => value.Ok().stores).map((i) => this.activate(i));
2829
+ }
2830
+ local() {
2831
+ if (!this._local) {
2832
+ throw this.loadable.sthis.logger.Error().Msg("local store not set").AsError();
2833
+ }
2834
+ return new ActiveStoreImpl(this._local.stores, this);
2835
+ }
2836
+ activate(store) {
2837
+ if ((0, import_cement13.isCoerceURI)(store)) {
2838
+ throw this.loadable.sthis.logger.Error().Msg("store must be an object").AsError();
2839
+ }
2840
+ return new ActiveStoreImpl(store, this);
2841
+ }
2842
+ async detach() {
2843
+ await Promise.all(
2844
+ this._remotes.values().map(async ({ value: rvalue }) => {
2845
+ if (rvalue.isOk()) {
2846
+ await rvalue.Ok().detach();
2847
+ }
2848
+ })
2849
+ );
2850
+ }
2851
+ async attach(attached) {
2852
+ const gwp = await attached.prepare();
2853
+ const gws = {
2854
+ car: {
2855
+ ...gwp.car,
2856
+ url: import_cement13.BuildURI.from(gwp.car.url).defParam("name", attached.name).URI()
2857
+ },
2858
+ file: {
2859
+ ...gwp.file,
2860
+ url: import_cement13.BuildURI.from(gwp.file.url).defParam("name", attached.name).URI()
2861
+ },
2862
+ meta: {
2863
+ ...gwp.meta,
2864
+ url: import_cement13.BuildURI.from(gwp.meta.url).defParam("name", attached.name).URI()
2865
+ },
2866
+ wal: gwp.wal ? {
2867
+ ...gwp.wal,
2868
+ url: import_cement13.BuildURI.from(gwp.wal.url).defParam("name", attached.name).URI()
2869
+ } : void 0
2870
+ };
2871
+ const key = JSON.stringify(
2872
+ toSortedArray({
2873
+ carUrl: gws.car.url.toString(),
2874
+ filesUrl: gws.file.url.toString(),
2875
+ metaUrl: gws.meta.url.toString(),
2876
+ walUrl: gws.wal?.url.toString()
2877
+ })
2878
+ );
2879
+ return this._remotes.get(key).once(async () => {
2880
+ const rt = toStoreRuntime(this.loadable.sthis);
2881
+ const result = new AttachedImpl(
2882
+ gws,
2883
+ await rt.makeStores({
2884
+ byStore: gws,
2885
+ loader: this.loadable
2886
+ }),
2887
+ // {
2888
+ // car: await rt.makeDataStore({ url: gws.carUrl, loader: this.loadable }),
2889
+ // file: await rt.makeDataStore({ url: gws.filesUrl, loader: this.loadable }),
2890
+ // meta: await rt.makeMetaStore({ url: gws.metaUrl, loader: this.loadable }),
2891
+ // },
2892
+ () => {
2893
+ this._remotes.unget(key);
2894
+ }
2895
+ );
2896
+ if (result.stores.wal) {
2897
+ if (this._local) {
2898
+ throw this.loadable.sthis.logger.Error().Msg("local store could only set once").AsError();
2899
+ }
2900
+ this._local = result;
2901
+ }
2902
+ return result;
2903
+ });
2904
+ }
2905
+ };
2906
+
2665
2907
  // src/blockstore/loader.ts
2666
2908
  function carLogIncludesGroup(list, cids) {
2667
2909
  return list.some((arr) => {
@@ -2687,11 +2929,7 @@ var Loader = class {
2687
2929
  this.getBlockCache = /* @__PURE__ */ new Map();
2688
2930
  this.seenMeta = /* @__PURE__ */ new Set();
2689
2931
  this.writeLimit = (0, import_p_limit.default)(1);
2690
- this._carStore = new import_cement13.ResolveOnce();
2691
- this._fileStore = new import_cement13.ResolveOnce();
2692
- this._WALStore = new import_cement13.ResolveOnce();
2693
- this._metaStore = new import_cement13.ResolveOnce();
2694
- this.onceReady = new import_cement13.ResolveOnce();
2932
+ this.onceReady = new import_cement14.ResolveOnce();
2695
2933
  this.sthis = sthis;
2696
2934
  this.ebOpts = defaultedBlockstoreRuntime(
2697
2935
  sthis,
@@ -2702,75 +2940,93 @@ var Loader = class {
2702
2940
  "Loader"
2703
2941
  );
2704
2942
  this.logger = this.ebOpts.logger;
2705
- this.taskManager = new TaskManager(sthis, async (dbMeta) => {
2706
- await this.handleDbMetasFromStore([dbMeta]);
2943
+ this.taskManager = new TaskManager(sthis, async (dbMeta, activeStore) => {
2944
+ await this.handleDbMetasFromStore([dbMeta], activeStore);
2707
2945
  });
2708
- }
2709
- async carStore() {
2710
- return this._carStore.once(
2711
- async () => this.ebOpts.storeRuntime.makeDataStore({
2712
- // sthis: this.sthis,
2713
- gatewayInterceptor: this.ebOpts.gatewayInterceptor,
2714
- url: this.ebOpts.storeUrls.data,
2715
- // keybag: await this.keyBag(),
2716
- loader: this
2717
- })
2718
- );
2719
- }
2720
- async fileStore() {
2721
- return this._fileStore.once(
2722
- async () => this.ebOpts.storeRuntime.makeDataStore({
2723
- // sthis: this.sthis,
2724
- gatewayInterceptor: this.ebOpts.gatewayInterceptor,
2725
- url: this.ebOpts.storeUrls.file,
2726
- // keybag: await this.keyBag(),
2727
- loader: this
2728
- })
2729
- );
2730
- }
2731
- async WALStore() {
2732
- return this._WALStore.once(
2733
- async () => this.ebOpts.storeRuntime.makeWALStore({
2734
- // sthis: this.sthis,
2735
- gatewayInterceptor: this.ebOpts.gatewayInterceptor,
2736
- url: this.ebOpts.storeUrls.wal,
2737
- // keybag: await this.keyBag(),
2738
- loader: this
2739
- })
2740
- );
2741
- }
2742
- async metaStore() {
2743
- return this._metaStore.once(
2744
- async () => this.ebOpts.storeRuntime.makeMetaStore({
2745
- // sthis: this.sthis,
2746
- gatewayInterceptor: this.ebOpts.gatewayInterceptor,
2747
- url: this.ebOpts.storeUrls.meta,
2748
- // keybag: await this.keyBag(),
2749
- loader: this
2750
- })
2751
- );
2752
- }
2946
+ this.attachedStores = new AttachedRemotesImpl(this);
2947
+ }
2948
+ attach(attached) {
2949
+ return this.attachedStores.attach(attached);
2950
+ }
2951
+ // private readonly _carStore = new ResolveOnce<DataStore>();
2952
+ // async carStore(): Promise<DataStore> {
2953
+ // return this._carStore.once(async () =>
2954
+ // this.ebOpts.storeRuntime.makeDataStore({
2955
+ // // sthis: this.sthis,
2956
+ // gatewayInterceptor: this.ebOpts.gatewayInterceptor,
2957
+ // url: this.ebOpts.storeUrls.data,
2958
+ // // keybag: await this.keyBag(),
2959
+ // loader: this,
2960
+ // }),
2961
+ // );
2962
+ // }
2963
+ // private readonly _fileStore = new ResolveOnce<DataStore>();
2964
+ // async fileStore(): Promise<DataStore> {
2965
+ // return this._fileStore.once(async () =>
2966
+ // this.ebOpts.storeRuntime.makeDataStore({
2967
+ // // sthis: this.sthis,
2968
+ // gatewayInterceptor: this.ebOpts.gatewayInterceptor,
2969
+ // url: this.ebOpts.storeUrls.file,
2970
+ // // keybag: await this.keyBag(),
2971
+ // loader: this,
2972
+ // }),
2973
+ // );
2974
+ // }
2975
+ // private readonly _WALStore = new ResolveOnce<WALStore>();
2976
+ // async WALStore(): Promise<WALStore> {
2977
+ // return this._WALStore.once(async () =>
2978
+ // this.ebOpts.storeRuntime.makeWALStore({
2979
+ // // sthis: this.sthis,
2980
+ // gatewayInterceptor: this.ebOpts.gatewayInterceptor,
2981
+ // url: this.ebOpts.storeUrls.wal,
2982
+ // // keybag: await this.keyBag(),
2983
+ // loader: this,
2984
+ // }),
2985
+ // );
2986
+ // }
2987
+ // private readonly _metaStore = new ResolveOnce<MetaStore>();
2988
+ // async metaStore(): Promise<MetaStore> {
2989
+ // return this._metaStore.once(async () =>
2990
+ // this.ebOpts.storeRuntime.makeMetaStore({
2991
+ // // sthis: this.sthis,
2992
+ // gatewayInterceptor: this.ebOpts.gatewayInterceptor,
2993
+ // url: this.ebOpts.storeUrls.meta,
2994
+ // // keybag: await this.keyBag(),
2995
+ // loader: this,
2996
+ // }),
2997
+ // );
2998
+ // }
2753
2999
  keyBag() {
2754
3000
  return getKeyBag(this.sthis, this.ebOpts.keyBag);
2755
3001
  }
2756
3002
  async ready() {
2757
3003
  return this.onceReady.once(async () => {
2758
- const metas = await (await this.metaStore()).load();
3004
+ await createAttachedStores(
3005
+ {
3006
+ car: { url: this.ebOpts.storeUrls.car, gatewayInterceptor: this.ebOpts.gatewayInterceptor },
3007
+ file: { url: this.ebOpts.storeUrls.file, gatewayInterceptor: this.ebOpts.gatewayInterceptor },
3008
+ meta: { url: this.ebOpts.storeUrls.meta, gatewayInterceptor: this.ebOpts.gatewayInterceptor },
3009
+ wal: { url: this.ebOpts.storeUrls.wal, gatewayInterceptor: this.ebOpts.gatewayInterceptor }
3010
+ },
3011
+ this.attachedStores
3012
+ );
3013
+ const local = this.attachedStores.local();
3014
+ const metas = await local.active.meta.load();
2759
3015
  if (this.ebOpts.meta) {
2760
- await this.handleDbMetasFromStore([this.ebOpts.meta]);
3016
+ await this.handleDbMetasFromStore([this.ebOpts.meta, ...metas || []], local);
2761
3017
  } else if (metas) {
2762
- await this.handleDbMetasFromStore(metas);
3018
+ await this.handleDbMetasFromStore(metas, local);
2763
3019
  }
2764
3020
  });
2765
3021
  }
2766
3022
  async close() {
2767
3023
  await this.commitQueue.waitIdle();
2768
- const toClose = await Promise.all([this.carStore(), this.metaStore(), this.fileStore(), this.WALStore()]);
2769
- await Promise.all(toClose.map((store) => store.close()));
3024
+ await this.attachedStores.detach();
2770
3025
  }
2771
3026
  async destroy() {
2772
- const toDestroy = await Promise.all([this.carStore(), this.metaStore(), this.fileStore(), this.WALStore()]);
2773
- await Promise.all(toDestroy.map((store) => store.destroy()));
3027
+ await Promise.all(
3028
+ this.attachedStores.local().baseStores().map((store) => store.destroy())
3029
+ );
2774
3030
  }
2775
3031
  // async snapToCar(carCid: AnyLink | string) {
2776
3032
  // await this.ready
@@ -2782,15 +3038,15 @@ var Loader = class {
2782
3038
  // await this.getMoreReaders(carHeader.cars)
2783
3039
  // await this._applyCarHeader(carHeader, true)
2784
3040
  // }
2785
- async handleDbMetasFromStore(metas) {
3041
+ async handleDbMetasFromStore(metas, activeStore) {
2786
3042
  this.logger.Debug().Any("metas", metas).Msg("handleDbMetasFromStore");
2787
3043
  for (const meta of metas) {
2788
3044
  await this.writeLimit(async () => {
2789
- await this.mergeDbMetaIntoClock(meta);
3045
+ await this.mergeDbMetaIntoClock(meta, activeStore);
2790
3046
  });
2791
3047
  }
2792
3048
  }
2793
- async mergeDbMetaIntoClock(meta) {
3049
+ async mergeDbMetaIntoClock(meta, activeStore) {
2794
3050
  if (this.isCompacting) {
2795
3051
  throw this.logger.Error().Msg("cannot merge while compacting").AsError();
2796
3052
  }
@@ -2799,9 +3055,9 @@ var Loader = class {
2799
3055
  if (carLogIncludesGroup(this.carLog, meta.cars)) {
2800
3056
  return;
2801
3057
  }
2802
- const carHeader = await this.loadCarHeaderFromMeta(meta);
3058
+ const carHeader = await this.loadCarHeaderFromMeta(meta, activeStore);
2803
3059
  carHeader.compact.map((c) => c.toString()).forEach(this.seenCompacted.add, this.seenCompacted);
2804
- await this.getMoreReaders(carHeader.cars.flat());
3060
+ await this.getMoreReaders(carHeader.cars.flat(), activeStore);
2805
3061
  this.carLog = [...uniqueCids([meta.cars, ...this.carLog, ...carHeader.cars], this.seenCompacted)];
2806
3062
  await this.ebOpts.applyMeta?.(carHeader.meta);
2807
3063
  }
@@ -2811,8 +3067,8 @@ var Loader = class {
2811
3067
  // await this.setKey(key);
2812
3068
  // }
2813
3069
  // }
2814
- async loadCarHeaderFromMeta({ cars: cids }) {
2815
- const reader = await this.loadCar(cids[0]);
3070
+ async loadCarHeaderFromMeta(dbm, astore) {
3071
+ const reader = await this.loadCar(dbm.cars[0], astore);
2816
3072
  return await parseCarFile(reader, this.logger);
2817
3073
  }
2818
3074
  // async _getKey(): Promise<string | undefined> {
@@ -2825,22 +3081,22 @@ var Loader = class {
2825
3081
  // }
2826
3082
  async commitFiles(t, done) {
2827
3083
  await this.ready();
2828
- const fstore = await this.fileStore();
2829
- const wstore = await this.WALStore();
3084
+ const fstore = this.attachedStores.local().active.file;
3085
+ const wstore = this.attachedStores.local().active.wal;
2830
3086
  return this.commitQueue.enqueue(() => commitFiles(fstore, wstore, t, done));
2831
3087
  }
2832
- async loadFileCar(cid) {
2833
- return await this.storesLoadCar(cid, await this.fileStore(), this.remoteFileStore);
3088
+ async loadFileCar(cid, store) {
3089
+ return await this.storesLoadCar(cid, store.fileStore());
2834
3090
  }
2835
3091
  async commit(t, done, opts = { noLoader: false, compact: false }) {
2836
3092
  await this.ready();
2837
- const carStore = await this.carStore();
3093
+ const carStore = await this.attachedStores.local().active.car;
2838
3094
  const params = {
2839
3095
  encoder: (await carStore.keyedCrypto()).codec(),
2840
3096
  carLog: this.carLog,
2841
3097
  carStore,
2842
- WALStore: await this.WALStore(),
2843
- metaStore: await this.metaStore(),
3098
+ WALStore: await this.attachedStores.local().active.wal,
3099
+ metaStore: await this.attachedStores.local().active.meta,
2844
3100
  threshold: this.ebOpts.threshold
2845
3101
  };
2846
3102
  return this.commitQueue.enqueue(async () => {
@@ -2855,7 +3111,7 @@ var Loader = class {
2855
3111
  const previousCompactCid = fp.compact[fp.compact.length - 1];
2856
3112
  fp.compact.map((c) => c.toString()).forEach(this.seenCompacted.add, this.seenCompacted);
2857
3113
  this.carLog = [...uniqueCids([...this.carLog, ...fp.cars, cids], this.seenCompacted)];
2858
- await this.removeCidsForCompact(previousCompactCid[0]).catch((e) => e);
3114
+ await this.removeCidsForCompact(previousCompactCid[0], this.attachedStores.local()).catch((e) => e);
2859
3115
  } else {
2860
3116
  this.carLog.unshift(cids);
2861
3117
  }
@@ -2878,13 +3134,16 @@ var Loader = class {
2878
3134
  }
2879
3135
  }
2880
3136
  }
2881
- async removeCidsForCompact(cid) {
2882
- const carHeader = await this.loadCarHeaderFromMeta({
2883
- cars: [cid]
2884
- });
3137
+ async removeCidsForCompact(cid, store) {
3138
+ const carHeader = await this.loadCarHeaderFromMeta(
3139
+ {
3140
+ cars: [cid]
3141
+ },
3142
+ store
3143
+ );
2885
3144
  for (const cids of carHeader.compact) {
2886
3145
  for (const cid2 of cids) {
2887
- await (await this.carStore()).remove(cid2);
3146
+ await this.attachedStores.local().active.car.remove(cid2);
2888
3147
  }
2889
3148
  }
2890
3149
  }
@@ -2908,7 +3167,7 @@ var Loader = class {
2908
3167
  }
2909
3168
  for (const cids of this.carLog) {
2910
3169
  for (const cid of cids) {
2911
- const reader = await this.loadCar(cid);
3170
+ const reader = await this.loadCar(cid, this.attachedStores.local());
2912
3171
  if (!reader) throw this.logger.Error().Ref("cid", cid).Msg("missing car reader").AsError();
2913
3172
  for await (const block of reader.blocks()) {
2914
3173
  const sCid = block.cid.toString();
@@ -2920,13 +3179,13 @@ var Loader = class {
2920
3179
  }
2921
3180
  }
2922
3181
  }
2923
- async getBlock(cid) {
3182
+ async getBlock(cid, store) {
2924
3183
  await this.ready();
2925
3184
  const sCid = cid.toString();
2926
3185
  if (this.getBlockCache.has(sCid)) return this.getBlockCache.get(sCid);
2927
3186
  const getCarCid = async (carCid) => {
2928
3187
  if (this.getBlockCache.has(sCid)) return this.getBlockCache.get(sCid);
2929
- const reader = await this.loadCar(carCid);
3188
+ const reader = await this.loadCar(carCid, store);
2930
3189
  if (!reader) {
2931
3190
  throw this.logger.Error().Ref("cid", carCid).Msg("missing car reader").AsError();
2932
3191
  }
@@ -2937,7 +3196,7 @@ var Loader = class {
2937
3196
  throw this.logger.Error().Str("cid", sCid).Msg("block not in reader").AsError();
2938
3197
  };
2939
3198
  const getCompactCarCids = async (carCid) => {
2940
- const reader = await this.loadCar(carCid);
3199
+ const reader = await this.loadCar(carCid, store);
2941
3200
  if (!reader) {
2942
3201
  throw this.logger.Error().Str("cid", carCid.toString()).Msg("missing car reader").AsError();
2943
3202
  }
@@ -2980,36 +3239,37 @@ var Loader = class {
2980
3239
  }
2981
3240
  return got;
2982
3241
  }
2983
- async loadCar(cid) {
2984
- if (!this.carStore) {
2985
- throw this.logger.Error().Msg("car store not initialized").AsError();
2986
- }
2987
- const loaded = await this.storesLoadCar(cid, await this.carStore(), this.remoteCarStore);
3242
+ async loadCar(cid, store) {
3243
+ const loaded = await this.storesLoadCar(cid, store.carStore());
2988
3244
  return loaded;
2989
3245
  }
2990
- async makeDecoderAndCarReader(cid, local, remote) {
3246
+ async makeDecoderAndCarReader(cid, store) {
2991
3247
  const cidsString = cid.toString();
2992
3248
  let loadedCar = void 0;
2993
- let activeStore = local;
3249
+ let activeStore = store.attached.local();
2994
3250
  try {
2995
3251
  this.logger.Debug().Any("cid", cidsString).Msg("loading car");
2996
- loadedCar = await local.load(cid);
3252
+ loadedCar = await store.attached.local().load(cid);
2997
3253
  this.logger.Debug().Bool("loadedCar", loadedCar).Msg("loaded");
2998
3254
  } catch (e) {
2999
- if (remote) {
3255
+ if (!isNotFoundError(e)) {
3256
+ throw this.logger.Error().Str("cid", cidsString).Err(e).Msg("loading car");
3257
+ }
3258
+ for (const remote of store.attached.remotes()) {
3000
3259
  const remoteCar = await remote.load(cid);
3001
3260
  if (remoteCar) {
3002
3261
  this.logger.Debug().Ref("cid", remoteCar.cid).Msg("saving remote car locally");
3003
- await local.save(remoteCar);
3262
+ await store.attached.local().save(remoteCar);
3004
3263
  loadedCar = remoteCar;
3005
3264
  activeStore = remote;
3265
+ break;
3266
+ } else {
3267
+ this.logger.Error().Str("cid", cidsString).Err(e).Msg("loading car");
3006
3268
  }
3007
- } else {
3008
- this.logger.Error().Str("cid", cidsString).Err(e).Msg("loading car");
3009
3269
  }
3010
3270
  }
3011
3271
  if (!loadedCar) {
3012
- throw this.logger.Error().Url(local.url()).Str("cid", cidsString).Msg("missing car files").AsError();
3272
+ throw this.logger.Error().Url(store.attached.local().url()).Str("cid", cidsString).Msg("missing car files").AsError();
3013
3273
  }
3014
3274
  const bytes = await decode({ bytes: loadedCar.bytes, hasher: import_sha24.sha256, codec: (await activeStore.keyedCrypto()).codec() });
3015
3275
  const rawReader = await import_reader.CarReader.fromBytes(bytes.value);
@@ -3025,19 +3285,19 @@ var Loader = class {
3025
3285
  return readerP;
3026
3286
  }
3027
3287
  //What if instead it returns an Array of CarHeader
3028
- async storesLoadCar(cid, local, remote) {
3288
+ async storesLoadCar(cid, store) {
3029
3289
  const cidsString = cid.toString();
3030
3290
  let dacr = this.carReaders.get(cidsString);
3031
3291
  if (!dacr) {
3032
- dacr = this.makeDecoderAndCarReader(cid, local, remote);
3292
+ dacr = this.makeDecoderAndCarReader(cid, store);
3033
3293
  this.carReaders.set(cidsString, dacr);
3034
3294
  }
3035
3295
  return dacr;
3036
3296
  }
3037
- async getMoreReaders(cids) {
3297
+ async getMoreReaders(cids, store) {
3038
3298
  const limit = (0, import_p_limit.default)(5);
3039
3299
  const missing = cids.filter((cid) => !this.carReaders.has(cid.toString()));
3040
- await Promise.all(missing.map((cid) => limit(() => this.loadCar(cid))));
3300
+ await Promise.all(missing.map((cid) => limit(() => this.loadCar(cid, store))));
3041
3301
  }
3042
3302
  };
3043
3303
 
@@ -3232,39 +3492,39 @@ var import_p_retry = __toESM(require("p-retry"), 1);
3232
3492
  var import_p_map = __toESM(require("p-map"), 1);
3233
3493
 
3234
3494
  // src/blockstore/interceptor-gateway.ts
3235
- var import_cement14 = require("@adviser/cement");
3495
+ var import_cement15 = require("@adviser/cement");
3236
3496
  var PassThroughGateway = class {
3237
3497
  async buildUrl(ctx, url, key) {
3238
3498
  const op = { url, key };
3239
- return import_cement14.Result.Ok({ op });
3499
+ return import_cement15.Result.Ok({ op });
3240
3500
  }
3241
3501
  async start(ctx, url) {
3242
3502
  const op = { url };
3243
- return import_cement14.Result.Ok({ op });
3503
+ return import_cement15.Result.Ok({ op });
3244
3504
  }
3245
3505
  async close(ctx, url) {
3246
3506
  const op = { url };
3247
- return import_cement14.Result.Ok({ op });
3507
+ return import_cement15.Result.Ok({ op });
3248
3508
  }
3249
3509
  async delete(ctx, url) {
3250
3510
  const op = { url };
3251
- return import_cement14.Result.Ok({ op });
3511
+ return import_cement15.Result.Ok({ op });
3252
3512
  }
3253
3513
  async destroy(ctx, url) {
3254
3514
  const op = { url };
3255
- return import_cement14.Result.Ok({ op });
3515
+ return import_cement15.Result.Ok({ op });
3256
3516
  }
3257
3517
  async put(ctx, url, body) {
3258
3518
  const op = { url, body };
3259
- return import_cement14.Result.Ok({ op });
3519
+ return import_cement15.Result.Ok({ op });
3260
3520
  }
3261
3521
  async get(ctx, url) {
3262
3522
  const op = { url };
3263
- return import_cement14.Result.Ok({ op });
3523
+ return import_cement15.Result.Ok({ op });
3264
3524
  }
3265
3525
  async subscribe(ctx, url, callback) {
3266
3526
  const op = { url, callback };
3267
- return import_cement14.Result.Ok({ op });
3527
+ return import_cement15.Result.Ok({ op });
3268
3528
  }
3269
3529
  };
3270
3530
  var passThrougthGateway = new PassThroughGateway();
@@ -3276,7 +3536,7 @@ var InterceptorGateway = class {
3276
3536
  async buildUrl(ctx, baseUrl, key) {
3277
3537
  const rret = await this.interceptor.buildUrl(ctx, baseUrl, key);
3278
3538
  if (rret.isErr()) {
3279
- return import_cement14.Result.Err(rret.Err());
3539
+ return import_cement15.Result.Err(rret.Err());
3280
3540
  }
3281
3541
  const ret = rret.unwrap();
3282
3542
  if (ret.stop && ret.value) {
@@ -3287,7 +3547,7 @@ var InterceptorGateway = class {
3287
3547
  async destroy(ctx, iurl) {
3288
3548
  const rret = await this.interceptor.destroy(ctx, iurl);
3289
3549
  if (rret.isErr()) {
3290
- return import_cement14.Result.Err(rret.Err());
3550
+ return import_cement15.Result.Err(rret.Err());
3291
3551
  }
3292
3552
  const ret = rret.unwrap();
3293
3553
  if (ret.stop && ret.value) {
@@ -3298,7 +3558,7 @@ var InterceptorGateway = class {
3298
3558
  async start(ctx, url) {
3299
3559
  const rret = await this.interceptor.start(ctx, url);
3300
3560
  if (rret.isErr()) {
3301
- return import_cement14.Result.Err(rret.Err());
3561
+ return import_cement15.Result.Err(rret.Err());
3302
3562
  }
3303
3563
  const ret = rret.unwrap();
3304
3564
  if (ret.stop && ret.value) {
@@ -3309,7 +3569,7 @@ var InterceptorGateway = class {
3309
3569
  async close(ctx, url) {
3310
3570
  const rret = await this.interceptor.close(ctx, url);
3311
3571
  if (rret.isErr()) {
3312
- return import_cement14.Result.Err(rret.Err());
3572
+ return import_cement15.Result.Err(rret.Err());
3313
3573
  }
3314
3574
  const ret = rret.unwrap();
3315
3575
  if (ret.stop && ret.value) {
@@ -3320,7 +3580,7 @@ var InterceptorGateway = class {
3320
3580
  async put(ctx, url, fpEnv) {
3321
3581
  const rret = await this.interceptor.put(ctx, url, fpEnv);
3322
3582
  if (rret.isErr()) {
3323
- return import_cement14.Result.Err(rret.Err());
3583
+ return import_cement15.Result.Err(rret.Err());
3324
3584
  }
3325
3585
  const ret = rret.unwrap();
3326
3586
  if (ret.stop && ret.value) {
@@ -3331,7 +3591,7 @@ var InterceptorGateway = class {
3331
3591
  async get(ctx, url) {
3332
3592
  const rret = await this.interceptor.get(ctx, url);
3333
3593
  if (rret.isErr()) {
3334
- return import_cement14.Result.Err(rret.Err());
3594
+ return import_cement15.Result.Err(rret.Err());
3335
3595
  }
3336
3596
  const ret = rret.unwrap();
3337
3597
  if (ret.stop && ret.value) {
@@ -3341,11 +3601,11 @@ var InterceptorGateway = class {
3341
3601
  }
3342
3602
  async subscribe(ctx, url, callback) {
3343
3603
  if (!this.innerGW.subscribe) {
3344
- return import_cement14.Result.Err(ctx.loader.sthis.logger.Error().Url(url).Msg("subscribe not supported").AsError());
3604
+ return import_cement15.Result.Err(ctx.loader.sthis.logger.Error().Url(url).Msg("subscribe not supported").AsError());
3345
3605
  }
3346
3606
  const rret = await this.interceptor.subscribe(ctx, url, callback);
3347
3607
  if (rret.isErr()) {
3348
- return import_cement14.Result.Err(rret.Err());
3608
+ return import_cement15.Result.Err(rret.Err());
3349
3609
  }
3350
3610
  const ret = rret.unwrap();
3351
3611
  if (ret.stop && ret.value) {
@@ -3356,7 +3616,7 @@ var InterceptorGateway = class {
3356
3616
  async delete(ctx, url) {
3357
3617
  const rret = await this.interceptor.delete(ctx, url);
3358
3618
  if (rret.isErr()) {
3359
- return import_cement14.Result.Err(rret.Err());
3619
+ return import_cement15.Result.Err(rret.Err());
3360
3620
  }
3361
3621
  const ret = rret.unwrap();
3362
3622
  if (ret.stop && ret.value) {
@@ -3372,9 +3632,9 @@ var InterceptorGateway = class {
3372
3632
  // src/blockstore/store.ts
3373
3633
  function guardVersion(url) {
3374
3634
  if (!url.hasParam("version")) {
3375
- return import_cement15.Result.Err(`missing version: ${url.toString()}`);
3635
+ return import_cement16.Result.Err(`missing version: ${url.toString()}`);
3376
3636
  }
3377
- return import_cement15.Result.Ok(url);
3637
+ return import_cement16.Result.Ok(url);
3378
3638
  }
3379
3639
  var BaseStoreImpl = class {
3380
3640
  // readonly loader: Loadable;
@@ -3408,7 +3668,7 @@ var BaseStoreImpl = class {
3408
3668
  async keyedCrypto() {
3409
3669
  return keyedCryptoFactory(this._url, await this.loader.keyBag(), this.sthis);
3410
3670
  }
3411
- async start() {
3671
+ async start(dam) {
3412
3672
  this.logger.Debug().Str("storeType", this.storeType).Msg("starting-gateway-pre");
3413
3673
  this._url = this._url.build().setParam(PARAM.STORE, this.storeType).URI();
3414
3674
  const res = await this.gateway.start({ loader: this.loader }, this._url);
@@ -3439,13 +3699,13 @@ var BaseStoreImpl = class {
3439
3699
  }
3440
3700
  if (this.ready) {
3441
3701
  const fn = this.ready.bind(this);
3442
- const ready = await (0, import_cement15.exception2Result)(fn);
3702
+ const ready = await (0, import_cement16.exception2Result)(fn);
3443
3703
  if (ready.isErr()) {
3444
3704
  await this.close();
3445
3705
  return ready;
3446
3706
  }
3447
3707
  }
3448
- this._onStarted.forEach((fn) => fn());
3708
+ this._onStarted.forEach((fn) => fn(dam));
3449
3709
  this.logger.Debug().Msg("started");
3450
3710
  return version;
3451
3711
  }
@@ -3474,12 +3734,19 @@ var MetaStoreImpl = class extends BaseStoreImpl {
3474
3734
  /*this.remote && */
3475
3735
  opts.gateway.subscribe
3476
3736
  ) {
3477
- this.onStarted(async () => {
3737
+ this.onStarted(async (dam) => {
3478
3738
  this.logger.Debug().Str("url", this.url().toString()).Msg("Subscribing to the gateway");
3479
3739
  opts.gateway.subscribe({ loader: this.loader }, this.url(), async ({ payload: dbMetas }) => {
3480
3740
  this.logger.Debug().Msg("Received message from gateway");
3481
3741
  await Promise.all(
3482
- dbMetas.map((dbMeta) => this.loader.taskManager?.handleEvent(dbMeta.eventCid, dbMeta.parents, dbMeta.dbMeta))
3742
+ dbMetas.map(
3743
+ (dbMetaEv) => this.loader.taskManager?.handleEvent(
3744
+ dbMetaEv.eventCid,
3745
+ dbMetaEv.parents,
3746
+ dbMetaEv.dbMeta,
3747
+ this.loader.attachedStores.activate(dam)
3748
+ )
3749
+ )
3483
3750
  );
3484
3751
  this.updateParentsFromDbMetas(dbMetas);
3485
3752
  });
@@ -3514,10 +3781,11 @@ var MetaStoreImpl = class extends BaseStoreImpl {
3514
3781
  }
3515
3782
  throw this.logger.Error().Url(url.Ok()).Err(rfpEnv).Msg("gateway get").AsError();
3516
3783
  }
3517
- const dbMetas = rfpEnv.Ok().payload;
3518
- await this.loader.handleDbMetasFromStore(dbMetas.map((m) => m.dbMeta));
3519
- this.updateParentsFromDbMetas(dbMetas);
3520
- return dbMetas.map((m) => m.dbMeta);
3784
+ const fpMeta = rfpEnv.Ok().payload;
3785
+ const dbMetas = fpMeta.map((m) => m.dbMeta);
3786
+ await this.loader.handleDbMetasFromStore(dbMetas, this.loader.attachedStores.local());
3787
+ this.updateParentsFromDbMetas(fpMeta);
3788
+ return dbMetas;
3521
3789
  }
3522
3790
  async save(meta, branch) {
3523
3791
  branch = branch || "main";
@@ -3539,7 +3807,7 @@ var MetaStoreImpl = class extends BaseStoreImpl {
3539
3807
  async close() {
3540
3808
  await this.gateway.close({ loader: this.loader }, this.url());
3541
3809
  this._onClosed.forEach((fn) => fn());
3542
- return import_cement15.Result.Ok(void 0);
3810
+ return import_cement16.Result.Ok(void 0);
3543
3811
  }
3544
3812
  async destroy() {
3545
3813
  this.logger.Debug().Msg("destroy");
@@ -3609,7 +3877,7 @@ var DataStoreImpl = class extends BaseStoreImpl {
3609
3877
  async close() {
3610
3878
  await this.gateway.close({ loader: this.loader }, this.url());
3611
3879
  this._onClosed.forEach((fn) => fn());
3612
- return import_cement15.Result.Ok(void 0);
3880
+ return import_cement16.Result.Ok(void 0);
3613
3881
  }
3614
3882
  destroy() {
3615
3883
  this.logger.Debug().Msg("destroy");
@@ -3622,7 +3890,7 @@ var WALStoreImpl = class extends BaseStoreImpl {
3622
3890
  this.storeType = "wal";
3623
3891
  // readonly tag: string = "rwal-base";
3624
3892
  // readonly loader: Loadable;
3625
- this._ready = new import_cement15.ResolveOnce();
3893
+ this._ready = new import_cement16.ResolveOnce();
3626
3894
  this.walState = { operations: [], noLoaderOps: [], fileOperations: [] };
3627
3895
  this.processing = void 0;
3628
3896
  this.processQueue = new CommitQueue();
@@ -3663,7 +3931,6 @@ var WALStoreImpl = class extends BaseStoreImpl {
3663
3931
  }
3664
3932
  async process() {
3665
3933
  await this.ready();
3666
- if (!this.loader.remoteCarStore) return;
3667
3934
  await this.processQueue.enqueue(async () => {
3668
3935
  try {
3669
3936
  await this._doProcess();
@@ -3677,7 +3944,6 @@ var WALStoreImpl = class extends BaseStoreImpl {
3677
3944
  }
3678
3945
  async _doProcess() {
3679
3946
  if (!this.loader) return;
3680
- if (!this.loader.remoteCarStore) return;
3681
3947
  const operations = [...this.walState.operations];
3682
3948
  const noLoaderOps = [...this.walState.noLoaderOps];
3683
3949
  const fileOperations = [...this.walState.fileOperations];
@@ -3698,13 +3964,13 @@ var WALStoreImpl = class extends BaseStoreImpl {
3698
3964
  return;
3699
3965
  }
3700
3966
  for (const cid of dbMeta.cars) {
3701
- const car = await (await this.loader.carStore()).load(cid);
3967
+ const car = await this.loader.attachedStores.local().active.car.load(cid);
3702
3968
  if (!car) {
3703
3969
  if (carLogIncludesGroup(this.loader.carLog, dbMeta.cars)) {
3704
3970
  throw this.logger.Error().Ref("cid", cid).Msg("missing local car").AsError();
3705
3971
  }
3706
3972
  } else {
3707
- await throwFalsy(this.loader.remoteCarStore).save(car);
3973
+ await this.loader.attachedStores.forRemotes((x) => x.active.car.save(car));
3708
3974
  }
3709
3975
  }
3710
3976
  inplaceFilter(this.walState.noLoaderOps, (op) => op !== dbMeta);
@@ -3720,13 +3986,13 @@ var WALStoreImpl = class extends BaseStoreImpl {
3720
3986
  return;
3721
3987
  }
3722
3988
  for (const cid of dbMeta.cars) {
3723
- const car = await (await this.loader.carStore()).load(cid);
3989
+ const car = await this.loader.attachedStores.local().active.car.load(cid);
3724
3990
  if (!car) {
3725
3991
  if (carLogIncludesGroup(this.loader.carLog, dbMeta.cars)) {
3726
3992
  throw this.logger.Error().Ref("cid", cid).Msg(`missing local car`).AsError();
3727
3993
  }
3728
3994
  } else {
3729
- await throwFalsy(this.loader.remoteCarStore).save(car);
3995
+ await this.loader.attachedStores.forRemotes((x) => x.active.car.save(car));
3730
3996
  }
3731
3997
  }
3732
3998
  inplaceFilter(this.walState.operations, (op) => op !== dbMeta);
@@ -3741,11 +4007,11 @@ var WALStoreImpl = class extends BaseStoreImpl {
3741
4007
  if (!this.loader) {
3742
4008
  return;
3743
4009
  }
3744
- const fileBlock = await (await this.loader.fileStore()).load(fileCid);
4010
+ const fileBlock = await this.loader.attachedStores.local().active.file.load(fileCid);
3745
4011
  if (!fileBlock) {
3746
4012
  throw this.logger.Error().Ref("cid", fileCid).Msg("missing file block").AsError();
3747
4013
  }
3748
- await this.loader.remoteFileStore?.save(fileBlock, { public: publicFile });
4014
+ await this.loader.attachedStores.forRemotes((x) => x.active.file.save(fileBlock, { public: publicFile }));
3749
4015
  inplaceFilter(this.walState.fileOperations, (op) => op.cid !== fileCid);
3750
4016
  }, `fileOperation with cid=${fileCid.toString()}`);
3751
4017
  },
@@ -3757,7 +4023,7 @@ var WALStoreImpl = class extends BaseStoreImpl {
3757
4023
  if (!this.loader) {
3758
4024
  return;
3759
4025
  }
3760
- await this.loader.remoteMetaStore?.save(lastOp);
4026
+ await this.loader.attachedStores.forRemotes((x) => x.active.meta.save(lastOp));
3761
4027
  }, `remoteMetaStore save with dbMeta.cars=${lastOp.cars.toString()}`);
3762
4028
  }
3763
4029
  } catch (error) {
@@ -3801,7 +4067,7 @@ var WALStoreImpl = class extends BaseStoreImpl {
3801
4067
  async close() {
3802
4068
  await this.gateway.close({ loader: this.loader }, this.url());
3803
4069
  this._onClosed.forEach((fn) => fn());
3804
- return import_cement15.Result.Ok(void 0);
4070
+ return import_cement16.Result.Ok(void 0);
3805
4071
  }
3806
4072
  destroy() {
3807
4073
  this.logger.Debug().Msg("destroy");
@@ -3810,8 +4076,8 @@ var WALStoreImpl = class extends BaseStoreImpl {
3810
4076
  };
3811
4077
 
3812
4078
  // src/blockstore/store-factory.ts
3813
- var onceGateway = new import_cement16.KeyedResolvOnce();
3814
- var gatewayInstances = new import_cement16.KeyedResolvOnce();
4079
+ var onceGateway = new import_cement17.KeyedResolvOnce();
4080
+ var gatewayInstances = new import_cement17.KeyedResolvOnce();
3815
4081
  async function getStartedGateway(ctx, url) {
3816
4082
  return onceGateway.get(url.toString()).once(async () => {
3817
4083
  const item = getGatewayFactoryItem(url.protocol);
@@ -3823,58 +4089,58 @@ async function getStartedGateway(ctx, url) {
3823
4089
  };
3824
4090
  const res = await ret.gateway.start(ctx, url);
3825
4091
  if (res.isErr()) {
3826
- return import_cement16.Result.Err(ctx.loader.sthis.logger.Error().Result("start", res).Msg("start failed").AsError());
4092
+ return import_cement17.Result.Err(ctx.loader.sthis.logger.Error().Result("start", res).Msg("start failed").AsError());
3827
4093
  }
3828
4094
  ret.url = res.Ok();
3829
- return import_cement16.Result.Ok(ret);
4095
+ return import_cement17.Result.Ok(ret);
3830
4096
  }
3831
- return import_cement16.Result.Err(ctx.loader.sthis.logger.Warn().Url(url).Msg("unsupported protocol").AsError());
4097
+ return import_cement17.Result.Err(ctx.loader.sthis.logger.Warn().Url(url).Msg("unsupported protocol").AsError());
3832
4098
  });
3833
4099
  }
3834
- async function dataStoreFactory(sfi) {
3835
- const storeUrl = sfi.url.build().setParam(PARAM.STORE, "data").URI();
3836
- const rgateway = await getStartedGateway(sfi, storeUrl);
4100
+ async function dataStoreFactory(ctx, uai) {
4101
+ const storeUrl = uai.url.build().setParam(PARAM.STORE, "data").URI();
4102
+ const rgateway = await getStartedGateway(ctx, storeUrl);
3837
4103
  if (rgateway.isErr()) {
3838
- throw sfi.loader.sthis.logger.Error().Result("err", rgateway).Url(sfi.url).Msg("notfound").AsError();
4104
+ throw ctx.loader.sthis.logger.Error().Result("err", rgateway).Url(uai.url).Msg("notfound").AsError();
3839
4105
  }
3840
4106
  const gateway = rgateway.Ok();
3841
- const store = new DataStoreImpl(sfi.loader.sthis, gateway.url, {
4107
+ const store = new DataStoreImpl(ctx.loader.sthis, gateway.url, {
3842
4108
  gateway: gateway.gateway,
3843
- gatewayInterceptor: sfi.gatewayInterceptor,
3844
- loader: sfi.loader
4109
+ gatewayInterceptor: uai.gatewayInterceptor,
4110
+ loader: ctx.loader
3845
4111
  });
3846
4112
  return store;
3847
4113
  }
3848
- async function metaStoreFactory(sfi) {
3849
- const storeUrl = sfi.url.build().setParam(PARAM.STORE, "meta").URI();
3850
- const rgateway = await getStartedGateway(sfi, storeUrl);
4114
+ async function metaStoreFactory(ctx, uai) {
4115
+ const storeUrl = uai.url.build().setParam(PARAM.STORE, "meta").URI();
4116
+ const rgateway = await getStartedGateway(ctx, storeUrl);
3851
4117
  if (rgateway.isErr()) {
3852
- throw sfi.loader.sthis.logger.Error().Result("err", rgateway).Url(sfi.url).Msg("notfound").AsError();
4118
+ throw ctx.loader.sthis.logger.Error().Result("err", rgateway).Url(uai.url).Msg("notfound").AsError();
3853
4119
  }
3854
4120
  const gateway = rgateway.Ok();
3855
- const store = new MetaStoreImpl(sfi.loader.sthis, gateway.url, {
4121
+ const store = new MetaStoreImpl(ctx.loader.sthis, gateway.url, {
3856
4122
  gateway: gateway.gateway,
3857
- gatewayInterceptor: sfi.gatewayInterceptor,
3858
- loader: sfi.loader
4123
+ gatewayInterceptor: uai.gatewayInterceptor,
4124
+ loader: ctx.loader
3859
4125
  });
3860
4126
  return store;
3861
4127
  }
3862
- async function WALStoreFactory(sfi) {
3863
- const storeUrl = sfi.url.build().setParam(PARAM.STORE, "wal").URI();
3864
- const rgateway = await getStartedGateway(sfi, storeUrl);
4128
+ async function WALStoreFactory(ctx, uai) {
4129
+ const storeUrl = uai.url.build().setParam(PARAM.STORE, "wal").URI();
4130
+ const rgateway = await getStartedGateway(ctx, storeUrl);
3865
4131
  if (rgateway.isErr()) {
3866
- throw sfi.loader.sthis.logger.Error().Result("err", rgateway).Url(sfi.url).Msg("notfound").AsError();
4132
+ throw ctx.loader.sthis.logger.Error().Result("err", rgateway).Url(uai.url).Msg("notfound").AsError();
3867
4133
  }
3868
4134
  const gateway = rgateway.Ok();
3869
- const store = new WALStoreImpl(sfi.loader.sthis, gateway.url, {
4135
+ const store = new WALStoreImpl(ctx.loader.sthis, gateway.url, {
3870
4136
  gateway: gateway.gateway,
3871
- gatewayInterceptor: sfi.gatewayInterceptor,
3872
- loader: sfi.loader
4137
+ gatewayInterceptor: uai.gatewayInterceptor,
4138
+ loader: ctx.loader
3873
4139
  });
3874
4140
  return store;
3875
4141
  }
3876
- async function ensureStart(store) {
3877
- const ret = await store.start();
4142
+ async function ensureStart(store, damaw) {
4143
+ const ret = await store.start(damaw);
3878
4144
  if (ret.isErr()) {
3879
4145
  throw store.logger.Error().Result("start", ret).Msg("start failed").AsError();
3880
4146
  }
@@ -3890,191 +4156,32 @@ function ensureStoreEnDeFile(ende) {
3890
4156
  }
3891
4157
  function toStoreRuntime(sthis, endeOpts = {}) {
3892
4158
  return {
3893
- makeMetaStore: async (sfi) => ensureStart(await metaStoreFactory(sfi)),
3894
- // async (loader: Loadable) => {
3895
- // logger
3896
- // .Debug()
3897
- // .Str("fromOpts", "" + !!endeOpts.func?.makeMetaStore)
3898
- // .Msg("makeMetaStore");
3899
- // return ensureStart(await (endeOpts.func?.makeMetaStore || metaStoreFactory)(loader), logger);
3900
- // },
3901
- makeDataStore: async (sfi) => ensureStart(await dataStoreFactory(sfi)),
3902
- // async (loader: Loadable) => {
3903
- // logger
3904
- // .Debug()
3905
- // .Str("fromOpts", "" + !!endeOpts.func?.makeDataStore)
3906
- // .Msg("makeDataStore");
3907
- // return ensureStart(await (endeOpts.func?.makeDataStore || dataStoreFactory)(loader), logger);
3908
- // },
3909
- makeWALStore: async (sfi) => ensureStart(await WALStoreFactory(sfi)),
3910
- // async (loader: Loadable) => {
3911
- // logger
3912
- // .Debug()
3913
- // .Str("fromOpts", "" + !!endeOpts.func?.makeWALStore)
3914
- // .Msg("makeRemoteWAL");
3915
- // return ensureStart(await (endeOpts.func?.makeWALStore || remoteWalFactory)(loader), logger);
3916
- // },
4159
+ makeStores: async (sfi) => {
4160
+ const ctx = {
4161
+ loader: sfi.loader
4162
+ };
4163
+ const storeSet = {};
4164
+ storeSet.meta = await metaStoreFactory(ctx, sfi.byStore.meta);
4165
+ storeSet.car = await dataStoreFactory(ctx, sfi.byStore.car);
4166
+ storeSet.file = await dataStoreFactory(ctx, sfi.byStore.file);
4167
+ if (sfi.byStore.wal) {
4168
+ storeSet.wal = await WALStoreFactory(ctx, sfi.byStore.wal);
4169
+ }
4170
+ await ensureStart(storeSet.meta, storeSet);
4171
+ await ensureStart(storeSet.car, storeSet);
4172
+ await ensureStart(storeSet.file, storeSet);
4173
+ if (storeSet.wal) {
4174
+ await ensureStart(storeSet.wal, storeSet);
4175
+ }
4176
+ return storeSet;
4177
+ },
4178
+ // makeMetaStore: async (sfi: StoreFactoryItem) => ensureStart(await metaStoreFactory(sfi)),
4179
+ // makeDataStore: async (sfi: StoreFactoryItem) => ensureStart(await dataStoreFactory(sfi)),
4180
+ // makeWALStore: async (sfi: StoreFactoryItem) => ensureStart(await WALStoreFactory(sfi)),
3917
4181
  ...ensureStoreEnDeFile(endeOpts)
3918
4182
  };
3919
4183
  }
3920
4184
 
3921
- // src/blockstore/connection-base.ts
3922
- var import_cement17 = require("@adviser/cement");
3923
-
3924
- // src/blockstore/store-remote.ts
3925
- async function RemoteDataStore(sthis, url, opts) {
3926
- const ds = new DataStoreImpl(sthis, url, opts);
3927
- await ds.start();
3928
- return ds;
3929
- }
3930
- async function RemoteMetaStore(sthis, url, opts) {
3931
- const ms = new MetaStoreImpl(sthis, url, opts);
3932
- await ms.start();
3933
- return ms;
3934
- }
3935
-
3936
- // src/context.ts
3937
- var Context = class {
3938
- constructor() {
3939
- this.ctx = /* @__PURE__ */ new Map();
3940
- }
3941
- set(key, value) {
3942
- this.ctx.set(key, value);
3943
- }
3944
- get(key) {
3945
- return this.ctx.get(key);
3946
- }
3947
- delete(key) {
3948
- this.ctx.delete(key);
3949
- }
3950
- };
3951
-
3952
- // src/blockstore/connection-base.ts
3953
- function coerceLoader(ref) {
3954
- const refl = ref;
3955
- if (refl.loader) {
3956
- return refl.loader;
3957
- }
3958
- const refb = ref;
3959
- if (refb.blockstore) {
3960
- return coerceLoader(refb.blockstore);
3961
- }
3962
- return void 0;
3963
- }
3964
- var ConnectionBase = class {
3965
- constructor(url, logger) {
3966
- // loaded: Promise<void> = Promise.resolve();
3967
- this.context = new Context();
3968
- this._loaded = /* @__PURE__ */ new Set();
3969
- this._metaIsLoading = false;
3970
- this.logger = logger;
3971
- this.url = url;
3972
- }
3973
- loaded() {
3974
- const f = new import_cement17.Future();
3975
- if (!this._metaIsLoading) {
3976
- f.resolve();
3977
- } else {
3978
- this._loaded.add(f);
3979
- }
3980
- return f;
3981
- }
3982
- async refresh() {
3983
- await throwFalsy(throwFalsy(this.loader).remoteMetaStore).load();
3984
- await (await throwFalsy(this.loader).WALStore()).process();
3985
- }
3986
- async connect(refl) {
3987
- await this.connectMeta(refl);
3988
- await this.connectStorage(refl);
3989
- }
3990
- async connectMeta(refl) {
3991
- const loader = coerceLoader(refl);
3992
- if (!loader) throw this.logger.Error().Msg("connectMeta: loader is required").AsError();
3993
- this.loader = loader;
3994
- await this.onConnect();
3995
- const metaUrl = this.url.build().defParam(PARAM.STORE, "meta").URI();
3996
- const rgateway = await getStartedGateway({ loader }, metaUrl);
3997
- if (rgateway.isErr())
3998
- throw this.logger.Error().Result("err", rgateway).Url(metaUrl).Msg("connectMeta: gateway is required").AsError();
3999
- const dbName = metaUrl.getParam(PARAM.NAME);
4000
- if (!dbName) {
4001
- throw this.logger.Error().Url(metaUrl).Msg("connectMeta: dbName is required").AsError();
4002
- }
4003
- const gateway = rgateway.Ok();
4004
- const remote = await RemoteMetaStore(loader.sthis, metaUrl, {
4005
- gateway: gateway.gateway,
4006
- loader
4007
- });
4008
- this.loader.remoteMetaStore = remote;
4009
- this._metaIsLoading = true;
4010
- this.loader.ready().then(async () => {
4011
- return remote.load().then(async () => {
4012
- const res = await (0, import_cement17.exception2Result)(async () => {
4013
- return await (await throwFalsy(this.loader).WALStore()).process();
4014
- });
4015
- this._metaIsLoading = false;
4016
- for (const f of this._loaded) {
4017
- if (res.isErr()) {
4018
- f.reject(res.Err());
4019
- } else {
4020
- f.resolve();
4021
- }
4022
- }
4023
- this._loaded.clear();
4024
- });
4025
- });
4026
- }
4027
- async connectStorage(refl) {
4028
- const loader = coerceLoader(refl);
4029
- if (!loader) throw this.logger.Error().Msg("connectStorage: loader is required").AsError();
4030
- this.loader = loader;
4031
- const dataUrl = this.url.build().defParam(PARAM.STORE, "data").URI();
4032
- const rgateway = await getStartedGateway({ loader }, dataUrl);
4033
- if (rgateway.isErr())
4034
- throw this.logger.Error().Result("err", rgateway).Url(dataUrl).Msg("connectStorage: gateway is required").AsError();
4035
- const name = dataUrl.getParam(PARAM.NAME);
4036
- if (!name) throw this.logger.Error().Url(dataUrl).Msg("connectStorage: name is required").AsError;
4037
- loader.remoteCarStore = await RemoteDataStore(loader.sthis, this.url, {
4038
- gateway: rgateway.Ok().gateway,
4039
- loader
4040
- });
4041
- loader.remoteFileStore = loader.remoteCarStore;
4042
- }
4043
- // move this stuff to connect
4044
- // async getDashboardURL(compact = true) {
4045
- // const baseUrl = 'https://dashboard.fireproof.storage/'
4046
- // if (!this.loader?.remoteCarStore) return new URL('/howto', baseUrl)
4047
- // // if (compact) {
4048
- // // await this.compact()
4049
- // // }
4050
- // const currents = await this.loader?.metaStore?.load()
4051
- // if (!currents) throw new Error("Can't sync empty ledger: save data first")
4052
- // if (currents.length > 1)
4053
- // throw new Error("Can't sync ledger with split heads: make an update first")
4054
- // const current = currents[0]
4055
- // const params = {
4056
- // car: current.car.toString()
4057
- // }
4058
- // if (current.key) {
4059
- // // @ts-ignore
4060
- // params.key = current.key.toString()
4061
- // }
4062
- // // @ts-ignore
4063
- // if (this.name) {
4064
- // // @ts-ignore
4065
- // params.name = this.name
4066
- // }
4067
- // const url = new URL('/import#' + new URLSearchParams(params).toString(), baseUrl)
4068
- // console.log('Import to dashboard: ' + url.toString())
4069
- // return url
4070
- // }
4071
- // openDashboard() {
4072
- // void this.getDashboardURL().then(url => {
4073
- // if (url) window.open(url.toString(), '_blank')
4074
- // })
4075
- // }
4076
- };
4077
-
4078
4185
  // src/crdt-helpers.ts
4079
4186
  var import_link2 = require("multiformats/link");
4080
4187
  var import_sha26 = require("multiformats/hashes/sha2");
@@ -4649,6 +4756,22 @@ var CRDTImpl = class {
4649
4756
  }
4650
4757
  };
4651
4758
 
4759
+ // src/context.ts
4760
+ var Context = class {
4761
+ constructor() {
4762
+ this.ctx = /* @__PURE__ */ new Map();
4763
+ }
4764
+ set(key, value) {
4765
+ this.ctx.set(key, value);
4766
+ }
4767
+ get(key) {
4768
+ return this.ctx.get(key);
4769
+ }
4770
+ delete(key) {
4771
+ this.ctx.delete(key);
4772
+ }
4773
+ };
4774
+
4652
4775
  // src/ledger.ts
4653
4776
  var ledgers = new import_cement20.KeyedResolvOnce();
4654
4777
  function keyConfigOpts(sthis, name, opts) {
@@ -4693,6 +4816,9 @@ var LedgerShell = class {
4693
4816
  this.name = ref.name;
4694
4817
  ref.addShell(this);
4695
4818
  }
4819
+ attach(a) {
4820
+ return this.ref.attach(a);
4821
+ }
4696
4822
  get opts() {
4697
4823
  return this.ref.opts;
4698
4824
  }
@@ -4791,6 +4917,9 @@ var LedgerImpl = class {
4791
4917
  });
4792
4918
  return ret;
4793
4919
  }
4920
+ attach(a) {
4921
+ return this.crdt.blockstore.loader.attach(a);
4922
+ }
4794
4923
  // readonly _asDb = new ResolveOnce<Database>();
4795
4924
  // asDB(): Database {
4796
4925
  // return this._asDb.once(() => new DatabaseImpl(this));
@@ -4870,13 +4999,13 @@ function toStoreURIRuntime(sthis, name, sopts) {
4870
4999
  const base = import_cement20.URI.from(sopts.base);
4871
5000
  return {
4872
5001
  idx: {
4873
- data: defaultURI2(sthis, name, sopts.idx?.data, base, "data", { idx: true }),
5002
+ car: defaultURI2(sthis, name, sopts.idx?.data, base, "data", { idx: true }),
4874
5003
  file: defaultURI2(sthis, name, sopts.idx?.data, base, "data", { file: true, idx: true }),
4875
5004
  meta: defaultURI2(sthis, name, sopts.idx?.meta, base, "meta", { idx: true }),
4876
5005
  wal: defaultURI2(sthis, name, sopts.idx?.wal, base, "wal", { idx: true })
4877
5006
  },
4878
5007
  data: {
4879
- data: defaultURI2(sthis, name, sopts.data?.data, base, "data"),
5008
+ car: defaultURI2(sthis, name, sopts.data?.data, base, "data"),
4880
5009
  file: defaultURI2(sthis, name, sopts.data?.data, base, "data", { file: true }),
4881
5010
  meta: defaultURI2(sthis, name, sopts.data?.meta, base, "meta"),
4882
5011
  wal: defaultURI2(sthis, name, sopts.data?.wal, base, "wal")
@@ -4943,6 +5072,6 @@ __export(file_exports, {
4943
5072
 
4944
5073
  // src/version.ts
4945
5074
  var PACKAGE_VERSION = Object.keys({
4946
- "0.20.0-dev-preview-39": "xxxx"
5075
+ "0.20.0-dev-preview-41": "xxxx"
4947
5076
  })[0];
4948
5077
  //# sourceMappingURL=index.cjs.map