@fireproof/core 0.19.101 → 0.19.102

Sign up to get free protection for your applications and to get access to all the features.
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.102": "xxxx"
4779
4358
  })[0];
4780
4359
  //# sourceMappingURL=index.cjs.map