@fireproof/core 0.19.99 → 0.19.101

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. package/{chunk-OFGPKRCM.js → chunk-3EB3ENHT.js} +54 -25
  2. package/chunk-3EB3ENHT.js.map +1 -0
  3. package/chunk-HQ7D3PEU.js +61 -0
  4. package/chunk-HQ7D3PEU.js.map +1 -0
  5. package/chunk-PZ5AY32C.js +10 -0
  6. package/deno-filesystem-Q2IJ7YDR.js +57 -0
  7. package/deno-filesystem-Q2IJ7YDR.js.map +1 -0
  8. package/deno.json +3 -1
  9. package/{gateway-5FCWPX5W.js → gateway-GK5QZ6KP.js} +13 -12
  10. package/gateway-GK5QZ6KP.js.map +1 -0
  11. package/{gateway-H7UD6TNB.js → gateway-TQTGDRCN.js} +9 -8
  12. package/gateway-TQTGDRCN.js.map +1 -0
  13. package/index.cjs +2232 -1781
  14. package/index.cjs.map +1 -1
  15. package/index.d.cts +261 -117
  16. package/index.d.ts +261 -117
  17. package/index.global.js +12776 -11829
  18. package/index.global.js.map +1 -1
  19. package/index.js +1936 -1579
  20. package/index.js.map +1 -1
  21. package/{key-bag-file-WADZBHYG.js → key-bag-file-VOSSK46F.js} +4 -3
  22. package/{key-bag-file-WADZBHYG.js.map → key-bag-file-VOSSK46F.js.map} +1 -1
  23. package/{key-bag-indexdb-PGVAI3FJ.js → key-bag-indexdb-AXTQOSMC.js} +4 -3
  24. package/{key-bag-indexdb-PGVAI3FJ.js.map → key-bag-indexdb-AXTQOSMC.js.map} +1 -1
  25. package/key-bag-memory-LWE6ARPX.js +29 -0
  26. package/key-bag-memory-LWE6ARPX.js.map +1 -0
  27. package/metafile-cjs.json +1 -1
  28. package/metafile-esm.json +1 -1
  29. package/metafile-iife.json +1 -1
  30. package/{node-filesystem-INX4ZTHE.js → node-filesystem-CFRXFSO7.js} +6 -9
  31. package/node-filesystem-CFRXFSO7.js.map +1 -0
  32. package/package.json +4 -2
  33. package/tests/blockstore/keyed-crypto-indexdb-file.test.ts +129 -0
  34. package/tests/blockstore/keyed-crypto.test.ts +63 -227
  35. package/tests/blockstore/loader.test.ts +19 -11
  36. package/tests/blockstore/store.test.ts +23 -19
  37. package/tests/blockstore/transaction.test.ts +12 -12
  38. package/tests/fireproof/all-gateway.test.ts +201 -193
  39. package/tests/fireproof/cars/bafkreidxwt2nhvbl4fnqfw3ctlt6zbrir4kqwmjo5im6rf4q5si27kgo2i.ts +324 -316
  40. package/tests/fireproof/crdt.test.ts +67 -16
  41. package/tests/fireproof/database.test.ts +183 -21
  42. package/tests/fireproof/fireproof.test.ts +83 -74
  43. package/tests/fireproof/hello.test.ts +18 -14
  44. package/tests/fireproof/indexer.test.ts +53 -43
  45. package/tests/fireproof/utils.test.ts +18 -6
  46. package/tests/gateway/file/loader-config.test.ts +303 -0
  47. package/tests/gateway/indexdb/loader-config.test.ts +75 -0
  48. package/tests/helpers.ts +27 -9
  49. package/tests/react/useFireproof.test.tsx +1 -1
  50. package/{utils-QO2HIWGI.js → utils-STA2C35G.js} +4 -3
  51. package/utils-STA2C35G.js.map +1 -0
  52. package/chunk-OFGPKRCM.js.map +0 -1
  53. package/chunk-WS3YRPIA.js +0 -75
  54. package/chunk-WS3YRPIA.js.map +0 -1
  55. package/gateway-5FCWPX5W.js.map +0 -1
  56. package/gateway-H7UD6TNB.js.map +0 -1
  57. package/mem-filesystem-YPPJV7Q2.js +0 -41
  58. package/mem-filesystem-YPPJV7Q2.js.map +0 -1
  59. package/node-filesystem-INX4ZTHE.js.map +0 -1
  60. package/tests/fireproof/config.test.ts +0 -172
  61. /package/{utils-QO2HIWGI.js.map → chunk-PZ5AY32C.js.map} +0 -0
  62. /package/tests/fireproof/{fireproof.test.fixture.ts → fireproof.fixture.ts} +0 -0
package/index.cjs CHANGED
@@ -30,6 +30,47 @@ 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
+
33
74
  // src/utils.ts
