@fireproof/core 0.19.101 → 0.19.103

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 (61) hide show
  1. package/{chunk-3EB3ENHT.js → chunk-OFGPKRCM.js} +25 -54
  2. package/chunk-OFGPKRCM.js.map +1 -0
  3. package/chunk-WS3YRPIA.js +75 -0
  4. package/chunk-WS3YRPIA.js.map +1 -0
  5. package/{gateway-GK5QZ6KP.js → gateway-5FCWPX5W.js} +12 -13
  6. package/gateway-5FCWPX5W.js.map +1 -0
  7. package/{gateway-TQTGDRCN.js → gateway-H7UD6TNB.js} +8 -9
  8. package/gateway-H7UD6TNB.js.map +1 -0
  9. package/index.cjs +1571 -1992
  10. package/index.cjs.map +1 -1
  11. package/index.d.cts +117 -257
  12. package/index.d.ts +117 -257
  13. package/index.global.js +12280 -12741
  14. package/index.global.js.map +1 -1
  15. package/index.js +1463 -1790
  16. package/index.js.map +1 -1
  17. package/{key-bag-file-VOSSK46F.js → key-bag-file-WADZBHYG.js} +3 -4
  18. package/{key-bag-file-VOSSK46F.js.map → key-bag-file-WADZBHYG.js.map} +1 -1
  19. package/{key-bag-indexdb-AXTQOSMC.js → key-bag-indexdb-PGVAI3FJ.js} +3 -4
  20. package/{key-bag-indexdb-AXTQOSMC.js.map → key-bag-indexdb-PGVAI3FJ.js.map} +1 -1
  21. package/mem-filesystem-YPPJV7Q2.js +41 -0
  22. package/mem-filesystem-YPPJV7Q2.js.map +1 -0
  23. package/metafile-cjs.json +1 -1
  24. package/metafile-esm.json +1 -1
  25. package/metafile-iife.json +1 -1
  26. package/{node-filesystem-CFRXFSO7.js → node-filesystem-INX4ZTHE.js} +9 -6
  27. package/node-filesystem-INX4ZTHE.js.map +1 -0
  28. package/package.json +1 -1
  29. package/tests/blockstore/keyed-crypto.test.ts +227 -63
  30. package/tests/blockstore/loader.test.ts +11 -19
  31. package/tests/blockstore/store.test.ts +19 -23
  32. package/tests/blockstore/transaction.test.ts +12 -12
  33. package/tests/fireproof/all-gateway.test.ts +193 -201
  34. package/tests/fireproof/cars/bafkreidxwt2nhvbl4fnqfw3ctlt6zbrir4kqwmjo5im6rf4q5si27kgo2i.ts +316 -324
  35. package/tests/fireproof/config.test.ts +172 -0
  36. package/tests/fireproof/crdt.test.ts +16 -67
  37. package/tests/fireproof/database.test.ts +21 -183
  38. package/tests/fireproof/fireproof.test.ts +74 -83
  39. package/tests/fireproof/hello.test.ts +14 -18
  40. package/tests/fireproof/indexer.test.ts +43 -53
  41. package/tests/fireproof/utils.test.ts +6 -18
  42. package/tests/helpers.ts +9 -27
  43. package/tests/react/useFireproof.test.tsx +1 -1
  44. package/{utils-STA2C35G.js → utils-QO2HIWGI.js} +3 -4
  45. package/chunk-3EB3ENHT.js.map +0 -1
  46. package/chunk-HQ7D3PEU.js +0 -61
  47. package/chunk-HQ7D3PEU.js.map +0 -1
  48. package/chunk-PZ5AY32C.js +0 -10
  49. package/deno-filesystem-Q2IJ7YDR.js +0 -57
  50. package/deno-filesystem-Q2IJ7YDR.js.map +0 -1
  51. package/gateway-GK5QZ6KP.js.map +0 -1
  52. package/gateway-TQTGDRCN.js.map +0 -1
  53. package/key-bag-memory-LWE6ARPX.js +0 -29
  54. package/key-bag-memory-LWE6ARPX.js.map +0 -1
  55. package/node-filesystem-CFRXFSO7.js.map +0 -1
  56. package/tests/blockstore/keyed-crypto-indexdb-file.test.ts +0 -129
  57. package/tests/gateway/file/loader-config.test.ts +0 -303
  58. package/tests/gateway/indexdb/loader-config.test.ts +0 -75
  59. package/utils-STA2C35G.js.map +0 -1
  60. /package/tests/fireproof/{fireproof.fixture.ts → fireproof.test.fixture.ts} +0 -0
  61. /package/{chunk-PZ5AY32C.js.map → utils-QO2HIWGI.js.map} +0 -0
package/index.cjs CHANGED
@@ -30,47 +30,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
30
30
  ));
31
31
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
32
 
33
- // src/types.ts
34
- function isFalsy(value) {
35
- return value === false && value === null && value === void 0;
36
- }
37
- function throwFalsy(value) {
38
- if (isFalsy(value)) {
39
- throw new Error("value is Falsy");
40
- }
41
- return value;
42
- }
43
- function falsyToUndef(value) {
44
- if (isFalsy(value)) {
45
- return void 0;
46
- }
47
- return value;
48
- }
49
- var PARAM;
50
- var init_types = __esm({
51
- "src/types.ts"() {
52
- "use strict";
53
- PARAM = /* @__PURE__ */ ((PARAM2) => {
54
- PARAM2["SUFFIX"] = "suffix";
55
- PARAM2["URL_GEN"] = "urlGen";
56
- PARAM2["STORE_KEY"] = "storekey";
57
- PARAM2["STORE"] = "store";
58
- PARAM2["KEY"] = "key";
59
- PARAM2["INDEX"] = "index";
60
- PARAM2["NAME"] = "name";
61
- PARAM2["VERSION"] = "version";
62
- PARAM2["FRAG_SIZE"] = "fragSize";
63
- PARAM2["IV_VERIFY"] = "ivVerify";
64
- PARAM2["IV_HASH"] = "ivHash";
65
- PARAM2["FRAG_FID"] = "fid";
66
- PARAM2["FRAG_OFS"] = "ofs";
67
- PARAM2["FRAG_LEN"] = "len";
68
- PARAM2["FRAG_HEAD"] = "headerSize";
69
- return PARAM2;
70
- })(PARAM || {});
71
- }
72
- });
73
-
74
33
  // src/utils.ts
