@fireproof/core 0.19.8-dev-getcon → 0.19.8-dev-series-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.md +34 -0
  2. package/chunk-7EWIAXTM.js +7 -0
  3. package/chunk-7EWIAXTM.js.map +1 -0
  4. package/chunk-OFGPKRCM.js +290 -0
  5. package/chunk-OFGPKRCM.js.map +1 -0
  6. package/chunk-PB4BKL4O.js +7 -0
  7. package/chunk-PB4BKL4O.js.map +1 -0
  8. package/chunk-WS3YRPIA.js +75 -0
  9. package/chunk-WS3YRPIA.js.map +1 -0
  10. package/deno.json +20 -0
  11. package/gateway-5FCWPX5W.js +144 -0
  12. package/gateway-5FCWPX5W.js.map +1 -0
  13. package/{store-indexdb-WLRSICCB.js → gateway-H7UD6TNB.js} +49 -82
  14. package/gateway-H7UD6TNB.js.map +1 -0
  15. package/index.cjs +2317 -1838
  16. package/index.cjs.map +1 -1
  17. package/index.d.cts +663 -535
  18. package/index.d.ts +663 -535
  19. package/index.global.js +26291 -20733
  20. package/index.global.js.map +1 -1
  21. package/index.js +1618 -1032
  22. package/index.js.map +1 -1
  23. package/key-bag-file-WADZBHYG.js +54 -0
  24. package/key-bag-file-WADZBHYG.js.map +1 -0
  25. package/key-bag-indexdb-PGVAI3FJ.js +50 -0
  26. package/key-bag-indexdb-PGVAI3FJ.js.map +1 -0
  27. package/mem-filesystem-YPPJV7Q2.js +41 -0
  28. package/mem-filesystem-YPPJV7Q2.js.map +1 -0
  29. package/metafile-cjs.json +1 -1
  30. package/metafile-esm.json +1 -1
  31. package/metafile-iife.json +1 -1
  32. package/node-filesystem-INX4ZTHE.js +45 -0
  33. package/node-filesystem-INX4ZTHE.js.map +1 -0
  34. package/package.json +12 -8
  35. package/tests/blockstore/fragment-gateway.test.ts +107 -0
  36. package/tests/blockstore/keyed-crypto.test.ts +332 -0
  37. package/tests/blockstore/loader.test.ts +24 -19
  38. package/tests/blockstore/store.test.ts +51 -40
  39. package/tests/blockstore/transaction.test.ts +19 -15
  40. package/tests/fireproof/all-gateway.test.ts +394 -0
  41. package/tests/fireproof/cars/bafkreidxwt2nhvbl4fnqfw3ctlt6zbrir4kqwmjo5im6rf4q5si27kgo2i.car +0 -0
  42. package/tests/fireproof/cars/bafkreidxwt2nhvbl4fnqfw3ctlt6zbrir4kqwmjo5im6rf4q5si27kgo2i.ts +316 -0
  43. package/tests/fireproof/config.test.ts +94 -78
  44. package/tests/fireproof/crdt.test.ts +34 -28
  45. package/tests/fireproof/database.test.ts +22 -14
  46. package/tests/fireproof/fireproof.test.fixture.ts +133 -0
  47. package/tests/fireproof/fireproof.test.ts +331 -219
  48. package/tests/fireproof/hello.test.ts +34 -18
  49. package/tests/fireproof/indexer.test.ts +34 -27
  50. package/tests/fireproof/utils.test.ts +84 -0
  51. package/tests/helpers.ts +28 -57
  52. package/tests/www/todo-local.html +1 -1
  53. package/tests/www/todo.html +12 -15
  54. package/utils-QO2HIWGI.js +14 -0
  55. package/utils-QO2HIWGI.js.map +1 -0
  56. package/chunk-BNL4PVBF.js +0 -314
  57. package/chunk-BNL4PVBF.js.map +0 -1
  58. package/chunk-JW2QT6BF.js +0 -184
  59. package/chunk-JW2QT6BF.js.map +0 -1
  60. package/node-sys-container-MIEX6ELJ.js +0 -29
  61. package/node-sys-container-MIEX6ELJ.js.map +0 -1
  62. package/store-file-VJ6BI4II.js +0 -191
  63. package/store-file-VJ6BI4II.js.map +0 -1
  64. package/store-indexdb-WLRSICCB.js.map +0 -1
package/index.js CHANGED
@@ -1,30 +1,33 @@
1
+ import {
2
+ FILESTORE_VERSION
3
+ } from "./chunk-7EWIAXTM.js";
4
+ import {
5
+ getFileName,
6
+ getFileSystem,
7
+ getPath,
8
+ toArrayBuffer
9
+ } from "./chunk-WS3YRPIA.js";
10
+ import {
11
+ INDEXDB_VERSION
12
+ } from "./chunk-PB4BKL4O.js";
1
13
  import {
2
14
  NotFoundError,
3
15
  Result,
16
+ UInt8ArrayEqual,
17
+ __export,
4
18
  dataDir,
5
- decodeFile,
6
- encodeFile,
7
19
  ensureLogger,
8
- exception2Result,
20
+ ensureSuperLog,
21
+ ensureSuperThis,
9
22
  exceptionWrapper,
10
23
  getKey,
11
24
  getName,
12
25
  getStore,
13
- isNotFoundError,
14
- runtime_exports,
15
- toCryptoOpts
16
- } from "./chunk-BNL4PVBF.js";
17
- import {
18
- SysContainer,
19
- __export,
20
- falsyToUndef,
21
- isFalsy,
22
- throwFalsy
23
- } from "./chunk-JW2QT6BF.js";
26
+ isNotFoundError
27
+ } from "./chunk-OFGPKRCM.js";
24
28
 
25
29
  // src/database.ts
26
- import { uuidv7 } from "uuidv7";
27
- import { ResolveOnce as ResolveOnce5 } from "@adviser/cement";
30
+ import { ResolveOnce as ResolveOnce6 } from "@adviser/cement";
28
31
 
29
32
  // src/write-queue.ts