34
75
  function presetEnv() {
35
76
  const penv = new Map([
@@ -87,6 +128,10 @@ function ensureLogger(sthis, componentName, ctx) {
87
128
  exposeStack = true;
88
129
  delete ctx.exposeStack;
89
130
  }
131
+ if ("exposeStack" in ctx) {
132
+ exposeStack = true;
133
+ delete ctx.exposeStack;
134
+ }
90
135
  if ("this" in ctx) {
91
136
  cLogger.Str("this", sthis.nextId(4).str);
92
137
  delete ctx.this;
@@ -153,10 +198,13 @@ function ensureLogger(sthis, componentName, ctx) {
153
198
  logger.SetExposeStack(true);
154
199
  }
155
200
  const out = cLogger.Logger();
201
+ if (sthis.env.get("FP_CONSTRUCTOR_DEBUG")) {
202
+ out.Debug().Msg("constructor");
203
+ }
156
204
  return out;
157
205
  }
158
206
  function getStore(url, sthis, joiner) {
159
- const store = url.getParam("store");
207
+ const store = url.getParam("store" /* STORE */);
160
208
  switch (store) {
161
209
  case "data":
162
210
  case "wal":
@@ -164,20 +212,21 @@ function getStore(url, sthis, joiner) {
164
212
  break;
165
213
  default:
166
214
  throw sthis.logger.Error().Url(url).Msg(`store not found`).AsError();
215
+ throw sthis.logger.Error().Url(url).Msg(`store not found`).AsError();
167
216
  }
168
217
  let name = store;
169
218
  if (url.hasParam("index")) {
170
- name = joiner(url.getParam("index") || "idx", name);
219
+ name = joiner(url.getParam("index" /* INDEX */) || "idx", name);
171
220
  }
172
221
  return { store, name };
173
222
  }
174
223
  function getKey(url, logger) {
175
- const result = url.getParam("key");
224
+ const result = url.getParam("key" /* KEY */);
176
225
  if (!result) throw logger.Error().Str("url", url.toString()).Msg(`key not found`).AsError();
177
226
  return result;
178
227
  }
179
228
  function getName(sthis, url) {
180
- let result = url.getParam("name");
229
+ let result = url.getParam("name" /* NAME */);
181
230
  if (!result) {
182
231
  result = sthis.pathOps.dirname(url.pathname);
183
232
  if (result.length === 0) {
@@ -197,17 +246,6 @@ function isNotFoundError(e) {
197
246
  if (e.code === "ENOENT") return true;
198
247
  return false;
199
248
  }
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
- }
211
249
  function UInt8ArrayEqual(a, b) {
212
250
  if (a.length !== b.length) {
213
251
  return false;
@@ -224,6 +262,7 @@ var init_utils = __esm({
224
262
  "src/utils.ts"() {
225
263
  "use strict";
226
264
  import_cement = require("@adviser/cement");
265
+ init_types();
227
266
  import_base58 = require("multiformats/bases/base58");
228
267
  globalLogger = new import_cement.LoggerImpl();
229
268
  registerFP_DEBUG = new import_cement.ResolveOnce();
@@ -274,6 +313,9 @@ var init_utils = __esm({
274
313
  dirname(path) {
275
314
  return path.split("/").slice(0, -1).join("/");
276
315
  }
316
+ basename(path) {
317
+ return path.split("/").pop() || "";
318
+ }
277
319
  // homedir() {
278
320
  // throw new Error("SysContainer:homedir is not available in seeded state");
279
321
  // }
@@ -292,45 +334,63 @@ var init_utils = __esm({
292
334
  }
293
335
  });
294
336
 
295
- // src/runtime/gateways/file/mem-filesystem.ts
296
- var mem_filesystem_exports = {};
297
- __export(mem_filesystem_exports, {
298
- MemFileSystem: () => MemFileSystem
337
+ // src/runtime/gateways/file/deno-filesystem.ts
338
+ var deno_filesystem_exports = {};
339
+ __export(deno_filesystem_exports, {
340
+ DenoFileSystem: () => DenoFileSystem
299
341
  });
300
- var import_memfs, MemFileSystem;
301
- var init_mem_filesystem = __esm({
302
- "src/runtime/gateways/file/mem-filesystem.ts"() {
342
+ var DenoFileSystem;
343
+ var init_deno_filesystem = __esm({
344
+ "src/runtime/gateways/file/deno-filesystem.ts"() {
303
345
  "use strict";
304
- import_memfs = require("memfs");
305
- init_utils2();
306
- MemFileSystem = class {
346
+ DenoFileSystem = class {
307
347
  async start() {
348
+ this.fs = Deno;
308
349
  return this;
309
350
  }
310
- mkdir(path, options) {
311
- return import_memfs.fs.promises.mkdir(path, options);
351
+ async mkdir(path, options) {
352
+ return this.fs?.mkdir(path, options).then(() => path);
312
353
  }
313
- readdir(path, options) {
314
- return import_memfs.fs.promises.readdir(path, options);
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;
315
360
  }
316
- rm(path, options) {
317
- return import_memfs.fs.promises.rm(path, options);
361
+ async rm(path, options) {
362
+ return this.fs?.rm(path, options);
318
363
  }
319
- copyFile(source, destination) {
320
- return import_memfs.fs.promises.copyFile(source, destination);
364
+ async copyFile(source, destination) {
365
+ return this.fs?.copyFile(source, destination);
321
366
  }
322
- async readfile(path, options) {
323
- const ret = await import_memfs.fs.promises.readFile(path, options);
324
- return toArrayBuffer(ret);
367
+ async readfile(path) {
368
+ return this.fs.readFile(path);
325
369
  }
326
- stat(path) {
327
- return import_memfs.fs.promises.stat(path);
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
+ };
328
388
  }
329
- unlink(path) {
330
- return import_memfs.fs.promises.unlink(path);
389
+ async unlink(path) {
390
+ return this.fs?.unlink(path);
331
391
  }
332
- writefile(path, data) {
333
- return import_memfs.fs.promises.writeFile(path, Buffer.from(data));
392
+ async writefile(path, data) {
393
+ return this.fs?.writeFile(path, Buffer.from(data));
334
394
  }
335
395
  };
336
396
  }
@@ -341,12 +401,11 @@ var node_filesystem_exports = {};
341
401
  __export(node_filesystem_exports, {
342
402
  NodeFileSystem: () => NodeFileSystem
343
403
  });
344
- var import_cement4, NodeFileSystem;
404
+ var NodeFileSystem;
345
405
  var init_node_filesystem = __esm({
346
406
  "src/runtime/gateways/file/node-filesystem.ts"() {
347
407
  "use strict";
348
408
  init_utils2();
349
- import_cement4 = require("@adviser/cement");
350
409
  NodeFileSystem = class {
351
410
  async start() {
352
411
  this.fs = await import("fs/promises");
@@ -369,15 +428,12 @@ var init_node_filesystem = __esm({
369
428
  return toArrayBuffer(ret);
370
429
  }
371
430
  stat(path) {
372
- return this.fs?.stat(path);
431
+ return this.fs.stat(path);
373
432
  }
374
433
  async unlink(path) {
375
434
  return this.fs?.unlink(path);
376
435
  }
377
436
  async writefile(path, data) {
378
- if ((0, import_cement4.runtimeFn)().isDeno) {
379
- return this.fs?.writeFile(path, data);
380
- }
381
437
  return this.fs?.writeFile(path, Buffer.from(data));
382
438
  }
383
439
  };
@@ -393,49 +449,34 @@ __export(utils_exports, {
393
449
  toArrayBuffer: () => toArrayBuffer
394
450
  });
395
451
  async function getFileSystem(url) {
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
- }
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");
419
461
  }
420
- return fs2.start();
462
+ return fs.start();
421
463
  }
422
464
  function getPath(url, sthis) {
423
465
  const basePath = url.pathname;
424
- const name = url.getParam("name");
466
+ const name = url.getParam("name" /* NAME */);
425
467
  if (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);
468
+ return sthis.pathOps.join(basePath, name);
429
469
  }
430
470
  return sthis.pathOps.join(basePath);
431
471
  }
432
472
  function getFileName(url, sthis) {
433
- const key = url.getParam("key");
473
+ const key = url.getParam("key" /* KEY */);
434
474
  if (!key) throw sthis.logger.Error().Url(url).Msg(`key not found`).AsError();
435
475
  const res = getStore(url, sthis, (...a) => a.join("-"));
436
476
  switch (res.store) {
437
- case "data":
438
- return sthis.pathOps.join(res.name, key + ".car");
477
+ case "data": {
478
+ return sthis.pathOps.join(res.name, key + (url.getParam("suffix" /* SUFFIX */) || ""));
479
+ }
439
480
  case "wal":
440
481
  case "meta":
441
482
  return sthis.pathOps.join(res.name, key + ".json");
@@ -454,10 +495,13 @@ function toArrayBuffer(buffer) {
454
495
  }
455
496
  return view;
456
497
  }
498
+ var import_cement4;
457
499
  var init_utils2 = __esm({
458
500
  "src/runtime/gateways/file/utils.ts"() {
459
501
  "use strict";
502
+ import_cement4 = require("@adviser/cement");
460
503
  init_utils();
504
+ init_types();
461
505
  }
462
506
  });
463
507
 
@@ -572,6 +616,40 @@ var init_key_bag_indexdb = __esm({
572
616
  }
573
617
  });
574
618
 
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
+
575
653
  // src/runtime/gateways/file/version.ts
576
654
  var FILESTORE_VERSION;
577
655
  var init_version = __esm({
@@ -587,23 +665,24 @@ __export(gateway_exports, {
587
665
  FileGateway: () => FileGateway,
588
666
  FileTestStore: () => FileTestStore
589
667
  });
590
- var import_cement11, versionFiles, FileGateway, FileTestStore;
668
+ var import_cement12, versionFiles, FileGateway, FileTestStore;
591
669
  var init_gateway = __esm({
592
670
  "src/runtime/gateways/file/gateway.ts"() {
593
671
  "use strict";
594
672
  init_version();
595
- import_cement11 = require("@adviser/cement");
673
+ import_cement12 = require("@adviser/cement");
596
674
  init_utils();
597
675
  init_utils2();
598
- versionFiles = new import_cement11.KeyedResolvOnce();
676
+ init_types();
677
+ versionFiles = new import_cement12.KeyedResolvOnce();
599
678
  FileGateway = class {
600
679
  get fs() {
601
680
  if (!this._fs) throw this.logger.Error().Msg("fs not initialized").AsError();
602
681
  return this._fs;
603
682
  }
604
683
  constructor(sthis) {
605
- this.sthis = sthis;
606
- this.logger = sthis.logger;
684
+ this.sthis = ensureSuperLog(sthis, "FileGateway", { this: 1 });
685
+ this.logger = this.sthis.logger;
607
686
  }
608
687
  async getVersionFromFile(path, logger) {
609
688
  return versionFiles.get(path).once(async () => {
@@ -625,34 +704,33 @@ var init_gateway = __esm({
625
704
  });
626
705
  }
627
706
  start(baseURL) {
628
- return (0, import_cement11.exception2Result)(async () => {
707
+ return (0, import_cement12.exception2Result)(async () => {
629
708
  this._fs = await getFileSystem(baseURL);
630
- await this.fs.start();
631
709
  const url = baseURL.build();
632
- url.defParam("version", FILESTORE_VERSION);
710
+ url.defParam("version" /* VERSION */, FILESTORE_VERSION);
633
711
  const dbUrl = await this.buildUrl(url.URI(), "dummy");
634
712
  const dbdirFile = this.getFilePath(dbUrl.Ok());
635
713
  await this.fs.mkdir(this.sthis.pathOps.dirname(dbdirFile), { recursive: true });
636
714
  const dbroot = this.sthis.pathOps.dirname(dbdirFile);
637
715
  this.logger.Debug().Url(url.URI()).Str("dbroot", dbroot).Msg("start");
638
- url.setParam("version", await this.getVersionFromFile(dbroot, this.logger));
716
+ url.setParam("version" /* VERSION */, await this.getVersionFromFile(dbroot, this.logger));
639
717
  return url.URI();
640
718
  });
641
719
  }
642
720
  async buildUrl(baseUrl, key) {
643
- return import_cement11.Result.Ok(baseUrl.build().setParam("key", key).URI());
721
+ return import_cement12.Result.Ok(baseUrl.build().setParam("key" /* KEY */, key).URI());
644
722
  }
645
723
  async close() {
646
- return import_cement11.Result.Ok(void 0);
724
+ return import_cement12.Result.Ok(void 0);
647
725
  }
648
726
  // abstract buildUrl(baseUrl: URL, key: string): Promise<Result<URL>>;
649
727
  getFilePath(url) {
650
- const key = url.getParam("key");
728
+ const key = url.getParam("key" /* KEY */);
651
729
  if (!key) throw this.logger.Error().Url(url).Msg(`key not found`).AsError();
652
730
  return this.sthis.pathOps.join(getPath(url, this.sthis), getFileName(url, this.sthis));
653
731
  }
654
732
  async put(url, body) {
655
- return (0, import_cement11.exception2Result)(async () => {
733
+ return (0, import_cement12.exception2Result)(async () => {
656
734
  const file = await this.getFilePath(url);
657
735
  this.logger.Debug().Str("url", url.toString()).Str("file", file).Msg("put");
658
736
  await this.fs.writefile(file, body);
@@ -662,19 +740,19 @@ var init_gateway = __esm({
662
740
  return exceptionWrapper(async () => {
663
741
  const file = this.getFilePath(url);
664
742
  try {
743
+ this.logger.Debug().Url(url).Str("file", file).Msg("get");
665
744
  const res = await this.fs.readfile(file);
666
- this.logger.Debug().Url(url.asURL()).Str("file", file).Msg("get");
667
- return import_cement11.Result.Ok(new Uint8Array(res));
745
+ return import_cement12.Result.Ok(new Uint8Array(res));
668
746
  } catch (e) {
669
747
  if (isNotFoundError(e)) {
670
- return import_cement11.Result.Err(new NotFoundError(`file not found: ${file}`));
748
+ return import_cement12.Result.Err(new NotFoundError(`file not found: ${file}`));
671
749
  }
672
- return import_cement11.Result.Err(e);
750
+ return import_cement12.Result.Err(e);
673
751
  }
674
752
  });
675
753
  }
676
754
  async delete(url) {
677
- return (0, import_cement11.exception2Result)(async () => {
755
+ return (0, import_cement12.exception2Result)(async () => {
678
756
  await this.fs.unlink(this.getFilePath(url));
679
757
  });
680
758
  }
@@ -700,7 +778,7 @@ var init_gateway = __esm({
700
778
  }
701
779
  }
702
780
  }
703
- return import_cement11.Result.Ok(void 0);
781
+ return import_cement12.Result.Ok(void 0);
704
782
  }
705
783
  };
706
784
  FileTestStore = class {
@@ -709,7 +787,7 @@ var init_gateway = __esm({
709
787
  this.sthis = sthis;
710
788
  }
711
789
  async get(iurl, key) {
712
- const url = iurl.build().setParam("key", key).URI();
790
+ const url = iurl.build().setParam("key" /* KEY */, key).URI();
713
791
  const dbFile = this.sthis.pathOps.join(getPath(url, this.sthis), getFileName(url, this.sthis));
714
792
  this.logger.Debug().Url(url).Str("dbFile", dbFile).Msg("get");
715
793
  const buffer = await (await getFileSystem(url)).readfile(dbFile);
@@ -737,7 +815,7 @@ __export(gateway_exports2, {
737
815
  getIndexDBName: () => getIndexDBName
738
816
  });
739
817
  function ensureVersion(url) {
740
- return url.build().defParam("version", INDEXDB_VERSION).URI();
818
+ return url.build().defParam("version" /* VERSION */, INDEXDB_VERSION).URI();
741
819
  }
742
820
  function sanitzeKey(key) {
743
821
  if (key.length === 1) {
@@ -758,17 +836,17 @@ async function connectIdb(url, sthis) {
758
836
  }
759
837
  });
760
838
  const found = await db.get("version", "version");
761
- const version = ensureVersion(url).getParam("version");
839
+ const version = ensureVersion(url).getParam("version" /* VERSION */);
762
840
  if (!found) {
763
841
  await db.put("version", { version }, "version");
764
842
  } else if (found.version !== version) {
765
- sthis.logger.Warn().Str("url", url.toString()).Str("version", version).Str("found", found.version).Msg("version mismatch");
843
+ sthis.logger.Warn().Url(url).Str("version", version).Str("found", found.version).Msg("version mismatch");
766
844
  }
767
845
  return { db, dbName, version, url };
768
846
  });
769
847
  return {
770
848
  ...once,
771
- url: url.build().setParam("version", once.version).URI()
849
+ url: url.build().setParam("version" /* VERSION */, once.version).URI()
772
850
  };
773
851
  }
774
852
  function joinDBName(...names) {
@@ -777,7 +855,7 @@ function joinDBName(...names) {
777
855
  function getIndexDBName(iurl, sthis) {
778
856
  const url = ensureVersion(iurl);
779
857
  const fullDb = url.pathname.replace(/^\/+/, "").replace(/\?.*$/, "");
780
- const dbName = url.getParam("name");
858
+ const dbName = url.getParam("name" /* NAME */);
781
859
  if (!dbName) throw sthis.logger.Error().Str("url", url.toString()).Msg(`name not found`).AsError();
782
860
  const result = joinDBName(fullDb, dbName);
783
861
  const objStore = getStore(url, sthis, joinDBName).name;
@@ -789,15 +867,16 @@ function getIndexDBName(iurl, sthis) {
789
867
  dbName
790
868
  };
791
869
  }
792
- var import_idb2, import_cement12, onceIndexDB, IndexDBGateway, IndexDBTestStore;
870
+ var import_idb2, import_cement13, onceIndexDB, IndexDBGateway, IndexDBTestStore;
793
871
  var init_gateway2 = __esm({
794
872
  "src/runtime/gateways/indexdb/gateway.ts"() {
795
873
  "use strict";
796
874
  import_idb2 = require("idb");
797
- import_cement12 = require("@adviser/cement");
875
+ import_cement13 = require("@adviser/cement");
798
876
  init_version2();
799
877
  init_utils();
800
- onceIndexDB = new import_cement12.KeyedResolvOnce();
878
+ init_types();
879
+ onceIndexDB = new import_cement13.KeyedResolvOnce();
801
880
  IndexDBGateway = class {
802
881
  constructor(sthis) {
803
882
  this._db = {};
@@ -805,7 +884,7 @@ var init_gateway2 = __esm({
805
884
  this.sthis = sthis;
806
885
  }
807
886
  async start(baseURL) {
808
- return (0, import_cement12.exception2Result)(async () => {
887
+ return (0, import_cement13.exception2Result)(async () => {
809
888
  this.logger.Debug().Url(baseURL).Msg("starting");
810
889
  await this.sthis.start();
811
890
  const ic = await connectIdb(baseURL, this.sthis);
@@ -815,10 +894,10 @@ var init_gateway2 = __esm({
815
894
  });
816
895
  }
817
896
  async close() {
818
- return import_cement12.Result.Ok(void 0);
897
+ return import_cement13.Result.Ok(void 0);
819
898
  }
820
899
  async destroy(baseUrl) {
821
- return (0, import_cement12.exception2Result)(async () => {
900
+ return (0, import_cement13.exception2Result)(async () => {
822
901
  const type = getStore(baseUrl, this.sthis, joinDBName).name;
823
902
  const idb = this._db;
824
903
  const trans = idb.transaction(type, "readwrite");
@@ -834,7 +913,7 @@ var init_gateway2 = __esm({
834
913
  });
835
914
  }
836
915
  buildUrl(baseUrl, key) {
837
- return Promise.resolve(import_cement12.Result.Ok(baseUrl.build().setParam("key", key).URI()));
916
+ return Promise.resolve(import_cement13.Result.Ok(baseUrl.build().setParam("key" /* KEY */, key).URI()));
838
917
  }
839
918
  async get(url) {
840
919
  return exceptionWrapper(async () => {
@@ -845,13 +924,13 @@ var init_gateway2 = __esm({
845
924
  const bytes = await tx.objectStore(store).get(sanitzeKey(key));
846
925
  await tx.done;
847
926
  if (!bytes) {
848
- return import_cement12.Result.Err(new NotFoundError(`missing ${key}`));
927
+ return import_cement13.Result.Err(new NotFoundError(`missing ${key}`));
849
928
  }
850
- return import_cement12.Result.Ok(bytes);
929
+ return import_cement13.Result.Ok(bytes);
851
930
  });
852
931
  }
853
932
  async put(url, value) {
854
- return (0, import_cement12.exception2Result)(async () => {
933
+ return (0, import_cement13.exception2Result)(async () => {
855
934
  const key = getKey(url, this.logger);
856
935
  const store = getStore(url, this.sthis, joinDBName).name;
857
936
  this.logger.Debug().Url(url).Str("key", key).Str("store", store).Msg("putting");
@@ -861,14 +940,14 @@ var init_gateway2 = __esm({
861
940
  });
862
941
  }
863
942
  async delete(url) {
864
- return (0, import_cement12.exception2Result)(async () => {
943
+ return (0, import_cement13.exception2Result)(async () => {
865
944
  const key = getKey(url, this.logger);
866
945
  const store = getStore(url, this.sthis, joinDBName).name;
867
946
  this.logger.Debug().Url(url).Str("key", key).Str("store", store).Msg("deleting");
868
947
  const tx = this._db.transaction([store], "readwrite");
869
948
  await tx.objectStore(store).delete(sanitzeKey(key));
870
949
  await tx.done;
871
- return import_cement12.Result.Ok(void 0);
950
+ return import_cement13.Result.Ok(void 0);
872
951
  });
873
952
  }
874
953
  };
@@ -896,15 +975,16 @@ var init_gateway2 = __esm({
896
975
  var src_exports = {};
897
976
  __export(src_exports, {
898
977
  CRDT: () => CRDT,
899
- Database: () => Database,
978
+ DatabaseFactory: () => DatabaseFactory,
979
+ DatabaseShell: () => DatabaseShell,
900
980
  Index: () => Index,
901
981
  NotFoundError: () => NotFoundError,
902
982
  PACKAGE_VERSION: () => PACKAGE_VERSION,
983
+ PARAM: () => PARAM,
903
984
  Result: () => import_cement.Result,
904
985
  UInt8ArrayEqual: () => UInt8ArrayEqual,
905
986
  blockstore: () => blockstore_exports,
906
987
  bs: () => blockstore_exports,
907
- dataDir: () => dataDir,
908
988
  ensureLogger: () => ensureLogger,
909
989
  ensureSuperLog: () => ensureSuperLog,
910
990
  ensureSuperThis: () => ensureSuperThis,
@@ -915,16 +995,19 @@ __export(src_exports, {
915
995
  getName: () => getName,
916
996
  getStore: () => getStore,
917
997
  index: () => index,
998
+ isDatabase: () => isDatabase,
918
999
  isFalsy: () => isFalsy,
919
1000
  isNotFoundError: () => isNotFoundError,
1001
+ keyConfigOpts: () => keyConfigOpts,
920
1002
  rt: () => runtime_exports,
921
1003
  runtime: () => runtime_exports,
922
- throwFalsy: () => throwFalsy
1004
+ throwFalsy: () => throwFalsy,
1005
+ toStoreURIRuntime: () => toStoreURIRuntime
923
1006
  });
924
1007
  module.exports = __toCommonJS(src_exports);
925
1008
 
926
1009
  // src/database.ts
927
- var import_cement16 = require("@adviser/cement");
1010
+ var import_cement18 = require("@adviser/cement");
928
1011
 
929
1012
  // src/write-queue.ts
930
1013
  function writeQueue(worker, payload = Infinity, unbounded = false) {
@@ -967,86 +1050,7 @@ function writeQueue(worker, payload = Infinity, unbounded = false) {
967
1050
  }
968
1051
 
969
1052
  // src/crdt.ts
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);
1053
+ var import_cement17 = require("@adviser/cement");
1050
1054
 
1051
1055
  // src/blockstore/index.ts
1052
1056
  var blockstore_exports = {};
@@ -1059,8 +1063,11 @@ __export(blockstore_exports, {
1059
1063
  FragmentGateway: () => FragmentGateway,
1060
1064
  Loader: () => Loader,
1061
1065
  addCryptoKeyToGatewayMetaPayload: () => addCryptoKeyToGatewayMetaPayload,
1062
- ensureStart: () => ensureStart,
1063
- getGatewayFromURL: () => getGatewayFromURL,
1066
+ ensureStoreEnDeFile: () => ensureStoreEnDeFile,
1067
+ fileGatewayFactoryItem: () => fileGatewayFactoryItem,
1068
+ getDefaultURI: () => getDefaultURI,
1069
+ getGatewayFactoryItem: () => getGatewayFactoryItem,
1070
+ getStartedGateway: () => getStartedGateway,
1064
1071
  parseCarFile: () => parseCarFile,
1065
1072
  registerStoreProtocol: () => registerStoreProtocol,
1066
1073
  setCryptoKeyFromGatewayMetaPayload: () => setCryptoKeyFromGatewayMetaPayload,
@@ -1075,7 +1082,7 @@ function toCIDBlock(block) {
1075
1082
  }
1076
1083
 
1077
1084
  // src/blockstore/store-factory.ts
1078
- var import_cement13 = require("@adviser/cement");
1085
+ var import_cement15 = require("@adviser/cement");
1079
1086
 
1080
1087
  // src/runtime/files.ts
1081
1088
  var files_exports = {};
@@ -1149,261 +1156,26 @@ var UnixFSFileBuilder = class {
1149
1156
  };
1150
1157
 
1151
1158
  // src/blockstore/store.ts
1152
- var import_p_limit2 = __toESM(require("p-limit"), 1);
1153
1159
  var import_dag_json2 = require("@ipld/dag-json");
1154
1160
  var import_cement10 = require("@adviser/cement");
1155
-
1156
- // src/types.ts
1157
- function isFalsy(value) {
1158
- return value === false && value === null && value === void 0;
1159
- }
1160
- function throwFalsy(value) {
1161
- if (isFalsy(value)) {
1162
- throw new Error("value is Falsy");
1163
- }
1164
- return value;
1165
- }
1166
- function falsyToUndef(value) {
1167
- if (isFalsy(value)) {
1168
- return void 0;
1169
- }
1170
- return value;
1171
- }
1172
-
1173
- // src/blockstore/store.ts
1161
+ init_types();
1174
1162
  init_utils();
1175
1163
 
1176
- // src/blockstore/loader.ts
1177
- var import_p_limit = __toESM(require("p-limit"), 1);
1178
- var import_car = require("@ipld/car");
1179
- var import_cement7 = require("@adviser/cement");
1180
-
1181
- // src/blockstore/loader-helpers.ts
1182
- var import_sha2 = require("multiformats/hashes/sha2");
1183
- var dagCodec = __toESM(require("@ipld/dag-cbor"), 1);
1184
- async function parseCarFile(reader, logger) {
1185
- const roots = await reader.getRoots();
1186
- const header = await reader.get(roots[0]);
1187
- if (!header) throw logger.Error().Msg("missing header block").AsError();
1188
- const dec = await decode({ bytes: header.bytes, hasher: import_sha2.sha256, codec: dagCodec });
1189
- const fpvalue = dec.value;
1190
- if (fpvalue && !fpvalue.fp) {
1191
- throw logger.Error().Msg("missing fp").AsError();
1192
- }
1193
- return fpvalue.fp;
1194
- }
1195
-
1196
- // src/blockstore/transaction.ts
1197
- var import_block3 = require("@web3-storage/pail/block");
1164
+ // src/blockstore/commit-queue.ts
1198
1165
  var import_cement2 = require("@adviser/cement");
1199
- init_utils();
1200
- var CarTransaction = class extends import_block3.MemoryBlockstore {
1201
- constructor(parent, opts = { add: true, noLoader: false }) {
1202
- super();
1203
- if (opts.add) {
1204
- parent.transactions.add(this);
1205
- }
1206
- this.parent = parent;
1207
- }
1208
- async get(cid) {
1209
- return await this.superGet(cid) || falsyToUndef(await this.parent.get(cid));
1210
- }
1211
- async superGet(cid) {
1212
- return super.get(cid);
1166
+ var CommitQueue = class {
1167
+ constructor() {
1168
+ this.queue = [];
1169
+ this.processing = false;
1170
+ this._waitIdleItems = /* @__PURE__ */ new Set();
1213
1171
  }
1214
- };
1215
- function defaultedBlockstoreRuntime(sthis, opts, component, ctx) {
1216
- const logger = ensureLogger(sthis, component, ctx);
1217
- const store = opts.store || {};
1218
- return {
1219
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1220
- applyMeta: (meta, snap) => {
1172
+ waitIdle() {
1173
+ if (this.queue.length === 0 && !this.processing) {
1221
1174
  return Promise.resolve();
1222
- },
1223
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1224
- compact: async (blocks) => {
1225
- return {};
1226
- },
1227
- autoCompact: 100,
1228
- public: false,
1229
- name: void 0,
1230
- threshold: 1e3 * 1e3,
1231
- ...opts,
1232
- logger,
1233
- keyBag: opts.keyBag || {},
1234
- crypto: (0, import_cement2.toCryptoRuntime)(opts.crypto),
1235
- store,
1236
- storeRuntime: toStoreRuntime(store, sthis)
1237
- };
1238
- }
1239
- function blockstoreFactory(sthis, opts) {
1240
- if (opts.name) {
1241
- return new EncryptedBlockstore(sthis, opts);
1242
- } else {
1243
- return new BaseBlockstore(opts);
1244
- }
1245
- }
1246
- var BaseBlockstore = class {
1247
- constructor(ebOpts = {}) {
1248
- this.transactions = /* @__PURE__ */ new Set();
1249
- this.sthis = ensureSuperThis(ebOpts);
1250
- this.ebOpts = defaultedBlockstoreRuntime(this.sthis, ebOpts, "BaseBlockstore");
1251
- this.logger = this.ebOpts.logger;
1252
- }
1253
- // ready: Promise<void>;
1254
- ready() {
1255
- return Promise.resolve();
1256
- }
1257
- async close() {
1258
- }
1259
- async destroy() {
1260
- }
1261
- async get(cid) {
1262
- if (!cid) throw this.logger.Error().Msg("required cid").AsError();
1263
- for (const f of this.transactions) {
1264
- const v = await f.superGet(cid);
1265
- if (v) return v;
1266
- }
1267
- }
1268
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1269
- async put(cid, block) {
1270
- throw this.logger.Error().Msg("use a transaction to put").AsError();
1271
- }
1272
- // TransactionMeta
1273
- async transaction(fn, _opts) {
1274
- const t = new CarTransaction(this, _opts);
1275
- const done = await fn(t);
1276
- this.lastTxMeta = done;
1277
- return { t, meta: done };
1278
- }
1279
- async *entries() {
1280
- const seen = /* @__PURE__ */ new Set();
1281
- for (const t of this.transactions) {
1282
- for await (const blk of t.entries()) {
1283
- if (seen.has(blk.cid.toString())) continue;
1284
- seen.add(blk.cid.toString());
1285
- yield blk;
1286
- }
1287
- }
1288
- }
1289
- };
1290
- var EncryptedBlockstore = class extends BaseBlockstore {
1291
- constructor(sthis, ebOpts) {
1292
- super(ebOpts);
1293
- this.compacting = false;
1294
- this.logger = ensureLogger(this.sthis, "EncryptedBlockstore");
1295
- const { name } = ebOpts;
1296
- if (!name) {
1297
- throw this.logger.Error().Msg("name required").AsError();
1298
- }
1299
- this.name = name;
1300
- this.loader = new Loader(this.name, ebOpts, sthis);
1301
- }
1302
- ready() {
1303
- return this.loader.ready();
1304
- }
1305
- close() {
1306
- return this.loader.close();
1307
- }
1308
- destroy() {
1309
- return this.loader.destroy();
1310
- }
1311
- async get(cid) {
1312
- const got = await super.get(cid);
1313
- if (got) return got;
1314
- if (!this.loader) {
1315
- return;
1316
- }
1317
- return falsyToUndef(await this.loader.getBlock(cid));
1318
- }
1319
- async transaction(fn, opts = { noLoader: false }) {
1320
- const { t, meta: done } = await super.transaction(fn);
1321
- const cars = await this.loader.commit(t, done, opts);
1322
- if (this.ebOpts.autoCompact && this.loader.carLog.length > this.ebOpts.autoCompact) {
1323
- setTimeout(() => void this.compact(), 10);
1324
- }
1325
- if (cars) {
1326
- this.transactions.delete(t);
1327
- return { meta: done, cars, t };
1328
- }
1329
- throw this.logger.Error().Msg("failed to commit car files").AsError();
1330
- }
1331
- async getFile(car, cid) {
1332
- await this.ready();
1333
- if (!this.loader) throw this.logger.Error().Msg("loader required to get file, database must be named").AsError();
1334
- const reader = await this.loader.loadFileCar(
1335
- car
1336
- /*, isPublic */
1337
- );
1338
- const block = await reader.get(cid);
1339
- if (!block) throw this.logger.Error().Str("cid", cid.toString()).Msg(`Missing block`).AsError();
1340
- return block.bytes;
1341
- }
1342
- async compact() {
1343
- await this.ready();
1344
- if (!this.loader) throw this.logger.Error().Msg("loader required to compact").AsError();
1345
- if (this.loader.carLog.length < 2) return;
1346
- const compactFn = this.ebOpts.compact || ((blocks) => this.defaultCompact(blocks, this.logger));
1347
- if (!compactFn || this.compacting) return;
1348
- const blockLog = new CompactionFetcher(this);
1349
- this.compacting = true;
1350
- const meta = await compactFn(blockLog);
1351
- await this.loader?.commit(blockLog.loggedBlocks, meta, {
1352
- compact: true,
1353
- noLoader: true
1354
- });
1355
- this.compacting = false;
1356
- }
1357
- async defaultCompact(blocks, logger) {
1358
- if (!this.loader) {
1359
- throw logger.Error().Msg("no loader").AsError();
1360
- }
1361
- if (!this.lastTxMeta) {
1362
- throw logger.Error().Msg("no lastTxMeta").AsError();
1363
- }
1364
- for await (const blk of this.loader.entries(false)) {
1365
- blocks.loggedBlocks.putSync(blk.cid, blk.bytes);
1366
- }
1367
- for (const t of this.transactions) {
1368
- for await (const blk of t.entries()) {
1369
- blocks.loggedBlocks.putSync(blk.cid, blk.bytes);
1370
- }
1371
- }
1372
- return this.lastTxMeta;
1373
- }
1374
- async *entries() {
1375
- for await (const blk of this.loader.entries()) {
1376
- yield blk;
1377
- }
1378
- }
1379
- };
1380
- var CompactionFetcher = class {
1381
- constructor(blocks) {
1382
- this.blockstore = blocks;
1383
- this.loggedBlocks = new CarTransaction(blocks);
1384
- }
1385
- async get(cid) {
1386
- const block = await this.blockstore.get(cid);
1387
- if (block) this.loggedBlocks.putSync(cid, block.bytes);
1388
- return falsyToUndef(block);
1389
- }
1390
- };
1391
-
1392
- // src/blockstore/commit-queue.ts
1393
- var import_cement3 = require("@adviser/cement");
1394
- var CommitQueue = class {
1395
- constructor() {
1396
- this.queue = [];
1397
- this.processing = false;
1398
- this._waitIdleItems = /* @__PURE__ */ new Set();
1399
- }
1400
- waitIdle() {
1401
- if (this.queue.length === 0 && !this.processing) {
1402
- return Promise.resolve();
1403
- }
1404
- const fn = new import_cement3.Future();
1405
- this._waitIdleItems.add(fn);
1406
- return fn.asPromise();
1175
+ }
1176
+ const fn = new import_cement2.Future();
1177
+ this._waitIdleItems.add(fn);
1178
+ return fn.asPromise();
1407
1179
  }
1408
1180
  async enqueue(fn) {
1409
1181
  return new Promise((resolve, reject) => {
@@ -1440,1128 +1212,1499 @@ var CommitQueue = class {
1440
1212
  }
1441
1213
  };
1442
1214
 
1443
- // src/runtime/key-bag.ts
1444
- var key_bag_exports = {};
1445
- __export(key_bag_exports, {
1446
- KeyBag: () => KeyBag,
1447
- getKeyBag: () => getKeyBag,
1448
- registerKeyBagProviderFactory: () => registerKeyBagProviderFactory
1215
+ // src/runtime/keyed-crypto.ts
1216
+ var keyed_crypto_exports = {};
1217
+ __export(keyed_crypto_exports, {
1218
+ BlockIvKeyIdCodec: () => BlockIvKeyIdCodec,
1219
+ keyedCryptoFactory: () => keyedCryptoFactory
1449
1220
  });
1450
- var import_cement6 = require("@adviser/cement");
1451
1221
  init_utils();
1452
1222
  var import_base582 = require("multiformats/bases/base58");
1453
- var KeyBag = class {
1454
- constructor(rt) {
1455
- this.rt = rt;
1456
- this._warnOnce = new import_cement6.ResolveOnce();
1457
- this._seq = new import_cement6.ResolveSeq();
1458
- this.logger = ensureLogger(rt.sthis, "KeyBag");
1459
- this.logger.Debug().Msg("KeyBag created");
1460
- }
1461
- async subtleKey(key) {
1462
- const extractable = this.rt.url.getParam("extractKey") === "_deprecated_internal_api";
1463
- if (extractable) {
1464
- this._warnOnce.once(
1465
- () => this.logger.Warn().Msg("extractKey is enabled via _deprecated_internal_api --- handle keys safely!!!")
1466
- );
1467
- }
1468
- return await this.rt.crypto.importKey(
1469
- "raw",
1470
- // raw or jwk
1471
- import_base582.base58btc.decode(key),
1472
- // hexStringToUint8Array(key), // raw data
1473
- "AES-GCM",
1474
- extractable,
1475
- ["encrypt", "decrypt"]
1476
- );
1477
- }
1478
- async ensureKeyFromUrl(url, keyFactory) {
1479
- const storeKey = url.getParam("storekey");
1480
- if (storeKey === "insecure") {
1481
- return import_cement6.Result.Ok(url);
1482
- }
1483
- if (!storeKey) {
1484
- const keyName = `@${keyFactory()}@`;
1485
- const ret = await this.getNamedKey(keyName);
1486
- if (ret.isErr()) {
1487
- return ret;
1488
- }
1489
- const urb = url.build().setParam("storekey", keyName);
1490
- return import_cement6.Result.Ok(urb.URI());
1223
+ 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;
1491
1235
  }
1492
- if (storeKey.startsWith("@") && storeKey.endsWith("@")) {
1493
- const ret = await this.getNamedKey(storeKey);
1494
- if (ret.isErr()) {
1495
- return ret;
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];
1496
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));
1497
1249
  }
1498
- return import_cement6.Result.Ok(url);
1499
1250
  }
1500
- async toKeyWithFingerPrint(keyStr) {
1501
- const material = import_base582.base58btc.decode(keyStr);
1502
- const key = await this.subtleKey(keyStr);
1503
- const fpr = await this.rt.crypto.digestSHA256(material);
1504
- return import_cement6.Result.Ok({
1505
- key,
1506
- fingerPrint: import_base582.base58btc.encode(new Uint8Array(fpr))
1251
+ };
1252
+ function getGenerateIVFn(url, opts) {
1253
+ const ivhash = opts.ivCalc || url.getParam("ivHash" /* IV_HASH */) || "hash";
1254
+ return generateIV[ivhash] || generateIV["hash"];
1255
+ }
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 || {};
1263
+ }
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 })
1507
1274
  });
1508
1275
  }
1509
- async setNamedKey(name, key) {
1510
- return this._seq.add(() => this._setNamedKey(name, key));
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;
1511
1294
  }
1512
- // avoid deadlock
1513
- async _setNamedKey(name, key) {
1514
- const item = {
1515
- name,
1516
- key
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;
1304
+ }
1305
+ fingerPrint() {
1306
+ return Promise.resolve(this.key.fingerPrint);
1307
+ }
1308
+ codec(iv, opts) {
1309
+ return new BlockIvKeyIdCodec(this, iv, opts);
1310
+ }
1311
+ algo(iv) {
1312
+ return {
1313
+ name: "AES-GCM",
1314
+ iv: iv || this.crypto.randomBytes(this.ivLength),
1315
+ tagLength: 128
1517
1316
  };
1518
- const bag = await this.rt.getBag();
1519
- this.logger.Debug().Str("name", name).Msg("setNamedKey");
1520
- await bag.set(name, item);
1521
- return await this.toKeyWithFingerPrint(item.key);
1522
1317
  }
1523
- async getNamedExtractableKey(name, failIfNotFound = false) {
1524
- const ret = await this.getNamedKey(name, failIfNotFound);
1525
- if (ret.isErr()) {
1526
- return ret;
1527
- }
1528
- const named = ret.Ok();
1529
- return import_cement6.Result.Ok({
1530
- ...named,
1531
- extract: async () => {
1532
- const ext = new Uint8Array(await this.rt.crypto.exportKey("raw", named.key));
1533
- return {
1534
- key: ext,
1535
- keyStr: import_base582.base58btc.encode(ext)
1536
- };
1537
- }
1538
- });
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));
1539
1321
  }
1540
- async getNamedKey(name, failIfNotFound = false) {
1541
- const id = this.rt.sthis.nextId(4).str;
1542
- return this._seq.add(async () => {
1543
- const bag = await this.rt.getBag();
1544
- const named = await bag.get(name);
1545
- if (named) {
1546
- const fpr = await this.toKeyWithFingerPrint(named.key);
1547
- this.logger.Debug().Str("id", id).Str("name", name).Result("fpr", fpr).Msg("fingerPrint getNamedKey");
1548
- return fpr;
1549
- }
1550
- if (failIfNotFound) {
1551
- this.logger.Debug().Str("id", id).Str("name", name).Msg("failIfNotFound getNamedKey");
1552
- return import_cement6.Result.Err(new Error(`Key not found: ${name}`));
1553
- }
1554
- const ret = await this._setNamedKey(name, import_base582.base58btc.encode(this.rt.crypto.randomBytes(this.rt.keyLength)));
1555
- this.logger.Debug().Str("id", id).Str("name", name).Result("fpr", ret).Msg("createKey getNamedKey-post");
1556
- return ret;
1557
- });
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));
1558
1326
  }
1559
1327
  };
1560
- var keyBagProviderFactories = new Map(
1561
- [
1562
- {
1563
- protocol: "file:",
1564
- factory: async (url, sthis) => {
1565
- const { KeyBagProviderFile: KeyBagProviderFile2 } = await Promise.resolve().then(() => (init_key_bag_file(), key_bag_file_exports));
1566
- return new KeyBagProviderFile2(url, sthis);
1567
- }
1568
- },
1569
- {
1570
- protocol: "indexdb:",
1571
- factory: async (url, sthis) => {
1572
- const { KeyBagProviderIndexDB: KeyBagProviderIndexDB2 } = await Promise.resolve().then(() => (init_key_bag_indexdb(), key_bag_indexdb_exports));
1573
- return new KeyBagProviderIndexDB2(url, sthis);
1574
- }
1575
- }
1576
- ].map((i) => [i.protocol, i])
1577
- );
1578
- function registerKeyBagProviderFactory(item) {
1579
- const protocol = item.protocol.endsWith(":") ? item.protocol : item.protocol + ":";
1580
- keyBagProviderFactories.set(protocol, {
1581
- ...item,
1582
- protocol
1583
- });
1584
- }
1585
- function defaultKeyBagOpts(sthis, kbo) {
1586
- if (kbo.keyRuntime) {
1587
- return kbo.keyRuntime;
1328
+ var nullCodec = class {
1329
+ constructor() {
1330
+ this.code = 0;
1331
+ this.name = "Fireproof@unencrypted-block";
1588
1332
  }
1589
- const logger = ensureLogger(sthis, "KeyBag");
1590
- let url;
1591
- if (kbo.url) {
1592
- url = import_cement6.URI.from(kbo.url);
1593
- logger.Debug().Url(url).Msg("from opts");
1594
- } else {
1595
- let bagFnameOrUrl = sthis.env.get("FP_KEYBAG_URL");
1596
- if ((0, import_cement6.runtimeFn)().isBrowser) {
1597
- url = import_cement6.URI.from(bagFnameOrUrl || "indexdb://fp-keybag");
1598
- } else {
1599
- if (!bagFnameOrUrl) {
1600
- const home = sthis.env.get("HOME");
1601
- bagFnameOrUrl = `${home}/.fireproof/keybag`;
1602
- url = import_cement6.URI.from(`file://${bagFnameOrUrl}`);
1603
- } else {
1604
- url = import_cement6.URI.from(bagFnameOrUrl);
1605
- }
1606
- }
1607
- logger.Debug().Url(url).Msg("from env");
1333
+ encode(data) {
1334
+ return data;
1608
1335
  }
1609
- const kitem = keyBagProviderFactories.get(url.protocol);
1610
- if (!kitem) {
1611
- throw logger.Error().Url(url).Msg("unsupported protocol").AsError();
1336
+ decode(data) {
1337
+ return data;
1612
1338
  }
1613
- const getBag = async () => kitem.factory(url, sthis);
1614
- if (url.hasParam("masterkey")) {
1615
- throw logger.Error().Url(url).Msg("masterkey is not supported").AsError();
1339
+ };
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;
1616
1350
  }
1617
- return {
1618
- url,
1619
- crypto: kbo.crypto || (0, import_cement6.toCryptoRuntime)({}),
1620
- sthis,
1621
- logger,
1622
- keyLength: kbo.keyLength || 16,
1623
- getBag,
1624
- id: () => {
1625
- return url.toString();
1626
- }
1627
- };
1628
- }
1629
- var _keyBags = new import_cement6.KeyedResolvOnce();
1630
- async function getKeyBag(sthis, kbo = {}) {
1631
- await sthis.start();
1632
- const rt = defaultKeyBagOpts(sthis, kbo);
1633
- return _keyBags.get(rt.id()).once(async () => new KeyBag(rt));
1634
- }
1635
-
1636
- // src/blockstore/commitor.ts
1637
- var CBW = __toESM(require("@ipld/car/buffer-writer"), 1);
1638
- var import_sha22 = require("multiformats/hashes/sha2");
1639
- var dagCodec2 = __toESM(require("@ipld/dag-cbor"), 1);
1640
- async function encodeCarFile(roots, t, codec3) {
1641
- let size = 0;
1642
- const headerSize = CBW.headerLength({ roots });
1643
- size += headerSize;
1644
- for (const { cid, bytes } of t.entries()) {
1645
- size += CBW.blockLength({ cid, bytes });
1351
+ fingerPrint() {
1352
+ return Promise.resolve(this._fingerPrint);
1646
1353
  }
1647
- const buffer = new Uint8Array(size);
1648
- const writer = CBW.createWriter(buffer, { headerSize });
1649
- for (const r of roots) {
1650
- writer.addRoot(r);
1354
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1355
+ codec(iv) {
1356
+ return new nullCodec();
1651
1357
  }
1652
- for (const { cid, bytes } of t.entries()) {
1653
- writer.write({ cid, bytes });
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
+ };
1654
1365
  }
1655
- writer.close();
1656
- return await encode({ value: writer.bytes, hasher: import_sha22.sha256, codec: codec3 });
1657
- }
1658
- async function createCarFile(encoder, cid, t) {
1659
- return encodeCarFile([cid], t, encoder);
1660
- }
1661
- async function commitFiles(fileStore, walStore, t, done) {
1662
- const { files: roots } = makeFileCarHeader(done);
1663
- const cids = [];
1664
- const codec3 = (await fileStore.keyedCrypto()).codec();
1665
- const cars = await prepareCarFilesFiles(codec3, roots, t);
1666
- for (const car of cars) {
1667
- const { cid, bytes } = car;
1668
- await fileStore.save({ cid, bytes });
1669
- await walStore.enqueueFile(
1670
- cid
1671
- /*, !!opts.public*/
1672
- );
1673
- cids.push(cid);
1366
+ _decrypt() {
1367
+ throw this.logger.Error().Msg("noCrypto.decrypt not implemented").AsError();
1674
1368
  }
1675
- return cids;
1676
- }
1677
- function makeFileCarHeader(result) {
1678
- const files = [];
1679
- for (const [, meta] of Object.entries(result.files || {})) {
1680
- if (meta && typeof meta === "object" && "cid" in meta && meta !== null) {
1681
- files.push(meta.cid);
1369
+ _encrypt() {
1370
+ throw this.logger.Error().Msg("noCrypto.decrypt not implemented").AsError();
1371
+ }
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
+ }
1682
1383
  }
1384
+ return new keyedCrypto(url, rkey.Ok(), kb.rt.crypto, sthis);
1683
1385
  }
1684
- return { ...result, files };
1685
- }
1686
- async function prepareCarFilesFiles(encoder, roots, t) {
1687
- return [await encodeCarFile(roots, t, encoder)];
1688
- }
1689
- function makeCarHeader(meta, cars, compact = false) {
1690
- const coreHeader = compact ? { cars: [], compact: cars } : { cars, compact: [] };
1691
- return { ...coreHeader, meta };
1692
- }
1693
- async function encodeCarHeader(fp) {
1694
- return await encode({
1695
- value: { fp },
1696
- hasher: import_sha22.sha256,
1697
- codec: dagCodec2
1698
- });
1386
+ return new noCrypto(url, kb.rt.crypto, sthis);
1699
1387
  }
1700
- async function commit(params, t, done, opts = { noLoader: false, compact: false }) {
1701
- const fp = makeCarHeader(done, params.carLog, !!opts.compact);
1702
- const rootBlock = await encodeCarHeader(fp);
1703
- const cars = await prepareCarFiles(params.encoder, params.threshold, rootBlock, t);
1704
- const cids = [];
1705
- for (const car of cars) {
1706
- const { cid, bytes } = car;
1707
- await params.carStore.save({ cid, bytes });
1708
- cids.push(cid);
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);
1709
1400
  }
1710
- const newDbMeta = { cars: cids };
1711
- await params.WALStore.enqueue(newDbMeta, opts);
1712
- await params.metaStore.save(newDbMeta);
1713
- return { cgrp: cids, header: fp };
1401
+ if (isNaN(ret) || ret <= 0) {
1402
+ ret = 0;
1403
+ }
1404
+ return ret;
1714
1405
  }
1715
- async function prepareCarFiles(encoder, threshold, rootBlock, t) {
1716
- const carFiles = [];
1717
- threshold = threshold || 128e3 * 8;
1718
- let clonedt = new CarTransaction(t.parent, { add: false, noLoader: false });
1719
- clonedt.putSync(rootBlock.cid, rootBlock.bytes);
1720
- let newsize = CBW.blockLength(toCIDBlock(rootBlock));
1721
- let cidRootBlock = rootBlock;
1722
- for (const { cid, bytes } of t.entries()) {
1723
- newsize += CBW.blockLength(toCIDBlock({ cid, bytes }));
1724
- if (newsize >= threshold) {
1725
- carFiles.push(await createCarFile(encoder, cidRootBlock.cid, clonedt));
1726
- clonedt = new CarTransaction(t.parent, { add: false, noLoader: false });
1727
- clonedt.putSync(cid, bytes);
1728
- cidRootBlock = { cid, bytes };
1729
- newsize = CBW.blockLength(toCIDBlock({ cid, bytes }));
1730
- } else {
1731
- clonedt.putSync(cid, bytes);
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];
1732
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
+ ];
1733
1422
  }
1734
- carFiles.push(await createCarFile(encoder, cidRootBlock.cid, clonedt));
1735
- return carFiles;
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)
1448
+ );
1449
+ }
1450
+ return Promise.all(ops);
1736
1451
  }
1737
-
1738
- // src/blockstore/loader.ts
1739
- var import_sha23 = require("multiformats/hashes/sha2");
1740
-
1741
- // src/blockstore/task-manager.ts
1742
- init_utils();
1743
- var TaskManager = class {
1744
- constructor(sthis, callback) {
1745
- this.eventsWeHandled = /* @__PURE__ */ new Set();
1746
- this.queue = [];
1747
- this.isProcessing = false;
1748
- this.logger = ensureLogger(sthis, "TaskManager");
1749
- this.callback = callback;
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;
1750
1459
  }
1751
- async handleEvent(cid, parents, dbMeta) {
1752
- for (const parent of parents) {
1753
- this.eventsWeHandled.add(parent.toString());
1460
+ slicer(url, body) {
1461
+ const fragSize = getFragSize(url);
1462
+ if (!fragSize) {
1463
+ return [this.innerGW.put(url, body)];
1754
1464
  }
1755
- this.queue.push({ cid: cid.toString(), dbMeta, retries: 0 });
1756
- this.queue = this.queue.filter(({ cid: cid2 }) => !this.eventsWeHandled.has(cid2));
1757
- void this.processQueue();
1758
- }
1759
- async processQueue() {
1760
- if (this.isProcessing) return;
1761
- this.isProcessing = true;
1762
- const filteredQueue = this.queue.filter(({ cid }) => !this.eventsWeHandled.has(cid));
1763
- const first = filteredQueue[0];
1764
- if (!first) {
1765
- return;
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();
1766
1468
  }
1767
- try {
1768
- await this.callback(first.dbMeta);
1769
- this.eventsWeHandled.add(first.cid);
1770
- this.queue = this.queue.filter(({ cid }) => !this.eventsWeHandled.has(cid));
1771
- } catch (err) {
1772
- if (first.retries++ > 3) {
1773
- this.logger.Error().Str("cid", first.cid).Msg("failed to process event block after 3 retries");
1774
- this.queue = this.queue.filter(({ cid }) => cid !== first.cid);
1775
- }
1776
- await new Promise((resolve) => setTimeout(resolve, 50));
1777
- throw this.logger.Error().Err(err).Msg("failed to process event block").AsError();
1778
- } finally {
1779
- this.isProcessing = false;
1780
- if (this.queue.length > 0) {
1781
- void this.processQueue();
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();
1782
1481
  }
1482
+ ops.push(this.innerGW.put(fragUrl.setParam("ofs", ofs.toString()).URI(), block));
1783
1483
  }
1484
+ return ops;
1784
1485
  }
1785
- };
1786
-
1787
- // src/blockstore/loader.ts
1788
- function carLogIncludesGroup(list, cids) {
1789
- return list.some((arr) => {
1790
- return arr.toString() === cids.toString();
1791
- });
1792
- }
1793
- function uniqueCids(list, remove = /* @__PURE__ */ new Set()) {
1794
- const byString = /* @__PURE__ */ new Map();
1795
- for (const cid of list) {
1796
- if (remove.has(cid.toString())) continue;
1797
- byString.set(cid.toString(), cid);
1798
- }
1799
- return [...byString.values()];
1800
- }
1801
- var Loader = class {
1802
- constructor(name, ebOpts, sthis) {
1803
- this.commitQueue = new CommitQueue();
1804
- this.isCompacting = false;
1805
- this.carReaders = /* @__PURE__ */ new Map();
1806
- this.seenCompacted = /* @__PURE__ */ new Set();
1807
- this.processedCars = /* @__PURE__ */ new Set();
1808
- this.carLog = [];
1809
- this.getBlockCache = /* @__PURE__ */ new Map();
1810
- this.seenMeta = /* @__PURE__ */ new Set();
1811
- this.writeLimit = (0, import_p_limit.default)(1);
1812
- this.onceReady = new import_cement7.ResolveOnce();
1813
- this.name = name;
1814
- this.sthis = sthis;
1815
- this.ebOpts = defaultedBlockstoreRuntime(
1816
- sthis,
1817
- {
1818
- ...ebOpts,
1819
- name
1820
- },
1821
- "Loader"
1822
- );
1823
- this.logger = this.ebOpts.logger;
1824
- this.taskManager = new TaskManager(sthis, async (dbMeta) => {
1825
- await this.handleDbMetasFromStore([dbMeta]);
1826
- });
1827
- }
1828
- // readonly id = uuidv4();
1829
- async keyBag() {
1830
- return getKeyBag(this.sthis, this.ebOpts.keyBag);
1486
+ buildUrl(baseUrl, key) {
1487
+ return this.innerGW.buildUrl(baseUrl, key);
1831
1488
  }
1832
- async carStore() {
1833
- return this.ebOpts.storeRuntime.makeDataStore(this);
1489
+ async destroy(iurl) {
1490
+ return this.innerGW.destroy(iurl);
1834
1491
  }
1835
- async fileStore() {
1836
- return this.ebOpts.storeRuntime.makeDataStore(this);
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);
1837
1502
  }
1838
- async WALStore() {
1839
- return this.ebOpts.storeRuntime.makeWALStore(this);
1503
+ async close(url) {
1504
+ return this.innerGW.close(url);
1840
1505
  }
1841
- async metaStore() {
1842
- return this.ebOpts.storeRuntime.makeMetaStore(this);
1506
+ async put(url, body) {
1507
+ await Promise.all(this.slicer(url, body));
1508
+ return import_cement3.Result.Ok(void 0);
1843
1509
  }
1844
- async ready() {
1845
- return this.onceReady.once(async () => {
1846
- const metas = await (await this.metaStore()).load();
1847
- if (this.ebOpts.meta) {
1848
- await this.handleDbMetasFromStore([this.ebOpts.meta]);
1849
- } else if (metas) {
1850
- await this.handleDbMetasFromStore(metas);
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());
1851
1516
  }
1852
- });
1853
- }
1854
- async close() {
1855
- const toClose = await Promise.all([this.carStore(), this.metaStore(), this.fileStore(), this.WALStore()]);
1856
- await Promise.all(toClose.map((store) => store.close()));
1857
- }
1858
- async destroy() {
1859
- const toDestroy = await Promise.all([this.carStore(), this.metaStore(), this.fileStore(), this.WALStore()]);
1860
- await Promise.all(toDestroy.map((store) => store.destroy()));
1861
- }
1862
- // async snapToCar(carCid: AnyLink | string) {
1863
- // await this.ready
1864
- // if (typeof carCid === 'string') {
1865
- // carCid = CID.parse(carCid)
1866
- // }
1867
- // const carHeader = await this.loadCarHeaderFromMeta({ car: carCid, key: this.key || null })
1868
- // this.carLog = [carCid, ...carHeader.cars]
1869
- // await this.getMoreReaders(carHeader.cars)
1870
- // await this._applyCarHeader(carHeader, true)
1871
- // }
1872
- async handleDbMetasFromStore(metas) {
1873
- this.logger.Debug().Any("metas", metas).Msg("handleDbMetasFromStore");
1874
- for (const meta of metas) {
1875
- await this.writeLimit(async () => {
1876
- await this.mergeDbMetaIntoClock(meta);
1877
- });
1517
+ const frag = rfrag.Ok();
1518
+ buffer = buffer || new Uint8Array(frag.len);
1519
+ buffer.set(frag.data, frag.ofs);
1878
1520
  }
1521
+ return import_cement3.Result.Ok(buffer || new Uint8Array(0));
1879
1522
  }
1880
- async mergeDbMetaIntoClock(meta) {
1881
- if (this.isCompacting) {
1882
- throw this.logger.Error().Msg("cannot merge while compacting").AsError();
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());
1883
1528
  }
1884
- if (this.seenMeta.has(meta.cars.toString())) return;
1885
- this.seenMeta.add(meta.cars.toString());
1886
- if (carLogIncludesGroup(this.carLog, meta.cars)) {
1887
- return;
1888
- }
1889
- const carHeader = await this.loadCarHeaderFromMeta(meta);
1890
- carHeader.compact.map((c) => c.toString()).forEach(this.seenCompacted.add, this.seenCompacted);
1891
- await this.getMoreReaders(carHeader.cars.flat());
1892
- this.carLog = [...uniqueCids([meta.cars, ...this.carLog, ...carHeader.cars], this.seenCompacted)];
1893
- await this.ebOpts.applyMeta?.(carHeader.meta);
1894
- }
1895
- // protected async ingestKeyFromMeta(meta: DbMeta): Promise<void> {
1896
- // const { key } = meta;
1897
- // if (key) {
1898
- // await this.setKey(key);
1899
- // }
1900
- // }
1901
- async loadCarHeaderFromMeta({ cars: cids }) {
1902
- const reader = await this.loadCar(cids[0]);
1903
- return await parseCarFile(reader, this.logger);
1904
- }
1905
- // async _getKey(): Promise<string | undefined> {
1906
- // if (this.key) return this.key;
1907
- // // generate a random key
1908
- // if (!this.ebOpts.public) {
1909
- // await this.setKey(toHexString(this.ebOpts.crypto.randomBytes(32)));
1910
- // }
1911
- // return this.key || undefined;
1912
- // }
1913
- async commitFiles(t, done) {
1914
- await this.ready();
1915
- const fstore = await this.fileStore();
1916
- const wstore = await this.WALStore();
1917
- return this.commitQueue.enqueue(() => commitFiles(fstore, wstore, t, done));
1918
1529
  }
1919
- async loadFileCar(cid) {
1920
- return await this.storesLoadCar(cid, await this.fileStore(), this.remoteFileStore);
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());
1535
+ }
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;
1543
+ }
1544
+ await this.innerGW.delete(fragUrl);
1545
+ }
1546
+ return import_cement3.Result.Ok(void 0);
1921
1547
  }
1922
- async commit(t, done, opts = { noLoader: false, compact: false }) {
1923
- await this.ready();
1924
- const fstore = await this.fileStore();
1925
- const params = {
1926
- encoder: (await fstore.keyedCrypto()).codec(),
1927
- carLog: this.carLog,
1928
- carStore: fstore,
1929
- WALStore: await this.WALStore(),
1930
- metaStore: await this.metaStore(),
1931
- threshold: this.ebOpts.threshold
1932
- };
1933
- return this.commitQueue.enqueue(async () => {
1934
- await this.cacheTransaction(t);
1935
- const ret = await commit(params, t, done, opts);
1936
- await this.updateCarLog(ret.cgrp, ret.header, !!opts.compact);
1937
- return ret.cgrp;
1548
+ };
1549
+
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
+ // src/runtime/key-bag.ts
1558
+ var key_bag_exports = {};
1559
+ __export(key_bag_exports, {
1560
+ KeyBag: () => KeyBag,
1561
+ defaultKeyBagOpts: () => defaultKeyBagOpts,
1562
+ getKeyBag: () => getKeyBag,
1563
+ registerKeyBagProviderFactory: () => registerKeyBagProviderFactory
1564
+ });
1565
+ var import_cement6 = require("@adviser/cement");
1566
+ init_utils();
1567
+ var import_base584 = require("multiformats/bases/base58");
1568
+ init_types();
1569
+ var KeyBag = class {
1570
+ constructor(rt) {
1571
+ this.rt = rt;
1572
+ this._warnOnce = new import_cement6.ResolveOnce();
1573
+ this._seq = new import_cement6.ResolveSeq();
1574
+ this.logger = ensureLogger(rt.sthis, "KeyBag", {
1575
+ id: rt.id()
1938
1576
  });
1577
+ this.logger.Debug().Msg("KeyBag created");
1939
1578
  }
1940
- async updateCarLog(cids, fp, compact) {
1941
- if (compact) {
1942
- const previousCompactCid = fp.compact[fp.compact.length - 1];
1943
- fp.compact.map((c) => c.toString()).forEach(this.seenCompacted.add, this.seenCompacted);
1944
- this.carLog = [...uniqueCids([...this.carLog, ...fp.cars, cids], this.seenCompacted)];
1945
- await this.removeCidsForCompact(previousCompactCid[0]).catch((e) => e);
1946
- } else {
1947
- this.carLog.unshift(cids);
1579
+ async subtleKey(key) {
1580
+ const extractable = this.rt.url.getParam("extractKey") === "_deprecated_internal_api";
1581
+ if (extractable) {
1582
+ this._warnOnce.once(
1583
+ () => this.logger.Warn().Msg("extractKey is enabled via _deprecated_internal_api --- handle keys safely!!!")
1584
+ );
1948
1585
  }
1586
+ return await this.rt.crypto.importKey(
1587
+ "raw",
1588
+ // raw or jwk
1589
+ import_base584.base58btc.decode(key),
1590
+ // hexStringToUint8Array(key), // raw data
1591
+ "AES-GCM",
1592
+ extractable,
1593
+ ["encrypt", "decrypt"]
1594
+ );
1949
1595
  }
1950
- async cacheTransaction(t) {
1951
- for await (const block of t.entries()) {
1952
- const sBlock = block.cid.toString();
1953
- if (!this.getBlockCache.has(sBlock)) {
1954
- this.getBlockCache.set(sBlock, block);
1596
+ async ensureKeyFromUrl(url, keyFactory) {
1597
+ const storeKey = url.getParam("storekey" /* STORE_KEY */);
1598
+ if (storeKey === "insecure") {
1599
+ return import_cement6.Result.Ok(url);
1600
+ }
1601
+ if (!storeKey) {
1602
+ const keyName = `@${keyFactory()}@`;
1603
+ const ret = await this.getNamedKey(keyName);
1604
+ if (ret.isErr()) {
1605
+ return ret;
1955
1606
  }
1607
+ const urb = url.build().setParam("storekey" /* STORE_KEY */, keyName);
1608
+ return import_cement6.Result.Ok(urb.URI());
1956
1609
  }
1957
- }
1958
- async cacheCarReader(carCidStr, reader) {
1959
- if (this.processedCars.has(carCidStr)) return;
1960
- this.processedCars.add(carCidStr);
1961
- for await (const block of reader.blocks()) {
1962
- const sBlock = block.cid.toString();
1963
- if (!this.getBlockCache.has(sBlock)) {
1964
- this.getBlockCache.set(sBlock, block);
1610
+ if (storeKey.startsWith("@") && storeKey.endsWith("@")) {
1611
+ const ret = await this.getNamedKey(storeKey);
1612
+ if (ret.isErr()) {
1613
+ return ret;
1965
1614
  }
1966
1615
  }
1616
+ return import_cement6.Result.Ok(url);
1967
1617
  }
1968
- async removeCidsForCompact(cid) {
1969
- const carHeader = await this.loadCarHeaderFromMeta({
1970
- cars: [cid]
1618
+ async toKeyWithFingerPrint(keyStr) {
1619
+ const material = import_base584.base58btc.decode(keyStr);
1620
+ const key = await this.subtleKey(keyStr);
1621
+ const fpr = await this.rt.crypto.digestSHA256(material);
1622
+ return import_cement6.Result.Ok({
1623
+ key,
1624
+ fingerPrint: import_base584.base58btc.encode(new Uint8Array(fpr))
1971
1625
  });
1972
- for (const cids of carHeader.compact) {
1973
- for (const cid2 of cids) {
1974
- await (await this.carStore()).remove(cid2);
1975
- }
1976
- }
1977
1626
  }
1978
- // async flushCars() {
1979
- // await this.ready
1980
- // // for each cid in car log, make a dbMeta
1981
- // for (const cid of this.carLog) {
1982
- // const dbMeta = { car: cid, key: this.key || null } as DbMeta
1983
- // await this.remoteWAL!.enqueue(dbMeta, { public: false })
1984
- // }
1985
- // }
1986
- async *entries(cache2 = true) {
1987
- await this.ready();
1988
- if (cache2) {
1989
- for (const [, block] of this.getBlockCache) {
1990
- yield block;
1627
+ async setNamedKey(name, key) {
1628
+ return this._seq.add(() => this._setNamedKey(name, key));
1629
+ }
1630
+ // avoid deadlock
1631
+ async _setNamedKey(name, key) {
1632
+ const item = {
1633
+ name,
1634
+ key
1635
+ };
1636
+ const bag = await this.rt.getBag();
1637
+ this.logger.Debug().Str("name", name).Msg("setNamedKey");
1638
+ await bag.set(name, item);
1639
+ return await this.toKeyWithFingerPrint(item.key);
1640
+ }
1641
+ async getNamedExtractableKey(name, failIfNotFound = false) {
1642
+ const ret = await this.getNamedKey(name, failIfNotFound);
1643
+ if (ret.isErr()) {
1644
+ return ret;
1645
+ }
1646
+ const named = ret.Ok();
1647
+ return import_cement6.Result.Ok({
1648
+ ...named,
1649
+ extract: async () => {
1650
+ const ext = new Uint8Array(await this.rt.crypto.exportKey("raw", named.key));
1651
+ return {
1652
+ key: ext,
1653
+ keyStr: import_base584.base58btc.encode(ext)
1654
+ };
1991
1655
  }
1992
- } else {
1993
- for (const [, block] of this.getBlockCache) {
1994
- yield block;
1656
+ });
1657
+ }
1658
+ async getNamedKey(name, failIfNotFound = false) {
1659
+ const id = this.rt.sthis.nextId(4).str;
1660
+ return this._seq.add(async () => {
1661
+ const bag = await this.rt.getBag();
1662
+ const named = await bag.get(name);
1663
+ if (named) {
1664
+ const fpr = await this.toKeyWithFingerPrint(named.key);
1665
+ this.logger.Debug().Str("id", id).Str("name", name).Result("fpr", fpr).Msg("fingerPrint getNamedKey");
1666
+ return fpr;
1995
1667
  }
1996
- for (const cids of this.carLog) {
1997
- for (const cid of cids) {
1998
- const reader = await this.loadCar(cid);
1999
- if (!reader) throw this.logger.Error().Ref("cid", cid).Msg("missing car reader").AsError();
2000
- for await (const block of reader.blocks()) {
2001
- const sCid = block.cid.toString();
2002
- if (!this.getBlockCache.has(sCid)) {
2003
- yield block;
2004
- }
2005
- }
2006
- }
1668
+ if (failIfNotFound) {
1669
+ this.logger.Debug().Str("id", id).Str("name", name).Msg("failIfNotFound getNamedKey");
1670
+ return import_cement6.Result.Err(new Error(`Key not found: ${name}`));
2007
1671
  }
2008
- }
1672
+ const ret = await this._setNamedKey(name, import_base584.base58btc.encode(this.rt.crypto.randomBytes(this.rt.keyLength)));
1673
+ this.logger.Debug().Str("id", id).Str("name", name).Result("fpr", ret).Msg("createKey getNamedKey-post");
1674
+ return ret;
1675
+ });
2009
1676
  }
2010
- async getBlock(cid) {
2011
- await this.ready();
2012
- const sCid = cid.toString();
2013
- if (this.getBlockCache.has(sCid)) return this.getBlockCache.get(sCid);
2014
- const getCarCid = async (carCid) => {
2015
- if (this.getBlockCache.has(sCid)) return this.getBlockCache.get(sCid);
2016
- const reader = await this.loadCar(carCid);
2017
- if (!reader) {
2018
- throw this.logger.Error().Ref("cid", carCid).Msg("missing car reader").AsError();
1677
+ };
1678
+ var keyBagProviderFactories = new Map(
1679
+ [
1680
+ {
1681
+ protocol: "file:",
1682
+ factory: async (url, sthis) => {
1683
+ const { KeyBagProviderFile: KeyBagProviderFile2 } = await Promise.resolve().then(() => (init_key_bag_file(), key_bag_file_exports));
1684
+ return new KeyBagProviderFile2(url, sthis);
2019
1685
  }
2020
- await this.cacheCarReader(carCid.toString(), reader).catch(() => {
2021
- return;
2022
- });
2023
- if (this.getBlockCache.has(sCid)) return this.getBlockCache.get(sCid);
2024
- throw this.logger.Error().Str("cid", sCid).Msg("block not in reader").AsError();
2025
- };
2026
- const getCompactCarCids = async (carCid) => {
2027
- const reader = await this.loadCar(carCid);
2028
- if (!reader) {
2029
- throw this.logger.Error().Str("cid", carCid.toString()).Msg("missing car reader").AsError();
1686
+ },
1687
+ {
1688
+ protocol: "indexdb:",
1689
+ factory: async (url, sthis) => {
1690
+ const { KeyBagProviderIndexDB: KeyBagProviderIndexDB2 } = await Promise.resolve().then(() => (init_key_bag_indexdb(), key_bag_indexdb_exports));
1691
+ return new KeyBagProviderIndexDB2(url, sthis);
2030
1692
  }
2031
- const header = await parseCarFile(reader, this.logger);
2032
- const compacts = header.compact;
2033
- let got2;
2034
- const batchSize2 = 5;
2035
- for (let i = 0; i < compacts.length; i += batchSize2) {
2036
- const promises = [];
2037
- for (let j = i; j < Math.min(i + batchSize2, compacts.length); j++) {
2038
- for (const cid2 of compacts[j]) {
2039
- promises.push(getCarCid(cid2));
2040
- }
2041
- }
2042
- try {
2043
- got2 = await Promise.any(promises);
2044
- } catch {
2045
- }
2046
- if (got2) break;
2047
- }
2048
- if (this.getBlockCache.has(sCid)) return this.getBlockCache.get(sCid);
2049
- throw this.logger.Error().Str("cid", sCid).Msg("block not in compact reader").AsError();
2050
- };
2051
- let got;
2052
- const batchSize = 5;
2053
- for (let i = 0; i < this.carLog.length; i += batchSize) {
2054
- const batch = this.carLog.slice(i, i + batchSize);
2055
- const promises = batch.flatMap((slice) => slice.map(getCarCid));
2056
- try {
2057
- got = await Promise.any(promises);
2058
- } catch {
2059
- }
2060
- if (got) break;
2061
1693
  }
2062
- if (!got) {
2063
- try {
2064
- got = await getCompactCarCids(this.carLog[this.carLog.length - 1][0]);
2065
- } catch {
1694
+ ].map((i) => [i.protocol, i])
1695
+ );
1696
+ function registerKeyBagProviderFactory(item) {
1697
+ const protocol = item.protocol.endsWith(":") ? item.protocol : item.protocol + ":";
1698
+ keyBagProviderFactories.set(protocol, {
1699
+ ...item,
1700
+ protocol
1701
+ });
1702
+ }
1703
+ function defaultKeyBagOpts(sthis, kbo) {
1704
+ kbo = kbo || {};
1705
+ if (kbo.keyRuntime) {
1706
+ return kbo.keyRuntime;
1707
+ }
1708
+ const logger = ensureLogger(sthis, "KeyBag");
1709
+ let url;
1710
+ if (kbo.url) {
1711
+ url = import_cement6.URI.from(kbo.url);
1712
+ logger.Debug().Url(url).Msg("from opts");
1713
+ } else {
1714
+ let bagFnameOrUrl = sthis.env.get("FP_KEYBAG_URL");
1715
+ if ((0, import_cement6.runtimeFn)().isBrowser) {
1716
+ url = import_cement6.URI.from(bagFnameOrUrl || "indexdb://fp-keybag");
1717
+ } else {
1718
+ if (!bagFnameOrUrl) {
1719
+ const home = sthis.env.get("HOME");
1720
+ bagFnameOrUrl = `${home}/.fireproof/keybag`;
1721
+ url = import_cement6.URI.from(`file://${bagFnameOrUrl}`);
1722
+ } else {
1723
+ url = import_cement6.URI.from(bagFnameOrUrl);
2066
1724
  }
2067
1725
  }
2068
- return got;
1726
+ logger.Debug().Url(url).Msg("from env");
2069
1727
  }
2070
- async loadCar(cid) {
2071
- if (!this.carStore) {
2072
- throw this.logger.Error().Msg("car store not initialized").AsError();
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();
1750
+ }
1751
+ if (url.hasParam("masterkey")) {
1752
+ throw logger.Error().Url(url).Msg("masterkey is not supported").AsError();
1753
+ }
1754
+ return {
1755
+ url,
1756
+ crypto: kbo.crypto || (0, import_cement6.toCryptoRuntime)({}),
1757
+ sthis,
1758
+ logger,
1759
+ keyLength: kbo.keyLength || 16,
1760
+ getBag: keyProviderFactory,
1761
+ id: () => {
1762
+ return url.toString();
2073
1763
  }
2074
- const loaded = await this.storesLoadCar(cid, await this.carStore(), this.remoteCarStore);
2075
- return loaded;
1764
+ };
1765
+ }
1766
+ var _keyBags = new import_cement6.KeyedResolvOnce();
1767
+ async function getKeyBag(sthis, kbo = {}) {
1768
+ await sthis.start();
1769
+ const rt = defaultKeyBagOpts(sthis, kbo);
1770
+ return _keyBags.get(rt.id()).once(async () => new KeyBag(rt));
1771
+ }
1772
+
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 [];
2076
1779
  }
2077
- async makeDecoderAndCarReader(cid, local, remote) {
2078
- const cidsString = cid.toString();
2079
- let loadedCar = void 0;
2080
- let activeStore = local;
2081
- try {
2082
- this.logger.Debug().Str("cid", cidsString).Msg("loading car");
2083
- loadedCar = await local.load(cid);
2084
- this.logger.Debug().Bool("loadedCar", loadedCar).Msg("loaded");
2085
- } catch (e) {
2086
- if (remote) {
2087
- const remoteCar = await remote.load(cid);
2088
- if (remoteCar) {
2089
- this.logger.Debug().Ref("cid", remoteCar.cid).Msg("saving remote car locally");
2090
- await local.save(remoteCar);
2091
- loadedCar = remoteCar;
2092
- activeStore = remote;
1780
+ if (!crdtEntries.map) {
1781
+ sthis.logger.Debug().Str("crdtEntries", JSON.stringify(crdtEntries)).Msg("No data in CRDT entries");
1782
+ return [];
1783
+ }
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
+ );
1795
+ }
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();
2093
1809
  }
2094
- } else {
2095
- this.logger.Error().Str("cid", cidsString).Err(e).Msg("loading car");
2096
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);
2097
1813
  }
2098
- if (!loadedCar) {
2099
- throw this.logger.Error().Url(local.url()).Str("cid", cidsString).Msg("missing car files").AsError();
2100
- }
2101
- const bytes = await decode({ bytes: loadedCar.bytes, hasher: import_sha23.sha256, codec: (await activeStore.keyedCrypto()).codec() });
2102
- const rawReader = await import_car.CarReader.fromBytes(bytes.value);
2103
- const readerP = Promise.resolve(rawReader);
2104
- const cachedReaderP = readerP.then(async (reader) => {
2105
- await this.cacheCarReader(cidsString, reader).catch((e) => {
2106
- this.logger.Error().Err(e).Str("cid", cidsString).Msg("error caching car reader");
2107
- return;
2108
- });
2109
- return reader;
2110
- });
2111
- this.carReaders.set(cidsString, cachedReaderP);
2112
- return readerP;
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);
2113
1819
  }
2114
- //What if instead it returns an Array of CarHeader
2115
- async storesLoadCar(cid, local, remote) {
2116
- const cidsString = cid.toString();
2117
- let dacr = this.carReaders.get(cidsString);
2118
- if (!dacr) {
2119
- dacr = this.makeDecoderAndCarReader(cid, local, remote);
2120
- this.carReaders.set(cidsString, dacr);
1820
+ }
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();
2121
1830
  }
2122
- return dacr;
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);
2123
1843
  }
2124
- async getMoreReaders(cids) {
2125
- const limit = (0, import_p_limit.default)(5);
2126
- const missing = cids.filter((cid) => !this.carReaders.has(cid.toString()));
2127
- await Promise.all(missing.map((cid) => limit(() => this.loadCar(cid))));
1844
+ }
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);
2128
1850
  }
2129
- };
1851
+ storeKeyName.push("data");
1852
+ return `@${storeKeyName.join(":")}@`;
1853
+ }
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;
1862
+ }
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
+ };
1871
+ });
1872
+ return sthis.txt.encode(JSON.stringify(crdtEntries));
1873
+ }
2130
1874
 
2131
- // src/runtime/keyed-crypto.ts
2132
- var keyed_crypto_exports = {};
2133
- __export(keyed_crypto_exports, {
2134
- BlockIvKeyIdCodec: () => BlockIvKeyIdCodec,
2135
- keyedCryptoFactory: () => keyedCryptoFactory
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
2136
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
+ }
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");
1932
+ }
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
+ });
1953
+ }
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();
1966
+ }
1967
+ return fpvalue.fp;
1968
+ }
1969
+
1970
+ // src/blockstore/transaction.ts
1971
+ var import_block3 = require("@web3-storage/pail/block");
1972
+ init_types();
1973
+ var import_cement8 = require("@adviser/cement");
2137
1974
  init_utils();
2138
- var import_base583 = require("multiformats/bases/base58");
2139
- var import_sha24 = require("multiformats/hashes/sha2");
2140
- var CBOR = __toESM(require("cborg"), 1);
2141
- var generateIV = {
2142
- random: {
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));
1985
+ }
1986
+ async superGet(cid) {
1987
+ return super.get(cid);
1988
+ }
1989
+ };
1990
+ function defaultedBlockstoreRuntime(sthis, opts, component, ctx) {
1991
+ const logger = ensureLogger(sthis, component, ctx);
1992
+ return {
2143
1993
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
2144
- calc: async (ko, crypto, data) => {
2145
- return crypto.randomBytes(ko.ivLength);
1994
+ applyMeta: (meta, snap) => {
1995
+ return Promise.resolve();
2146
1996
  },
2147
1997
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
2148
- verify: async (ko, crypto, iv, data) => {
2149
- return true;
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
+ };
2014
+ }
2015
+ function blockstoreFactory(sthis, opts) {
2016
+ return new EncryptedBlockstore(sthis, opts);
2017
+ }
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");
2025
+ this.logger = this.ebOpts.logger;
2026
+ }
2027
+ // readonly name?: string;
2028
+ // ready: Promise<void>;
2029
+ ready() {
2030
+ return Promise.resolve();
2031
+ }
2032
+ async close() {
2033
+ }
2034
+ async destroy() {
2035
+ }
2036
+ async compact() {
2037
+ }
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;
2150
2043
  }
2151
- },
2152
- hash: {
2153
- calc: async (ko, crypto, data) => {
2154
- const hash = await import_sha24.sha256.digest(data);
2155
- const hashBytes = new Uint8Array(hash.bytes);
2156
- const hashArray = new Uint8Array(ko.ivLength);
2157
- for (let i = 0; i < hashBytes.length; i++) {
2158
- hashArray[i % ko.ivLength] ^= hashBytes[i];
2044
+ }
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();
2048
+ }
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 };
2058
+ }
2059
+ openTransaction(opts = { add: true, noLoader: false }) {
2060
+ return new CarTransaction(this, opts);
2061
+ }
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);
2067
+ }
2068
+ if (cars) {
2069
+ this.transactions.delete(t);
2070
+ return { meta: done, cars, t };
2071
+ }
2072
+ throw this.logger.Error().Msg("failed to commit car files").AsError();
2073
+ }
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;
2159
2081
  }
2160
- return hashArray;
2161
- },
2162
- verify: async function(ko, crypto, iv, data) {
2163
- return ko.url.getParam("ivverify") !== "disable" && UInt8ArrayEqual(iv, await this.calc(ko, crypto, data));
2164
2082
  }
2165
2083
  }
2166
2084
  };
2167
- function getGenerateIVFn(url, opts) {
2168
- const ivhash = opts.ivCalc || url.getParam("ivhash") || "hash";
2169
- return generateIV[ivhash] || generateIV["hash"];
2170
- }
2171
- var BlockIvKeyIdCodec = class {
2172
- constructor(ko, iv, opts) {
2173
- this.code = 3147065;
2174
- this.name = "Fireproof@encrypted-block:aes-gcm";
2175
- this.ko = ko;
2176
- this.iv = iv;
2177
- this.opts = opts || {};
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
2091
+ });
2092
+ this.loader = new Loader(sthis, ebOpts);
2178
2093
  }
2179
- async encode(data) {
2180
- const calcIv = this.iv || await getGenerateIVFn(this.ko.url, this.opts).calc(this.ko, this.ko.crypto, data);
2181
- const { iv } = this.ko.algo(calcIv);
2182
- const fprt = await this.ko.fingerPrint();
2183
- const keyId = import_base583.base58btc.decode(fprt);
2184
- this.ko.logger.Debug().Str("fp", fprt).Msg("encode");
2185
- return CBOR.encode({
2186
- iv,
2187
- keyId,
2188
- data: await this.ko._encrypt({ iv, bytes: data })
2094
+ ready() {
2095
+ return this.loader.ready();
2096
+ }
2097
+ close() {
2098
+ return this.loader.close();
2099
+ }
2100
+ destroy() {
2101
+ return this.loader.destroy();
2102
+ }
2103
+ async get(cid) {
2104
+ const got = await super.get(cid);
2105
+ if (got) return got;
2106
+ if (!this.loader) {
2107
+ return;
2108
+ }
2109
+ return falsyToUndef(await this.loader.getBlock(cid));
2110
+ }
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);
2119
+ }
2120
+ if (cars) {
2121
+ this.transactions.delete(t);
2122
+ return { meta: done, cars, t };
2123
+ }
2124
+ throw this.logger.Error().Msg("failed to commit car files").AsError();
2125
+ }
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;
2136
+ }
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
2189
2149
  });
2150
+ this.compacting = false;
2190
2151
  }
2191
- async decode(abytes) {
2192
- let bytes;
2193
- if (abytes instanceof Uint8Array) {
2194
- bytes = abytes;
2195
- } else {
2196
- bytes = new Uint8Array(abytes);
2152
+ async defaultCompact(blocks, logger) {
2153
+ if (!this.loader) {
2154
+ throw logger.Error().Msg("no loader").AsError();
2197
2155
  }
2198
- const { iv, keyId, data } = CBOR.decode(bytes);
2199
- const fprt = await this.ko.fingerPrint();
2200
- this.ko.logger.Debug().Str("fp", import_base583.base58btc.encode(keyId)).Msg("decode");
2201
- if (import_base583.base58btc.encode(keyId) !== fprt) {
2202
- throw this.ko.logger.Error().Str("fp", fprt).Str("keyId", import_base583.base58btc.encode(keyId)).Msg("keyId mismatch").AsError();
2156
+ if (!this.lastTxMeta) {
2157
+ throw logger.Error().Msg("no lastTxMeta").AsError();
2203
2158
  }
2204
- const result = await this.ko._decrypt({ iv, bytes: data });
2205
- if (!this.opts?.noIVVerify && !await getGenerateIVFn(this.ko.url, this.opts).verify(this.ko, this.ko.crypto, iv, result)) {
2206
- throw this.ko.logger.Error().Msg("iv missmatch").AsError();
2159
+ for await (const blk of this.loader.entries(false)) {
2160
+ blocks.loggedBlocks.putSync(blk.cid, blk.bytes);
2161
+ }
2162
+ for (const t of this.transactions) {
2163
+ for await (const blk of t.entries()) {
2164
+ blocks.loggedBlocks.putSync(blk.cid, blk.bytes);
2165
+ }
2166
+ }
2167
+ return this.lastTxMeta;
2168
+ }
2169
+ async *entries() {
2170
+ for await (const blk of this.loader.entries()) {
2171
+ yield blk;
2207
2172
  }
2208
- return result;
2209
2173
  }
2210
2174
  };
2211
- var keyedCrypto = class {
2212
- constructor(url, key, cyopt, sthis) {
2213
- this.ivLength = 12;
2214
- this.isEncrypting = true;
2215
- this.logger = ensureLogger(sthis, "keyedCrypto");
2216
- this.crypto = cyopt;
2217
- this.key = key;
2218
- this.url = url;
2175
+ var CompactionFetcher = class {
2176
+ constructor(blocks) {
2177
+ this.blockstore = blocks;
2178
+ this.loggedBlocks = new CarTransaction(blocks);
2219
2179
  }
2220
- fingerPrint() {
2221
- return Promise.resolve(this.key.fingerPrint);
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);
2222
2184
  }
2223
- codec(iv, opts) {
2224
- return new BlockIvKeyIdCodec(this, iv, opts);
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 });
2225
2197
  }
2226
- algo(iv) {
2227
- return {
2228
- name: "AES-GCM",
2229
- iv: iv || this.crypto.randomBytes(this.ivLength),
2230
- tagLength: 128
2231
- };
2198
+ const buffer = new Uint8Array(size);
2199
+ const writer = CBW.createWriter(buffer, { headerSize });
2200
+ for (const r of roots) {
2201
+ writer.addRoot(r);
2232
2202
  }
2233
- async _decrypt(data) {
2234
- this.logger.Debug().Len(data.bytes, "bytes").Len(data.iv, "iv").Str("fp", this.key.fingerPrint).Msg("decrypting");
2235
- return new Uint8Array(await this.crypto.decrypt(this.algo(data.iv), this.key.key, data.bytes));
2203
+ for (const { cid, bytes } of t.entries()) {
2204
+ writer.write({ cid, bytes });
2236
2205
  }
2237
- async _encrypt(data) {
2238
- this.logger.Debug().Len(data.bytes).Str("fp", this.key.fingerPrint).Msg("encrypting");
2239
- const a = this.algo(data.iv);
2240
- return new Uint8Array(await this.crypto.encrypt(a, this.key.key, data.bytes));
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);
2241
2225
  }
2242
- };
2243
- var nullCodec = class {
2244
- constructor() {
2245
- this.code = 0;
2246
- this.name = "Fireproof@unencrypted-block";
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
+ }
2247
2234
  }
2248
- encode(data) {
2249
- return data;
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);
2250
2260
  }
2251
- decode(data) {
2252
- return data;
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
+ }
2284
+ }
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;
2301
+ }
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();
2309
+ }
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
+ }
2253
2335
  }
2254
2336
  };
2255
- var noCrypto = class {
2256
- constructor(url, cyrt, sthis) {
2257
- this.ivLength = 0;
2258
- this.code = 0;
2259
- this.name = "Fireproof@unencrypted-block";
2260
- this.isEncrypting = false;
2261
- this._fingerPrint = "noCrypto:" + Math.random();
2262
- this.logger = ensureLogger(sthis, "noCrypto");
2263
- this.crypto = cyrt;
2264
- this.url = url;
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);
2349
+ }
2350
+ return [...byString.values()];
2351
+ }
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
+ });
2265
2381
  }
2266
- fingerPrint() {
2267
- return Promise.resolve(this._fingerPrint);
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
+ );
2268
2390
  }
2269
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2270
- codec(iv) {
2271
- return new nullCodec();
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()
2397
+ })
2398
+ );
2272
2399
  }
2273
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2274
- algo(iv) {
2275
- return {
2276
- name: "noCrypto",
2277
- iv: new Uint8Array(),
2278
- tagLength: 0
2279
- };
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
+ );
2280
2408
  }
2281
- _decrypt() {
2282
- throw this.logger.Error().Msg("noCrypto.decrypt not implemented").AsError();
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
+ })
2416
+ );
2283
2417
  }
2284
- _encrypt() {
2285
- throw this.logger.Error().Msg("noCrypto.decrypt not implemented").AsError();
2418
+ keyBag() {
2419
+ return getKeyBag(this.sthis, this.ebOpts.keyBag);
2286
2420
  }
2287
- };
2288
- async function keyedCryptoFactory(url, kb, sthis) {
2289
- const storekey = url.getParam("storekey");
2290
- if (storekey && storekey !== "insecure") {
2291
- let rkey = await kb.getNamedKey(storekey, true);
2292
- if (rkey.isErr()) {
2293
- try {
2294
- rkey = await kb.toKeyWithFingerPrint(storekey);
2295
- } catch (e) {
2296
- throw sthis.logger.Error().Err(e).Str("keybag", kb.rt.id()).Str("name", storekey).Msg("getNamedKey failed").AsError();
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);
2297
2428
  }
2298
- }
2299
- return new keyedCrypto(url, rkey.Ok(), kb.rt.crypto, sthis);
2429
+ });
2300
2430
  }
2301
- return new noCrypto(url, kb.rt.crypto, sthis);
2302
- }
2303
-
2304
- // src/blockstore/fragment-gateway.ts
2305
- var import_cement8 = require("@adviser/cement");
2306
- var import_base584 = require("multiformats/bases/base58");
2307
- var import_cborg = require("cborg");
2308
- init_utils();
2309
- function getFragSize(url) {
2310
- const fragSize = url.getParam("fragSize");
2311
- let ret = 0;
2312
- if (fragSize) {
2313
- ret = parseInt(fragSize);
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()));
2314
2435
  }
2315
- if (isNaN(ret) || ret <= 0) {
2316
- ret = 0;
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()));
2317
2439
  }
2318
- return ret;
2319
- }
2320
- async function getFrags(url, innerGW, headerSize, logger) {
2321
- const fragSize = getFragSize(url);
2322
- if (!fragSize) {
2323
- const res = await innerGW.get(url);
2324
- if (res.isErr()) {
2325
- return [res];
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
+ });
2326
2456
  }
2327
- const data = res.unwrap();
2328
- return [
2329
- import_cement8.Result.Ok({
2330
- fid: new Uint8Array(0),
2331
- ofs: 0,
2332
- len: data.length,
2333
- data
2334
- })
2335
- ];
2336
- }
2337
- const firstRaw = await innerGW.get(url.build().setParam("ofs", "0").URI());
2338
- if (firstRaw.isErr()) {
2339
- return [firstRaw];
2340
- }
2341
- const firstFragment = (0, import_cborg.decode)(firstRaw.unwrap());
2342
- const blockSize = firstFragment.data.length;
2343
- const ops = [Promise.resolve(import_cement8.Result.Ok(firstFragment))];
2344
- const fidStr = import_base584.base58btc.encode(firstFragment.fid);
2345
- const fragUrl = url.build().setParam("fid", fidStr).setParam("len", firstFragment.len.toString()).setParam("headerSize", headerSize.toString());
2346
- for (let ofs = blockSize; ofs < firstFragment.len; ofs += blockSize) {
2347
- ops.push(
2348
- (async (furl, ofs2) => {
2349
- const raw2 = await innerGW.get(furl);
2350
- if (raw2.isErr()) {
2351
- return raw2;
2352
- }
2353
- const fragment = (0, import_cborg.decode)(raw2.unwrap());
2354
- if (import_base584.base58btc.encode(fragment.fid) !== fidStr) {
2355
- return import_cement8.Result.Err(logger.Error().Msg("Fragment fid mismatch").AsError());
2356
- }
2357
- if (fragment.ofs !== ofs2) {
2358
- return import_cement8.Result.Err(logger.Error().Uint64("ofs", ofs2).Msg("Fragment ofs mismatch").AsError());
2359
- }
2360
- return import_cement8.Result.Ok(fragment);
2361
- })(fragUrl.setParam("ofs", ofs.toString()).URI(), ofs)
2362
- );
2363
- }
2364
- return Promise.all(ops);
2365
- }
2366
- var FragmentGateway = class {
2367
- constructor(sthis, innerGW) {
2368
- this.fidLength = 4;
2369
- this.headerSize = 32;
2370
- this.sthis = ensureSuperLog(sthis, "FragmentGateway");
2371
- this.logger = this.sthis.logger;
2372
- this.innerGW = innerGW;
2373
2457
  }
2374
- slicer(url, body) {
2375
- const fragSize = getFragSize(url);
2376
- if (!fragSize) {
2377
- return [this.innerGW.put(url, body)];
2378
- }
2379
- const blocksize = fragSize - this.headerSize;
2380
- if (blocksize <= 0) {
2381
- throw this.logger.Error().Uint64("fragSize", fragSize).Uint64("headerSize", this.headerSize).Msg("Fragment size is too small").AsError();
2458
+ async mergeDbMetaIntoClock(meta) {
2459
+ if (this.isCompacting) {
2460
+ throw this.logger.Error().Msg("cannot merge while compacting").AsError();
2382
2461
  }
2383
- const ops = [];
2384
- const fid = this.sthis.nextId(this.fidLength);
2385
- const fragUrl = url.build().setParam("fid", fid.str).setParam("len", body.length.toString()).setParam("headerSize", this.headerSize.toString());
2386
- for (let ofs = 0; ofs < body.length; ofs += blocksize) {
2387
- const block = (0, import_cborg.encode)({
2388
- fid: fid.bin,
2389
- ofs,
2390
- len: body.length,
2391
- data: body.slice(ofs, ofs + blocksize)
2392
- });
2393
- if (block.length > fragSize) {
2394
- throw this.logger.Error().Uint64("block", block.length).Uint64("fragSize", fragSize).Msg("Block size to big").AsError();
2395
- }
2396
- ops.push(this.innerGW.put(fragUrl.setParam("ofs", ofs.toString()).URI(), block));
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;
2397
2466
  }
2398
- return ops;
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);
2399
2472
  }
2400
- buildUrl(baseUrl, key) {
2401
- return this.innerGW.buildUrl(baseUrl, key);
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);
2402
2482
  }
2403
- async destroy(iurl) {
2404
- return this.innerGW.destroy(iurl);
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));
2405
2496
  }
2406
- async start(url) {
2407
- this.headerSize = (0, import_cborg.encode)({
2408
- fid: this.sthis.nextId(this.fidLength).bin,
2409
- ofs: 1024 * 1024,
2410
- // 32bit
2411
- len: 16 * 1024 * 1024,
2412
- // 32bit
2413
- data: new Uint8Array(1024)
2414
- }).length - 1024;
2415
- return this.innerGW.start(url);
2497
+ async loadFileCar(cid) {
2498
+ return await this.storesLoadCar(cid, await this.fileStore(), this.remoteFileStore);
2416
2499
  }
2417
- async close(url) {
2418
- return this.innerGW.close(url);
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
2517
  }
2420
- async put(url, body) {
2421
- await Promise.all(this.slicer(url, body));
2422
- return import_cement8.Result.Ok(void 0);
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
+ }
2423
2527
  }
2424
- async get(url) {
2425
- const rfrags = await getFrags(url, this.innerGW, this.headerSize, this.logger);
2426
- let buffer = void 0;
2427
- for (const rfrag of rfrags) {
2428
- if (rfrag.isErr()) {
2429
- return import_cement8.Result.Err(rfrag.Err());
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
+ }
2535
+ }
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
+ }
2545
+ }
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);
2430
2553
  }
2431
- const frag = rfrag.Ok();
2432
- buffer = buffer || new Uint8Array(frag.len);
2433
- buffer.set(frag.data, frag.ofs);
2434
2554
  }
2435
- return import_cement8.Result.Ok(buffer || new Uint8Array(0));
2436
2555
  }
2437
- async subscribe(url, callback) {
2438
- if (this.innerGW.subscribe) {
2439
- return this.innerGW.subscribe(url, callback);
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
+ }
2440
2570
  } else {
2441
- return import_cement8.Result.Err(this.logger.Error().Url(url).Msg("subscribe not supported").AsError());
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
+ }
2442
2586
  }
2443
2587
  }
2444
- async delete(url) {
2445
- const rfrags = await getFrags(url, this.innerGW, this.headerSize, this.logger);
2446
- for (const rfrag of rfrags) {
2447
- if (rfrag.isErr()) {
2448
- return import_cement8.Result.Err(rfrag.Err());
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();
2449
2597
  }
2450
- const frag = rfrag.Ok();
2451
- const fidStr = import_base584.base58btc.encode(frag.fid);
2452
- const fragUrl = url.build().setParam("fid", fidStr).setParam("len", frag.len.toString()).setParam("headerSize", this.headerSize.toString()).URI();
2453
- await this.innerGW.delete(fragUrl);
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;
2454
2639
  }
2455
- return import_cement8.Result.Ok(void 0);
2456
- }
2457
- };
2458
-
2459
- // src/blockstore/meta-key-helper.ts
2460
- var import_dag_json = require("@ipld/dag-json");
2461
- var import_clock = require("@web3-storage/pail/clock");
2462
- var import_multiformats2 = require("multiformats");
2463
- var import_base64 = require("multiformats/bases/base64");
2464
- var import_cement9 = require("@adviser/cement");
2465
- async function decodeGatewayMetaBytesToDbMeta(sthis, byteHeads) {
2466
- const crdtEntries = JSON.parse(sthis.txt.decode(byteHeads));
2467
- if (!crdtEntries.length) {
2468
- sthis.logger.Debug().Str("byteHeads", new TextDecoder().decode(byteHeads)).Msg("No CRDT entries found");
2469
- return [];
2640
+ if (!got) {
2641
+ try {
2642
+ got = await getCompactCarCids(this.carLog[this.carLog.length - 1][0]);
2643
+ } catch {
2644
+ }
2645
+ }
2646
+ return got;
2470
2647
  }
2471
- if (!crdtEntries.map) {
2472
- sthis.logger.Debug().Str("crdtEntries", JSON.stringify(crdtEntries)).Msg("No data in CRDT entries");
2473
- return [];
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;
2474
2654
  }
2475
- return Promise.all(
2476
- crdtEntries.map(async (crdtEntry) => {
2477
- const eventBlock = await (0, import_clock.decodeEventBlock)(import_base64.base64pad.decode(crdtEntry.data));
2478
- const dbMeta = (0, import_dag_json.parse)(sthis.txt.decode(eventBlock.value.data.dbMeta));
2479
- return {
2480
- eventCid: eventBlock.cid,
2481
- parents: crdtEntry.parents,
2482
- dbMeta
2483
- };
2484
- })
2485
- );
2486
- }
2487
- async function setCryptoKeyFromGatewayMetaPayload(uri, sthis, data) {
2488
- try {
2489
- sthis.logger.Debug().Str("uri", uri.toString()).Msg("Setting crypto key from gateway meta payload");
2490
- const keyInfo = await decodeGatewayMetaBytesToDbMeta(sthis, data);
2491
- if (keyInfo.length) {
2492
- const dbMeta = keyInfo[0].dbMeta;
2493
- if (dbMeta.key) {
2494
- const kb = await getKeyBag(sthis);
2495
- const keyName = getStoreKeyName(uri);
2496
- const res = await kb.setNamedKey(keyName, dbMeta.key);
2497
- if (res.isErr()) {
2498
- sthis.logger.Debug().Str("keyName", keyName).Str("dbMeta.key", dbMeta.key).Msg("Failed to set named key");
2499
- throw res.Err();
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;
2500
2671
  }
2672
+ } else {
2673
+ this.logger.Error().Str("cid", cidsString).Err(e).Msg("loading car");
2501
2674
  }
2502
- sthis.logger.Debug().Str("dbMeta.key", dbMeta.key).Str("uri", uri.toString()).Msg("Set crypto key from gateway meta payload");
2503
- return import_cement9.Result.Ok(dbMeta);
2504
2675
  }
2505
- sthis.logger.Debug().Str("data", new TextDecoder().decode(data)).Msg("No crypto in gateway meta payload");
2506
- return import_cement9.Result.Ok(void 0);
2507
- } catch (error) {
2508
- sthis.logger.Debug().Err(error).Msg("Failed to set crypto key from gateway meta payload");
2509
- return import_cement9.Result.Err(error);
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;
2510
2691
  }
2511
- }
2512
- async function addCryptoKeyToGatewayMetaPayload(uri, sthis, body) {
2513
- try {
2514
- sthis.logger.Debug().Str("uri", uri.toString()).Msg("Adding crypto key to gateway meta payload");
2515
- const keyName = getStoreKeyName(uri);
2516
- const kb = await getKeyBag(sthis);
2517
- const res = await kb.getNamedExtractableKey(keyName, true);
2518
- if (res.isErr()) {
2519
- sthis.logger.Error().Str("keyName", keyName).Msg("Failed to get named extractable key");
2520
- throw res.Err();
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);
2521
2699
  }
2522
- const keyData = await res.Ok().extract();
2523
- const dbMetas = await decodeGatewayMetaBytesToDbMeta(sthis, body);
2524
- const { dbMeta, parents } = dbMetas[0];
2525
- const parentLinks = parents.map((p) => import_multiformats2.CID.parse(p));
2526
- dbMeta.key = keyData.keyStr;
2527
- const events = await Promise.all([dbMeta].map((dbMeta2) => createDbMetaEventBlock(sthis, dbMeta2, parentLinks)));
2528
- const encoded = await encodeEventsWithParents(sthis, events, parentLinks);
2529
- sthis.logger.Debug().Str("uri", uri.toString()).Msg("Added crypto key to gateway meta payload");
2530
- return import_cement9.Result.Ok(encoded);
2531
- } catch (error) {
2532
- sthis.logger.Error().Err(error).Msg("Failed to add crypto key to gateway meta payload");
2533
- return import_cement9.Result.Err(error);
2700
+ return dacr;
2534
2701
  }
2535
- }
2536
- function getStoreKeyName(url) {
2537
- const storeKeyName = [url.getParam("localName") || url.getParam("name")];
2538
- const idx = url.getParam("index");
2539
- if (idx) {
2540
- storeKeyName.push(idx);
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))));
2541
2706
  }
2542
- storeKeyName.push("data");
2543
- return `@${storeKeyName.join(":")}@`;
2544
- }
2545
- async function createDbMetaEventBlock(sthis, dbMeta, parents) {
2546
- const event = await import_clock.EventBlock.create(
2547
- {
2548
- dbMeta: sthis.txt.encode((0, import_dag_json.format)(dbMeta))
2549
- },
2550
- parents
2551
- );
2552
- return event;
2553
- }
2554
- async function encodeEventsWithParents(sthis, events, parents) {
2555
- const crdtEntries = events.map((event) => {
2556
- const base64String = import_base64.base64pad.encode(event.bytes);
2557
- return {
2558
- cid: event.cid.toString(),
2559
- data: base64String,
2560
- parents: parents.map((p) => p.toString())
2561
- };
2562
- });
2563
- return sthis.txt.encode(JSON.stringify(crdtEntries));
2564
- }
2707
+ };
2565
2708
 
2566
2709
  // src/blockstore/store.ts
2567
2710
  function guardVersion(url) {
@@ -2571,16 +2714,21 @@ function guardVersion(url) {
2571
2714
  return import_cement10.Result.Ok(url);
2572
2715
  }
2573
2716
  var BaseStoreImpl = class {
2574
- constructor(name, url, opts, sthis, logger) {
2717
+ constructor(sthis, url, opts, logger) {
2575
2718
  this._onStarted = [];
2576
2719
  this._onClosed = [];
2577
- this.name = name;
2578
2720
  this._url = url;
2579
2721
  this.keybag = opts.keybag;
2722
+ this.loader = opts.loader;
2580
2723
  this.sthis = sthis;
2581
- this.logger = logger.With().Ref("url", () => this._url.toString()).Str("name", name).Logger();
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;
2582
2731
  this.gateway = new FragmentGateway(this.sthis, opts.gateway);
2583
- this.loader = opts.loader;
2584
2732
  }
2585
2733
  url() {
2586
2734
  return this._url;
@@ -2595,20 +2743,20 @@ var BaseStoreImpl = class {
2595
2743
  return;
2596
2744
  }
2597
2745
  async keyedCrypto() {
2598
- return keyedCryptoFactory(this._url, await this.keybag(), this.sthis);
2746
+ return keyedCryptoFactory(this._url, this.keybag, this.sthis);
2599
2747
  }
2600
2748
  async start() {
2601
2749
  this.logger.Debug().Str("storeType", this.storeType).Msg("starting-gateway-pre");
2602
- this._url = this._url.build().setParam("store", this.storeType).URI();
2750
+ this._url = this._url.build().setParam("store" /* STORE */, this.storeType).URI();
2603
2751
  const res = await this.gateway.start(this._url);
2604
2752
  if (res.isErr()) {
2605
2753
  this.logger.Error().Result("gw-start", res).Msg("started-gateway");
2606
2754
  return res;
2607
2755
  }
2608
2756
  this._url = res.Ok();
2609
- const kb = await this.keybag();
2757
+ const kb = await this.keybag;
2610
2758
  const skRes = await kb.ensureKeyFromUrl(this._url, () => {
2611
- const idx = this._url.getParam("index");
2759
+ const idx = this._url.getParam("index" /* INDEX */);
2612
2760
  const storeKeyName = [this.name];
2613
2761
  if (idx) {
2614
2762
  storeKeyName.push(idx);
@@ -2641,8 +2789,8 @@ var BaseStoreImpl = class {
2641
2789
  };
2642
2790
  var MetaStoreImpl = class extends BaseStoreImpl {
2643
2791
  // remote: boolean;
2644
- constructor(sthis, name, url, opts) {
2645
- super(name, url, { ...opts }, sthis, ensureLogger(sthis, "MetaStoreImpl"));
2792
+ constructor(sthis, url, opts) {
2793
+ super(sthis, url, { ...opts }, ensureLogger(sthis, "MetaStoreImpl"));
2646
2794
  this.storeType = "meta";
2647
2795
  this.subscribers = /* @__PURE__ */ new Map();
2648
2796
  this.parents = [];
@@ -2713,13 +2861,21 @@ var MetaStoreImpl = class extends BaseStoreImpl {
2713
2861
  return import_cement10.Result.Ok(void 0);
2714
2862
  }
2715
2863
  async destroy() {
2864
+ this.logger.Debug().Msg("destroy");
2716
2865
  return this.gateway.destroy(this.url());
2717
2866
  }
2718
2867
  };
2719
2868
  var DataStoreImpl = class extends BaseStoreImpl {
2720
2869
  // readonly tag: string = "car-base";
2721
- constructor(sthis, name, url, opts) {
2722
- super(name, url, { ...opts }, sthis, ensureLogger(sthis, "DataStoreImpl"));
2870
+ constructor(sthis, url, opts) {
2871
+ super(
2872
+ sthis,
2873
+ url,
2874
+ {
2875
+ ...opts
2876
+ },
2877
+ ensureLogger(sthis, "DataStoreImpl")
2878
+ );
2723
2879
  this.storeType = "data";
2724
2880
  }
2725
2881
  async load(cid) {
@@ -2760,23 +2916,32 @@ var DataStoreImpl = class extends BaseStoreImpl {
2760
2916
  return import_cement10.Result.Ok(void 0);
2761
2917
  }
2762
2918
  destroy() {
2919
+ this.logger.Debug().Msg("destroy");
2763
2920
  return this.gateway.destroy(this.url());
2764
2921
  }
2765
2922
  };
2766
2923
  var WALStoreImpl = class extends BaseStoreImpl {
2767
- constructor(loader, url, opts) {
2768
- super(loader.name, url, { ...opts }, loader.sthis, ensureLogger(loader.sthis, "WALStoreImpl"));
2924
+ constructor(sthis, url, opts) {
2925
+ super(
2926
+ sthis,
2927
+ url,
2928
+ {
2929
+ ...opts
2930
+ },
2931
+ ensureLogger(sthis, "WALStoreImpl")
2932
+ );
2769
2933
  this.storeType = "wal";
2934
+ // readonly tag: string = "rwal-base";
2935
+ // readonly loader: Loadable;
2770
2936
  this._ready = new import_cement10.ResolveOnce();
2771
2937
  this.walState = { operations: [], noLoaderOps: [], fileOperations: [] };
2772
2938
  this.processing = void 0;
2773
2939
  this.processQueue = new CommitQueue();
2774
- this.loader = loader;
2775
2940
  }
2776
2941
  async ready() {
2777
2942
  return this._ready.once(async () => {
2778
2943
  const walState = await this.load().catch((e) => {
2779
- this.logger.Error().Any("error", e).Msg("error loading wal");
2944
+ this.logger.Error().Err(e).Msg("error loading wal");
2780
2945
  return void 0;
2781
2946
  });
2782
2947
  if (!walState) {
@@ -2809,7 +2974,7 @@ var WALStoreImpl = class extends BaseStoreImpl {
2809
2974
  }
2810
2975
  async process() {
2811
2976
  await this.ready();
2812
- if (!this.loader.remoteCarStore) return;
2977
+ if (!this.loader?.remoteCarStore) return;
2813
2978
  await this.processQueue.enqueue(async () => {
2814
2979
  try {
2815
2980
  await this._doProcess();
@@ -2822,73 +2987,88 @@ var WALStoreImpl = class extends BaseStoreImpl {
2822
2987
  });
2823
2988
  }
2824
2989
  async _doProcess() {
2990
+ if (!this.loader) return;
2825
2991
  if (!this.loader.remoteCarStore) return;
2826
- const rmlp = (async () => {
2827
- const operations = [...this.walState.operations];
2828
- const fileOperations = [...this.walState.fileOperations];
2829
- const uploads = [];
2830
- const noLoaderOps = [...this.walState.noLoaderOps];
2831
- const limit = (0, import_p_limit2.default)(3);
2832
- if (operations.length + fileOperations.length + noLoaderOps.length === 0) return;
2833
- for (const dbMeta of noLoaderOps) {
2834
- const uploadP = limit(async () => {
2835
- for (const cid of dbMeta.cars) {
2836
- const car = await (await this.loader.carStore()).load(cid);
2837
- if (!car) {
2838
- if (carLogIncludesGroup(this.loader.carLog, dbMeta.cars))
2839
- throw this.logger.Error().Ref("cid", cid).Msg("missing local car").AsError();
2840
- } else {
2841
- await throwFalsy(this.loader.remoteCarStore).save(car);
2992
+ const operations = [...this.walState.operations];
2993
+ const noLoaderOps = [...this.walState.noLoaderOps];
2994
+ const fileOperations = [...this.walState.fileOperations];
2995
+ if (operations.length + noLoaderOps.length + fileOperations.length === 0) return;
2996
+ const concurrencyLimit = 3;
2997
+ const retryableUpload = (fn, description) => (0, import_p_retry.default)(fn, {
2998
+ retries: 5,
2999
+ onFailedAttempt: (error) => {
3000
+ this.logger.Warn().Msg(`Attempt ${error.attemptNumber} failed for ${description}. There are ${error.retriesLeft} retries left.`);
3001
+ }
3002
+ });
3003
+ try {
3004
+ await (0, import_p_map.default)(
3005
+ noLoaderOps,
3006
+ async (dbMeta) => {
3007
+ await retryableUpload(async () => {
3008
+ if (!this.loader) return;
3009
+ for (const cid of dbMeta.cars) {
3010
+ const car = await (await this.loader.carStore()).load(cid);
3011
+ if (!car) {
3012
+ if (carLogIncludesGroup(this.loader.carLog, dbMeta.cars)) {
3013
+ throw this.logger.Error().Ref("cid", cid).Msg("missing local car").AsError();
3014
+ }
3015
+ } else {
3016
+ await throwFalsy(this.loader.remoteCarStore).save(car);
3017
+ }
2842
3018
  }
2843
3019
  this.walState.noLoaderOps = this.walState.noLoaderOps.filter((op) => op !== dbMeta);
2844
- }
2845
- });
2846
- uploads.push(uploadP);
2847
- }
2848
- for (const dbMeta of operations) {
2849
- const uploadP = limit(async () => {
2850
- for (const cid of dbMeta.cars) {
2851
- const car = await (await this.loader.carStore()).load(cid).catch(() => null);
2852
- if (!car) {
2853
- if (carLogIncludesGroup(this.loader.carLog, dbMeta.cars))
2854
- throw this.logger.Error().Ref("cid", cid).Msg(`missing local car`).AsError();
2855
- } else {
2856
- await throwFalsy(this.loader.remoteCarStore).save(car);
3020
+ }, `noLoaderOp with dbMeta.cars=${dbMeta.cars.toString()}`);
3021
+ },
3022
+ { concurrency: concurrencyLimit }
3023
+ );
3024
+ await (0, import_p_map.default)(
3025
+ operations,
3026
+ async (dbMeta) => {
3027
+ await retryableUpload(async () => {
3028
+ if (!this.loader) return;
3029
+ for (const cid of dbMeta.cars) {
3030
+ const car = await (await this.loader.carStore()).load(cid);
3031
+ if (!car) {
3032
+ if (carLogIncludesGroup(this.loader.carLog, dbMeta.cars)) {
3033
+ throw this.logger.Error().Ref("cid", cid).Msg(`missing local car`).AsError();
3034
+ }
3035
+ } else {
3036
+ await throwFalsy(this.loader.remoteCarStore).save(car);
3037
+ }
2857
3038
  }
2858
- }
2859
- this.walState.operations = this.walState.operations.filter((op) => op !== dbMeta);
2860
- });
2861
- uploads.push(uploadP);
2862
- }
2863
- if (fileOperations.length) {
2864
- const dbLoader = this.loader;
2865
- for (const { cid: fileCid, public: publicFile } of fileOperations) {
2866
- const uploadP = limit(async () => {
2867
- const fileBlock = await (await dbLoader.fileStore()).load(fileCid);
2868
- await dbLoader.remoteFileStore?.save(fileBlock, { public: publicFile });
3039
+ this.walState.operations = this.walState.operations.filter((op) => op !== dbMeta);
3040
+ }, `operation with dbMeta.cars=${dbMeta.cars.toString()}`);
3041
+ },
3042
+ { concurrency: concurrencyLimit }
3043
+ );
3044
+ await (0, import_p_map.default)(
3045
+ fileOperations,
3046
+ async ({ cid: fileCid, public: publicFile }) => {
3047
+ await retryableUpload(async () => {
3048
+ if (!this.loader) return;
3049
+ const fileBlock = await (await this.loader.fileStore()).load(fileCid);
3050
+ if (!fileBlock) {
3051
+ throw this.logger.Error().Ref("cid", fileCid).Msg("missing file block").AsError();
3052
+ }
3053
+ await this.loader.remoteFileStore?.save(fileBlock, { public: publicFile });
2869
3054
  this.walState.fileOperations = this.walState.fileOperations.filter((op) => op.cid !== fileCid);
2870
- });
2871
- uploads.push(uploadP);
2872
- }
2873
- }
2874
- try {
2875
- const res = await Promise.allSettled(uploads);
2876
- const errors = res.filter((r) => r.status === "rejected");
2877
- if (errors.length) {
2878
- throw this.logger.Error().Any("errors", errors).Msg("error uploading").AsError();
2879
- }
2880
- if (operations.length) {
2881
- const lastOp = operations[operations.length - 1];
2882
- await this.loader.remoteMetaStore?.save(lastOp).catch((e) => {
2883
- this.walState.operations.push(lastOp);
2884
- throw this.logger.Error().Any("error", e).Msg("error saving remote meta").AsError();
2885
- });
2886
- }
2887
- } finally {
2888
- await this.save(this.walState);
3055
+ }, `fileOperation with cid=${fileCid.toString()}`);
3056
+ },
3057
+ { concurrency: concurrencyLimit }
3058
+ );
3059
+ if (operations.length) {
3060
+ const lastOp = operations[operations.length - 1];
3061
+ await retryableUpload(async () => {
3062
+ if (!this.loader) return;
3063
+ await this.loader.remoteMetaStore?.save(lastOp);
3064
+ }, `remoteMetaStore save with dbMeta.cars=${lastOp.cars.toString()}`);
2889
3065
  }
2890
- })();
2891
- await rmlp;
3066
+ } catch (error) {
3067
+ this.logger.Error().Any("error", error).Msg("Processing failed");
3068
+ return;
3069
+ } finally {
3070
+ await this.save(this.walState);
3071
+ }
2892
3072
  }
2893
3073
  async load() {
2894
3074
  this.logger.Debug().Msg("loading");
@@ -2905,6 +3085,7 @@ var WALStoreImpl = class extends BaseStoreImpl {
2905
3085
  }
2906
3086
  try {
2907
3087
  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()));
2908
3089
  } catch (e) {
2909
3090
  throw this.logger.Error().Err(e).Msg("error parse").AsError();
2910
3091
  }
@@ -2931,73 +3112,98 @@ var WALStoreImpl = class extends BaseStoreImpl {
2931
3112
  return import_cement10.Result.Ok(void 0);
2932
3113
  }
2933
3114
  destroy() {
3115
+ this.logger.Debug().Msg("destroy");
2934
3116
  return this.gateway.destroy(this.url());
2935
3117
  }
2936
3118
  };
2937
3119
 
2938
3120
  // 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
2939
3135
  init_utils();
2940
- function ensureIsIndex(url, isIndex) {
2941
- if (isIndex) {
2942
- return url.build().setParam("index", isIndex).URI();
3136
+ var MemoryGateway = class {
3137
+ constructor(memorys) {
3138
+ this.memorys = memorys;
2943
3139
  }
2944
- return url.build().delParam("index").URI();
2945
- }
2946
- function ensureName(name, url) {
2947
- if (!url.hasParam("name")) {
2948
- return url.build().setParam("name", name).URI();
3140
+ buildUrl(baseUrl, key) {
3141
+ return Promise.resolve(import_cement11.Result.Ok(baseUrl.build().setParam("key" /* KEY */, key).URI()));
2949
3142
  }
2950
- return url;
2951
- }
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());
3178
+ }
3179
+ };
3180
+
3181
+ // src/blockstore/register-store-protocol.ts
2952
3182
  var storeFactory = /* @__PURE__ */ new Map();
2953
- function buildURL(optURL, loader) {
2954
- const storeOpts = loader.ebOpts.store;
2955
- const obuItem = Array.from(storeFactory.values()).find((items) => items.overrideBaseURL);
2956
- let obuUrl;
2957
- if (obuItem && obuItem.overrideBaseURL) {
2958
- obuUrl = import_cement13.URI.from(obuItem.overrideBaseURL);
2959
- }
2960
- const ret = ensureIsIndex(
2961
- import_cement13.URI.from(optURL || obuUrl || dataDir(loader.sthis, loader.name, storeOpts.stores?.base)),
2962
- storeOpts.isIndex
2963
- );
2964
- return ret;
2965
- }
2966
- var onceGateway = new import_cement13.KeyedResolvOnce();
2967
- async function getGatewayFromURL(url, sthis) {
2968
- return onceGateway.get(url.toString()).once(async () => {
2969
- const item = storeFactory.get(url.protocol);
2970
- if (item) {
2971
- const ret = {
2972
- gateway: await item.gateway(sthis),
2973
- test: await item.test(sthis)
2974
- };
2975
- const res = await ret.gateway.start(url);
2976
- if (res.isErr()) {
2977
- sthis.logger.Error().Result("start", res).Msg("start failed");
2978
- return void 0;
2979
- }
2980
- return ret;
3183
+ function getDefaultURI(sthis, protocol) {
3184
+ if (protocol) {
3185
+ if (!protocol.endsWith(":")) {
3186
+ protocol += ":";
2981
3187
  }
2982
- sthis.logger.Warn().Url(url).Msg("unsupported protocol");
2983
- return void 0;
2984
- });
3188
+ const gfi = storeFactory.get(protocol);
3189
+ if (gfi) {
3190
+ return gfi.defaultURI(sthis);
3191
+ }
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);
2985
3198
  }
2986
3199
  function registerStoreProtocol(item) {
2987
3200
  let protocol = item.protocol;
2988
3201
  if (!protocol.endsWith(":")) {
2989
3202
  protocol += ":";
2990
3203
  }
2991
- if (storeFactory.has(protocol)) {
2992
- if (!item.overrideBaseURL && storeFactory.get(protocol) !== item) {
2993
- throw new Error(`we need a logger here`);
2994
- return () => {
2995
- };
2996
- }
2997
- }
2998
- if (item.overrideBaseURL) {
3204
+ if (item.isDefault) {
2999
3205
  Array.from(storeFactory.values()).forEach((items) => {
3000
- items.overrideBaseURL = void 0;
3206
+ items.isDefault = false;
3001
3207
  });
3002
3208
  }
3003
3209
  storeFactory.set(protocol, item);
@@ -3005,134 +3211,186 @@ function registerStoreProtocol(item) {
3005
3211
  storeFactory.delete(protocol);
3006
3212
  };
3007
3213
  }
3008
- var onceDataStoreFactory = new import_cement13.KeyedResolvOnce();
3009
- async function dataStoreFactory(loader) {
3010
- const url = ensureName(loader.name, buildURL(loader.ebOpts.store.stores?.data, loader)).build().setParam("store", "data").URI();
3011
- const sthis = ensureSuperLog(loader.sthis, "dataStoreFactory", { url: url.toString() });
3012
- return onceDataStoreFactory.get(url.toString()).once(async () => {
3013
- const gateway = await getGatewayFromURL(url, sthis);
3014
- if (!gateway) {
3015
- throw sthis.logger.Error().Url(url).Msg("gateway not found").AsError();
3016
- }
3017
- const store = new DataStoreImpl(sthis, loader.name, url, {
3018
- gateway: gateway.gateway,
3019
- keybag: () => getKeyBag(loader.sthis, {
3020
- ...loader.ebOpts.keyBag
3021
- })
3022
- });
3023
- return store;
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
+ }
3024
3249
  });
3250
+ } else {
3251
+ registerStoreProtocol(fileGatewayFactoryItem());
3025
3252
  }
3026
- var onceMetaStoreFactory = new import_cement13.KeyedResolvOnce();
3027
- async function metaStoreFactory(loader) {
3028
- const url = ensureName(loader.name, buildURL(loader.ebOpts.store.stores?.meta, loader)).build().setParam("store", "meta").URI();
3029
- const sthis = ensureSuperLog(loader.sthis, "metaStoreFactory", { url: () => url.toString() });
3030
- return onceMetaStoreFactory.get(url.toString()).once(async () => {
3031
- sthis.logger.Debug().Str("protocol", url.protocol).Msg("pre-protocol switch");
3032
- const gateway = await getGatewayFromURL(url, sthis);
3033
- if (!gateway) {
3034
- throw sthis.logger.Error().Url(url).Msg("gateway not found").AsError();
3035
- }
3036
- const store = new MetaStoreImpl(loader.sthis, loader.name, url, {
3037
- gateway: gateway.gateway,
3038
- keybag: () => getKeyBag(loader.sthis, {
3039
- ...loader.ebOpts.keyBag
3040
- })
3041
- });
3042
- return store;
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());
3043
3290
  });
3044
3291
  }
3045
- var onceRemoteWalFactory = new import_cement13.KeyedResolvOnce();
3046
- async function remoteWalFactory(loader) {
3047
- const url = ensureName(loader.name, buildURL(loader.ebOpts.store.stores?.wal, loader)).build().setParam("store", "wal").URI();
3048
- const sthis = ensureSuperLog(loader.sthis, "remoteWalFactory", { url: url.toString() });
3049
- return onceRemoteWalFactory.get(url.toString()).once(async () => {
3050
- const gateway = await getGatewayFromURL(url, sthis);
3051
- if (!gateway) {
3052
- throw sthis.logger.Error().Url(url).Msg("gateway not found").AsError();
3053
- }
3054
- sthis.logger.Debug().Str("prepared", url.toString()).Msg("produced");
3055
- const store = new WALStoreImpl(loader, url, {
3056
- gateway: gateway.gateway,
3057
- keybag: () => getKeyBag(loader.sthis, {
3058
- ...loader.ebOpts.keyBag
3059
- })
3060
- });
3061
- return store;
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
3302
+ });
3303
+ return store;
3304
+ }
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
3062
3315
  });
3316
+ return store;
3317
+ }
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
3328
+ });
3329
+ return store;
3063
3330
  }
3064
3331
  async function testStoreFactory(url, sthis) {
3065
- sthis = ensureSuperLog(sthis, "testStoreFactory");
3066
- const gateway = await getGatewayFromURL(url, sthis);
3067
- if (!gateway) {
3332
+ const rgateway = await getStartedGateway(sthis, url);
3333
+ if (!rgateway) {
3068
3334
  throw sthis.logger.Error().Url(url).Msg("gateway not found").AsError();
3069
3335
  }
3070
- return gateway.test;
3336
+ return rgateway.Ok().test;
3071
3337
  }
3072
- async function ensureStart(store, logger) {
3338
+ async function ensureStart(store) {
3073
3339
  const ret = await store.start();
3074
3340
  if (ret.isErr()) {
3075
- throw logger.Error().Result("start", ret).Msg("start failed").AsError();
3341
+ throw store.logger.Error().Result("start", ret).Msg("start failed").AsError();
3076
3342
  }
3077
- logger.Debug().Url(ret.Ok(), "prepared").Msg("produced");
3343
+ store.logger.Debug().Url(ret.Ok(), "prepared").Msg("produced");
3078
3344
  return store;
3079
3345
  }
3080
- function toStoreRuntime(opts, sthis) {
3081
- const logger = ensureLogger(sthis, "toStoreRuntime", {});
3346
+ function ensureStoreEnDeFile(ende) {
3347
+ ende = ende || {};
3082
3348
  return {
3083
- makeMetaStore: async (loader) => {
3084
- logger.Debug().Str("fromOpts", "" + !!loader.ebOpts.store.makeMetaStore).Msg("makeMetaStore");
3085
- return ensureStart(await (loader.ebOpts.store.makeMetaStore || metaStoreFactory)(loader), logger);
3086
- },
3087
- makeDataStore: async (loader) => {
3088
- logger.Debug().Str("fromOpts", "" + !!loader.ebOpts.store.makeDataStore).Msg("makeDataStore");
3089
- return ensureStart(await (loader.ebOpts.store.makeDataStore || dataStoreFactory)(loader), logger);
3090
- },
3091
- makeWALStore: async (loader) => {
3092
- logger.Debug().Str("fromOpts", "" + !!loader.ebOpts.store.makeWALStore).Msg("makeRemoteWAL");
3093
- return ensureStart(await (loader.ebOpts.store.makeWALStore || remoteWalFactory)(loader), logger);
3094
- },
3095
- encodeFile: opts.encodeFile || encodeFile,
3096
- decodeFile: opts.decodeFile || decodeFile
3349
+ encodeFile: ende.encodeFile || encodeFile,
3350
+ decodeFile: ende.decodeFile || decodeFile
3097
3351
  };
3098
3352
  }
3099
- registerStoreProtocol({
3100
- protocol: "file:",
3101
- gateway: async (sthis) => {
3102
- const { FileGateway: FileGateway2 } = await Promise.resolve().then(() => (init_gateway(), gateway_exports));
3103
- return new FileGateway2(sthis);
3104
- },
3105
- test: async (sthis) => {
3106
- const { FileTestStore: FileTestStore2 } = await Promise.resolve().then(() => (init_gateway(), gateway_exports));
3107
- return new FileTestStore2(sthis);
3108
- }
3109
- });
3110
- registerStoreProtocol({
3111
- protocol: "indexdb:",
3112
- gateway: async (sthis) => {
3113
- const { IndexDBGateway: IndexDBGateway2 } = await Promise.resolve().then(() => (init_gateway2(), gateway_exports2));
3114
- return new IndexDBGateway2(sthis);
3115
- },
3116
- test: async (sthis) => {
3117
- const { IndexDBTestStore: IndexDBTestStore2 } = await Promise.resolve().then(() => (init_gateway2(), gateway_exports2));
3118
- return new IndexDBTestStore2(sthis);
3119
- }
3120
- });
3353
+ function toStoreRuntime(sthis, endeOpts = {}) {
3354
+ 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)
3380
+ };
3381
+ }
3382
+
3383
+ // src/blockstore/connection-base.ts
3384
+ init_types();
3121
3385
 
3122
3386
  // src/blockstore/store-remote.ts
3123
3387
  async function RemoteDataStore(sthis, name, url, opts) {
3124
- const ds = new DataStoreImpl(sthis, name, url, opts);
3388
+ const ds = new DataStoreImpl(sthis, url, opts);
3125
3389
  await ds.start();
3126
3390
  return ds;
3127
3391
  }
3128
3392
  async function RemoteMetaStore(sthis, name, url, opts) {
3129
- const ms = new MetaStoreImpl(
3130
- sthis,
3131
- name,
3132
- url,
3133
- opts
3134
- /* , true*/
3135
- );
3393
+ const ms = new MetaStoreImpl(sthis, url, opts);
3136
3394
  await ms.start();
3137
3395
  return ms;
3138
3396
  }
@@ -3157,14 +3415,17 @@ var ConnectionBase = class {
3157
3415
  if (!loader) throw this.logger.Error().Msg("connectMeta_X: loader is required").AsError();
3158
3416
  this.loader = loader;
3159
3417
  await this.onConnect();
3160
- const metaUrl = this.url.build().defParam("store", "meta").URI();
3161
- const gateway = await getGatewayFromURL(metaUrl, this.loader.sthis);
3162
- if (!gateway) throw this.logger.Error().Url(metaUrl).Msg("connectMeta_X: gateway is required").AsError();
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();
3163
3423
  const dbName = metaUrl.getParam("name");
3164
- if (!dbName) throw this.logger.Error().Url(metaUrl).Msg("connectMeta_X: name is required").AsError();
3165
- const remote = await RemoteMetaStore(loader.sthis, dbName, metaUrl, {
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, {
3166
3427
  gateway: gateway.gateway,
3167
- keybag: () => getKeyBag(loader.sthis, loader.ebOpts.keyBag),
3428
+ keybag: await loader.keyBag(),
3168
3429
  loader
3169
3430
  });
3170
3431
  this.loader.remoteMetaStore = remote;
@@ -3177,14 +3438,15 @@ var ConnectionBase = class {
3177
3438
  async connectStorage_X({ loader }) {
3178
3439
  if (!loader) throw this.logger.Error().Msg("connectStorage_X: loader is required").AsError();
3179
3440
  this.loader = loader;
3180
- const dataUrl = this.url.build().defParam("store", "data").URI();
3181
- const gateway = await getGatewayFromURL(dataUrl, this.loader.sthis);
3182
- if (!gateway) throw this.logger.Error().Url(dataUrl).Msg("connectStorage_X: gateway is required").AsError();
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();
3183
3445
  const name = dataUrl.getParam("name");
3184
3446
  if (!name) throw this.logger.Error().Url(dataUrl).Msg("connectStorage_X: name is required").AsError;
3185
3447
  loader.remoteCarStore = await RemoteDataStore(loader.sthis, name, this.url, {
3186
- gateway: gateway.gateway,
3187
- keybag: () => getKeyBag(loader.sthis, this.loader?.ebOpts.keyBag)
3448
+ gateway: rgateway.Ok().gateway,
3449
+ keybag: await loader.keyBag()
3188
3450
  });
3189
3451
  loader.remoteFileStore = loader.remoteCarStore;
3190
3452
  }
@@ -3224,6 +3486,13 @@ var ConnectionBase = class {
3224
3486
  };
3225
3487
 
3226
3488
  // 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();
3227
3496
  function time(tag) {
3228
3497
  }
3229
3498
  function timeEnd(tag) {
@@ -3271,7 +3540,7 @@ async function writeDocContent(store, blocks, update, logger) {
3271
3540
  await processFiles(store, blocks, update.value, logger);
3272
3541
  value = { doc: update.value };
3273
3542
  }
3274
- const block = await encode({ value, hasher: import_sha25.sha256, codec });
3543
+ const block = await encode3({ value, hasher: import_sha25.sha256, codec });
3275
3544
  blocks.putSync(block.cid, block.bytes);
3276
3545
  return block.cid;
3277
3546
  }
@@ -3362,7 +3631,7 @@ function readFileset(blocks, files, isPublic = false) {
3362
3631
  async function getValueFromLink(blocks, link, logger) {
3363
3632
  const block = await blocks.get(link);
3364
3633
  if (!block) throw logger.Error().Str("link", link.toString()).Msg(`Missing linked block`).AsError();
3365
- const { value } = await decode({ bytes: block.bytes, hasher: import_sha25.sha256, codec });
3634
+ const { value } = await decode3({ bytes: block.bytes, hasher: import_sha25.sha256, codec });
3366
3635
  const cvalue = {
3367
3636
  ...value,
3368
3637
  cid: link
@@ -3483,16 +3752,19 @@ async function doCompact(blockLog, head, logger) {
3483
3752
  async function getBlock(blocks, cidString) {
3484
3753
  const block = await blocks.get((0, import_link.parse)(cidString));
3485
3754
  if (!block) throw new Error(`Missing block ${cidString}`);
3486
- const { cid, value } = await decode({ bytes: block.bytes, codec, hasher: import_sha25.sha256 });
3755
+ const { cid, value } = await decode3({ bytes: block.bytes, codec, hasher: import_sha25.sha256 });
3487
3756
  return new Block({ cid, value, bytes: block.bytes });
3488
3757
  }
3489
3758
 
3759
+ // src/indexer.ts
3760
+ init_types();
3761
+
3490
3762
  // src/indexer-helpers.ts
3491
3763
  var import_sha26 = require("multiformats/hashes/sha2");
3492
3764
  var codec2 = __toESM(require("@ipld/dag-cbor"), 1);
3493
3765
  var import_charwise = __toESM(require("charwise"), 1);
3494
3766
  var DbIndex = __toESM(require("prolly-trees/db-index"), 1);
3495
- var import_utils16 = require("prolly-trees/utils");
3767
+ var import_utils15 = require("prolly-trees/utils");
3496
3768
  var import_cache = require("prolly-trees/cache");
3497
3769
  var IndexTree = class {
3498
3770
  };
@@ -3500,17 +3772,17 @@ function refCompare(aRef, bRef) {
3500
3772
  if (Number.isNaN(aRef)) return -1;
3501
3773
  if (Number.isNaN(bRef)) throw new Error("ref may not be Infinity or NaN");
3502
3774
  if (aRef === Infinity) return 1;
3503
- return (0, import_utils16.simpleCompare)(aRef, bRef);
3775
+ return (0, import_utils15.simpleCompare)(aRef, bRef);
3504
3776
  }
3505
3777
  function compare(a, b) {
3506
3778
  const [aKey, aRef] = a;
3507
3779
  const [bKey, bRef] = b;
3508
- const comp = (0, import_utils16.simpleCompare)(aKey, bKey);
3780
+ const comp = (0, import_utils15.simpleCompare)(aKey, bKey);
3509
3781
  if (comp !== 0) return comp;
3510
3782
  return refCompare(aRef, bRef);
3511
3783
  }
3512
- var byKeyOpts = { cache: import_cache.nocache, chunker: (0, import_utils16.bf)(30), codec: codec2, hasher: import_sha26.sha256, compare };
3513
- var byIdOpts = { cache: import_cache.nocache, chunker: (0, import_utils16.bf)(30), codec: codec2, hasher: import_sha26.sha256, compare: import_utils16.simpleCompare };
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 };
3514
3786
  function indexEntriesForChanges(changes, mapFn) {
3515
3787
  const indexEntries = [];
3516
3788
  changes.forEach(({ id: key, value, del }) => {
@@ -3541,7 +3813,8 @@ function makeProllyGetBlock(blocks) {
3541
3813
  return create({ cid, bytes, hasher: import_sha26.sha256, codec: codec2 });
3542
3814
  };
3543
3815
  }
3544
- async function bulkIndex(tblocks, inIndex, indexEntries, opts) {
3816
+ async function bulkIndex(logger, tblocks, inIndex, indexEntries, opts) {
3817
+ logger.Debug().Msg("enter bulkIndex");
3545
3818
  if (!indexEntries.length) return inIndex;
3546
3819
  if (!inIndex.root) {
3547
3820
  if (!inIndex.cid) {
@@ -3558,18 +3831,22 @@ async function bulkIndex(tblocks, inIndex, indexEntries, opts) {
3558
3831
  returnNode = node;
3559
3832
  }
3560
3833
  if (!returnNode || !returnRootBlock) throw new Error("failed to create index");
3834
+ logger.Debug().Msg("exit !root bulkIndex");
3561
3835
  return { root: returnNode, cid: returnRootBlock.cid };
3562
3836
  } else {
3563
3837
  inIndex.root = await DbIndex.load({ cid: inIndex.cid, get: makeProllyGetBlock(tblocks), ...opts });
3564
3838
  }
3565
3839
  }
3840
+ logger.Debug().Msg("pre bulk bulkIndex");
3566
3841
  const { root: root3, blocks: newBlocks } = await inIndex.root.bulk(indexEntries);
3567
3842
  if (root3) {
3843
+ logger.Debug().Msg("pre root put bulkIndex");
3568
3844
  for await (const block of newBlocks) {
3569
3845
  await tblocks.put(block.cid, block.bytes);
3570
3846
  }
3571
3847
  return { root: root3, cid: (await root3.block).cid };
3572
3848
  } else {
3849
+ logger.Debug().Msg("pre !root bulkIndex");
3573
3850
  return { root: void 0, cid: void 0 };
3574
3851
  }
3575
3852
  }
@@ -3610,17 +3887,17 @@ function encodeKey(key) {
3610
3887
 
3611
3888
  // src/indexer.ts
3612
3889
  init_utils();
3613
- function index(sthis, { _crdt }, name, mapFn, meta) {
3614
- if (mapFn && meta) throw _crdt.logger.Error().Msg("cannot provide both mapFn and meta").AsError();
3615
- if (mapFn && mapFn.constructor.name !== "Function") throw _crdt.logger.Error().Msg("mapFn must be a function").AsError();
3616
- if (_crdt.indexers.has(name)) {
3617
- const idx = _crdt.indexers.get(name);
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);
3618
3895
  idx.applyMapFn(name, mapFn, meta);
3619
3896
  } else {
3620
- const idx = new Index(sthis, _crdt, name, mapFn, meta);
3621
- _crdt.indexers.set(name, idx);
3897
+ const idx = new Index(refDb.crdt.sthis, refDb.crdt, name, mapFn, meta);
3898
+ refDb.crdt.indexers.set(name, idx);
3622
3899
  }
3623
- return _crdt.indexers.get(name);
3900
+ return refDb.crdt.indexers.get(name);
3624
3901
  }
3625
3902
  var Index = class {
3626
3903
  constructor(sthis, crdt, name, mapFn, meta) {
@@ -3639,18 +3916,9 @@ var Index = class {
3639
3916
  return Promise.all([this.blockstore.ready(), this.crdt.ready()]).then(() => {
3640
3917
  });
3641
3918
  }
3642
- close() {
3643
- return Promise.all([this.blockstore.close(), this.crdt.close()]).then(() => {
3644
- });
3645
- }
3646
- destroy() {
3647
- return Promise.all([this.blockstore.destroy(), this.crdt.destroy()]).then(() => {
3648
- });
3649
- }
3650
3919
  applyMapFn(name, mapFn, meta) {
3651
3920
  if (mapFn && meta) throw this.logger.Error().Msg("cannot provide both mapFn and meta").AsError();
3652
3921
  if (this.name && this.name !== name) throw this.logger.Error().Msg("cannot change name").AsError();
3653
- this.name = name;
3654
3922
  try {
3655
3923
  if (meta) {
3656
3924
  if (this.indexHead && this.indexHead.map((c) => c.toString()).join() !== meta.head.map((c) => c.toString()).join()) {
@@ -3698,9 +3966,13 @@ var Index = class {
3698
3966
  }
3699
3967
  }
3700
3968
  async query(opts = {}) {
3969
+ this.logger.Debug().Msg("enter query");
3701
3970
  await this.ready();
3971
+ this.logger.Debug().Msg("post ready query");
3702
3972
  await this._updateIndex();
3973
+ this.logger.Debug().Msg("post _updateIndex query");
3703
3974
  await this._hydrateIndex();
3975
+ this.logger.Debug().Msg("post _hydrateIndex query");
3704
3976
  if (!this.byKey.root) {
3705
3977
  return await applyQuery(this.crdt, { result: [] }, opts);
3706
3978
  }
@@ -3756,13 +4028,16 @@ var Index = class {
3756
4028
  }
3757
4029
  async _updateIndex() {
3758
4030
  await this.ready();
4031
+ this.logger.Debug().Msg("enter _updateIndex");
3759
4032
  if (this.initError) throw this.initError;
3760
4033
  if (!this.mapFn) throw this.logger.Error().Msg("No map function defined").AsError();
3761
4034
  let result, head;
3762
4035
  if (!this.indexHead || this.indexHead.length === 0) {
3763
4036
  ({ result, head } = await this.crdt.allDocs());
4037
+ this.logger.Debug().Msg("enter crdt.allDocs");
3764
4038
  } else {
3765
4039
  ({ result, head } = await this.crdt.changes(this.indexHead));
4040
+ this.logger.Debug().Msg("enter crdt.changes");
3766
4041
  }
3767
4042
  if (result.length === 0) {
3768
4043
  this.indexHead = head;
@@ -3795,9 +4070,22 @@ var Index = class {
3795
4070
  if (result.length === 0) {
3796
4071
  return indexerMeta;
3797
4072
  }
4073
+ this.logger.Debug().Msg("pre this.blockstore.transaction");
3798
4074
  const { meta } = await this.blockstore.transaction(async (tblocks) => {
3799
- this.byId = await bulkIndex(tblocks, this.byId, removeIdIndexEntries.concat(byIdIndexEntries), byIdOpts);
3800
- this.byKey = await bulkIndex(tblocks, this.byKey, staleKeyIndexEntries.concat(indexEntries), byKeyOpts);
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
+ );
3801
4089
  this.indexHead = head;
3802
4090
  if (this.byId.cid && this.byKey.cid) {
3803
4091
  const idxMeta = {
@@ -3809,8 +4097,10 @@ var Index = class {
3809
4097
  };
3810
4098
  indexerMeta.indexes?.set(this.name, idxMeta);
3811
4099
  }
4100
+ this.logger.Debug().Any("indexerMeta", new Array(indexerMeta.indexes?.entries())).Msg("exit this.blockstore.transaction fn");
3812
4101
  return indexerMeta;
3813
4102
  });
4103
+ this.logger.Debug().Msg("post this.blockstore.transaction");
3814
4104
  return meta;
3815
4105
  }
3816
4106
  };
@@ -3818,7 +4108,8 @@ var Index = class {
3818
4108
  // src/crdt-clock.ts
3819
4109
  var import_clock3 = require("@web3-storage/pail/clock");
3820
4110
  var import_crdt2 = require("@web3-storage/pail/crdt");
3821
- var import_cement14 = require("@adviser/cement");
4111
+ var import_cement16 = require("@adviser/cement");
4112
+ init_types();
3822
4113
 
3823
4114
  // src/apply-head-queue.ts
3824
4115
  function applyHeadQueue(worker, logger) {
@@ -3876,7 +4167,7 @@ var CRDTClock = class {
3876
4167
  this.zoomers = /* @__PURE__ */ new Set();
3877
4168
  this.watchers = /* @__PURE__ */ new Set();
3878
4169
  this.emptyWatchers = /* @__PURE__ */ new Set();
3879
- this._ready = new import_cement14.ResolveOnce();
4170
+ this._ready = new import_cement16.ResolveOnce();
3880
4171
  this.blockstore = blockstore;
3881
4172
  this.logger = ensureLogger(blockstore.sthis, "CRDTClock");
3882
4173
  this.applyHeadQueue = applyHeadQueue(this.int_applyHead.bind(this), this.logger);
@@ -3939,21 +4230,23 @@ var CRDTClock = class {
3939
4230
  throw this.logger.Error().Msg("missing blockstore").AsError();
3940
4231
  }
3941
4232
  await validateBlocks(this.logger, newHead, this.blockstore);
3942
- const { meta } = await this.blockstore.transaction(
3943
- async (tblocks) => {
3944
- const advancedHead = await advanceBlocks(this.logger, newHead, tblocks, this.head);
3945
- const result = await (0, import_crdt2.root)(tblocks, advancedHead);
3946
- for (const { cid, bytes } of [
3947
- ...result.additions
3948
- // ...result.removals
3949
- ]) {
3950
- tblocks.putSync(cid, bytes);
3951
- }
3952
- return { head: advancedHead };
3953
- },
3954
- { noLoader, add: false }
3955
- );
3956
- this.setHead(meta.head);
4233
+ if (!this.transaction) {
4234
+ this.transaction = this.blockstore.openTransaction({ noLoader, add: false });
4235
+ }
4236
+ const tblocks = this.transaction;
4237
+ const advancedHead = await advanceBlocks(this.logger, newHead, tblocks, this.head);
4238
+ const result = await (0, import_crdt2.root)(tblocks, advancedHead);
4239
+ for (const { cid, bytes } of [
4240
+ ...result.additions
4241
+ // ...result.removals
4242
+ ]) {
4243
+ tblocks.putSync(cid, bytes);
4244
+ }
4245
+ if (!noLoader) {
4246
+ await this.blockstore.commitTransaction(tblocks, { head: advancedHead }, { add: false, noLoader });
4247
+ this.transaction = void 0;
4248
+ }
4249
+ this.setHead(advancedHead);
3957
4250
  }
3958
4251
  };
3959
4252
  function sortClockHead(clockHead) {
@@ -3986,15 +4279,13 @@ async function advanceBlocks(logger, newHead, tblocks, head) {
3986
4279
  // src/crdt.ts
3987
4280
  init_utils();
3988
4281
  var CRDT = class {
3989
- constructor(sthis, name, opts = {}) {
4282
+ constructor(sthis, opts) {
3990
4283
  this.indexers = /* @__PURE__ */ new Map();
3991
- this.onceReady = new import_cement15.ResolveOnce();
4284
+ this.onceReady = new import_cement17.ResolveOnce();
3992
4285
  this.sthis = sthis;
3993
- this.name = name;
3994
4286
  this.logger = ensureLogger(sthis, "CRDT");
3995
4287
  this.opts = opts;
3996
4288
  this.blockstore = blockstoreFactory(sthis, {
3997
- name,
3998
4289
  applyMeta: async (meta) => {
3999
4290
  const crdtMeta = meta;
4000
4291
  if (!crdtMeta.head) throw this.logger.Error().Msg("missing head").AsError();
@@ -4004,23 +4295,27 @@ var CRDT = class {
4004
4295
  await doCompact(blocks, this.clock.head, this.logger);
4005
4296
  return { head: this.clock.head };
4006
4297
  },
4007
- autoCompact: this.opts.autoCompact || 100,
4008
- store: { ...this.opts.store, isIndex: void 0 },
4009
- public: this.opts.public,
4010
- meta: this.opts.meta,
4011
- threshold: this.opts.threshold
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,
4012
4305
  });
4013
4306
  this.indexBlockstore = blockstoreFactory(sthis, {
4014
- name,
4307
+ // name: opts.name,
4015
4308
  applyMeta: async (meta) => {
4016
4309
  const idxCarMeta = meta;
4017
4310
  if (!idxCarMeta.indexes) throw this.logger.Error().Msg("missing indexes").AsError();
4018
- for (const [name2, idx] of Object.entries(idxCarMeta.indexes)) {
4019
- index(this.sthis, { _crdt: this }, name2, void 0, idx);
4311
+ for (const [name, idx] of Object.entries(idxCarMeta.indexes)) {
4312
+ index({ crdt: this }, name, void 0, idx);
4020
4313
  }
4021
4314
  },
4022
- store: { ...this.opts.store, isIndex: this.opts.store?.isIndex || "idx" },
4023
- public: this.opts.public
4315
+ storeRuntime: toStoreRuntime(this.sthis, this.opts.storeEnDe),
4316
+ storeUrls: this.opts.storeUrls.idx,
4317
+ keyBag: this.opts.keyBag
4318
+ // public: this.opts.public,
4024
4319
  });
4025
4320
  this.clock = new CRDTClock(this.blockstore);
4026
4321
  this.clock.onZoom(() => {
@@ -4102,52 +4397,166 @@ var CRDT = class {
4102
4397
  };
4103
4398
 
4104
4399
  // src/database.ts
4400
+ init_types();
4105
4401
  init_utils();
4106
- var Database = class {
4107
- constructor(name, opts) {
4108
- this.opts = {};
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) {
4109
4502
  this._listening = false;
4110
4503
  this._listeners = /* @__PURE__ */ new Set();
4111
4504
  this._noupdate_listeners = /* @__PURE__ */ new Set();
4112
- this._ready = new import_cement16.ResolveOnce();
4113
- this.name = name;
4114
- this.opts = opts || this.opts;
4115
- this.sthis = ensureSuperThis(this.opts);
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;
4116
4512
  this.logger = ensureLogger(this.sthis, "Database");
4117
- this._crdt = new CRDT(this.sthis, name, this.opts);
4118
- this.blockstore = this._crdt.blockstore;
4513
+ this.crdt = new CRDT(this.sthis, this.opts);
4119
4514
  this._writeQueue = writeQueue(async (updates) => {
4120
- return await this._crdt.bulk(updates);
4515
+ return await this.crdt.bulk(updates);
4121
4516
  });
4122
- this._crdt.clock.onTock(() => {
4517
+ this.crdt.clock.onTock(() => {
4123
4518
  this._no_update_notify();
4124
4519
  });
4125
4520
  }
4126
- static {
4127
- this.databases = /* @__PURE__ */ new Map();
4521
+ addShell(shell) {
4522
+ this.shells.add(shell);
4523
+ }
4524
+ onClosed(fn) {
4525
+ this._onClosedFns.add(fn);
4128
4526
  }
4129
4527
  async close() {
4130
- await this.ready();
4131
- await this._crdt.close();
4132
- await this.blockstore.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
+ }
4133
4540
  }
4134
4541
  async destroy() {
4135
4542
  await this.ready();
4136
- await this._crdt.destroy();
4137
- await this.blockstore.destroy();
4543
+ await this.crdt.destroy();
4138
4544
  }
4139
4545
  async ready() {
4140
- return this._ready.once(async () => {
4546
+ const ret = await this._ready.once(async () => {
4141
4547
  await this.sthis.start();
4142
- await this._crdt.ready();
4143
- await this.blockstore.ready();
4548
+ await this.crdt.ready();
4144
4549
  });
4550
+ return ret;
4551
+ }
4552
+ name() {
4553
+ return this.opts.storeUrls.data.data.getParam("name" /* NAME */) || "default";
4145
4554
  }
4146
4555
  async get(id) {
4147
- if (!id) throw this.logger.Error().Str("db", this.name).Msg(`Doc id is required`).AsError();
4556
+ if (!id) throw this.logger.Error().Str("db", this.name()).Msg(`Doc id is required`).AsError();
4148
4557
  await this.ready();
4149
4558
  this.logger.Debug().Str("id", id).Msg("get");
4150
- const got = await this._crdt.get(id).catch((e) => {
4559
+ const got = await this.crdt.get(id).catch((e) => {
4151
4560
  throw new NotFoundError(`Not found: ${id} - ${e.message}`);
4152
4561
  });
4153
4562
  if (!got) throw new NotFoundError(`Not found: ${id}`);
@@ -4166,34 +4575,34 @@ var Database = class {
4166
4575
  _id: docId
4167
4576
  }
4168
4577
  });
4169
- return { id: docId, clock: result?.head, name: this.name };
4578
+ return { id: docId, clock: result?.head, name: this.name() };
4170
4579
  }
4171
4580
  async del(id) {
4172
4581
  await this.ready();
4173
4582
  this.logger.Debug().Str("id", id).Msg("del");
4174
4583
  const result = await this._writeQueue.push({ id, del: true });
4175
- return { id, clock: result?.head, name: this.name };
4584
+ return { id, clock: result?.head, name: this.name() };
4176
4585
  }
4177
4586
  async changes(since = [], opts = {}) {
4178
4587
  await this.ready();
4179
4588
  this.logger.Debug().Any("since", since).Any("opts", opts).Msg("changes");
4180
- const { result, head } = await this._crdt.changes(since, opts);
4589
+ const { result, head } = await this.crdt.changes(since, opts);
4181
4590
  const rows = result.map(({ id: key, value, del, clock }) => ({
4182
4591
  key,
4183
4592
  value: del ? { _id: key, _deleted: true } : { _id: key, ...value },
4184
4593
  clock
4185
4594
  }));
4186
- return { rows, clock: head, name: this.name };
4595
+ return { rows, clock: head, name: this.name() };
4187
4596
  }
4188
4597
  async allDocs(opts = {}) {
4189
4598
  await this.ready();
4190
4599
  this.logger.Debug().Msg("allDocs");
4191
- const { result, head } = await this._crdt.allDocs();
4600
+ const { result, head } = await this.crdt.allDocs();
4192
4601
  const rows = result.map(({ id: key, value, del }) => ({
4193
4602
  key,
4194
4603
  value: del ? { _id: key, _deleted: true } : { _id: key, ...value }
4195
4604
  }));
4196
- return { rows, clock: head, name: this.name };
4605
+ return { rows, clock: head, name: this.name() };
4197
4606
  }
4198
4607
  async allDocuments() {
4199
4608
  return this.allDocs();
@@ -4203,7 +4612,7 @@ var Database = class {
4203
4612
  if (updates) {
4204
4613
  if (!this._listening) {
4205
4614
  this._listening = true;
4206
- this._crdt.clock.onTick((updates2) => {
4615
+ this.crdt.clock.onTick((updates2) => {
4207
4616
  void this._notify(updates2);
4208
4617
  });
4209
4618
  }
@@ -4222,13 +4631,13 @@ var Database = class {
4222
4631
  async query(field, opts = {}) {
4223
4632
  await this.ready();
4224
4633
  this.logger.Debug().Any("field", field).Any("opts", opts).Msg("query");
4225
- const _crdt = this._crdt;
4226
- const idx = typeof field === "string" ? index(this.sthis, { _crdt }, field) : index(this.sthis, { _crdt }, makeName(field.toString()), field);
4634
+ const _crdt = this.crdt;
4635
+ const idx = typeof field === "string" ? index({ crdt: _crdt }, field) : index({ crdt: _crdt }, makeName(field.toString()), field);
4227
4636
  return await idx.query(opts);
4228
4637
  }
4229
4638
  async compact() {
4230
4639
  await this.ready();
4231
- await this._crdt.compact();
4640
+ await this.crdt.compact();
4232
4641
  }
4233
4642
  async _notify(updates) {
4234
4643
  await this.ready();
@@ -4252,23 +4661,62 @@ var Database = class {
4252
4661
  }
4253
4662
  }
4254
4663
  };
4255
- function toSortedArray(set) {
4256
- if (!set) return [];
4257
- return Object.entries(set).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => ({ [k]: v }));
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();
4258
4687
  }
4259
- function fireproof(name, opts) {
4260
- const key = JSON.stringify(
4261
- toSortedArray({
4262
- name,
4263
- stores: toSortedArray(opts?.store?.stores)
4264
- })
4265
- );
4266
- let db = Database.databases.get(key);
4267
- if (!db) {
4268
- db = new Database(name, opts);
4269
- Database.databases.set(key, db);
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);
4270
4701
  }
4271
- return db;
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
+ };
4717
+ }
4718
+ function fireproof(name, opts) {
4719
+ return DatabaseFactory(name, opts);
4272
4720
  }
4273
4721
  function makeName(fnString) {
4274
4722
  const regex = /\(([^,()]+,\s*[^,()]+|\[[^\]]+\],\s*[^,()]+)\)/g;
@@ -4287,6 +4735,9 @@ function makeName(fnString) {
4287
4735
  }
4288
4736
  }
4289
4737
 
4738
+ // src/index.ts
4739
+ init_types();
4740
+
4290
4741
  // src/runtime/index.ts
4291
4742
  var runtime_exports = {};
4292
4743
  __export(runtime_exports, {
@@ -4299,7 +4750,7 @@ __export(runtime_exports, {
4299
4750
  kb: () => key_bag_exports,
4300
4751
  kc: () => keyed_crypto_exports,
4301
4752
  mf: () => wait_pr_multiformats_exports,
4302
- runtimeFn: () => import_cement17.runtimeFn,
4753
+ runtimeFn: () => import_cement19.runtimeFn,
4303
4754
  toArrayBuffer: () => toArrayBuffer
4304
4755
  });
4305
4756
  init_utils2();
@@ -4315,7 +4766,7 @@ __export(wait_pr_multiformats_exports, {
4315
4766
  var codec_interface_exports = {};
4316
4767
 
4317
4768
  // src/runtime/index.ts
4318
- var import_cement17 = require("@adviser/cement");
4769
+ var import_cement19 = require("@adviser/cement");
4319
4770
  init_version();
4320
4771
  init_version2();
4321
4772
 
@@ -4324,6 +4775,6 @@ init_utils();
4324
4775
 
4325
4776
  // src/version.ts
4326
4777
  var PACKAGE_VERSION = Object.keys({
4327
- "0.19.99": "xxxx"
4778
+ "0.19.101": "xxxx"
4328
4779
  })[0];
4329
4780
  //# sourceMappingURL=index.cjs.map