75
34
  function presetEnv() {
76
35
  const penv = new Map([
@@ -128,10 +87,6 @@ function ensureLogger(sthis, componentName, ctx) {
128
87
  exposeStack = true;
129
88
  delete ctx.exposeStack;
130
89
  }
131
- if ("exposeStack" in ctx) {
132
- exposeStack = true;
133
- delete ctx.exposeStack;
134
- }
135
90
  if ("this" in ctx) {
136
91
  cLogger.Str("this", sthis.nextId(4).str);
137
92
  delete ctx.this;
@@ -198,13 +153,10 @@ function ensureLogger(sthis, componentName, ctx) {
198
153
  logger.SetExposeStack(true);
199
154
  }
200
155
  const out = cLogger.Logger();
201
- if (sthis.env.get("FP_CONSTRUCTOR_DEBUG")) {
202
- out.Debug().Msg("constructor");
203
- }
204
156
  return out;
205
157
  }
206
158
  function getStore(url, sthis, joiner) {
207
- const store = url.getParam("store" /* STORE */);
159
+ const store = url.getParam("store");
208
160
  switch (store) {
209
161
  case "data":
210
162
  case "wal":
@@ -212,21 +164,20 @@ function getStore(url, sthis, joiner) {
212
164
  break;
213
165
  default:
214
166
  throw sthis.logger.Error().Url(url).Msg(`store not found`).AsError();
215
- throw sthis.logger.Error().Url(url).Msg(`store not found`).AsError();
216
167
  }
217
168
  let name = store;
218
169
  if (url.hasParam("index")) {
219
- name = joiner(url.getParam("index" /* INDEX */) || "idx", name);
170
+ name = joiner(url.getParam("index") || "idx", name);
220
171
  }
221
172
  return { store, name };
222
173
  }
223
174
  function getKey(url, logger) {
224
- const result = url.getParam("key" /* KEY */);
175
+ const result = url.getParam("key");
225
176
  if (!result) throw logger.Error().Str("url", url.toString()).Msg(`key not found`).AsError();
226
177
  return result;
227
178
  }
228
179
  function getName(sthis, url) {
229
- let result = url.getParam("name" /* NAME */);
180
+ let result = url.getParam("name");
230
181
  if (!result) {
231
182
  result = sthis.pathOps.dirname(url.pathname);
232
183
  if (result.length === 0) {
@@ -246,6 +197,17 @@ function isNotFoundError(e) {
246
197
  if (e.code === "ENOENT") return true;
247
198
  return false;
248
199
  }
200
+ function dataDir(sthis, name, base) {
201
+ if (!base) {
202
+ if (!(0, import_cement.runtimeFn)().isBrowser) {
203
+ const home = sthis.env.get("HOME") || "./";
204
+ base = sthis.env.get("FP_STORAGE_URL") || `file://${sthis.pathOps.join(home, ".fireproof")}`;
205
+ } else {
206
+ base = sthis.env.get("FP_STORAGE_URL") || `indexdb://fp`;
207
+ }
208
+ }
209
+ return import_cement.URI.from(base.toString()).build().setParam("name", name || "").URI();
210
+ }
249
211
  function UInt8ArrayEqual(a, b) {
250
212
  if (a.length !== b.length) {
251
213
  return false;
@@ -262,7 +224,6 @@ var init_utils = __esm({
262
224
  "src/utils.ts"() {
263
225
  "use strict";
264
226
  import_cement = require("@adviser/cement");
265
- init_types();
266
227
  import_base58 = require("multiformats/bases/base58");
267
228
  globalLogger = new import_cement.LoggerImpl();
268
229
  registerFP_DEBUG = new import_cement.ResolveOnce();
@@ -313,9 +274,6 @@ var init_utils = __esm({
313
274
  dirname(path) {
314
275
  return path.split("/").slice(0, -1).join("/");
315
276
  }
316
- basename(path) {
317
- return path.split("/").pop() || "";
318
- }
319
277
  // homedir() {
320
278
  // throw new Error("SysContainer:homedir is not available in seeded state");
321
279
  // }
@@ -334,63 +292,45 @@ var init_utils = __esm({
334
292
  }
335
293
  });
336
294
 
337
- // src/runtime/gateways/file/deno-filesystem.ts
338
- var deno_filesystem_exports = {};
339
- __export(deno_filesystem_exports, {
340
- DenoFileSystem: () => DenoFileSystem
295
+ // src/runtime/gateways/file/mem-filesystem.ts
296
+ var mem_filesystem_exports = {};
297
+ __export(mem_filesystem_exports, {
298
+ MemFileSystem: () => MemFileSystem
341
299
  });
342
- var DenoFileSystem;
343
- var init_deno_filesystem = __esm({
344
- "src/runtime/gateways/file/deno-filesystem.ts"() {
300
+ var import_memfs, MemFileSystem;
301
+ var init_mem_filesystem = __esm({
302
+ "src/runtime/gateways/file/mem-filesystem.ts"() {
345
303
  "use strict";
346
- DenoFileSystem = class {
304
+ import_memfs = require("memfs");
305
+ init_utils2();
306
+ MemFileSystem = class {
347
307
  async start() {
348
- this.fs = Deno;
349
308
  return this;
350
309
  }
351
- async mkdir(path, options) {
352
- return this.fs?.mkdir(path, options).then(() => path);
310
+ mkdir(path, options) {
311
+ return import_memfs.fs.promises.mkdir(path, options);
353
312
  }
354
- async readdir(path) {
355
- const ret = [];
356
- for await (const dirEntry of this.fs.readdir(path)) {
357
- ret.push(dirEntry.name);
358
- }
359
- return ret;
313
+ readdir(path, options) {
314
+ return import_memfs.fs.promises.readdir(path, options);
360
315
  }
361
- async rm(path, options) {
362
- return this.fs?.rm(path, options);
316
+ rm(path, options) {
317
+ return import_memfs.fs.promises.rm(path, options);
363
318
  }
364
- async copyFile(source, destination) {
365
- return this.fs?.copyFile(source, destination);
319
+ copyFile(source, destination) {
320
+ return import_memfs.fs.promises.copyFile(source, destination);
366
321
  }
367
- async readfile(path) {
368
- return this.fs.readFile(path);
322
+ async readfile(path, options) {
323
+ const ret = await import_memfs.fs.promises.readFile(path, options);
324
+ return toArrayBuffer(ret);
369
325
  }
370
- async stat(path) {
371
- const x = await this.fs.stat(path);
372
- return {
373
- isFile: () => x.isFile,
374
- isDirectory: () => x.isDirectory,
375
- isBlockDevice: () => !!x.isBlockDevice,
376
- isCharacterDevice: () => !!x.isCharDevice,
377
- isSymbolicLink: () => !!x.isSymlink,
378
- isFIFO: () => !!x.isFifo,
379
- isSocket: () => !!x.isSocket,
380
- uid: x.uid,
381
- gid: x.gid,
382
- size: x.size,
383
- atime: x.atime,
384
- mtime: x.mtime,
385
- ctime: x.birthtime,
386
- birthtime: x.birthtime
387
- };
326
+ stat(path) {
327
+ return import_memfs.fs.promises.stat(path);
388
328
  }
389
- async unlink(path) {
390
- return this.fs?.unlink(path);
329
+ unlink(path) {
330
+ return import_memfs.fs.promises.unlink(path);
391
331
  }
392
- async writefile(path, data) {
393
- return this.fs?.writeFile(path, Buffer.from(data));
332
+ writefile(path, data) {
333
+ return import_memfs.fs.promises.writeFile(path, Buffer.from(data));
394
334
  }
395
335
  };
396
336
  }
@@ -401,11 +341,12 @@ var node_filesystem_exports = {};
401
341
  __export(node_filesystem_exports, {
402
342
  NodeFileSystem: () => NodeFileSystem
403
343
  });
404
- var NodeFileSystem;
344
+ var import_cement4, NodeFileSystem;
405
345
  var init_node_filesystem = __esm({
406
346
  "src/runtime/gateways/file/node-filesystem.ts"() {
407
347
  "use strict";
408
348
  init_utils2();
349
+ import_cement4 = require("@adviser/cement");
409
350
  NodeFileSystem = class {
410
351
  async start() {
411
352
  this.fs = await import("fs/promises");
@@ -428,12 +369,15 @@ var init_node_filesystem = __esm({
428
369
  return toArrayBuffer(ret);
429
370
  }
430
371
  stat(path) {
431
- return this.fs.stat(path);
372
+ return this.fs?.stat(path);
432
373
  }
433
374
  async unlink(path) {
434
375
  return this.fs?.unlink(path);
435
376
  }
436
377
  async writefile(path, data) {
378
+ if ((0, import_cement4.runtimeFn)().isDeno) {
379
+ return this.fs?.writeFile(path, data);
380
+ }
437
381
  return this.fs?.writeFile(path, Buffer.from(data));
438
382
  }
439
383
  };
@@ -449,34 +393,49 @@ __export(utils_exports, {
449
393
  toArrayBuffer: () => toArrayBuffer
450
394
  });
451
395
  async function getFileSystem(url) {
452
- let fs;
453
- if ((0, import_cement4.runtimeFn)().isDeno) {
454
- const { DenoFileSystem: DenoFileSystem2 } = await Promise.resolve().then(() => (init_deno_filesystem(), deno_filesystem_exports));
455
- fs = new DenoFileSystem2();
456
- } else if ((0, import_cement4.runtimeFn)().isNodeIsh) {
457
- const { NodeFileSystem: NodeFileSystem2 } = await Promise.resolve().then(() => (init_node_filesystem(), node_filesystem_exports));
458
- fs = new NodeFileSystem2();
459
- } else {
460
- throw new Error("unsupported runtime");
396
+ const name = url.getParam("fs");
397
+ let fs2;
398
+ switch (name) {
399
+ case "mem":
400
+ {
401
+ const { MemFileSystem: MemFileSystem2 } = await Promise.resolve().then(() => (init_mem_filesystem(), mem_filesystem_exports));
402
+ fs2 = new MemFileSystem2();
403
+ }
404
+ break;
405
+ // case 'deno': {
406
+ // const { DenoFileSystem } = await import("./deno-filesystem.js");
407
+ // fs = new DenoFileSystem();
408
+ // break;
409
+ // }
410
+ case "node": {
411
+ const { NodeFileSystem: NodeFileSystem2 } = await Promise.resolve().then(() => (init_node_filesystem(), node_filesystem_exports));
412
+ fs2 = new NodeFileSystem2();
413
+ break;
414
+ }
415
+ case "sys":
416
+ default: {
417
+ return getFileSystem(url.build().setParam("fs", "node").URI());
418
+ }
461
419
  }
462
- return fs.start();
420
+ return fs2.start();
463
421
  }
464
422
  function getPath(url, sthis) {
465
423
  const basePath = url.pathname;
466
- const name = url.getParam("name" /* NAME */);
424
+ const name = url.getParam("name");
467
425
  if (name) {
468
- return sthis.pathOps.join(basePath, name);
426
+ const version = url.getParam("version");
427
+ if (!version) throw sthis.logger.Error().Url(url).Msg(`version not found`).AsError();
428
+ return sthis.pathOps.join(basePath, version, name);
469
429
  }
470
430
  return sthis.pathOps.join(basePath);
471
431
  }
472
432
  function getFileName(url, sthis) {
473
- const key = url.getParam("key" /* KEY */);
433
+ const key = url.getParam("key");
474
434
  if (!key) throw sthis.logger.Error().Url(url).Msg(`key not found`).AsError();
475
435
  const res = getStore(url, sthis, (...a) => a.join("-"));
476
436
  switch (res.store) {
477
- case "data": {
478
- return sthis.pathOps.join(res.name, key + (url.getParam("suffix" /* SUFFIX */) || ""));
479
- }
437
+ case "data":
438
+ return sthis.pathOps.join(res.name, key + ".car");
480
439
  case "wal":
481
440
  case "meta":
482
441
  return sthis.pathOps.join(res.name, key + ".json");
@@ -495,13 +454,10 @@ function toArrayBuffer(buffer) {
495
454
  }
496
455
  return view;
497
456
  }
498
- var import_cement4;
499
457
  var init_utils2 = __esm({
500
458
  "src/runtime/gateways/file/utils.ts"() {
501
459
  "use strict";
502
- import_cement4 = require("@adviser/cement");
503
460
  init_utils();
504
- init_types();
505
461
  }
506
462
  });
507
463
 
@@ -616,40 +572,6 @@ var init_key_bag_indexdb = __esm({
616
572
  }
617
573
  });
618
574
 
619
- // src/runtime/key-bag-memory.ts
620
- var key_bag_memory_exports = {};
621
- __export(key_bag_memory_exports, {
622
- KeyBagProviderMemory: () => KeyBagProviderMemory
623
- });
624
- var memoryKeyBag, KeyBagProviderMemory;
625
- var init_key_bag_memory = __esm({
626
- "src/runtime/key-bag-memory.ts"() {
627
- "use strict";
628
- memoryKeyBag = /* @__PURE__ */ new Map();
629
- KeyBagProviderMemory = class {
630
- constructor(url, sthis) {
631
- this.url = url;
632
- this.sthis = sthis;
633
- }
634
- key(id) {
635
- return `${this.url.pathname}/${id}`;
636
- }
637
- async get(id) {
638
- const binKeyItem = memoryKeyBag.get(this.key(id));
639
- if (binKeyItem) {
640
- const ki = JSON.parse(this.sthis.txt.decode(binKeyItem));
641
- return ki;
642
- }
643
- return void 0;
644
- }
645
- async set(id, item) {
646
- const p = this.sthis.txt.encode(JSON.stringify(item, null, 2));
647
- memoryKeyBag.set(this.key(id), p);
648
- }
649
- };
650
- }
651
- });
652
-
653
575
  // src/runtime/gateways/file/version.ts
654
576
  var FILESTORE_VERSION;
655
577
  var init_version = __esm({
@@ -665,24 +587,23 @@ __export(gateway_exports, {
665
587
  FileGateway: () => FileGateway,
666
588
  FileTestStore: () => FileTestStore
667
589
  });
668
- var import_cement12, versionFiles, FileGateway, FileTestStore;
590
+ var import_cement11, versionFiles, FileGateway, FileTestStore;
669
591
  var init_gateway = __esm({
670
592
  "src/runtime/gateways/file/gateway.ts"() {
671
593
  "use strict";
672
594
  init_version();
673
- import_cement12 = require("@adviser/cement");
595
+ import_cement11 = require("@adviser/cement");
674
596
  init_utils();
675
597
  init_utils2();
676
- init_types();
677
- versionFiles = new import_cement12.KeyedResolvOnce();
598
+ versionFiles = new import_cement11.KeyedResolvOnce();
678
599
  FileGateway = class {
679
600
  get fs() {
680
601
  if (!this._fs) throw this.logger.Error().Msg("fs not initialized").AsError();
681
602
  return this._fs;
682
603
  }
683
604
  constructor(sthis) {
684
- this.sthis = ensureSuperLog(sthis, "FileGateway", { this: 1 });
685
- this.logger = this.sthis.logger;
605
+ this.sthis = sthis;
606
+ this.logger = sthis.logger;
686
607
  }
687
608
  async getVersionFromFile(path, logger) {
688
609
  return versionFiles.get(path).once(async () => {
@@ -704,33 +625,34 @@ var init_gateway = __esm({
704
625
  });
705
626
  }
706
627
  start(baseURL) {
707
- return (0, import_cement12.exception2Result)(async () => {
628
+ return (0, import_cement11.exception2Result)(async () => {
708
629
  this._fs = await getFileSystem(baseURL);
630
+ await this.fs.start();
709
631
  const url = baseURL.build();
710
- url.defParam("version" /* VERSION */, FILESTORE_VERSION);
632
+ url.defParam("version", FILESTORE_VERSION);
711
633
  const dbUrl = await this.buildUrl(url.URI(), "dummy");
712
634
  const dbdirFile = this.getFilePath(dbUrl.Ok());
713
635
  await this.fs.mkdir(this.sthis.pathOps.dirname(dbdirFile), { recursive: true });
714
636
  const dbroot = this.sthis.pathOps.dirname(dbdirFile);
715
637
  this.logger.Debug().Url(url.URI()).Str("dbroot", dbroot).Msg("start");
716
- url.setParam("version" /* VERSION */, await this.getVersionFromFile(dbroot, this.logger));
638
+ url.setParam("version", await this.getVersionFromFile(dbroot, this.logger));
717
639
  return url.URI();
718
640
  });
719
641
  }
720
642
  async buildUrl(baseUrl, key) {
721
- return import_cement12.Result.Ok(baseUrl.build().setParam("key" /* KEY */, key).URI());
643
+ return import_cement11.Result.Ok(baseUrl.build().setParam("key", key).URI());
722
644
  }
723
645
  async close() {
724
- return import_cement12.Result.Ok(void 0);
646
+ return import_cement11.Result.Ok(void 0);
725
647
  }
726
648
  // abstract buildUrl(baseUrl: URL, key: string): Promise<Result<URL>>;
727
649
  getFilePath(url) {
728
- const key = url.getParam("key" /* KEY */);
650
+ const key = url.getParam("key");
729
651
  if (!key) throw this.logger.Error().Url(url).Msg(`key not found`).AsError();
730
652
  return this.sthis.pathOps.join(getPath(url, this.sthis), getFileName(url, this.sthis));
731
653
  }
732
654
  async put(url, body) {
733
- return (0, import_cement12.exception2Result)(async () => {
655
+ return (0, import_cement11.exception2Result)(async () => {
734
656
  const file = await this.getFilePath(url);
735
657
  this.logger.Debug().Str("url", url.toString()).Str("file", file).Msg("put");
736
658
  await this.fs.writefile(file, body);
@@ -740,19 +662,19 @@ var init_gateway = __esm({
740
662
  return exceptionWrapper(async () => {
741
663
  const file = this.getFilePath(url);
742
664
  try {
743
- this.logger.Debug().Url(url).Str("file", file).Msg("get");
744
665
  const res = await this.fs.readfile(file);
745
- return import_cement12.Result.Ok(new Uint8Array(res));
666
+ this.logger.Debug().Url(url.asURL()).Str("file", file).Msg("get");
667
+ return import_cement11.Result.Ok(new Uint8Array(res));
746
668
  } catch (e) {
747
669
  if (isNotFoundError(e)) {
748
- return import_cement12.Result.Err(new NotFoundError(`file not found: ${file}`));
670
+ return import_cement11.Result.Err(new NotFoundError(`file not found: ${file}`));
749
671
  }
750
- return import_cement12.Result.Err(e);
672
+ return import_cement11.Result.Err(e);
751
673
  }
752
674
  });
753
675
  }
754
676
  async delete(url) {
755
- return (0, import_cement12.exception2Result)(async () => {
677
+ return (0, import_cement11.exception2Result)(async () => {
756
678
  await this.fs.unlink(this.getFilePath(url));
757
679
  });
758
680
  }
@@ -778,7 +700,7 @@ var init_gateway = __esm({
778
700
  }
779
701
  }
780
702
  }
781
- return import_cement12.Result.Ok(void 0);
703
+ return import_cement11.Result.Ok(void 0);
782
704
  }
783
705
  };
784
706
  FileTestStore = class {
@@ -787,7 +709,7 @@ var init_gateway = __esm({
787
709
  this.sthis = sthis;
788
710
  }
789
711
  async get(iurl, key) {
790
- const url = iurl.build().setParam("key" /* KEY */, key).URI();
712
+ const url = iurl.build().setParam("key", key).URI();
791
713
  const dbFile = this.sthis.pathOps.join(getPath(url, this.sthis), getFileName(url, this.sthis));
792
714
  this.logger.Debug().Url(url).Str("dbFile", dbFile).Msg("get");
793
715
  const buffer = await (await getFileSystem(url)).readfile(dbFile);
@@ -815,7 +737,7 @@ __export(gateway_exports2, {
815
737
  getIndexDBName: () => getIndexDBName
816
738
  });
817
739
  function ensureVersion(url) {
818
- return url.build().defParam("version" /* VERSION */, INDEXDB_VERSION).URI();
740
+ return url.build().defParam("version", INDEXDB_VERSION).URI();
819
741
  }
820
742
  function sanitzeKey(key) {
821
743
  if (key.length === 1) {
@@ -836,17 +758,17 @@ async function connectIdb(url, sthis) {
836
758
  }
837
759
  });
838
760
  const found = await db.get("version", "version");
839
- const version = ensureVersion(url).getParam("version" /* VERSION */);
761
+ const version = ensureVersion(url).getParam("version");
840
762
  if (!found) {
841
763
  await db.put("version", { version }, "version");
842
764
  } else if (found.version !== version) {
843
- sthis.logger.Warn().Url(url).Str("version", version).Str("found", found.version).Msg("version mismatch");
765
+ sthis.logger.Warn().Str("url", url.toString()).Str("version", version).Str("found", found.version).Msg("version mismatch");
844
766
  }
845
767
  return { db, dbName, version, url };
846
768
  });
847
769
  return {
848
770
  ...once,
849
- url: url.build().setParam("version" /* VERSION */, once.version).URI()
771
+ url: url.build().setParam("version", once.version).URI()
850
772
  };
851
773
  }
852
774
  function joinDBName(...names) {
@@ -855,7 +777,7 @@ function joinDBName(...names) {
855
777
  function getIndexDBName(iurl, sthis) {
856
778
  const url = ensureVersion(iurl);
857
779
  const fullDb = url.pathname.replace(/^\/+/, "").replace(/\?.*$/, "");
858
- const dbName = url.getParam("name" /* NAME */);
780
+ const dbName = url.getParam("name");
859
781
  if (!dbName) throw sthis.logger.Error().Str("url", url.toString()).Msg(`name not found`).AsError();
860
782
  const result = joinDBName(fullDb, dbName);
861
783
  const objStore = getStore(url, sthis, joinDBName).name;
@@ -867,16 +789,15 @@ function getIndexDBName(iurl, sthis) {
867
789
  dbName
868
790
  };
869
791
  }
870
- var import_idb2, import_cement13, onceIndexDB, IndexDBGateway, IndexDBTestStore;
792
+ var import_idb2, import_cement12, onceIndexDB, IndexDBGateway, IndexDBTestStore;
871
793
  var init_gateway2 = __esm({
872
794
  "src/runtime/gateways/indexdb/gateway.ts"() {
873
795
  "use strict";
874
796
  import_idb2 = require("idb");
875
- import_cement13 = require("@adviser/cement");
797
+ import_cement12 = require("@adviser/cement");
876
798
  init_version2();
877
799
  init_utils();
878
- init_types();
879
- onceIndexDB = new import_cement13.KeyedResolvOnce();
800
+ onceIndexDB = new import_cement12.KeyedResolvOnce();
880
801
  IndexDBGateway = class {
881
802
  constructor(sthis) {
882
803
  this._db = {};
@@ -884,7 +805,7 @@ var init_gateway2 = __esm({
884
805
  this.sthis = sthis;
885
806
  }
886
807
  async start(baseURL) {
887
- return (0, import_cement13.exception2Result)(async () => {
808
+ return (0, import_cement12.exception2Result)(async () => {
888
809
  this.logger.Debug().Url(baseURL).Msg("starting");
889
810
  await this.sthis.start();
890
811
  const ic = await connectIdb(baseURL, this.sthis);
@@ -894,10 +815,10 @@ var init_gateway2 = __esm({
894
815
  });
895
816
  }
896
817
  async close() {
897
- return import_cement13.Result.Ok(void 0);
818
+ return import_cement12.Result.Ok(void 0);
898
819
  }
899
820
  async destroy(baseUrl) {
900
- return (0, import_cement13.exception2Result)(async () => {
821
+ return (0, import_cement12.exception2Result)(async () => {
901
822
  const type = getStore(baseUrl, this.sthis, joinDBName).name;
902
823
  const idb = this._db;
903
824
  const trans = idb.transaction(type, "readwrite");
@@ -913,7 +834,7 @@ var init_gateway2 = __esm({
913
834
  });
914
835
  }
915
836
  buildUrl(baseUrl, key) {
916
- return Promise.resolve(import_cement13.Result.Ok(baseUrl.build().setParam("key" /* KEY */, key).URI()));
837
+ return Promise.resolve(import_cement12.Result.Ok(baseUrl.build().setParam("key", key).URI()));
917
838
  }
918
839
  async get(url) {
919
840
  return exceptionWrapper(async () => {
@@ -924,13 +845,13 @@ var init_gateway2 = __esm({
924
845
  const bytes = await tx.objectStore(store).get(sanitzeKey(key));
925
846
  await tx.done;
926
847
  if (!bytes) {
927
- return import_cement13.Result.Err(new NotFoundError(`missing ${key}`));
848
+ return import_cement12.Result.Err(new NotFoundError(`missing ${key}`));
928
849
  }
929
- return import_cement13.Result.Ok(bytes);
850
+ return import_cement12.Result.Ok(bytes);
930
851
  });
931
852
  }
932
853
  async put(url, value) {
933
- return (0, import_cement13.exception2Result)(async () => {
854
+ return (0, import_cement12.exception2Result)(async () => {
934
855
  const key = getKey(url, this.logger);
935
856
  const store = getStore(url, this.sthis, joinDBName).name;
936
857
  this.logger.Debug().Url(url).Str("key", key).Str("store", store).Msg("putting");
@@ -940,14 +861,14 @@ var init_gateway2 = __esm({
940
861
  });
941
862
  }
942
863
  async delete(url) {
943
- return (0, import_cement13.exception2Result)(async () => {
864
+ return (0, import_cement12.exception2Result)(async () => {
944
865
  const key = getKey(url, this.logger);
945
866
  const store = getStore(url, this.sthis, joinDBName).name;
946
867
  this.logger.Debug().Url(url).Str("key", key).Str("store", store).Msg("deleting");
947
868
  const tx = this._db.transaction([store], "readwrite");
948
869
  await tx.objectStore(store).delete(sanitzeKey(key));
949
870
  await tx.done;
950
- return import_cement13.Result.Ok(void 0);
871
+ return import_cement12.Result.Ok(void 0);
951
872
  });
952
873
  }
953
874
  };
@@ -975,16 +896,15 @@ var init_gateway2 = __esm({
975
896
  var src_exports = {};
976
897
  __export(src_exports, {
977
898
  CRDT: () => CRDT,
978
- DatabaseFactory: () => DatabaseFactory,
979
- DatabaseShell: () => DatabaseShell,
899
+ Database: () => Database,
980
900
  Index: () => Index,
981
901
  NotFoundError: () => NotFoundError,
982
902
  PACKAGE_VERSION: () => PACKAGE_VERSION,
983
- PARAM: () => PARAM,
984
903
  Result: () => import_cement.Result,
985
904
  UInt8ArrayEqual: () => UInt8ArrayEqual,
986
905
  blockstore: () => blockstore_exports,
987
906
  bs: () => blockstore_exports,
907
+ dataDir: () => dataDir,
988
908
  ensureLogger: () => ensureLogger,
989
909
  ensureSuperLog: () => ensureSuperLog,
990
910
  ensureSuperThis: () => ensureSuperThis,
@@ -995,19 +915,16 @@ __export(src_exports, {
995
915
  getName: () => getName,
996
916
  getStore: () => getStore,
997
917
  index: () => index,
998
- isDatabase: () => isDatabase,
999
918
  isFalsy: () => isFalsy,
1000
919
  isNotFoundError: () => isNotFoundError,
1001
- keyConfigOpts: () => keyConfigOpts,
1002
920
  rt: () => runtime_exports,
1003
921
  runtime: () => runtime_exports,
1004
- throwFalsy: () => throwFalsy,
1005
- toStoreURIRuntime: () => toStoreURIRuntime
922
+ throwFalsy: () => throwFalsy
1006
923
  });
1007
924
  module.exports = __toCommonJS(src_exports);
1008
925
 
1009
926
  // src/database.ts
1010
- var import_cement18 = require("@adviser/cement");
927
+ var import_cement16 = require("@adviser/cement");
1011
928
 
1012
929
  // src/write-queue.ts
1013
930
  function writeQueue(worker, payload = Infinity, unbounded = false) {
@@ -1050,7 +967,86 @@ function writeQueue(worker, payload = Infinity, unbounded = false) {
1050
967
  }
1051
968
 
1052
969
  // src/crdt.ts
1053
- var import_cement17 = require("@adviser/cement");
970
+ var import_cement15 = require("@adviser/cement");
971
+
972
+ // src/runtime/wait-pr-multiformats/block.ts
973
+ var block_exports = {};
974
+ __export(block_exports, {
975
+ Block: () => Block,
976
+ create: () => create,
977
+ createUnsafe: () => createUnsafe,
978
+ decode: () => decode,
979
+ encode: () => encode
980
+ });
981
+ var import_multiformats = require("multiformats");
982
+ var import_block = require("multiformats/block");
983
+ var Block = import_block.Block;
984
+ async function decode({
985
+ bytes,
986
+ codec: codec3,
987
+ hasher: hasher7
988
+ }) {
989
+ if (bytes == null) throw new Error('Missing required argument "bytes"');
990
+ if (codec3 == null || hasher7 == null) throw new Error("Missing required argument: codec or hasher");
991
+ const value = await Promise.resolve(codec3.decode(bytes));
992
+ const hash = await hasher7.digest(bytes);
993
+ const cid = import_multiformats.CID.create(1, codec3.code, hash);
994
+ return new import_block.Block({ value, bytes, cid });
995
+ }
996
+ async function encode({
997
+ value,
998
+ codec: codec3,
999
+ hasher: hasher7
1000
+ }) {
1001
+ if (typeof value === "undefined") throw new Error('Missing required argument "value"');
1002
+ if (codec3 == null || hasher7 == null) throw new Error("Missing required argument: codec or hasher");
1003
+ const bytes = await Promise.resolve(codec3.encode(value));
1004
+ const hash = await hasher7.digest(bytes);
1005
+ const cid = import_multiformats.CID.create(1, codec3.code, hash);
1006
+ return new import_block.Block({ value, bytes, cid });
1007
+ }
1008
+ async function create({
1009
+ bytes,
1010
+ cid,
1011
+ hasher: hasher7,
1012
+ codec: codec3
1013
+ }) {
1014
+ if (bytes == null) throw new Error('Missing required argument "bytes"');
1015
+ if (hasher7 == null) throw new Error('Missing required argument "hasher"');
1016
+ const value = await Promise.resolve(codec3.decode(bytes));
1017
+ const hash = await hasher7.digest(bytes);
1018
+ if (!import_multiformats.bytes.equals(cid.multihash.bytes, hash.bytes)) {
1019
+ throw new Error("CID hash does not match bytes");
1020
+ }
1021
+ return createUnsafe({
1022
+ bytes,
1023
+ cid,
1024
+ value,
1025
+ codec: codec3
1026
+ });
1027
+ }
1028
+ async function createUnsafe({
1029
+ bytes,
1030
+ cid,
1031
+ value: maybeValue,
1032
+ codec: codec3
1033
+ }) {
1034
+ const value = await Promise.resolve(maybeValue !== void 0 ? maybeValue : codec3?.decode(bytes));
1035
+ if (value === void 0) throw new Error('Missing required argument, must either provide "value" or "codec"');
1036
+ return new Block({
1037
+ cid,
1038
+ bytes,
1039
+ value
1040
+ });
1041
+ }
1042
+
1043
+ // src/crdt-helpers.ts
1044
+ var import_link = require("multiformats/link");
1045
+ var import_sha25 = require("multiformats/hashes/sha2");
1046
+ var codec = __toESM(require("@ipld/dag-cbor"), 1);
1047
+ var import_crdt = require("@web3-storage/pail/crdt");
1048
+ var import_clock2 = require("@web3-storage/pail/clock");
1049
+ var Batch = __toESM(require("@web3-storage/pail/crdt/batch"), 1);
1054
1050
 
1055
1051
  // src/blockstore/index.ts
1056
1052
  var blockstore_exports = {};
@@ -1063,11 +1059,8 @@ __export(blockstore_exports, {
1063
1059
  FragmentGateway: () => FragmentGateway,
1064
1060
  Loader: () => Loader,
1065
1061
  addCryptoKeyToGatewayMetaPayload: () => addCryptoKeyToGatewayMetaPayload,
1066
- ensureStoreEnDeFile: () => ensureStoreEnDeFile,
1067
- fileGatewayFactoryItem: () => fileGatewayFactoryItem,
1068
- getDefaultURI: () => getDefaultURI,
1069
- getGatewayFactoryItem: () => getGatewayFactoryItem,
1070
- getStartedGateway: () => getStartedGateway,
1062
+ ensureStart: () => ensureStart,
1063
+ getGatewayFromURL: () => getGatewayFromURL,
1071
1064
  parseCarFile: () => parseCarFile,
1072
1065
  registerStoreProtocol: () => registerStoreProtocol,
1073
1066
  setCryptoKeyFromGatewayMetaPayload: () => setCryptoKeyFromGatewayMetaPayload,
@@ -1082,7 +1075,7 @@ function toCIDBlock(block) {
1082
1075
  }
1083
1076
 
1084
1077
  // src/blockstore/store-factory.ts
1085
- var import_cement15 = require("@adviser/cement");
1078
+ var import_cement13 = require("@adviser/cement");
1086
1079
 
1087
1080
  // src/runtime/files.ts
1088
1081
  var files_exports = {};
@@ -1158,422 +1151,327 @@ var UnixFSFileBuilder = class {
1158
1151
  // src/blockstore/store.ts
1159
1152
  var import_dag_json2 = require("@ipld/dag-json");
1160
1153
  var import_cement10 = require("@adviser/cement");
1161
- init_types();
1162
- init_utils();
1163
1154
 
1164
- // src/blockstore/commit-queue.ts
1165
- var import_cement2 = require("@adviser/cement");
1166
- var CommitQueue = class {
1167
- constructor() {
1168
- this.queue = [];
1169
- this.processing = false;
1170
- this._waitIdleItems = /* @__PURE__ */ new Set();
1171
- }
1172
- waitIdle() {
1173
- if (this.queue.length === 0 && !this.processing) {
1174
- return Promise.resolve();
1175
- }
1176
- const fn = new import_cement2.Future();
1177
- this._waitIdleItems.add(fn);
1178
- return fn.asPromise();
1179
- }
1180
- async enqueue(fn) {
1181
- return new Promise((resolve, reject) => {
1182
- const queueFn = async () => {
1183
- try {
1184
- resolve(await fn());
1185
- } catch (e) {
1186
- reject(e);
1187
- } finally {
1188
- this.processing = false;
1189
- this.processNext();
1190
- }
1191
- };
1192
- this.queue.push(queueFn);
1193
- if (!this.processing) {
1194
- this.processNext();
1195
- }
1196
- });
1155
+ // src/types.ts
1156
+ function isFalsy(value) {
1157
+ return value === false && value === null && value === void 0;
1158
+ }
1159
+ function throwFalsy(value) {
1160
+ if (isFalsy(value)) {
1161
+ throw new Error("value is Falsy");
1197
1162
  }
1198
- processNext() {
1199
- if (this.queue.length > 0 && !this.processing) {
1200
- this.processing = true;
1201
- const queueFn = this.queue.shift();
1202
- if (queueFn) {
1203
- queueFn().finally(() => {
1204
- });
1205
- }
1206
- }
1207
- if (this.queue.length === 0 && !this.processing) {
1208
- const toResolve = Array.from(this._waitIdleItems);
1209
- this._waitIdleItems.clear();
1210
- toResolve.map((fn) => fn.resolve());
1211
- }
1163
+ return value;
1164
+ }
1165
+ function falsyToUndef(value) {
1166
+ if (isFalsy(value)) {
1167
+ return void 0;
1212
1168
  }
1213
- };
1169
+ return value;
1170
+ }
1214
1171
 
1215
- // src/runtime/keyed-crypto.ts
1216
- var keyed_crypto_exports = {};
1217
- __export(keyed_crypto_exports, {
1218
- BlockIvKeyIdCodec: () => BlockIvKeyIdCodec,
1219
- keyedCryptoFactory: () => keyedCryptoFactory
1220
- });
1172
+ // src/blockstore/store.ts
1221
1173
  init_utils();
1222
- var import_base582 = require("multiformats/bases/base58");
1174
+
1175
+ // src/blockstore/loader.ts
1176
+ var import_p_limit = __toESM(require("p-limit"), 1);
1177
+ var import_car = require("@ipld/car");
1178
+ var import_cement7 = require("@adviser/cement");
1179
+
1180
+ // src/blockstore/loader-helpers.ts
1223
1181
  var import_sha2 = require("multiformats/hashes/sha2");
1224
- var CBOR = __toESM(require("cborg"), 1);
1225
- init_types();
1226
- var generateIV = {
1227
- random: {
1228
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1229
- calc: async (ko, crypto, data) => {
1230
- return crypto.randomBytes(ko.ivLength);
1231
- },
1232
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1233
- verify: async (ko, crypto, iv, data) => {
1234
- return true;
1235
- }
1236
- },
1237
- hash: {
1238
- calc: async (ko, crypto, data) => {
1239
- const hash = await import_sha2.sha256.digest(data);
1240
- const hashBytes = new Uint8Array(hash.bytes);
1241
- const hashArray = new Uint8Array(ko.ivLength);
1242
- for (let i = 0; i < hashBytes.length; i++) {
1243
- hashArray[i % ko.ivLength] ^= hashBytes[i];
1244
- }
1245
- return hashArray;
1246
- },
1247
- verify: async function(ko, crypto, iv, data) {
1248
- return ko.url.getParam("ivVerify" /* IV_VERIFY */) !== "disable" && UInt8ArrayEqual(iv, await this.calc(ko, crypto, data));
1182
+ var dagCodec = __toESM(require("@ipld/dag-cbor"), 1);
1183
+ async function parseCarFile(reader, logger) {
1184
+ const roots = await reader.getRoots();
1185
+ const header = await reader.get(roots[0]);
1186
+ if (!header) throw logger.Error().Msg("missing header block").AsError();
1187
+ const dec = await decode({ bytes: header.bytes, hasher: import_sha2.sha256, codec: dagCodec });
1188
+ const fpvalue = dec.value;
1189
+ if (fpvalue && !fpvalue.fp) {
1190
+ throw logger.Error().Msg("missing fp").AsError();
1191
+ }
1192
+ return fpvalue.fp;
1193
+ }
1194
+
1195
+ // src/blockstore/transaction.ts
1196
+ var import_block3 = require("@web3-storage/pail/block");
1197
+ var import_cement2 = require("@adviser/cement");
1198
+ init_utils();
1199
+ var CarTransaction = class extends import_block3.MemoryBlockstore {
1200
+ constructor(parent, opts = { add: true, noLoader: false }) {
1201
+ super();
1202
+ if (opts.add) {
1203
+ parent.transactions.add(this);
1249
1204
  }
1205
+ this.parent = parent;
1206
+ }
1207
+ async get(cid) {
1208
+ return await this.superGet(cid) || falsyToUndef(await this.parent.get(cid));
1209
+ }
1210
+ async superGet(cid) {
1211
+ return super.get(cid);
1250
1212
  }
1251
1213
  };
1252
- function getGenerateIVFn(url, opts) {
1253
- const ivhash = opts.ivCalc || url.getParam("ivHash" /* IV_HASH */) || "hash";
1254
- return generateIV[ivhash] || generateIV["hash"];
1214
+ function defaultedBlockstoreRuntime(sthis, opts, component, ctx) {
1215
+ const logger = ensureLogger(sthis, component, ctx);
1216
+ const store = opts.store || {};
1217
+ return {
1218
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1219
+ applyMeta: (meta, snap) => {
1220
+ return Promise.resolve();
1221
+ },
1222
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1223
+ compact: async (blocks) => {
1224
+ return {};
1225
+ },
1226
+ autoCompact: 100,
1227
+ public: false,
1228
+ name: void 0,
1229
+ threshold: 1e3 * 1e3,
1230
+ ...opts,
1231
+ logger,
1232
+ keyBag: opts.keyBag || {},
1233
+ crypto: (0, import_cement2.toCryptoRuntime)(opts.crypto),
1234
+ store,
1235
+ storeRuntime: toStoreRuntime(store, sthis)
1236
+ };
1255
1237
  }
1256
- var BlockIvKeyIdCodec = class {
1257
- constructor(ko, iv, opts) {
1258
- this.code = 3147065;
1259
- this.name = "Fireproof@encrypted-block:aes-gcm";
1260
- this.ko = ko;
1261
- this.iv = iv;
1262
- this.opts = opts || {};
1238
+ function blockstoreFactory(sthis, opts) {
1239
+ if (opts.name) {
1240
+ return new EncryptedBlockstore(sthis, opts);
1241
+ } else {
1242
+ return new BaseBlockstore(opts);
1263
1243
  }
1264
- async encode(data) {
1265
- const calcIv = this.iv || await getGenerateIVFn(this.ko.url, this.opts).calc(this.ko, this.ko.crypto, data);
1266
- const { iv } = this.ko.algo(calcIv);
1267
- const fprt = await this.ko.fingerPrint();
1268
- const keyId = import_base582.base58btc.decode(fprt);
1269
- this.ko.logger.Debug().Str("fp", fprt).Msg("encode");
1270
- return CBOR.encode({
1271
- iv,
1272
- keyId,
1273
- data: await this.ko._encrypt({ iv, bytes: data })
1274
- });
1244
+ }
1245
+ var BaseBlockstore = class {
1246
+ constructor(ebOpts = {}) {
1247
+ this.transactions = /* @__PURE__ */ new Set();
1248
+ this.sthis = ensureSuperThis(ebOpts);
1249
+ this.ebOpts = defaultedBlockstoreRuntime(this.sthis, ebOpts, "BaseBlockstore");
1250
+ this.logger = this.ebOpts.logger;
1275
1251
  }
1276
- async decode(abytes) {
1277
- let bytes;
1278
- if (abytes instanceof Uint8Array) {
1279
- bytes = abytes;
1280
- } else {
1281
- bytes = new Uint8Array(abytes);
1282
- }
1283
- const { iv, keyId, data } = CBOR.decode(bytes);
1284
- const fprt = await this.ko.fingerPrint();
1285
- this.ko.logger.Debug().Str("fp", import_base582.base58btc.encode(keyId)).Msg("decode");
1286
- if (import_base582.base58btc.encode(keyId) !== fprt) {
1287
- throw this.ko.logger.Error().Str("fp", fprt).Str("keyId", import_base582.base58btc.encode(keyId)).Msg("keyId mismatch").AsError();
1288
- }
1289
- const result = await this.ko._decrypt({ iv, bytes: data });
1290
- if (!this.opts?.noIVVerify && !await getGenerateIVFn(this.ko.url, this.opts).verify(this.ko, this.ko.crypto, iv, result)) {
1291
- throw this.ko.logger.Error().Msg("iv missmatch").AsError();
1292
- }
1293
- return result;
1252
+ // ready: Promise<void>;
1253
+ ready() {
1254
+ return Promise.resolve();
1294
1255
  }
1295
- };
1296
- var keyedCrypto = class {
1297
- constructor(url, key, cyopt, sthis) {
1298
- this.ivLength = 12;
1299
- this.isEncrypting = true;
1300
- this.logger = ensureLogger(sthis, "keyedCrypto");
1301
- this.crypto = cyopt;
1302
- this.key = key;
1303
- this.url = url;
1256
+ async close() {
1304
1257
  }
1305
- fingerPrint() {
1306
- return Promise.resolve(this.key.fingerPrint);
1258
+ async destroy() {
1307
1259
  }
1308
- codec(iv, opts) {
1309
- return new BlockIvKeyIdCodec(this, iv, opts);
1260
+ async compact() {
1310
1261
  }
1311
- algo(iv) {
1312
- return {
1313
- name: "AES-GCM",
1314
- iv: iv || this.crypto.randomBytes(this.ivLength),
1315
- tagLength: 128
1316
- };
1262
+ async get(cid) {
1263
+ if (!cid) throw this.logger.Error().Msg("required cid").AsError();
1264
+ for (const f of this.transactions) {
1265
+ const v = await f.superGet(cid);
1266
+ if (v) return v;
1267
+ }
1317
1268
  }
1318
- async _decrypt(data) {
1319
- this.logger.Debug().Len(data.bytes, "bytes").Len(data.iv, "iv").Str("fp", this.key.fingerPrint).Msg("decrypting");
1320
- return new Uint8Array(await this.crypto.decrypt(this.algo(data.iv), this.key.key, data.bytes));
1269
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1270
+ async put(cid, block) {
1271
+ throw this.logger.Error().Msg("use a transaction to put").AsError();
1321
1272
  }
1322
- async _encrypt(data) {
1323
- this.logger.Debug().Len(data.bytes).Str("fp", this.key.fingerPrint).Msg("encrypting");
1324
- const a = this.algo(data.iv);
1325
- return new Uint8Array(await this.crypto.encrypt(a, this.key.key, data.bytes));
1273
+ // TransactionMeta
1274
+ async transaction(fn, _opts) {
1275
+ const t = new CarTransaction(this, _opts);
1276
+ const done = await fn(t);
1277
+ this.lastTxMeta = done;
1278
+ return { t, meta: done };
1326
1279
  }
1327
- };
1328
- var nullCodec = class {
1329
- constructor() {
1330
- this.code = 0;
1331
- this.name = "Fireproof@unencrypted-block";
1280
+ openTransaction(opts = { add: true, noLoader: false }) {
1281
+ return new CarTransaction(this, opts);
1332
1282
  }
1333
- encode(data) {
1334
- return data;
1283
+ async commitTransaction(t, done, opts) {
1284
+ if (!this.loader) throw this.logger.Error().Msg("loader required to commit").AsError();
1285
+ const cars = await this.loader?.commit(t, done, opts);
1286
+ if (this.ebOpts.autoCompact && this.loader.carLog.length > this.ebOpts.autoCompact) {
1287
+ setTimeout(() => void this.compact(), 10);
1288
+ }
1289
+ if (cars) {
1290
+ this.transactions.delete(t);
1291
+ return { meta: done, cars, t };
1292
+ }
1293
+ throw this.logger.Error().Msg("failed to commit car files").AsError();
1335
1294
  }
1336
- decode(data) {
1337
- return data;
1295
+ async *entries() {
1296
+ const seen = /* @__PURE__ */ new Set();
1297
+ for (const t of this.transactions) {
1298
+ for await (const blk of t.entries()) {
1299
+ if (seen.has(blk.cid.toString())) continue;
1300
+ seen.add(blk.cid.toString());
1301
+ yield blk;
1302
+ }
1303
+ }
1338
1304
  }
1339
1305
  };
1340
- var noCrypto = class {
1341
- constructor(url, cyrt, sthis) {
1342
- this.ivLength = 0;
1343
- this.code = 0;
1344
- this.name = "Fireproof@unencrypted-block";
1345
- this.isEncrypting = false;
1346
- this._fingerPrint = "noCrypto:" + Math.random();
1347
- this.logger = ensureLogger(sthis, "noCrypto");
1348
- this.crypto = cyrt;
1349
- this.url = url;
1350
- }
1351
- fingerPrint() {
1352
- return Promise.resolve(this._fingerPrint);
1306
+ var EncryptedBlockstore = class extends BaseBlockstore {
1307
+ constructor(sthis, ebOpts) {
1308
+ super(ebOpts);
1309
+ this.compacting = false;
1310
+ this.logger = ensureLogger(this.sthis, "EncryptedBlockstore");
1311
+ const { name } = ebOpts;
1312
+ if (!name) {
1313
+ throw this.logger.Error().Msg("name required").AsError();
1314
+ }
1315
+ this.name = name;
1316
+ this.loader = new Loader(this.name, ebOpts, sthis);
1353
1317
  }
1354
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1355
- codec(iv) {
1356
- return new nullCodec();
1318
+ ready() {
1319
+ return this.loader.ready();
1357
1320
  }
1358
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1359
- algo(iv) {
1360
- return {
1361
- name: "noCrypto",
1362
- iv: new Uint8Array(),
1363
- tagLength: 0
1364
- };
1321
+ close() {
1322
+ return this.loader.close();
1365
1323
  }
1366
- _decrypt() {
1367
- throw this.logger.Error().Msg("noCrypto.decrypt not implemented").AsError();
1324
+ destroy() {
1325
+ return this.loader.destroy();
1368
1326
  }
1369
- _encrypt() {
1370
- throw this.logger.Error().Msg("noCrypto.decrypt not implemented").AsError();
1327
+ async get(cid) {
1328
+ const got = await super.get(cid);
1329
+ if (got) return got;
1330
+ if (!this.loader) {
1331
+ return;
1332
+ }
1333
+ return falsyToUndef(await this.loader.getBlock(cid));
1371
1334
  }
1372
- };
1373
- async function keyedCryptoFactory(url, kb, sthis) {
1374
- const storekey = url.getParam("storekey" /* STORE_KEY */);
1375
- if (storekey && storekey !== "insecure") {
1376
- let rkey = await kb.getNamedKey(storekey, true);
1377
- if (rkey.isErr()) {
1378
- try {
1379
- rkey = await kb.toKeyWithFingerPrint(storekey);
1380
- } catch (e) {
1381
- throw sthis.logger.Error().Err(e).Str("keybag", kb.rt.id()).Str("name", storekey).Msg("getNamedKey failed").AsError();
1382
- }
1335
+ async transaction(fn, opts = { noLoader: false }) {
1336
+ const { t, meta: done } = await super.transaction(fn);
1337
+ const cars = await this.loader.commit(t, done, opts);
1338
+ if (this.ebOpts.autoCompact && this.loader.carLog.length > this.ebOpts.autoCompact) {
1339
+ setTimeout(() => void this.compact(), 10);
1383
1340
  }
1384
- return new keyedCrypto(url, rkey.Ok(), kb.rt.crypto, sthis);
1341
+ if (cars) {
1342
+ this.transactions.delete(t);
1343
+ return { meta: done, cars, t };
1344
+ }
1345
+ throw this.logger.Error().Msg("failed to commit car files").AsError();
1385
1346
  }
1386
- return new noCrypto(url, kb.rt.crypto, sthis);
1387
- }
1388
-
1389
- // src/blockstore/fragment-gateway.ts
1390
- var import_cement3 = require("@adviser/cement");
1391
- var import_base583 = require("multiformats/bases/base58");
1392
- var import_cborg = require("cborg");
1393
- init_types();
1394
- init_utils();
1395
- function getFragSize(url) {
1396
- const fragSize = url.getParam("fragSize" /* FRAG_SIZE */);
1397
- let ret = 0;
1398
- if (fragSize) {
1399
- ret = parseInt(fragSize);
1400
- }
1401
- if (isNaN(ret) || ret <= 0) {
1402
- ret = 0;
1403
- }
1404
- return ret;
1405
- }
1406
- async function getFrags(url, innerGW, headerSize, logger) {
1407
- const fragSize = getFragSize(url);
1408
- if (!fragSize) {
1409
- const res = await innerGW.get(url);
1410
- if (res.isErr()) {
1411
- return [res];
1412
- }
1413
- const data = res.unwrap();
1414
- return [
1415
- import_cement3.Result.Ok({
1416
- fid: new Uint8Array(0),
1417
- ofs: 0,
1418
- len: data.length,
1419
- data
1420
- })
1421
- ];
1422
- }
1423
- const firstRaw = await innerGW.get(url.build().setParam("ofs", "0").URI());
1424
- if (firstRaw.isErr()) {
1425
- return [firstRaw];
1426
- }
1427
- const firstFragment = (0, import_cborg.decode)(firstRaw.unwrap());
1428
- const blockSize = firstFragment.data.length;
1429
- const ops = [Promise.resolve(import_cement3.Result.Ok(firstFragment))];
1430
- const fidStr = import_base583.base58btc.encode(firstFragment.fid);
1431
- const fragUrl = url.build().setParam("fid" /* FRAG_FID */, fidStr).setParam("len" /* FRAG_LEN */, firstFragment.len.toString()).setParam("headerSize" /* FRAG_HEAD */, headerSize.toString());
1432
- for (let ofs = blockSize; ofs < firstFragment.len; ofs += blockSize) {
1433
- ops.push(
1434
- (async (furl, ofs2) => {
1435
- const raw2 = await innerGW.get(furl);
1436
- if (raw2.isErr()) {
1437
- return raw2;
1438
- }
1439
- const fragment = (0, import_cborg.decode)(raw2.unwrap());
1440
- if (import_base583.base58btc.encode(fragment.fid) !== fidStr) {
1441
- return import_cement3.Result.Err(logger.Error().Msg("Fragment fid mismatch").AsError());
1442
- }
1443
- if (fragment.ofs !== ofs2) {
1444
- return import_cement3.Result.Err(logger.Error().Uint64("ofs", ofs2).Msg("Fragment ofs mismatch").AsError());
1445
- }
1446
- return import_cement3.Result.Ok(fragment);
1447
- })(fragUrl.setParam("ofs", ofs.toString()).URI(), ofs)
1347
+ async getFile(car, cid) {
1348
+ await this.ready();
1349
+ if (!this.loader) throw this.logger.Error().Msg("loader required to get file, database must be named").AsError();
1350
+ const reader = await this.loader.loadFileCar(
1351
+ car
1352
+ /*, isPublic */
1448
1353
  );
1354
+ const block = await reader.get(cid);
1355
+ if (!block) throw this.logger.Error().Str("cid", cid.toString()).Msg(`Missing block`).AsError();
1356
+ return block.bytes;
1449
1357
  }
1450
- return Promise.all(ops);
1451
- }
1452
- var FragmentGateway = class {
1453
- constructor(sthis, innerGW) {
1454
- this.fidLength = 4;
1455
- this.headerSize = 32;
1456
- this.sthis = ensureSuperLog(sthis, "FragmentGateway");
1457
- this.logger = this.sthis.logger;
1458
- this.innerGW = innerGW;
1358
+ async compact() {
1359
+ await this.ready();
1360
+ if (!this.loader) throw this.logger.Error().Msg("loader required to compact").AsError();
1361
+ if (this.loader.carLog.length < 2) return;
1362
+ const compactFn = this.ebOpts.compact || ((blocks) => this.defaultCompact(blocks, this.logger));
1363
+ if (!compactFn || this.compacting) return;
1364
+ const blockLog = new CompactionFetcher(this);
1365
+ this.compacting = true;
1366
+ const meta = await compactFn(blockLog);
1367
+ await this.loader?.commit(blockLog.loggedBlocks, meta, {
1368
+ compact: true,
1369
+ noLoader: true
1370
+ });
1371
+ this.compacting = false;
1459
1372
  }
1460
- slicer(url, body) {
1461
- const fragSize = getFragSize(url);
1462
- if (!fragSize) {
1463
- return [this.innerGW.put(url, body)];
1373
+ async defaultCompact(blocks, logger) {
1374
+ if (!this.loader) {
1375
+ throw logger.Error().Msg("no loader").AsError();
1464
1376
  }
1465
- const blocksize = fragSize - this.headerSize;
1466
- if (blocksize <= 0) {
1467
- throw this.logger.Error().Uint64("fragSize" /* FRAG_SIZE */, fragSize).Uint64("headerSize" /* FRAG_HEAD */, this.headerSize).Msg("Fragment size is too small").AsError();
1377
+ if (!this.lastTxMeta) {
1378
+ throw logger.Error().Msg("no lastTxMeta").AsError();
1468
1379
  }
1469
- const ops = [];
1470
- const fid = this.sthis.nextId(this.fidLength);
1471
- const fragUrl = url.build().setParam("fid" /* FRAG_FID */, fid.str).setParam("len" /* FRAG_LEN */, body.length.toString()).setParam("headerSize" /* FRAG_HEAD */, this.headerSize.toString());
1472
- for (let ofs = 0; ofs < body.length; ofs += blocksize) {
1473
- const block = (0, import_cborg.encode)({
1474
- fid: fid.bin,
1475
- ofs,
1476
- len: body.length,
1477
- data: body.slice(ofs, ofs + blocksize)
1478
- });
1479
- if (block.length > fragSize) {
1480
- throw this.logger.Error().Uint64("block", block.length).Uint64("fragSize", fragSize).Msg("Block size to big").AsError();
1380
+ for await (const blk of this.loader.entries(false)) {
1381
+ blocks.loggedBlocks.putSync(blk.cid, blk.bytes);
1382
+ }
1383
+ for (const t of this.transactions) {
1384
+ for await (const blk of t.entries()) {
1385
+ blocks.loggedBlocks.putSync(blk.cid, blk.bytes);
1481
1386
  }
1482
- ops.push(this.innerGW.put(fragUrl.setParam("ofs", ofs.toString()).URI(), block));
1483
1387
  }
1484
- return ops;
1485
- }
1486
- buildUrl(baseUrl, key) {
1487
- return this.innerGW.buildUrl(baseUrl, key);
1488
- }
1489
- async destroy(iurl) {
1490
- return this.innerGW.destroy(iurl);
1388
+ return this.lastTxMeta;
1491
1389
  }
1492
- async start(url) {
1493
- this.headerSize = (0, import_cborg.encode)({
1494
- fid: this.sthis.nextId(this.fidLength).bin,
1495
- ofs: 1024 * 1024,
1496
- // 32bit
1497
- len: 16 * 1024 * 1024,
1498
- // 32bit
1499
- data: new Uint8Array(1024)
1500
- }).length - 1024;
1501
- return this.innerGW.start(url);
1390
+ async *entries() {
1391
+ for await (const blk of this.loader.entries()) {
1392
+ yield blk;
1393
+ }
1502
1394
  }
1503
- async close(url) {
1504
- return this.innerGW.close(url);
1395
+ };
1396
+ var CompactionFetcher = class {
1397
+ constructor(blocks) {
1398
+ this.blockstore = blocks;
1399
+ this.loggedBlocks = new CarTransaction(blocks);
1505
1400
  }
1506
- async put(url, body) {
1507
- await Promise.all(this.slicer(url, body));
1508
- return import_cement3.Result.Ok(void 0);
1401
+ async get(cid) {
1402
+ const block = await this.blockstore.get(cid);
1403
+ if (block) this.loggedBlocks.putSync(cid, block.bytes);
1404
+ return falsyToUndef(block);
1509
1405
  }
1510
- async get(url) {
1511
- const rfrags = await getFrags(url, this.innerGW, this.headerSize, this.logger);
1512
- let buffer = void 0;
1513
- for (const rfrag of rfrags) {
1514
- if (rfrag.isErr()) {
1515
- return import_cement3.Result.Err(rfrag.Err());
1516
- }
1517
- const frag = rfrag.Ok();
1518
- buffer = buffer || new Uint8Array(frag.len);
1519
- buffer.set(frag.data, frag.ofs);
1520
- }
1521
- return import_cement3.Result.Ok(buffer || new Uint8Array(0));
1406
+ };
1407
+
1408
+ // src/blockstore/commit-queue.ts
1409
+ var import_cement3 = require("@adviser/cement");
1410
+ var CommitQueue = class {
1411
+ constructor() {
1412
+ this.queue = [];
1413
+ this.processing = false;
1414
+ this._waitIdleItems = /* @__PURE__ */ new Set();
1522
1415
  }
1523
- async subscribe(url, callback) {
1524
- if (this.innerGW.subscribe) {
1525
- return this.innerGW.subscribe(url, callback);
1526
- } else {
1527
- return import_cement3.Result.Err(this.logger.Error().Url(url).Msg("subscribe not supported").AsError());
1416
+ waitIdle() {
1417
+ if (this.queue.length === 0 && !this.processing) {
1418
+ return Promise.resolve();
1528
1419
  }
1420
+ const fn = new import_cement3.Future();
1421
+ this._waitIdleItems.add(fn);
1422
+ return fn.asPromise();
1529
1423
  }
1530
- async delete(url) {
1531
- const rfrags = await getFrags(url, this.innerGW, this.headerSize, this.logger);
1532
- for (const rfrag of rfrags) {
1533
- if (rfrag.isErr()) {
1534
- return import_cement3.Result.Err(rfrag.Err());
1424
+ async enqueue(fn) {
1425
+ return new Promise((resolve, reject) => {
1426
+ const queueFn = async () => {
1427
+ try {
1428
+ resolve(await fn());
1429
+ } catch (e) {
1430
+ reject(e);
1431
+ } finally {
1432
+ this.processing = false;
1433
+ this.processNext();
1434
+ }
1435
+ };
1436
+ this.queue.push(queueFn);
1437
+ if (!this.processing) {
1438
+ this.processNext();
1535
1439
  }
1536
- const frag = rfrag.Ok();
1537
- let fragUrl;
1538
- if (rfrags.length > 1) {
1539
- const fidStr = import_base583.base58btc.encode(frag.fid);
1540
- fragUrl = url.build().setParam("fid" /* FRAG_FID */, fidStr).setParam("len" /* FRAG_LEN */, frag.len.toString()).setParam("headerSize" /* FRAG_HEAD */, this.headerSize.toString()).URI();
1541
- } else {
1542
- fragUrl = url;
1440
+ });
1441
+ }
1442
+ processNext() {
1443
+ if (this.queue.length > 0 && !this.processing) {
1444
+ this.processing = true;
1445
+ const queueFn = this.queue.shift();
1446
+ if (queueFn) {
1447
+ queueFn().finally(() => {
1448
+ });
1543
1449
  }
1544
- await this.innerGW.delete(fragUrl);
1545
1450
  }
1546
- return import_cement3.Result.Ok(void 0);
1451
+ if (this.queue.length === 0 && !this.processing) {
1452
+ const toResolve = Array.from(this._waitIdleItems);
1453
+ this._waitIdleItems.clear();
1454
+ toResolve.map((fn) => fn.resolve());
1455
+ }
1547
1456
  }
1548
1457
  };
1549
1458
 
1550
- // src/blockstore/meta-key-helper.ts
1551
- var import_dag_json = require("@ipld/dag-json");
1552
- var import_clock = require("@web3-storage/pail/clock");
1553
- var import_multiformats = require("multiformats");
1554
- var import_base64 = require("multiformats/bases/base64");
1555
- var import_cement7 = require("@adviser/cement");
1556
-
1557
1459
  // src/runtime/key-bag.ts
1558
1460
  var key_bag_exports = {};
1559
1461
  __export(key_bag_exports, {
1560
1462
  KeyBag: () => KeyBag,
1561
- defaultKeyBagOpts: () => defaultKeyBagOpts,
1562
1463
  getKeyBag: () => getKeyBag,
1563
1464
  registerKeyBagProviderFactory: () => registerKeyBagProviderFactory
1564
1465
  });
1565
1466
  var import_cement6 = require("@adviser/cement");
1566
1467
  init_utils();
1567
- var import_base584 = require("multiformats/bases/base58");
1568
- init_types();
1468
+ var import_base582 = require("multiformats/bases/base58");
1569
1469
  var KeyBag = class {
1570
1470
  constructor(rt) {
1571
1471
  this.rt = rt;
1572
1472
  this._warnOnce = new import_cement6.ResolveOnce();
1573
1473
  this._seq = new import_cement6.ResolveSeq();
1574
- this.logger = ensureLogger(rt.sthis, "KeyBag", {
1575
- id: rt.id()
1576
- });
1474
+ this.logger = ensureLogger(rt.sthis, "KeyBag");
1577
1475
  this.logger.Debug().Msg("KeyBag created");
1578
1476
  }
1579
1477
  async subtleKey(key) {
@@ -1586,7 +1484,7 @@ var KeyBag = class {
1586
1484
  return await this.rt.crypto.importKey(
1587
1485
  "raw",
1588
1486
  // raw or jwk
1589
- import_base584.base58btc.decode(key),
1487
+ import_base582.base58btc.decode(key),
1590
1488
  // hexStringToUint8Array(key), // raw data
1591
1489
  "AES-GCM",
1592
1490
  extractable,
@@ -1594,7 +1492,7 @@ var KeyBag = class {
1594
1492
  );
1595
1493
  }
1596
1494
  async ensureKeyFromUrl(url, keyFactory) {
1597
- const storeKey = url.getParam("storekey" /* STORE_KEY */);
1495
+ const storeKey = url.getParam("storekey");
1598
1496
  if (storeKey === "insecure") {
1599
1497
  return import_cement6.Result.Ok(url);
1600
1498
  }
@@ -1604,7 +1502,7 @@ var KeyBag = class {
1604
1502
  if (ret.isErr()) {
1605
1503
  return ret;
1606
1504
  }
1607
- const urb = url.build().setParam("storekey" /* STORE_KEY */, keyName);
1505
+ const urb = url.build().setParam("storekey", keyName);
1608
1506
  return import_cement6.Result.Ok(urb.URI());
1609
1507
  }
1610
1508
  if (storeKey.startsWith("@") && storeKey.endsWith("@")) {
@@ -1616,12 +1514,12 @@ var KeyBag = class {
1616
1514
  return import_cement6.Result.Ok(url);
1617
1515
  }
1618
1516
  async toKeyWithFingerPrint(keyStr) {
1619
- const material = import_base584.base58btc.decode(keyStr);
1517
+ const material = import_base582.base58btc.decode(keyStr);
1620
1518
  const key = await this.subtleKey(keyStr);
1621
1519
  const fpr = await this.rt.crypto.digestSHA256(material);
1622
1520
  return import_cement6.Result.Ok({
1623
1521
  key,
1624
- fingerPrint: import_base584.base58btc.encode(new Uint8Array(fpr))
1522
+ fingerPrint: import_base582.base58btc.encode(new Uint8Array(fpr))
1625
1523
  });
1626
1524
  }
1627
1525
  async setNamedKey(name, key) {
@@ -1650,7 +1548,7 @@ var KeyBag = class {
1650
1548
  const ext = new Uint8Array(await this.rt.crypto.exportKey("raw", named.key));
1651
1549
  return {
1652
1550
  key: ext,
1653
- keyStr: import_base584.base58btc.encode(ext)
1551
+ keyStr: import_base582.base58btc.encode(ext)
1654
1552
  };
1655
1553
  }
1656
1554
  });
@@ -1669,7 +1567,7 @@ var KeyBag = class {
1669
1567
  this.logger.Debug().Str("id", id).Str("name", name).Msg("failIfNotFound getNamedKey");
1670
1568
  return import_cement6.Result.Err(new Error(`Key not found: ${name}`));
1671
1569
  }
1672
- const ret = await this._setNamedKey(name, import_base584.base58btc.encode(this.rt.crypto.randomBytes(this.rt.keyLength)));
1570
+ const ret = await this._setNamedKey(name, import_base582.base58btc.encode(this.rt.crypto.randomBytes(this.rt.keyLength)));
1673
1571
  this.logger.Debug().Str("id", id).Str("name", name).Result("fpr", ret).Msg("createKey getNamedKey-post");
1674
1572
  return ret;
1675
1573
  });
@@ -1701,7 +1599,6 @@ function registerKeyBagProviderFactory(item) {
1701
1599
  });
1702
1600
  }
1703
1601
  function defaultKeyBagOpts(sthis, kbo) {
1704
- kbo = kbo || {};
1705
1602
  if (kbo.keyRuntime) {
1706
1603
  return kbo.keyRuntime;
1707
1604
  }
@@ -1725,29 +1622,11 @@ function defaultKeyBagOpts(sthis, kbo) {
1725
1622
  }
1726
1623
  logger.Debug().Url(url).Msg("from env");
1727
1624
  }
1728
- let keyProviderFactory;
1729
- switch (url.protocol) {
1730
- case "file:":
1731
- keyProviderFactory = async () => {
1732
- const { KeyBagProviderFile: KeyBagProviderFile2 } = await Promise.resolve().then(() => (init_key_bag_file(), key_bag_file_exports));
1733
- return new KeyBagProviderFile2(url, sthis);
1734
- };
1735
- break;
1736
- case "indexdb:":
1737
- keyProviderFactory = async () => {
1738
- const { KeyBagProviderIndexDB: KeyBagProviderIndexDB2 } = await Promise.resolve().then(() => (init_key_bag_indexdb(), key_bag_indexdb_exports));
1739
- return new KeyBagProviderIndexDB2(url, sthis);
1740
- };
1741
- break;
1742
- case "memory:":
1743
- keyProviderFactory = async () => {
1744
- const { KeyBagProviderMemory: KeyBagProviderMemory2 } = await Promise.resolve().then(() => (init_key_bag_memory(), key_bag_memory_exports));
1745
- return new KeyBagProviderMemory2(url, sthis);
1746
- };
1747
- break;
1748
- default:
1749
- throw logger.Error().Url(url).Msg("unsupported protocol").AsError();
1625
+ const kitem = keyBagProviderFactories.get(url.protocol);
1626
+ if (!kitem) {
1627
+ throw logger.Error().Url(url).Msg("unsupported protocol").AsError();
1750
1628
  }
1629
+ const getBag = async () => kitem.factory(url, sthis);
1751
1630
  if (url.hasParam("masterkey")) {
1752
1631
  throw logger.Error().Url(url).Msg("masterkey is not supported").AsError();
1753
1632
  }
@@ -1757,7 +1636,7 @@ function defaultKeyBagOpts(sthis, kbo) {
1757
1636
  sthis,
1758
1637
  logger,
1759
1638
  keyLength: kbo.keyLength || 16,
1760
- getBag: keyProviderFactory,
1639
+ getBag,
1761
1640
  id: () => {
1762
1641
  return url.toString();
1763
1642
  }
@@ -1770,943 +1649,939 @@ async function getKeyBag(sthis, kbo = {}) {
1770
1649
  return _keyBags.get(rt.id()).once(async () => new KeyBag(rt));
1771
1650
  }
1772
1651
 
1773
- // src/blockstore/meta-key-helper.ts
1774
- async function decodeGatewayMetaBytesToDbMeta(sthis, byteHeads) {
1775
- const crdtEntries = JSON.parse(sthis.txt.decode(byteHeads));
1776
- if (!crdtEntries.length) {
1777
- sthis.logger.Debug().Str("byteHeads", new TextDecoder().decode(byteHeads)).Msg("No CRDT entries found");
1778
- return [];
1652
+ // src/blockstore/commitor.ts
1653
+ var CBW = __toESM(require("@ipld/car/buffer-writer"), 1);
1654
+ var import_sha22 = require("multiformats/hashes/sha2");
1655
+ var dagCodec2 = __toESM(require("@ipld/dag-cbor"), 1);
1656
+ async function encodeCarFile(roots, t, codec3) {
1657
+ let size = 0;
1658
+ const headerSize = CBW.headerLength({ roots });
1659
+ size += headerSize;
1660
+ for (const { cid, bytes } of t.entries()) {
1661
+ size += CBW.blockLength({ cid, bytes });
1779
1662
  }
1780
- if (!crdtEntries.map) {
1781
- sthis.logger.Debug().Str("crdtEntries", JSON.stringify(crdtEntries)).Msg("No data in CRDT entries");
1782
- return [];
1663
+ const buffer = new Uint8Array(size);
1664
+ const writer = CBW.createWriter(buffer, { headerSize });
1665
+ for (const r of roots) {
1666
+ writer.addRoot(r);
1783
1667
  }
1784
- return Promise.all(
1785
- crdtEntries.map(async (crdtEntry) => {
1786
- const eventBlock = await (0, import_clock.decodeEventBlock)(import_base64.base64pad.decode(crdtEntry.data));
1787
- const dbMeta = (0, import_dag_json.parse)(sthis.txt.decode(eventBlock.value.data.dbMeta));
1788
- return {
1789
- eventCid: eventBlock.cid,
1790
- parents: crdtEntry.parents,
1791
- dbMeta
1792
- };
1793
- })
1794
- );
1668
+ for (const { cid, bytes } of t.entries()) {
1669
+ writer.write({ cid, bytes });
1670
+ }
1671
+ writer.close();
1672
+ return await encode({ value: writer.bytes, hasher: import_sha22.sha256, codec: codec3 });
1795
1673
  }
1796
- async function setCryptoKeyFromGatewayMetaPayload(uri, sthis, data) {
1797
- try {
1798
- sthis.logger.Debug().Str("uri", uri.toString()).Msg("Setting crypto key from gateway meta payload");
1799
- const keyInfo = await decodeGatewayMetaBytesToDbMeta(sthis, data);
1800
- if (keyInfo.length) {
1801
- const dbMeta = keyInfo[0].dbMeta;
1802
- if (dbMeta.key) {
1803
- const kb = await getKeyBag(sthis);
1804
- const keyName = getStoreKeyName(uri);
1805
- const res = await kb.setNamedKey(keyName, dbMeta.key);
1806
- if (res.isErr()) {
1807
- sthis.logger.Debug().Str("keyName", keyName).Str("dbMeta.key", dbMeta.key).Msg("Failed to set named key");
1808
- throw res.Err();
1809
- }
1810
- }
1811
- sthis.logger.Debug().Str("dbMeta.key", dbMeta.key).Str("uri", uri.toString()).Msg("Set crypto key from gateway meta payload");
1812
- return import_cement7.Result.Ok(dbMeta);
1813
- }
1814
- sthis.logger.Debug().Str("data", new TextDecoder().decode(data)).Msg("No crypto in gateway meta payload");
1815
- return import_cement7.Result.Ok(void 0);
1816
- } catch (error) {
1817
- sthis.logger.Debug().Err(error).Msg("Failed to set crypto key from gateway meta payload");
1818
- return import_cement7.Result.Err(error);
1674
+ async function createCarFile(encoder, cid, t) {
1675
+ return encodeCarFile([cid], t, encoder);
1676
+ }
1677
+ async function commitFiles(fileStore, walStore, t, done) {
1678
+ const { files: roots } = makeFileCarHeader(done);
1679
+ const cids = [];
1680
+ const codec3 = (await fileStore.keyedCrypto()).codec();
1681
+ const cars = await prepareCarFilesFiles(codec3, roots, t);
1682
+ for (const car of cars) {
1683
+ const { cid, bytes } = car;
1684
+ await fileStore.save({ cid, bytes });
1685
+ await walStore.enqueueFile(
1686
+ cid
1687
+ /*, !!opts.public*/
1688
+ );
1689
+ cids.push(cid);
1819
1690
  }
1691
+ return cids;
1820
1692
  }
1821
- async function addCryptoKeyToGatewayMetaPayload(uri, sthis, body) {
1822
- try {
1823
- sthis.logger.Debug().Str("uri", uri.toString()).Msg("Adding crypto key to gateway meta payload");
1824
- const keyName = getStoreKeyName(uri);
1825
- const kb = await getKeyBag(sthis);
1826
- const res = await kb.getNamedExtractableKey(keyName, true);
1827
- if (res.isErr()) {
1828
- sthis.logger.Error().Str("keyName", keyName).Msg("Failed to get named extractable key");
1829
- throw res.Err();
1693
+ function makeFileCarHeader(result) {
1694
+ const files = [];
1695
+ for (const [, meta] of Object.entries(result.files || {})) {
1696
+ if (meta && typeof meta === "object" && "cid" in meta && meta !== null) {
1697
+ files.push(meta.cid);
1830
1698
  }
1831
- const keyData = await res.Ok().extract();
1832
- const dbMetas = await decodeGatewayMetaBytesToDbMeta(sthis, body);
1833
- const { dbMeta, parents } = dbMetas[0];
1834
- const parentLinks = parents.map((p) => import_multiformats.CID.parse(p));
1835
- dbMeta.key = keyData.keyStr;
1836
- const events = await Promise.all([dbMeta].map((dbMeta2) => createDbMetaEventBlock(sthis, dbMeta2, parentLinks)));
1837
- const encoded = await encodeEventsWithParents(sthis, events, parentLinks);
1838
- sthis.logger.Debug().Str("uri", uri.toString()).Msg("Added crypto key to gateway meta payload");
1839
- return import_cement7.Result.Ok(encoded);
1840
- } catch (error) {
1841
- sthis.logger.Error().Err(error).Msg("Failed to add crypto key to gateway meta payload");
1842
- return import_cement7.Result.Err(error);
1843
1699
  }
1700
+ return { ...result, files };
1844
1701
  }
1845
- function getStoreKeyName(url) {
1846
- const storeKeyName = [url.getParam("localName") || url.getParam("name")];
1847
- const idx = url.getParam("index");
1848
- if (idx) {
1849
- storeKeyName.push(idx);
1850
- }
1851
- storeKeyName.push("data");
1852
- return `@${storeKeyName.join(":")}@`;
1702
+ async function prepareCarFilesFiles(encoder, roots, t) {
1703
+ return [await encodeCarFile(roots, t, encoder)];
1853
1704
  }
1854
- async function createDbMetaEventBlock(sthis, dbMeta, parents) {
1855
- const event = await import_clock.EventBlock.create(
1856
- {
1857
- dbMeta: sthis.txt.encode((0, import_dag_json.format)(dbMeta))
1858
- },
1859
- parents
1860
- );
1861
- return event;
1705
+ function makeCarHeader(meta, cars, compact = false) {
1706
+ const coreHeader = compact ? { cars: [], compact: cars } : { cars, compact: [] };
1707
+ return { ...coreHeader, meta };
1862
1708
  }
1863
- async function encodeEventsWithParents(sthis, events, parents) {
1864
- const crdtEntries = events.map((event) => {
1865
- const base64String = import_base64.base64pad.encode(event.bytes);
1866
- return {
1867
- cid: event.cid.toString(),
1868
- data: base64String,
1869
- parents: parents.map((p) => p.toString())
1870
- };
1709
+ async function encodeCarHeader(fp) {
1710
+ return await encode({
1711
+ value: { fp },
1712
+ hasher: import_sha22.sha256,
1713
+ codec: dagCodec2
1871
1714
  });
1872
- return sthis.txt.encode(JSON.stringify(crdtEntries));
1873
- }
1874
-
1875
- // src/blockstore/store.ts
1876
- var import_p_retry = __toESM(require("p-retry"), 1);
1877
- var import_p_map = __toESM(require("p-map"), 1);
1878
-
1879
- // src/blockstore/loader.ts
1880
- var import_p_limit = __toESM(require("p-limit"), 1);
1881
- var import_car = require("@ipld/car");
1882
- var import_cement9 = require("@adviser/cement");
1883
-
1884
- // src/runtime/wait-pr-multiformats/block.ts
1885
- var block_exports = {};
1886
- __export(block_exports, {
1887
- Block: () => Block,
1888
- create: () => create,
1889
- createUnsafe: () => createUnsafe,
1890
- decode: () => decode3,
1891
- encode: () => encode3
1892
- });
1893
- var import_multiformats2 = require("multiformats");
1894
- var import_block = require("multiformats/block");
1895
- var Block = import_block.Block;
1896
- async function decode3({
1897
- bytes,
1898
- codec: codec3,
1899
- hasher: hasher7
1900
- }) {
1901
- if (bytes == null) throw new Error('Missing required argument "bytes"');
1902
- if (codec3 == null || hasher7 == null) throw new Error("Missing required argument: codec or hasher");
1903
- const value = await Promise.resolve(codec3.decode(bytes));
1904
- const hash = await hasher7.digest(bytes);
1905
- const cid = import_multiformats2.CID.create(1, codec3.code, hash);
1906
- return new import_block.Block({ value, bytes, cid });
1907
- }
1908
- async function encode3({
1909
- value,
1910
- codec: codec3,
1911
- hasher: hasher7
1912
- }) {
1913
- if (typeof value === "undefined") throw new Error('Missing required argument "value"');
1914
- if (codec3 == null || hasher7 == null) throw new Error("Missing required argument: codec or hasher");
1915
- const bytes = await Promise.resolve(codec3.encode(value));
1916
- const hash = await hasher7.digest(bytes);
1917
- const cid = import_multiformats2.CID.create(1, codec3.code, hash);
1918
- return new import_block.Block({ value, bytes, cid });
1919
1715
  }
1920
- async function create({
1921
- bytes,
1922
- cid,
1923
- hasher: hasher7,
1924
- codec: codec3
1925
- }) {
1926
- if (bytes == null) throw new Error('Missing required argument "bytes"');
1927
- if (hasher7 == null) throw new Error('Missing required argument "hasher"');
1928
- const value = await Promise.resolve(codec3.decode(bytes));
1929
- const hash = await hasher7.digest(bytes);
1930
- if (!import_multiformats2.bytes.equals(cid.multihash.bytes, hash.bytes)) {
1931
- throw new Error("CID hash does not match bytes");
1716
+ async function commit(params, t, done, opts = { noLoader: false, compact: false }) {
1717
+ const fp = makeCarHeader(done, params.carLog, !!opts.compact);
1718
+ const rootBlock = await encodeCarHeader(fp);
1719
+ const cars = await prepareCarFiles(params.encoder, params.threshold, rootBlock, t);
1720
+ const cids = [];
1721
+ for (const car of cars) {
1722
+ const { cid, bytes } = car;
1723
+ await params.carStore.save({ cid, bytes });
1724
+ cids.push(cid);
1932
1725
  }
1933
- return createUnsafe({
1934
- bytes,
1935
- cid,
1936
- value,
1937
- codec: codec3
1938
- });
1939
- }
1940
- async function createUnsafe({
1941
- bytes,
1942
- cid,
1943
- value: maybeValue,
1944
- codec: codec3
1945
- }) {
1946
- const value = await Promise.resolve(maybeValue !== void 0 ? maybeValue : codec3?.decode(bytes));
1947
- if (value === void 0) throw new Error('Missing required argument, must either provide "value" or "codec"');
1948
- return new Block({
1949
- cid,
1950
- bytes,
1951
- value
1952
- });
1726
+ const newDbMeta = { cars: cids };
1727
+ await params.WALStore.enqueue(newDbMeta, opts);
1728
+ await params.metaStore.save(newDbMeta);
1729
+ return { cgrp: cids, header: fp };
1953
1730
  }
1954
-
1955
- // src/blockstore/loader-helpers.ts
1956
- var import_sha22 = require("multiformats/hashes/sha2");
1957
- var dagCodec = __toESM(require("@ipld/dag-cbor"), 1);
1958
- async function parseCarFile(reader, logger) {
1959
- const roots = await reader.getRoots();
1960
- const header = await reader.get(roots[0]);
1961
- if (!header) throw logger.Error().Msg("missing header block").AsError();
1962
- const dec = await decode3({ bytes: header.bytes, hasher: import_sha22.sha256, codec: dagCodec });
1963
- const fpvalue = dec.value;
1964
- if (fpvalue && !fpvalue.fp) {
1965
- throw logger.Error().Msg("missing fp").AsError();
1731
+ async function prepareCarFiles(encoder, threshold, rootBlock, t) {
1732
+ const carFiles = [];
1733
+ threshold = threshold || 128e3 * 8;
1734
+ let clonedt = new CarTransaction(t.parent, { add: false, noLoader: false });
1735
+ clonedt.putSync(rootBlock.cid, rootBlock.bytes);
1736
+ let newsize = CBW.blockLength(toCIDBlock(rootBlock));
1737
+ let cidRootBlock = rootBlock;
1738
+ for (const { cid, bytes } of t.entries()) {
1739
+ newsize += CBW.blockLength(toCIDBlock({ cid, bytes }));
1740
+ if (newsize >= threshold) {
1741
+ carFiles.push(await createCarFile(encoder, cidRootBlock.cid, clonedt));
1742
+ clonedt = new CarTransaction(t.parent, { add: false, noLoader: false });
1743
+ clonedt.putSync(cid, bytes);
1744
+ cidRootBlock = { cid, bytes };
1745
+ newsize = CBW.blockLength(toCIDBlock({ cid, bytes }));
1746
+ } else {
1747
+ clonedt.putSync(cid, bytes);
1748
+ }
1966
1749
  }
1967
- return fpvalue.fp;
1750
+ carFiles.push(await createCarFile(encoder, cidRootBlock.cid, clonedt));
1751
+ return carFiles;
1968
1752
  }
1969
1753
 
1970
- // src/blockstore/transaction.ts
1971
- var import_block3 = require("@web3-storage/pail/block");
1972
- init_types();
1973
- var import_cement8 = require("@adviser/cement");
1754
+ // src/blockstore/loader.ts
1755
+ var import_sha23 = require("multiformats/hashes/sha2");
1756
+
1757
+ // src/blockstore/task-manager.ts
1974
1758
  init_utils();
1975
- var CarTransaction = class extends import_block3.MemoryBlockstore {
1976
- constructor(parent, opts = { add: true, noLoader: false }) {
1977
- super();
1978
- if (opts.add) {
1979
- parent.transactions.add(this);
1980
- }
1981
- this.parent = parent;
1982
- }
1983
- async get(cid) {
1984
- return await this.superGet(cid) || falsyToUndef(await this.parent.get(cid));
1759
+ var TaskManager = class {
1760
+ constructor(sthis, callback) {
1761
+ this.eventsWeHandled = /* @__PURE__ */ new Set();
1762
+ this.queue = [];
1763
+ this.isProcessing = false;
1764
+ this.logger = ensureLogger(sthis, "TaskManager");
1765
+ this.callback = callback;
1985
1766
  }
1986
- async superGet(cid) {
1987
- return super.get(cid);
1767
+ async handleEvent(cid, parents, dbMeta) {
1768
+ for (const parent of parents) {
1769
+ this.eventsWeHandled.add(parent.toString());
1770
+ }
1771
+ this.queue.push({ cid: cid.toString(), dbMeta, retries: 0 });
1772
+ this.queue = this.queue.filter(({ cid: cid2 }) => !this.eventsWeHandled.has(cid2));
1773
+ void this.processQueue();
1988
1774
  }
1989
- };
1990
- function defaultedBlockstoreRuntime(sthis, opts, component, ctx) {
1991
- const logger = ensureLogger(sthis, component, ctx);
1992
- return {
1993
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1994
- applyMeta: (meta, snap) => {
1995
- return Promise.resolve();
1996
- },
1997
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1998
- compact: async (blocks) => {
1999
- return {};
2000
- },
2001
- autoCompact: 100,
2002
- public: false,
2003
- // name: undefined,
2004
- threshold: 1e3 * 1e3,
2005
- ...opts,
2006
- logger,
2007
- keyBag: opts.keyBag || {},
2008
- crypto: (0, import_cement8.toCryptoRuntime)(opts.crypto),
2009
- storeUrls: opts.storeUrls,
2010
- // storeEnDeFile: ensureStoreEnDeFile(opts.storeEnDeFile),
2011
- // store,
2012
- storeRuntime: toStoreRuntime(sthis, ensureStoreEnDeFile(opts.storeEnDeFile))
2013
- };
1775
+ async processQueue() {
1776
+ if (this.isProcessing) return;
1777
+ this.isProcessing = true;
1778
+ const filteredQueue = this.queue.filter(({ cid }) => !this.eventsWeHandled.has(cid));
1779
+ const first = filteredQueue[0];
1780
+ if (!first) {
1781
+ return;
1782
+ }
1783
+ try {
1784
+ await this.callback(first.dbMeta);
1785
+ this.eventsWeHandled.add(first.cid);
1786
+ this.queue = this.queue.filter(({ cid }) => !this.eventsWeHandled.has(cid));
1787
+ } catch (err) {
1788
+ if (first.retries++ > 3) {
1789
+ this.logger.Error().Str("cid", first.cid).Msg("failed to process event block after 3 retries");
1790
+ this.queue = this.queue.filter(({ cid }) => cid !== first.cid);
1791
+ }
1792
+ await new Promise((resolve) => setTimeout(resolve, 50));
1793
+ throw this.logger.Error().Err(err).Msg("failed to process event block").AsError();
1794
+ } finally {
1795
+ this.isProcessing = false;
1796
+ if (this.queue.length > 0) {
1797
+ void this.processQueue();
1798
+ }
1799
+ }
1800
+ }
1801
+ };
1802
+
1803
+ // src/blockstore/loader.ts
1804
+ function carLogIncludesGroup(list, cids) {
1805
+ return list.some((arr) => {
1806
+ return arr.toString() === cids.toString();
1807
+ });
2014
1808
  }
2015
- function blockstoreFactory(sthis, opts) {
2016
- return new EncryptedBlockstore(sthis, opts);
1809
+ function uniqueCids(list, remove = /* @__PURE__ */ new Set()) {
1810
+ const byString = /* @__PURE__ */ new Map();
1811
+ for (const cid of list) {
1812
+ if (remove.has(cid.toString())) continue;
1813
+ byString.set(cid.toString(), cid);
1814
+ }
1815
+ return [...byString.values()];
2017
1816
  }
2018
- var BaseBlockstore = class {
2019
- constructor(ebOpts) {
2020
- this.transactions = /* @__PURE__ */ new Set();
2021
- this.sthis = ensureSuperThis(ebOpts);
2022
- this.ebOpts = defaultedBlockstoreRuntime(this.sthis, ebOpts, "BaseBlockstore");
2023
- this.sthis = ensureSuperThis(ebOpts);
2024
- this.ebOpts = defaultedBlockstoreRuntime(this.sthis, ebOpts, "BaseBlockstore");
1817
+ var Loader = class {
1818
+ constructor(name, ebOpts, sthis) {
1819
+ this.commitQueue = new CommitQueue();
1820
+ this.isCompacting = false;
1821
+ this.carReaders = /* @__PURE__ */ new Map();
1822
+ this.seenCompacted = /* @__PURE__ */ new Set();
1823
+ this.processedCars = /* @__PURE__ */ new Set();
1824
+ this.carLog = [];
1825
+ this.getBlockCache = /* @__PURE__ */ new Map();
1826
+ this.seenMeta = /* @__PURE__ */ new Set();
1827
+ this.writeLimit = (0, import_p_limit.default)(1);
1828
+ this.onceReady = new import_cement7.ResolveOnce();
1829
+ this.name = name;
1830
+ this.sthis = sthis;
1831
+ this.ebOpts = defaultedBlockstoreRuntime(
1832
+ sthis,
1833
+ {
1834
+ ...ebOpts,
1835
+ name
1836
+ },
1837
+ "Loader"
1838
+ );
2025
1839
  this.logger = this.ebOpts.logger;
1840
+ this.taskManager = new TaskManager(sthis, async (dbMeta) => {
1841
+ await this.handleDbMetasFromStore([dbMeta]);
1842
+ });
2026
1843
  }
2027
- // readonly name?: string;
2028
- // ready: Promise<void>;
2029
- ready() {
2030
- return Promise.resolve();
1844
+ // readonly id = uuidv4();
1845
+ async keyBag() {
1846
+ return getKeyBag(this.sthis, this.ebOpts.keyBag);
1847
+ }
1848
+ async carStore() {
1849
+ return this.ebOpts.storeRuntime.makeDataStore(this);
1850
+ }
1851
+ async fileStore() {
1852
+ return this.ebOpts.storeRuntime.makeDataStore(this);
1853
+ }
1854
+ async WALStore() {
1855
+ return this.ebOpts.storeRuntime.makeWALStore(this);
1856
+ }
1857
+ async metaStore() {
1858
+ return this.ebOpts.storeRuntime.makeMetaStore(this);
1859
+ }
1860
+ async ready() {
1861
+ return this.onceReady.once(async () => {
1862
+ const metas = await (await this.metaStore()).load();
1863
+ if (this.ebOpts.meta) {
1864
+ await this.handleDbMetasFromStore([this.ebOpts.meta]);
1865
+ } else if (metas) {
1866
+ await this.handleDbMetasFromStore(metas);
1867
+ }
1868
+ });
2031
1869
  }
2032
1870
  async close() {
1871
+ const toClose = await Promise.all([this.carStore(), this.metaStore(), this.fileStore(), this.WALStore()]);
1872
+ await Promise.all(toClose.map((store) => store.close()));
2033
1873
  }
2034
1874
  async destroy() {
1875
+ const toDestroy = await Promise.all([this.carStore(), this.metaStore(), this.fileStore(), this.WALStore()]);
1876
+ await Promise.all(toDestroy.map((store) => store.destroy()));
2035
1877
  }
2036
- async compact() {
1878
+ // async snapToCar(carCid: AnyLink | string) {
1879
+ // await this.ready
1880
+ // if (typeof carCid === 'string') {
1881
+ // carCid = CID.parse(carCid)
1882
+ // }
1883
+ // const carHeader = await this.loadCarHeaderFromMeta({ car: carCid, key: this.key || null })
1884
+ // this.carLog = [carCid, ...carHeader.cars]
1885
+ // await this.getMoreReaders(carHeader.cars)
1886
+ // await this._applyCarHeader(carHeader, true)
1887
+ // }
1888
+ async handleDbMetasFromStore(metas) {
1889
+ this.logger.Debug().Any("metas", metas).Msg("handleDbMetasFromStore");
1890
+ for (const meta of metas) {
1891
+ await this.writeLimit(async () => {
1892
+ await this.mergeDbMetaIntoClock(meta);
1893
+ });
1894
+ }
2037
1895
  }
2038
- async get(cid) {
2039
- if (!cid) throw this.logger.Error().Msg("required cid").AsError();
2040
- for (const f of this.transactions) {
2041
- const v = await f.superGet(cid);
2042
- if (v) return v;
1896
+ async mergeDbMetaIntoClock(meta) {
1897
+ if (this.isCompacting) {
1898
+ throw this.logger.Error().Msg("cannot merge while compacting").AsError();
1899
+ }
1900
+ if (this.seenMeta.has(meta.cars.toString())) return;
1901
+ this.seenMeta.add(meta.cars.toString());
1902
+ if (carLogIncludesGroup(this.carLog, meta.cars)) {
1903
+ return;
2043
1904
  }
1905
+ const carHeader = await this.loadCarHeaderFromMeta(meta);
1906
+ carHeader.compact.map((c) => c.toString()).forEach(this.seenCompacted.add, this.seenCompacted);
1907
+ await this.getMoreReaders(carHeader.cars.flat());
1908
+ this.carLog = [...uniqueCids([meta.cars, ...this.carLog, ...carHeader.cars], this.seenCompacted)];
1909
+ await this.ebOpts.applyMeta?.(carHeader.meta);
2044
1910
  }
2045
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2046
- async put(cid, block) {
2047
- throw this.logger.Error().Msg("use a transaction to put").AsError();
1911
+ // protected async ingestKeyFromMeta(meta: DbMeta): Promise<void> {
1912
+ // const { key } = meta;
1913
+ // if (key) {
1914
+ // await this.setKey(key);
1915
+ // }
1916
+ // }
1917
+ async loadCarHeaderFromMeta({ cars: cids }) {
1918
+ const reader = await this.loadCar(cids[0]);
1919
+ return await parseCarFile(reader, this.logger);
2048
1920
  }
2049
- // TransactionMeta
2050
- async transaction(fn, _opts) {
2051
- this.logger.Debug().Msg("enter transaction");
2052
- const t = new CarTransaction(this, _opts);
2053
- this.logger.Debug().Msg("post CarTransaction");
2054
- const done = await fn(t);
2055
- this.logger.Debug().Msg("post fn");
2056
- this.lastTxMeta = done;
2057
- return { t, meta: done };
1921
+ // async _getKey(): Promise<string | undefined> {
1922
+ // if (this.key) return this.key;
1923
+ // // generate a random key
1924
+ // if (!this.ebOpts.public) {
1925
+ // await this.setKey(toHexString(this.ebOpts.crypto.randomBytes(32)));
1926
+ // }
1927
+ // return this.key || undefined;
1928
+ // }
1929
+ async commitFiles(t, done) {
1930
+ await this.ready();
1931
+ const fstore = await this.fileStore();
1932
+ const wstore = await this.WALStore();
1933
+ return this.commitQueue.enqueue(() => commitFiles(fstore, wstore, t, done));
2058
1934
  }
2059
- openTransaction(opts = { add: true, noLoader: false }) {
2060
- return new CarTransaction(this, opts);
1935
+ async loadFileCar(cid) {
1936
+ return await this.storesLoadCar(cid, await this.fileStore(), this.remoteFileStore);
2061
1937
  }
2062
- async commitTransaction(t, done, opts) {
2063
- if (!this.loader) throw this.logger.Error().Msg("loader required to commit").AsError();
2064
- const cars = await this.loader?.commit(t, done, opts);
2065
- if (this.ebOpts.autoCompact && this.loader.carLog.length > this.ebOpts.autoCompact) {
2066
- setTimeout(() => void this.compact(), 10);
1938
+ async commit(t, done, opts = { noLoader: false, compact: false }) {
1939
+ await this.ready();
1940
+ const fstore = await this.fileStore();
1941
+ const params = {
1942
+ encoder: (await fstore.keyedCrypto()).codec(),
1943
+ carLog: this.carLog,
1944
+ carStore: fstore,
1945
+ WALStore: await this.WALStore(),
1946
+ metaStore: await this.metaStore(),
1947
+ threshold: this.ebOpts.threshold
1948
+ };
1949
+ return this.commitQueue.enqueue(async () => {
1950
+ await this.cacheTransaction(t);
1951
+ const ret = await commit(params, t, done, opts);
1952
+ await this.updateCarLog(ret.cgrp, ret.header, !!opts.compact);
1953
+ return ret.cgrp;
1954
+ });
1955
+ }
1956
+ async updateCarLog(cids, fp, compact) {
1957
+ if (compact) {
1958
+ const previousCompactCid = fp.compact[fp.compact.length - 1];
1959
+ fp.compact.map((c) => c.toString()).forEach(this.seenCompacted.add, this.seenCompacted);
1960
+ this.carLog = [...uniqueCids([...this.carLog, ...fp.cars, cids], this.seenCompacted)];
1961
+ await this.removeCidsForCompact(previousCompactCid[0]).catch((e) => e);
1962
+ } else {
1963
+ this.carLog.unshift(cids);
2067
1964
  }
2068
- if (cars) {
2069
- this.transactions.delete(t);
2070
- return { meta: done, cars, t };
1965
+ }
1966
+ async cacheTransaction(t) {
1967
+ for await (const block of t.entries()) {
1968
+ const sBlock = block.cid.toString();
1969
+ if (!this.getBlockCache.has(sBlock)) {
1970
+ this.getBlockCache.set(sBlock, block);
1971
+ }
2071
1972
  }
2072
- throw this.logger.Error().Msg("failed to commit car files").AsError();
2073
1973
  }
2074
- async *entries() {
2075
- const seen = /* @__PURE__ */ new Set();
2076
- for (const t of this.transactions) {
2077
- for await (const blk of t.entries()) {
2078
- if (seen.has(blk.cid.toString())) continue;
2079
- seen.add(blk.cid.toString());
2080
- yield blk;
1974
+ async cacheCarReader(carCidStr, reader) {
1975
+ if (this.processedCars.has(carCidStr)) return;
1976
+ this.processedCars.add(carCidStr);
1977
+ for await (const block of reader.blocks()) {
1978
+ const sBlock = block.cid.toString();
1979
+ if (!this.getBlockCache.has(sBlock)) {
1980
+ this.getBlockCache.set(sBlock, block);
2081
1981
  }
2082
1982
  }
2083
1983
  }
2084
- };
2085
- var EncryptedBlockstore = class extends BaseBlockstore {
2086
- constructor(sthis, ebOpts) {
2087
- super(ebOpts);
2088
- this.compacting = false;
2089
- this.logger = ensureLogger(this.sthis, "EncryptedBlockstore", {
2090
- this: 1
1984
+ async removeCidsForCompact(cid) {
1985
+ const carHeader = await this.loadCarHeaderFromMeta({
1986
+ cars: [cid]
2091
1987
  });
2092
- this.loader = new Loader(sthis, ebOpts);
1988
+ for (const cids of carHeader.compact) {
1989
+ for (const cid2 of cids) {
1990
+ await (await this.carStore()).remove(cid2);
1991
+ }
1992
+ }
2093
1993
  }
2094
- ready() {
2095
- return this.loader.ready();
1994
+ // async flushCars() {
1995
+ // await this.ready
1996
+ // // for each cid in car log, make a dbMeta
1997
+ // for (const cid of this.carLog) {
1998
+ // const dbMeta = { car: cid, key: this.key || null } as DbMeta
1999
+ // await this.remoteWAL!.enqueue(dbMeta, { public: false })
2000
+ // }
2001
+ // }
2002
+ async *entries(cache2 = true) {
2003
+ await this.ready();
2004
+ if (cache2) {
2005
+ for (const [, block] of this.getBlockCache) {
2006
+ yield block;
2007
+ }
2008
+ } else {
2009
+ for (const [, block] of this.getBlockCache) {
2010
+ yield block;
2011
+ }
2012
+ for (const cids of this.carLog) {
2013
+ for (const cid of cids) {
2014
+ const reader = await this.loadCar(cid);
2015
+ if (!reader) throw this.logger.Error().Ref("cid", cid).Msg("missing car reader").AsError();
2016
+ for await (const block of reader.blocks()) {
2017
+ const sCid = block.cid.toString();
2018
+ if (!this.getBlockCache.has(sCid)) {
2019
+ yield block;
2020
+ }
2021
+ }
2022
+ }
2023
+ }
2024
+ }
2096
2025
  }
2097
- close() {
2098
- return this.loader.close();
2026
+ async getBlock(cid) {
2027
+ await this.ready();
2028
+ const sCid = cid.toString();
2029
+ if (this.getBlockCache.has(sCid)) return this.getBlockCache.get(sCid);
2030
+ const getCarCid = async (carCid) => {
2031
+ if (this.getBlockCache.has(sCid)) return this.getBlockCache.get(sCid);
2032
+ const reader = await this.loadCar(carCid);
2033
+ if (!reader) {
2034
+ throw this.logger.Error().Ref("cid", carCid).Msg("missing car reader").AsError();
2035
+ }
2036
+ await this.cacheCarReader(carCid.toString(), reader).catch(() => {
2037
+ return;
2038
+ });
2039
+ if (this.getBlockCache.has(sCid)) return this.getBlockCache.get(sCid);
2040
+ throw this.logger.Error().Str("cid", sCid).Msg("block not in reader").AsError();
2041
+ };
2042
+ const getCompactCarCids = async (carCid) => {
2043
+ const reader = await this.loadCar(carCid);
2044
+ if (!reader) {
2045
+ throw this.logger.Error().Str("cid", carCid.toString()).Msg("missing car reader").AsError();
2046
+ }
2047
+ const header = await parseCarFile(reader, this.logger);
2048
+ const compacts = header.compact;
2049
+ let got2;
2050
+ const batchSize2 = 5;
2051
+ for (let i = 0; i < compacts.length; i += batchSize2) {
2052
+ const promises = [];
2053
+ for (let j = i; j < Math.min(i + batchSize2, compacts.length); j++) {
2054
+ for (const cid2 of compacts[j]) {
2055
+ promises.push(getCarCid(cid2));
2056
+ }
2057
+ }
2058
+ try {
2059
+ got2 = await Promise.any(promises);
2060
+ } catch {
2061
+ }
2062
+ if (got2) break;
2063
+ }
2064
+ if (this.getBlockCache.has(sCid)) return this.getBlockCache.get(sCid);
2065
+ throw this.logger.Error().Str("cid", sCid).Msg("block not in compact reader").AsError();
2066
+ };
2067
+ let got;
2068
+ const batchSize = 5;
2069
+ for (let i = 0; i < this.carLog.length; i += batchSize) {
2070
+ const batch = this.carLog.slice(i, i + batchSize);
2071
+ const promises = batch.flatMap((slice) => slice.map(getCarCid));
2072
+ try {
2073
+ got = await Promise.any(promises);
2074
+ } catch {
2075
+ }
2076
+ if (got) break;
2077
+ }
2078
+ if (!got) {
2079
+ try {
2080
+ got = await getCompactCarCids(this.carLog[this.carLog.length - 1][0]);
2081
+ } catch {
2082
+ }
2083
+ }
2084
+ return got;
2099
2085
  }
2100
- destroy() {
2101
- return this.loader.destroy();
2086
+ async loadCar(cid) {
2087
+ if (!this.carStore) {
2088
+ throw this.logger.Error().Msg("car store not initialized").AsError();
2089
+ }
2090
+ const loaded = await this.storesLoadCar(cid, await this.carStore(), this.remoteCarStore);
2091
+ return loaded;
2102
2092
  }
2103
- async get(cid) {
2104
- const got = await super.get(cid);
2105
- if (got) return got;
2106
- if (!this.loader) {
2107
- return;
2093
+ async makeDecoderAndCarReader(cid, local, remote) {
2094
+ const cidsString = cid.toString();
2095
+ let loadedCar = void 0;
2096
+ let activeStore = local;
2097
+ try {
2098
+ this.logger.Debug().Str("cid", cidsString).Msg("loading car");
2099
+ loadedCar = await local.load(cid);
2100
+ this.logger.Debug().Bool("loadedCar", loadedCar).Msg("loaded");
2101
+ } catch (e) {
2102
+ if (remote) {
2103
+ const remoteCar = await remote.load(cid);
2104
+ if (remoteCar) {
2105
+ this.logger.Debug().Ref("cid", remoteCar.cid).Msg("saving remote car locally");
2106
+ await local.save(remoteCar);
2107
+ loadedCar = remoteCar;
2108
+ activeStore = remote;
2109
+ }
2110
+ } else {
2111
+ this.logger.Error().Str("cid", cidsString).Err(e).Msg("loading car");
2112
+ }
2108
2113
  }
2109
- return falsyToUndef(await this.loader.getBlock(cid));
2114
+ if (!loadedCar) {
2115
+ throw this.logger.Error().Url(local.url()).Str("cid", cidsString).Msg("missing car files").AsError();
2116
+ }
2117
+ const bytes = await decode({ bytes: loadedCar.bytes, hasher: import_sha23.sha256, codec: (await activeStore.keyedCrypto()).codec() });
2118
+ const rawReader = await import_car.CarReader.fromBytes(bytes.value);
2119
+ const readerP = Promise.resolve(rawReader);
2120
+ const cachedReaderP = readerP.then(async (reader) => {
2121
+ await this.cacheCarReader(cidsString, reader).catch((e) => {
2122
+ this.logger.Error().Err(e).Str("cid", cidsString).Msg("error caching car reader");
2123
+ return;
2124
+ });
2125
+ return reader;
2126
+ });
2127
+ this.carReaders.set(cidsString, cachedReaderP);
2128
+ return readerP;
2110
2129
  }
2111
- async transaction(fn, opts = { noLoader: false }) {
2112
- this.logger.Debug().Msg("enter transaction");
2113
- const { t, meta: done } = await super.transaction(fn);
2114
- this.logger.Debug().Msg("post super.transaction");
2115
- const cars = await this.loader.commit(t, done, opts);
2116
- this.logger.Debug().Msg("post this.loader.commit");
2117
- if (this.ebOpts.autoCompact && this.loader.carLog.length > this.ebOpts.autoCompact) {
2118
- setTimeout(() => void this.compact(), 10);
2130
+ //What if instead it returns an Array of CarHeader
2131
+ async storesLoadCar(cid, local, remote) {
2132
+ const cidsString = cid.toString();
2133
+ let dacr = this.carReaders.get(cidsString);
2134
+ if (!dacr) {
2135
+ dacr = this.makeDecoderAndCarReader(cid, local, remote);
2136
+ this.carReaders.set(cidsString, dacr);
2119
2137
  }
2120
- if (cars) {
2121
- this.transactions.delete(t);
2122
- return { meta: done, cars, t };
2138
+ return dacr;
2139
+ }
2140
+ async getMoreReaders(cids) {
2141
+ const limit = (0, import_p_limit.default)(5);
2142
+ const missing = cids.filter((cid) => !this.carReaders.has(cid.toString()));
2143
+ await Promise.all(missing.map((cid) => limit(() => this.loadCar(cid))));
2144
+ }
2145
+ };
2146
+
2147
+ // src/runtime/keyed-crypto.ts
2148
+ var keyed_crypto_exports = {};
2149
+ __export(keyed_crypto_exports, {
2150
+ BlockIvKeyIdCodec: () => BlockIvKeyIdCodec,
2151
+ keyedCryptoFactory: () => keyedCryptoFactory
2152
+ });
2153
+ init_utils();
2154
+ var import_base583 = require("multiformats/bases/base58");
2155
+ var import_sha24 = require("multiformats/hashes/sha2");
2156
+ var CBOR = __toESM(require("cborg"), 1);
2157
+ var generateIV = {
2158
+ random: {
2159
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2160
+ calc: async (ko, crypto, data) => {
2161
+ return crypto.randomBytes(ko.ivLength);
2162
+ },
2163
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2164
+ verify: async (ko, crypto, iv, data) => {
2165
+ return true;
2166
+ }
2167
+ },
2168
+ hash: {
2169
+ calc: async (ko, crypto, data) => {
2170
+ const hash = await import_sha24.sha256.digest(data);
2171
+ const hashBytes = new Uint8Array(hash.bytes);
2172
+ const hashArray = new Uint8Array(ko.ivLength);
2173
+ for (let i = 0; i < hashBytes.length; i++) {
2174
+ hashArray[i % ko.ivLength] ^= hashBytes[i];
2175
+ }
2176
+ return hashArray;
2177
+ },
2178
+ verify: async function(ko, crypto, iv, data) {
2179
+ return ko.url.getParam("ivverify") !== "disable" && UInt8ArrayEqual(iv, await this.calc(ko, crypto, data));
2123
2180
  }
2124
- throw this.logger.Error().Msg("failed to commit car files").AsError();
2125
2181
  }
2126
- async getFile(car, cid) {
2127
- await this.ready();
2128
- if (!this.loader) throw this.logger.Error().Msg("loader required to get file, database must be named").AsError();
2129
- const reader = await this.loader.loadFileCar(
2130
- car
2131
- /*, isPublic */
2132
- );
2133
- const block = await reader.get(cid);
2134
- if (!block) throw this.logger.Error().Str("cid", cid.toString()).Msg(`Missing block`).AsError();
2135
- return block.bytes;
2182
+ };
2183
+ function getGenerateIVFn(url, opts) {
2184
+ const ivhash = opts.ivCalc || url.getParam("ivhash") || "hash";
2185
+ return generateIV[ivhash] || generateIV["hash"];
2186
+ }
2187
+ var BlockIvKeyIdCodec = class {
2188
+ constructor(ko, iv, opts) {
2189
+ this.code = 3147065;
2190
+ this.name = "Fireproof@encrypted-block:aes-gcm";
2191
+ this.ko = ko;
2192
+ this.iv = iv;
2193
+ this.opts = opts || {};
2136
2194
  }
2137
- async compact() {
2138
- await this.ready();
2139
- if (!this.loader) throw this.logger.Error().Msg("loader required to compact").AsError();
2140
- if (this.loader.carLog.length < 2) return;
2141
- const compactFn = this.ebOpts.compact || ((blocks) => this.defaultCompact(blocks, this.logger));
2142
- if (!compactFn || this.compacting) return;
2143
- const blockLog = new CompactionFetcher(this);
2144
- this.compacting = true;
2145
- const meta = await compactFn(blockLog);
2146
- await this.loader?.commit(blockLog.loggedBlocks, meta, {
2147
- compact: true,
2148
- noLoader: true
2195
+ async encode(data) {
2196
+ const calcIv = this.iv || await getGenerateIVFn(this.ko.url, this.opts).calc(this.ko, this.ko.crypto, data);
2197
+ const { iv } = this.ko.algo(calcIv);
2198
+ const fprt = await this.ko.fingerPrint();
2199
+ const keyId = import_base583.base58btc.decode(fprt);
2200
+ this.ko.logger.Debug().Str("fp", fprt).Msg("encode");
2201
+ return CBOR.encode({
2202
+ iv,
2203
+ keyId,
2204
+ data: await this.ko._encrypt({ iv, bytes: data })
2149
2205
  });
2150
- this.compacting = false;
2151
2206
  }
2152
- async defaultCompact(blocks, logger) {
2153
- if (!this.loader) {
2154
- throw logger.Error().Msg("no loader").AsError();
2155
- }
2156
- if (!this.lastTxMeta) {
2157
- throw logger.Error().Msg("no lastTxMeta").AsError();
2158
- }
2159
- for await (const blk of this.loader.entries(false)) {
2160
- blocks.loggedBlocks.putSync(blk.cid, blk.bytes);
2207
+ async decode(abytes) {
2208
+ let bytes;
2209
+ if (abytes instanceof Uint8Array) {
2210
+ bytes = abytes;
2211
+ } else {
2212
+ bytes = new Uint8Array(abytes);
2161
2213
  }
2162
- for (const t of this.transactions) {
2163
- for await (const blk of t.entries()) {
2164
- blocks.loggedBlocks.putSync(blk.cid, blk.bytes);
2165
- }
2214
+ const { iv, keyId, data } = CBOR.decode(bytes);
2215
+ const fprt = await this.ko.fingerPrint();
2216
+ this.ko.logger.Debug().Str("fp", import_base583.base58btc.encode(keyId)).Msg("decode");
2217
+ if (import_base583.base58btc.encode(keyId) !== fprt) {
2218
+ throw this.ko.logger.Error().Str("fp", fprt).Str("keyId", import_base583.base58btc.encode(keyId)).Msg("keyId mismatch").AsError();
2166
2219
  }
2167
- return this.lastTxMeta;
2168
- }
2169
- async *entries() {
2170
- for await (const blk of this.loader.entries()) {
2171
- yield blk;
2220
+ const result = await this.ko._decrypt({ iv, bytes: data });
2221
+ if (!this.opts?.noIVVerify && !await getGenerateIVFn(this.ko.url, this.opts).verify(this.ko, this.ko.crypto, iv, result)) {
2222
+ throw this.ko.logger.Error().Msg("iv missmatch").AsError();
2172
2223
  }
2224
+ return result;
2173
2225
  }
2174
2226
  };
2175
- var CompactionFetcher = class {
2176
- constructor(blocks) {
2177
- this.blockstore = blocks;
2178
- this.loggedBlocks = new CarTransaction(blocks);
2227
+ var keyedCrypto = class {
2228
+ constructor(url, key, cyopt, sthis) {
2229
+ this.ivLength = 12;
2230
+ this.isEncrypting = true;
2231
+ this.logger = ensureLogger(sthis, "keyedCrypto");
2232
+ this.crypto = cyopt;
2233
+ this.key = key;
2234
+ this.url = url;
2179
2235
  }
2180
- async get(cid) {
2181
- const block = await this.blockstore.get(cid);
2182
- if (block) this.loggedBlocks.putSync(cid, block.bytes);
2183
- return falsyToUndef(block);
2236
+ fingerPrint() {
2237
+ return Promise.resolve(this.key.fingerPrint);
2184
2238
  }
2185
- };
2186
-
2187
- // src/blockstore/commitor.ts
2188
- var CBW = __toESM(require("@ipld/car/buffer-writer"), 1);
2189
- var import_sha23 = require("multiformats/hashes/sha2");
2190
- var dagCodec2 = __toESM(require("@ipld/dag-cbor"), 1);
2191
- async function encodeCarFile(roots, t, codec3) {
2192
- let size = 0;
2193
- const headerSize = CBW.headerLength({ roots });
2194
- size += headerSize;
2195
- for (const { cid, bytes } of t.entries()) {
2196
- size += CBW.blockLength({ cid, bytes });
2239
+ codec(iv, opts) {
2240
+ return new BlockIvKeyIdCodec(this, iv, opts);
2197
2241
  }
2198
- const buffer = new Uint8Array(size);
2199
- const writer = CBW.createWriter(buffer, { headerSize });
2200
- for (const r of roots) {
2201
- writer.addRoot(r);
2242
+ algo(iv) {
2243
+ return {
2244
+ name: "AES-GCM",
2245
+ iv: iv || this.crypto.randomBytes(this.ivLength),
2246
+ tagLength: 128
2247
+ };
2202
2248
  }
2203
- for (const { cid, bytes } of t.entries()) {
2204
- writer.write({ cid, bytes });
2249
+ async _decrypt(data) {
2250
+ this.logger.Debug().Len(data.bytes, "bytes").Len(data.iv, "iv").Str("fp", this.key.fingerPrint).Msg("decrypting");
2251
+ return new Uint8Array(await this.crypto.decrypt(this.algo(data.iv), this.key.key, data.bytes));
2205
2252
  }
2206
- writer.close();
2207
- return await encode3({ value: writer.bytes, hasher: import_sha23.sha256, codec: codec3 });
2208
- }
2209
- async function createCarFile(encoder, cid, t) {
2210
- return encodeCarFile([cid], t, encoder);
2211
- }
2212
- async function commitFiles(fileStore, walStore, t, done) {
2213
- const { files: roots } = makeFileCarHeader(done);
2214
- const cids = [];
2215
- const codec3 = (await fileStore.keyedCrypto()).codec();
2216
- const cars = await prepareCarFilesFiles(codec3, roots, t);
2217
- for (const car of cars) {
2218
- const { cid, bytes } = car;
2219
- await fileStore.save({ cid, bytes });
2220
- await walStore.enqueueFile(
2221
- cid
2222
- /*, !!opts.public*/
2223
- );
2224
- cids.push(cid);
2253
+ async _encrypt(data) {
2254
+ this.logger.Debug().Len(data.bytes).Str("fp", this.key.fingerPrint).Msg("encrypting");
2255
+ const a = this.algo(data.iv);
2256
+ return new Uint8Array(await this.crypto.encrypt(a, this.key.key, data.bytes));
2225
2257
  }
2226
- return cids;
2227
- }
2228
- function makeFileCarHeader(result) {
2229
- const files = [];
2230
- for (const [, meta] of Object.entries(result.files || {})) {
2231
- if (meta && typeof meta === "object" && "cid" in meta && meta !== null) {
2232
- files.push(meta.cid);
2233
- }
2258
+ };
2259
+ var nullCodec = class {
2260
+ constructor() {
2261
+ this.code = 0;
2262
+ this.name = "Fireproof@unencrypted-block";
2234
2263
  }
2235
- return { ...result, files };
2236
- }
2237
- async function prepareCarFilesFiles(encoder, roots, t) {
2238
- return [await encodeCarFile(roots, t, encoder)];
2239
- }
2240
- function makeCarHeader(meta, cars, compact = false) {
2241
- const coreHeader = compact ? { cars: [], compact: cars } : { cars, compact: [] };
2242
- return { ...coreHeader, meta };
2243
- }
2244
- async function encodeCarHeader(fp) {
2245
- return await encode3({
2246
- value: { fp },
2247
- hasher: import_sha23.sha256,
2248
- codec: dagCodec2
2249
- });
2250
- }
2251
- async function commit(params, t, done, opts = { noLoader: false, compact: false }) {
2252
- const fp = makeCarHeader(done, params.carLog, !!opts.compact);
2253
- const rootBlock = await encodeCarHeader(fp);
2254
- const cars = await prepareCarFiles(params.encoder, params.threshold, rootBlock, t);
2255
- const cids = [];
2256
- for (const car of cars) {
2257
- const { cid, bytes } = car;
2258
- await params.carStore.save({ cid, bytes });
2259
- cids.push(cid);
2264
+ encode(data) {
2265
+ return data;
2260
2266
  }
2261
- const newDbMeta = { cars: cids };
2262
- await params.WALStore.enqueue(newDbMeta, opts);
2263
- await params.metaStore.save(newDbMeta);
2264
- return { cgrp: cids, header: fp };
2265
- }
2266
- async function prepareCarFiles(encoder, threshold, rootBlock, t) {
2267
- const carFiles = [];
2268
- threshold = threshold || 128e3 * 8;
2269
- let clonedt = new CarTransaction(t.parent, { add: false, noLoader: false });
2270
- clonedt.putSync(rootBlock.cid, rootBlock.bytes);
2271
- let newsize = CBW.blockLength(toCIDBlock(rootBlock));
2272
- let cidRootBlock = rootBlock;
2273
- for (const { cid, bytes } of t.entries()) {
2274
- newsize += CBW.blockLength(toCIDBlock({ cid, bytes }));
2275
- if (newsize >= threshold) {
2276
- carFiles.push(await createCarFile(encoder, cidRootBlock.cid, clonedt));
2277
- clonedt = new CarTransaction(t.parent, { add: false, noLoader: false });
2278
- clonedt.putSync(cid, bytes);
2279
- cidRootBlock = { cid, bytes };
2280
- newsize = CBW.blockLength(toCIDBlock({ cid, bytes }));
2281
- } else {
2282
- clonedt.putSync(cid, bytes);
2283
- }
2267
+ decode(data) {
2268
+ return data;
2284
2269
  }
2285
- carFiles.push(await createCarFile(encoder, cidRootBlock.cid, clonedt));
2286
- return carFiles;
2287
- }
2288
-
2289
- // src/blockstore/loader.ts
2290
- var import_sha24 = require("multiformats/hashes/sha2");
2291
-
2292
- // src/blockstore/task-manager.ts
2293
- init_utils();
2294
- var TaskManager = class {
2295
- constructor(sthis, callback) {
2296
- this.eventsWeHandled = /* @__PURE__ */ new Set();
2297
- this.queue = [];
2298
- this.isProcessing = false;
2299
- this.logger = ensureLogger(sthis, "TaskManager");
2300
- this.callback = callback;
2270
+ };
2271
+ var noCrypto = class {
2272
+ constructor(url, cyrt, sthis) {
2273
+ this.ivLength = 0;
2274
+ this.code = 0;
2275
+ this.name = "Fireproof@unencrypted-block";
2276
+ this.isEncrypting = false;
2277
+ this._fingerPrint = "noCrypto:" + Math.random();
2278
+ this.logger = ensureLogger(sthis, "noCrypto");
2279
+ this.crypto = cyrt;
2280
+ this.url = url;
2301
2281
  }
2302
- async handleEvent(cid, parents, dbMeta) {
2303
- for (const parent of parents) {
2304
- this.eventsWeHandled.add(parent.toString());
2305
- }
2306
- this.queue.push({ cid: cid.toString(), dbMeta, retries: 0 });
2307
- this.queue = this.queue.filter(({ cid: cid2 }) => !this.eventsWeHandled.has(cid2));
2308
- void this.processQueue();
2282
+ fingerPrint() {
2283
+ return Promise.resolve(this._fingerPrint);
2309
2284
  }
2310
- async processQueue() {
2311
- if (this.isProcessing) return;
2312
- this.isProcessing = true;
2313
- const filteredQueue = this.queue.filter(({ cid }) => !this.eventsWeHandled.has(cid));
2314
- const first = filteredQueue[0];
2315
- if (!first) {
2316
- return;
2317
- }
2318
- try {
2319
- await this.callback(first.dbMeta);
2320
- this.eventsWeHandled.add(first.cid);
2321
- this.queue = this.queue.filter(({ cid }) => !this.eventsWeHandled.has(cid));
2322
- } catch (err) {
2323
- if (first.retries++ > 3) {
2324
- this.logger.Error().Str("cid", first.cid).Msg("failed to process event block after 3 retries");
2325
- this.queue = this.queue.filter(({ cid }) => cid !== first.cid);
2326
- }
2327
- await new Promise((resolve) => setTimeout(resolve, 50));
2328
- throw this.logger.Error().Err(err).Msg("failed to process event block").AsError();
2329
- } finally {
2330
- this.isProcessing = false;
2331
- if (this.queue.length > 0) {
2332
- void this.processQueue();
2333
- }
2334
- }
2285
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2286
+ codec(iv) {
2287
+ return new nullCodec();
2288
+ }
2289
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2290
+ algo(iv) {
2291
+ return {
2292
+ name: "noCrypto",
2293
+ iv: new Uint8Array(),
2294
+ tagLength: 0
2295
+ };
2296
+ }
2297
+ _decrypt() {
2298
+ throw this.logger.Error().Msg("noCrypto.decrypt not implemented").AsError();
2299
+ }
2300
+ _encrypt() {
2301
+ throw this.logger.Error().Msg("noCrypto.decrypt not implemented").AsError();
2335
2302
  }
2336
2303
  };
2337
-
2338
- // src/blockstore/loader.ts
2339
- function carLogIncludesGroup(list, cids) {
2340
- return list.some((arr) => {
2341
- return arr.toString() === cids.toString();
2342
- });
2343
- }
2344
- function uniqueCids(list, remove = /* @__PURE__ */ new Set()) {
2345
- const byString = /* @__PURE__ */ new Map();
2346
- for (const cid of list) {
2347
- if (remove.has(cid.toString())) continue;
2348
- byString.set(cid.toString(), cid);
2304
+ async function keyedCryptoFactory(url, kb, sthis) {
2305
+ const storekey = url.getParam("storekey");
2306
+ if (storekey && storekey !== "insecure") {
2307
+ let rkey = await kb.getNamedKey(storekey, true);
2308
+ if (rkey.isErr()) {
2309
+ try {
2310
+ rkey = await kb.toKeyWithFingerPrint(storekey);
2311
+ } catch (e) {
2312
+ throw sthis.logger.Error().Err(e).Str("keybag", kb.rt.id()).Str("name", storekey).Msg("getNamedKey failed").AsError();
2313
+ }
2314
+ }
2315
+ return new keyedCrypto(url, rkey.Ok(), kb.rt.crypto, sthis);
2349
2316
  }
2350
- return [...byString.values()];
2317
+ return new noCrypto(url, kb.rt.crypto, sthis);
2351
2318
  }
2352
- var Loader = class {
2353
- constructor(sthis, ebOpts) {
2354
- this.commitQueue = new CommitQueue();
2355
- this.isCompacting = false;
2356
- this.carReaders = /* @__PURE__ */ new Map();
2357
- this.seenCompacted = /* @__PURE__ */ new Set();
2358
- this.processedCars = /* @__PURE__ */ new Set();
2359
- this.carLog = [];
2360
- this.getBlockCache = /* @__PURE__ */ new Map();
2361
- this.seenMeta = /* @__PURE__ */ new Set();
2362
- this.writeLimit = (0, import_p_limit.default)(1);
2363
- this._carStore = new import_cement9.ResolveOnce();
2364
- this._fileStore = new import_cement9.ResolveOnce();
2365
- this._WALStore = new import_cement9.ResolveOnce();
2366
- this._metaStore = new import_cement9.ResolveOnce();
2367
- this.onceReady = new import_cement9.ResolveOnce();
2368
- this.sthis = sthis;
2369
- this.ebOpts = defaultedBlockstoreRuntime(
2370
- sthis,
2371
- {
2372
- ...ebOpts
2373
- // name,
2374
- },
2375
- "Loader"
2376
- );
2377
- this.logger = this.ebOpts.logger;
2378
- this.taskManager = new TaskManager(sthis, async (dbMeta) => {
2379
- await this.handleDbMetasFromStore([dbMeta]);
2380
- });
2319
+
2320
+ // src/blockstore/fragment-gateway.ts
2321
+ var import_cement8 = require("@adviser/cement");
2322
+ var import_base584 = require("multiformats/bases/base58");
2323
+ var import_cborg = require("cborg");
2324
+ init_utils();
2325
+ function getFragSize(url) {
2326
+ const fragSize = url.getParam("fragSize");
2327
+ let ret = 0;
2328
+ if (fragSize) {
2329
+ ret = parseInt(fragSize);
2381
2330
  }
2382
- async carStore() {
2383
- return this._carStore.once(
2384
- async () => this.ebOpts.storeRuntime.makeDataStore({
2385
- sthis: this.sthis,
2386
- url: this.ebOpts.storeUrls.data,
2387
- keybag: await this.keyBag()
2388
- })
2389
- );
2331
+ if (isNaN(ret) || ret <= 0) {
2332
+ ret = 0;
2390
2333
  }
2391
- async fileStore() {
2392
- return this._fileStore.once(
2393
- async () => this.ebOpts.storeRuntime.makeDataStore({
2394
- sthis: this.sthis,
2395
- url: this.ebOpts.storeUrls.file,
2396
- keybag: await this.keyBag()
2334
+ return ret;
2335
+ }
2336
+ async function getFrags(url, innerGW, headerSize, logger) {
2337
+ const fragSize = getFragSize(url);
2338
+ if (!fragSize) {
2339
+ const res = await innerGW.get(url);
2340
+ if (res.isErr()) {
2341
+ return [res];
2342
+ }
2343
+ const data = res.unwrap();
2344
+ return [
2345
+ import_cement8.Result.Ok({
2346
+ fid: new Uint8Array(0),
2347
+ ofs: 0,
2348
+ len: data.length,
2349
+ data
2397
2350
  })
2398
- );
2351
+ ];
2399
2352
  }
2400
- async WALStore() {
2401
- return this._WALStore.once(
2402
- async () => this.ebOpts.storeRuntime.makeWALStore({
2403
- sthis: this.sthis,
2404
- url: this.ebOpts.storeUrls.wal,
2405
- keybag: await this.keyBag()
2406
- })
2407
- );
2353
+ const firstRaw = await innerGW.get(url.build().setParam("ofs", "0").URI());
2354
+ if (firstRaw.isErr()) {
2355
+ return [firstRaw];
2408
2356
  }
2409
- async metaStore() {
2410
- return this._metaStore.once(
2411
- async () => this.ebOpts.storeRuntime.makeMetaStore({
2412
- sthis: this.sthis,
2413
- url: this.ebOpts.storeUrls.meta,
2414
- keybag: await this.keyBag()
2415
- })
2357
+ const firstFragment = (0, import_cborg.decode)(firstRaw.unwrap());
2358
+ const blockSize = firstFragment.data.length;
2359
+ const ops = [Promise.resolve(import_cement8.Result.Ok(firstFragment))];
2360
+ const fidStr = import_base584.base58btc.encode(firstFragment.fid);
2361
+ const fragUrl = url.build().setParam("fid", fidStr).setParam("len", firstFragment.len.toString()).setParam("headerSize", headerSize.toString());
2362
+ for (let ofs = blockSize; ofs < firstFragment.len; ofs += blockSize) {
2363
+ ops.push(
2364
+ (async (furl, ofs2) => {
2365
+ const raw2 = await innerGW.get(furl);
2366
+ if (raw2.isErr()) {
2367
+ return raw2;
2368
+ }
2369
+ const fragment = (0, import_cborg.decode)(raw2.unwrap());
2370
+ if (import_base584.base58btc.encode(fragment.fid) !== fidStr) {
2371
+ return import_cement8.Result.Err(logger.Error().Msg("Fragment fid mismatch").AsError());
2372
+ }
2373
+ if (fragment.ofs !== ofs2) {
2374
+ return import_cement8.Result.Err(logger.Error().Uint64("ofs", ofs2).Msg("Fragment ofs mismatch").AsError());
2375
+ }
2376
+ return import_cement8.Result.Ok(fragment);
2377
+ })(fragUrl.setParam("ofs", ofs.toString()).URI(), ofs)
2416
2378
  );
2417
2379
  }
2418
- keyBag() {
2419
- return getKeyBag(this.sthis, this.ebOpts.keyBag);
2420
- }
2421
- async ready() {
2422
- return this.onceReady.once(async () => {
2423
- const metas = await (await this.metaStore()).load();
2424
- if (this.ebOpts.meta) {
2425
- await this.handleDbMetasFromStore([this.ebOpts.meta]);
2426
- } else if (metas) {
2427
- await this.handleDbMetasFromStore(metas);
2428
- }
2429
- });
2430
- }
2431
- async close() {
2432
- await this.commitQueue.waitIdle();
2433
- const toClose = await Promise.all([this.carStore(), this.metaStore(), this.fileStore(), this.WALStore()]);
2434
- await Promise.all(toClose.map((store) => store.close()));
2435
- }
2436
- async destroy() {
2437
- const toDestroy = await Promise.all([this.carStore(), this.metaStore(), this.fileStore(), this.WALStore()]);
2438
- await Promise.all(toDestroy.map((store) => store.destroy()));
2380
+ return Promise.all(ops);
2381
+ }
2382
+ var FragmentGateway = class {
2383
+ constructor(sthis, innerGW) {
2384
+ this.fidLength = 4;
2385
+ this.headerSize = 32;
2386
+ this.sthis = ensureSuperLog(sthis, "FragmentGateway");
2387
+ this.logger = this.sthis.logger;
2388
+ this.innerGW = innerGW;
2439
2389
  }
2440
- // async snapToCar(carCid: AnyLink | string) {
2441
- // await this.ready
2442
- // if (typeof carCid === 'string') {
2443
- // carCid = CID.parse(carCid)
2444
- // }
2445
- // const carHeader = await this.loadCarHeaderFromMeta({ car: carCid, key: this.key || null })
2446
- // this.carLog = [carCid, ...carHeader.cars]
2447
- // await this.getMoreReaders(carHeader.cars)
2448
- // await this._applyCarHeader(carHeader, true)
2449
- // }
2450
- async handleDbMetasFromStore(metas) {
2451
- this.logger.Debug().Any("metas", metas).Msg("handleDbMetasFromStore");
2452
- for (const meta of metas) {
2453
- await this.writeLimit(async () => {
2454
- await this.mergeDbMetaIntoClock(meta);
2455
- });
2390
+ slicer(url, body) {
2391
+ const fragSize = getFragSize(url);
2392
+ if (!fragSize) {
2393
+ return [this.innerGW.put(url, body)];
2456
2394
  }
2457
- }
2458
- async mergeDbMetaIntoClock(meta) {
2459
- if (this.isCompacting) {
2460
- throw this.logger.Error().Msg("cannot merge while compacting").AsError();
2395
+ const blocksize = fragSize - this.headerSize;
2396
+ if (blocksize <= 0) {
2397
+ throw this.logger.Error().Uint64("fragSize", fragSize).Uint64("headerSize", this.headerSize).Msg("Fragment size is too small").AsError();
2461
2398
  }
2462
- if (this.seenMeta.has(meta.cars.toString())) return;
2463
- this.seenMeta.add(meta.cars.toString());
2464
- if (carLogIncludesGroup(this.carLog, meta.cars)) {
2465
- return;
2399
+ const ops = [];
2400
+ const fid = this.sthis.nextId(this.fidLength);
2401
+ const fragUrl = url.build().setParam("fid", fid.str).setParam("len", body.length.toString()).setParam("headerSize", this.headerSize.toString());
2402
+ for (let ofs = 0; ofs < body.length; ofs += blocksize) {
2403
+ const block = (0, import_cborg.encode)({
2404
+ fid: fid.bin,
2405
+ ofs,
2406
+ len: body.length,
2407
+ data: body.slice(ofs, ofs + blocksize)
2408
+ });
2409
+ if (block.length > fragSize) {
2410
+ throw this.logger.Error().Uint64("block", block.length).Uint64("fragSize", fragSize).Msg("Block size to big").AsError();
2411
+ }
2412
+ ops.push(this.innerGW.put(fragUrl.setParam("ofs", ofs.toString()).URI(), block));
2466
2413
  }
2467
- const carHeader = await this.loadCarHeaderFromMeta(meta);
2468
- carHeader.compact.map((c) => c.toString()).forEach(this.seenCompacted.add, this.seenCompacted);
2469
- await this.getMoreReaders(carHeader.cars.flat());
2470
- this.carLog = [...uniqueCids([meta.cars, ...this.carLog, ...carHeader.cars], this.seenCompacted)];
2471
- await this.ebOpts.applyMeta?.(carHeader.meta);
2472
- }
2473
- // protected async ingestKeyFromMeta(meta: DbMeta): Promise<void> {
2474
- // const { key } = meta;
2475
- // if (key) {
2476
- // await this.setKey(key);
2477
- // }
2478
- // }
2479
- async loadCarHeaderFromMeta({ cars: cids }) {
2480
- const reader = await this.loadCar(cids[0]);
2481
- return await parseCarFile(reader, this.logger);
2482
- }
2483
- // async _getKey(): Promise<string | undefined> {
2484
- // if (this.key) return this.key;
2485
- // // generate a random key
2486
- // if (!this.ebOpts.public) {
2487
- // await this.setKey(toHexString(this.ebOpts.crypto.randomBytes(32)));
2488
- // }
2489
- // return this.key || undefined;
2490
- // }
2491
- async commitFiles(t, done) {
2492
- await this.ready();
2493
- const fstore = await this.fileStore();
2494
- const wstore = await this.WALStore();
2495
- return this.commitQueue.enqueue(() => commitFiles(fstore, wstore, t, done));
2414
+ return ops;
2496
2415
  }
2497
- async loadFileCar(cid) {
2498
- return await this.storesLoadCar(cid, await this.fileStore(), this.remoteFileStore);
2416
+ buildUrl(baseUrl, key) {
2417
+ return this.innerGW.buildUrl(baseUrl, key);
2499
2418
  }
2500
- async commit(t, done, opts = { noLoader: false, compact: false }) {
2501
- await this.ready();
2502
- const carStore = await this.carStore();
2503
- const params = {
2504
- encoder: (await carStore.keyedCrypto()).codec(),
2505
- carLog: this.carLog,
2506
- carStore,
2507
- WALStore: await this.WALStore(),
2508
- metaStore: await this.metaStore(),
2509
- threshold: this.ebOpts.threshold
2510
- };
2511
- return this.commitQueue.enqueue(async () => {
2512
- await this.cacheTransaction(t);
2513
- const ret = await commit(params, t, done, opts);
2514
- await this.updateCarLog(ret.cgrp, ret.header, !!opts.compact);
2515
- return ret.cgrp;
2516
- });
2419
+ async destroy(iurl) {
2420
+ return this.innerGW.destroy(iurl);
2517
2421
  }
2518
- async updateCarLog(cids, fp, compact) {
2519
- if (compact) {
2520
- const previousCompactCid = fp.compact[fp.compact.length - 1];
2521
- fp.compact.map((c) => c.toString()).forEach(this.seenCompacted.add, this.seenCompacted);
2522
- this.carLog = [...uniqueCids([...this.carLog, ...fp.cars, cids], this.seenCompacted)];
2523
- await this.removeCidsForCompact(previousCompactCid[0]).catch((e) => e);
2524
- } else {
2525
- this.carLog.unshift(cids);
2526
- }
2422
+ async start(url) {
2423
+ this.headerSize = (0, import_cborg.encode)({
2424
+ fid: this.sthis.nextId(this.fidLength).bin,
2425
+ ofs: 1024 * 1024,
2426
+ // 32bit
2427
+ len: 16 * 1024 * 1024,
2428
+ // 32bit
2429
+ data: new Uint8Array(1024)
2430
+ }).length - 1024;
2431
+ return this.innerGW.start(url);
2527
2432
  }
2528
- async cacheTransaction(t) {
2529
- for await (const block of t.entries()) {
2530
- const sBlock = block.cid.toString();
2531
- if (!this.getBlockCache.has(sBlock)) {
2532
- this.getBlockCache.set(sBlock, block);
2533
- }
2534
- }
2433
+ async close(url) {
2434
+ return this.innerGW.close(url);
2535
2435
  }
2536
- async cacheCarReader(carCidStr, reader) {
2537
- if (this.processedCars.has(carCidStr)) return;
2538
- this.processedCars.add(carCidStr);
2539
- for await (const block of reader.blocks()) {
2540
- const sBlock = block.cid.toString();
2541
- if (!this.getBlockCache.has(sBlock)) {
2542
- this.getBlockCache.set(sBlock, block);
2543
- }
2544
- }
2436
+ async put(url, body) {
2437
+ await Promise.all(this.slicer(url, body));
2438
+ return import_cement8.Result.Ok(void 0);
2545
2439
  }
2546
- async removeCidsForCompact(cid) {
2547
- const carHeader = await this.loadCarHeaderFromMeta({
2548
- cars: [cid]
2549
- });
2550
- for (const cids of carHeader.compact) {
2551
- for (const cid2 of cids) {
2552
- await (await this.carStore()).remove(cid2);
2440
+ async get(url) {
2441
+ const rfrags = await getFrags(url, this.innerGW, this.headerSize, this.logger);
2442
+ let buffer = void 0;
2443
+ for (const rfrag of rfrags) {
2444
+ if (rfrag.isErr()) {
2445
+ return import_cement8.Result.Err(rfrag.Err());
2553
2446
  }
2447
+ const frag = rfrag.Ok();
2448
+ buffer = buffer || new Uint8Array(frag.len);
2449
+ buffer.set(frag.data, frag.ofs);
2554
2450
  }
2451
+ return import_cement8.Result.Ok(buffer || new Uint8Array(0));
2555
2452
  }
2556
- // async flushCars() {
2557
- // await this.ready
2558
- // // for each cid in car log, make a dbMeta
2559
- // for (const cid of this.carLog) {
2560
- // const dbMeta = { car: cid, key: this.key || null } as DbMeta
2561
- // await this.remoteWAL!.enqueue(dbMeta, { public: false })
2562
- // }
2563
- // }
2564
- async *entries(cache2 = true) {
2565
- await this.ready();
2566
- if (cache2) {
2567
- for (const [, block] of this.getBlockCache) {
2568
- yield block;
2569
- }
2453
+ async subscribe(url, callback) {
2454
+ if (this.innerGW.subscribe) {
2455
+ return this.innerGW.subscribe(url, callback);
2570
2456
  } else {
2571
- for (const [, block] of this.getBlockCache) {
2572
- yield block;
2573
- }
2574
- for (const cids of this.carLog) {
2575
- for (const cid of cids) {
2576
- const reader = await this.loadCar(cid);
2577
- if (!reader) throw this.logger.Error().Ref("cid", cid).Msg("missing car reader").AsError();
2578
- for await (const block of reader.blocks()) {
2579
- const sCid = block.cid.toString();
2580
- if (!this.getBlockCache.has(sCid)) {
2581
- yield block;
2582
- }
2583
- }
2584
- }
2585
- }
2457
+ return import_cement8.Result.Err(this.logger.Error().Url(url).Msg("subscribe not supported").AsError());
2586
2458
  }
2587
2459
  }
2588
- async getBlock(cid) {
2589
- await this.ready();
2590
- const sCid = cid.toString();
2591
- if (this.getBlockCache.has(sCid)) return this.getBlockCache.get(sCid);
2592
- const getCarCid = async (carCid) => {
2593
- if (this.getBlockCache.has(sCid)) return this.getBlockCache.get(sCid);
2594
- const reader = await this.loadCar(carCid);
2595
- if (!reader) {
2596
- throw this.logger.Error().Ref("cid", carCid).Msg("missing car reader").AsError();
2597
- }
2598
- await this.cacheCarReader(carCid.toString(), reader).catch(() => {
2599
- return;
2600
- });
2601
- if (this.getBlockCache.has(sCid)) return this.getBlockCache.get(sCid);
2602
- throw this.logger.Error().Str("cid", sCid).Msg("block not in reader").AsError();
2603
- };
2604
- const getCompactCarCids = async (carCid) => {
2605
- const reader = await this.loadCar(carCid);
2606
- if (!reader) {
2607
- throw this.logger.Error().Str("cid", carCid.toString()).Msg("missing car reader").AsError();
2608
- }
2609
- const header = await parseCarFile(reader, this.logger);
2610
- const compacts = header.compact;
2611
- let got2;
2612
- const batchSize2 = 5;
2613
- for (let i = 0; i < compacts.length; i += batchSize2) {
2614
- const promises = [];
2615
- for (let j = i; j < Math.min(i + batchSize2, compacts.length); j++) {
2616
- for (const cid2 of compacts[j]) {
2617
- promises.push(getCarCid(cid2));
2618
- }
2619
- }
2620
- try {
2621
- got2 = await Promise.any(promises);
2622
- } catch {
2623
- }
2624
- if (got2) break;
2625
- }
2626
- if (this.getBlockCache.has(sCid)) return this.getBlockCache.get(sCid);
2627
- throw this.logger.Error().Str("cid", sCid).Msg("block not in compact reader").AsError();
2628
- };
2629
- let got;
2630
- const batchSize = 5;
2631
- for (let i = 0; i < this.carLog.length; i += batchSize) {
2632
- const batch = this.carLog.slice(i, i + batchSize);
2633
- const promises = batch.flatMap((slice) => slice.map(getCarCid));
2634
- try {
2635
- got = await Promise.any(promises);
2636
- } catch {
2637
- }
2638
- if (got) break;
2639
- }
2640
- if (!got) {
2641
- try {
2642
- got = await getCompactCarCids(this.carLog[this.carLog.length - 1][0]);
2643
- } catch {
2460
+ async delete(url) {
2461
+ const rfrags = await getFrags(url, this.innerGW, this.headerSize, this.logger);
2462
+ for (const rfrag of rfrags) {
2463
+ if (rfrag.isErr()) {
2464
+ return import_cement8.Result.Err(rfrag.Err());
2644
2465
  }
2466
+ const frag = rfrag.Ok();
2467
+ const fidStr = import_base584.base58btc.encode(frag.fid);
2468
+ const fragUrl = url.build().setParam("fid", fidStr).setParam("len", frag.len.toString()).setParam("headerSize", this.headerSize.toString()).URI();
2469
+ await this.innerGW.delete(fragUrl);
2645
2470
  }
2646
- return got;
2471
+ return import_cement8.Result.Ok(void 0);
2647
2472
  }
2648
- async loadCar(cid) {
2649
- if (!this.carStore) {
2650
- throw this.logger.Error().Msg("car store not initialized").AsError();
2651
- }
2652
- const loaded = await this.storesLoadCar(cid, await this.carStore(), this.remoteCarStore);
2653
- return loaded;
2473
+ };
2474
+
2475
+ // src/blockstore/meta-key-helper.ts
2476
+ var import_dag_json = require("@ipld/dag-json");
2477
+ var import_clock = require("@web3-storage/pail/clock");
2478
+ var import_multiformats2 = require("multiformats");
2479
+ var import_base64 = require("multiformats/bases/base64");
2480
+ var import_cement9 = require("@adviser/cement");
2481
+ async function decodeGatewayMetaBytesToDbMeta(sthis, byteHeads) {
2482
+ const crdtEntries = JSON.parse(sthis.txt.decode(byteHeads));
2483
+ if (!crdtEntries.length) {
2484
+ sthis.logger.Debug().Str("byteHeads", new TextDecoder().decode(byteHeads)).Msg("No CRDT entries found");
2485
+ return [];
2654
2486
  }
2655
- async makeDecoderAndCarReader(cid, local, remote) {
2656
- const cidsString = cid.toString();
2657
- let loadedCar = void 0;
2658
- let activeStore = local;
2659
- try {
2660
- this.logger.Debug().Str("cid", cidsString).Msg("loading car");
2661
- loadedCar = await local.load(cid);
2662
- this.logger.Debug().Bool("loadedCar", loadedCar).Msg("loaded");
2663
- } catch (e) {
2664
- if (remote) {
2665
- const remoteCar = await remote.load(cid);
2666
- if (remoteCar) {
2667
- this.logger.Debug().Ref("cid", remoteCar.cid).Msg("saving remote car locally");
2668
- await local.save(remoteCar);
2669
- loadedCar = remoteCar;
2670
- activeStore = remote;
2487
+ if (!crdtEntries.map) {
2488
+ sthis.logger.Debug().Str("crdtEntries", JSON.stringify(crdtEntries)).Msg("No data in CRDT entries");
2489
+ return [];
2490
+ }
2491
+ return Promise.all(
2492
+ crdtEntries.map(async (crdtEntry) => {
2493
+ const eventBlock = await (0, import_clock.decodeEventBlock)(import_base64.base64pad.decode(crdtEntry.data));
2494
+ const dbMeta = (0, import_dag_json.parse)(sthis.txt.decode(eventBlock.value.data.dbMeta));
2495
+ return {
2496
+ eventCid: eventBlock.cid,
2497
+ parents: crdtEntry.parents,
2498
+ dbMeta
2499
+ };
2500
+ })
2501
+ );
2502
+ }
2503
+ async function setCryptoKeyFromGatewayMetaPayload(uri, sthis, data) {
2504
+ try {
2505
+ sthis.logger.Debug().Str("uri", uri.toString()).Msg("Setting crypto key from gateway meta payload");
2506
+ const keyInfo = await decodeGatewayMetaBytesToDbMeta(sthis, data);
2507
+ if (keyInfo.length) {
2508
+ const dbMeta = keyInfo[0].dbMeta;
2509
+ if (dbMeta.key) {
2510
+ const kb = await getKeyBag(sthis);
2511
+ const keyName = getStoreKeyName(uri);
2512
+ const res = await kb.setNamedKey(keyName, dbMeta.key);
2513
+ if (res.isErr()) {
2514
+ sthis.logger.Debug().Str("keyName", keyName).Str("dbMeta.key", dbMeta.key).Msg("Failed to set named key");
2515
+ throw res.Err();
2671
2516
  }
2672
- } else {
2673
- this.logger.Error().Str("cid", cidsString).Err(e).Msg("loading car");
2674
2517
  }
2518
+ sthis.logger.Debug().Str("dbMeta.key", dbMeta.key).Str("uri", uri.toString()).Msg("Set crypto key from gateway meta payload");
2519
+ return import_cement9.Result.Ok(dbMeta);
2675
2520
  }
2676
- if (!loadedCar) {
2677
- throw this.logger.Error().Url(local.url()).Str("cid", cidsString).Msg("missing car files").AsError();
2678
- }
2679
- const bytes = await decode3({ bytes: loadedCar.bytes, hasher: import_sha24.sha256, codec: (await activeStore.keyedCrypto()).codec() });
2680
- const rawReader = await import_car.CarReader.fromBytes(bytes.value);
2681
- const readerP = Promise.resolve(rawReader);
2682
- const cachedReaderP = readerP.then(async (reader) => {
2683
- await this.cacheCarReader(cidsString, reader).catch((e) => {
2684
- this.logger.Error().Err(e).Str("cid", cidsString).Msg("error caching car reader");
2685
- return;
2686
- });
2687
- return reader;
2688
- });
2689
- this.carReaders.set(cidsString, cachedReaderP);
2690
- return readerP;
2521
+ sthis.logger.Debug().Str("data", new TextDecoder().decode(data)).Msg("No crypto in gateway meta payload");
2522
+ return import_cement9.Result.Ok(void 0);
2523
+ } catch (error) {
2524
+ sthis.logger.Debug().Err(error).Msg("Failed to set crypto key from gateway meta payload");
2525
+ return import_cement9.Result.Err(error);
2691
2526
  }
2692
- //What if instead it returns an Array of CarHeader
2693
- async storesLoadCar(cid, local, remote) {
2694
- const cidsString = cid.toString();
2695
- let dacr = this.carReaders.get(cidsString);
2696
- if (!dacr) {
2697
- dacr = this.makeDecoderAndCarReader(cid, local, remote);
2698
- this.carReaders.set(cidsString, dacr);
2527
+ }
2528
+ async function addCryptoKeyToGatewayMetaPayload(uri, sthis, body) {
2529
+ try {
2530
+ sthis.logger.Debug().Str("uri", uri.toString()).Msg("Adding crypto key to gateway meta payload");
2531
+ const keyName = getStoreKeyName(uri);
2532
+ const kb = await getKeyBag(sthis);
2533
+ const res = await kb.getNamedExtractableKey(keyName, true);
2534
+ if (res.isErr()) {
2535
+ sthis.logger.Error().Str("keyName", keyName).Msg("Failed to get named extractable key");
2536
+ throw res.Err();
2699
2537
  }
2700
- return dacr;
2538
+ const keyData = await res.Ok().extract();
2539
+ const dbMetas = await decodeGatewayMetaBytesToDbMeta(sthis, body);
2540
+ const { dbMeta, parents } = dbMetas[0];
2541
+ const parentLinks = parents.map((p) => import_multiformats2.CID.parse(p));
2542
+ dbMeta.key = keyData.keyStr;
2543
+ const events = await Promise.all([dbMeta].map((dbMeta2) => createDbMetaEventBlock(sthis, dbMeta2, parentLinks)));
2544
+ const encoded = await encodeEventsWithParents(sthis, events, parentLinks);
2545
+ sthis.logger.Debug().Str("uri", uri.toString()).Msg("Added crypto key to gateway meta payload");
2546
+ return import_cement9.Result.Ok(encoded);
2547
+ } catch (error) {
2548
+ sthis.logger.Error().Err(error).Msg("Failed to add crypto key to gateway meta payload");
2549
+ return import_cement9.Result.Err(error);
2701
2550
  }
2702
- async getMoreReaders(cids) {
2703
- const limit = (0, import_p_limit.default)(5);
2704
- const missing = cids.filter((cid) => !this.carReaders.has(cid.toString()));
2705
- await Promise.all(missing.map((cid) => limit(() => this.loadCar(cid))));
2551
+ }
2552
+ function getStoreKeyName(url) {
2553
+ const storeKeyName = [url.getParam("localName") || url.getParam("name")];
2554
+ const idx = url.getParam("index");
2555
+ if (idx) {
2556
+ storeKeyName.push(idx);
2706
2557
  }
2707
- };
2558
+ storeKeyName.push("data");
2559
+ return `@${storeKeyName.join(":")}@`;
2560
+ }
2561
+ async function createDbMetaEventBlock(sthis, dbMeta, parents) {
2562
+ const event = await import_clock.EventBlock.create(
2563
+ {
2564
+ dbMeta: sthis.txt.encode((0, import_dag_json.format)(dbMeta))
2565
+ },
2566
+ parents
2567
+ );
2568
+ return event;
2569
+ }
2570
+ async function encodeEventsWithParents(sthis, events, parents) {
2571
+ const crdtEntries = events.map((event) => {
2572
+ const base64String = import_base64.base64pad.encode(event.bytes);
2573
+ return {
2574
+ cid: event.cid.toString(),
2575
+ data: base64String,
2576
+ parents: parents.map((p) => p.toString())
2577
+ };
2578
+ });
2579
+ return sthis.txt.encode(JSON.stringify(crdtEntries));
2580
+ }
2708
2581
 
2709
2582
  // src/blockstore/store.ts
2583
+ var import_p_retry = __toESM(require("p-retry"), 1);
2584
+ var import_p_map = __toESM(require("p-map"), 1);
2710
2585
  function guardVersion(url) {
2711
2586
  if (!url.hasParam("version")) {
2712
2587
  return import_cement10.Result.Err(`missing version: ${url.toString()}`);
@@ -2714,21 +2589,16 @@ function guardVersion(url) {
2714
2589
  return import_cement10.Result.Ok(url);
2715
2590
  }
2716
2591
  var BaseStoreImpl = class {
2717
- constructor(sthis, url, opts, logger) {
2592
+ constructor(name, url, opts, sthis, logger) {
2718
2593
  this._onStarted = [];
2719
2594
  this._onClosed = [];
2595
+ this.name = name;
2720
2596
  this._url = url;
2721
2597
  this.keybag = opts.keybag;
2722
- this.loader = opts.loader;
2723
2598
  this.sthis = sthis;
2724
- const name = this._url.getParam("name" /* NAME */);
2725
- if (!name) {
2726
- throw logger.Error().Str("url", this._url.toString()).Msg("missing name").AsError();
2727
- }
2728
- this.name = name;
2729
- this.logger = logger.With().Str("this", this.sthis.nextId().str).Ref("url", () => this._url.toString()).Logger();
2730
- this.realGateway = opts.gateway;
2599
+ this.logger = logger.With().Ref("url", () => this._url.toString()).Str("name", name).Logger();
2731
2600
  this.gateway = new FragmentGateway(this.sthis, opts.gateway);
2601
+ this.loader = opts.loader;
2732
2602
  }
2733
2603
  url() {
2734
2604
  return this._url;
@@ -2743,20 +2613,20 @@ var BaseStoreImpl = class {
2743
2613
  return;
2744
2614
  }
2745
2615
  async keyedCrypto() {
2746
- return keyedCryptoFactory(this._url, this.keybag, this.sthis);
2616
+ return keyedCryptoFactory(this._url, await this.keybag(), this.sthis);
2747
2617
  }
2748
2618
  async start() {
2749
2619
  this.logger.Debug().Str("storeType", this.storeType).Msg("starting-gateway-pre");
2750
- this._url = this._url.build().setParam("store" /* STORE */, this.storeType).URI();
2620
+ this._url = this._url.build().setParam("store", this.storeType).URI();
2751
2621
  const res = await this.gateway.start(this._url);
2752
2622
  if (res.isErr()) {
2753
2623
  this.logger.Error().Result("gw-start", res).Msg("started-gateway");
2754
2624
  return res;
2755
2625
  }
2756
2626
  this._url = res.Ok();
2757
- const kb = await this.keybag;
2627
+ const kb = await this.keybag();
2758
2628
  const skRes = await kb.ensureKeyFromUrl(this._url, () => {
2759
- const idx = this._url.getParam("index" /* INDEX */);
2629
+ const idx = this._url.getParam("index");
2760
2630
  const storeKeyName = [this.name];
2761
2631
  if (idx) {
2762
2632
  storeKeyName.push(idx);
@@ -2789,8 +2659,8 @@ var BaseStoreImpl = class {
2789
2659
  };
2790
2660
  var MetaStoreImpl = class extends BaseStoreImpl {
2791
2661
  // remote: boolean;
2792
- constructor(sthis, url, opts) {
2793
- super(sthis, url, { ...opts }, ensureLogger(sthis, "MetaStoreImpl"));
2662
+ constructor(sthis, name, url, opts) {
2663
+ super(name, url, { ...opts }, sthis, ensureLogger(sthis, "MetaStoreImpl"));
2794
2664
  this.storeType = "meta";
2795
2665
  this.subscribers = /* @__PURE__ */ new Map();
2796
2666
  this.parents = [];
@@ -2861,21 +2731,13 @@ var MetaStoreImpl = class extends BaseStoreImpl {
2861
2731
  return import_cement10.Result.Ok(void 0);
2862
2732
  }
2863
2733
  async destroy() {
2864
- this.logger.Debug().Msg("destroy");
2865
2734
  return this.gateway.destroy(this.url());
2866
2735
  }
2867
2736
  };
2868
2737
  var DataStoreImpl = class extends BaseStoreImpl {
2869
2738
  // readonly tag: string = "car-base";
2870
- constructor(sthis, url, opts) {
2871
- super(
2872
- sthis,
2873
- url,
2874
- {
2875
- ...opts
2876
- },
2877
- ensureLogger(sthis, "DataStoreImpl")
2878
- );
2739
+ constructor(sthis, name, url, opts) {
2740
+ super(name, url, { ...opts }, sthis, ensureLogger(sthis, "DataStoreImpl"));
2879
2741
  this.storeType = "data";
2880
2742
  }
2881
2743
  async load(cid) {
@@ -2916,32 +2778,23 @@ var DataStoreImpl = class extends BaseStoreImpl {
2916
2778
  return import_cement10.Result.Ok(void 0);
2917
2779
  }
2918
2780
  destroy() {
2919
- this.logger.Debug().Msg("destroy");
2920
2781
  return this.gateway.destroy(this.url());
2921
2782
  }
2922
2783
  };
2923
2784
  var WALStoreImpl = class extends BaseStoreImpl {
2924
- constructor(sthis, url, opts) {
2925
- super(
2926
- sthis,
2927
- url,
2928
- {
2929
- ...opts
2930
- },
2931
- ensureLogger(sthis, "WALStoreImpl")
2932
- );
2785
+ constructor(loader, url, opts) {
2786
+ super(loader.name, url, { ...opts }, loader.sthis, ensureLogger(loader.sthis, "WALStoreImpl"));
2933
2787
  this.storeType = "wal";
2934
- // readonly tag: string = "rwal-base";
2935
- // readonly loader: Loadable;
2936
2788
  this._ready = new import_cement10.ResolveOnce();
2937
2789
  this.walState = { operations: [], noLoaderOps: [], fileOperations: [] };
2938
2790
  this.processing = void 0;
2939
2791
  this.processQueue = new CommitQueue();
2792
+ this.loader = loader;
2940
2793
  }
2941
2794
  async ready() {
2942
2795
  return this._ready.once(async () => {
2943
2796
  const walState = await this.load().catch((e) => {
2944
- this.logger.Error().Err(e).Msg("error loading wal");
2797
+ this.logger.Error().Any("error", e).Msg("error loading wal");
2945
2798
  return void 0;
2946
2799
  });
2947
2800
  if (!walState) {
@@ -2974,7 +2827,7 @@ var WALStoreImpl = class extends BaseStoreImpl {
2974
2827
  }
2975
2828
  async process() {
2976
2829
  await this.ready();
2977
- if (!this.loader?.remoteCarStore) return;
2830
+ if (!this.loader.remoteCarStore) return;
2978
2831
  await this.processQueue.enqueue(async () => {
2979
2832
  try {
2980
2833
  await this._doProcess();
@@ -2987,7 +2840,6 @@ var WALStoreImpl = class extends BaseStoreImpl {
2987
2840
  });
2988
2841
  }
2989
2842
  async _doProcess() {
2990
- if (!this.loader) return;
2991
2843
  if (!this.loader.remoteCarStore) return;
2992
2844
  const operations = [...this.walState.operations];
2993
2845
  const noLoaderOps = [...this.walState.noLoaderOps];
@@ -3005,7 +2857,6 @@ var WALStoreImpl = class extends BaseStoreImpl {
3005
2857
  noLoaderOps,
3006
2858
  async (dbMeta) => {
3007
2859
  await retryableUpload(async () => {
3008
- if (!this.loader) return;
3009
2860
  for (const cid of dbMeta.cars) {
3010
2861
  const car = await (await this.loader.carStore()).load(cid);
3011
2862
  if (!car) {
@@ -3025,7 +2876,6 @@ var WALStoreImpl = class extends BaseStoreImpl {
3025
2876
  operations,
3026
2877
  async (dbMeta) => {
3027
2878
  await retryableUpload(async () => {
3028
- if (!this.loader) return;
3029
2879
  for (const cid of dbMeta.cars) {
3030
2880
  const car = await (await this.loader.carStore()).load(cid);
3031
2881
  if (!car) {
@@ -3045,7 +2895,6 @@ var WALStoreImpl = class extends BaseStoreImpl {
3045
2895
  fileOperations,
3046
2896
  async ({ cid: fileCid, public: publicFile }) => {
3047
2897
  await retryableUpload(async () => {
3048
- if (!this.loader) return;
3049
2898
  const fileBlock = await (await this.loader.fileStore()).load(fileCid);
3050
2899
  if (!fileBlock) {
3051
2900
  throw this.logger.Error().Ref("cid", fileCid).Msg("missing file block").AsError();
@@ -3059,7 +2908,6 @@ var WALStoreImpl = class extends BaseStoreImpl {
3059
2908
  if (operations.length) {
3060
2909
  const lastOp = operations[operations.length - 1];
3061
2910
  await retryableUpload(async () => {
3062
- if (!this.loader) return;
3063
2911
  await this.loader.remoteMetaStore?.save(lastOp);
3064
2912
  }, `remoteMetaStore save with dbMeta.cars=${lastOp.cars.toString()}`);
3065
2913
  }
@@ -3085,7 +2933,6 @@ var WALStoreImpl = class extends BaseStoreImpl {
3085
2933
  }
3086
2934
  try {
3087
2935
  return bytes && (0, import_dag_json2.parse)(this.sthis.txt.decode(bytes.Ok()));
3088
- return bytes && (0, import_dag_json2.parse)(this.sthis.txt.decode(bytes.Ok()));
3089
2936
  } catch (e) {
3090
2937
  throw this.logger.Error().Err(e).Msg("error parse").AsError();
3091
2938
  }
@@ -3112,98 +2959,73 @@ var WALStoreImpl = class extends BaseStoreImpl {
3112
2959
  return import_cement10.Result.Ok(void 0);
3113
2960
  }
3114
2961
  destroy() {
3115
- this.logger.Debug().Msg("destroy");
3116
2962
  return this.gateway.destroy(this.url());
3117
2963
  }
3118
2964
  };
3119
2965
 
3120
2966
  // src/blockstore/store-factory.ts
3121
- init_types();
3122
-
3123
- // src/blockstore/register-store-protocol.ts
3124
- var import_cement14 = require("@adviser/cement");
3125
- init_version();
3126
-
3127
- // src/runtime/gateways/memory/gateway.ts
3128
- var import_cement11 = require("@adviser/cement");
3129
- init_types();
3130
-
3131
- // src/runtime/gateways/memory/version.ts
3132
- var MEMORY_VERSION = "v0.19-memory";
3133
-
3134
- // src/runtime/gateways/memory/gateway.ts
3135
2967
  init_utils();
3136
- var MemoryGateway = class {
3137
- constructor(memorys) {
3138
- this.memorys = memorys;
2968
+ function ensureIsIndex(url, isIndex) {
2969
+ if (isIndex) {
2970
+ return url.build().setParam("index", isIndex).URI();
3139
2971
  }
3140
- buildUrl(baseUrl, key) {
3141
- return Promise.resolve(import_cement11.Result.Ok(baseUrl.build().setParam("key" /* KEY */, key).URI()));
3142
- }
3143
- start(baseUrl) {
3144
- return Promise.resolve(import_cement11.Result.Ok(baseUrl.build().setParam("version" /* VERSION */, MEMORY_VERSION).URI()));
3145
- }
3146
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
3147
- close(baseUrl) {
3148
- return Promise.resolve(import_cement11.Result.Ok(void 0));
3149
- }
3150
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
3151
- destroy(baseUrl) {
3152
- this.memorys.clear();
3153
- return Promise.resolve(import_cement11.Result.Ok(void 0));
3154
- }
3155
- put(url, body) {
3156
- this.memorys.set(url.toString(), body);
3157
- return Promise.resolve(import_cement11.Result.Ok(void 0));
3158
- }
3159
- // get could return a NotFoundError if the key is not found
3160
- get(url) {
3161
- const x = this.memorys.get(url.toString());
3162
- if (x === void 0) {
3163
- return Promise.resolve(import_cement11.Result.Err(new NotFoundError("not found")));
3164
- }
3165
- return Promise.resolve(import_cement11.Result.Ok(x));
3166
- }
3167
- delete(url) {
3168
- this.memorys.delete(url.toString());
3169
- return Promise.resolve(import_cement11.Result.Ok(void 0));
3170
- }
3171
- };
3172
- var MemoryTestGateway = class {
3173
- constructor(memorys) {
3174
- this.memorys = memorys;
3175
- }
3176
- async get(url, key) {
3177
- return this.memorys.get(url.build().setParam("key" /* KEY */, key).toString());
2972
+ return url.build().delParam("index").URI();
2973
+ }
2974
+ function ensureName(name, url) {
2975
+ if (!url.hasParam("name")) {
2976
+ return url.build().setParam("name", name).URI();
3178
2977
  }
3179
- };
3180
-
3181
- // src/blockstore/register-store-protocol.ts
2978
+ return url;
2979
+ }
3182
2980
  var storeFactory = /* @__PURE__ */ new Map();
3183
- function getDefaultURI(sthis, protocol) {
3184
- if (protocol) {
3185
- if (!protocol.endsWith(":")) {
3186
- protocol += ":";
3187
- }
3188
- const gfi = storeFactory.get(protocol);
3189
- if (gfi) {
3190
- return gfi.defaultURI(sthis);
2981
+ function buildURL(optURL, loader) {
2982
+ const storeOpts = loader.ebOpts.store;
2983
+ const obuItem = Array.from(storeFactory.values()).find((items) => items.overrideBaseURL);
2984
+ let obuUrl;
2985
+ if (obuItem && obuItem.overrideBaseURL) {
2986
+ obuUrl = import_cement13.URI.from(obuItem.overrideBaseURL);
2987
+ }
2988
+ const ret = ensureIsIndex(
2989
+ import_cement13.URI.from(optURL || obuUrl || dataDir(loader.sthis, loader.name, storeOpts.stores?.base)),
2990
+ storeOpts.isIndex
2991
+ );
2992
+ return ret;
2993
+ }
2994
+ var onceGateway = new import_cement13.KeyedResolvOnce();
2995
+ async function getGatewayFromURL(url, sthis) {
2996
+ return onceGateway.get(url.toString()).once(async () => {
2997
+ const item = storeFactory.get(url.protocol);
2998
+ if (item) {
2999
+ const ret = {
3000
+ gateway: await item.gateway(sthis),
3001
+ test: await item.test(sthis)
3002
+ };
3003
+ const res = await ret.gateway.start(url);
3004
+ if (res.isErr()) {
3005
+ sthis.logger.Error().Result("start", res).Msg("start failed");
3006
+ return void 0;
3007
+ }
3008
+ return ret;
3191
3009
  }
3192
- }
3193
- const found = Array.from(storeFactory.values()).find((item) => item.isDefault);
3194
- if (!found) {
3195
- throw sthis.logger.Error().Msg("no default found").AsError();
3196
- }
3197
- return found.defaultURI(sthis);
3010
+ sthis.logger.Warn().Url(url).Msg("unsupported protocol");
3011
+ return void 0;
3012
+ });
3198
3013
  }
3199
3014
  function registerStoreProtocol(item) {
3200
3015
  let protocol = item.protocol;
3201
3016
  if (!protocol.endsWith(":")) {
3202
3017
  protocol += ":";
3203
3018
  }
3204
- if (item.isDefault) {
3019
+ if (storeFactory.has(protocol)) {
3020
+ if (!item.overrideBaseURL && storeFactory.get(protocol) !== item) {
3021
+ throw new Error(`we need a logger here`);
3022
+ return () => {
3023
+ };
3024
+ }
3025
+ }
3026
+ if (item.overrideBaseURL) {
3205
3027
  Array.from(storeFactory.values()).forEach((items) => {
3206
- items.isDefault = false;
3028
+ items.overrideBaseURL = void 0;
3207
3029
  });
3208
3030
  }
3209
3031
  storeFactory.set(protocol, item);
@@ -3211,186 +3033,134 @@ function registerStoreProtocol(item) {
3211
3033
  storeFactory.delete(protocol);
3212
3034
  };
3213
3035
  }
3214
- function getGatewayFactoryItem(protocol) {
3215
- return storeFactory.get(protocol);
3216
- }
3217
- function fileGatewayFactoryItem() {
3218
- return {
3219
- protocol: "file:",
3220
- isDefault: true,
3221
- defaultURI: (sthis) => {
3222
- return import_cement14.BuildURI.from("file://").pathname(`${sthis.env.get("HOME")}/.fireproof/${FILESTORE_VERSION.replace(/-.*$/, "")}`).URI();
3223
- },
3224
- gateway: async (sthis) => {
3225
- const { FileGateway: FileGateway2 } = await Promise.resolve().then(() => (init_gateway(), gateway_exports));
3226
- return new FileGateway2(sthis);
3227
- },
3228
- test: async (sthis) => {
3229
- const { FileTestStore: FileTestStore2 } = await Promise.resolve().then(() => (init_gateway(), gateway_exports));
3230
- return new FileTestStore2(sthis);
3231
- }
3232
- };
3233
- }
3234
- if ((0, import_cement14.runtimeFn)().isBrowser) {
3235
- registerStoreProtocol({
3236
- protocol: "indexdb:",
3237
- isDefault: true,
3238
- defaultURI: () => {
3239
- return import_cement14.BuildURI.from("indexdb://").pathname("fp").URI();
3240
- },
3241
- gateway: async (logger) => {
3242
- const { IndexDBGateway: IndexDBGateway2 } = await Promise.resolve().then(() => (init_gateway2(), gateway_exports2));
3243
- return new IndexDBGateway2(logger);
3244
- },
3245
- test: async (logger) => {
3246
- const { IndexDBTestStore: IndexDBTestStore2 } = await Promise.resolve().then(() => (init_gateway2(), gateway_exports2));
3247
- return new IndexDBTestStore2(logger);
3248
- }
3249
- });
3250
- } else {
3251
- registerStoreProtocol(fileGatewayFactoryItem());
3252
- }
3253
- var memory = /* @__PURE__ */ new Map();
3254
- registerStoreProtocol({
3255
- protocol: "memory:",
3256
- isDefault: false,
3257
- defaultURI: () => {
3258
- return import_cement14.BuildURI.from("memory://").pathname("ram").URI();
3259
- },
3260
- gateway: async () => {
3261
- return new MemoryGateway(memory);
3262
- },
3263
- test: async () => {
3264
- return new MemoryTestGateway(memory);
3265
- }
3266
- });
3267
-
3268
- // src/blockstore/store-factory.ts
3269
- var onceGateway = new import_cement15.KeyedResolvOnce();
3270
- var gatewayInstances = new import_cement15.KeyedResolvOnce();
3271
- async function getStartedGateway(sthis, url) {
3272
- return onceGateway.get(url.toString()).once(async () => {
3273
- const item = getGatewayFactoryItem(url.protocol);
3274
- if (item) {
3275
- const ret = {
3276
- url,
3277
- ...await gatewayInstances.get(url.protocol).once(async () => ({
3278
- gateway: await item.gateway(sthis),
3279
- test: await item.test(sthis)
3280
- }))
3281
- };
3282
- const res = await ret.gateway.start(url);
3283
- if (res.isErr()) {
3284
- return import_cement15.Result.Err(sthis.logger.Error().Result("start", res).Msg("start failed").AsError());
3285
- }
3286
- ret.url = res.Ok();
3287
- return import_cement15.Result.Ok(ret);
3288
- }
3289
- return import_cement15.Result.Err(sthis.logger.Warn().Url(url).Msg("unsupported protocol").AsError());
3290
- });
3291
- }
3292
- async function dataStoreFactory(sfi) {
3293
- const storeUrl = sfi.url.build().setParam("store" /* STORE */, "data").URI();
3294
- const rgateway = await getStartedGateway(sfi.sthis, storeUrl);
3295
- if (rgateway.isErr()) {
3296
- throw sfi.sthis.logger.Error().Result("err", rgateway).Url(sfi.url).Msg("notfound").AsError();
3297
- }
3298
- const gateway = rgateway.Ok();
3299
- const store = new DataStoreImpl(sfi.sthis, gateway.url, {
3300
- gateway: gateway.gateway,
3301
- keybag: sfi.keybag
3036
+ var onceDataStoreFactory = new import_cement13.KeyedResolvOnce();
3037
+ async function dataStoreFactory(loader) {
3038
+ const url = ensureName(loader.name, buildURL(loader.ebOpts.store.stores?.data, loader)).build().setParam("store", "data").URI();
3039
+ const sthis = ensureSuperLog(loader.sthis, "dataStoreFactory", { url: url.toString() });
3040
+ return onceDataStoreFactory.get(url.toString()).once(async () => {
3041
+ const gateway = await getGatewayFromURL(url, sthis);
3042
+ if (!gateway) {
3043
+ throw sthis.logger.Error().Url(url).Msg("gateway not found").AsError();
3044
+ }
3045
+ const store = new DataStoreImpl(sthis, loader.name, url, {
3046
+ gateway: gateway.gateway,
3047
+ keybag: () => getKeyBag(loader.sthis, {
3048
+ ...loader.ebOpts.keyBag
3049
+ })
3050
+ });
3051
+ return store;
3302
3052
  });
3303
- return store;
3304
3053
  }
3305
- async function metaStoreFactory(sfi) {
3306
- const storeUrl = sfi.url.build().setParam("store" /* STORE */, "meta").URI();
3307
- const rgateway = await getStartedGateway(sfi.sthis, storeUrl);
3308
- if (rgateway.isErr()) {
3309
- throw sfi.sthis.logger.Error().Result("err", rgateway).Url(sfi.url).Msg("notfound").AsError();
3310
- }
3311
- const gateway = rgateway.Ok();
3312
- const store = new MetaStoreImpl(sfi.sthis, gateway.url, {
3313
- gateway: gateway.gateway,
3314
- keybag: sfi.keybag
3054
+ var onceMetaStoreFactory = new import_cement13.KeyedResolvOnce();
3055
+ async function metaStoreFactory(loader) {
3056
+ const url = ensureName(loader.name, buildURL(loader.ebOpts.store.stores?.meta, loader)).build().setParam("store", "meta").URI();
3057
+ const sthis = ensureSuperLog(loader.sthis, "metaStoreFactory", { url: () => url.toString() });
3058
+ return onceMetaStoreFactory.get(url.toString()).once(async () => {
3059
+ sthis.logger.Debug().Str("protocol", url.protocol).Msg("pre-protocol switch");
3060
+ const gateway = await getGatewayFromURL(url, sthis);
3061
+ if (!gateway) {
3062
+ throw sthis.logger.Error().Url(url).Msg("gateway not found").AsError();
3063
+ }
3064
+ const store = new MetaStoreImpl(loader.sthis, loader.name, url, {
3065
+ gateway: gateway.gateway,
3066
+ keybag: () => getKeyBag(loader.sthis, {
3067
+ ...loader.ebOpts.keyBag
3068
+ })
3069
+ });
3070
+ return store;
3315
3071
  });
3316
- return store;
3317
3072
  }
3318
- async function WALStoreFactory(sfi) {
3319
- const storeUrl = sfi.url.build().setParam("store" /* STORE */, "wal").URI();
3320
- const rgateway = await getStartedGateway(sfi.sthis, storeUrl);
3321
- if (rgateway.isErr()) {
3322
- throw sfi.sthis.logger.Error().Result("err", rgateway).Url(sfi.url).Msg("notfound").AsError();
3323
- }
3324
- const gateway = rgateway.Ok();
3325
- const store = new WALStoreImpl(sfi.sthis, gateway.url, {
3326
- gateway: gateway.gateway,
3327
- keybag: sfi.keybag
3073
+ var onceRemoteWalFactory = new import_cement13.KeyedResolvOnce();
3074
+ async function remoteWalFactory(loader) {
3075
+ const url = ensureName(loader.name, buildURL(loader.ebOpts.store.stores?.wal, loader)).build().setParam("store", "wal").URI();
3076
+ const sthis = ensureSuperLog(loader.sthis, "remoteWalFactory", { url: url.toString() });
3077
+ return onceRemoteWalFactory.get(url.toString()).once(async () => {
3078
+ const gateway = await getGatewayFromURL(url, sthis);
3079
+ if (!gateway) {
3080
+ throw sthis.logger.Error().Url(url).Msg("gateway not found").AsError();
3081
+ }
3082
+ sthis.logger.Debug().Str("prepared", url.toString()).Msg("produced");
3083
+ const store = new WALStoreImpl(loader, url, {
3084
+ gateway: gateway.gateway,
3085
+ keybag: () => getKeyBag(loader.sthis, {
3086
+ ...loader.ebOpts.keyBag
3087
+ })
3088
+ });
3089
+ return store;
3328
3090
  });
3329
- return store;
3330
3091
  }
3331
3092
  async function testStoreFactory(url, sthis) {
3332
- const rgateway = await getStartedGateway(sthis, url);
3333
- if (!rgateway) {
3093
+ sthis = ensureSuperLog(sthis, "testStoreFactory");
3094
+ const gateway = await getGatewayFromURL(url, sthis);
3095
+ if (!gateway) {
3334
3096
  throw sthis.logger.Error().Url(url).Msg("gateway not found").AsError();
3335
3097
  }
3336
- return rgateway.Ok().test;
3098
+ return gateway.test;
3337
3099
  }
3338
- async function ensureStart(store) {
3100
+ async function ensureStart(store, logger) {
3339
3101
  const ret = await store.start();
3340
3102
  if (ret.isErr()) {
3341
- throw store.logger.Error().Result("start", ret).Msg("start failed").AsError();
3103
+ throw logger.Error().Result("start", ret).Msg("start failed").AsError();
3342
3104
  }
3343
- store.logger.Debug().Url(ret.Ok(), "prepared").Msg("produced");
3105
+ logger.Debug().Url(ret.Ok(), "prepared").Msg("produced");
3344
3106
  return store;
3345
3107
  }
3346
- function ensureStoreEnDeFile(ende) {
3347
- ende = ende || {};
3348
- return {
3349
- encodeFile: ende.encodeFile || encodeFile,
3350
- decodeFile: ende.decodeFile || decodeFile
3351
- };
3352
- }
3353
- function toStoreRuntime(sthis, endeOpts = {}) {
3108
+ function toStoreRuntime(opts, sthis) {
3109
+ const logger = ensureLogger(sthis, "toStoreRuntime", {});
3354
3110
  return {
3355
- makeMetaStore: async (sfi) => ensureStart(await metaStoreFactory(sfi)),
3356
- // async (loader: Loadable) => {
3357
- // logger
3358
- // .Debug()
3359
- // .Str("fromOpts", "" + !!endeOpts.func?.makeMetaStore)
3360
- // .Msg("makeMetaStore");
3361
- // return ensureStart(await (endeOpts.func?.makeMetaStore || metaStoreFactory)(loader), logger);
3362
- // },
3363
- makeDataStore: async (sfi) => ensureStart(await dataStoreFactory(sfi)),
3364
- // async (loader: Loadable) => {
3365
- // logger
3366
- // .Debug()
3367
- // .Str("fromOpts", "" + !!endeOpts.func?.makeDataStore)
3368
- // .Msg("makeDataStore");
3369
- // return ensureStart(await (endeOpts.func?.makeDataStore || dataStoreFactory)(loader), logger);
3370
- // },
3371
- makeWALStore: async (sfi) => ensureStart(await WALStoreFactory(sfi)),
3372
- // async (loader: Loadable) => {
3373
- // logger
3374
- // .Debug()
3375
- // .Str("fromOpts", "" + !!endeOpts.func?.makeWALStore)
3376
- // .Msg("makeRemoteWAL");
3377
- // return ensureStart(await (endeOpts.func?.makeWALStore || remoteWalFactory)(loader), logger);
3378
- // },
3379
- ...ensureStoreEnDeFile(endeOpts)
3111
+ makeMetaStore: async (loader) => {
3112
+ logger.Debug().Str("fromOpts", "" + !!loader.ebOpts.store.makeMetaStore).Msg("makeMetaStore");
3113
+ return ensureStart(await (loader.ebOpts.store.makeMetaStore || metaStoreFactory)(loader), logger);
3114
+ },
3115
+ makeDataStore: async (loader) => {
3116
+ logger.Debug().Str("fromOpts", "" + !!loader.ebOpts.store.makeDataStore).Msg("makeDataStore");
3117
+ return ensureStart(await (loader.ebOpts.store.makeDataStore || dataStoreFactory)(loader), logger);
3118
+ },
3119
+ makeWALStore: async (loader) => {
3120
+ logger.Debug().Str("fromOpts", "" + !!loader.ebOpts.store.makeWALStore).Msg("makeRemoteWAL");
3121
+ return ensureStart(await (loader.ebOpts.store.makeWALStore || remoteWalFactory)(loader), logger);
3122
+ },
3123
+ encodeFile: opts.encodeFile || encodeFile,
3124
+ decodeFile: opts.decodeFile || decodeFile
3380
3125
  };
3381
3126
  }
3382
-
3383
- // src/blockstore/connection-base.ts
3384
- init_types();
3127
+ registerStoreProtocol({
3128
+ protocol: "file:",
3129
+ gateway: async (sthis) => {
3130
+ const { FileGateway: FileGateway2 } = await Promise.resolve().then(() => (init_gateway(), gateway_exports));
3131
+ return new FileGateway2(sthis);
3132
+ },
3133
+ test: async (sthis) => {
3134
+ const { FileTestStore: FileTestStore2 } = await Promise.resolve().then(() => (init_gateway(), gateway_exports));
3135
+ return new FileTestStore2(sthis);
3136
+ }
3137
+ });
3138
+ registerStoreProtocol({
3139
+ protocol: "indexdb:",
3140
+ gateway: async (sthis) => {
3141
+ const { IndexDBGateway: IndexDBGateway2 } = await Promise.resolve().then(() => (init_gateway2(), gateway_exports2));
3142
+ return new IndexDBGateway2(sthis);
3143
+ },
3144
+ test: async (sthis) => {
3145
+ const { IndexDBTestStore: IndexDBTestStore2 } = await Promise.resolve().then(() => (init_gateway2(), gateway_exports2));
3146
+ return new IndexDBTestStore2(sthis);
3147
+ }
3148
+ });
3385
3149
 
3386
3150
  // src/blockstore/store-remote.ts
3387
3151
  async function RemoteDataStore(sthis, name, url, opts) {
3388
- const ds = new DataStoreImpl(sthis, url, opts);
3152
+ const ds = new DataStoreImpl(sthis, name, url, opts);
3389
3153
  await ds.start();
3390
3154
  return ds;
3391
3155
  }
3392
3156
  async function RemoteMetaStore(sthis, name, url, opts) {
3393
- const ms = new MetaStoreImpl(sthis, url, opts);
3157
+ const ms = new MetaStoreImpl(
3158
+ sthis,
3159
+ name,
3160
+ url,
3161
+ opts
3162
+ /* , true*/
3163
+ );
3394
3164
  await ms.start();
3395
3165
  return ms;
3396
3166
  }
@@ -3415,17 +3185,14 @@ var ConnectionBase = class {
3415
3185
  if (!loader) throw this.logger.Error().Msg("connectMeta_X: loader is required").AsError();
3416
3186
  this.loader = loader;
3417
3187
  await this.onConnect();
3418
- const metaUrl = this.url.build().defParam("store" /* STORE */, "meta").URI();
3419
- const rgateway = await getStartedGateway(loader.sthis, metaUrl);
3420
- if (rgateway.isErr())
3421
- throw this.logger.Error().Result("err", rgateway).Url(metaUrl).Msg("connectMeta_X: gateway is required").AsError();
3422
- const name = metaUrl.toString();
3188
+ const metaUrl = this.url.build().defParam("store", "meta").URI();
3189
+ const gateway = await getGatewayFromURL(metaUrl, this.loader.sthis);
3190
+ if (!gateway) throw this.logger.Error().Url(metaUrl).Msg("connectMeta_X: gateway is required").AsError();
3423
3191
  const dbName = metaUrl.getParam("name");
3424
- if (!dbName) throw this.logger.Error().Url(metaUrl).Msg("connectMeta_X: dbName is required").AsError();
3425
- const gateway = rgateway.Ok();
3426
- const remote = await RemoteMetaStore(loader.sthis, name, metaUrl, {
3192
+ if (!dbName) throw this.logger.Error().Url(metaUrl).Msg("connectMeta_X: name is required").AsError();
3193
+ const remote = await RemoteMetaStore(loader.sthis, dbName, metaUrl, {
3427
3194
  gateway: gateway.gateway,
3428
- keybag: await loader.keyBag(),
3195
+ keybag: () => getKeyBag(loader.sthis, loader.ebOpts.keyBag),
3429
3196
  loader
3430
3197
  });
3431
3198
  this.loader.remoteMetaStore = remote;
@@ -3438,15 +3205,14 @@ var ConnectionBase = class {
3438
3205
  async connectStorage_X({ loader }) {
3439
3206
  if (!loader) throw this.logger.Error().Msg("connectStorage_X: loader is required").AsError();
3440
3207
  this.loader = loader;
3441
- const dataUrl = this.url.build().defParam("store" /* STORE */, "data").URI();
3442
- const rgateway = await getStartedGateway(loader.sthis, dataUrl);
3443
- if (rgateway.isErr())
3444
- throw this.logger.Error().Result("err", rgateway).Url(dataUrl).Msg("connectStorage_X: gateway is required").AsError();
3208
+ const dataUrl = this.url.build().defParam("store", "data").URI();
3209
+ const gateway = await getGatewayFromURL(dataUrl, this.loader.sthis);
3210
+ if (!gateway) throw this.logger.Error().Url(dataUrl).Msg("connectStorage_X: gateway is required").AsError();
3445
3211
  const name = dataUrl.getParam("name");
3446
3212
  if (!name) throw this.logger.Error().Url(dataUrl).Msg("connectStorage_X: name is required").AsError;
3447
3213
  loader.remoteCarStore = await RemoteDataStore(loader.sthis, name, this.url, {
3448
- gateway: rgateway.Ok().gateway,
3449
- keybag: await loader.keyBag()
3214
+ gateway: gateway.gateway,
3215
+ keybag: () => getKeyBag(loader.sthis, this.loader?.ebOpts.keyBag)
3450
3216
  });
3451
3217
  loader.remoteFileStore = loader.remoteCarStore;
3452
3218
  }
@@ -3486,13 +3252,6 @@ var ConnectionBase = class {
3486
3252
  };
3487
3253
 
3488
3254
  // src/crdt-helpers.ts
3489
- var import_link = require("multiformats/link");
3490
- var import_sha25 = require("multiformats/hashes/sha2");
3491
- var codec = __toESM(require("@ipld/dag-cbor"), 1);
3492
- var import_crdt = require("@web3-storage/pail/crdt");
3493
- var import_clock2 = require("@web3-storage/pail/clock");
3494
- var Batch = __toESM(require("@web3-storage/pail/crdt/batch"), 1);
3495
- init_types();
3496
3255
  function time(tag) {
3497
3256
  }
3498
3257
  function timeEnd(tag) {
@@ -3540,7 +3299,7 @@ async function writeDocContent(store, blocks, update, logger) {
3540
3299
  await processFiles(store, blocks, update.value, logger);
3541
3300
  value = { doc: update.value };
3542
3301
  }
3543
- const block = await encode3({ value, hasher: import_sha25.sha256, codec });
3302
+ const block = await encode({ value, hasher: import_sha25.sha256, codec });
3544
3303
  blocks.putSync(block.cid, block.bytes);
3545
3304
  return block.cid;
3546
3305
  }
@@ -3631,7 +3390,7 @@ function readFileset(blocks, files, isPublic = false) {
3631
3390
  async function getValueFromLink(blocks, link, logger) {
3632
3391
  const block = await blocks.get(link);
3633
3392
  if (!block) throw logger.Error().Str("link", link.toString()).Msg(`Missing linked block`).AsError();
3634
- const { value } = await decode3({ bytes: block.bytes, hasher: import_sha25.sha256, codec });
3393
+ const { value } = await decode({ bytes: block.bytes, hasher: import_sha25.sha256, codec });
3635
3394
  const cvalue = {
3636
3395
  ...value,
3637
3396
  cid: link
@@ -3752,19 +3511,16 @@ async function doCompact(blockLog, head, logger) {
3752
3511
  async function getBlock(blocks, cidString) {
3753
3512
  const block = await blocks.get((0, import_link.parse)(cidString));
3754
3513
  if (!block) throw new Error(`Missing block ${cidString}`);
3755
- const { cid, value } = await decode3({ bytes: block.bytes, codec, hasher: import_sha25.sha256 });
3514
+ const { cid, value } = await decode({ bytes: block.bytes, codec, hasher: import_sha25.sha256 });
3756
3515
  return new Block({ cid, value, bytes: block.bytes });
3757
3516
  }
3758
3517
 
3759
- // src/indexer.ts
3760
- init_types();
3761
-
3762
3518
  // src/indexer-helpers.ts
3763
3519
  var import_sha26 = require("multiformats/hashes/sha2");
3764
3520
  var codec2 = __toESM(require("@ipld/dag-cbor"), 1);
3765
3521
  var import_charwise = __toESM(require("charwise"), 1);
3766
3522
  var DbIndex = __toESM(require("prolly-trees/db-index"), 1);
3767
- var import_utils15 = require("prolly-trees/utils");
3523
+ var import_utils16 = require("prolly-trees/utils");
3768
3524
  var import_cache = require("prolly-trees/cache");
3769
3525
  var IndexTree = class {
3770
3526
  };
@@ -3772,17 +3528,17 @@ function refCompare(aRef, bRef) {
3772
3528
  if (Number.isNaN(aRef)) return -1;
3773
3529
  if (Number.isNaN(bRef)) throw new Error("ref may not be Infinity or NaN");
3774
3530
  if (aRef === Infinity) return 1;
3775
- return (0, import_utils15.simpleCompare)(aRef, bRef);
3531
+ return (0, import_utils16.simpleCompare)(aRef, bRef);
3776
3532
  }
3777
3533
  function compare(a, b) {
3778
3534
  const [aKey, aRef] = a;
3779
3535
  const [bKey, bRef] = b;
3780
- const comp = (0, import_utils15.simpleCompare)(aKey, bKey);
3536
+ const comp = (0, import_utils16.simpleCompare)(aKey, bKey);
3781
3537
  if (comp !== 0) return comp;
3782
3538
  return refCompare(aRef, bRef);
3783
3539
  }
3784
- var byKeyOpts = { cache: import_cache.nocache, chunker: (0, import_utils15.bf)(30), codec: codec2, hasher: import_sha26.sha256, compare };
3785
- var byIdOpts = { cache: import_cache.nocache, chunker: (0, import_utils15.bf)(30), codec: codec2, hasher: import_sha26.sha256, compare: import_utils15.simpleCompare };
3540
+ var byKeyOpts = { cache: import_cache.nocache, chunker: (0, import_utils16.bf)(30), codec: codec2, hasher: import_sha26.sha256, compare };
3541
+ var byIdOpts = { cache: import_cache.nocache, chunker: (0, import_utils16.bf)(30), codec: codec2, hasher: import_sha26.sha256, compare: import_utils16.simpleCompare };
3786
3542
  function indexEntriesForChanges(changes, mapFn) {
3787
3543
  const indexEntries = [];
3788
3544
  changes.forEach(({ id: key, value, del }) => {
@@ -3813,8 +3569,7 @@ function makeProllyGetBlock(blocks) {
3813
3569
  return create({ cid, bytes, hasher: import_sha26.sha256, codec: codec2 });
3814
3570
  };
3815
3571
  }
3816
- async function bulkIndex(logger, tblocks, inIndex, indexEntries, opts) {
3817
- logger.Debug().Msg("enter bulkIndex");
3572
+ async function bulkIndex(tblocks, inIndex, indexEntries, opts) {
3818
3573
  if (!indexEntries.length) return inIndex;
3819
3574
  if (!inIndex.root) {
3820
3575
  if (!inIndex.cid) {
@@ -3831,22 +3586,18 @@ async function bulkIndex(logger, tblocks, inIndex, indexEntries, opts) {
3831
3586
  returnNode = node;
3832
3587
  }
3833
3588
  if (!returnNode || !returnRootBlock) throw new Error("failed to create index");
3834
- logger.Debug().Msg("exit !root bulkIndex");
3835
3589
  return { root: returnNode, cid: returnRootBlock.cid };
3836
3590
  } else {
3837
3591
  inIndex.root = await DbIndex.load({ cid: inIndex.cid, get: makeProllyGetBlock(tblocks), ...opts });
3838
3592
  }
3839
3593
  }
3840
- logger.Debug().Msg("pre bulk bulkIndex");
3841
3594
  const { root: root3, blocks: newBlocks } = await inIndex.root.bulk(indexEntries);
3842
3595
  if (root3) {
3843
- logger.Debug().Msg("pre root put bulkIndex");
3844
3596
  for await (const block of newBlocks) {
3845
3597
  await tblocks.put(block.cid, block.bytes);
3846
3598
  }
3847
3599
  return { root: root3, cid: (await root3.block).cid };
3848
3600
  } else {
3849
- logger.Debug().Msg("pre !root bulkIndex");
3850
3601
  return { root: void 0, cid: void 0 };
3851
3602
  }
3852
3603
  }
@@ -3887,17 +3638,17 @@ function encodeKey(key) {
3887
3638
 
3888
3639
  // src/indexer.ts
3889
3640
  init_utils();
3890
- function index(refDb, name, mapFn, meta) {
3891
- if (mapFn && meta) throw refDb.crdt.logger.Error().Msg("cannot provide both mapFn and meta").AsError();
3892
- if (mapFn && mapFn.constructor.name !== "Function") throw refDb.crdt.logger.Error().Msg("mapFn must be a function").AsError();
3893
- if (refDb.crdt.indexers.has(name)) {
3894
- const idx = refDb.crdt.indexers.get(name);
3641
+ function index(sthis, { _crdt }, name, mapFn, meta) {
3642
+ if (mapFn && meta) throw _crdt.logger.Error().Msg("cannot provide both mapFn and meta").AsError();
3643
+ if (mapFn && mapFn.constructor.name !== "Function") throw _crdt.logger.Error().Msg("mapFn must be a function").AsError();
3644
+ if (_crdt.indexers.has(name)) {
3645
+ const idx = _crdt.indexers.get(name);
3895
3646
  idx.applyMapFn(name, mapFn, meta);
3896
3647
  } else {
3897
- const idx = new Index(refDb.crdt.sthis, refDb.crdt, name, mapFn, meta);
3898
- refDb.crdt.indexers.set(name, idx);
3648
+ const idx = new Index(sthis, _crdt, name, mapFn, meta);
3649
+ _crdt.indexers.set(name, idx);
3899
3650
  }
3900
- return refDb.crdt.indexers.get(name);
3651
+ return _crdt.indexers.get(name);
3901
3652
  }
3902
3653
  var Index = class {
3903
3654
  constructor(sthis, crdt, name, mapFn, meta) {
@@ -3916,9 +3667,18 @@ var Index = class {
3916
3667
  return Promise.all([this.blockstore.ready(), this.crdt.ready()]).then(() => {
3917
3668
  });
3918
3669
  }
3670
+ close() {
3671
+ return Promise.all([this.blockstore.close(), this.crdt.close()]).then(() => {
3672
+ });
3673
+ }
3674
+ destroy() {
3675
+ return Promise.all([this.blockstore.destroy(), this.crdt.destroy()]).then(() => {
3676
+ });
3677
+ }
3919
3678
  applyMapFn(name, mapFn, meta) {
3920
3679
  if (mapFn && meta) throw this.logger.Error().Msg("cannot provide both mapFn and meta").AsError();
3921
3680
  if (this.name && this.name !== name) throw this.logger.Error().Msg("cannot change name").AsError();
3681
+ this.name = name;
3922
3682
  try {
3923
3683
  if (meta) {
3924
3684
  if (this.indexHead && this.indexHead.map((c) => c.toString()).join() !== meta.head.map((c) => c.toString()).join()) {
@@ -3966,13 +3726,9 @@ var Index = class {
3966
3726
  }
3967
3727
  }
3968
3728
  async query(opts = {}) {
3969
- this.logger.Debug().Msg("enter query");
3970
3729
  await this.ready();
3971
- this.logger.Debug().Msg("post ready query");
3972
3730
  await this._updateIndex();
3973
- this.logger.Debug().Msg("post _updateIndex query");
3974
3731
  await this._hydrateIndex();
3975
- this.logger.Debug().Msg("post _hydrateIndex query");
3976
3732
  if (!this.byKey.root) {
3977
3733
  return await applyQuery(this.crdt, { result: [] }, opts);
3978
3734
  }
@@ -4028,16 +3784,13 @@ var Index = class {
4028
3784
  }
4029
3785
  async _updateIndex() {
4030
3786
  await this.ready();
4031
- this.logger.Debug().Msg("enter _updateIndex");
4032
3787
  if (this.initError) throw this.initError;
4033
3788
  if (!this.mapFn) throw this.logger.Error().Msg("No map function defined").AsError();
4034
3789
  let result, head;
4035
3790
  if (!this.indexHead || this.indexHead.length === 0) {
4036
3791
  ({ result, head } = await this.crdt.allDocs());
4037
- this.logger.Debug().Msg("enter crdt.allDocs");
4038
3792
  } else {
4039
3793
  ({ result, head } = await this.crdt.changes(this.indexHead));
4040
- this.logger.Debug().Msg("enter crdt.changes");
4041
3794
  }
4042
3795
  if (result.length === 0) {
4043
3796
  this.indexHead = head;
@@ -4070,22 +3823,9 @@ var Index = class {
4070
3823
  if (result.length === 0) {
4071
3824
  return indexerMeta;
4072
3825
  }
4073
- this.logger.Debug().Msg("pre this.blockstore.transaction");
4074
3826
  const { meta } = await this.blockstore.transaction(async (tblocks) => {
4075
- this.byId = await bulkIndex(
4076
- this.logger,
4077
- tblocks,
4078
- this.byId,
4079
- removeIdIndexEntries.concat(byIdIndexEntries),
4080
- byIdOpts
4081
- );
4082
- this.byKey = await bulkIndex(
4083
- this.logger,
4084
- tblocks,
4085
- this.byKey,
4086
- staleKeyIndexEntries.concat(indexEntries),
4087
- byKeyOpts
4088
- );
3827
+ this.byId = await bulkIndex(tblocks, this.byId, removeIdIndexEntries.concat(byIdIndexEntries), byIdOpts);
3828
+ this.byKey = await bulkIndex(tblocks, this.byKey, staleKeyIndexEntries.concat(indexEntries), byKeyOpts);
4089
3829
  this.indexHead = head;
4090
3830
  if (this.byId.cid && this.byKey.cid) {
4091
3831
  const idxMeta = {
@@ -4097,10 +3837,8 @@ var Index = class {
4097
3837
  };
4098
3838
  indexerMeta.indexes?.set(this.name, idxMeta);
4099
3839
  }
4100
- this.logger.Debug().Any("indexerMeta", new Array(indexerMeta.indexes?.entries())).Msg("exit this.blockstore.transaction fn");
4101
3840
  return indexerMeta;
4102
3841
  });
4103
- this.logger.Debug().Msg("post this.blockstore.transaction");
4104
3842
  return meta;
4105
3843
  }
4106
3844
  };
@@ -4108,8 +3846,7 @@ var Index = class {
4108
3846
  // src/crdt-clock.ts
4109
3847
  var import_clock3 = require("@web3-storage/pail/clock");
4110
3848
  var import_crdt2 = require("@web3-storage/pail/crdt");
4111
- var import_cement16 = require("@adviser/cement");
4112
- init_types();
3849
+ var import_cement14 = require("@adviser/cement");
4113
3850
 
4114
3851
  // src/apply-head-queue.ts
4115
3852
  function applyHeadQueue(worker, logger) {
@@ -4167,7 +3904,7 @@ var CRDTClock = class {
4167
3904
  this.zoomers = /* @__PURE__ */ new Set();
4168
3905
  this.watchers = /* @__PURE__ */ new Set();
4169
3906
  this.emptyWatchers = /* @__PURE__ */ new Set();
4170
- this._ready = new import_cement16.ResolveOnce();
3907
+ this._ready = new import_cement14.ResolveOnce();
4171
3908
  this.blockstore = blockstore;
4172
3909
  this.logger = ensureLogger(blockstore.sthis, "CRDTClock");
4173
3910
  this.applyHeadQueue = applyHeadQueue(this.int_applyHead.bind(this), this.logger);
@@ -4279,13 +4016,15 @@ async function advanceBlocks(logger, newHead, tblocks, head) {
4279
4016
  // src/crdt.ts
4280
4017
  init_utils();
4281
4018
  var CRDT = class {
4282
- constructor(sthis, opts) {
4019
+ constructor(sthis, name, opts = {}) {
4283
4020
  this.indexers = /* @__PURE__ */ new Map();
4284
- this.onceReady = new import_cement17.ResolveOnce();
4021
+ this.onceReady = new import_cement15.ResolveOnce();
4285
4022
  this.sthis = sthis;
4023
+ this.name = name;
4286
4024
  this.logger = ensureLogger(sthis, "CRDT");
4287
4025
  this.opts = opts;
4288
4026
  this.blockstore = blockstoreFactory(sthis, {
4027
+ name,
4289
4028
  applyMeta: async (meta) => {
4290
4029
  const crdtMeta = meta;
4291
4030
  if (!crdtMeta.head) throw this.logger.Error().Msg("missing head").AsError();
@@ -4295,27 +4034,23 @@ var CRDT = class {
4295
4034
  await doCompact(blocks, this.clock.head, this.logger);
4296
4035
  return { head: this.clock.head };
4297
4036
  },
4298
- // autoCompact: this.opts.autoCompact || 100,
4299
- storeRuntime: toStoreRuntime(this.sthis, this.opts.storeEnDe),
4300
- storeUrls: this.opts.storeUrls.data,
4301
- keyBag: this.opts.keyBag,
4302
- // public: this.opts.public,
4303
- meta: this.opts.meta
4304
- // threshold: this.opts.threshold,
4037
+ autoCompact: this.opts.autoCompact || 100,
4038
+ store: { ...this.opts.store, isIndex: void 0 },
4039
+ public: this.opts.public,
4040
+ meta: this.opts.meta,
4041
+ threshold: this.opts.threshold
4305
4042
  });
4306
4043
  this.indexBlockstore = blockstoreFactory(sthis, {
4307
- // name: opts.name,
4044
+ name,
4308
4045
  applyMeta: async (meta) => {
4309
4046
  const idxCarMeta = meta;
4310
4047
  if (!idxCarMeta.indexes) throw this.logger.Error().Msg("missing indexes").AsError();
4311
- for (const [name, idx] of Object.entries(idxCarMeta.indexes)) {
4312
- index({ crdt: this }, name, void 0, idx);
4048
+ for (const [name2, idx] of Object.entries(idxCarMeta.indexes)) {
4049
+ index(this.sthis, { _crdt: this }, name2, void 0, idx);
4313
4050
  }
4314
4051
  },
4315
- storeRuntime: toStoreRuntime(this.sthis, this.opts.storeEnDe),
4316
- storeUrls: this.opts.storeUrls.idx,
4317
- keyBag: this.opts.keyBag
4318
- // public: this.opts.public,
4052
+ store: { ...this.opts.store, isIndex: this.opts.store?.isIndex || "idx" },
4053
+ public: this.opts.public
4319
4054
  });
4320
4055
  this.clock = new CRDTClock(this.blockstore);
4321
4056
  this.clock.onZoom(() => {
@@ -4397,166 +4132,52 @@ var CRDT = class {
4397
4132
  };
4398
4133
 
4399
4134
  // src/database.ts
4400
- init_types();
4401
4135
  init_utils();
4402
- var databases = new import_cement18.KeyedResolvOnce();
4403
- function toSortedArray(set) {
4404
- if (!set) return [];
4405
- return Object.entries(set).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => ({ [k]: v }));
4406
- }
4407
- function keyConfigOpts(sthis, name, opts) {
4408
- return JSON.stringify(
4409
- toSortedArray({
4410
- name,
4411
- stores: toSortedArray(JSON.parse(JSON.stringify(toStoreURIRuntime(sthis, name, opts?.storeUrls))))
4412
- })
4413
- );
4414
- }
4415
- function isDatabase(db) {
4416
- return db instanceof DatabaseImpl || db instanceof DatabaseShell;
4417
- }
4418
- function DatabaseFactory(name, opts) {
4419
- const sthis = ensureSuperThis(opts);
4420
- return new DatabaseShell(
4421
- databases.get(keyConfigOpts(sthis, name, opts)).once((key) => {
4422
- const db = new DatabaseImpl(sthis, {
4423
- name,
4424
- meta: opts?.meta,
4425
- keyBag: defaultKeyBagOpts(sthis, opts?.keyBag),
4426
- storeUrls: toStoreURIRuntime(sthis, name, opts?.storeUrls),
4427
- storeEnDe: {
4428
- encodeFile,
4429
- decodeFile,
4430
- ...opts?.storeEnDe
4431
- }
4432
- });
4433
- db.onClosed(() => {
4434
- databases.unget(key);
4435
- });
4436
- return db;
4437
- })
4438
- );
4439
- }
4440
- var DatabaseShell = class {
4441
- constructor(ref) {
4442
- this.ref = ref;
4443
- ref.addShell(this);
4444
- }
4445
- get id() {
4446
- return this.ref.id;
4447
- }
4448
- get logger() {
4449
- return this.ref.logger;
4450
- }
4451
- get sthis() {
4452
- return this.ref.sthis;
4453
- }
4454
- get crdt() {
4455
- return this.ref.crdt;
4456
- }
4457
- name() {
4458
- return this.ref.name();
4459
- }
4460
- onClosed(fn) {
4461
- return this.ref.onClosed(fn);
4462
- }
4463
- close() {
4464
- return this.ref.shellClose(this);
4465
- }
4466
- destroy() {
4467
- return this.ref.destroy();
4468
- }
4469
- ready() {
4470
- return this.ref.ready();
4471
- }
4472
- get(id) {
4473
- return this.ref.get(id);
4474
- }
4475
- put(doc) {
4476
- return this.ref.put(doc);
4477
- }
4478
- del(id) {
4479
- return this.ref.del(id);
4480
- }
4481
- changes(since, opts) {
4482
- return this.ref.changes(since, opts);
4483
- }
4484
- allDocs(opts) {
4485
- return this.ref.allDocs(opts);
4486
- }
4487
- allDocuments() {
4488
- return this.ref.allDocuments();
4489
- }
4490
- subscribe(listener, updates) {
4491
- return this.ref.subscribe(listener, updates);
4492
- }
4493
- query(field, opts) {
4494
- return this.ref.query(field, opts);
4495
- }
4496
- compact() {
4497
- return this.ref.compact();
4498
- }
4499
- };
4500
- var DatabaseImpl = class {
4501
- constructor(sthis, opts) {
4136
+ var Database = class {
4137
+ constructor(name, opts) {
4138
+ this.opts = {};
4502
4139
  this._listening = false;
4503
4140
  this._listeners = /* @__PURE__ */ new Set();
4504
4141
  this._noupdate_listeners = /* @__PURE__ */ new Set();
4505
- // readonly blockstore: BaseBlockstore;
4506
- this.shells = /* @__PURE__ */ new Set();
4507
- this._onClosedFns = /* @__PURE__ */ new Set();
4508
- this._ready = new import_cement18.ResolveOnce();
4509
- this.opts = opts;
4510
- this.sthis = sthis;
4511
- this.id = sthis.timeOrderedNextId().str;
4142
+ this._ready = new import_cement16.ResolveOnce();
4143
+ this.name = name;
4144
+ this.opts = opts || this.opts;
4145
+ this.sthis = ensureSuperThis(this.opts);
4512
4146
  this.logger = ensureLogger(this.sthis, "Database");
4513
- this.crdt = new CRDT(this.sthis, this.opts);
4147
+ this._crdt = new CRDT(this.sthis, name, this.opts);
4148
+ this.blockstore = this._crdt.blockstore;
4514
4149
  this._writeQueue = writeQueue(async (updates) => {
4515
- return await this.crdt.bulk(updates);
4150
+ return await this._crdt.bulk(updates);
4516
4151
  });
4517
- this.crdt.clock.onTock(() => {
4152
+ this._crdt.clock.onTock(() => {
4518
4153
  this._no_update_notify();
4519
4154
  });
4520
4155
  }
4521
- addShell(shell) {
4522
- this.shells.add(shell);
4523
- }
4524
- onClosed(fn) {
4525
- this._onClosedFns.add(fn);
4156
+ static {
4157
+ this.databases = /* @__PURE__ */ new Map();
4526
4158
  }
4527
4159
  async close() {
4528
- throw this.logger.Error().Str("db", this.name()).Msg(`use shellClose`).AsError();
4529
- }
4530
- async shellClose(db) {
4531
- if (!this.shells.has(db)) {
4532
- throw this.logger.Error().Str("db", this.name()).Msg(`Database Shell mismatch`).AsError();
4533
- }
4534
- this.shells.delete(db);
4535
- if (this.shells.size === 0) {
4536
- await this.ready();
4537
- await this.crdt.close();
4538
- this._onClosedFns.forEach((fn) => fn());
4539
- }
4160
+ await this.ready();
4161
+ await this._crdt.close();
4162
+ await this.blockstore.close();
4540
4163
  }
4541
4164
  async destroy() {
4542
4165
  await this.ready();
4543
- await this.crdt.destroy();
4166
+ await this._crdt.destroy();
4167
+ await this.blockstore.destroy();
4544
4168
  }
4545
4169
  async ready() {
4546
- const ret = await this._ready.once(async () => {
4170
+ return this._ready.once(async () => {
4547
4171
  await this.sthis.start();
4548
- await this.crdt.ready();
4172
+ await this._crdt.ready();
4173
+ await this.blockstore.ready();
4549
4174
  });
4550
- return ret;
4551
- }
4552
- name() {
4553
- return this.opts.storeUrls.data.data.getParam("name" /* NAME */) || "default";
4554
4175
  }
4555
4176
  async get(id) {
4556
- if (!id) throw this.logger.Error().Str("db", this.name()).Msg(`Doc id is required`).AsError();
4177
+ if (!id) throw this.logger.Error().Str("db", this.name).Msg(`Doc id is required`).AsError();
4557
4178
  await this.ready();
4558
4179
  this.logger.Debug().Str("id", id).Msg("get");
4559
- const got = await this.crdt.get(id).catch((e) => {
4180
+ const got = await this._crdt.get(id).catch((e) => {
4560
4181
  throw new NotFoundError(`Not found: ${id} - ${e.message}`);
4561
4182
  });
4562
4183
  if (!got) throw new NotFoundError(`Not found: ${id}`);
@@ -4575,34 +4196,34 @@ var DatabaseImpl = class {
4575
4196
  _id: docId
4576
4197
  }
4577
4198
  });
4578
- return { id: docId, clock: result?.head, name: this.name() };
4199
+ return { id: docId, clock: result?.head, name: this.name };
4579
4200
  }
4580
4201
  async del(id) {
4581
4202
  await this.ready();
4582
4203
  this.logger.Debug().Str("id", id).Msg("del");
4583
4204
  const result = await this._writeQueue.push({ id, del: true });
4584
- return { id, clock: result?.head, name: this.name() };
4205
+ return { id, clock: result?.head, name: this.name };
4585
4206
  }
4586
4207
  async changes(since = [], opts = {}) {
4587
4208
  await this.ready();
4588
4209
  this.logger.Debug().Any("since", since).Any("opts", opts).Msg("changes");
4589
- const { result, head } = await this.crdt.changes(since, opts);
4210
+ const { result, head } = await this._crdt.changes(since, opts);
4590
4211
  const rows = result.map(({ id: key, value, del, clock }) => ({
4591
4212
  key,
4592
4213
  value: del ? { _id: key, _deleted: true } : { _id: key, ...value },
4593
4214
  clock
4594
4215
  }));
4595
- return { rows, clock: head, name: this.name() };
4216
+ return { rows, clock: head, name: this.name };
4596
4217
  }
4597
4218
  async allDocs(opts = {}) {
4598
4219
  await this.ready();
4599
4220
  this.logger.Debug().Msg("allDocs");
4600
- const { result, head } = await this.crdt.allDocs();
4221
+ const { result, head } = await this._crdt.allDocs();
4601
4222
  const rows = result.map(({ id: key, value, del }) => ({
4602
4223
  key,
4603
4224
  value: del ? { _id: key, _deleted: true } : { _id: key, ...value }
4604
4225
  }));
4605
- return { rows, clock: head, name: this.name() };
4226
+ return { rows, clock: head, name: this.name };
4606
4227
  }
4607
4228
  async allDocuments() {
4608
4229
  return this.allDocs();
@@ -4612,7 +4233,7 @@ var DatabaseImpl = class {
4612
4233
  if (updates) {
4613
4234
  if (!this._listening) {
4614
4235
  this._listening = true;
4615
- this.crdt.clock.onTick((updates2) => {
4236
+ this._crdt.clock.onTick((updates2) => {
4616
4237
  void this._notify(updates2);
4617
4238
  });
4618
4239
  }
@@ -4631,13 +4252,13 @@ var DatabaseImpl = class {
4631
4252
  async query(field, opts = {}) {
4632
4253
  await this.ready();
4633
4254
  this.logger.Debug().Any("field", field).Any("opts", opts).Msg("query");
4634
- const _crdt = this.crdt;
4635
- const idx = typeof field === "string" ? index({ crdt: _crdt }, field) : index({ crdt: _crdt }, makeName(field.toString()), field);
4255
+ const _crdt = this._crdt;
4256
+ const idx = typeof field === "string" ? index(this.sthis, { _crdt }, field) : index(this.sthis, { _crdt }, makeName(field.toString()), field);
4636
4257
  return await idx.query(opts);
4637
4258
  }
4638
4259
  async compact() {
4639
4260
  await this.ready();
4640
- await this.crdt.compact();
4261
+ await this._crdt.compact();
4641
4262
  }
4642
4263
  async _notify(updates) {
4643
4264
  await this.ready();
@@ -4661,62 +4282,23 @@ var DatabaseImpl = class {
4661
4282
  }
4662
4283
  }
4663
4284
  };
4664
- function defaultURI(sthis, curi, uri, store, ctx) {
4665
- ctx = ctx || {};
4666
- const ret = (curi ? import_cement18.URI.from(curi) : uri).build().setParam("store" /* STORE */, store);
4667
- if (!ret.hasParam("name" /* NAME */)) {
4668
- const name = sthis.pathOps.basename(ret.URI().pathname);
4669
- if (!name) {
4670
- throw sthis.logger.Error().Url(ret).Any("ctx", ctx).Msg("Database name is required").AsError();
4671
- }
4672
- ret.setParam("name" /* NAME */, name);
4673
- }
4674
- if (ctx.idx) {
4675
- ret.defParam("index" /* INDEX */, "idx");
4676
- ret.defParam("storekey" /* STORE_KEY */, `@${ret.getParam("name" /* NAME */)}-${store}-idx@`);
4677
- } else {
4678
- ret.defParam("storekey" /* STORE_KEY */, `@${ret.getParam("name" /* NAME */)}-${store}@`);
4679
- }
4680
- if (store === "data") {
4681
- if (ctx.file) {
4682
- } else {
4683
- ret.defParam("suffix" /* SUFFIX */, ".car");
4684
- }
4685
- }
4686
- return ret.URI();
4687
- }
4688
- function toStoreURIRuntime(sthis, name, sopts) {
4689
- sopts = sopts || {};
4690
- if (!sopts.base) {
4691
- const fp_env = sthis.env.get("FP_STORAGE_URL");
4692
- if (fp_env) {
4693
- sopts = { ...sopts, base: import_cement18.BuildURI.from(fp_env).setParam("urlGen" /* URL_GEN */, "fromEnv") };
4694
- } else {
4695
- sopts = { ...sopts, base: getDefaultURI(sthis).build().setParam("urlGen" /* URL_GEN */, "default") };
4696
- }
4697
- }
4698
- const bbase = import_cement18.BuildURI.from(sopts.base);
4699
- if (name) {
4700
- bbase.setParam("name" /* NAME */, name);
4701
- }
4702
- const base = bbase.URI();
4703
- return {
4704
- idx: {
4705
- data: defaultURI(sthis, sopts.idx?.data, base, "data", { idx: true }),
4706
- file: defaultURI(sthis, sopts.idx?.data, base, "data", { file: true, idx: true }),
4707
- meta: defaultURI(sthis, sopts.idx?.meta, base, "meta", { idx: true }),
4708
- wal: defaultURI(sthis, sopts.idx?.wal, base, "wal", { idx: true })
4709
- },
4710
- data: {
4711
- data: defaultURI(sthis, sopts.data?.data, base, "data"),
4712
- file: defaultURI(sthis, sopts.data?.data, base, "data", { file: true }),
4713
- meta: defaultURI(sthis, sopts.data?.meta, base, "meta"),
4714
- wal: defaultURI(sthis, sopts.data?.wal, base, "wal")
4715
- }
4716
- };
4285
+ function toSortedArray(set) {
4286
+ if (!set) return [];
4287
+ return Object.entries(set).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => ({ [k]: v }));
4717
4288
  }
4718
4289
  function fireproof(name, opts) {
4719
- return DatabaseFactory(name, opts);
4290
+ const key = JSON.stringify(
4291
+ toSortedArray({
4292
+ name,
4293
+ stores: toSortedArray(opts?.store?.stores)
4294
+ })
4295
+ );
4296
+ let db = Database.databases.get(key);
4297
+ if (!db) {
4298
+ db = new Database(name, opts);
4299
+ Database.databases.set(key, db);
4300
+ }
4301
+ return db;
4720
4302
  }
4721
4303
  function makeName(fnString) {
4722
4304
  const regex = /\(([^,()]+,\s*[^,()]+|\[[^\]]+\],\s*[^,()]+)\)/g;
@@ -4735,9 +4317,6 @@ function makeName(fnString) {
4735
4317
  }
4736
4318
  }
4737
4319
 
4738
- // src/index.ts
4739
- init_types();
4740
-
4741
4320
  // src/runtime/index.ts
4742
4321
  var runtime_exports = {};
4743
4322
  __export(runtime_exports, {
@@ -4750,7 +4329,7 @@ __export(runtime_exports, {
4750
4329
  kb: () => key_bag_exports,
4751
4330
  kc: () => keyed_crypto_exports,
4752
4331
  mf: () => wait_pr_multiformats_exports,
4753
- runtimeFn: () => import_cement19.runtimeFn,
4332
+ runtimeFn: () => import_cement17.runtimeFn,
4754
4333
  toArrayBuffer: () => toArrayBuffer
4755
4334
  });
4756
4335
  init_utils2();
@@ -4766,7 +4345,7 @@ __export(wait_pr_multiformats_exports, {
4766
4345
  var codec_interface_exports = {};
4767
4346
 
4768
4347
  // src/runtime/index.ts
4769
- var import_cement19 = require("@adviser/cement");
4348
+ var import_cement17 = require("@adviser/cement");
4770
4349
  init_version();
4771
4350
  init_version2();
4772
4351
 
@@ -4775,6 +4354,6 @@ init_utils();
4775
4354
 
4776
4355
  // src/version.ts
4777
4356
  var PACKAGE_VERSION = Object.keys({
4778
- "0.19.101": "xxxx"
4357
+ "0.19.103": "xxxx"
4779
4358
  })[0];
4780
4359
  //# sourceMappingURL=index.cjs.map