30
33
  function writeQueue(worker, payload = Infinity, unbounded = false) {
@@ -67,13 +70,83 @@ function writeQueue(worker, payload = Infinity, unbounded = false) {
67
70
  }
68
71
 
69
72
  // src/crdt.ts
70
- import { ResolveOnce as ResolveOnce4 } from "@adviser/cement";
73
+ import { ResolveOnce as ResolveOnce5 } from "@adviser/cement";
74
+
75
+ // src/runtime/wait-pr-multiformats/block.ts
76
+ var block_exports = {};
77
+ __export(block_exports, {
78
+ Block: () => Block,
79
+ create: () => create,
80
+ createUnsafe: () => createUnsafe,
81
+ decode: () => decode,
82
+ encode: () => encode
83
+ });
84
+ import { bytes as binary, CID } from "multiformats";
85
+ import { Block as mfBlock } from "multiformats/block";
86
+ var Block = mfBlock;
87
+ async function decode({
88
+ bytes,
89
+ codec: codec3,
90
+ hasher: hasher7
91
+ }) {
92
+ if (bytes == null) throw new Error('Missing required argument "bytes"');
93
+ if (codec3 == null || hasher7 == null) throw new Error("Missing required argument: codec or hasher");
94
+ const value = await Promise.resolve(codec3.decode(bytes));
95
+ const hash = await hasher7.digest(bytes);
96
+ const cid = CID.create(1, codec3.code, hash);
97
+ return new mfBlock({ value, bytes, cid });
98
+ }
99
+ async function encode({
100
+ value,
101
+ codec: codec3,
102
+ hasher: hasher7
103
+ }) {
104
+ if (typeof value === "undefined") throw new Error('Missing required argument "value"');
105
+ if (codec3 == null || hasher7 == null) throw new Error("Missing required argument: codec or hasher");
106
+ const bytes = await Promise.resolve(codec3.encode(value));
107
+ const hash = await hasher7.digest(bytes);
108
+ const cid = CID.create(1, codec3.code, hash);
109
+ return new mfBlock({ value, bytes, cid });
110
+ }
111
+ async function create({
112
+ bytes,
113
+ cid,
114
+ hasher: hasher7,
115
+ codec: codec3
116
+ }) {
117
+ if (bytes == null) throw new Error('Missing required argument "bytes"');
118
+ if (hasher7 == null) throw new Error('Missing required argument "hasher"');
119
+ const value = await Promise.resolve(codec3.decode(bytes));
120
+ const hash = await hasher7.digest(bytes);
121
+ if (!binary.equals(cid.multihash.bytes, hash.bytes)) {
122
+ throw new Error("CID hash does not match bytes");
123
+ }
124
+ return createUnsafe({
125
+ bytes,
126
+ cid,
127
+ value,
128
+ codec: codec3
129
+ });
130
+ }
131
+ async function createUnsafe({
132
+ bytes,
133
+ cid,
134
+ value: maybeValue,
135
+ codec: codec3
136
+ }) {
137
+ const value = await Promise.resolve(maybeValue !== void 0 ? maybeValue : codec3?.decode(bytes));
138
+ if (value === void 0) throw new Error('Missing required argument, must either provide "value" or "codec"');
139
+ return new Block({
140
+ cid,
141
+ bytes,
142
+ value
143
+ });
144
+ }
71
145
 
72
146
  // src/crdt-helpers.ts
73
- import { encode as encode3, decode as decode3, Block as Block2 } from "multiformats/block";
74
- import { parse as parse2 } from "multiformats/link";
75
- import { sha256 as hasher2 } from "multiformats/hashes/sha2";
76
- import * as codec2 from "@ipld/dag-cbor";
147
+ import { parse as parse3 } from "multiformats/link";
148
+ import { sha256 as hasher5 } from "multiformats/hashes/sha2";
149
+ import * as codec from "@ipld/dag-cbor";
77
150
  import { put, get, entries, root } from "@web3-storage/pail/crdt";
78
151
  import { EventFetcher, vis } from "@web3-storage/pail/clock";
79
152
  import * as Batch from "@web3-storage/pail/crdt/batch";
@@ -84,512 +157,147 @@ __export(blockstore_exports, {
84
157
  BaseBlockstore: () => BaseBlockstore,
85
158
  CarTransaction: () => CarTransaction,
86
159
  CompactionFetcher: () => CompactionFetcher,
87
- ConnectREST: () => ConnectREST,
88
160
  ConnectionBase: () => ConnectionBase,
89
- DataStore: () => DataStore,
90
161
  EncryptedBlockstore: () => EncryptedBlockstore,
91
- Loadable: () => Loadable,
162
+ FragmentGateway: () => FragmentGateway,
92
163
  Loader: () => Loader,
93
- MetaStore: () => MetaStore,
94
- NotFoundError: () => NotFoundError,
95
- RemoteWAL: () => RemoteWAL,
96
- isNotFoundError: () => isNotFoundError,
164
+ addCryptoKeyToGatewayMetaPayload: () => addCryptoKeyToGatewayMetaPayload,
165
+ ensureStart: () => ensureStart,
166
+ getGatewayFromURL: () => getGatewayFromURL,
97
167
  parseCarFile: () => parseCarFile,
98
168
  registerStoreProtocol: () => registerStoreProtocol,
169
+ setCryptoKeyFromGatewayMetaPayload: () => setCryptoKeyFromGatewayMetaPayload,
99
170
  testStoreFactory: () => testStoreFactory,
100
- toStoreRuntime: () => toStoreRuntime,
101
- toURL: () => toURL
171
+ toCIDBlock: () => toCIDBlock,
172
+ toStoreRuntime: () => toStoreRuntime
102
173
  });
103
174
 
104
- // src/blockstore/connection-base.ts
105
- import { EventBlock, decodeEventBlock } from "@web3-storage/pail/clock";
106
- import { MemoryBlockstore } from "@web3-storage/pail/block";
175
+ // src/blockstore/types.ts
176
+ function toCIDBlock(block) {
177
+ return block;
178
+ }
107
179
 
108
- // src/blockstore/task-manager.ts
109
- var TaskManager = class {
110
- constructor(loader) {
111
- this.eventsWeHandled = /* @__PURE__ */ new Set();
112
- this.queue = [];
113
- this.isProcessing = false;
114
- this.loader = loader;
115
- this.logger = ensureLogger(loader.logger, "TaskManager");
116
- }
117
- async handleEvent(eventBlock) {
118
- const cid = eventBlock.cid.toString();
119
- const parents = eventBlock.value.parents.map((cid2) => cid2.toString());
120
- for (const parent of parents) {
121
- this.eventsWeHandled.add(parent);
122
- }
123
- this.queue.push({ cid, eventBlock, retries: 0 });
124
- this.queue = this.queue.filter(({ cid: cid2 }) => !this.eventsWeHandled.has(cid2));
125
- void this.processQueue();
126
- }
127
- async processQueue() {
128
- if (this.isProcessing) return;
129
- this.isProcessing = true;
130
- const filteredQueue = this.queue.filter(({ cid }) => !this.eventsWeHandled.has(cid));
131
- const first = filteredQueue[0];
132
- if (!first) {
133
- return;
134
- }
135
- try {
136
- this.loader?.remoteMetaStore?.handleByteHeads([first.eventBlock.value.data.dbMeta]);
137
- this.eventsWeHandled.add(first.cid);
138
- this.queue = this.queue.filter(({ cid }) => !this.eventsWeHandled.has(cid));
139
- } catch (err) {
140
- if (first.retries++ > 3) {
141
- this.logger.Error().Str("cid", first.cid).Msg("failed to process event block after 3 retries");
142
- this.queue = this.queue.filter(({ cid }) => cid !== first.cid);
143
- }
144
- await new Promise((resolve) => setTimeout(resolve, 50));
145
- throw this.logger.Error().Err(err).Msg("failed to process event block").AsError();
146
- } finally {
147
- this.isProcessing = false;
148
- if (this.queue.length > 0) {
149
- void this.processQueue();
150
- }
151
- }
152
- }
153
- };
180
+ // src/blockstore/store-factory.ts
181
+ import { KeyedResolvOnce as KeyedResolvOnce2, URI as URI5 } from "@adviser/cement";
154
182
 
155
- // src/blockstore/connection-base.ts
156
- var ConnectionBase = class {
157
- constructor(logger) {
158
- // readonly ready: Promise<unknown>;
159
- // todo move to LRU blockstore https://github.com/web3-storage/w3clock/blob/main/src/worker/block.js
160
- this.eventBlocks = new MemoryBlockstore();
161
- this.parents = [];
162
- this.loaded = Promise.resolve();
163
- this.logger = ensureLogger(logger, "ConnectionBase");
164
- }
165
- async refresh() {
166
- await throwFalsy(throwFalsy(this.loader).remoteMetaStore).load("main");
167
- await (await throwFalsy(this.loader).remoteWAL())._process();
168
- }
169
- connect({ loader }) {
170
- if (!loader) throw this.logger.Error().Msg("loader is required").AsError();
171
- this.connectMeta({ loader });
172
- this.connectStorage({ loader });
173
- }
174
- connectMeta({ loader }) {
175
- if (!loader) throw this.logger.Error().Msg("loader is required").AsError();
176
- this.loader = loader;
177
- this.taskManager = new TaskManager(loader);
178
- this.onConnect();
179
- this.logger.Warn().Msg("connectMeta: connecting to remote meta store is disabled");
180
- }
181
- async onConnect() {
182
- return;
183
- }
184
- connectStorage({ loader }) {
185
- if (!loader) throw this.logger.Error().Msg("loader is required").AsError();
186
- this.loader = loader;
187
- this.logger.Warn().Msg("connectStorage: connecting to remote meta store is disabled");
188
- }
189
- async createEventBlock(bytes) {
190
- const data = {
191
- dbMeta: bytes
192
- };
193
- const event = await EventBlock.create(
194
- data,
195
- this.parents
183
+ // src/runtime/files.ts
184
+ var files_exports = {};
185
+ __export(files_exports, {
186
+ decodeFile: () => decodeFile,
187
+ encodeFile: () => encodeFile
188
+ });
189
+ import * as UnixFS from "@ipld/unixfs";
190
+ import * as raw from "multiformats/codecs/raw";
191
+ import { withMaxChunkSize } from "@ipld/unixfs/file/chunker/fixed";
192
+ import { withWidth } from "@ipld/unixfs/file/layout/balanced";
193
+ import { exporter } from "ipfs-unixfs-exporter";
194
+ var queuingStrategy = UnixFS.withCapacity();
195
+ var settings = UnixFS.configure({
196
+ fileChunkEncoder: raw,
197
+ smallFileEncoder: raw,
198
+ chunker: withMaxChunkSize(1024 * 1024),
199
+ fileLayout: withWidth(1024)
200
+ });
201
+ async function collect(collectable) {
202
+ const chunks = [];
203
+ await collectable.pipeTo(
204
+ new WritableStream({
205
+ write(chunk) {
206
+ chunks.push(chunk);
207
+ }
208
+ })
209
+ );
210
+ return chunks;
211
+ }
212
+ async function encodeFile(blob) {
213
+ const readable = createFileEncoderStream(blob);
214
+ const blocks = await collect(readable);
215
+ return { cid: blocks.at(-1).cid, blocks };
216
+ }
217
+ async function decodeFile(blocks, cid, meta) {
218
+ const entry = await exporter(cid.toString(), blocks, { length: meta.size });
219
+ const chunks = [];
220
+ for await (const chunk of entry.content()) {
221
+ chunks.push(chunk);
222
+ }
223
+ return new File(chunks, entry.name, { type: meta.type, lastModified: 0 });
224
+ }
225
+ function createFileEncoderStream(blob) {
226
+ const { readable, writable } = new TransformStream({}, queuingStrategy);
227
+ const unixfsWriter = UnixFS.createWriter({ writable, settings });
228
+ const fileBuilder = new UnixFSFileBuilder("", blob);
229
+ void (async () => {
230
+ await fileBuilder.finalize(unixfsWriter);
231
+ await unixfsWriter.close();
232
+ })();
233
+ return readable;
234
+ }
235
+ var UnixFSFileBuilder = class {
236
+ #file;
237
+ constructor(name, file) {
238
+ this.name = name;
239
+ this.#file = file;
240
+ }
241
+ async finalize(writer) {
242
+ const unixfsFileWriter = UnixFS.createFileWriter(writer);
243
+ await this.#file.stream().pipeTo(
244
+ new WritableStream({
245
+ async write(chunk) {
246
+ await unixfsFileWriter.write(chunk);
247
+ }
248
+ })
196
249
  );
197
- await this.eventBlocks.put(event.cid, event.bytes);
198
- return event;
199
- }
200
- async decodeEventBlock(bytes) {
201
- const event = await decodeEventBlock(bytes);
202
- return event;
250
+ return await unixfsFileWriter.close();
203
251
  }
204
- // move this stuff to connect
205
- // async getDashboardURL(compact = true) {
206
- // const baseUrl = 'https://dashboard.fireproof.storage/'
207
- // if (!this.loader?.remoteCarStore) return new URL('/howto', baseUrl)
208
- // // if (compact) {
209
- // // await this.compact()
210
- // // }
211
- // const currents = await this.loader?.metaStore?.load()
212
- // if (!currents) throw new Error("Can't sync empty database: save data first")
213
- // if (currents.length > 1)
214
- // throw new Error("Can't sync database with split heads: make an update first")
215
- // const current = currents[0]
216
- // const params = {
217
- // car: current.car.toString()
218
- // }
219
- // if (current.key) {
220
- // // @ts-ignore
221
- // params.key = current.key.toString()
222
- // }
223
- // // @ts-ignore
224
- // if (this.name) {
225
- // // @ts-ignore
226
- // params.name = this.name
227
- // }
228
- // const url = new URL('/import#' + new URLSearchParams(params).toString(), baseUrl)
229
- // console.log('Import to dashboard: ' + url.toString())
230
- // return url
231
- // }
232
- // openDashboard() {
233
- // void this.getDashboardURL().then(url => {
234
- // if (url) window.open(url.toString(), '_blank')
235
- // })
236
- // }
237
252
  };
238
253
 
239
- // src/blockstore/connect-rest.ts
240
- var ConnectREST = class extends ConnectionBase {
241
- constructor(base, logger) {
242
- super(ensureLogger(logger, "ConnectREST"));
243
- this.baseUrl = new URL(base);
244
- }
245
- async dataUpload(bytes, params) {
246
- const carCid = params.car.toString();
247
- const uploadURL = new URL(`/cars/${carCid}.car`, this.baseUrl);
248
- const done = await fetch(uploadURL, { method: "PUT", body: bytes });
249
- if (!done.ok) {
250
- throw this.logger.Error().Msg("failed to upload data " + done.statusText);
251
- }
252
- }
253
- async dataDownload(params) {
254
- const { car } = params;
255
- const fetchFromUrl = new URL(`/cars/${car.toString()}.car`, this.baseUrl);
256
- const response = await fetch(fetchFromUrl);
257
- if (!response.ok) {
258
- return void 0;
259
- }
260
- const bytes = new Uint8Array(await response.arrayBuffer());
261
- return bytes;
254
+ // src/blockstore/store.ts
255
+ import pLimit2 from "p-limit";
256
+ import { format as format2, parse as parse2 } from "@ipld/dag-json";
257
+ import { exception2Result, ResolveOnce as ResolveOnce3, Result as Result5 } from "@adviser/cement";
258
+
259
+ // src/types.ts
260
+ function isFalsy(value) {
261
+ return value === false && value === null && value === void 0;
262
+ }
263
+ function throwFalsy(value) {
264
+ if (isFalsy(value)) {
265
+ throw new Error("value is Falsy");
262
266
  }
263
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
264
- async metaUpload(bytes, params) {
267
+ return value;
268
+ }
269
+ function falsyToUndef(value) {
270
+ if (isFalsy(value)) {
265
271
  return void 0;
266
272
  }
267
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
268
- async metaDownload(params) {
269
- return [];
270
- }
271
- };
272
-
273
- // src/blockstore/store-factory.ts
274
- import { KeyedResolvOnce } from "@adviser/cement";
275
-
276
- // src/blockstore/store.ts
277
- import pLimit2 from "p-limit";
278
- import { format, parse } from "@ipld/dag-json";
279
- import { ResolveOnce as ResolveOnce2, Result as Result2 } from "@adviser/cement";
273
+ return value;
274
+ }
280
275
 
281
276
  // src/blockstore/loader.ts
282
277
  import pLimit from "p-limit";
283
278
  import { CarReader } from "@ipld/car";
284
- import { ResolveOnce } from "@adviser/cement";
285
-
286
- // src/blockstore/types.ts
287
- function toCIDBlock(block) {
288
- return block;
289
- }
279
+ import { ResolveOnce as ResolveOnce2 } from "@adviser/cement";
290
280
 
291
281
  // src/blockstore/loader-helpers.ts
292
- import { encode, decode } from "multiformats/block";
293
282
  import { sha256 as hasher } from "multiformats/hashes/sha2";
294
- import * as raw from "multiformats/codecs/raw";
295
- import * as CBW from "@ipld/car/buffer-writer";
296
- import * as codec from "@ipld/dag-cbor";
297
- async function encodeCarFile(roots, t) {
298
- let size = 0;
299
- const headerSize = CBW.headerLength({ roots });
300
- size += headerSize;
301
- for (const { cid, bytes } of t.entries()) {
302
- size += CBW.blockLength({ cid, bytes });
303
- }
304
- const buffer = new Uint8Array(size);
305
- const writer = CBW.createWriter(buffer, { headerSize });
306
- for (const r of roots) {
307
- writer.addRoot(r);
308
- }
309
- for (const { cid, bytes } of t.entries()) {
310
- writer.write({ cid, bytes });
311
- }
312
- writer.close();
313
- return await encode({ value: writer.bytes, hasher, codec: raw });
314
- }
315
- async function encodeCarHeader(fp) {
316
- return await encode({
317
- value: { fp },
318
- hasher,
319
- codec
320
- });
321
- }
283
+ import * as dagCodec from "@ipld/dag-cbor";
322
284
  async function parseCarFile(reader, logger) {
323
285
  const roots = await reader.getRoots();
324
286
  const header = await reader.get(roots[0]);
325
287
  if (!header) throw logger.Error().Msg("missing header block").AsError();
326
- const { value } = await decode({ bytes: header.bytes, hasher, codec });
327
- const fpvalue = value;
288
+ const dec = await decode({ bytes: header.bytes, hasher, codec: dagCodec });
289
+ const fpvalue = dec.value;
328
290
  if (fpvalue && !fpvalue.fp) {
329
291
  throw logger.Error().Msg("missing fp").AsError();
330
292
  }
331
293
  return fpvalue.fp;
332
294
  }
333
295
 
334
- // src/blockstore/encrypt-helpers.ts
335
- import { sha256 } from "multiformats/hashes/sha2";
336
- import { CID as CID2 } from "multiformats";
337
- import { encode as encode2, decode as decode2, create as mfCreate } from "multiformats/block";
338
- import * as dagcbor from "@ipld/dag-cbor";
339
- import { MemoryBlockstore as MemoryBlockstore2 } from "@web3-storage/pail/block";
340
- import { bf } from "prolly-trees/utils";
341
- import { nocache as cache } from "prolly-trees/cache";
342
- import { create, load } from "prolly-trees/cid-set";
343
-
344
- // src/blockstore/encrypt-codec.ts
345
- import { CID } from "multiformats";
346
- function makeCodec(ilogger, crypto, randomBytes) {
347
- const logger = ensureLogger(ilogger, "makeCodec");
348
- const enc32 = (value) => {
349
- value = +value;
350
- const buff = new Uint8Array(4);
351
- buff[3] = value >>> 24;
352
- buff[2] = value >>> 16;
353
- buff[1] = value >>> 8;
354
- buff[0] = value & 255;
355
- return buff;
356
- };
357
- const readUInt32LE = (buffer) => {
358
- const offset = buffer.byteLength - 4;
359
- return (buffer[offset] | buffer[offset + 1] << 8 | buffer[offset + 2] << 16) + buffer[offset + 3] * 16777216;
360
- };
361
- const concat = (buffers) => {
362
- const uint8Arrays = buffers.map((b) => b instanceof ArrayBuffer ? new Uint8Array(b) : b);
363
- const totalLength = uint8Arrays.reduce((sum, arr) => sum + arr.length, 0);
364
- const result = new Uint8Array(totalLength);
365
- let offset = 0;
366
- for (const arr of uint8Arrays) {
367
- result.set(arr, offset);
368
- offset += arr.length;
369
- }
370
- return result;
371
- };
372
- const encode4 = ({ iv, bytes }) => concat([iv, bytes]);
373
- const decode4 = (bytes) => {
374
- const iv = bytes.subarray(0, 12);
375
- bytes = bytes.slice(12);
376
- return { iv, bytes };
377
- };
378
- const code = 3145728 + 1337;
379
- async function subtleKey(key) {
380
- return await crypto.importKey(
381
- "raw",
382
- // raw or jwk
383
- key,
384
- // raw data
385
- "AES-GCM",
386
- false,
387
- // extractable
388
- ["encrypt", "decrypt"]
389
- );
390
- }
391
- const decrypt = async ({ key, value }) => {
392
- const { bytes: inBytes, iv } = value;
393
- const cryKey = await subtleKey(key);
394
- const deBytes = await crypto.decrypt(
395
- {
396
- name: "AES-GCM",
397
- iv,
398
- tagLength: 128
399
- },
400
- cryKey,
401
- inBytes
402
- );
403
- const bytes = new Uint8Array(deBytes);
404
- const len = readUInt32LE(bytes.subarray(0, 4));
405
- const cid = CID.decode(bytes.subarray(4, 4 + len));
406
- return { cid, bytes: bytes.subarray(4 + len) };
407
- };
408
- const encrypt = async ({ key, cid, bytes }) => {
409
- const len = enc32(cid.bytes.byteLength);
410
- const iv = randomBytes(12);
411
- const msg = concat([len, cid.bytes, bytes]);
412
- try {
413
- const cryKey = await subtleKey(key);
414
- const deBytes = await crypto.encrypt(
415
- {
416
- name: "AES-GCM",
417
- iv,
418
- tagLength: 128
419
- },
420
- cryKey,
421
- msg
422
- );
423
- bytes = new Uint8Array(deBytes);
424
- } catch (e) {
425
- throw logger.Error().Err(e).Msg("encrypt failed").AsError();
426
- }
427
- return { value: { bytes, iv } };
428
- };
429
- const cryptoFn = (key) => {
430
- return { encrypt: (opts) => encrypt({ ...opts, key }), decrypt: (opts) => decrypt({ ...opts, key }) };
431
- };
432
- const name = "jchris@encrypted-block:aes-gcm";
433
- return { encode: encode4, decode: decode4, code, name, encrypt, decrypt, crypto: cryptoFn };
434
- }
435
-
436
- // src/blockstore/encrypt-helpers.ts
437
- function carLogIncludesGroup(list, cidMatch) {
438
- return list.some((cid) => {
439
- return cid.toString() === cidMatch.toString();
440
- });
441
- }
442
- function makeEncDec(logger, crypto, randomBytes) {
443
- const codec4 = makeCodec(logger, crypto, randomBytes);
444
- const encrypt = async function* ({
445
- get: get2,
446
- cids,
447
- hasher: hasher4,
448
- key,
449
- cache: cache3,
450
- chunker: chunker2,
451
- root: root3
452
- }) {
453
- const set = /* @__PURE__ */ new Set();
454
- let eroot;
455
- if (!carLogIncludesGroup(cids, root3)) cids.push(root3);
456
- for (const cid of cids) {
457
- const unencrypted = await get2(cid);
458
- if (!unencrypted) throw logger.Error().Ref("cid", cid).Msg("missing cid block").AsError();
459
- const encrypted = await codec4.encrypt({ ...unencrypted, key });
460
- const block2 = await encode2({ ...encrypted, codec: codec4, hasher: hasher4 });
461
- yield block2;
462
- set.add(block2.cid.toString());
463
- if (unencrypted.cid.equals(root3)) eroot = block2.cid;
464
- }
465
- if (!eroot) throw logger.Error().Msg("cids does not include root").AsError();
466
- const list = [...set].map((s) => CID2.parse(s));
467
- let last;
468
- for await (const node of create({ list, get: get2, cache: cache3, chunker: chunker2, hasher: hasher4, codec: dagcbor })) {
469
- const block2 = await node.block;
470
- yield block2;
471
- last = block2;
472
- }
473
- if (!last) throw logger.Error().Msg("missing last block").AsError();
474
- const head = [eroot, last.cid];
475
- const block = await encode2({ value: head, codec: dagcbor, hasher: hasher4 });
476
- yield block;
477
- };
478
- const decrypt = async function* ({
479
- root: root3,
480
- get: get2,
481
- key,
482
- cache: cache3,
483
- chunker: chunker2,
484
- hasher: hasher4
485
- }) {
486
- const getWithDecode = async (cid) => get2(cid).then(async (block) => {
487
- if (!block) return;
488
- const decoded = await decode2({ ...block, codec: dagcbor, hasher: hasher4 });
489
- return decoded;
490
- });
491
- const getWithDecrypt = async (cid) => get2(cid).then(async (block) => {
492
- if (!block) return;
493
- const decoded = await decode2({ ...block, codec: codec4, hasher: hasher4 });
494
- return decoded;
495
- });
496
- const decodedRoot = await getWithDecode(root3);
497
- if (!decodedRoot) throw logger.Error().Msg("missing root").AsError();
498
- if (!decodedRoot.bytes) throw logger.Error().Msg("missing bytes").AsError();
499
- const {
500
- value: [eroot, tree]
501
- } = decodedRoot;
502
- const rootBlock = await get2(eroot);
503
- if (!rootBlock) throw logger.Error().Msg("missing root block").AsError();
504
- const cidset = await load({ cid: tree, get: getWithDecode, cache: cache3, chunker: chunker2, codec: codec4, hasher: hasher4 });
505
- const { result: nodes } = await cidset.getAllEntries();
506
- const unwrap = async (eblock) => {
507
- if (!eblock) throw logger.Error().Msg("missing block").AsError();
508
- if (!eblock.value) {
509
- eblock = await decode2({ ...eblock, codec: codec4, hasher: hasher4 });
510
- if (!eblock.value) throw logger.Error().Msg("missing value").AsError();
511
- }
512
- const { bytes, cid } = await codec4.decrypt({ ...eblock, key }).catch((e) => {
513
- throw e;
514
- });
515
- const block = await mfCreate({ cid, bytes, hasher: hasher4, codec: codec4 });
516
- return block;
517
- };
518
- const promises = [];
519
- for (const { cid } of nodes) {
520
- if (!rootBlock.cid.equals(cid)) promises.push(getWithDecrypt(cid).then(unwrap));
521
- }
522
- yield* promises;
523
- yield unwrap(rootBlock);
524
- };
525
- return { encrypt, decrypt };
526
- }
527
- var chunker = bf(30);
528
- function hexStringToUint8Array(hexString) {
529
- const length = hexString.length;
530
- const uint8Array = new Uint8Array(length / 2);
531
- for (let i = 0; i < length; i += 2) {
532
- uint8Array[i / 2] = parseInt(hexString.substring(i, i + 2), 16);
533
- }
534
- return uint8Array;
535
- }
536
- async function encryptedEncodeCarFile(logger, crypto, key, rootCid, t) {
537
- const encryptionKey = hexStringToUint8Array(key);
538
- const encryptedBlocks = new MemoryBlockstore2();
539
- const cidsToEncrypt = [];
540
- for (const { cid, bytes } of t.entries()) {
541
- cidsToEncrypt.push(cid);
542
- const g = await t.get(cid);
543
- if (!g) throw logger.Error().Ref("cid", cid).Int("bytes", bytes.length).Msg("missing cid block").AsError();
544
- }
545
- let last = null;
546
- const { encrypt } = makeEncDec(logger, crypto, crypto.randomBytes);
547
- for await (const block of encrypt({
548
- cids: cidsToEncrypt,
549
- get: t.get.bind(t),
550
- key: encryptionKey,
551
- hasher: sha256,
552
- chunker,
553
- cache,
554
- root: rootCid
555
- })) {
556
- await encryptedBlocks.put(block.cid, block.bytes);
557
- last = block;
558
- }
559
- if (!last) throw logger.Error().Msg("no blocks encrypted").AsError();
560
- const encryptedCar = await encodeCarFile([last.cid], encryptedBlocks);
561
- return encryptedCar;
562
- }
563
- async function decodeEncryptedCar(logger, crypto, key, reader) {
564
- const roots = await reader.getRoots();
565
- const root3 = roots[0];
566
- return await decodeCarBlocks(logger, crypto, root3, reader.get.bind(reader), key);
567
- }
568
- async function decodeCarBlocks(logger, crypto, root3, get2, keyMaterial) {
569
- const decryptionKeyUint8 = hexStringToUint8Array(keyMaterial);
570
- const decryptionKey = decryptionKeyUint8.buffer.slice(0, decryptionKeyUint8.byteLength);
571
- const decryptedBlocks = new MemoryBlockstore2();
572
- let last = null;
573
- const { decrypt } = makeEncDec(logger, crypto, crypto.randomBytes);
574
- for await (const block of decrypt({
575
- root: root3,
576
- get: get2,
577
- key: decryptionKey,
578
- hasher: sha256,
579
- chunker,
580
- cache
581
- })) {
582
- await decryptedBlocks.put(block.cid, block.bytes);
583
- last = block;
584
- }
585
- if (!last) throw logger.Error().Msg("no blocks decrypted").AsError();
586
- return { blocks: decryptedBlocks, root: last.cid };
587
- }
588
-
589
296
  // src/blockstore/transaction.ts
590
- import { MemoryBlockstore as MemoryBlockstore3 } from "@web3-storage/pail/block";
591
- var CarTransaction = class extends MemoryBlockstore3 {
592
- constructor(parent, opts = { add: true }) {
297
+ import { MemoryBlockstore } from "@web3-storage/pail/block";
298
+ import { toCryptoRuntime } from "@adviser/cement";
299
+ var CarTransaction = class extends MemoryBlockstore {
300
+ constructor(parent, opts = { add: true, noLoader: false }) {
593
301
  super();
594
302
  if (opts.add) {
595
303
  parent.transactions.add(this);
@@ -603,8 +311,8 @@ var CarTransaction = class extends MemoryBlockstore3 {
603
311
  return super.get(cid);
604
312
  }
605
313
  };
606
- function defaultedBlockstoreRuntime(opts, component, ctx) {
607
- const logger = ensureLogger(opts, component, ctx);
314
+ function defaultedBlockstoreRuntime(sthis, opts, component, ctx) {
315
+ const logger = ensureLogger(sthis, component, ctx);
608
316
  const store = opts.store || {};
609
317
  return {
610
318
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -621,22 +329,24 @@ function defaultedBlockstoreRuntime(opts, component, ctx) {
621
329
  threshold: 1e3 * 1e3,
622
330
  ...opts,
623
331
  logger,
624
- crypto: toCryptoOpts(opts.crypto),
332
+ keyBag: opts.keyBag || {},
333
+ crypto: toCryptoRuntime(opts.crypto),
625
334
  store,
626
- storeRuntime: toStoreRuntime(store, logger)
335
+ storeRuntime: toStoreRuntime(store, sthis)
627
336
  };
628
337
  }
629
- var blockstoreFactory = function(opts) {
338
+ function blockstoreFactory(sthis, opts) {
630
339
  if (opts.name) {
631
- return new EncryptedBlockstore(opts);
340
+ return new EncryptedBlockstore(sthis, opts);
632
341
  } else {
633
342
  return new BaseBlockstore(opts);
634
343
  }
635
- };
344
+ }
636
345
  var BaseBlockstore = class {
637
346
  constructor(ebOpts = {}) {
638
347
  this.transactions = /* @__PURE__ */ new Set();
639
- this.ebOpts = defaultedBlockstoreRuntime(ebOpts, "BaseBlockstore");
348
+ this.sthis = ensureSuperThis(ebOpts);
349
+ this.ebOpts = defaultedBlockstoreRuntime(this.sthis, ebOpts, "BaseBlockstore");
640
350
  this.logger = this.ebOpts.logger;
641
351
  }
642
352
  // ready: Promise<void>;
@@ -659,8 +369,8 @@ var BaseBlockstore = class {
659
369
  throw this.logger.Error().Msg("use a transaction to put").AsError();
660
370
  }
661
371
  // TransactionMeta
662
- async transaction(fn, _opts = {}) {
663
- const t = new CarTransaction(this);
372
+ async transaction(fn, _opts) {
373
+ const t = new CarTransaction(this, _opts);
664
374
  const done = await fn(t);
665
375
  this.lastTxMeta = done;
666
376
  return { t, meta: done };
@@ -677,16 +387,16 @@ var BaseBlockstore = class {
677
387
  }
678
388
  };
679
389
  var EncryptedBlockstore = class extends BaseBlockstore {
680
- constructor(ebOpts) {
390
+ constructor(sthis, ebOpts) {
681
391
  super(ebOpts);
682
392
  this.compacting = false;
683
- this.logger = ensureLogger(ebOpts, "EncryptedBlockstore");
393
+ this.logger = ensureLogger(this.sthis, "EncryptedBlockstore");
684
394
  const { name } = ebOpts;
685
395
  if (!name) {
686
396
  throw this.logger.Error().Msg("name required").AsError();
687
397
  }
688
398
  this.name = name;
689
- this.loader = new Loader(this.name, ebOpts);
399
+ this.loader = new Loader(this.name, ebOpts, sthis);
690
400
  }
691
401
  ready() {
692
402
  return this.loader.ready();
@@ -717,10 +427,13 @@ var EncryptedBlockstore = class extends BaseBlockstore {
717
427
  }
718
428
  throw this.logger.Error().Msg("failed to commit car files").AsError();
719
429
  }
720
- async getFile(car, cid, isPublic = false) {
430
+ async getFile(car, cid) {
721
431
  await this.ready();
722
432
  if (!this.loader) throw this.logger.Error().Msg("loader required to get file, database must be named").AsError();
723
- const reader = await this.loader.loadFileCar(car, isPublic);
433
+ const reader = await this.loader.loadFileCar(
434
+ car
435
+ /*, isPublic */
436
+ );
724
437
  const block = await reader.get(cid);
725
438
  if (!block) throw this.logger.Error().Str("cid", cid.toString()).Msg(`Missing block`).AsError();
726
439
  return block.bytes;
@@ -776,10 +489,20 @@ var CompactionFetcher = class {
776
489
  };
777
490
 
778
491
  // src/blockstore/commit-queue.ts
492
+ import { Future } from "@adviser/cement";
779
493
  var CommitQueue = class {
780
494
  constructor() {
781
495
  this.queue = [];
782
496
  this.processing = false;
497
+ this._waitIdleItems = /* @__PURE__ */ new Set();
498
+ }
499
+ waitIdle() {
500
+ if (this.queue.length === 0 && !this.processing) {
501
+ return Promise.resolve();
502
+ }
503
+ const fn = new Future();
504
+ this._waitIdleItems.add(fn);
505
+ return fn.asPromise();
783
506
  }
784
507
  async enqueue(fn) {
785
508
  return new Promise((resolve, reject) => {
@@ -804,15 +527,370 @@ var CommitQueue = class {
804
527
  this.processing = true;
805
528
  const queueFn = this.queue.shift();
806
529
  if (queueFn) {
807
- queueFn();
530
+ queueFn().finally(() => {
531
+ });
532
+ }
533
+ }
534
+ if (this.queue.length === 0 && !this.processing) {
535
+ const toResolve = Array.from(this._waitIdleItems);
536
+ this._waitIdleItems.clear();
537
+ toResolve.map((fn) => fn.resolve());
538
+ }
539
+ }
540
+ };
541
+
542
+ // src/runtime/key-bag.ts
543
+ var key_bag_exports = {};
544
+ __export(key_bag_exports, {
545
+ KeyBag: () => KeyBag,
546
+ getKeyBag: () => getKeyBag,
547
+ registerKeyBagProviderFactory: () => registerKeyBagProviderFactory
548
+ });
549
+ import {
550
+ KeyedResolvOnce,
551
+ ResolveOnce,
552
+ ResolveSeq,
553
+ Result as Result2,
554
+ runtimeFn,
555
+ toCryptoRuntime as toCryptoRuntime2,
556
+ URI
557
+ } from "@adviser/cement";
558
+ import { base58btc } from "multiformats/bases/base58";
559
+ var KeyBag = class {
560
+ constructor(rt) {
561
+ this.rt = rt;
562
+ this._warnOnce = new ResolveOnce();
563
+ this._seq = new ResolveSeq();
564
+ this.logger = ensureLogger(rt.sthis, "KeyBag");
565
+ this.logger.Debug().Msg("KeyBag created");
566
+ }
567
+ async subtleKey(key) {
568
+ const extractable = this.rt.url.getParam("extractKey") === "_deprecated_internal_api";
569
+ if (extractable) {
570
+ this._warnOnce.once(
571
+ () => this.logger.Warn().Msg("extractKey is enabled via _deprecated_internal_api --- handle keys safely!!!")
572
+ );
573
+ }
574
+ return await this.rt.crypto.importKey(
575
+ "raw",
576
+ // raw or jwk
577
+ base58btc.decode(key),
578
+ // hexStringToUint8Array(key), // raw data
579
+ "AES-GCM",
580
+ extractable,
581
+ ["encrypt", "decrypt"]
582
+ );
583
+ }
584
+ async ensureKeyFromUrl(url, keyFactory) {
585
+ const storeKey = url.getParam("storekey");
586
+ if (storeKey === "insecure") {
587
+ return Result2.Ok(url);
588
+ }
589
+ if (!storeKey) {
590
+ const keyName = `@${keyFactory()}@`;
591
+ const ret = await this.getNamedKey(keyName);
592
+ if (ret.isErr()) {
593
+ return ret;
594
+ }
595
+ const urb = url.build().setParam("storekey", keyName);
596
+ return Result2.Ok(urb.URI());
597
+ }
598
+ if (storeKey.startsWith("@") && storeKey.endsWith("@")) {
599
+ const ret = await this.getNamedKey(storeKey);
600
+ if (ret.isErr()) {
601
+ return ret;
602
+ }
603
+ }
604
+ return Result2.Ok(url);
605
+ }
606
+ async toKeyWithFingerPrint(keyStr) {
607
+ const material = base58btc.decode(keyStr);
608
+ const key = await this.subtleKey(keyStr);
609
+ const fpr = await this.rt.crypto.digestSHA256(material);
610
+ return Result2.Ok({
611
+ key,
612
+ fingerPrint: base58btc.encode(new Uint8Array(fpr))
613
+ });
614
+ }
615
+ async setNamedKey(name, key) {
616
+ return this._seq.add(() => this._setNamedKey(name, key));
617
+ }
618
+ // avoid deadlock
619
+ async _setNamedKey(name, key) {
620
+ const item = {
621
+ name,
622
+ key
623
+ };
624
+ const bag = await this.rt.getBag();
625
+ this.logger.Debug().Str("name", name).Msg("setNamedKey");
626
+ await bag.set(name, item);
627
+ return await this.toKeyWithFingerPrint(item.key);
628
+ }
629
+ async getNamedExtractableKey(name, failIfNotFound = false) {
630
+ const ret = await this.getNamedKey(name, failIfNotFound);
631
+ if (ret.isErr()) {
632
+ return ret;
633
+ }
634
+ const named = ret.Ok();
635
+ return Result2.Ok({
636
+ ...named,
637
+ extract: async () => {
638
+ const ext = new Uint8Array(await this.rt.crypto.exportKey("raw", named.key));
639
+ return {
640
+ key: ext,
641
+ keyStr: base58btc.encode(ext)
642
+ };
643
+ }
644
+ });
645
+ }
646
+ async getNamedKey(name, failIfNotFound = false) {
647
+ const id = this.rt.sthis.nextId(4).str;
648
+ return this._seq.add(async () => {
649
+ const bag = await this.rt.getBag();
650
+ const named = await bag.get(name);
651
+ if (named) {
652
+ const fpr = await this.toKeyWithFingerPrint(named.key);
653
+ this.logger.Debug().Str("id", id).Str("name", name).Result("fpr", fpr).Msg("fingerPrint getNamedKey");
654
+ return fpr;
655
+ }
656
+ if (failIfNotFound) {
657
+ this.logger.Debug().Str("id", id).Str("name", name).Msg("failIfNotFound getNamedKey");
658
+ return Result2.Err(new Error(`Key not found: ${name}`));
659
+ }
660
+ const ret = await this._setNamedKey(name, base58btc.encode(this.rt.crypto.randomBytes(this.rt.keyLength)));
661
+ this.logger.Debug().Str("id", id).Str("name", name).Result("fpr", ret).Msg("createKey getNamedKey-post");
662
+ return ret;
663
+ });
664
+ }
665
+ };
666
+ var keyBagProviderFactories = new Map(
667
+ [
668
+ {
669
+ protocol: "file:",
670
+ factory: async (url, sthis) => {
671
+ const { KeyBagProviderFile } = await import("./key-bag-file-WADZBHYG.js");
672
+ return new KeyBagProviderFile(url, sthis);
673
+ }
674
+ },
675
+ {
676
+ protocol: "indexdb:",
677
+ factory: async (url, sthis) => {
678
+ const { KeyBagProviderIndexDB } = await import("./key-bag-indexdb-PGVAI3FJ.js");
679
+ return new KeyBagProviderIndexDB(url, sthis);
680
+ }
681
+ }
682
+ ].map((i) => [i.protocol, i])
683
+ );
684
+ function registerKeyBagProviderFactory(item) {
685
+ const protocol = item.protocol.endsWith(":") ? item.protocol : item.protocol + ":";
686
+ keyBagProviderFactories.set(protocol, {
687
+ ...item,
688
+ protocol
689
+ });
690
+ }
691
+ function defaultKeyBagOpts(sthis, kbo) {
692
+ if (kbo.keyRuntime) {
693
+ return kbo.keyRuntime;
694
+ }
695
+ const logger = ensureLogger(sthis, "KeyBag");
696
+ let url;
697
+ if (kbo.url) {
698
+ url = URI.from(kbo.url);
699
+ logger.Debug().Url(url).Msg("from opts");
700
+ } else {
701
+ let bagFnameOrUrl = sthis.env.get("FP_KEYBAG_URL");
702
+ if (runtimeFn().isBrowser) {
703
+ url = URI.from(bagFnameOrUrl || "indexdb://fp-keybag");
704
+ } else {
705
+ if (!bagFnameOrUrl) {
706
+ const home = sthis.env.get("HOME");
707
+ bagFnameOrUrl = `${home}/.fireproof/keybag`;
708
+ url = URI.from(`file://${bagFnameOrUrl}`);
709
+ } else {
710
+ url = URI.from(bagFnameOrUrl);
711
+ }
712
+ }
713
+ logger.Debug().Url(url).Msg("from env");
714
+ }
715
+ const kitem = keyBagProviderFactories.get(url.protocol);
716
+ if (!kitem) {
717
+ throw logger.Error().Url(url).Msg("unsupported protocol").AsError();
718
+ }
719
+ const getBag = async () => kitem.factory(url, sthis);
720
+ if (url.hasParam("masterkey")) {
721
+ throw logger.Error().Url(url).Msg("masterkey is not supported").AsError();
722
+ }
723
+ return {
724
+ url,
725
+ crypto: kbo.crypto || toCryptoRuntime2({}),
726
+ sthis,
727
+ logger,
728
+ keyLength: kbo.keyLength || 16,
729
+ getBag,
730
+ id: () => {
731
+ return url.toString();
732
+ }
733
+ };
734
+ }
735
+ var _keyBags = new KeyedResolvOnce();
736
+ async function getKeyBag(sthis, kbo = {}) {
737
+ await sthis.start();
738
+ const rt = defaultKeyBagOpts(sthis, kbo);
739
+ return _keyBags.get(rt.id()).once(async () => new KeyBag(rt));
740
+ }
741
+
742
+ // src/blockstore/commitor.ts
743
+ import * as CBW from "@ipld/car/buffer-writer";
744
+ import { sha256 as hasher2 } from "multiformats/hashes/sha2";
745
+ import * as dagCodec2 from "@ipld/dag-cbor";
746
+ async function encodeCarFile(roots, t, codec3) {
747
+ let size = 0;
748
+ const headerSize = CBW.headerLength({ roots });
749
+ size += headerSize;
750
+ for (const { cid, bytes } of t.entries()) {
751
+ size += CBW.blockLength({ cid, bytes });
752
+ }
753
+ const buffer = new Uint8Array(size);
754
+ const writer = CBW.createWriter(buffer, { headerSize });
755
+ for (const r of roots) {
756
+ writer.addRoot(r);
757
+ }
758
+ for (const { cid, bytes } of t.entries()) {
759
+ writer.write({ cid, bytes });
760
+ }
761
+ writer.close();
762
+ return await encode({ value: writer.bytes, hasher: hasher2, codec: codec3 });
763
+ }
764
+ async function createCarFile(encoder, cid, t) {
765
+ return encodeCarFile([cid], t, encoder);
766
+ }
767
+ async function commitFiles(fileStore, walStore, t, done) {
768
+ const { files: roots } = makeFileCarHeader(done);
769
+ const cids = [];
770
+ const codec3 = (await fileStore.keyedCrypto()).codec();
771
+ const cars = await prepareCarFilesFiles(codec3, roots, t);
772
+ for (const car of cars) {
773
+ const { cid, bytes } = car;
774
+ await fileStore.save({ cid, bytes });
775
+ await walStore.enqueueFile(
776
+ cid
777
+ /*, !!opts.public*/
778
+ );
779
+ cids.push(cid);
780
+ }
781
+ return cids;
782
+ }
783
+ function makeFileCarHeader(result) {
784
+ const files = [];
785
+ for (const [, meta] of Object.entries(result.files || {})) {
786
+ if (meta && typeof meta === "object" && "cid" in meta && meta !== null) {
787
+ files.push(meta.cid);
788
+ }
789
+ }
790
+ return { ...result, files };
791
+ }
792
+ async function prepareCarFilesFiles(encoder, roots, t) {
793
+ return [await encodeCarFile(roots, t, encoder)];
794
+ }
795
+ function makeCarHeader(meta, cars, compact = false) {
796
+ const coreHeader = compact ? { cars: [], compact: cars } : { cars, compact: [] };
797
+ return { ...coreHeader, meta };
798
+ }
799
+ async function encodeCarHeader(fp) {
800
+ return await encode({
801
+ value: { fp },
802
+ hasher: hasher2,
803
+ codec: dagCodec2
804
+ });
805
+ }
806
+ async function commit(params, t, done, opts = { noLoader: false, compact: false }) {
807
+ const fp = makeCarHeader(done, params.carLog, !!opts.compact);
808
+ const rootBlock = await encodeCarHeader(fp);
809
+ const cars = await prepareCarFiles(params.encoder, params.threshold, rootBlock, t);
810
+ const cids = [];
811
+ for (const car of cars) {
812
+ const { cid, bytes } = car;
813
+ await params.carStore.save({ cid, bytes });
814
+ cids.push(cid);
815
+ }
816
+ const newDbMeta = { cars: cids };
817
+ await params.WALStore.enqueue(newDbMeta, opts);
818
+ await params.metaStore.save(newDbMeta);
819
+ return { cgrp: cids, header: fp };
820
+ }
821
+ async function prepareCarFiles(encoder, threshold, rootBlock, t) {
822
+ const carFiles = [];
823
+ threshold = threshold || 128e3 * 8;
824
+ let clonedt = new CarTransaction(t.parent, { add: false, noLoader: false });
825
+ clonedt.putSync(rootBlock.cid, rootBlock.bytes);
826
+ let newsize = CBW.blockLength(toCIDBlock(rootBlock));
827
+ let cidRootBlock = rootBlock;
828
+ for (const { cid, bytes } of t.entries()) {
829
+ newsize += CBW.blockLength(toCIDBlock({ cid, bytes }));
830
+ if (newsize >= threshold) {
831
+ carFiles.push(await createCarFile(encoder, cidRootBlock.cid, clonedt));
832
+ clonedt = new CarTransaction(t.parent, { add: false, noLoader: false });
833
+ clonedt.putSync(cid, bytes);
834
+ cidRootBlock = { cid, bytes };
835
+ newsize = CBW.blockLength(toCIDBlock({ cid, bytes }));
836
+ } else {
837
+ clonedt.putSync(cid, bytes);
838
+ }
839
+ }
840
+ carFiles.push(await createCarFile(encoder, cidRootBlock.cid, clonedt));
841
+ return carFiles;
842
+ }
843
+
844
+ // src/blockstore/loader.ts
845
+ import { sha256 as hasher3 } from "multiformats/hashes/sha2";
846
+
847
+ // src/blockstore/task-manager.ts
848
+ var TaskManager = class {
849
+ constructor(sthis, callback) {
850
+ this.eventsWeHandled = /* @__PURE__ */ new Set();
851
+ this.queue = [];
852
+ this.isProcessing = false;
853
+ this.logger = ensureLogger(sthis, "TaskManager");
854
+ this.callback = callback;
855
+ }
856
+ async handleEvent(cid, parents, dbMeta) {
857
+ for (const parent of parents) {
858
+ this.eventsWeHandled.add(parent.toString());
859
+ }
860
+ this.queue.push({ cid: cid.toString(), dbMeta, retries: 0 });
861
+ this.queue = this.queue.filter(({ cid: cid2 }) => !this.eventsWeHandled.has(cid2));
862
+ void this.processQueue();
863
+ }
864
+ async processQueue() {
865
+ if (this.isProcessing) return;
866
+ this.isProcessing = true;
867
+ const filteredQueue = this.queue.filter(({ cid }) => !this.eventsWeHandled.has(cid));
868
+ const first = filteredQueue[0];
869
+ if (!first) {
870
+ return;
871
+ }
872
+ try {
873
+ await this.callback(first.dbMeta);
874
+ this.eventsWeHandled.add(first.cid);
875
+ this.queue = this.queue.filter(({ cid }) => !this.eventsWeHandled.has(cid));
876
+ } catch (err) {
877
+ if (first.retries++ > 3) {
878
+ this.logger.Error().Str("cid", first.cid).Msg("failed to process event block after 3 retries");
879
+ this.queue = this.queue.filter(({ cid }) => cid !== first.cid);
880
+ }
881
+ await new Promise((resolve) => setTimeout(resolve, 50));
882
+ throw this.logger.Error().Err(err).Msg("failed to process event block").AsError();
883
+ } finally {
884
+ this.isProcessing = false;
885
+ if (this.queue.length > 0) {
886
+ void this.processQueue();
808
887
  }
809
888
  }
810
889
  }
811
890
  };
812
891
 
813
892
  // src/blockstore/loader.ts
814
- import * as CBW2 from "@ipld/car/buffer-writer";
815
- function carLogIncludesGroup2(list, cids) {
893
+ function carLogIncludesGroup(list, cids) {
816
894
  return list.some((arr) => {
817
895
  return arr.toString() === cids.toString();
818
896
  });
@@ -825,17 +903,8 @@ function uniqueCids(list, remove = /* @__PURE__ */ new Set()) {
825
903
  }
826
904
  return [...byString.values()];
827
905
  }
828
- function toHexString(byteArray) {
829
- return Array.from(byteArray).map((byte) => byte.toString(16).padStart(2, "0")).join("");
830
- }
831
- var Loadable = class {
832
- constructor() {
833
- this.name = "";
834
- this.carLog = new Array();
835
- }
836
- };
837
906
  var Loader = class {
838
- constructor(name, ebOpts) {
907
+ constructor(name, ebOpts, sthis) {
839
908
  this.commitQueue = new CommitQueue();
840
909
  this.isCompacting = false;
841
910
  this.carReaders = /* @__PURE__ */ new Map();
@@ -845,9 +914,11 @@ var Loader = class {
845
914
  this.getBlockCache = /* @__PURE__ */ new Map();
846
915
  this.seenMeta = /* @__PURE__ */ new Set();
847
916
  this.writeLimit = pLimit(1);
848
- this.onceReady = new ResolveOnce();
917
+ this.onceReady = new ResolveOnce2();
849
918
  this.name = name;
919
+ this.sthis = sthis;
850
920
  this.ebOpts = defaultedBlockstoreRuntime(
921
+ sthis,
851
922
  {
852
923
  ...ebOpts,
853
924
  name
@@ -855,34 +926,42 @@ var Loader = class {
855
926
  "Loader"
856
927
  );
857
928
  this.logger = this.ebOpts.logger;
929
+ this.taskManager = new TaskManager(sthis, async (dbMeta) => {
930
+ await this.handleDbMetasFromStore([dbMeta]);
931
+ });
858
932
  }
859
933
  // readonly id = uuidv4();
934
+ async keyBag() {
935
+ return getKeyBag(this.sthis, this.ebOpts.keyBag);
936
+ }
860
937
  async carStore() {
861
938
  return this.ebOpts.storeRuntime.makeDataStore(this);
862
939
  }
863
940
  async fileStore() {
864
941
  return this.ebOpts.storeRuntime.makeDataStore(this);
865
942
  }
866
- async remoteWAL() {
867
- return this.ebOpts.storeRuntime.makeRemoteWAL(this);
943
+ async WALStore() {
944
+ return this.ebOpts.storeRuntime.makeWALStore(this);
868
945
  }
869
946
  async metaStore() {
870
947
  return this.ebOpts.storeRuntime.makeMetaStore(this);
871
948
  }
872
949
  async ready() {
873
950
  return this.onceReady.once(async () => {
874
- const metas = this.ebOpts.meta ? [this.ebOpts.meta] : await (await this.metaStore()).load("main");
875
- if (metas) {
951
+ const metas = await (await this.metaStore()).load();
952
+ if (this.ebOpts.meta) {
953
+ await this.handleDbMetasFromStore([this.ebOpts.meta]);
954
+ } else if (metas) {
876
955
  await this.handleDbMetasFromStore(metas);
877
956
  }
878
957
  });
879
958
  }
880
959
  async close() {
881
- const toClose = await Promise.all([this.carStore(), this.metaStore(), this.fileStore(), this.remoteWAL()]);
960
+ const toClose = await Promise.all([this.carStore(), this.metaStore(), this.fileStore(), this.WALStore()]);
882
961
  await Promise.all(toClose.map((store) => store.close()));
883
962
  }
884
963
  async destroy() {
885
- const toDestroy = await Promise.all([this.carStore(), this.metaStore(), this.fileStore(), this.remoteWAL()]);
964
+ const toDestroy = await Promise.all([this.carStore(), this.metaStore(), this.fileStore(), this.WALStore()]);
886
965
  await Promise.all(toDestroy.map((store) => store.destroy()));
887
966
  }
888
967
  // async snapToCar(carCid: AnyLink | string) {
@@ -896,6 +975,7 @@ var Loader = class {
896
975
  // await this._applyCarHeader(carHeader, true)
897
976
  // }
898
977
  async handleDbMetasFromStore(metas) {
978
+ this.logger.Debug().Any("metas", metas).Msg("handleDbMetasFromStore");
899
979
  for (const meta of metas) {
900
980
  await this.writeLimit(async () => {
901
981
  await this.mergeDbMetaIntoClock(meta);
@@ -908,10 +988,7 @@ var Loader = class {
908
988
  }
909
989
  if (this.seenMeta.has(meta.cars.toString())) return;
910
990
  this.seenMeta.add(meta.cars.toString());
911
- if (meta.key) {
912
- await this.setKey(meta.key);
913
- }
914
- if (carLogIncludesGroup2(this.carLog, meta.cars)) {
991
+ if (carLogIncludesGroup(this.carLog, meta.cars)) {
915
992
  return;
916
993
  }
917
994
  const carHeader = await this.loadCarHeaderFromMeta(meta);
@@ -920,45 +997,60 @@ var Loader = class {
920
997
  this.carLog = [...uniqueCids([meta.cars, ...this.carLog, ...carHeader.cars], this.seenCompacted)];
921
998
  await this.ebOpts.applyMeta?.(carHeader.meta);
922
999
  }
923
- async ingestKeyFromMeta(meta) {
924
- const { key } = meta;
925
- if (key) {
926
- await this.setKey(key);
927
- }
928
- }
1000
+ // protected async ingestKeyFromMeta(meta: DbMeta): Promise<void> {
1001
+ // const { key } = meta;
1002
+ // if (key) {
1003
+ // await this.setKey(key);
1004
+ // }
1005
+ // }
929
1006
  async loadCarHeaderFromMeta({ cars: cids }) {
930
1007
  const reader = await this.loadCar(cids[0]);
931
1008
  return await parseCarFile(reader, this.logger);
932
1009
  }
933
- async _getKey() {
934
- if (this.key) return this.key;
935
- if (!this.ebOpts.public) {
936
- await this.setKey(toHexString(this.ebOpts.crypto.randomBytes(32)));
937
- }
938
- return this.key || void 0;
939
- }
940
- async commitFiles(t, done, opts = { noLoader: false, compact: false }) {
941
- return this.commitQueue.enqueue(() => this._commitInternalFiles(t, done, opts));
942
- }
943
- // can these skip the queue? or have a file queue?
944
- async _commitInternalFiles(t, done, opts = { noLoader: false, compact: false }) {
1010
+ // async _getKey(): Promise<string | undefined> {
1011
+ // if (this.key) return this.key;
1012
+ // // generate a random key
1013
+ // if (!this.ebOpts.public) {
1014
+ // await this.setKey(toHexString(this.ebOpts.crypto.randomBytes(32)));
1015
+ // }
1016
+ // return this.key || undefined;
1017
+ // }
1018
+ async commitFiles(t, done) {
945
1019
  await this.ready();
946
- const { files: roots } = this.makeFileCarHeader(done);
947
- const cids = [];
948
- const cars = await this.prepareCarFilesFiles(roots, t, !!opts.public);
949
- for (const car of cars) {
950
- const { cid, bytes } = car;
951
- await (await this.fileStore()).save({ cid, bytes });
952
- await (await this.remoteWAL()).enqueueFile(cid, !!opts.public);
953
- cids.push(cid);
954
- }
955
- return cids;
1020
+ const fstore = await this.fileStore();
1021
+ const wstore = await this.WALStore();
1022
+ return this.commitQueue.enqueue(() => commitFiles(fstore, wstore, t, done));
956
1023
  }
957
- async loadFileCar(cid, isPublic = false) {
958
- return await this.storesLoadCar(cid, await this.fileStore(), this.remoteFileStore, isPublic);
1024
+ async loadFileCar(cid) {
1025
+ return await this.storesLoadCar(cid, await this.fileStore(), this.remoteFileStore);
959
1026
  }
960
1027
  async commit(t, done, opts = { noLoader: false, compact: false }) {
961
- return this.commitQueue.enqueue(() => this._commitInternal(t, done, opts));
1028
+ await this.ready();
1029
+ const fstore = await this.fileStore();
1030
+ const params = {
1031
+ encoder: (await fstore.keyedCrypto()).codec(),
1032
+ carLog: this.carLog,
1033
+ carStore: fstore,
1034
+ WALStore: await this.WALStore(),
1035
+ metaStore: await this.metaStore(),
1036
+ threshold: this.ebOpts.threshold
1037
+ };
1038
+ return this.commitQueue.enqueue(async () => {
1039
+ await this.cacheTransaction(t);
1040
+ const ret = await commit(params, t, done, opts);
1041
+ await this.updateCarLog(ret.cgrp, ret.header, !!opts.compact);
1042
+ return ret.cgrp;
1043
+ });
1044
+ }
1045
+ async updateCarLog(cids, fp, compact) {
1046
+ if (compact) {
1047
+ const previousCompactCid = fp.compact[fp.compact.length - 1];
1048
+ fp.compact.map((c) => c.toString()).forEach(this.seenCompacted.add, this.seenCompacted);
1049
+ this.carLog = [...uniqueCids([...this.carLog, ...fp.cars, cids], this.seenCompacted)];
1050
+ await this.removeCidsForCompact(previousCompactCid[0]).catch((e) => e);
1051
+ } else {
1052
+ this.carLog.unshift(cids);
1053
+ }
962
1054
  }
963
1055
  async cacheTransaction(t) {
964
1056
  for await (const block of t.entries()) {
@@ -978,79 +1070,6 @@ var Loader = class {
978
1070
  }
979
1071
  }
980
1072
  }
981
- async _commitInternal(t, done, opts = { noLoader: false, compact: false }) {
982
- await this.ready();
983
- const fp = this.makeCarHeader(done, this.carLog, !!opts.compact);
984
- const rootBlock = await encodeCarHeader(fp);
985
- const cars = await this.prepareCarFiles(rootBlock, t, !!opts.public);
986
- const cids = [];
987
- for (const car of cars) {
988
- const { cid, bytes } = car;
989
- await (await this.carStore()).save({ cid, bytes });
990
- cids.push(cid);
991
- }
992
- await this.cacheTransaction(t);
993
- const newDbMeta = { cars: cids, key: this.key || null };
994
- await (await this.remoteWAL()).enqueue(newDbMeta, opts);
995
- await (await this.metaStore()).save(newDbMeta);
996
- await this.updateCarLog(cids, fp, !!opts.compact);
997
- return cids;
998
- }
999
- async prepareCarFilesFiles(roots, t, isPublic) {
1000
- const theKey = isPublic ? null : await this._getKey();
1001
- const car = theKey && this.ebOpts.crypto ? await encryptedEncodeCarFile(this.logger, this.ebOpts.crypto, theKey, roots[0], t) : await encodeCarFile(roots, t);
1002
- return [car];
1003
- }
1004
- async prepareCarFiles(rootBlock, t, isPublic) {
1005
- const theKey = isPublic ? void 0 : await this._getKey();
1006
- const carFiles = [];
1007
- const threshold = this.ebOpts.threshold || 1e3 * 1e3;
1008
- let clonedt = new CarTransaction(t.parent, { add: false });
1009
- clonedt.putSync(rootBlock.cid, rootBlock.bytes);
1010
- let newsize = CBW2.blockLength(toCIDBlock(rootBlock));
1011
- let cidRootBlock = rootBlock;
1012
- for (const { cid, bytes } of t.entries()) {
1013
- newsize += CBW2.blockLength(toCIDBlock({ cid, bytes }));
1014
- if (newsize >= threshold) {
1015
- carFiles.push(await this.createCarFile(theKey, cidRootBlock.cid, clonedt));
1016
- clonedt = new CarTransaction(t.parent, { add: false });
1017
- clonedt.putSync(cid, bytes);
1018
- cidRootBlock = { cid, bytes };
1019
- newsize = CBW2.blockLength(toCIDBlock({ cid, bytes }));
1020
- } else {
1021
- clonedt.putSync(cid, bytes);
1022
- }
1023
- }
1024
- carFiles.push(await this.createCarFile(theKey, cidRootBlock.cid, clonedt));
1025
- return carFiles;
1026
- }
1027
- async createCarFile(theKey, cid, t) {
1028
- try {
1029
- return theKey && this.ebOpts.crypto ? await encryptedEncodeCarFile(this.logger, this.ebOpts.crypto, theKey, cid, t) : await encodeCarFile([cid], t);
1030
- } catch (e) {
1031
- console.error("error creating car file", e);
1032
- throw e;
1033
- }
1034
- }
1035
- makeFileCarHeader(result) {
1036
- const files = [];
1037
- for (const [, meta] of Object.entries(result.files || {})) {
1038
- if (meta && typeof meta === "object" && "cid" in meta && meta !== null) {
1039
- files.push(meta.cid);
1040
- }
1041
- }
1042
- return { ...result, files };
1043
- }
1044
- async updateCarLog(cids, fp, compact) {
1045
- if (compact) {
1046
- const previousCompactCid = fp.compact[fp.compact.length - 1];
1047
- fp.compact.map((c) => c.toString()).forEach(this.seenCompacted.add, this.seenCompacted);
1048
- this.carLog = [...uniqueCids([...this.carLog, ...fp.cars, cids], this.seenCompacted)];
1049
- await this.removeCidsForCompact(previousCompactCid[0]);
1050
- } else {
1051
- this.carLog.unshift(cids);
1052
- }
1053
- }
1054
1073
  async removeCidsForCompact(cid) {
1055
1074
  const carHeader = await this.loadCarHeaderFromMeta({
1056
1075
  cars: [cid]
@@ -1069,9 +1088,9 @@ var Loader = class {
1069
1088
  // await this.remoteWAL!.enqueue(dbMeta, { public: false })
1070
1089
  // }
1071
1090
  // }
1072
- async *entries(cache3 = true) {
1091
+ async *entries(cache2 = true) {
1073
1092
  await this.ready();
1074
- if (cache3) {
1093
+ if (cache2) {
1075
1094
  for (const [, block] of this.getBlockCache) {
1076
1095
  yield block;
1077
1096
  }
@@ -1153,105 +1172,521 @@ var Loader = class {
1153
1172
  }
1154
1173
  return got;
1155
1174
  }
1156
- makeCarHeader(meta, cars, compact = false) {
1157
- const coreHeader = compact ? { cars: [], compact: cars } : { cars, compact: [] };
1158
- return { ...coreHeader, meta };
1159
- }
1160
1175
  async loadCar(cid) {
1161
1176
  if (!this.carStore) {
1162
1177
  throw this.logger.Error().Msg("car store not initialized").AsError();
1163
1178
  }
1164
- const loaded = await this.storesLoadCar(cid, await this.carStore(), this.remoteCarStore);
1165
- return loaded;
1179
+ const loaded = await this.storesLoadCar(cid, await this.carStore(), this.remoteCarStore);
1180
+ return loaded;
1181
+ }
1182
+ async makeDecoderAndCarReader(cid, local, remote) {
1183
+ const cidsString = cid.toString();
1184
+ let loadedCar = void 0;
1185
+ let activeStore = local;
1186
+ try {
1187
+ this.logger.Debug().Str("cid", cidsString).Msg("loading car");
1188
+ loadedCar = await local.load(cid);
1189
+ this.logger.Debug().Bool("loadedCar", loadedCar).Msg("loaded");
1190
+ } catch (e) {
1191
+ if (remote) {
1192
+ const remoteCar = await remote.load(cid);
1193
+ if (remoteCar) {
1194
+ this.logger.Debug().Ref("cid", remoteCar.cid).Msg("saving remote car locally");
1195
+ await local.save(remoteCar);
1196
+ loadedCar = remoteCar;
1197
+ activeStore = remote;
1198
+ }
1199
+ } else {
1200
+ this.logger.Error().Str("cid", cidsString).Err(e).Msg("loading car");
1201
+ }
1202
+ }
1203
+ if (!loadedCar) {
1204
+ throw this.logger.Error().Url(local.url()).Str("cid", cidsString).Msg("missing car files").AsError();
1205
+ }
1206
+ const bytes = await decode({ bytes: loadedCar.bytes, hasher: hasher3, codec: (await activeStore.keyedCrypto()).codec() });
1207
+ const rawReader = await CarReader.fromBytes(bytes.value);
1208
+ const readerP = Promise.resolve(rawReader);
1209
+ const cachedReaderP = readerP.then(async (reader) => {
1210
+ await this.cacheCarReader(cidsString, reader).catch((e) => {
1211
+ this.logger.Error().Err(e).Str("cid", cidsString).Msg("error caching car reader");
1212
+ return;
1213
+ });
1214
+ return reader;
1215
+ });
1216
+ this.carReaders.set(cidsString, cachedReaderP);
1217
+ return readerP;
1218
+ }
1219
+ //What if instead it returns an Array of CarHeader
1220
+ async storesLoadCar(cid, local, remote) {
1221
+ const cidsString = cid.toString();
1222
+ let dacr = this.carReaders.get(cidsString);
1223
+ if (!dacr) {
1224
+ dacr = this.makeDecoderAndCarReader(cid, local, remote);
1225
+ this.carReaders.set(cidsString, dacr);
1226
+ }
1227
+ return dacr;
1228
+ }
1229
+ async getMoreReaders(cids) {
1230
+ const limit = pLimit(5);
1231
+ const missing = cids.filter((cid) => !this.carReaders.has(cid.toString()));
1232
+ await Promise.all(missing.map((cid) => limit(() => this.loadCar(cid))));
1233
+ }
1234
+ };
1235
+
1236
+ // src/runtime/keyed-crypto.ts
1237
+ var keyed_crypto_exports = {};
1238
+ __export(keyed_crypto_exports, {
1239
+ BlockIvKeyIdCodec: () => BlockIvKeyIdCodec,
1240
+ keyedCryptoFactory: () => keyedCryptoFactory
1241
+ });
1242
+ import { base58btc as base58btc2 } from "multiformats/bases/base58";
1243
+ import { sha256 as hasher4 } from "multiformats/hashes/sha2";
1244
+ import * as CBOR from "cborg";
1245
+ var generateIV = {
1246
+ random: {
1247
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1248
+ calc: async (ko, crypto, data) => {
1249
+ return crypto.randomBytes(ko.ivLength);
1250
+ },
1251
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1252
+ verify: async (ko, crypto, iv, data) => {
1253
+ return true;
1254
+ }
1255
+ },
1256
+ hash: {
1257
+ calc: async (ko, crypto, data) => {
1258
+ const hash = await hasher4.digest(data);
1259
+ const hashBytes = new Uint8Array(hash.bytes);
1260
+ const hashArray = new Uint8Array(ko.ivLength);
1261
+ for (let i = 0; i < hashBytes.length; i++) {
1262
+ hashArray[i % ko.ivLength] ^= hashBytes[i];
1263
+ }
1264
+ return hashArray;
1265
+ },
1266
+ verify: async function(ko, crypto, iv, data) {
1267
+ return ko.url.getParam("ivverify") !== "disable" && UInt8ArrayEqual(iv, await this.calc(ko, crypto, data));
1268
+ }
1269
+ }
1270
+ };
1271
+ function getGenerateIVFn(url, opts) {
1272
+ const ivhash = opts.ivCalc || url.getParam("ivhash") || "hash";
1273
+ return generateIV[ivhash] || generateIV["hash"];
1274
+ }
1275
+ var BlockIvKeyIdCodec = class {
1276
+ constructor(ko, iv, opts) {
1277
+ this.code = 3147065;
1278
+ this.name = "Fireproof@encrypted-block:aes-gcm";
1279
+ this.ko = ko;
1280
+ this.iv = iv;
1281
+ this.opts = opts || {};
1282
+ }
1283
+ async encode(data) {
1284
+ const calcIv = this.iv || await getGenerateIVFn(this.ko.url, this.opts).calc(this.ko, this.ko.crypto, data);
1285
+ const { iv } = this.ko.algo(calcIv);
1286
+ const fprt = await this.ko.fingerPrint();
1287
+ const keyId = base58btc2.decode(fprt);
1288
+ this.ko.logger.Debug().Str("fp", fprt).Msg("encode");
1289
+ return CBOR.encode({
1290
+ iv,
1291
+ keyId,
1292
+ data: await this.ko._encrypt({ iv, bytes: data })
1293
+ });
1294
+ }
1295
+ async decode(abytes) {
1296
+ let bytes;
1297
+ if (abytes instanceof Uint8Array) {
1298
+ bytes = abytes;
1299
+ } else {
1300
+ bytes = new Uint8Array(abytes);
1301
+ }
1302
+ const { iv, keyId, data } = CBOR.decode(bytes);
1303
+ const fprt = await this.ko.fingerPrint();
1304
+ this.ko.logger.Debug().Str("fp", base58btc2.encode(keyId)).Msg("decode");
1305
+ if (base58btc2.encode(keyId) !== fprt) {
1306
+ throw this.ko.logger.Error().Str("fp", fprt).Str("keyId", base58btc2.encode(keyId)).Msg("keyId mismatch").AsError();
1307
+ }
1308
+ const result = await this.ko._decrypt({ iv, bytes: data });
1309
+ if (!this.opts?.noIVVerify && !await getGenerateIVFn(this.ko.url, this.opts).verify(this.ko, this.ko.crypto, iv, result)) {
1310
+ throw this.ko.logger.Error().Msg("iv missmatch").AsError();
1311
+ }
1312
+ return result;
1313
+ }
1314
+ };
1315
+ var keyedCrypto = class {
1316
+ constructor(url, key, cyopt, sthis) {
1317
+ this.ivLength = 12;
1318
+ this.isEncrypting = true;
1319
+ this.logger = ensureLogger(sthis, "keyedCrypto");
1320
+ this.crypto = cyopt;
1321
+ this.key = key;
1322
+ this.url = url;
1323
+ }
1324
+ fingerPrint() {
1325
+ return Promise.resolve(this.key.fingerPrint);
1326
+ }
1327
+ codec(iv, opts) {
1328
+ return new BlockIvKeyIdCodec(this, iv, opts);
1329
+ }
1330
+ algo(iv) {
1331
+ return {
1332
+ name: "AES-GCM",
1333
+ iv: iv || this.crypto.randomBytes(this.ivLength),
1334
+ tagLength: 128
1335
+ };
1336
+ }
1337
+ async _decrypt(data) {
1338
+ this.logger.Debug().Len(data.bytes, "bytes").Len(data.iv, "iv").Str("fp", this.key.fingerPrint).Msg("decrypting");
1339
+ return new Uint8Array(await this.crypto.decrypt(this.algo(data.iv), this.key.key, data.bytes));
1340
+ }
1341
+ async _encrypt(data) {
1342
+ this.logger.Debug().Len(data.bytes).Str("fp", this.key.fingerPrint).Msg("encrypting");
1343
+ const a = this.algo(data.iv);
1344
+ return new Uint8Array(await this.crypto.encrypt(a, this.key.key, data.bytes));
1345
+ }
1346
+ };
1347
+ var nullCodec = class {
1348
+ constructor() {
1349
+ this.code = 0;
1350
+ this.name = "Fireproof@unencrypted-block";
1351
+ }
1352
+ encode(data) {
1353
+ return data;
1354
+ }
1355
+ decode(data) {
1356
+ return data;
1357
+ }
1358
+ };
1359
+ var noCrypto = class {
1360
+ constructor(url, cyrt, sthis) {
1361
+ this.ivLength = 0;
1362
+ this.code = 0;
1363
+ this.name = "Fireproof@unencrypted-block";
1364
+ this.isEncrypting = false;
1365
+ this._fingerPrint = "noCrypto:" + Math.random();
1366
+ this.logger = ensureLogger(sthis, "noCrypto");
1367
+ this.crypto = cyrt;
1368
+ this.url = url;
1369
+ }
1370
+ fingerPrint() {
1371
+ return Promise.resolve(this._fingerPrint);
1372
+ }
1373
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1374
+ codec(iv) {
1375
+ return new nullCodec();
1376
+ }
1377
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1378
+ algo(iv) {
1379
+ return {
1380
+ name: "noCrypto",
1381
+ iv: new Uint8Array(),
1382
+ tagLength: 0
1383
+ };
1384
+ }
1385
+ _decrypt() {
1386
+ throw this.logger.Error().Msg("noCrypto.decrypt not implemented").AsError();
1387
+ }
1388
+ _encrypt() {
1389
+ throw this.logger.Error().Msg("noCrypto.decrypt not implemented").AsError();
1390
+ }
1391
+ };
1392
+ async function keyedCryptoFactory(url, kb, sthis) {
1393
+ const storekey = url.getParam("storekey");
1394
+ if (storekey && storekey !== "insecure") {
1395
+ let rkey = await kb.getNamedKey(storekey, true);
1396
+ if (rkey.isErr()) {
1397
+ try {
1398
+ rkey = await kb.toKeyWithFingerPrint(storekey);
1399
+ } catch (e) {
1400
+ throw sthis.logger.Error().Err(e).Str("keybag", kb.rt.id()).Str("name", storekey).Msg("getNamedKey failed").AsError();
1401
+ }
1402
+ }
1403
+ return new keyedCrypto(url, rkey.Ok(), kb.rt.crypto, sthis);
1404
+ }
1405
+ return new noCrypto(url, kb.rt.crypto, sthis);
1406
+ }
1407
+
1408
+ // src/blockstore/fragment-gateway.ts
1409
+ import { Result as Result3 } from "@adviser/cement";
1410
+ import { base58btc as base58btc3 } from "multiformats/bases/base58";
1411
+ import { encode as encode3, decode as decode3 } from "cborg";
1412
+ function getFragSize(url) {
1413
+ const fragSize = url.getParam("fragSize");
1414
+ let ret = 0;
1415
+ if (fragSize) {
1416
+ ret = parseInt(fragSize);
1417
+ }
1418
+ if (isNaN(ret) || ret <= 0) {
1419
+ ret = 0;
1420
+ }
1421
+ return ret;
1422
+ }
1423
+ async function getFrags(url, innerGW, headerSize, logger) {
1424
+ const fragSize = getFragSize(url);
1425
+ if (!fragSize) {
1426
+ const res = await innerGW.get(url);
1427
+ if (res.isErr()) {
1428
+ return [res];
1429
+ }
1430
+ const data = res.unwrap();
1431
+ return [
1432
+ Result3.Ok({
1433
+ fid: new Uint8Array(0),
1434
+ ofs: 0,
1435
+ len: data.length,
1436
+ data
1437
+ })
1438
+ ];
1439
+ }
1440
+ const firstRaw = await innerGW.get(url.build().setParam("ofs", "0").URI());
1441
+ if (firstRaw.isErr()) {
1442
+ return [firstRaw];
1443
+ }
1444
+ const firstFragment = decode3(firstRaw.unwrap());
1445
+ const blockSize = firstFragment.data.length;
1446
+ const ops = [Promise.resolve(Result3.Ok(firstFragment))];
1447
+ const fidStr = base58btc3.encode(firstFragment.fid);
1448
+ const fragUrl = url.build().setParam("fid", fidStr).setParam("len", firstFragment.len.toString()).setParam("headerSize", headerSize.toString());
1449
+ for (let ofs = blockSize; ofs < firstFragment.len; ofs += blockSize) {
1450
+ ops.push(
1451
+ (async (furl, ofs2) => {
1452
+ const raw2 = await innerGW.get(furl);
1453
+ if (raw2.isErr()) {
1454
+ return raw2;
1455
+ }
1456
+ const fragment = decode3(raw2.unwrap());
1457
+ if (base58btc3.encode(fragment.fid) !== fidStr) {
1458
+ return Result3.Err(logger.Error().Msg("Fragment fid mismatch").AsError());
1459
+ }
1460
+ if (fragment.ofs !== ofs2) {
1461
+ return Result3.Err(logger.Error().Uint64("ofs", ofs2).Msg("Fragment ofs mismatch").AsError());
1462
+ }
1463
+ return Result3.Ok(fragment);
1464
+ })(fragUrl.setParam("ofs", ofs.toString()).URI(), ofs)
1465
+ );
1466
+ }
1467
+ return Promise.all(ops);
1468
+ }
1469
+ var FragmentGateway = class {
1470
+ constructor(sthis, innerGW) {
1471
+ this.fidLength = 4;
1472
+ this.headerSize = 32;
1473
+ this.sthis = ensureSuperLog(sthis, "FragmentGateway");
1474
+ this.logger = this.sthis.logger;
1475
+ this.innerGW = innerGW;
1476
+ }
1477
+ slicer(url, body) {
1478
+ const fragSize = getFragSize(url);
1479
+ if (!fragSize) {
1480
+ return [this.innerGW.put(url, body)];
1481
+ }
1482
+ const blocksize = fragSize - this.headerSize;
1483
+ if (blocksize <= 0) {
1484
+ throw this.logger.Error().Uint64("fragSize", fragSize).Uint64("headerSize", this.headerSize).Msg("Fragment size is too small").AsError();
1485
+ }
1486
+ const ops = [];
1487
+ const fid = this.sthis.nextId(this.fidLength);
1488
+ const fragUrl = url.build().setParam("fid", fid.str).setParam("len", body.length.toString()).setParam("headerSize", this.headerSize.toString());
1489
+ for (let ofs = 0; ofs < body.length; ofs += blocksize) {
1490
+ const block = encode3({
1491
+ fid: fid.bin,
1492
+ ofs,
1493
+ len: body.length,
1494
+ data: body.slice(ofs, ofs + blocksize)
1495
+ });
1496
+ if (block.length > fragSize) {
1497
+ throw this.logger.Error().Uint64("block", block.length).Uint64("fragSize", fragSize).Msg("Block size to big").AsError();
1498
+ }
1499
+ ops.push(this.innerGW.put(fragUrl.setParam("ofs", ofs.toString()).URI(), block));
1500
+ }
1501
+ return ops;
1502
+ }
1503
+ buildUrl(baseUrl, key) {
1504
+ return this.innerGW.buildUrl(baseUrl, key);
1505
+ }
1506
+ async destroy(iurl) {
1507
+ return this.innerGW.destroy(iurl);
1508
+ }
1509
+ async start(url) {
1510
+ this.headerSize = encode3({
1511
+ fid: this.sthis.nextId(this.fidLength).bin,
1512
+ ofs: 1024 * 1024,
1513
+ // 32bit
1514
+ len: 16 * 1024 * 1024,
1515
+ // 32bit
1516
+ data: new Uint8Array(1024)
1517
+ }).length - 1024;
1518
+ return this.innerGW.start(url);
1519
+ }
1520
+ async close(url) {
1521
+ return this.innerGW.close(url);
1522
+ }
1523
+ async put(url, body) {
1524
+ await Promise.all(this.slicer(url, body));
1525
+ return Result3.Ok(void 0);
1526
+ }
1527
+ async get(url) {
1528
+ const rfrags = await getFrags(url, this.innerGW, this.headerSize, this.logger);
1529
+ let buffer = void 0;
1530
+ for (const rfrag of rfrags) {
1531
+ if (rfrag.isErr()) {
1532
+ return Result3.Err(rfrag.Err());
1533
+ }
1534
+ const frag = rfrag.Ok();
1535
+ buffer = buffer || new Uint8Array(frag.len);
1536
+ buffer.set(frag.data, frag.ofs);
1537
+ }
1538
+ return Result3.Ok(buffer || new Uint8Array(0));
1539
+ }
1540
+ async subscribe(url, callback) {
1541
+ if (this.innerGW.subscribe) {
1542
+ return this.innerGW.subscribe(url, callback);
1543
+ } else {
1544
+ return Result3.Err(this.logger.Error().Url(url).Msg("subscribe not supported").AsError());
1545
+ }
1546
+ }
1547
+ async delete(url) {
1548
+ const rfrags = await getFrags(url, this.innerGW, this.headerSize, this.logger);
1549
+ for (const rfrag of rfrags) {
1550
+ if (rfrag.isErr()) {
1551
+ return Result3.Err(rfrag.Err());
1552
+ }
1553
+ const frag = rfrag.Ok();
1554
+ const fidStr = base58btc3.encode(frag.fid);
1555
+ const fragUrl = url.build().setParam("fid", fidStr).setParam("len", frag.len.toString()).setParam("headerSize", this.headerSize.toString()).URI();
1556
+ await this.innerGW.delete(fragUrl);
1557
+ }
1558
+ return Result3.Ok(void 0);
1166
1559
  }
1167
- //What if instead it returns an Array of CarHeader
1168
- async storesLoadCar(cid, local, remote, publicFiles) {
1169
- const cidsString = cid.toString();
1170
- if (!this.carReaders.has(cidsString)) {
1171
- this.carReaders.set(
1172
- cidsString,
1173
- (async () => {
1174
- let loadedCar = void 0;
1175
- try {
1176
- this.logger.Debug().Str("cid", cidsString).Msg("loading car");
1177
- loadedCar = await local.load(cid);
1178
- this.logger.Debug().Bool("loadedCar", loadedCar).Msg("loaded");
1179
- } catch (e) {
1180
- if (remote) {
1181
- const remoteCar = await remote.load(cid);
1182
- if (remoteCar) {
1183
- this.logger.Debug().Ref("cid", remoteCar.cid).Msg("saving remote car locally");
1184
- await local.save(remoteCar);
1185
- loadedCar = remoteCar;
1186
- }
1187
- } else {
1188
- this.logger.Error().Str("cid", cidsString).Err(e).Msg("loading car");
1189
- }
1190
- }
1191
- if (!loadedCar) {
1192
- throw this.logger.Error().Url(local.url).Str("cid", cidsString).Msg("missing car files").AsError();
1193
- }
1194
- const rawReader = await CarReader.fromBytes(loadedCar.bytes);
1195
- const readerP = publicFiles ? Promise.resolve(rawReader) : this.ensureDecryptedReader(rawReader);
1196
- const cachedReaderP = readerP.then(async (reader) => {
1197
- await this.cacheCarReader(cidsString, reader).catch(() => {
1198
- return;
1199
- });
1200
- return reader;
1201
- });
1202
- this.carReaders.set(cidsString, cachedReaderP);
1203
- return readerP;
1204
- })().catch((e) => {
1205
- this.carReaders.delete(cidsString);
1206
- throw e;
1207
- })
1208
- );
1560
+ };
1561
+
1562
+ // src/blockstore/meta-key-helper.ts
1563
+ import { format, parse } from "@ipld/dag-json";
1564
+ import { EventBlock, decodeEventBlock } from "@web3-storage/pail/clock";
1565
+ import { CID as CID2 } from "multiformats";
1566
+ import { base64pad } from "multiformats/bases/base64";
1567
+ import { Result as Result4 } from "@adviser/cement";
1568
+ async function decodeGatewayMetaBytesToDbMeta(sthis, byteHeads) {
1569
+ const crdtEntries = JSON.parse(sthis.txt.decode(byteHeads));
1570
+ if (!crdtEntries.length) {
1571
+ sthis.logger.Debug().Str("byteHeads", new TextDecoder().decode(byteHeads)).Msg("No CRDT entries found");
1572
+ return [];
1573
+ }
1574
+ if (!crdtEntries.map) {
1575
+ sthis.logger.Debug().Str("crdtEntries", JSON.stringify(crdtEntries)).Msg("No data in CRDT entries");
1576
+ return [];
1577
+ }
1578
+ return Promise.all(
1579
+ crdtEntries.map(async (crdtEntry) => {
1580
+ const eventBlock = await decodeEventBlock(base64pad.decode(crdtEntry.data));
1581
+ const dbMeta = parse(sthis.txt.decode(eventBlock.value.data.dbMeta));
1582
+ return {
1583
+ eventCid: eventBlock.cid,
1584
+ parents: crdtEntry.parents,
1585
+ dbMeta
1586
+ };
1587
+ })
1588
+ );
1589
+ }
1590
+ async function setCryptoKeyFromGatewayMetaPayload(uri, sthis, data) {
1591
+ try {
1592
+ sthis.logger.Debug().Str("uri", uri.toString()).Msg("Setting crypto key from gateway meta payload");
1593
+ const keyInfo = await decodeGatewayMetaBytesToDbMeta(sthis, data);
1594
+ if (keyInfo.length) {
1595
+ const dbMeta = keyInfo[0].dbMeta;
1596
+ if (dbMeta.key) {
1597
+ const kb = await getKeyBag(sthis);
1598
+ const keyName = getStoreKeyName(uri);
1599
+ const res = await kb.setNamedKey(keyName, dbMeta.key);
1600
+ if (res.isErr()) {
1601
+ sthis.logger.Debug().Str("keyName", keyName).Str("dbMeta.key", dbMeta.key).Msg("Failed to set named key");
1602
+ throw res.Err();
1603
+ }
1604
+ }
1605
+ sthis.logger.Debug().Str("dbMeta.key", dbMeta.key).Str("uri", uri.toString()).Msg("Set crypto key from gateway meta payload");
1606
+ return Result4.Ok(dbMeta);
1209
1607
  }
1210
- return this.carReaders.get(cidsString);
1608
+ sthis.logger.Debug().Str("data", new TextDecoder().decode(data)).Msg("No crypto in gateway meta payload");
1609
+ return Result4.Ok(void 0);
1610
+ } catch (error) {
1611
+ sthis.logger.Debug().Err(error).Msg("Failed to set crypto key from gateway meta payload");
1612
+ return Result4.Err(error);
1211
1613
  }
1212
- async ensureDecryptedReader(reader) {
1213
- const theKey = await this._getKey();
1214
- if (this.ebOpts.public || !(theKey && this.ebOpts.crypto)) {
1215
- return reader;
1614
+ }
1615
+ async function addCryptoKeyToGatewayMetaPayload(uri, sthis, body) {
1616
+ try {
1617
+ sthis.logger.Debug().Str("uri", uri.toString()).Msg("Adding crypto key to gateway meta payload");
1618
+ const keyName = getStoreKeyName(uri);
1619
+ const kb = await getKeyBag(sthis);
1620
+ const res = await kb.getNamedExtractableKey(keyName, true);
1621
+ if (res.isErr()) {
1622
+ sthis.logger.Error().Str("keyName", keyName).Msg("Failed to get named extractable key");
1623
+ throw res.Err();
1216
1624
  }
1217
- const { blocks, root: root3 } = await decodeEncryptedCar(this.logger, this.ebOpts.crypto, theKey, reader);
1625
+ const keyData = await res.Ok().extract();
1626
+ const dbMetas = await decodeGatewayMetaBytesToDbMeta(sthis, body);
1627
+ const { dbMeta, parents } = dbMetas[0];
1628
+ const parentLinks = parents.map((p) => CID2.parse(p));
1629
+ dbMeta.key = keyData.keyStr;
1630
+ const events = await Promise.all([dbMeta].map((dbMeta2) => createDbMetaEventBlock(sthis, dbMeta2, parentLinks)));
1631
+ const encoded = await encodeEventsWithParents(sthis, events, parentLinks);
1632
+ sthis.logger.Debug().Str("uri", uri.toString()).Msg("Added crypto key to gateway meta payload");
1633
+ return Result4.Ok(encoded);
1634
+ } catch (error) {
1635
+ sthis.logger.Error().Err(error).Msg("Failed to add crypto key to gateway meta payload");
1636
+ return Result4.Err(error);
1637
+ }
1638
+ }
1639
+ function getStoreKeyName(url) {
1640
+ const storeKeyName = [url.getParam("localName") || url.getParam("name")];
1641
+ const idx = url.getParam("index");
1642
+ if (idx) {
1643
+ storeKeyName.push(idx);
1644
+ }
1645
+ storeKeyName.push("data");
1646
+ return `@${storeKeyName.join(":")}@`;
1647
+ }
1648
+ async function createDbMetaEventBlock(sthis, dbMeta, parents) {
1649
+ const event = await EventBlock.create(
1650
+ {
1651
+ dbMeta: sthis.txt.encode(format(dbMeta))
1652
+ },
1653
+ parents
1654
+ );
1655
+ return event;
1656
+ }
1657
+ async function encodeEventsWithParents(sthis, events, parents) {
1658
+ const crdtEntries = events.map((event) => {
1659
+ const base64String = base64pad.encode(event.bytes);
1218
1660
  return {
1219
- getRoots: () => [root3],
1220
- get: blocks.get.bind(blocks),
1221
- blocks: blocks.entries.bind(blocks)
1661
+ cid: event.cid.toString(),
1662
+ data: base64String,
1663
+ parents: parents.map((p) => p.toString())
1222
1664
  };
1223
- }
1224
- async setKey(key) {
1225
- if (this.key && this.key !== key)
1226
- throw this.logger.Error().Str("this.key", this.key).Str("key", key).Msg("setting key").AsError();
1227
- this.key = key;
1228
- const encoder = new TextEncoder();
1229
- const data = encoder.encode(key);
1230
- const hashBuffer = await this.ebOpts.crypto.digestSHA256(data);
1231
- const hashArray = Array.from(new Uint8Array(hashBuffer));
1232
- this.keyId = hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
1233
- }
1234
- async getMoreReaders(cids) {
1235
- const limit = pLimit(5);
1236
- const missing = cids.filter((cid) => !this.carReaders.has(cid.toString()));
1237
- await Promise.all(missing.map((cid) => limit(() => this.loadCar(cid))));
1238
- }
1239
- };
1665
+ });
1666
+ return sthis.txt.encode(JSON.stringify(crdtEntries));
1667
+ }
1240
1668
 
1241
1669
  // src/blockstore/store.ts
1242
1670
  function guardVersion(url) {
1243
- if (!url.searchParams.has("version")) {
1244
- return Result2.Err(`missing version: ${url.toString()}`);
1671
+ if (!url.hasParam("version")) {
1672
+ return Result5.Err(`missing version: ${url.toString()}`);
1245
1673
  }
1246
- return Result2.Ok(url);
1674
+ return Result5.Ok(url);
1247
1675
  }
1248
- var VersionedStore = class {
1249
- constructor(name, url, logger) {
1676
+ var BaseStoreImpl = class {
1677
+ constructor(name, url, opts, sthis, logger) {
1250
1678
  this._onStarted = [];
1251
1679
  this._onClosed = [];
1252
1680
  this.name = name;
1253
- this.url = url;
1254
- this.logger = logger;
1681
+ this._url = url;
1682
+ this.keybag = opts.keybag;
1683
+ this.sthis = sthis;
1684
+ this.logger = logger.With().Ref("url", () => this._url.toString()).Str("name", name).Logger();
1685
+ this.gateway = new FragmentGateway(this.sthis, opts.gateway);
1686
+ this.loader = opts.loader;
1687
+ }
1688
+ url() {
1689
+ return this._url;
1255
1690
  }
1256
1691
  onStarted(fn) {
1257
1692
  this._onStarted.push(fn);
@@ -1259,38 +1694,93 @@ var VersionedStore = class {
1259
1694
  onClosed(fn) {
1260
1695
  this._onClosed.push(fn);
1261
1696
  }
1262
- };
1263
- var textEncoder = new TextEncoder();
1264
- var textDecoder = new TextDecoder();
1265
- var MetaStore = class extends VersionedStore {
1266
- constructor(name, url, logger, gateway) {
1267
- super(name, url, ensureLogger(logger, "MetaStore", {}));
1268
- this.tag = "header-base";
1269
- this.gateway = gateway;
1270
- }
1271
- makeHeader({ cars, key }) {
1272
- const toEncode = { cars };
1273
- if (key) toEncode.key = key;
1274
- return format(toEncode);
1275
- }
1276
- parseHeader(headerData) {
1277
- const got = parse(headerData);
1278
- return got;
1697
+ async ready() {
1698
+ return;
1699
+ }
1700
+ async keyedCrypto() {
1701
+ return keyedCryptoFactory(this._url, await this.keybag(), this.sthis);
1279
1702
  }
1280
1703
  async start() {
1281
- this.logger.Debug().Msg("starting");
1282
- const res = await this.gateway.start(this.url);
1704
+ this.logger.Debug().Str("storeType", this.storeType).Msg("starting-gateway-pre");
1705
+ this._url = this._url.build().setParam("store", this.storeType).URI();
1706
+ const res = await this.gateway.start(this._url);
1283
1707
  if (res.isErr()) {
1708
+ this.logger.Error().Result("gw-start", res).Msg("started-gateway");
1284
1709
  return res;
1285
1710
  }
1711
+ this._url = res.Ok();
1712
+ const kb = await this.keybag();
1713
+ const skRes = await kb.ensureKeyFromUrl(this._url, () => {
1714
+ const idx = this._url.getParam("index");
1715
+ const storeKeyName = [this.name];
1716
+ if (idx) {
1717
+ storeKeyName.push(idx);
1718
+ }
1719
+ storeKeyName.push(this.storeType);
1720
+ return storeKeyName.join(":");
1721
+ });
1722
+ if (skRes.isErr()) {
1723
+ return skRes;
1724
+ }
1725
+ this._url = skRes.Ok();
1726
+ const version = guardVersion(this._url);
1727
+ if (version.isErr()) {
1728
+ this.logger.Error().Result("version", version).Msg("guardVersion");
1729
+ await this.close();
1730
+ return version;
1731
+ }
1732
+ if (this.ready) {
1733
+ const fn = this.ready.bind(this);
1734
+ const ready = await exception2Result(fn);
1735
+ if (ready.isErr()) {
1736
+ await this.close();
1737
+ return ready;
1738
+ }
1739
+ }
1286
1740
  this._onStarted.forEach((fn) => fn());
1287
- return guardVersion(this.url);
1741
+ this.logger.Debug().Msg("started");
1742
+ return version;
1743
+ }
1744
+ };
1745
+ var MetaStoreImpl = class extends BaseStoreImpl {
1746
+ // remote: boolean;
1747
+ constructor(sthis, name, url, opts) {
1748
+ super(name, url, { ...opts }, sthis, ensureLogger(sthis, "MetaStoreImpl"));
1749
+ this.storeType = "meta";
1750
+ this.subscribers = /* @__PURE__ */ new Map();
1751
+ this.parents = [];
1752
+ if (
1753
+ /*this.remote && */
1754
+ opts.gateway.subscribe
1755
+ ) {
1756
+ this.onStarted(async () => {
1757
+ this.logger.Debug().Str("url", this.url().toString()).Msg("Subscribing to the gateway");
1758
+ opts.gateway.subscribe?.(this.url(), async (message) => {
1759
+ this.logger.Debug().Msg("Received message from gateway");
1760
+ const dbMetas = await decodeGatewayMetaBytesToDbMeta(this.sthis, message);
1761
+ await Promise.all(
1762
+ dbMetas.map((dbMeta) => this.loader?.taskManager?.handleEvent(dbMeta.eventCid, dbMeta.parents, dbMeta.dbMeta))
1763
+ );
1764
+ this.updateParentsFromDbMetas(dbMetas);
1765
+ });
1766
+ });
1767
+ }
1768
+ }
1769
+ updateParentsFromDbMetas(dbMetas) {
1770
+ const cids = dbMetas.map((m) => m.eventCid);
1771
+ const dbMetaParents = dbMetas.flatMap((m) => m.parents);
1772
+ const uniqueParentsMap = new Map([...this.parents, ...cids].map((p) => [p.toString(), p]));
1773
+ const dbMetaParentsSet = new Set(dbMetaParents.map((p) => p.toString()));
1774
+ this.parents = Array.from(uniqueParentsMap.values()).filter((p) => !dbMetaParentsSet.has(p.toString()));
1288
1775
  }
1289
- async load(branch) {
1290
- this.logger.Debug().Str("branch", branch || "").Msg("loading");
1291
- const url = await this.gateway.buildUrl(this.url, branch || "main");
1776
+ async handleByteHeads(byteHeads) {
1777
+ return await decodeGatewayMetaBytesToDbMeta(this.sthis, byteHeads);
1778
+ }
1779
+ async load() {
1780
+ const branch = "main";
1781
+ const url = await this.gateway.buildUrl(this.url(), branch);
1292
1782
  if (url.isErr()) {
1293
- throw this.logger.Error().Result("buidUrl", url).Str("branch", branch || "").Url(this.url).Msg("got error from gateway.buildUrl").AsError();
1783
+ throw this.logger.Error().Result("buildUrl", url).Str("branch", branch).Msg("got error from gateway.buildUrl").AsError();
1294
1784
  }
1295
1785
  const bytes = await this.gateway.get(url.Ok());
1296
1786
  if (bytes.isErr()) {
@@ -1299,66 +1789,45 @@ var MetaStore = class extends VersionedStore {
1299
1789
  }
1300
1790
  throw this.logger.Error().Url(url.Ok()).Result("bytes:", bytes).Msg("gateway get").AsError();
1301
1791
  }
1302
- try {
1303
- return [this.parseHeader(textDecoder.decode(bytes.Ok()))];
1304
- } catch (e) {
1305
- throw this.logger.Error().Err(e).Msg("parseHeader").AsError();
1306
- }
1792
+ const dbMetas = await this.handleByteHeads(bytes.Ok());
1793
+ await this.loader?.handleDbMetasFromStore(dbMetas.map((m) => m.dbMeta));
1794
+ this.updateParentsFromDbMetas(dbMetas);
1795
+ return dbMetas.map((m) => m.dbMeta);
1307
1796
  }
1308
- async save(meta, branch = "main") {
1797
+ async save(meta, branch) {
1798
+ branch = branch || "main";
1309
1799
  this.logger.Debug().Str("branch", branch).Any("meta", meta).Msg("saving meta");
1310
- const bytes = this.makeHeader(meta);
1311
- const url = await this.gateway.buildUrl(this.url, branch);
1800
+ const event = await createDbMetaEventBlock(this.sthis, meta, this.parents);
1801
+ const bytes = await encodeEventsWithParents(this.sthis, [event], this.parents);
1802
+ const url = await this.gateway.buildUrl(this.url(), branch);
1312
1803
  if (url.isErr()) {
1313
- throw this.logger.Error().Err(url.Err()).Str("branch", branch).Url(this.url).Msg("got error from gateway.buildUrl").AsError();
1804
+ throw this.logger.Error().Err(url.Err()).Str("branch", branch).Msg("got error from gateway.buildUrl").AsError();
1314
1805
  }
1315
- const res = await this.gateway.put(url.Ok(), textEncoder.encode(bytes));
1806
+ this.parents = [event.cid];
1807
+ const res = await this.gateway.put(url.Ok(), bytes);
1316
1808
  if (res.isErr()) {
1317
1809
  throw this.logger.Error().Err(res.Err()).Msg("got error from gateway.put").AsError();
1318
1810
  }
1319
- return res.Ok();
1811
+ return res;
1320
1812
  }
1321
1813
  async close() {
1322
- await this.gateway.close(this.url);
1814
+ await this.gateway.close(this.url());
1323
1815
  this._onClosed.forEach((fn) => fn());
1324
- return Result2.Ok(void 0);
1816
+ return Result5.Ok(void 0);
1325
1817
  }
1326
1818
  async destroy() {
1327
- return this.gateway.destroy(this.url);
1819
+ return this.gateway.destroy(this.url());
1328
1820
  }
1329
1821
  };
1330
- var DataStore = class extends VersionedStore {
1331
- constructor(name, url, logger, gateway) {
1332
- super(
1333
- name,
1334
- url,
1335
- ensureLogger(logger, "DataStore", {
1336
- url: () => url.toString()
1337
- })
1338
- );
1339
- this.tag = "car-base";
1340
- this.gateway = gateway;
1341
- }
1342
- async start() {
1343
- this.logger.Debug().Msg("starting-gateway");
1344
- const res = await this.gateway.start(this.url);
1345
- if (res.isErr()) {
1346
- this.logger.Error().Result("gw-start", res).Msg("started-gateway");
1347
- return res;
1348
- }
1349
- this._onStarted.forEach((fn) => fn());
1350
- const version = guardVersion(this.url);
1351
- if (version.isErr()) {
1352
- this.logger.Error().Result("version", version).Msg("guardVersion");
1353
- await this.close();
1354
- return version;
1355
- }
1356
- this.logger.Debug().Msg("started");
1357
- return version;
1822
+ var DataStoreImpl = class extends BaseStoreImpl {
1823
+ // readonly tag: string = "car-base";
1824
+ constructor(sthis, name, url, opts) {
1825
+ super(name, url, { ...opts }, sthis, ensureLogger(sthis, "DataStoreImpl"));
1826
+ this.storeType = "data";
1358
1827
  }
1359
1828
  async load(cid) {
1360
1829
  this.logger.Debug().Any("cid", cid).Msg("loading");
1361
- const url = await this.gateway.buildUrl(this.url, cid.toString());
1830
+ const url = await this.gateway.buildUrl(this.url(), cid.toString());
1362
1831
  if (url.isErr()) {
1363
1832
  throw this.logger.Error().Err(url.Err()).Str("cid", cid.toString()).Msg("got error from gateway.buildUrl").AsError();
1364
1833
  }
@@ -1371,7 +1840,7 @@ var DataStore = class extends VersionedStore {
1371
1840
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
1372
1841
  async save(car, opts) {
1373
1842
  this.logger.Debug().Any("cid", car.cid.toString()).Msg("saving");
1374
- const url = await this.gateway.buildUrl(this.url, car.cid.toString());
1843
+ const url = await this.gateway.buildUrl(this.url(), car.cid.toString());
1375
1844
  if (url.isErr()) {
1376
1845
  throw this.logger.Error().Err(url.Err()).Ref("cid", car.cid).Msg("got error from gateway.buildUrl").AsError();
1377
1846
  }
@@ -1382,31 +1851,30 @@ var DataStore = class extends VersionedStore {
1382
1851
  return res.Ok();
1383
1852
  }
1384
1853
  async remove(cid) {
1385
- const url = await this.gateway.buildUrl(this.url, cid.toString());
1854
+ const url = await this.gateway.buildUrl(this.url(), cid.toString());
1386
1855
  if (url.isErr()) {
1387
1856
  return url;
1388
1857
  }
1389
1858
  return this.gateway.delete(url.Ok());
1390
1859
  }
1391
1860
  async close() {
1392
- await this.gateway.close(this.url);
1861
+ await this.gateway.close(this.url());
1393
1862
  this._onClosed.forEach((fn) => fn());
1394
- return Result2.Ok(void 0);
1863
+ return Result5.Ok(void 0);
1395
1864
  }
1396
1865
  destroy() {
1397
- return this.gateway.destroy(this.url);
1866
+ return this.gateway.destroy(this.url());
1398
1867
  }
1399
1868
  };
1400
- var RemoteWAL = class extends VersionedStore {
1401
- constructor(loader, url, logger, gateway) {
1402
- super(loader.name, url, ensureLogger(logger, "RemoteWAL"));
1403
- this.tag = "rwal-base";
1404
- this._ready = new ResolveOnce2();
1869
+ var WALStoreImpl = class extends BaseStoreImpl {
1870
+ constructor(loader, url, opts) {
1871
+ super(loader.name, url, { ...opts }, loader.sthis, ensureLogger(loader.sthis, "WALStoreImpl"));
1872
+ this.storeType = "wal";
1873
+ this._ready = new ResolveOnce3();
1405
1874
  this.walState = { operations: [], noLoaderOps: [], fileOperations: [] };
1406
1875
  this.processing = void 0;
1407
1876
  this.processQueue = new CommitQueue();
1408
1877
  this.loader = loader;
1409
- this.gateway = gateway;
1410
1878
  }
1411
1879
  async ready() {
1412
1880
  return this._ready.once(async () => {
@@ -1425,25 +1893,34 @@ var RemoteWAL = class extends VersionedStore {
1425
1893
  }
1426
1894
  async enqueue(dbMeta, opts) {
1427
1895
  await this.ready();
1428
- if (opts.noLoader) {
1896
+ if (opts.compact) {
1897
+ this.walState.operations = [];
1898
+ this.walState.noLoaderOps = [dbMeta];
1899
+ } else if (opts.noLoader) {
1429
1900
  this.walState.noLoaderOps.push(dbMeta);
1430
1901
  } else {
1431
1902
  this.walState.operations.push(dbMeta);
1432
1903
  }
1433
1904
  await this.save(this.walState);
1434
- void this._process();
1905
+ if (!opts.noLoader) {
1906
+ void this.process();
1907
+ }
1435
1908
  }
1436
1909
  async enqueueFile(fileCid, publicFile = false) {
1437
1910
  await this.ready();
1438
1911
  this.walState.fileOperations.push({ cid: fileCid, public: publicFile });
1439
1912
  }
1440
- async _process() {
1913
+ async process() {
1441
1914
  await this.ready();
1442
1915
  if (!this.loader.remoteCarStore) return;
1443
1916
  await this.processQueue.enqueue(async () => {
1444
- await this._doProcess();
1917
+ try {
1918
+ await this._doProcess();
1919
+ } catch (e) {
1920
+ this.logger.Error().Any("error", e).Msg("error processing wal");
1921
+ }
1445
1922
  if (this.walState.operations.length || this.walState.fileOperations.length || this.walState.noLoaderOps.length) {
1446
- setTimeout(() => void this._process(), 0);
1923
+ setTimeout(() => void this.process(), 0);
1447
1924
  }
1448
1925
  });
1449
1926
  }
@@ -1454,14 +1931,14 @@ var RemoteWAL = class extends VersionedStore {
1454
1931
  const fileOperations = [...this.walState.fileOperations];
1455
1932
  const uploads = [];
1456
1933
  const noLoaderOps = [...this.walState.noLoaderOps];
1457
- const limit = pLimit2(5);
1934
+ const limit = pLimit2(3);
1458
1935
  if (operations.length + fileOperations.length + noLoaderOps.length === 0) return;
1459
1936
  for (const dbMeta of noLoaderOps) {
1460
1937
  const uploadP = limit(async () => {
1461
1938
  for (const cid of dbMeta.cars) {
1462
1939
  const car = await (await this.loader.carStore()).load(cid);
1463
1940
  if (!car) {
1464
- if (carLogIncludesGroup2(this.loader.carLog, dbMeta.cars))
1941
+ if (carLogIncludesGroup(this.loader.carLog, dbMeta.cars))
1465
1942
  throw this.logger.Error().Ref("cid", cid).Msg("missing local car").AsError();
1466
1943
  } else {
1467
1944
  await throwFalsy(this.loader.remoteCarStore).save(car);
@@ -1476,7 +1953,7 @@ var RemoteWAL = class extends VersionedStore {
1476
1953
  for (const cid of dbMeta.cars) {
1477
1954
  const car = await (await this.loader.carStore()).load(cid).catch(() => null);
1478
1955
  if (!car) {
1479
- if (carLogIncludesGroup2(this.loader.carLog, dbMeta.cars))
1956
+ if (carLogIncludesGroup(this.loader.carLog, dbMeta.cars))
1480
1957
  throw this.logger.Error().Ref("cid", cid).Msg(`missing local car`).AsError();
1481
1958
  } else {
1482
1959
  await throwFalsy(this.loader.remoteCarStore).save(car);
@@ -1501,11 +1978,7 @@ var RemoteWAL = class extends VersionedStore {
1501
1978
  const res = await Promise.allSettled(uploads);
1502
1979
  const errors = res.filter((r) => r.status === "rejected");
1503
1980
  if (errors.length) {
1504
- throw this.logger.Error().Any(
1505
- "errors",
1506
- errors.map((e) => e.reason)
1507
- ).Msg("error uploading").AsError();
1508
- errors[0].reason;
1981
+ throw this.logger.Error().Any("errors", errors).Msg("error uploading").AsError();
1509
1982
  }
1510
1983
  if (operations.length) {
1511
1984
  const lastOp = operations[operations.length - 1];
@@ -1520,29 +1993,11 @@ var RemoteWAL = class extends VersionedStore {
1520
1993
  })();
1521
1994
  await rmlp;
1522
1995
  }
1523
- async start() {
1524
- const res = await this.gateway.start(this.url);
1525
- if (res.isErr()) {
1526
- return res;
1527
- }
1528
- const ver = guardVersion(this.url);
1529
- if (ver.isErr()) {
1530
- await this.close();
1531
- return ver;
1532
- }
1533
- const ready = await exception2Result(() => this.ready());
1534
- this._onStarted.forEach((fn) => fn());
1535
- if (ready.isErr()) {
1536
- await this.close();
1537
- return ready;
1538
- }
1539
- return ready;
1540
- }
1541
1996
  async load() {
1542
1997
  this.logger.Debug().Msg("loading");
1543
- const filepath = await this.gateway.buildUrl(this.url, "main");
1998
+ const filepath = await this.gateway.buildUrl(this.url(), "main");
1544
1999
  if (filepath.isErr()) {
1545
- throw this.logger.Error().Err(filepath.Err()).Str("url", this.url.toString()).Msg("error building url").AsError();
2000
+ throw this.logger.Error().Err(filepath.Err()).Url(this.url()).Msg("error building url").AsError();
1546
2001
  }
1547
2002
  const bytes = await this.gateway.get(filepath.Ok());
1548
2003
  if (bytes.isErr()) {
@@ -1552,71 +2007,83 @@ var RemoteWAL = class extends VersionedStore {
1552
2007
  throw this.logger.Error().Err(bytes.Err()).Msg("error get").AsError();
1553
2008
  }
1554
2009
  try {
1555
- return bytes && parse(textDecoder.decode(bytes.Ok()));
2010
+ return bytes && parse2(this.sthis.txt.decode(bytes.Ok()));
1556
2011
  } catch (e) {
1557
2012
  throw this.logger.Error().Err(e).Msg("error parse").AsError();
1558
2013
  }
1559
2014
  }
1560
2015
  async save(state) {
1561
- const filepath = await this.gateway.buildUrl(this.url, "main");
2016
+ const filepath = await this.gateway.buildUrl(this.url(), "main");
1562
2017
  if (filepath.isErr()) {
1563
- throw this.logger.Error().Err(filepath.Err()).Str("url", this.url.toString()).Msg("error building url").AsError();
2018
+ throw this.logger.Error().Err(filepath.Err()).Url(this.url()).Msg("error building url").AsError();
1564
2019
  }
1565
2020
  let encoded;
1566
2021
  try {
1567
- encoded = format(state);
2022
+ encoded = format2(state);
1568
2023
  } catch (e) {
1569
2024
  throw this.logger.Error().Err(e).Any("state", state).Msg("error format").AsError();
1570
2025
  }
1571
- const res = await this.gateway.put(filepath.Ok(), textEncoder.encode(encoded));
2026
+ const res = await this.gateway.put(filepath.Ok(), this.sthis.txt.encode(encoded));
1572
2027
  if (res.isErr()) {
1573
2028
  throw this.logger.Error().Err(res.Err()).Str("filePath", filepath.Ok().toString()).Msg("error saving").AsError();
1574
2029
  }
1575
2030
  }
1576
2031
  async close() {
1577
- await this.gateway.close(this.url);
2032
+ await this.gateway.close(this.url());
1578
2033
  this._onClosed.forEach((fn) => fn());
1579
- return Result2.Ok(void 0);
2034
+ return Result5.Ok(void 0);
1580
2035
  }
1581
2036
  destroy() {
1582
- return this.gateway.destroy(this.url);
2037
+ return this.gateway.destroy(this.url());
1583
2038
  }
1584
2039
  };
1585
2040
 
1586
2041
  // src/blockstore/store-factory.ts
1587
2042
  function ensureIsIndex(url, isIndex) {
1588
2043
  if (isIndex) {
1589
- url.searchParams.set("index", isIndex);
1590
- return url;
1591
- } else {
1592
- url.searchParams.delete("index");
1593
- return url;
1594
- }
1595
- }
1596
- function toURL(pathOrUrl, isIndex) {
1597
- if (pathOrUrl instanceof URL) return ensureIsIndex(pathOrUrl, isIndex);
1598
- try {
1599
- const url = new URL(pathOrUrl);
1600
- return ensureIsIndex(url, isIndex);
1601
- } catch (e) {
1602
- const url = new URL(`file://${pathOrUrl}`);
1603
- return ensureIsIndex(url, isIndex);
2044
+ return url.build().setParam("index", isIndex).URI();
1604
2045
  }
2046
+ return url.build().delParam("index").URI();
1605
2047
  }
1606
- var storeFactory = /* @__PURE__ */ new Map();
1607
2048
  function ensureName(name, url) {
1608
- if (!url.searchParams.has("name")) {
1609
- url.searchParams.set("name", name);
2049
+ if (!url.hasParam("name")) {
2050
+ return url.build().setParam("name", name).URI();
1610
2051
  }
2052
+ return url;
1611
2053
  }
2054
+ var storeFactory = /* @__PURE__ */ new Map();
1612
2055
  function buildURL(optURL, loader) {
1613
2056
  const storeOpts = loader.ebOpts.store;
1614
2057
  const obuItem = Array.from(storeFactory.values()).find((items) => items.overrideBaseURL);
1615
2058
  let obuUrl;
1616
2059
  if (obuItem && obuItem.overrideBaseURL) {
1617
- obuUrl = new URL(obuItem.overrideBaseURL);
2060
+ obuUrl = URI5.from(obuItem.overrideBaseURL);
1618
2061
  }
1619
- return toURL(optURL || obuUrl || dataDir(loader.name, storeOpts.stores?.base), storeOpts.isIndex);
2062
+ const ret = ensureIsIndex(
2063
+ URI5.from(optURL || obuUrl || dataDir(loader.sthis, loader.name, storeOpts.stores?.base)),
2064
+ storeOpts.isIndex
2065
+ );
2066
+ return ret;
2067
+ }
2068
+ var onceGateway = new KeyedResolvOnce2();
2069
+ async function getGatewayFromURL(url, sthis) {
2070
+ return onceGateway.get(url.toString()).once(async () => {
2071
+ const item = storeFactory.get(url.protocol);
2072
+ if (item) {
2073
+ const ret = {
2074
+ gateway: await item.gateway(sthis),
2075
+ test: await item.test(sthis)
2076
+ };
2077
+ const res = await ret.gateway.start(url);
2078
+ if (res.isErr()) {
2079
+ sthis.logger.Error().Result("start", res).Msg("start failed");
2080
+ return void 0;
2081
+ }
2082
+ return ret;
2083
+ }
2084
+ sthis.logger.Warn().Url(url).Msg("unsupported protocol");
2085
+ return void 0;
2086
+ });
1620
2087
  }
1621
2088
  function registerStoreProtocol(item) {
1622
2089
  let protocol = item.protocol;
@@ -1625,8 +2092,7 @@ function registerStoreProtocol(item) {
1625
2092
  }
1626
2093
  if (storeFactory.has(protocol)) {
1627
2094
  if (!item.overrideBaseURL && storeFactory.get(protocol) !== item) {
1628
- const logger = ensureLogger({}, "registerStoreProtocol", { protocol });
1629
- logger.Warn().Msg(`protocol ${protocol} already registered`);
2095
+ throw new Error(`we need a logger here`);
1630
2096
  return () => {
1631
2097
  };
1632
2098
  }
@@ -1641,106 +2107,92 @@ function registerStoreProtocol(item) {
1641
2107
  storeFactory.delete(protocol);
1642
2108
  };
1643
2109
  }
1644
- function runStoreFactory(url, logger, run) {
1645
- const item = storeFactory.get(url.protocol);
1646
- if (!item) {
1647
- throw logger.Error().Url(url).Str("protocol", url.protocol).Any("keys", Array(storeFactory.keys())).Msg(`unsupported protocol`).AsError();
1648
- }
1649
- logger.Debug().Str("protocol", url.protocol).Msg("run");
1650
- return run(item);
1651
- }
1652
- var onceLoadDataGateway = new KeyedResolvOnce();
1653
- function loadDataGateway(url, logger) {
1654
- return onceLoadDataGateway.get(url.protocol).once(async () => {
1655
- return runStoreFactory(url, logger, async (item) => item.data(logger));
1656
- });
1657
- }
1658
- var onceDataStoreFactory = new KeyedResolvOnce();
2110
+ var onceDataStoreFactory = new KeyedResolvOnce2();
1659
2111
  async function dataStoreFactory(loader) {
1660
- const url = buildURL(loader.ebOpts.store.stores?.data, loader);
1661
- ensureName(loader.name, url);
1662
- const logger = ensureLogger(loader.logger, "dataStoreFactory", { url: url.toString() });
1663
- url.searchParams.set("store", "data");
2112
+ const url = ensureName(loader.name, buildURL(loader.ebOpts.store.stores?.data, loader)).build().setParam("store", "data").URI();
2113
+ const sthis = ensureSuperLog(loader.sthis, "dataStoreFactory", { url: url.toString() });
1664
2114
  return onceDataStoreFactory.get(url.toString()).once(async () => {
1665
- const gateway = await loadDataGateway(url, logger);
1666
- const store = new DataStore(loader.name, url, loader.logger, gateway);
1667
- const ret = await store.start();
1668
- if (ret.isErr()) {
1669
- throw logger.Error().Result("start", ret).Msg("start failed").AsError();
1670
- }
1671
- logger.Debug().Str("prepared", store.url.toString()).Msg("produced");
2115
+ const gateway = await getGatewayFromURL(url, sthis);
2116
+ if (!gateway) {
2117
+ throw sthis.logger.Error().Url(url).Msg("gateway not found").AsError();
2118
+ }
2119
+ const store = new DataStoreImpl(sthis, loader.name, url, {
2120
+ gateway: gateway.gateway,
2121
+ keybag: () => getKeyBag(loader.sthis, {
2122
+ ...loader.ebOpts.keyBag
2123
+ })
2124
+ });
1672
2125
  return store;
1673
2126
  });
1674
2127
  }
1675
- var onceLoadMetaGateway = new KeyedResolvOnce();
1676
- function loadMetaGateway(url, logger) {
1677
- return onceLoadMetaGateway.get(url.protocol).once(async () => {
1678
- return runStoreFactory(url, logger, async (item) => item.meta(logger));
1679
- });
1680
- }
1681
- var onceMetaStoreFactory = new KeyedResolvOnce();
2128
+ var onceMetaStoreFactory = new KeyedResolvOnce2();
1682
2129
  async function metaStoreFactory(loader) {
1683
- const url = buildURL(loader.ebOpts.store.stores?.meta, loader);
1684
- ensureName(loader.name, url);
1685
- const logger = ensureLogger(loader.logger, "metaStoreFactory", { url: () => url.toString() });
1686
- url.searchParams.set("store", "meta");
2130
+ const url = ensureName(loader.name, buildURL(loader.ebOpts.store.stores?.meta, loader)).build().setParam("store", "meta").URI();
2131
+ const sthis = ensureSuperLog(loader.sthis, "metaStoreFactory", { url: () => url.toString() });
1687
2132
  return onceMetaStoreFactory.get(url.toString()).once(async () => {
1688
- logger.Debug().Str("protocol", url.protocol).Msg("pre-protocol switch");
1689
- const gateway = await loadMetaGateway(url, logger);
1690
- const store = new MetaStore(loader.name, url, loader.logger, gateway);
1691
- const ret = await store.start();
1692
- if (ret.isErr()) {
1693
- throw logger.Error().Result("start", ret).Msg("start failed").AsError();
1694
- }
2133
+ sthis.logger.Debug().Str("protocol", url.protocol).Msg("pre-protocol switch");
2134
+ const gateway = await getGatewayFromURL(url, sthis);
2135
+ if (!gateway) {
2136
+ throw sthis.logger.Error().Url(url).Msg("gateway not found").AsError();
2137
+ }
2138
+ const store = new MetaStoreImpl(loader.sthis, loader.name, url, {
2139
+ gateway: gateway.gateway,
2140
+ keybag: () => getKeyBag(loader.sthis, {
2141
+ ...loader.ebOpts.keyBag
2142
+ })
2143
+ });
1695
2144
  return store;
1696
2145
  });
1697
2146
  }
1698
- var onceWalGateway = new KeyedResolvOnce();
1699
- function loadWalGateway(url, logger) {
1700
- return onceWalGateway.get(url.protocol).once(async () => {
1701
- return runStoreFactory(url, logger, async (item) => item.wal(logger));
1702
- });
1703
- }
1704
- var onceRemoteWalFactory = new KeyedResolvOnce();
2147
+ var onceRemoteWalFactory = new KeyedResolvOnce2();
1705
2148
  async function remoteWalFactory(loader) {
1706
- const url = buildURL(loader.ebOpts.store.stores?.meta, loader);
1707
- ensureName(loader.name, url);
1708
- const logger = ensureLogger(loader.logger, "remoteWalFactory", { url: url.toString() });
1709
- url.searchParams.set("store", "wal");
2149
+ const url = ensureName(loader.name, buildURL(loader.ebOpts.store.stores?.wal, loader)).build().setParam("store", "wal").URI();
2150
+ const sthis = ensureSuperLog(loader.sthis, "remoteWalFactory", { url: url.toString() });
1710
2151
  return onceRemoteWalFactory.get(url.toString()).once(async () => {
1711
- const gateway = await loadWalGateway(url, logger);
1712
- logger.Debug().Str("prepared", url.toString()).Msg("produced");
1713
- const store = new RemoteWAL(loader, url, loader.logger, gateway);
1714
- const ret = await store.start();
1715
- if (ret.isErr()) {
1716
- throw logger.Error().Result("start", ret).Msg("start failed").AsError();
1717
- }
2152
+ const gateway = await getGatewayFromURL(url, sthis);
2153
+ if (!gateway) {
2154
+ throw sthis.logger.Error().Url(url).Msg("gateway not found").AsError();
2155
+ }
2156
+ sthis.logger.Debug().Str("prepared", url.toString()).Msg("produced");
2157
+ const store = new WALStoreImpl(loader, url, {
2158
+ gateway: gateway.gateway,
2159
+ keybag: () => getKeyBag(loader.sthis, {
2160
+ ...loader.ebOpts.keyBag
2161
+ })
2162
+ });
1718
2163
  return store;
1719
2164
  });
1720
2165
  }
1721
- async function testStoreFactory(url, ilogger) {
1722
- const logger = ensureLogger(
1723
- {
1724
- logger: ilogger
1725
- },
1726
- "testStoreFactory"
1727
- );
1728
- return runStoreFactory(url, logger, async (item) => item.test(logger));
2166
+ async function testStoreFactory(url, sthis) {
2167
+ sthis = ensureSuperLog(sthis, "testStoreFactory");
2168
+ const gateway = await getGatewayFromURL(url, sthis);
2169
+ if (!gateway) {
2170
+ throw sthis.logger.Error().Url(url).Msg("gateway not found").AsError();
2171
+ }
2172
+ return gateway.test;
2173
+ }
2174
+ async function ensureStart(store, logger) {
2175
+ const ret = await store.start();
2176
+ if (ret.isErr()) {
2177
+ throw logger.Error().Result("start", ret).Msg("start failed").AsError();
2178
+ }
2179
+ logger.Debug().Url(ret.Ok(), "prepared").Msg("produced");
2180
+ return store;
1729
2181
  }
1730
- function toStoreRuntime(opts, ilogger) {
1731
- const logger = ensureLogger(ilogger, "toStoreRuntime", {});
2182
+ function toStoreRuntime(opts, sthis) {
2183
+ const logger = ensureLogger(sthis, "toStoreRuntime", {});
1732
2184
  return {
1733
- makeMetaStore: (loader) => {
2185
+ makeMetaStore: async (loader) => {
1734
2186
  logger.Debug().Str("fromOpts", "" + !!loader.ebOpts.store.makeMetaStore).Msg("makeMetaStore");
1735
- return (loader.ebOpts.store.makeMetaStore || metaStoreFactory)(loader);
2187
+ return ensureStart(await (loader.ebOpts.store.makeMetaStore || metaStoreFactory)(loader), logger);
1736
2188
  },
1737
- makeDataStore: (loader) => {
2189
+ makeDataStore: async (loader) => {
1738
2190
  logger.Debug().Str("fromOpts", "" + !!loader.ebOpts.store.makeDataStore).Msg("makeDataStore");
1739
- return (loader.ebOpts.store.makeDataStore || dataStoreFactory)(loader);
2191
+ return ensureStart(await (loader.ebOpts.store.makeDataStore || dataStoreFactory)(loader), logger);
1740
2192
  },
1741
- makeRemoteWAL: (loader) => {
1742
- logger.Debug().Str("fromOpts", "" + !!loader.ebOpts.store.makeRemoteWAL).Msg("makeRemoteWAL");
1743
- return (loader.ebOpts.store.makeRemoteWAL || remoteWalFactory)(loader);
2193
+ makeWALStore: async (loader) => {
2194
+ logger.Debug().Str("fromOpts", "" + !!loader.ebOpts.store.makeWALStore).Msg("makeRemoteWAL");
2195
+ return ensureStart(await (loader.ebOpts.store.makeWALStore || remoteWalFactory)(loader), logger);
1744
2196
  },
1745
2197
  encodeFile: opts.encodeFile || encodeFile,
1746
2198
  decodeFile: opts.decodeFile || decodeFile
@@ -1748,43 +2200,131 @@ function toStoreRuntime(opts, ilogger) {
1748
2200
  }
1749
2201
  registerStoreProtocol({
1750
2202
  protocol: "file:",
1751
- data: async (logger) => {
1752
- const { FileDataGateway } = await import("./store-file-VJ6BI4II.js");
1753
- return new FileDataGateway(logger);
2203
+ gateway: async (sthis) => {
2204
+ const { FileGateway } = await import("./gateway-5FCWPX5W.js");
2205
+ return new FileGateway(sthis);
1754
2206
  },
1755
- meta: async (logger) => {
1756
- const { FileMetaGateway } = await import("./store-file-VJ6BI4II.js");
1757
- return new FileMetaGateway(logger);
1758
- },
1759
- wal: async (logger) => {
1760
- const { FileWALGateway } = await import("./store-file-VJ6BI4II.js");
1761
- return new FileWALGateway(logger);
1762
- },
1763
- test: async (logger) => {
1764
- const { FileTestStore } = await import("./store-file-VJ6BI4II.js");
1765
- return new FileTestStore(logger);
2207
+ test: async (sthis) => {
2208
+ const { FileTestStore } = await import("./gateway-5FCWPX5W.js");
2209
+ return new FileTestStore(sthis);
1766
2210
  }
1767
2211
  });
1768
2212
  registerStoreProtocol({
1769
2213
  protocol: "indexdb:",
1770
- data: async (logger) => {
1771
- const { IndexDBDataGateway } = await import("./store-indexdb-WLRSICCB.js");
1772
- return new IndexDBDataGateway(logger);
1773
- },
1774
- meta: async (logger) => {
1775
- const { IndexDBMetaGateway } = await import("./store-indexdb-WLRSICCB.js");
1776
- return new IndexDBMetaGateway(logger);
1777
- },
1778
- wal: async (logger) => {
1779
- const { IndexDBMetaGateway } = await import("./store-indexdb-WLRSICCB.js");
1780
- return new IndexDBMetaGateway(logger);
2214
+ gateway: async (sthis) => {
2215
+ const { IndexDBGateway } = await import("./gateway-H7UD6TNB.js");
2216
+ return new IndexDBGateway(sthis);
1781
2217
  },
1782
- test: async (logger) => {
1783
- const { IndexDBTestStore } = await import("./store-indexdb-WLRSICCB.js");
1784
- return new IndexDBTestStore(logger);
2218
+ test: async (sthis) => {
2219
+ const { IndexDBTestStore } = await import("./gateway-H7UD6TNB.js");
2220
+ return new IndexDBTestStore(sthis);
1785
2221
  }
1786
2222
  });
1787
2223
 
2224
+ // src/blockstore/store-remote.ts
2225
+ async function RemoteDataStore(sthis, name, url, opts) {
2226
+ const ds = new DataStoreImpl(sthis, name, url, opts);
2227
+ await ds.start();
2228
+ return ds;
2229
+ }
2230
+ async function RemoteMetaStore(sthis, name, url, opts) {
2231
+ const ms = new MetaStoreImpl(
2232
+ sthis,
2233
+ name,
2234
+ url,
2235
+ opts
2236
+ /* , true*/
2237
+ );
2238
+ await ms.start();
2239
+ return ms;
2240
+ }
2241
+
2242
+ // src/blockstore/connection-base.ts
2243
+ var ConnectionBase = class {
2244
+ constructor(url, logger) {
2245
+ this.loaded = Promise.resolve();
2246
+ this.logger = logger;
2247
+ this.url = url;
2248
+ }
2249
+ async refresh() {
2250
+ await throwFalsy(throwFalsy(this.loader).remoteMetaStore).load();
2251
+ await (await throwFalsy(this.loader).WALStore()).process();
2252
+ }
2253
+ async connect_X({ loader }) {
2254
+ if (!loader) throw this.logger.Error().Msg("loader is required").AsError();
2255
+ await this.connectMeta_X({ loader });
2256
+ await this.connectStorage_X({ loader });
2257
+ }
2258
+ async connectMeta_X({ loader }) {
2259
+ if (!loader) throw this.logger.Error().Msg("connectMeta_X: loader is required").AsError();
2260
+ this.loader = loader;
2261
+ await this.onConnect();
2262
+ const metaUrl = this.url.build().defParam("store", "meta").URI();
2263
+ const gateway = await getGatewayFromURL(metaUrl, this.loader.sthis);
2264
+ if (!gateway) throw this.logger.Error().Url(metaUrl).Msg("connectMeta_X: gateway is required").AsError();
2265
+ const dbName = metaUrl.getParam("name");
2266
+ if (!dbName) throw this.logger.Error().Url(metaUrl).Msg("connectMeta_X: name is required").AsError();
2267
+ const remote = await RemoteMetaStore(loader.sthis, dbName, metaUrl, {
2268
+ gateway: gateway.gateway,
2269
+ keybag: () => getKeyBag(loader.sthis, loader.ebOpts.keyBag),
2270
+ loader
2271
+ });
2272
+ this.loader.remoteMetaStore = remote;
2273
+ this.loaded = this.loader.ready().then(async () => {
2274
+ remote.load().then(async () => {
2275
+ (await throwFalsy(this.loader).WALStore()).process();
2276
+ });
2277
+ });
2278
+ }
2279
+ async connectStorage_X({ loader }) {
2280
+ if (!loader) throw this.logger.Error().Msg("connectStorage_X: loader is required").AsError();
2281
+ this.loader = loader;
2282
+ const dataUrl = this.url.build().defParam("store", "data").URI();
2283
+ const gateway = await getGatewayFromURL(dataUrl, this.loader.sthis);
2284
+ if (!gateway) throw this.logger.Error().Url(dataUrl).Msg("connectStorage_X: gateway is required").AsError();
2285
+ const name = dataUrl.getParam("name");
2286
+ if (!name) throw this.logger.Error().Url(dataUrl).Msg("connectStorage_X: name is required").AsError;
2287
+ loader.remoteCarStore = await RemoteDataStore(loader.sthis, name, this.url, {
2288
+ gateway: gateway.gateway,
2289
+ keybag: () => getKeyBag(loader.sthis, this.loader?.ebOpts.keyBag)
2290
+ });
2291
+ loader.remoteFileStore = loader.remoteCarStore;
2292
+ }
2293
+ // move this stuff to connect
2294
+ // async getDashboardURL(compact = true) {
2295
+ // const baseUrl = 'https://dashboard.fireproof.storage/'
2296
+ // if (!this.loader?.remoteCarStore) return new URL('/howto', baseUrl)
2297
+ // // if (compact) {
2298
+ // // await this.compact()
2299
+ // // }
2300
+ // const currents = await this.loader?.metaStore?.load()
2301
+ // if (!currents) throw new Error("Can't sync empty database: save data first")
2302
+ // if (currents.length > 1)
2303
+ // throw new Error("Can't sync database with split heads: make an update first")
2304
+ // const current = currents[0]
2305
+ // const params = {
2306
+ // car: current.car.toString()
2307
+ // }
2308
+ // if (current.key) {
2309
+ // // @ts-ignore
2310
+ // params.key = current.key.toString()
2311
+ // }
2312
+ // // @ts-ignore
2313
+ // if (this.name) {
2314
+ // // @ts-ignore
2315
+ // params.name = this.name
2316
+ // }
2317
+ // const url = new URL('/import#' + new URLSearchParams(params).toString(), baseUrl)
2318
+ // console.log('Import to dashboard: ' + url.toString())
2319
+ // return url
2320
+ // }
2321
+ // openDashboard() {
2322
+ // void this.getDashboardURL().then(url => {
2323
+ // if (url) window.open(url.toString(), '_blank')
2324
+ // })
2325
+ // }
2326
+ };
2327
+
1788
2328
  // src/crdt-helpers.ts
1789
2329
  function time(tag) {
1790
2330
  }
@@ -1833,7 +2373,7 @@ async function writeDocContent(store, blocks, update, logger) {
1833
2373
  await processFiles(store, blocks, update.value, logger);
1834
2374
  value = { doc: update.value };
1835
2375
  }
1836
- const block = await encode3({ value, hasher: hasher2, codec: codec2 });
2376
+ const block = await encode({ value, hasher: hasher5, codec });
1837
2377
  blocks.putSync(block.cid, block.bytes);
1838
2378
  return block.cid;
1839
2379
  }
@@ -1842,10 +2382,16 @@ async function processFiles(store, blocks, doc, logger) {
1842
2382
  await processFileset(logger, store, blocks, doc._files);
1843
2383
  }
1844
2384
  if (doc._publicFiles) {
1845
- await processFileset(logger, store, blocks, doc._publicFiles, true);
2385
+ await processFileset(
2386
+ logger,
2387
+ store,
2388
+ blocks,
2389
+ doc._publicFiles
2390
+ /*, true*/
2391
+ );
1846
2392
  }
1847
2393
  }
1848
- async function processFileset(logger, store, blocks, files, publicFiles = false) {
2394
+ async function processFileset(logger, store, blocks, files) {
1849
2395
  const dbBlockstore = blocks.parent;
1850
2396
  if (!dbBlockstore.loader) throw logger.Error().Msg("Missing loader, database name is required").AsError();
1851
2397
  const t = new CarTransaction(dbBlockstore);
@@ -1867,9 +2413,10 @@ async function processFileset(logger, store, blocks, files, publicFiles = false)
1867
2413
  }
1868
2414
  }
1869
2415
  if (didPut.length) {
1870
- const car = await dbBlockstore.loader.commitFiles(t, { files }, {
1871
- public: publicFiles
1872
- });
2416
+ const car = await dbBlockstore.loader.commitFiles(
2417
+ t,
2418
+ { files }
2419
+ );
1873
2420
  if (car) {
1874
2421
  for (const name of didPut) {
1875
2422
  files[name] = { car, ...files[name] };
@@ -1903,7 +2450,7 @@ function readFileset(blocks, files, isPublic = false) {
1903
2450
  fileMeta.file = async () => await blocks.ebOpts.storeRuntime.decodeFile(
1904
2451
  {
1905
2452
  get: async (cid) => {
1906
- return await blocks.getFile(throwFalsy(fileMeta.car), cid, isPublic);
2453
+ return await blocks.getFile(throwFalsy(fileMeta.car), cid);
1907
2454
  }
1908
2455
  },
1909
2456
  fileMeta.cid,
@@ -1917,7 +2464,7 @@ function readFileset(blocks, files, isPublic = false) {
1917
2464
  async function getValueFromLink(blocks, link, logger) {
1918
2465
  const block = await blocks.get(link);
1919
2466
  if (!block) throw logger.Error().Str("link", link.toString()).Msg(`Missing linked block`).AsError();
1920
- const { value } = await decode3({ bytes: block.bytes, hasher: hasher2, codec: codec2 });
2467
+ const { value } = await decode({ bytes: block.bytes, hasher: hasher5, codec });
1921
2468
  const cvalue = {
1922
2469
  ...value,
1923
2470
  cid: link
@@ -1926,17 +2473,21 @@ async function getValueFromLink(blocks, link, logger) {
1926
2473
  return cvalue;
1927
2474
  }
1928
2475
  var DirtyEventFetcher = class extends EventFetcher {
2476
+ constructor(logger, blocks) {
2477
+ super(blocks);
2478
+ this.logger = logger;
2479
+ }
1929
2480
  async get(link) {
1930
2481
  try {
1931
2482
  return super.get(link);
1932
2483
  } catch (e) {
1933
- console.error("missing event", link.toString(), e);
2484
+ this.logger.Error().Ref("link", link.toString()).Err(e).Msg("Missing event");
1934
2485
  return { value: void 0 };
1935
2486
  }
1936
2487
  }
1937
2488
  };
1938
2489
  async function clockChangesSince(blocks, head, since, opts, logger) {
1939
- const eventsFetcher = opts.dirty ? new DirtyEventFetcher(blocks) : new EventFetcher(blocks);
2490
+ const eventsFetcher = opts.dirty ? new DirtyEventFetcher(logger, blocks) : new EventFetcher(blocks);
1940
2491
  const keys = /* @__PURE__ */ new Set();
1941
2492
  const updates = await gatherUpdates(
1942
2493
  blocks,
@@ -2032,20 +2583,19 @@ async function doCompact(blockLog, head, logger) {
2032
2583
  isCompacting = false;
2033
2584
  }
2034
2585
  async function getBlock(blocks, cidString) {
2035
- const block = await blocks.get(parse2(cidString));
2586
+ const block = await blocks.get(parse3(cidString));
2036
2587
  if (!block) throw new Error(`Missing block ${cidString}`);
2037
- const { cid, value } = await decode3({ bytes: block.bytes, codec: codec2, hasher: hasher2 });
2038
- return new Block2({ cid, value, bytes: block.bytes });
2588
+ const { cid, value } = await decode({ bytes: block.bytes, codec, hasher: hasher5 });
2589
+ return new Block({ cid, value, bytes: block.bytes });
2039
2590
  }
2040
2591
 
2041
2592
  // src/indexer-helpers.ts
2042
- import { create as create3 } from "multiformats/block";
2043
- import { sha256 as hasher3 } from "multiformats/hashes/sha2";
2044
- import * as codec3 from "@ipld/dag-cbor";
2593
+ import { sha256 as hasher6 } from "multiformats/hashes/sha2";
2594
+ import * as codec2 from "@ipld/dag-cbor";
2045
2595
  import charwise from "charwise";
2046
2596
  import * as DbIndex from "prolly-trees/db-index";
2047
- import { bf as bf2, simpleCompare } from "prolly-trees/utils";
2048
- import { nocache as cache2 } from "prolly-trees/cache";
2597
+ import { bf, simpleCompare } from "prolly-trees/utils";
2598
+ import { nocache as cache } from "prolly-trees/cache";
2049
2599
  var IndexTree = class {
2050
2600
  };
2051
2601
  function refCompare(aRef, bRef) {
@@ -2061,8 +2611,8 @@ function compare(a, b) {
2061
2611
  if (comp !== 0) return comp;
2062
2612
  return refCompare(aRef, bRef);
2063
2613
  }
2064
- var byKeyOpts = { cache: cache2, chunker: bf2(30), codec: codec3, hasher: hasher3, compare };
2065
- var byIdOpts = { cache: cache2, chunker: bf2(30), codec: codec3, hasher: hasher3, compare: simpleCompare };
2614
+ var byKeyOpts = { cache, chunker: bf(30), codec: codec2, hasher: hasher6, compare };
2615
+ var byIdOpts = { cache, chunker: bf(30), codec: codec2, hasher: hasher6, compare: simpleCompare };
2066
2616
  function indexEntriesForChanges(changes, mapFn) {
2067
2617
  const indexEntries = [];
2068
2618
  changes.forEach(({ id: key, value, del }) => {
@@ -2090,7 +2640,7 @@ function makeProllyGetBlock(blocks) {
2090
2640
  const block = await blocks.get(address);
2091
2641
  if (!block) throw new Error(`Missing block ${address.toString()}`);
2092
2642
  const { cid, bytes } = block;
2093
- return create3({ cid, bytes, hasher: hasher3, codec: codec3 });
2643
+ return create({ cid, bytes, hasher: hasher6, codec: codec2 });
2094
2644
  };
2095
2645
  }
2096
2646
  async function bulkIndex(tblocks, inIndex, indexEntries, opts) {
@@ -2161,25 +2711,25 @@ function encodeKey(key) {
2161
2711
  }
2162
2712
 
2163
2713
  // src/indexer.ts
2164
- function index({ _crdt }, name, mapFn, meta) {
2714
+ function index(sthis, { _crdt }, name, mapFn, meta) {
2165
2715
  if (mapFn && meta) throw _crdt.logger.Error().Msg("cannot provide both mapFn and meta").AsError();
2166
2716
  if (mapFn && mapFn.constructor.name !== "Function") throw _crdt.logger.Error().Msg("mapFn must be a function").AsError();
2167
2717
  if (_crdt.indexers.has(name)) {
2168
2718
  const idx = _crdt.indexers.get(name);
2169
2719
  idx.applyMapFn(name, mapFn, meta);
2170
2720
  } else {
2171
- const idx = new Index(_crdt, name, mapFn, meta);
2721
+ const idx = new Index(sthis, _crdt, name, mapFn, meta);
2172
2722
  _crdt.indexers.set(name, idx);
2173
2723
  }
2174
2724
  return _crdt.indexers.get(name);
2175
2725
  }
2176
2726
  var Index = class {
2177
- constructor(crdt, name, mapFn, meta) {
2727
+ constructor(sthis, crdt, name, mapFn, meta) {
2178
2728
  this.mapFnString = "";
2179
2729
  this.byKey = new IndexTree();
2180
2730
  this.byId = new IndexTree();
2181
2731
  this.includeDocsDefault = false;
2182
- this.logger = ensureLogger(crdt.logger, "Index");
2732
+ this.logger = ensureLogger(sthis, "Index");
2183
2733
  this.blockstore = crdt.indexBlockstore;
2184
2734
  this.crdt = crdt;
2185
2735
  this.applyMapFn(name, mapFn, meta);
@@ -2234,7 +2784,7 @@ var Index = class {
2234
2784
  }
2235
2785
  if (this.mapFnString) {
2236
2786
  if (this.mapFnString !== mapFn.toString()) {
2237
- throw this.logger.Error().Msg("cannot apply different mapFn app").AsError();
2787
+ throw this.logger.Error().Str("mapFnString", this.mapFnString).Str("mapFn", mapFn.toString()).Msg("cannot apply different mapFn app").AsError();
2238
2788
  }
2239
2789
  } else {
2240
2790
  this.mapFnString = mapFn.toString();
@@ -2369,7 +2919,7 @@ var Index = class {
2369
2919
  // src/crdt-clock.ts
2370
2920
  import { advance } from "@web3-storage/pail/clock";
2371
2921
  import { root as root2 } from "@web3-storage/pail/crdt";
2372
- import { ResolveOnce as ResolveOnce3 } from "@adviser/cement";
2922
+ import { ResolveOnce as ResolveOnce4 } from "@adviser/cement";
2373
2923
 
2374
2924
  // src/apply-head-queue.ts
2375
2925
  function applyHeadQueue(worker, logger) {
@@ -2384,7 +2934,7 @@ function applyHeadQueue(worker, logger) {
2384
2934
  queue.sort((a, b) => b.updates ? 1 : -1);
2385
2935
  const task = queue.shift();
2386
2936
  if (!task) continue;
2387
- await worker(task.newHead, task.prevHead, task.updates !== null).catch((e) => {
2937
+ await worker(task.newHead, task.prevHead, task.updates !== void 0).catch((e) => {
2388
2938
  throw logger.Error().Err(e).Msg("int_applyHead worker error").AsError();
2389
2939
  });
2390
2940
  if (task.updates) {
@@ -2426,9 +2976,9 @@ var CRDTClock = class {
2426
2976
  this.zoomers = /* @__PURE__ */ new Set();
2427
2977
  this.watchers = /* @__PURE__ */ new Set();
2428
2978
  this.emptyWatchers = /* @__PURE__ */ new Set();
2429
- this._ready = new ResolveOnce3();
2979
+ this._ready = new ResolveOnce4();
2430
2980
  this.blockstore = blockstore;
2431
- this.logger = ensureLogger(blockstore.logger, "CRDTClock");
2981
+ this.logger = ensureLogger(blockstore.sthis, "CRDTClock");
2432
2982
  this.applyHeadQueue = applyHeadQueue(this.int_applyHead.bind(this), this.logger);
2433
2983
  }
2434
2984
  async ready() {
@@ -2474,6 +3024,7 @@ var CRDTClock = class {
2474
3024
  this.zoomers.add(fn);
2475
3025
  }
2476
3026
  async int_applyHead(newHead, prevHead, localUpdates) {
3027
+ const noLoader = !localUpdates;
2477
3028
  const ogHead = sortClockHead(this.head);
2478
3029
  newHead = sortClockHead(newHead);
2479
3030
  if (compareClockHeads(ogHead, newHead)) {
@@ -2484,7 +3035,6 @@ var CRDTClock = class {
2484
3035
  this.setHead(newHead);
2485
3036
  return;
2486
3037
  }
2487
- const noLoader = !localUpdates;
2488
3038
  if (!this.blockstore) {
2489
3039
  throw this.logger.Error().Msg("missing blockstore").AsError();
2490
3040
  }
@@ -2501,7 +3051,7 @@ var CRDTClock = class {
2501
3051
  }
2502
3052
  return { head: advancedHead };
2503
3053
  },
2504
- { noLoader }
3054
+ { noLoader, add: false }
2505
3055
  );
2506
3056
  this.setHead(meta.head);
2507
3057
  }
@@ -2535,13 +3085,14 @@ async function advanceBlocks(logger, newHead, tblocks, head) {
2535
3085
 
2536
3086
  // src/crdt.ts
2537
3087
  var CRDT = class {
2538
- constructor(name, opts = {}) {
2539
- this.onceReady = new ResolveOnce4();
3088
+ constructor(sthis, name, opts = {}) {
2540
3089
  this.indexers = /* @__PURE__ */ new Map();
3090
+ this.onceReady = new ResolveOnce5();
3091
+ this.sthis = sthis;
2541
3092
  this.name = name;
2542
- this.logger = ensureLogger(opts, "CRDT");
3093
+ this.logger = ensureLogger(sthis, "CRDT");
2543
3094
  this.opts = opts;
2544
- this.blockstore = blockstoreFactory({
3095
+ this.blockstore = blockstoreFactory(sthis, {
2545
3096
  name,
2546
3097
  applyMeta: async (meta) => {
2547
3098
  const crdtMeta = meta;
@@ -2553,22 +3104,20 @@ var CRDT = class {
2553
3104
  return { head: this.clock.head };
2554
3105
  },
2555
3106
  autoCompact: this.opts.autoCompact || 100,
2556
- crypto: this.opts.crypto,
2557
3107
  store: { ...this.opts.store, isIndex: void 0 },
2558
3108
  public: this.opts.public,
2559
3109
  meta: this.opts.meta,
2560
3110
  threshold: this.opts.threshold
2561
3111
  });
2562
- this.indexBlockstore = blockstoreFactory({
3112
+ this.indexBlockstore = blockstoreFactory(sthis, {
2563
3113
  name,
2564
3114
  applyMeta: async (meta) => {
2565
3115
  const idxCarMeta = meta;
2566
3116
  if (!idxCarMeta.indexes) throw this.logger.Error().Msg("missing indexes").AsError();
2567
3117
  for (const [name2, idx] of Object.entries(idxCarMeta.indexes)) {
2568
- index({ _crdt: this }, name2, void 0, idx);
3118
+ index(this.sthis, { _crdt: this }, name2, void 0, idx);
2569
3119
  }
2570
3120
  },
2571
- crypto: this.opts.crypto,
2572
3121
  store: { ...this.opts.store, isIndex: this.opts.store?.isIndex || "idx" },
2573
3122
  public: this.opts.public
2574
3123
  });
@@ -2579,17 +3128,6 @@ var CRDT = class {
2579
3128
  }
2580
3129
  });
2581
3130
  }
2582
- async ready() {
2583
- return this.onceReady.once(async () => {
2584
- await Promise.all([this.blockstore.ready(), this.indexBlockstore.ready(), this.clock.ready()]);
2585
- });
2586
- }
2587
- async close() {
2588
- await Promise.all([this.blockstore.close(), this.indexBlockstore.close(), this.clock.close()]);
2589
- }
2590
- async destroy() {
2591
- await Promise.all([this.blockstore.destroy(), this.indexBlockstore.destroy()]);
2592
- }
2593
3131
  async bulk(updates) {
2594
3132
  await this.ready();
2595
3133
  const prevHead = [...this.clock.head];
@@ -2610,6 +3148,21 @@ var CRDT = class {
2610
3148
  await this.clock.applyHead(done.meta.head, prevHead, updates);
2611
3149
  return done.meta;
2612
3150
  }
3151
+ async ready() {
3152
+ return this.onceReady.once(async () => {
3153
+ try {
3154
+ await Promise.all([this.blockstore.ready(), this.indexBlockstore.ready(), this.clock.ready()]);
3155
+ } catch (e) {
3156
+ throw this.logger.Error().Err(e).Msg(`CRDT is not ready`).AsError();
3157
+ }
3158
+ });
3159
+ }
3160
+ async close() {
3161
+ await Promise.all([this.blockstore.close(), this.indexBlockstore.close(), this.clock.close()]);
3162
+ }
3163
+ async destroy() {
3164
+ await Promise.all([this.blockstore.destroy(), this.indexBlockstore.destroy()]);
3165
+ }
2613
3166
  // if (snap) await this.clock.applyHead(crdtMeta.head, this.clock.head)
2614
3167
  async allDocs() {
2615
3168
  await this.ready();
@@ -2654,11 +3207,12 @@ var Database = class {
2654
3207
  this._listening = false;
2655
3208
  this._listeners = /* @__PURE__ */ new Set();
2656
3209
  this._noupdate_listeners = /* @__PURE__ */ new Set();
2657
- this._ready = new ResolveOnce5();
3210
+ this._ready = new ResolveOnce6();
2658
3211
  this.name = name;
2659
3212
  this.opts = opts || this.opts;
2660
- this.logger = ensureLogger(this.opts, "Database");
2661
- this._crdt = new CRDT(name, this.opts);
3213
+ this.sthis = ensureSuperThis(this.opts);
3214
+ this.logger = ensureLogger(this.sthis, "Database");
3215
+ this._crdt = new CRDT(this.sthis, name, this.opts);
2662
3216
  this.blockstore = this._crdt.blockstore;
2663
3217
  this._writeQueue = writeQueue(async (updates) => {
2664
3218
  return await this._crdt.bulk(updates);
@@ -2682,7 +3236,7 @@ var Database = class {
2682
3236
  }
2683
3237
  async ready() {
2684
3238
  return this._ready.once(async () => {
2685
- await SysContainer.start();
3239
+ await this.sthis.start();
2686
3240
  await this._crdt.ready();
2687
3241
  await this.blockstore.ready();
2688
3242
  });
@@ -2702,7 +3256,7 @@ var Database = class {
2702
3256
  await this.ready();
2703
3257
  this.logger.Debug().Str("id", doc._id).Msg("put");
2704
3258
  const { _id, ...value } = doc;
2705
- const docId = _id || uuidv7();
3259
+ const docId = _id || this.sthis.timeOrderedNextId().str;
2706
3260
  const result = await this._writeQueue.push({
2707
3261
  id: docId,
2708
3262
  value: {
@@ -2767,7 +3321,7 @@ var Database = class {
2767
3321
  await this.ready();
2768
3322
  this.logger.Debug().Any("field", field).Any("opts", opts).Msg("query");
2769
3323
  const _crdt = this._crdt;
2770
- const idx = typeof field === "string" ? index({ _crdt }, field) : index({ _crdt }, makeName(field.toString()), field);
3324
+ const idx = typeof field === "string" ? index(this.sthis, { _crdt }, field) : index(this.sthis, { _crdt }, makeName(field.toString()), field);
2771
3325
  return await idx.query(opts);
2772
3326
  }
2773
3327
  async compact() {
@@ -2804,12 +3358,7 @@ function fireproof(name, opts) {
2804
3358
  const key = JSON.stringify(
2805
3359
  toSortedArray({
2806
3360
  name,
2807
- stores: toSortedArray(opts?.store?.stores),
2808
- makeMetaStore: !!opts?.store?.makeMetaStore,
2809
- makeDataStore: !!opts?.store?.makeDataStore,
2810
- makeRemoteWAL: !!opts?.store?.makeRemoteWAL,
2811
- encodeFile: !!opts?.store?.encodeFile,
2812
- decodeFile: !!opts?.store?.decodeFile
3361
+ stores: toSortedArray(opts?.store?.stores)
2813
3362
  })
2814
3363
  );
2815
3364
  let db = Database.databases.get(key);
@@ -2824,7 +3373,10 @@ function makeName(fnString) {
2824
3373
  let found = null;
2825
3374
  const matches = Array.from(fnString.matchAll(regex), (match) => match[1].trim());
2826
3375
  if (matches.length === 0) {
2827
- found = /=>\s*(.*)/.exec(fnString);
3376
+ found = /=>\s*{?\s*([^{}]+)\s*}?/.exec(fnString);
3377
+ if (found && found[1].includes("return")) {
3378
+ found = null;
3379
+ }
2828
3380
  }
2829
3381
  if (!found) {
2830
3382
  return fnString;
@@ -2833,20 +3385,53 @@ function makeName(fnString) {
2833
3385
  }
2834
3386
  }
2835
3387
 
3388
+ // src/runtime/index.ts
3389
+ var runtime_exports = {};
3390
+ __export(runtime_exports, {
3391
+ FILESTORE_VERSION: () => FILESTORE_VERSION,
3392
+ INDEXDB_VERSION: () => INDEXDB_VERSION,
3393
+ files: () => files_exports,
3394
+ getFileName: () => getFileName,
3395
+ getFileSystem: () => getFileSystem,
3396
+ getPath: () => getPath,
3397
+ kb: () => key_bag_exports,
3398
+ kc: () => keyed_crypto_exports,
3399
+ mf: () => wait_pr_multiformats_exports,
3400
+ runtimeFn: () => runtimeFn2,
3401
+ toArrayBuffer: () => toArrayBuffer
3402
+ });
3403
+
3404
+ // src/runtime/wait-pr-multiformats/index.ts
3405
+ var wait_pr_multiformats_exports = {};
3406
+ __export(wait_pr_multiformats_exports, {
3407
+ block: () => block_exports,
3408
+ codec: () => codec_interface_exports
3409
+ });
3410
+
3411
+ // src/runtime/wait-pr-multiformats/codec-interface.ts
3412
+ var codec_interface_exports = {};
3413
+
3414
+ // src/runtime/index.ts
3415
+ import { runtimeFn as runtimeFn2 } from "@adviser/cement";
3416
+
2836
3417
  // src/version.ts
2837
3418
  var PACKAGE_VERSION = Object.keys({
2838
- "0.19.8-dev-getcon": "xxxx"
3419
+ "0.19.8-dev-series-1": "xxxx"
2839
3420
  })[0];
2840
3421
  export {
2841
3422
  CRDT,
2842
3423
  Database,
2843
3424
  Index,
3425
+ NotFoundError,
2844
3426
  PACKAGE_VERSION,
2845
3427
  Result,
3428
+ UInt8ArrayEqual,
2846
3429
  blockstore_exports as blockstore,
2847
3430
  blockstore_exports as bs,
3431
+ dataDir,
2848
3432
  ensureLogger,
2849
- exception2Result,
3433
+ ensureSuperLog,
3434
+ ensureSuperThis,
2850
3435
  exceptionWrapper,
2851
3436
  falsyToUndef,
2852
3437
  fireproof,
@@ -2855,6 +3440,7 @@ export {
2855
3440
  getStore,
2856
3441
  index,
2857
3442
  isFalsy,
3443
+ isNotFoundError,
2858
3444
  runtime_exports as rt,
2859
3445
  runtime_exports as runtime,
2860
3446
  throwFalsy