@fireproof/core 0.19.8-dev-getcon → 0.19.9-dev-frag

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 (58) hide show
  1. package/README.md +7 -0
  2. package/chunk-7EWIAXTM.js +7 -0
  3. package/chunk-7EWIAXTM.js.map +1 -0
  4. package/chunk-JO5AVWG7.js +67 -0
  5. package/chunk-JO5AVWG7.js.map +1 -0
  6. package/chunk-PB4BKL4O.js +7 -0
  7. package/chunk-PB4BKL4O.js.map +1 -0
  8. package/chunk-YS4GL6OK.js +266 -0
  9. package/chunk-YS4GL6OK.js.map +1 -0
  10. package/{store-indexdb-WLRSICCB.js → gateway-IZRHJWPE.js} +48 -80
  11. package/gateway-IZRHJWPE.js.map +1 -0
  12. package/gateway-YSNUK2L3.js +145 -0
  13. package/gateway-YSNUK2L3.js.map +1 -0
  14. package/index.cjs +2132 -1783
  15. package/index.cjs.map +1 -1
  16. package/index.d.cts +613 -513
  17. package/index.d.ts +613 -513
  18. package/index.global.js +19367 -20108
  19. package/index.global.js.map +1 -1
  20. package/index.js +1512 -1022
  21. package/index.js.map +1 -1
  22. package/key-bag-file-NMEBFSPM.js +54 -0
  23. package/key-bag-file-NMEBFSPM.js.map +1 -0
  24. package/key-bag-indexdb-X5V6GNBZ.js +50 -0
  25. package/key-bag-indexdb-X5V6GNBZ.js.map +1 -0
  26. package/mem-filesystem-B6C6QOIP.js +41 -0
  27. package/mem-filesystem-B6C6QOIP.js.map +1 -0
  28. package/metafile-cjs.json +1 -1
  29. package/metafile-esm.json +1 -1
  30. package/metafile-iife.json +1 -1
  31. package/node-filesystem-5JLBSHKQ.js +41 -0
  32. package/node-filesystem-5JLBSHKQ.js.map +1 -0
  33. package/package.json +8 -7
  34. package/tests/blockstore/fragment-gateway.test.ts +107 -0
  35. package/tests/blockstore/keyed-crypto.test.ts +302 -0
  36. package/tests/blockstore/loader.test.ts +24 -19
  37. package/tests/blockstore/store.test.ts +34 -28
  38. package/tests/blockstore/transaction.test.ts +19 -15
  39. package/tests/fireproof/config.test.ts +94 -78
  40. package/tests/fireproof/crdt.test.ts +34 -28
  41. package/tests/fireproof/database.test.ts +22 -14
  42. package/tests/fireproof/fireproof.test.fixture.ts +133 -0
  43. package/tests/fireproof/fireproof.test.ts +331 -219
  44. package/tests/fireproof/hello.test.ts +6 -4
  45. package/tests/fireproof/indexer.test.ts +34 -27
  46. package/tests/fireproof/utils.test.ts +65 -0
  47. package/tests/helpers.ts +25 -57
  48. package/utils-IZPK4QS7.js +14 -0
  49. package/utils-IZPK4QS7.js.map +1 -0
  50. package/chunk-BNL4PVBF.js +0 -314
  51. package/chunk-BNL4PVBF.js.map +0 -1
  52. package/chunk-JW2QT6BF.js +0 -184
  53. package/chunk-JW2QT6BF.js.map +0 -1
  54. package/node-sys-container-MIEX6ELJ.js +0 -29
  55. package/node-sys-container-MIEX6ELJ.js.map +0 -1
  56. package/store-file-VJ6BI4II.js +0 -191
  57. package/store-file-VJ6BI4II.js.map +0 -1
  58. package/store-indexdb-WLRSICCB.js.map +0 -1
package/index.js CHANGED
@@ -1,29 +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-JO5AVWG7.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,
20
+ ensureSuperLog,
21
+ ensureSuperThis,
8
22
  exception2Result,
9
23
  exceptionWrapper,
10
24
  getKey,
11
25
  getName,
12
26
  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";
27
+ isNotFoundError
28
+ } from "./chunk-YS4GL6OK.js";
24
29
 
25
30
  // src/database.ts
26
- import { uuidv7 } from "uuidv7";
27
31
  import { ResolveOnce as ResolveOnce5 } from "@adviser/cement";
28
32
 
29
33
  // src/write-queue.ts
@@ -69,11 +73,81 @@ function writeQueue(worker, payload = Infinity, unbounded = false) {
69
73
  // src/crdt.ts
70
74
  import { ResolveOnce as ResolveOnce4 } from "@adviser/cement";
71
75
 
76
+ // src/runtime/wait-pr-multiformats/block.ts
77
+ var block_exports = {};
78
+ __export(block_exports, {
79
+ Block: () => Block,
80
+ create: () => create,
81
+ createUnsafe: () => createUnsafe,
82
+ decode: () => decode,
83
+ encode: () => encode
84
+ });
85
+ import { bytes as binary, CID } from "multiformats";
86
+ import { Block as mfBlock } from "multiformats/block";
87
+ var Block = mfBlock;
88
+ async function decode({
89
+ bytes,
90
+ codec: codec3,
91
+ hasher: hasher7
92
+ }) {
93
+ if (bytes == null) throw new Error('Missing required argument "bytes"');
94
+ if (codec3 == null || hasher7 == null) throw new Error("Missing required argument: codec or hasher");
95
+ const value = await Promise.resolve(codec3.decode(bytes));
96
+ const hash = await hasher7.digest(bytes);
97
+ const cid = CID.create(1, codec3.code, hash);
98
+ return new mfBlock({ value, bytes, cid });
99
+ }
100
+ async function encode({
101
+ value,
102
+ codec: codec3,
103
+ hasher: hasher7
104
+ }) {
105
+ if (typeof value === "undefined") throw new Error('Missing required argument "value"');
106
+ if (codec3 == null || hasher7 == null) throw new Error("Missing required argument: codec or hasher");
107
+ const bytes = await Promise.resolve(codec3.encode(value));
108
+ const hash = await hasher7.digest(bytes);
109
+ const cid = CID.create(1, codec3.code, hash);
110
+ return new mfBlock({ value, bytes, cid });
111
+ }
112
+ async function create({
113
+ bytes,
114
+ cid,
115
+ hasher: hasher7,
116
+ codec: codec3
117
+ }) {
118
+ if (bytes == null) throw new Error('Missing required argument "bytes"');
119
+ if (hasher7 == null) throw new Error('Missing required argument "hasher"');
120
+ const value = await Promise.resolve(codec3.decode(bytes));
121
+ const hash = await hasher7.digest(bytes);
122
+ if (!binary.equals(cid.multihash.bytes, hash.bytes)) {
123
+ throw new Error("CID hash does not match bytes");
124
+ }
125
+ return createUnsafe({
126
+ bytes,
127
+ cid,
128
+ value,
129
+ codec: codec3
130
+ });
131
+ }
132
+ async function createUnsafe({
133
+ bytes,
134
+ cid,
135
+ value: maybeValue,
136
+ codec: codec3
137
+ }) {
138
+ const value = await Promise.resolve(maybeValue !== void 0 ? maybeValue : codec3?.decode(bytes));
139
+ if (value === void 0) throw new Error('Missing required argument, must either provide "value" or "codec"');
140
+ return new Block({
141
+ cid,
142
+ bytes,
143
+ value
144
+ });
145
+ }
146
+
72
147
  // src/crdt-helpers.ts
73
- import { encode as encode3, decode as decode3, Block as Block2 } from "multiformats/block";
74
148
  import { parse as parse2 } from "multiformats/link";
75
- import { sha256 as hasher2 } from "multiformats/hashes/sha2";
76
- import * as codec2 from "@ipld/dag-cbor";
149
+ import { sha256 as hasher5 } from "multiformats/hashes/sha2";
150
+ import * as codec from "@ipld/dag-cbor";
77
151
  import { put, get, entries, root } from "@web3-storage/pail/crdt";
78
152
  import { EventFetcher, vis } from "@web3-storage/pail/clock";
79
153
  import * as Batch from "@web3-storage/pail/crdt/batch";
@@ -84,512 +158,145 @@ __export(blockstore_exports, {
84
158
  BaseBlockstore: () => BaseBlockstore,
85
159
  CarTransaction: () => CarTransaction,
86
160
  CompactionFetcher: () => CompactionFetcher,
87
- ConnectREST: () => ConnectREST,
88
161
  ConnectionBase: () => ConnectionBase,
89
- DataStore: () => DataStore,
90
162
  EncryptedBlockstore: () => EncryptedBlockstore,
91
- Loadable: () => Loadable,
163
+ FragmentGateway: () => FragmentGateway,
92
164
  Loader: () => Loader,
93
- MetaStore: () => MetaStore,
94
- NotFoundError: () => NotFoundError,
95
- RemoteWAL: () => RemoteWAL,
96
- isNotFoundError: () => isNotFoundError,
165
+ ensureStart: () => ensureStart,
166
+ getGatewayFromURL: () => getGatewayFromURL,
97
167
  parseCarFile: () => parseCarFile,
98
168
  registerStoreProtocol: () => registerStoreProtocol,
99
169
  testStoreFactory: () => testStoreFactory,
100
- toStoreRuntime: () => toStoreRuntime,
101
- toURL: () => toURL
170
+ toCIDBlock: () => toCIDBlock,
171
+ toStoreRuntime: () => toStoreRuntime
102
172
  });
103
173
 
104
- // src/blockstore/connection-base.ts
105
- import { EventBlock, decodeEventBlock } from "@web3-storage/pail/clock";
106
- import { MemoryBlockstore } from "@web3-storage/pail/block";
174
+ // src/blockstore/types.ts
175
+ function toCIDBlock(block) {
176
+ return block;
177
+ }
107
178
 
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
- };
179
+ // src/blockstore/store-factory.ts
180
+ import { KeyedResolvOnce as KeyedResolvOnce2, URI as URI3 } from "@adviser/cement";
154
181
 
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
182
+ // src/runtime/files.ts
183
+ var files_exports = {};
184
+ __export(files_exports, {
185
+ decodeFile: () => decodeFile,
186
+ encodeFile: () => encodeFile
187
+ });
188
+ import * as UnixFS from "@ipld/unixfs";
189
+ import * as raw from "multiformats/codecs/raw";
190
+ import { withMaxChunkSize } from "@ipld/unixfs/file/chunker/fixed";
191
+ import { withWidth } from "@ipld/unixfs/file/layout/balanced";
192
+ import { exporter } from "ipfs-unixfs-exporter";
193
+ var queuingStrategy = UnixFS.withCapacity();
194
+ var settings = UnixFS.configure({
195
+ fileChunkEncoder: raw,
196
+ smallFileEncoder: raw,
197
+ chunker: withMaxChunkSize(1024 * 1024),
198
+ fileLayout: withWidth(1024)
199
+ });
200
+ async function collect(collectable) {
201
+ const chunks = [];
202
+ await collectable.pipeTo(
203
+ new WritableStream({
204
+ write(chunk) {
205
+ chunks.push(chunk);
206
+ }
207
+ })
208
+ );
209
+ return chunks;
210
+ }
211
+ async function encodeFile(blob) {
212
+ const readable = createFileEncoderStream(blob);
213
+ const blocks = await collect(readable);
214
+ return { cid: blocks.at(-1).cid, blocks };
215
+ }
216
+ async function decodeFile(blocks, cid, meta) {
217
+ const entry = await exporter(cid.toString(), blocks, { length: meta.size });
218
+ const chunks = [];
219
+ for await (const chunk of entry.content()) {
220
+ chunks.push(chunk);
221
+ }
222
+ return new File(chunks, entry.name, { type: meta.type, lastModified: 0 });
223
+ }
224
+ function createFileEncoderStream(blob) {
225
+ const { readable, writable } = new TransformStream({}, queuingStrategy);
226
+ const unixfsWriter = UnixFS.createWriter({ writable, settings });
227
+ const fileBuilder = new UnixFSFileBuilder("", blob);
228
+ void (async () => {
229
+ await fileBuilder.finalize(unixfsWriter);
230
+ await unixfsWriter.close();
231
+ })();
232
+ return readable;
233
+ }
234
+ var UnixFSFileBuilder = class {
235
+ #file;
236
+ constructor(name, file) {
237
+ this.name = name;
238
+ this.#file = file;
239
+ }
240
+ async finalize(writer) {
241
+ const unixfsFileWriter = UnixFS.createFileWriter(writer);
242
+ await this.#file.stream().pipeTo(
243
+ new WritableStream({
244
+ async write(chunk) {
245
+ await unixfsFileWriter.write(chunk);
246
+ }
247
+ })
196
248
  );
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;
203
- }
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
- };
238
-
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;
262
- }
263
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
264
- async metaUpload(bytes, params) {
265
- return void 0;
266
- }
267
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
268
- async metaDownload(params) {
269
- return [];
249
+ return await unixfsFileWriter.close();
270
250
  }
271
251
  };
272
252
 
273
- // src/blockstore/store-factory.ts
274
- import { KeyedResolvOnce } from "@adviser/cement";
275
-
276
253
  // src/blockstore/store.ts
277
254
  import pLimit2 from "p-limit";
278
255
  import { format, parse } from "@ipld/dag-json";
279
- import { ResolveOnce as ResolveOnce2, Result as Result2 } from "@adviser/cement";
256
+ import { ResolveOnce as ResolveOnce2, Result as Result3 } from "@adviser/cement";
257
+
258
+ // src/types.ts
259
+ function isFalsy(value) {
260
+ return value === false && value === null && value === void 0;
261
+ }
262
+ function throwFalsy(value) {
263
+ if (isFalsy(value)) {
264
+ throw new Error("value is Falsy");
265
+ }
266
+ return value;
267
+ }
268
+ function falsyToUndef(value) {
269
+ if (isFalsy(value)) {
270
+ return void 0;
271
+ }
272
+ return value;
273
+ }
280
274
 
281
275
  // src/blockstore/loader.ts
282
276
  import pLimit from "p-limit";
283
277
  import { CarReader } from "@ipld/car";
284
278
  import { ResolveOnce } from "@adviser/cement";
285
279
 
286
- // src/blockstore/types.ts
287
- function toCIDBlock(block) {
288
- return block;
289
- }
290
-
291
280
  // src/blockstore/loader-helpers.ts
292
- import { encode, decode } from "multiformats/block";
293
281
  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
- }
282
+ import * as dagCodec from "@ipld/dag-cbor";
322
283
  async function parseCarFile(reader, logger) {
323
284
  const roots = await reader.getRoots();
324
285
  const header = await reader.get(roots[0]);
325
286
  if (!header) throw logger.Error().Msg("missing header block").AsError();
326
- const { value } = await decode({ bytes: header.bytes, hasher, codec });
327
- const fpvalue = value;
287
+ const dec = await decode({ bytes: header.bytes, hasher, codec: dagCodec });
288
+ const fpvalue = dec.value;
328
289
  if (fpvalue && !fpvalue.fp) {
329
290
  throw logger.Error().Msg("missing fp").AsError();
330
291
  }
331
292
  return fpvalue.fp;
332
293
  }
333
294
 
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
295
  // 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 }) {
296
+ import { MemoryBlockstore } from "@web3-storage/pail/block";
297
+ import { toCryptoRuntime } from "@adviser/cement";
298
+ var CarTransaction = class extends MemoryBlockstore {
299
+ constructor(parent, opts = { add: true, noLoader: false }) {
593
300
  super();
594
301
  if (opts.add) {
595
302
  parent.transactions.add(this);
@@ -603,8 +310,8 @@ var CarTransaction = class extends MemoryBlockstore3 {
603
310
  return super.get(cid);
604
311
  }
605
312
  };
606
- function defaultedBlockstoreRuntime(opts, component, ctx) {
607
- const logger = ensureLogger(opts, component, ctx);
313
+ function defaultedBlockstoreRuntime(sthis, opts, component, ctx) {
314
+ const logger = ensureLogger(sthis, component, ctx);
608
315
  const store = opts.store || {};
609
316
  return {
610
317
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -621,22 +328,24 @@ function defaultedBlockstoreRuntime(opts, component, ctx) {
621
328
  threshold: 1e3 * 1e3,
622
329
  ...opts,
623
330
  logger,
624
- crypto: toCryptoOpts(opts.crypto),
331
+ keyBag: opts.keyBag || {},
332
+ crypto: toCryptoRuntime(opts.crypto),
625
333
  store,
626
- storeRuntime: toStoreRuntime(store, logger)
334
+ storeRuntime: toStoreRuntime(store, sthis)
627
335
  };
628
336
  }
629
- var blockstoreFactory = function(opts) {
337
+ function blockstoreFactory(sthis, opts) {
630
338
  if (opts.name) {
631
- return new EncryptedBlockstore(opts);
339
+ return new EncryptedBlockstore(sthis, opts);
632
340
  } else {
633
341
  return new BaseBlockstore(opts);
634
342
  }
635
- };
343
+ }
636
344
  var BaseBlockstore = class {
637
345
  constructor(ebOpts = {}) {
638
346
  this.transactions = /* @__PURE__ */ new Set();
639
- this.ebOpts = defaultedBlockstoreRuntime(ebOpts, "BaseBlockstore");
347
+ this.sthis = ensureSuperThis(ebOpts);
348
+ this.ebOpts = defaultedBlockstoreRuntime(this.sthis, ebOpts, "BaseBlockstore");
640
349
  this.logger = this.ebOpts.logger;
641
350
  }
642
351
  // ready: Promise<void>;
@@ -659,8 +368,8 @@ var BaseBlockstore = class {
659
368
  throw this.logger.Error().Msg("use a transaction to put").AsError();
660
369
  }
661
370
  // TransactionMeta
662
- async transaction(fn, _opts = {}) {
663
- const t = new CarTransaction(this);
371
+ async transaction(fn, _opts) {
372
+ const t = new CarTransaction(this, _opts);
664
373
  const done = await fn(t);
665
374
  this.lastTxMeta = done;
666
375
  return { t, meta: done };
@@ -677,16 +386,16 @@ var BaseBlockstore = class {
677
386
  }
678
387
  };
679
388
  var EncryptedBlockstore = class extends BaseBlockstore {
680
- constructor(ebOpts) {
389
+ constructor(sthis, ebOpts) {
681
390
  super(ebOpts);
682
391
  this.compacting = false;
683
- this.logger = ensureLogger(ebOpts, "EncryptedBlockstore");
392
+ this.logger = ensureLogger(this.sthis, "EncryptedBlockstore");
684
393
  const { name } = ebOpts;
685
394
  if (!name) {
686
395
  throw this.logger.Error().Msg("name required").AsError();
687
396
  }
688
397
  this.name = name;
689
- this.loader = new Loader(this.name, ebOpts);
398
+ this.loader = new Loader(this.name, ebOpts, sthis);
690
399
  }
691
400
  ready() {
692
401
  return this.loader.ready();
@@ -717,10 +426,13 @@ var EncryptedBlockstore = class extends BaseBlockstore {
717
426
  }
718
427
  throw this.logger.Error().Msg("failed to commit car files").AsError();
719
428
  }
720
- async getFile(car, cid, isPublic = false) {
429
+ async getFile(car, cid) {
721
430
  await this.ready();
722
431
  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);
432
+ const reader = await this.loader.loadFileCar(
433
+ car
434
+ /*, isPublic */
435
+ );
724
436
  const block = await reader.get(cid);
725
437
  if (!block) throw this.logger.Error().Str("cid", cid.toString()).Msg(`Missing block`).AsError();
726
438
  return block.bytes;
@@ -776,10 +488,20 @@ var CompactionFetcher = class {
776
488
  };
777
489
 
778
490
  // src/blockstore/commit-queue.ts
491
+ import { Future } from "@adviser/cement";
779
492
  var CommitQueue = class {
780
493
  constructor() {
781
494
  this.queue = [];
782
495
  this.processing = false;
496
+ this._waitIdleItems = /* @__PURE__ */ new Set();
497
+ }
498
+ waitIdle() {
499
+ if (this.queue.length === 0 && !this.processing) {
500
+ return Promise.resolve();
501
+ }
502
+ const fn = new Future();
503
+ this._waitIdleItems.add(fn);
504
+ return fn.asPromise();
783
505
  }
784
506
  async enqueue(fn) {
785
507
  return new Promise((resolve, reject) => {
@@ -804,20 +526,318 @@ var CommitQueue = class {
804
526
  this.processing = true;
805
527
  const queueFn = this.queue.shift();
806
528
  if (queueFn) {
807
- queueFn();
529
+ queueFn().finally(() => {
530
+ });
808
531
  }
809
532
  }
533
+ if (this.queue.length === 0 && !this.processing) {
534
+ const toResolve = Array.from(this._waitIdleItems);
535
+ this._waitIdleItems.clear();
536
+ toResolve.map((fn) => fn.resolve());
537
+ }
810
538
  }
811
539
  };
812
540
 
813
- // src/blockstore/loader.ts
814
- import * as CBW2 from "@ipld/car/buffer-writer";
815
- function carLogIncludesGroup2(list, cids) {
816
- return list.some((arr) => {
817
- return arr.toString() === cids.toString();
818
- });
819
- }
820
- function uniqueCids(list, remove = /* @__PURE__ */ new Set()) {
541
+ // src/runtime/key-bag.ts
542
+ var key_bag_exports = {};
543
+ __export(key_bag_exports, {
544
+ KeyBag: () => KeyBag,
545
+ getKeyBag: () => getKeyBag,
546
+ registerKeyBagProviderFactory: () => registerKeyBagProviderFactory
547
+ });
548
+ import {
549
+ KeyedResolvOnce,
550
+ ResolveSeq,
551
+ Result as Result2,
552
+ runtimeFn,
553
+ toCryptoRuntime as toCryptoRuntime2,
554
+ URI
555
+ } from "@adviser/cement";
556
+ import { base58btc } from "multiformats/bases/base58";
557
+ var KeyBag = class {
558
+ constructor(rt) {
559
+ this.rt = rt;
560
+ this._seq = new ResolveSeq();
561
+ this.logger = ensureLogger(rt.sthis, "KeyBag", {
562
+ id: rt.id()
563
+ });
564
+ this.logger.Debug().Msg("KeyBag created");
565
+ }
566
+ async subtleKey(key) {
567
+ return await this.rt.crypto.importKey(
568
+ "raw",
569
+ // raw or jwk
570
+ base58btc.decode(key),
571
+ // hexStringToUint8Array(key), // raw data
572
+ "AES-GCM",
573
+ false,
574
+ // extractable
575
+ ["encrypt", "decrypt"]
576
+ );
577
+ }
578
+ async ensureKeyFromUrl(url, keyFactory) {
579
+ const storeKey = url.getParam("storekey");
580
+ if (storeKey === "insecure") {
581
+ return Result2.Ok(url);
582
+ }
583
+ if (!storeKey) {
584
+ const keyName = `@${keyFactory()}@`;
585
+ const ret = await this.getNamedKey(keyName);
586
+ if (ret.isErr()) {
587
+ return ret;
588
+ }
589
+ const urb = url.build().setParam("storekey", keyName);
590
+ return Result2.Ok(urb.URI());
591
+ }
592
+ if (storeKey.startsWith("@") && storeKey.endsWith("@")) {
593
+ const ret = await this.getNamedKey(storeKey);
594
+ if (ret.isErr()) {
595
+ return ret;
596
+ }
597
+ }
598
+ return Result2.Ok(url);
599
+ }
600
+ async toKeyWithFingerPrint(keyStr) {
601
+ const material = base58btc.decode(keyStr);
602
+ const key = await this.subtleKey(keyStr);
603
+ const fpr = await this.rt.crypto.digestSHA256(material);
604
+ return Result2.Ok({
605
+ key,
606
+ fingerPrint: base58btc.encode(new Uint8Array(fpr))
607
+ });
608
+ }
609
+ async setNamedKey(name, key) {
610
+ return this._seq.add(() => this._setNamedKey(name, key));
611
+ }
612
+ // avoid deadlock
613
+ async _setNamedKey(name, key) {
614
+ const item = {
615
+ name,
616
+ key
617
+ };
618
+ const bag = await this.rt.getBag();
619
+ this.logger.Debug().Str("name", name).Msg("setNamedKey");
620
+ await bag.set(name, item);
621
+ return await this.toKeyWithFingerPrint(item.key);
622
+ }
623
+ async getNamedKey(name, failIfNotFound = false) {
624
+ const id = this.rt.sthis.nextId(4).str;
625
+ return this._seq.add(async () => {
626
+ const bag = await this.rt.getBag();
627
+ const named = await bag.get(name);
628
+ if (named) {
629
+ const fpr = await this.toKeyWithFingerPrint(named.key);
630
+ this.logger.Debug().Str("id", id).Str("name", name).Result("fpr", fpr).Msg("fingerPrint getNamedKey");
631
+ return fpr;
632
+ }
633
+ if (failIfNotFound) {
634
+ this.logger.Debug().Str("id", id).Str("name", name).Msg("failIfNotFound getNamedKey");
635
+ return Result2.Err(new Error(`Key not found: ${name}`));
636
+ }
637
+ const ret = await this._setNamedKey(name, base58btc.encode(this.rt.crypto.randomBytes(this.rt.keyLength)));
638
+ this.logger.Debug().Str("id", id).Str("name", name).Result("fpr", ret).Msg("createKey getNamedKey-post");
639
+ return ret;
640
+ });
641
+ }
642
+ };
643
+ var keyBagProviderFactories = new Map(
644
+ [
645
+ {
646
+ protocol: "file:",
647
+ factory: async (url, sthis) => {
648
+ const { KeyBagProviderFile } = await import("./key-bag-file-NMEBFSPM.js");
649
+ return new KeyBagProviderFile(url, sthis);
650
+ }
651
+ },
652
+ {
653
+ protocol: "indexdb:",
654
+ factory: async (url, sthis) => {
655
+ const { KeyBagProviderIndexDB } = await import("./key-bag-indexdb-X5V6GNBZ.js");
656
+ return new KeyBagProviderIndexDB(url, sthis);
657
+ }
658
+ }
659
+ ].map((i) => [i.protocol, i])
660
+ );
661
+ function registerKeyBagProviderFactory(item) {
662
+ const protocol = item.protocol.endsWith(":") ? item.protocol : item.protocol + ":";
663
+ keyBagProviderFactories.set(protocol, {
664
+ ...item,
665
+ protocol
666
+ });
667
+ }
668
+ function defaultKeyBagOpts(sthis, kbo) {
669
+ if (kbo.keyRuntime) {
670
+ return kbo.keyRuntime;
671
+ }
672
+ const logger = ensureLogger(sthis, "KeyBag");
673
+ let url;
674
+ if (kbo.url) {
675
+ url = URI.from(kbo.url);
676
+ logger.Debug().Url(url).Msg("from opts");
677
+ } else {
678
+ let bagFnameOrUrl = sthis.env.get("FP_KEYBAG_URL");
679
+ if (runtimeFn().isBrowser) {
680
+ url = URI.from(bagFnameOrUrl || "indexdb://fp-keybag");
681
+ } else {
682
+ if (!bagFnameOrUrl) {
683
+ const home = sthis.env.get("HOME");
684
+ bagFnameOrUrl = `${home}/.fireproof/keybag`;
685
+ url = URI.from(`file://${bagFnameOrUrl}`);
686
+ } else {
687
+ url = URI.from(bagFnameOrUrl);
688
+ }
689
+ }
690
+ logger.Debug().Url(url).Msg("from env");
691
+ }
692
+ let keyProviderFactory;
693
+ switch (url.protocol) {
694
+ case "file:":
695
+ keyProviderFactory = async () => {
696
+ const { KeyBagProviderFile } = await import("./key-bag-file-NMEBFSPM.js");
697
+ return new KeyBagProviderFile(url, sthis);
698
+ };
699
+ break;
700
+ case "indexdb:":
701
+ keyProviderFactory = async () => {
702
+ const { KeyBagProviderIndexDB } = await import("./key-bag-indexdb-X5V6GNBZ.js");
703
+ return new KeyBagProviderIndexDB(url, sthis);
704
+ };
705
+ break;
706
+ default:
707
+ throw logger.Error().Url(url).Msg("unsupported protocol").AsError();
708
+ }
709
+ if (url.hasParam("masterkey")) {
710
+ throw logger.Error().Url(url).Msg("masterkey is not supported").AsError();
711
+ }
712
+ return {
713
+ url,
714
+ crypto: kbo.crypto || toCryptoRuntime2({}),
715
+ sthis,
716
+ logger,
717
+ keyLength: kbo.keyLength || 16,
718
+ getBag: keyProviderFactory,
719
+ id: () => {
720
+ return url.toString();
721
+ }
722
+ };
723
+ }
724
+ var _keyBags = new KeyedResolvOnce();
725
+ async function getKeyBag(sthis, kbo = {}) {
726
+ await sthis.start();
727
+ const rt = defaultKeyBagOpts(sthis, kbo);
728
+ return _keyBags.get(rt.id()).once(async () => new KeyBag(rt));
729
+ }
730
+
731
+ // src/blockstore/commitor.ts
732
+ import * as CBW from "@ipld/car/buffer-writer";
733
+ import { sha256 as hasher2 } from "multiformats/hashes/sha2";
734
+ import * as dagCodec2 from "@ipld/dag-cbor";
735
+ async function encodeCarFile(roots, t, codec3) {
736
+ let size = 0;
737
+ const headerSize = CBW.headerLength({ roots });
738
+ size += headerSize;
739
+ for (const { cid, bytes } of t.entries()) {
740
+ size += CBW.blockLength({ cid, bytes });
741
+ }
742
+ const buffer = new Uint8Array(size);
743
+ const writer = CBW.createWriter(buffer, { headerSize });
744
+ for (const r of roots) {
745
+ writer.addRoot(r);
746
+ }
747
+ for (const { cid, bytes } of t.entries()) {
748
+ writer.write({ cid, bytes });
749
+ }
750
+ writer.close();
751
+ return await encode({ value: writer.bytes, hasher: hasher2, codec: codec3 });
752
+ }
753
+ async function createCarFile(encoder, cid, t) {
754
+ return encodeCarFile([cid], t, encoder);
755
+ }
756
+ async function commitFiles(fileStore, walStore, t, done) {
757
+ const { files: roots } = makeFileCarHeader(done);
758
+ const cids = [];
759
+ const codec3 = (await fileStore.keyedCrypto()).codec();
760
+ const cars = await prepareCarFilesFiles(codec3, roots, t);
761
+ for (const car of cars) {
762
+ const { cid, bytes } = car;
763
+ await fileStore.save({ cid, bytes });
764
+ await walStore.enqueueFile(
765
+ cid
766
+ /*, !!opts.public*/
767
+ );
768
+ cids.push(cid);
769
+ }
770
+ return cids;
771
+ }
772
+ function makeFileCarHeader(result) {
773
+ const files = [];
774
+ for (const [, meta] of Object.entries(result.files || {})) {
775
+ if (meta && typeof meta === "object" && "cid" in meta && meta !== null) {
776
+ files.push(meta.cid);
777
+ }
778
+ }
779
+ return { ...result, files };
780
+ }
781
+ async function prepareCarFilesFiles(encoder, roots, t) {
782
+ return [await encodeCarFile(roots, t, encoder)];
783
+ }
784
+ function makeCarHeader(meta, cars, compact = false) {
785
+ const coreHeader = compact ? { cars: [], compact: cars } : { cars, compact: [] };
786
+ return { ...coreHeader, meta };
787
+ }
788
+ async function encodeCarHeader(fp) {
789
+ return await encode({
790
+ value: { fp },
791
+ hasher: hasher2,
792
+ codec: dagCodec2
793
+ });
794
+ }
795
+ async function commit(params, t, done, opts = { noLoader: false, compact: false }) {
796
+ const fp = makeCarHeader(done, params.carLog, !!opts.compact);
797
+ const rootBlock = await encodeCarHeader(fp);
798
+ const cars = await prepareCarFiles(params.encoder, params.threshold, rootBlock, t);
799
+ const cids = [];
800
+ for (const car of cars) {
801
+ const { cid, bytes } = car;
802
+ await params.carStore.save({ cid, bytes });
803
+ cids.push(cid);
804
+ }
805
+ const newDbMeta = { cars: cids };
806
+ await params.WALStore.enqueue(newDbMeta, opts);
807
+ await params.metaStore.save(newDbMeta);
808
+ return { cgrp: cids, header: fp };
809
+ }
810
+ async function prepareCarFiles(encoder, threshold, rootBlock, t) {
811
+ const carFiles = [];
812
+ threshold = threshold || 1e3 * 1e3;
813
+ let clonedt = new CarTransaction(t.parent, { add: false, noLoader: false });
814
+ clonedt.putSync(rootBlock.cid, rootBlock.bytes);
815
+ let newsize = CBW.blockLength(toCIDBlock(rootBlock));
816
+ let cidRootBlock = rootBlock;
817
+ for (const { cid, bytes } of t.entries()) {
818
+ newsize += CBW.blockLength(toCIDBlock({ cid, bytes }));
819
+ if (newsize >= threshold) {
820
+ carFiles.push(await createCarFile(encoder, cidRootBlock.cid, clonedt));
821
+ clonedt = new CarTransaction(t.parent, { add: false, noLoader: false });
822
+ clonedt.putSync(cid, bytes);
823
+ cidRootBlock = { cid, bytes };
824
+ newsize = CBW.blockLength(toCIDBlock({ cid, bytes }));
825
+ } else {
826
+ clonedt.putSync(cid, bytes);
827
+ }
828
+ }
829
+ carFiles.push(await createCarFile(encoder, cidRootBlock.cid, clonedt));
830
+ return carFiles;
831
+ }
832
+
833
+ // src/blockstore/loader.ts
834
+ import { sha256 as hasher3 } from "multiformats/hashes/sha2";
835
+ function carLogIncludesGroup(list, cids) {
836
+ return list.some((arr) => {
837
+ return arr.toString() === cids.toString();
838
+ });
839
+ }
840
+ function uniqueCids(list, remove = /* @__PURE__ */ new Set()) {
821
841
  const byString = /* @__PURE__ */ new Map();
822
842
  for (const cid of list) {
823
843
  if (remove.has(cid.toString())) continue;
@@ -825,17 +845,8 @@ function uniqueCids(list, remove = /* @__PURE__ */ new Set()) {
825
845
  }
826
846
  return [...byString.values()];
827
847
  }
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
848
  var Loader = class {
838
- constructor(name, ebOpts) {
849
+ constructor(name, ebOpts, sthis) {
839
850
  this.commitQueue = new CommitQueue();
840
851
  this.isCompacting = false;
841
852
  this.carReaders = /* @__PURE__ */ new Map();
@@ -847,7 +858,9 @@ var Loader = class {
847
858
  this.writeLimit = pLimit(1);
848
859
  this.onceReady = new ResolveOnce();
849
860
  this.name = name;
861
+ this.sthis = sthis;
850
862
  this.ebOpts = defaultedBlockstoreRuntime(
863
+ sthis,
851
864
  {
852
865
  ...ebOpts,
853
866
  name
@@ -857,14 +870,17 @@ var Loader = class {
857
870
  this.logger = this.ebOpts.logger;
858
871
  }
859
872
  // readonly id = uuidv4();
873
+ async keyBag() {
874
+ return getKeyBag(this.sthis, this.ebOpts.keyBag);
875
+ }
860
876
  async carStore() {
861
877
  return this.ebOpts.storeRuntime.makeDataStore(this);
862
878
  }
863
879
  async fileStore() {
864
880
  return this.ebOpts.storeRuntime.makeDataStore(this);
865
881
  }
866
- async remoteWAL() {
867
- return this.ebOpts.storeRuntime.makeRemoteWAL(this);
882
+ async WALStore() {
883
+ return this.ebOpts.storeRuntime.makeWALStore(this);
868
884
  }
869
885
  async metaStore() {
870
886
  return this.ebOpts.storeRuntime.makeMetaStore(this);
@@ -878,11 +894,11 @@ var Loader = class {
878
894
  });
879
895
  }
880
896
  async close() {
881
- const toClose = await Promise.all([this.carStore(), this.metaStore(), this.fileStore(), this.remoteWAL()]);
897
+ const toClose = await Promise.all([this.carStore(), this.metaStore(), this.fileStore(), this.WALStore()]);
882
898
  await Promise.all(toClose.map((store) => store.close()));
883
899
  }
884
900
  async destroy() {
885
- const toDestroy = await Promise.all([this.carStore(), this.metaStore(), this.fileStore(), this.remoteWAL()]);
901
+ const toDestroy = await Promise.all([this.carStore(), this.metaStore(), this.fileStore(), this.WALStore()]);
886
902
  await Promise.all(toDestroy.map((store) => store.destroy()));
887
903
  }
888
904
  // async snapToCar(carCid: AnyLink | string) {
@@ -896,6 +912,7 @@ var Loader = class {
896
912
  // await this._applyCarHeader(carHeader, true)
897
913
  // }
898
914
  async handleDbMetasFromStore(metas) {
915
+ this.logger.Debug().Any("metas", metas).Msg("handleDbMetasFromStore");
899
916
  for (const meta of metas) {
900
917
  await this.writeLimit(async () => {
901
918
  await this.mergeDbMetaIntoClock(meta);
@@ -908,10 +925,7 @@ var Loader = class {
908
925
  }
909
926
  if (this.seenMeta.has(meta.cars.toString())) return;
910
927
  this.seenMeta.add(meta.cars.toString());
911
- if (meta.key) {
912
- await this.setKey(meta.key);
913
- }
914
- if (carLogIncludesGroup2(this.carLog, meta.cars)) {
928
+ if (carLogIncludesGroup(this.carLog, meta.cars)) {
915
929
  return;
916
930
  }
917
931
  const carHeader = await this.loadCarHeaderFromMeta(meta);
@@ -920,45 +934,59 @@ var Loader = class {
920
934
  this.carLog = [...uniqueCids([meta.cars, ...this.carLog, ...carHeader.cars], this.seenCompacted)];
921
935
  await this.ebOpts.applyMeta?.(carHeader.meta);
922
936
  }
923
- async ingestKeyFromMeta(meta) {
924
- const { key } = meta;
925
- if (key) {
926
- await this.setKey(key);
927
- }
928
- }
937
+ // protected async ingestKeyFromMeta(meta: DbMeta): Promise<void> {
938
+ // const { key } = meta;
939
+ // if (key) {
940
+ // await this.setKey(key);
941
+ // }
942
+ // }
929
943
  async loadCarHeaderFromMeta({ cars: cids }) {
930
944
  const reader = await this.loadCar(cids[0]);
931
945
  return await parseCarFile(reader, this.logger);
932
946
  }
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 }) {
947
+ // async _getKey(): Promise<string | undefined> {
948
+ // if (this.key) return this.key;
949
+ // // generate a random key
950
+ // if (!this.ebOpts.public) {
951
+ // await this.setKey(toHexString(this.ebOpts.crypto.randomBytes(32)));
952
+ // }
953
+ // return this.key || undefined;
954
+ // }
955
+ async commitFiles(t, done) {
945
956
  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;
957
+ const fstore = await this.fileStore();
958
+ const wstore = await this.WALStore();
959
+ return this.commitQueue.enqueue(() => commitFiles(fstore, wstore, t, done));
956
960
  }
957
- async loadFileCar(cid, isPublic = false) {
958
- return await this.storesLoadCar(cid, await this.fileStore(), this.remoteFileStore, isPublic);
961
+ async loadFileCar(cid) {
962
+ return await this.storesLoadCar(cid, await this.fileStore(), this.remoteFileStore);
959
963
  }
960
964
  async commit(t, done, opts = { noLoader: false, compact: false }) {
961
- return this.commitQueue.enqueue(() => this._commitInternal(t, done, opts));
965
+ await this.ready();
966
+ const fstore = await this.fileStore();
967
+ const params = {
968
+ encoder: (await fstore.keyedCrypto()).codec(),
969
+ carLog: this.carLog,
970
+ carStore: fstore,
971
+ WALStore: await this.WALStore(),
972
+ metaStore: await this.metaStore()
973
+ };
974
+ return this.commitQueue.enqueue(async () => {
975
+ await this.cacheTransaction(t);
976
+ const ret = await commit(params, t, done, opts);
977
+ await this.updateCarLog(ret.cgrp, ret.header, !!opts.compact);
978
+ return ret.cgrp;
979
+ });
980
+ }
981
+ async updateCarLog(cids, fp, compact) {
982
+ if (compact) {
983
+ const previousCompactCid = fp.compact[fp.compact.length - 1];
984
+ fp.compact.map((c) => c.toString()).forEach(this.seenCompacted.add, this.seenCompacted);
985
+ this.carLog = [...uniqueCids([...this.carLog, ...fp.cars, cids], this.seenCompacted)];
986
+ await this.removeCidsForCompact(previousCompactCid[0]).catch((e) => e);
987
+ } else {
988
+ this.carLog.unshift(cids);
989
+ }
962
990
  }
963
991
  async cacheTransaction(t) {
964
992
  for await (const block of t.entries()) {
@@ -978,79 +1006,6 @@ var Loader = class {
978
1006
  }
979
1007
  }
980
1008
  }
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
1009
  async removeCidsForCompact(cid) {
1055
1010
  const carHeader = await this.loadCarHeaderFromMeta({
1056
1011
  cars: [cid]
@@ -1069,9 +1024,9 @@ var Loader = class {
1069
1024
  // await this.remoteWAL!.enqueue(dbMeta, { public: false })
1070
1025
  // }
1071
1026
  // }
1072
- async *entries(cache3 = true) {
1027
+ async *entries(cache2 = true) {
1073
1028
  await this.ready();
1074
- if (cache3) {
1029
+ if (cache2) {
1075
1030
  for (const [, block] of this.getBlockCache) {
1076
1031
  yield block;
1077
1032
  }
@@ -1153,10 +1108,6 @@ var Loader = class {
1153
1108
  }
1154
1109
  return got;
1155
1110
  }
1156
- makeCarHeader(meta, cars, compact = false) {
1157
- const coreHeader = compact ? { cars: [], compact: cars } : { cars, compact: [] };
1158
- return { ...coreHeader, meta };
1159
- }
1160
1111
  async loadCar(cid) {
1161
1112
  if (!this.carStore) {
1162
1113
  throw this.logger.Error().Msg("car store not initialized").AsError();
@@ -1164,72 +1115,52 @@ var Loader = class {
1164
1115
  const loaded = await this.storesLoadCar(cid, await this.carStore(), this.remoteCarStore);
1165
1116
  return loaded;
1166
1117
  }
1167
- //What if instead it returns an Array of CarHeader
1168
- async storesLoadCar(cid, local, remote, publicFiles) {
1118
+ async makeDecoderAndCarReader(cid, local, remote) {
1169
1119
  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
- );
1120
+ let loadedCar = void 0;
1121
+ let activeStore = local;
1122
+ try {
1123
+ this.logger.Debug().Str("cid", cidsString).Msg("loading car");
1124
+ loadedCar = await local.load(cid);
1125
+ this.logger.Debug().Bool("loadedCar", loadedCar).Msg("loaded");
1126
+ } catch (e) {
1127
+ if (remote) {
1128
+ const remoteCar = await remote.load(cid);
1129
+ if (remoteCar) {
1130
+ this.logger.Debug().Ref("cid", remoteCar.cid).Msg("saving remote car locally");
1131
+ await local.save(remoteCar);
1132
+ loadedCar = remoteCar;
1133
+ activeStore = remote;
1134
+ }
1135
+ } else {
1136
+ this.logger.Error().Str("cid", cidsString).Err(e).Msg("loading car");
1137
+ }
1209
1138
  }
1210
- return this.carReaders.get(cidsString);
1211
- }
1212
- async ensureDecryptedReader(reader) {
1213
- const theKey = await this._getKey();
1214
- if (this.ebOpts.public || !(theKey && this.ebOpts.crypto)) {
1215
- return reader;
1139
+ if (!loadedCar) {
1140
+ throw this.logger.Error().Url(local.url()).Str("cid", cidsString).Msg("missing car files").AsError();
1216
1141
  }
1217
- const { blocks, root: root3 } = await decodeEncryptedCar(this.logger, this.ebOpts.crypto, theKey, reader);
1218
- return {
1219
- getRoots: () => [root3],
1220
- get: blocks.get.bind(blocks),
1221
- blocks: blocks.entries.bind(blocks)
1222
- };
1142
+ const bytes = await decode({ bytes: loadedCar.bytes, hasher: hasher3, codec: (await activeStore.keyedCrypto()).codec() });
1143
+ const rawReader = await CarReader.fromBytes(bytes.value);
1144
+ const readerP = Promise.resolve(rawReader);
1145
+ const cachedReaderP = readerP.then(async (reader) => {
1146
+ await this.cacheCarReader(cidsString, reader).catch((e) => {
1147
+ this.logger.Error().Err(e).Str("cid", cidsString).Msg("error caching car reader");
1148
+ return;
1149
+ });
1150
+ return reader;
1151
+ });
1152
+ this.carReaders.set(cidsString, cachedReaderP);
1153
+ return readerP;
1223
1154
  }
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("");
1155
+ //What if instead it returns an Array of CarHeader
1156
+ async storesLoadCar(cid, local, remote) {
1157
+ const cidsString = cid.toString();
1158
+ let dacr = this.carReaders.get(cidsString);
1159
+ if (!dacr) {
1160
+ dacr = this.makeDecoderAndCarReader(cid, local, remote);
1161
+ this.carReaders.set(cidsString, dacr);
1162
+ }
1163
+ return dacr;
1233
1164
  }
1234
1165
  async getMoreReaders(cids) {
1235
1166
  const limit = pLimit(5);
@@ -1238,20 +1169,344 @@ var Loader = class {
1238
1169
  }
1239
1170
  };
1240
1171
 
1172
+ // src/runtime/keyed-crypto.ts
1173
+ var keyed_crypto_exports = {};
1174
+ __export(keyed_crypto_exports, {
1175
+ BlockIvKeyIdCodec: () => BlockIvKeyIdCodec,
1176
+ keyedCryptoFactory: () => keyedCryptoFactory
1177
+ });
1178
+ import { base58btc as base58btc2 } from "multiformats/bases/base58";
1179
+ import { sha256 as hasher4 } from "multiformats/hashes/sha2";
1180
+ import * as CBOR from "cborg";
1181
+ var generateIV = {
1182
+ random: {
1183
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1184
+ calc: async (ko, crypto, data) => {
1185
+ return crypto.randomBytes(ko.ivLength);
1186
+ },
1187
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1188
+ verify: async (ko, crypto, iv, data) => {
1189
+ return true;
1190
+ }
1191
+ },
1192
+ hash: {
1193
+ calc: async (ko, crypto, data) => {
1194
+ const hash = await hasher4.digest(data);
1195
+ const hashBytes = new Uint8Array(hash.bytes);
1196
+ const hashArray = new Uint8Array(ko.ivLength * 8);
1197
+ for (let i = 0; i < hashBytes.length; i++) {
1198
+ hashArray[i % ko.ivLength] ^= hashBytes[i];
1199
+ }
1200
+ return hashArray;
1201
+ },
1202
+ verify: async function(ko, crypto, iv, data) {
1203
+ return ko.url.getParam("ivverify") !== "disable" && UInt8ArrayEqual(iv, await this.calc(ko, crypto, data));
1204
+ }
1205
+ }
1206
+ };
1207
+ function getGenerateIVFn(url, opts) {
1208
+ const ivhash = opts.ivCalc || url.getParam("ivhash") || "hash";
1209
+ return generateIV[ivhash] || generateIV["hash"];
1210
+ }
1211
+ var BlockIvKeyIdCodec = class {
1212
+ constructor(ko, iv, opts) {
1213
+ this.code = 3147065;
1214
+ this.name = "Fireproof@encrypted-block:aes-gcm";
1215
+ this.ko = ko;
1216
+ this.iv = iv;
1217
+ this.opts = opts || {};
1218
+ }
1219
+ async encode(data) {
1220
+ const calcIv = this.iv || await getGenerateIVFn(this.ko.url, this.opts).calc(this.ko, this.ko.crypto, data);
1221
+ const { iv } = this.ko.algo(calcIv);
1222
+ const fprt = await this.ko.fingerPrint();
1223
+ const keyId = base58btc2.decode(fprt);
1224
+ this.ko.logger.Debug().Str("fp", fprt).Msg("encode");
1225
+ return CBOR.encode({
1226
+ iv,
1227
+ keyId,
1228
+ data: await this.ko._encrypt({ iv, bytes: data })
1229
+ });
1230
+ }
1231
+ async decode(abytes) {
1232
+ let bytes;
1233
+ if (abytes instanceof Uint8Array) {
1234
+ bytes = abytes;
1235
+ } else {
1236
+ bytes = new Uint8Array(abytes);
1237
+ }
1238
+ const { iv, keyId, data } = CBOR.decode(bytes);
1239
+ const fprt = await this.ko.fingerPrint();
1240
+ this.ko.logger.Debug().Str("fp", base58btc2.encode(keyId)).Msg("decode");
1241
+ if (base58btc2.encode(keyId) !== fprt) {
1242
+ throw this.ko.logger.Error().Str("fp", fprt).Str("keyId", base58btc2.encode(keyId)).Msg("keyId mismatch").AsError();
1243
+ }
1244
+ const result = await this.ko._decrypt({ iv, bytes: data });
1245
+ if (!this.opts?.noIVVerify && !await getGenerateIVFn(this.ko.url, this.opts).verify(this.ko, this.ko.crypto, iv, result)) {
1246
+ throw this.ko.logger.Error().Msg("iv missmatch").AsError();
1247
+ }
1248
+ return result;
1249
+ }
1250
+ };
1251
+ var keyedCrypto = class {
1252
+ constructor(url, key, cyopt, sthis) {
1253
+ this.ivLength = 12;
1254
+ this.isEncrypting = true;
1255
+ this.logger = ensureLogger(sthis, "keyedCrypto");
1256
+ this.crypto = cyopt;
1257
+ this.key = key;
1258
+ this.url = url;
1259
+ }
1260
+ fingerPrint() {
1261
+ return Promise.resolve(this.key.fingerPrint);
1262
+ }
1263
+ codec(iv, opts) {
1264
+ return new BlockIvKeyIdCodec(this, iv, opts);
1265
+ }
1266
+ algo(iv) {
1267
+ return {
1268
+ name: "AES-GCM",
1269
+ iv: iv || this.crypto.randomBytes(this.ivLength),
1270
+ tagLength: 128
1271
+ };
1272
+ }
1273
+ async _decrypt(data) {
1274
+ this.logger.Debug().Len(data.bytes).Str("fp", this.key.fingerPrint).Msg("decrypting");
1275
+ return new Uint8Array(await this.crypto.decrypt(this.algo(data.iv), this.key.key, data.bytes));
1276
+ }
1277
+ async _encrypt(data) {
1278
+ this.logger.Debug().Len(data.bytes).Str("fp", this.key.fingerPrint).Msg("encrypting");
1279
+ const a = this.algo(data.iv);
1280
+ return new Uint8Array(await this.crypto.encrypt(a, this.key.key, data.bytes));
1281
+ }
1282
+ };
1283
+ var nullCodec = class {
1284
+ constructor() {
1285
+ this.code = 0;
1286
+ this.name = "Fireproof@unencrypted-block";
1287
+ }
1288
+ encode(data) {
1289
+ return data;
1290
+ }
1291
+ decode(data) {
1292
+ return data;
1293
+ }
1294
+ };
1295
+ var noCrypto = class {
1296
+ constructor(url, cyrt, sthis) {
1297
+ this.ivLength = 0;
1298
+ this.code = 0;
1299
+ this.name = "Fireproof@unencrypted-block";
1300
+ this.isEncrypting = false;
1301
+ this._fingerPrint = "noCrypto:" + Math.random();
1302
+ this.logger = ensureLogger(sthis, "noCrypto");
1303
+ this.crypto = cyrt;
1304
+ this.url = url;
1305
+ }
1306
+ fingerPrint() {
1307
+ return Promise.resolve(this._fingerPrint);
1308
+ }
1309
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1310
+ codec(iv) {
1311
+ return new nullCodec();
1312
+ }
1313
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1314
+ algo(iv) {
1315
+ return {
1316
+ name: "noCrypto",
1317
+ iv: new Uint8Array(),
1318
+ tagLength: 0
1319
+ };
1320
+ }
1321
+ _decrypt() {
1322
+ throw this.logger.Error().Msg("noCrypto.decrypt not implemented").AsError();
1323
+ }
1324
+ _encrypt() {
1325
+ throw this.logger.Error().Msg("noCrypto.decrypt not implemented").AsError();
1326
+ }
1327
+ };
1328
+ async function keyedCryptoFactory(url, kb, sthis) {
1329
+ const storekey = url.getParam("storekey");
1330
+ if (storekey && storekey !== "insecure") {
1331
+ let rkey = await kb.getNamedKey(storekey, true);
1332
+ if (rkey.isErr()) {
1333
+ try {
1334
+ rkey = await kb.toKeyWithFingerPrint(storekey);
1335
+ } catch (e) {
1336
+ throw sthis.logger.Error().Err(e).Str("keybag", kb.rt.id()).Str("name", storekey).Msg("getNamedKey failed").AsError();
1337
+ }
1338
+ }
1339
+ return new keyedCrypto(url, rkey.Ok(), kb.rt.crypto, sthis);
1340
+ }
1341
+ return new noCrypto(url, kb.rt.crypto, sthis);
1342
+ }
1343
+
1344
+ // src/blockstore/fragment-gateway.ts
1345
+ import { base58btc as base58btc3 } from "multiformats/bases/base58";
1346
+ import { encode as encode3, decode as decode3 } from "cborg";
1347
+ function getFragSize(url) {
1348
+ const fragSize = url.getParam("fragSize");
1349
+ let ret = 0;
1350
+ if (fragSize) {
1351
+ ret = parseInt(fragSize);
1352
+ }
1353
+ if (isNaN(ret) || ret <= 0) {
1354
+ ret = 0;
1355
+ }
1356
+ return ret;
1357
+ }
1358
+ async function getFrags(url, innerGW, headerSize, logger) {
1359
+ const fragSize = getFragSize(url);
1360
+ if (!fragSize) {
1361
+ const res = await innerGW.get(url);
1362
+ if (res.isErr()) {
1363
+ return [res];
1364
+ }
1365
+ const data = res.unwrap();
1366
+ return [
1367
+ Result.Ok({
1368
+ fid: new Uint8Array(0),
1369
+ ofs: 0,
1370
+ len: data.length,
1371
+ data
1372
+ })
1373
+ ];
1374
+ }
1375
+ const firstRaw = await innerGW.get(url.build().setParam("ofs", "0").URI());
1376
+ if (firstRaw.isErr()) {
1377
+ return [firstRaw];
1378
+ }
1379
+ const firstFragment = decode3(firstRaw.unwrap());
1380
+ const blockSize = firstFragment.data.length;
1381
+ const ops = [Promise.resolve(Result.Ok(firstFragment))];
1382
+ const fidStr = base58btc3.encode(firstFragment.fid);
1383
+ const fragUrl = url.build().setParam("fid", fidStr).setParam("len", firstFragment.len.toString()).setParam("headerSize", headerSize.toString());
1384
+ for (let ofs = blockSize; ofs < firstFragment.len; ofs += blockSize) {
1385
+ ops.push(
1386
+ (async (furl, ofs2) => {
1387
+ const raw2 = await innerGW.get(furl);
1388
+ if (raw2.isErr()) {
1389
+ return raw2;
1390
+ }
1391
+ const fragment = decode3(raw2.unwrap());
1392
+ if (base58btc3.encode(fragment.fid) !== fidStr) {
1393
+ return Result.Err(logger.Error().Msg("Fragment fid mismatch").AsError());
1394
+ }
1395
+ if (fragment.ofs !== ofs2) {
1396
+ return Result.Err(logger.Error().Uint64("ofs", ofs2).Msg("Fragment ofs mismatch").AsError());
1397
+ }
1398
+ return Result.Ok(fragment);
1399
+ })(fragUrl.setParam("ofs", ofs.toString()).URI(), ofs)
1400
+ );
1401
+ }
1402
+ return Promise.all(ops);
1403
+ }
1404
+ var FragmentGateway = class {
1405
+ constructor(sthis, innerGW) {
1406
+ this.fidLength = 4;
1407
+ this.headerSize = 32;
1408
+ this.sthis = ensureSuperLog(sthis, "FragmentGateway");
1409
+ this.logger = this.sthis.logger;
1410
+ this.innerGW = innerGW;
1411
+ }
1412
+ slicer(url, body) {
1413
+ const fragSize = getFragSize(url);
1414
+ if (!fragSize) {
1415
+ return [this.innerGW.put(url, body)];
1416
+ }
1417
+ const blocksize = fragSize - this.headerSize;
1418
+ if (blocksize <= 0) {
1419
+ throw this.logger.Error().Uint64("fragSize", fragSize).Uint64("headerSize", this.headerSize).Msg("Fragment size is too small").AsError();
1420
+ }
1421
+ const ops = [];
1422
+ const fid = this.sthis.nextId(this.fidLength);
1423
+ const fragUrl = url.build().setParam("fid", fid.str).setParam("len", body.length.toString()).setParam("headerSize", this.headerSize.toString());
1424
+ for (let ofs = 0; ofs < body.length; ofs += blocksize) {
1425
+ const block = encode3({
1426
+ fid: fid.bin,
1427
+ ofs,
1428
+ len: body.length,
1429
+ data: body.slice(ofs, ofs + blocksize)
1430
+ });
1431
+ if (block.length > fragSize) {
1432
+ throw this.logger.Error().Uint64("block", block.length).Uint64("fragSize", fragSize).Msg("Block size to big").AsError();
1433
+ }
1434
+ ops.push(this.innerGW.put(fragUrl.setParam("ofs", ofs.toString()).URI(), block));
1435
+ }
1436
+ return ops;
1437
+ }
1438
+ buildUrl(baseUrl, key) {
1439
+ return this.innerGW.buildUrl(baseUrl, key);
1440
+ }
1441
+ async destroy(iurl) {
1442
+ return this.innerGW.destroy(iurl);
1443
+ }
1444
+ async start(url) {
1445
+ this.headerSize = encode3({
1446
+ fid: this.sthis.nextId(this.fidLength).bin,
1447
+ ofs: 1024 * 1024,
1448
+ // 32bit
1449
+ len: 16 * 1024 * 1024,
1450
+ // 32bit
1451
+ data: new Uint8Array(1024)
1452
+ }).length - 1024;
1453
+ return this.innerGW.start(url);
1454
+ }
1455
+ async close(url) {
1456
+ return this.innerGW.close(url);
1457
+ }
1458
+ async put(url, body) {
1459
+ await Promise.all(this.slicer(url, body));
1460
+ return Result.Ok(void 0);
1461
+ }
1462
+ async get(url) {
1463
+ const rfrags = await getFrags(url, this.innerGW, this.headerSize, this.logger);
1464
+ let buffer = void 0;
1465
+ for (const rfrag of rfrags) {
1466
+ if (rfrag.isErr()) {
1467
+ return Result.Err(rfrag.Err());
1468
+ }
1469
+ const frag = rfrag.Ok();
1470
+ buffer = buffer || new Uint8Array(frag.len);
1471
+ buffer.set(frag.data, frag.ofs);
1472
+ }
1473
+ return Result.Ok(buffer || new Uint8Array(0));
1474
+ }
1475
+ async delete(url) {
1476
+ const rfrags = await getFrags(url, this.innerGW, this.headerSize, this.logger);
1477
+ for (const rfrag of rfrags) {
1478
+ if (rfrag.isErr()) {
1479
+ return Result.Err(rfrag.Err());
1480
+ }
1481
+ const frag = rfrag.Ok();
1482
+ const fidStr = base58btc3.encode(frag.fid);
1483
+ const fragUrl = url.build().setParam("fid", fidStr).setParam("len", frag.len.toString()).setParam("headerSize", this.headerSize.toString()).URI();
1484
+ await this.innerGW.delete(fragUrl);
1485
+ }
1486
+ return Result.Ok(void 0);
1487
+ }
1488
+ };
1489
+
1241
1490
  // src/blockstore/store.ts
1242
1491
  function guardVersion(url) {
1243
- if (!url.searchParams.has("version")) {
1244
- return Result2.Err(`missing version: ${url.toString()}`);
1492
+ if (!url.hasParam("version")) {
1493
+ return Result3.Err(`missing version: ${url.toString()}`);
1245
1494
  }
1246
- return Result2.Ok(url);
1495
+ return Result3.Ok(url);
1247
1496
  }
1248
- var VersionedStore = class {
1249
- constructor(name, url, logger) {
1497
+ var BaseStoreImpl = class {
1498
+ constructor(name, url, opts, sthis, logger) {
1250
1499
  this._onStarted = [];
1251
1500
  this._onClosed = [];
1252
1501
  this.name = name;
1253
- this.url = url;
1254
- this.logger = logger;
1502
+ this._url = url;
1503
+ this.keybag = opts.keybag;
1504
+ this.sthis = sthis;
1505
+ this.logger = logger.With().Ref("url", () => this._url.toString()).Str("name", name).Logger();
1506
+ this.gateway = new FragmentGateway(this.sthis, opts.gateway);
1507
+ }
1508
+ url() {
1509
+ return this._url;
1255
1510
  }
1256
1511
  onStarted(fn) {
1257
1512
  this._onStarted.push(fn);
@@ -1259,106 +1514,164 @@ var VersionedStore = class {
1259
1514
  onClosed(fn) {
1260
1515
  this._onClosed.push(fn);
1261
1516
  }
1517
+ async keyedCrypto() {
1518
+ return keyedCryptoFactory(this._url, await this.keybag(), this.sthis);
1519
+ }
1520
+ async start() {
1521
+ this.logger.Debug().Str("storeType", this.storeType).Msg("starting-gateway-pre");
1522
+ this._url = this._url.build().setParam("store", this.storeType).URI();
1523
+ const res = await this.gateway.start(this._url);
1524
+ if (res.isErr()) {
1525
+ this.logger.Error().Result("gw-start", res).Msg("started-gateway");
1526
+ return res;
1527
+ }
1528
+ this._url = res.Ok();
1529
+ const kb = await this.keybag();
1530
+ const skRes = await kb.ensureKeyFromUrl(this._url, () => {
1531
+ const idx = this._url.getParam("index");
1532
+ const storeKeyName = [this.name];
1533
+ if (idx) {
1534
+ storeKeyName.push(idx);
1535
+ }
1536
+ storeKeyName.push(this.storeType);
1537
+ return storeKeyName.join(":");
1538
+ });
1539
+ if (skRes.isErr()) {
1540
+ return skRes;
1541
+ }
1542
+ this._url = skRes.Ok();
1543
+ const version = guardVersion(this._url);
1544
+ if (version.isErr()) {
1545
+ this.logger.Error().Result("version", version).Msg("guardVersion");
1546
+ await this.close();
1547
+ return version;
1548
+ }
1549
+ if (this.ready) {
1550
+ const fn = this.ready.bind(this);
1551
+ const ready = await exception2Result(fn);
1552
+ if (ready.isErr()) {
1553
+ await this.close();
1554
+ return ready;
1555
+ }
1556
+ }
1557
+ this._onStarted.forEach((fn) => fn());
1558
+ this.logger.Debug().Msg("started");
1559
+ return version;
1560
+ }
1262
1561
  };
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 }) {
1562
+ var MetaStoreImpl = class extends BaseStoreImpl {
1563
+ constructor(sthis, name, url, opts) {
1564
+ super(
1565
+ name,
1566
+ url,
1567
+ {
1568
+ ...opts
1569
+ },
1570
+ sthis,
1571
+ ensureLogger(sthis, "MetaStoreImpl")
1572
+ );
1573
+ this.storeType = "meta";
1574
+ this.subscribers = /* @__PURE__ */ new Map();
1575
+ }
1576
+ onLoad(branch, loadHandler) {
1577
+ const subscribers = this.subscribers.get(branch) || [];
1578
+ subscribers.push(loadHandler);
1579
+ this.subscribers.set(branch, subscribers);
1580
+ return () => {
1581
+ const subscribers2 = this.subscribers.get(branch) || [];
1582
+ const idx = subscribers2.indexOf(loadHandler);
1583
+ if (idx > -1) subscribers2.splice(idx, 1);
1584
+ };
1585
+ }
1586
+ makeHeader({ cars }) {
1272
1587
  const toEncode = { cars };
1273
- if (key) toEncode.key = key;
1274
1588
  return format(toEncode);
1275
1589
  }
1276
1590
  parseHeader(headerData) {
1277
1591
  const got = parse(headerData);
1278
1592
  return got;
1279
1593
  }
1280
- async start() {
1281
- this.logger.Debug().Msg("starting");
1282
- const res = await this.gateway.start(this.url);
1283
- if (res.isErr()) {
1284
- return res;
1594
+ async handleSubscribers(dbMetas, branch) {
1595
+ try {
1596
+ const subscribers = this.subscribers.get(branch) || [];
1597
+ await Promise.all(subscribers.map((subscriber) => subscriber(dbMetas)));
1598
+ } catch (e) {
1599
+ this.logger.Error().Err(e).Msg("handleSubscribers").AsError();
1285
1600
  }
1286
- this._onStarted.forEach((fn) => fn());
1287
- return guardVersion(this.url);
1601
+ }
1602
+ async handleByteHeads(byteHeads, branch = "main") {
1603
+ let dbMetas;
1604
+ try {
1605
+ dbMetas = this.dbMetasForByteHeads(byteHeads);
1606
+ } catch (e) {
1607
+ throw this.logger.Error().Err(e).Msg("parseHeader").AsError();
1608
+ }
1609
+ await this.handleSubscribers(dbMetas, branch);
1610
+ return dbMetas;
1611
+ }
1612
+ dbMetasForByteHeads(byteHeads) {
1613
+ return byteHeads.map((bytes) => {
1614
+ const txt = this.sthis.txt.decode(bytes);
1615
+ return this.parseHeader(txt);
1616
+ });
1288
1617
  }
1289
1618
  async load(branch) {
1290
- this.logger.Debug().Str("branch", branch || "").Msg("loading");
1291
- const url = await this.gateway.buildUrl(this.url, branch || "main");
1619
+ branch = branch || "main";
1620
+ this.logger.Debug().Str("branch", branch).Msg("loading");
1621
+ const url = await this.gateway.buildUrl(this.url(), branch);
1292
1622
  if (url.isErr()) {
1293
- throw this.logger.Error().Result("buidUrl", url).Str("branch", branch || "").Url(this.url).Msg("got error from gateway.buildUrl").AsError();
1623
+ throw this.logger.Error().Result("buidUrl", url).Str("branch", branch).Msg("got error from gateway.buildUrl").AsError();
1294
1624
  }
1295
1625
  const bytes = await this.gateway.get(url.Ok());
1296
1626
  if (bytes.isErr()) {
1297
1627
  if (isNotFoundError(bytes)) {
1298
- return void 0;
1299
- }
1300
- throw this.logger.Error().Url(url.Ok()).Result("bytes:", bytes).Msg("gateway get").AsError();
1301
- }
1302
- try {
1303
- return [this.parseHeader(textDecoder.decode(bytes.Ok()))];
1304
- } catch (e) {
1305
- throw this.logger.Error().Err(e).Msg("parseHeader").AsError();
1628
+ return void 0;
1629
+ }
1630
+ throw this.logger.Error().Url(url.Ok()).Result("bytes:", bytes).Msg("gateway get").AsError();
1306
1631
  }
1632
+ return this.handleByteHeads([bytes.Ok()], branch);
1307
1633
  }
1308
- async save(meta, branch = "main") {
1634
+ async save(meta, branch) {
1635
+ branch = branch || "main";
1309
1636
  this.logger.Debug().Str("branch", branch).Any("meta", meta).Msg("saving meta");
1310
1637
  const bytes = this.makeHeader(meta);
1311
- const url = await this.gateway.buildUrl(this.url, branch);
1638
+ const url = await this.gateway.buildUrl(this.url(), branch);
1312
1639
  if (url.isErr()) {
1313
- throw this.logger.Error().Err(url.Err()).Str("branch", branch).Url(this.url).Msg("got error from gateway.buildUrl").AsError();
1640
+ throw this.logger.Error().Err(url.Err()).Str("branch", branch).Msg("got error from gateway.buildUrl").AsError();
1314
1641
  }
1315
- const res = await this.gateway.put(url.Ok(), textEncoder.encode(bytes));
1642
+ const res = await this.gateway.put(url.Ok(), this.sthis.txt.encode(bytes));
1316
1643
  if (res.isErr()) {
1317
1644
  throw this.logger.Error().Err(res.Err()).Msg("got error from gateway.put").AsError();
1318
1645
  }
1319
- return res.Ok();
1646
+ await this.handleSubscribers([meta], branch);
1647
+ return res;
1320
1648
  }
1321
1649
  async close() {
1322
- await this.gateway.close(this.url);
1650
+ await this.gateway.close(this.url());
1323
1651
  this._onClosed.forEach((fn) => fn());
1324
- return Result2.Ok(void 0);
1652
+ return Result3.Ok(void 0);
1325
1653
  }
1326
1654
  async destroy() {
1327
- return this.gateway.destroy(this.url);
1655
+ return this.gateway.destroy(this.url());
1328
1656
  }
1329
1657
  };
1330
- var DataStore = class extends VersionedStore {
1331
- constructor(name, url, logger, gateway) {
1658
+ var DataStoreImpl = class extends BaseStoreImpl {
1659
+ // readonly tag: string = "car-base";
1660
+ constructor(sthis, name, url, opts) {
1332
1661
  super(
1333
1662
  name,
1334
1663
  url,
1335
- ensureLogger(logger, "DataStore", {
1336
- url: () => url.toString()
1337
- })
1664
+ {
1665
+ ...opts
1666
+ },
1667
+ sthis,
1668
+ ensureLogger(sthis, "DataStoreImpl")
1338
1669
  );
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;
1670
+ this.storeType = "data";
1358
1671
  }
1359
1672
  async load(cid) {
1360
1673
  this.logger.Debug().Any("cid", cid).Msg("loading");
1361
- const url = await this.gateway.buildUrl(this.url, cid.toString());
1674
+ const url = await this.gateway.buildUrl(this.url(), cid.toString());
1362
1675
  if (url.isErr()) {
1363
1676
  throw this.logger.Error().Err(url.Err()).Str("cid", cid.toString()).Msg("got error from gateway.buildUrl").AsError();
1364
1677
  }
@@ -1371,7 +1684,7 @@ var DataStore = class extends VersionedStore {
1371
1684
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
1372
1685
  async save(car, opts) {
1373
1686
  this.logger.Debug().Any("cid", car.cid.toString()).Msg("saving");
1374
- const url = await this.gateway.buildUrl(this.url, car.cid.toString());
1687
+ const url = await this.gateway.buildUrl(this.url(), car.cid.toString());
1375
1688
  if (url.isErr()) {
1376
1689
  throw this.logger.Error().Err(url.Err()).Ref("cid", car.cid).Msg("got error from gateway.buildUrl").AsError();
1377
1690
  }
@@ -1382,46 +1695,53 @@ var DataStore = class extends VersionedStore {
1382
1695
  return res.Ok();
1383
1696
  }
1384
1697
  async remove(cid) {
1385
- const url = await this.gateway.buildUrl(this.url, cid.toString());
1698
+ const url = await this.gateway.buildUrl(this.url(), cid.toString());
1386
1699
  if (url.isErr()) {
1387
1700
  return url;
1388
1701
  }
1389
1702
  return this.gateway.delete(url.Ok());
1390
1703
  }
1391
1704
  async close() {
1392
- await this.gateway.close(this.url);
1705
+ await this.gateway.close(this.url());
1393
1706
  this._onClosed.forEach((fn) => fn());
1394
- return Result2.Ok(void 0);
1707
+ return Result3.Ok(void 0);
1395
1708
  }
1396
1709
  destroy() {
1397
- return this.gateway.destroy(this.url);
1710
+ return this.gateway.destroy(this.url());
1398
1711
  }
1399
1712
  };
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";
1713
+ var WALStoreImpl = class extends BaseStoreImpl {
1714
+ constructor(loader, url, opts) {
1715
+ super(
1716
+ loader.name,
1717
+ url,
1718
+ {
1719
+ ...opts
1720
+ },
1721
+ loader.sthis,
1722
+ ensureLogger(loader.sthis, "WALStoreImpl")
1723
+ );
1724
+ this.storeType = "wal";
1404
1725
  this._ready = new ResolveOnce2();
1405
1726
  this.walState = { operations: [], noLoaderOps: [], fileOperations: [] };
1406
1727
  this.processing = void 0;
1407
1728
  this.processQueue = new CommitQueue();
1408
- this.loader = loader;
1409
- this.gateway = gateway;
1410
- }
1411
- async ready() {
1412
- return this._ready.once(async () => {
1413
- const walState = await this.load().catch((e) => {
1414
- this.logger.Error().Any("error", e).Msg("error loading wal");
1415
- return void 0;
1729
+ this.ready = async () => {
1730
+ return this._ready.once(async () => {
1731
+ const walState = await this.load().catch((e) => {
1732
+ this.logger.Error().Any("error", e).Msg("error loading wal");
1733
+ return void 0;
1734
+ });
1735
+ if (!walState) {
1736
+ this.walState.operations = [];
1737
+ this.walState.fileOperations = [];
1738
+ } else {
1739
+ this.walState.operations = walState.operations || [];
1740
+ this.walState.fileOperations = walState.fileOperations || [];
1741
+ }
1416
1742
  });
1417
- if (!walState) {
1418
- this.walState.operations = [];
1419
- this.walState.fileOperations = [];
1420
- } else {
1421
- this.walState.operations = walState.operations || [];
1422
- this.walState.fileOperations = walState.fileOperations || [];
1423
- }
1424
- });
1743
+ };
1744
+ this.loader = loader;
1425
1745
  }
1426
1746
  async enqueue(dbMeta, opts) {
1427
1747
  await this.ready();
@@ -1431,19 +1751,23 @@ var RemoteWAL = class extends VersionedStore {
1431
1751
  this.walState.operations.push(dbMeta);
1432
1752
  }
1433
1753
  await this.save(this.walState);
1434
- void this._process();
1754
+ void this.process();
1435
1755
  }
1436
1756
  async enqueueFile(fileCid, publicFile = false) {
1437
1757
  await this.ready();
1438
1758
  this.walState.fileOperations.push({ cid: fileCid, public: publicFile });
1439
1759
  }
1440
- async _process() {
1760
+ async process() {
1441
1761
  await this.ready();
1442
1762
  if (!this.loader.remoteCarStore) return;
1443
1763
  await this.processQueue.enqueue(async () => {
1444
- await this._doProcess();
1764
+ try {
1765
+ await this._doProcess();
1766
+ } catch (e) {
1767
+ this.logger.Error().Any("error", e).Msg("error processing wal");
1768
+ }
1445
1769
  if (this.walState.operations.length || this.walState.fileOperations.length || this.walState.noLoaderOps.length) {
1446
- setTimeout(() => void this._process(), 0);
1770
+ setTimeout(() => void this.process(), 0);
1447
1771
  }
1448
1772
  });
1449
1773
  }
@@ -1461,7 +1785,7 @@ var RemoteWAL = class extends VersionedStore {
1461
1785
  for (const cid of dbMeta.cars) {
1462
1786
  const car = await (await this.loader.carStore()).load(cid);
1463
1787
  if (!car) {
1464
- if (carLogIncludesGroup2(this.loader.carLog, dbMeta.cars))
1788
+ if (carLogIncludesGroup(this.loader.carLog, dbMeta.cars))
1465
1789
  throw this.logger.Error().Ref("cid", cid).Msg("missing local car").AsError();
1466
1790
  } else {
1467
1791
  await throwFalsy(this.loader.remoteCarStore).save(car);
@@ -1476,7 +1800,7 @@ var RemoteWAL = class extends VersionedStore {
1476
1800
  for (const cid of dbMeta.cars) {
1477
1801
  const car = await (await this.loader.carStore()).load(cid).catch(() => null);
1478
1802
  if (!car) {
1479
- if (carLogIncludesGroup2(this.loader.carLog, dbMeta.cars))
1803
+ if (carLogIncludesGroup(this.loader.carLog, dbMeta.cars))
1480
1804
  throw this.logger.Error().Ref("cid", cid).Msg(`missing local car`).AsError();
1481
1805
  } else {
1482
1806
  await throwFalsy(this.loader.remoteCarStore).save(car);
@@ -1501,11 +1825,7 @@ var RemoteWAL = class extends VersionedStore {
1501
1825
  const res = await Promise.allSettled(uploads);
1502
1826
  const errors = res.filter((r) => r.status === "rejected");
1503
1827
  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;
1828
+ throw this.logger.Error().Any("errors", errors).Msg("error uploading").AsError();
1509
1829
  }
1510
1830
  if (operations.length) {
1511
1831
  const lastOp = operations[operations.length - 1];
@@ -1520,29 +1840,11 @@ var RemoteWAL = class extends VersionedStore {
1520
1840
  })();
1521
1841
  await rmlp;
1522
1842
  }
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
1843
  async load() {
1542
1844
  this.logger.Debug().Msg("loading");
1543
- const filepath = await this.gateway.buildUrl(this.url, "main");
1845
+ const filepath = await this.gateway.buildUrl(this.url(), "main");
1544
1846
  if (filepath.isErr()) {
1545
- throw this.logger.Error().Err(filepath.Err()).Str("url", this.url.toString()).Msg("error building url").AsError();
1847
+ throw this.logger.Error().Err(filepath.Err()).Url(this.url()).Msg("error building url").AsError();
1546
1848
  }
1547
1849
  const bytes = await this.gateway.get(filepath.Ok());
1548
1850
  if (bytes.isErr()) {
@@ -1552,15 +1854,15 @@ var RemoteWAL = class extends VersionedStore {
1552
1854
  throw this.logger.Error().Err(bytes.Err()).Msg("error get").AsError();
1553
1855
  }
1554
1856
  try {
1555
- return bytes && parse(textDecoder.decode(bytes.Ok()));
1857
+ return bytes && parse(this.sthis.txt.decode(bytes.Ok()));
1556
1858
  } catch (e) {
1557
1859
  throw this.logger.Error().Err(e).Msg("error parse").AsError();
1558
1860
  }
1559
1861
  }
1560
1862
  async save(state) {
1561
- const filepath = await this.gateway.buildUrl(this.url, "main");
1863
+ const filepath = await this.gateway.buildUrl(this.url(), "main");
1562
1864
  if (filepath.isErr()) {
1563
- throw this.logger.Error().Err(filepath.Err()).Str("url", this.url.toString()).Msg("error building url").AsError();
1865
+ throw this.logger.Error().Err(filepath.Err()).Url(this.url()).Msg("error building url").AsError();
1564
1866
  }
1565
1867
  let encoded;
1566
1868
  try {
@@ -1568,55 +1870,67 @@ var RemoteWAL = class extends VersionedStore {
1568
1870
  } catch (e) {
1569
1871
  throw this.logger.Error().Err(e).Any("state", state).Msg("error format").AsError();
1570
1872
  }
1571
- const res = await this.gateway.put(filepath.Ok(), textEncoder.encode(encoded));
1873
+ const res = await this.gateway.put(filepath.Ok(), this.sthis.txt.encode(encoded));
1572
1874
  if (res.isErr()) {
1573
1875
  throw this.logger.Error().Err(res.Err()).Str("filePath", filepath.Ok().toString()).Msg("error saving").AsError();
1574
1876
  }
1575
1877
  }
1576
1878
  async close() {
1577
- await this.gateway.close(this.url);
1879
+ await this.gateway.close(this.url());
1578
1880
  this._onClosed.forEach((fn) => fn());
1579
- return Result2.Ok(void 0);
1881
+ return Result3.Ok(void 0);
1580
1882
  }
1581
1883
  destroy() {
1582
- return this.gateway.destroy(this.url);
1884
+ return this.gateway.destroy(this.url());
1583
1885
  }
1584
1886
  };
1585
1887
 
1586
1888
  // src/blockstore/store-factory.ts
1587
1889
  function ensureIsIndex(url, isIndex) {
1588
1890
  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);
1891
+ return url.build().setParam("index", isIndex).URI();
1604
1892
  }
1893
+ return url.build().delParam("index").URI();
1605
1894
  }
1606
- var storeFactory = /* @__PURE__ */ new Map();
1607
1895
  function ensureName(name, url) {
1608
- if (!url.searchParams.has("name")) {
1609
- url.searchParams.set("name", name);
1896
+ if (!url.hasParam("name")) {
1897
+ return url.build().setParam("name", name).URI();
1610
1898
  }
1899
+ return url;
1611
1900
  }
1901
+ var storeFactory = /* @__PURE__ */ new Map();
1612
1902
  function buildURL(optURL, loader) {
1613
1903
  const storeOpts = loader.ebOpts.store;
1614
1904
  const obuItem = Array.from(storeFactory.values()).find((items) => items.overrideBaseURL);
1615
1905
  let obuUrl;
1616
1906
  if (obuItem && obuItem.overrideBaseURL) {
1617
- obuUrl = new URL(obuItem.overrideBaseURL);
1907
+ obuUrl = URI3.from(obuItem.overrideBaseURL);
1618
1908
  }
1619
- return toURL(optURL || obuUrl || dataDir(loader.name, storeOpts.stores?.base), storeOpts.isIndex);
1909
+ const ret = ensureIsIndex(
1910
+ URI3.from(optURL || obuUrl || dataDir(loader.sthis, loader.name, storeOpts.stores?.base)),
1911
+ storeOpts.isIndex
1912
+ );
1913
+ return ret;
1914
+ }
1915
+ var onceGateway = new KeyedResolvOnce2();
1916
+ async function getGatewayFromURL(url, sthis) {
1917
+ return onceGateway.get(url.toString()).once(async () => {
1918
+ const item = storeFactory.get(url.protocol);
1919
+ if (item) {
1920
+ const ret = {
1921
+ gateway: await item.gateway(sthis),
1922
+ test: await item.test(sthis)
1923
+ };
1924
+ const res = await ret.gateway.start(url);
1925
+ if (res.isErr()) {
1926
+ sthis.logger.Error().Result("start", res).Msg("start failed");
1927
+ return void 0;
1928
+ }
1929
+ return ret;
1930
+ }
1931
+ sthis.logger.Warn().Url(url).Msg("unsupported protocol");
1932
+ return void 0;
1933
+ });
1620
1934
  }
1621
1935
  function registerStoreProtocol(item) {
1622
1936
  let protocol = item.protocol;
@@ -1625,8 +1939,7 @@ function registerStoreProtocol(item) {
1625
1939
  }
1626
1940
  if (storeFactory.has(protocol)) {
1627
1941
  if (!item.overrideBaseURL && storeFactory.get(protocol) !== item) {
1628
- const logger = ensureLogger({}, "registerStoreProtocol", { protocol });
1629
- logger.Warn().Msg(`protocol ${protocol} already registered`);
1942
+ throw new Error(`we need a logger here`);
1630
1943
  return () => {
1631
1944
  };
1632
1945
  }
@@ -1641,106 +1954,83 @@ function registerStoreProtocol(item) {
1641
1954
  storeFactory.delete(protocol);
1642
1955
  };
1643
1956
  }
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();
1659
1957
  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");
1664
- 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");
1672
- return store;
1673
- });
1674
- }
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));
1958
+ const url = ensureName(loader.name, buildURL(loader.ebOpts.store.stores?.data, loader)).build().setParam("store", "data").URI();
1959
+ const sthis = ensureSuperLog(loader.sthis, "dataStoreFactory", { url: url.toString() });
1960
+ const gateway = await getGatewayFromURL(url, sthis);
1961
+ if (!gateway) {
1962
+ throw sthis.logger.Error().Url(url).Msg("gateway not found").AsError();
1963
+ }
1964
+ const store = new DataStoreImpl(sthis, loader.name, url, {
1965
+ gateway: gateway.gateway,
1966
+ keybag: () => getKeyBag(loader.sthis, {
1967
+ ...loader.ebOpts.keyBag
1968
+ })
1679
1969
  });
1970
+ return store;
1680
1971
  }
1681
- var onceMetaStoreFactory = new KeyedResolvOnce();
1682
1972
  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");
1687
- 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
- }
1695
- return store;
1696
- });
1697
- }
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));
1973
+ const url = ensureName(loader.name, buildURL(loader.ebOpts.store.stores?.meta, loader)).build().setParam("store", "meta").URI();
1974
+ const sthis = ensureSuperLog(loader.sthis, "metaStoreFactory", { url: () => url.toString() });
1975
+ sthis.logger.Debug().Str("protocol", url.protocol).Msg("pre-protocol switch");
1976
+ const gateway = await getGatewayFromURL(url, sthis);
1977
+ if (!gateway) {
1978
+ throw sthis.logger.Error().Url(url).Msg("gateway not found").AsError();
1979
+ }
1980
+ const store = new MetaStoreImpl(loader.sthis, loader.name, url, {
1981
+ gateway: gateway.gateway,
1982
+ keybag: () => getKeyBag(loader.sthis, {
1983
+ ...loader.ebOpts.keyBag
1984
+ })
1702
1985
  });
1986
+ return store;
1703
1987
  }
1704
- var onceRemoteWalFactory = new KeyedResolvOnce();
1705
1988
  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");
1710
- 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
- }
1718
- return store;
1989
+ const url = ensureName(loader.name, buildURL(loader.ebOpts.store.stores?.wal, loader)).build().setParam("store", "wal").URI();
1990
+ const sthis = ensureSuperLog(loader.sthis, "remoteWalFactory", { url: url.toString() });
1991
+ const gateway = await getGatewayFromURL(url, sthis);
1992
+ if (!gateway) {
1993
+ throw sthis.logger.Error().Url(url).Msg("gateway not found").AsError();
1994
+ }
1995
+ sthis.logger.Debug().Str("prepared", url.toString()).Msg("produced");
1996
+ const store = new WALStoreImpl(loader, url, {
1997
+ gateway: gateway.gateway,
1998
+ keybag: () => getKeyBag(loader.sthis, {
1999
+ ...loader.ebOpts.keyBag
2000
+ })
1719
2001
  });
2002
+ return store;
1720
2003
  }
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));
2004
+ async function testStoreFactory(url, sthis) {
2005
+ sthis = ensureSuperLog(sthis, "testStoreFactory");
2006
+ const gateway = await getGatewayFromURL(url, sthis);
2007
+ if (!gateway) {
2008
+ throw sthis.logger.Error().Url(url).Msg("gateway not found").AsError();
2009
+ }
2010
+ return gateway.test;
1729
2011
  }
1730
- function toStoreRuntime(opts, ilogger) {
1731
- const logger = ensureLogger(ilogger, "toStoreRuntime", {});
2012
+ async function ensureStart(store, logger) {
2013
+ const ret = await store.start();
2014
+ if (ret.isErr()) {
2015
+ throw logger.Error().Result("start", ret).Msg("start failed").AsError();
2016
+ }
2017
+ logger.Debug().Url(ret.Ok(), "prepared").Msg("produced");
2018
+ return store;
2019
+ }
2020
+ function toStoreRuntime(opts, sthis) {
2021
+ const logger = ensureLogger(sthis, "toStoreRuntime", {});
1732
2022
  return {
1733
- makeMetaStore: (loader) => {
2023
+ makeMetaStore: async (loader) => {
1734
2024
  logger.Debug().Str("fromOpts", "" + !!loader.ebOpts.store.makeMetaStore).Msg("makeMetaStore");
1735
- return (loader.ebOpts.store.makeMetaStore || metaStoreFactory)(loader);
2025
+ return ensureStart(await (loader.ebOpts.store.makeMetaStore || metaStoreFactory)(loader), logger);
1736
2026
  },
1737
- makeDataStore: (loader) => {
2027
+ makeDataStore: async (loader) => {
1738
2028
  logger.Debug().Str("fromOpts", "" + !!loader.ebOpts.store.makeDataStore).Msg("makeDataStore");
1739
- return (loader.ebOpts.store.makeDataStore || dataStoreFactory)(loader);
2029
+ return ensureStart(await (loader.ebOpts.store.makeDataStore || dataStoreFactory)(loader), logger);
1740
2030
  },
1741
- makeRemoteWAL: (loader) => {
1742
- logger.Debug().Str("fromOpts", "" + !!loader.ebOpts.store.makeRemoteWAL).Msg("makeRemoteWAL");
1743
- return (loader.ebOpts.store.makeRemoteWAL || remoteWalFactory)(loader);
2031
+ makeWALStore: async (loader) => {
2032
+ logger.Debug().Str("fromOpts", "" + !!loader.ebOpts.store.makeWALStore).Msg("makeRemoteWAL");
2033
+ return ensureStart(await (loader.ebOpts.store.makeWALStore || remoteWalFactory)(loader), logger);
1744
2034
  },
1745
2035
  encodeFile: opts.encodeFile || encodeFile,
1746
2036
  decodeFile: opts.decodeFile || decodeFile
@@ -1748,43 +2038,200 @@ function toStoreRuntime(opts, ilogger) {
1748
2038
  }
1749
2039
  registerStoreProtocol({
1750
2040
  protocol: "file:",
1751
- data: async (logger) => {
1752
- const { FileDataGateway } = await import("./store-file-VJ6BI4II.js");
1753
- return new FileDataGateway(logger);
1754
- },
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);
2041
+ gateway: async (logger) => {
2042
+ const { FileGateway } = await import("./gateway-YSNUK2L3.js");
2043
+ return new FileGateway(logger);
1762
2044
  },
1763
2045
  test: async (logger) => {
1764
- const { FileTestStore } = await import("./store-file-VJ6BI4II.js");
2046
+ const { FileTestStore } = await import("./gateway-YSNUK2L3.js");
1765
2047
  return new FileTestStore(logger);
1766
2048
  }
1767
2049
  });
1768
2050
  registerStoreProtocol({
1769
2051
  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);
2052
+ gateway: async (logger) => {
2053
+ const { IndexDBGateway } = await import("./gateway-IZRHJWPE.js");
2054
+ return new IndexDBGateway(logger);
1781
2055
  },
1782
2056
  test: async (logger) => {
1783
- const { IndexDBTestStore } = await import("./store-indexdb-WLRSICCB.js");
2057
+ const { IndexDBTestStore } = await import("./gateway-IZRHJWPE.js");
1784
2058
  return new IndexDBTestStore(logger);
1785
2059
  }
1786
2060
  });
1787
2061
 
2062
+ // src/blockstore/connection-base.ts
2063
+ import { EventBlock, decodeEventBlock } from "@web3-storage/pail/clock";
2064
+ import { MemoryBlockstore as MemoryBlockstore2 } from "@web3-storage/pail/block";
2065
+
2066
+ // src/blockstore/task-manager.ts
2067
+ var TaskManager = class {
2068
+ constructor(loader) {
2069
+ this.eventsWeHandled = /* @__PURE__ */ new Set();
2070
+ this.queue = [];
2071
+ this.isProcessing = false;
2072
+ this.loader = loader;
2073
+ this.logger = ensureLogger(loader.sthis, "TaskManager");
2074
+ }
2075
+ async handleEvent(eventBlock) {
2076
+ const cid = eventBlock.cid.toString();
2077
+ const parents = eventBlock.value.parents.map((cid2) => cid2.toString());
2078
+ for (const parent of parents) {
2079
+ this.eventsWeHandled.add(parent);
2080
+ }
2081
+ this.queue.push({ cid, eventBlock, retries: 0 });
2082
+ this.queue = this.queue.filter(({ cid: cid2 }) => !this.eventsWeHandled.has(cid2));
2083
+ void this.processQueue();
2084
+ }
2085
+ async processQueue() {
2086
+ if (this.isProcessing) return;
2087
+ this.isProcessing = true;
2088
+ const filteredQueue = this.queue.filter(({ cid }) => !this.eventsWeHandled.has(cid));
2089
+ const first = filteredQueue[0];
2090
+ if (!first) {
2091
+ return;
2092
+ }
2093
+ try {
2094
+ this.loader?.remoteMetaStore?.handleByteHeads([first.eventBlock.value.data.dbMeta]);
2095
+ this.eventsWeHandled.add(first.cid);
2096
+ this.queue = this.queue.filter(({ cid }) => !this.eventsWeHandled.has(cid));
2097
+ } catch (err) {
2098
+ if (first.retries++ > 3) {
2099
+ this.logger.Error().Str("cid", first.cid).Msg("failed to process event block after 3 retries");
2100
+ this.queue = this.queue.filter(({ cid }) => cid !== first.cid);
2101
+ }
2102
+ await new Promise((resolve) => setTimeout(resolve, 50));
2103
+ throw this.logger.Error().Err(err).Msg("failed to process event block").AsError();
2104
+ } finally {
2105
+ this.isProcessing = false;
2106
+ if (this.queue.length > 0) {
2107
+ void this.processQueue();
2108
+ }
2109
+ }
2110
+ }
2111
+ };
2112
+
2113
+ // src/blockstore/store-remote.ts
2114
+ async function RemoteDataStore(sthis, name, url, opts) {
2115
+ const ds = new DataStoreImpl(sthis, name, url, opts);
2116
+ await ds.start();
2117
+ return ds;
2118
+ }
2119
+ async function RemoteMetaStore(sthis, name, url, opts) {
2120
+ const ms = new MetaStoreImpl(sthis, name, url, opts);
2121
+ await ms.start();
2122
+ return ms;
2123
+ }
2124
+
2125
+ // src/blockstore/connection-base.ts
2126
+ var ConnectionBase = class {
2127
+ constructor(url, logger) {
2128
+ // readonly ready: Promise<unknown>;
2129
+ // todo move to LRU blockstore https://github.com/web3-storage/w3clock/blob/main/src/worker/block.js
2130
+ this.eventBlocks = new MemoryBlockstore2();
2131
+ this.parents = [];
2132
+ this.loaded = Promise.resolve();
2133
+ this.logger = logger;
2134
+ this.url = url;
2135
+ }
2136
+ async refresh() {
2137
+ await throwFalsy(throwFalsy(this.loader).remoteMetaStore).load("main");
2138
+ await (await throwFalsy(this.loader).WALStore()).process();
2139
+ }
2140
+ async connect_X({ loader }) {
2141
+ if (!loader) throw this.logger.Error().Msg("loader is required").AsError();
2142
+ await this.connectMeta_X({ loader });
2143
+ await this.connectStorage_X({ loader });
2144
+ }
2145
+ async connectMeta_X({ loader }) {
2146
+ if (!loader) throw this.logger.Error().Msg("connectMeta_X: loader is required").AsError();
2147
+ this.loader = loader;
2148
+ this.taskManager = new TaskManager(loader);
2149
+ await this.onConnect();
2150
+ const metaUrl = this.url.build().defParam("store", "meta").URI();
2151
+ const gateway = await getGatewayFromURL(metaUrl, this.loader.sthis);
2152
+ if (!gateway) throw this.logger.Error().Url(metaUrl).Msg("connectMeta_X: gateway is required").AsError();
2153
+ const name = metaUrl.toString();
2154
+ const remote = await RemoteMetaStore(loader.sthis, name, metaUrl, {
2155
+ gateway: gateway.gateway,
2156
+ keybag: () => getKeyBag(loader.sthis, loader.ebOpts.keyBag)
2157
+ });
2158
+ remote.onLoad("main", async (metas) => {
2159
+ if (metas) {
2160
+ this.logger.Debug().Any("metas", metas).Bool("loader", this.loader).Msg("connectMeta_X: handleDbMetasFromStore pre");
2161
+ await throwFalsy(this.loader).handleDbMetasFromStore(metas);
2162
+ this.logger.Debug().Any("metas", metas).Msg("connectMeta_X: handleDbMetasFromStore post");
2163
+ }
2164
+ });
2165
+ this.loader.remoteMetaStore = remote;
2166
+ this.loaded = this.loader.ready().then(async () => {
2167
+ remote.load("main").then(async () => {
2168
+ (await throwFalsy(this.loader).WALStore()).process();
2169
+ });
2170
+ });
2171
+ }
2172
+ async connectStorage_X({ loader }) {
2173
+ if (!loader) throw this.logger.Error().Msg("connectStorage_X: loader is required").AsError();
2174
+ this.loader = loader;
2175
+ const dataUrl = this.url.build().defParam("store", "data").URI();
2176
+ const gateway = await getGatewayFromURL(dataUrl, this.loader.sthis);
2177
+ if (!gateway) throw this.logger.Error().Url(dataUrl).Msg("connectStorage_X: gateway is required").AsError();
2178
+ const name = dataUrl.toString();
2179
+ loader.remoteCarStore = await RemoteDataStore(loader.sthis, name, this.url, {
2180
+ gateway: gateway.gateway,
2181
+ keybag: () => getKeyBag(loader.sthis, this.loader?.ebOpts.keyBag)
2182
+ });
2183
+ loader.remoteFileStore = loader.remoteCarStore;
2184
+ }
2185
+ async createEventBlock(bytes) {
2186
+ const data = {
2187
+ dbMeta: bytes
2188
+ };
2189
+ const event = await EventBlock.create(
2190
+ data,
2191
+ this.parents
2192
+ );
2193
+ await this.eventBlocks.put(event.cid, event.bytes);
2194
+ return event;
2195
+ }
2196
+ async decodeEventBlock(bytes) {
2197
+ const event = await decodeEventBlock(bytes);
2198
+ return event;
2199
+ }
2200
+ // move this stuff to connect
2201
+ // async getDashboardURL(compact = true) {
2202
+ // const baseUrl = 'https://dashboard.fireproof.storage/'
2203
+ // if (!this.loader?.remoteCarStore) return new URL('/howto', baseUrl)
2204
+ // // if (compact) {
2205
+ // // await this.compact()
2206
+ // // }
2207
+ // const currents = await this.loader?.metaStore?.load()
2208
+ // if (!currents) throw new Error("Can't sync empty database: save data first")
2209
+ // if (currents.length > 1)
2210
+ // throw new Error("Can't sync database with split heads: make an update first")
2211
+ // const current = currents[0]
2212
+ // const params = {
2213
+ // car: current.car.toString()
2214
+ // }
2215
+ // if (current.key) {
2216
+ // // @ts-ignore
2217
+ // params.key = current.key.toString()
2218
+ // }
2219
+ // // @ts-ignore
2220
+ // if (this.name) {
2221
+ // // @ts-ignore
2222
+ // params.name = this.name
2223
+ // }
2224
+ // const url = new URL('/import#' + new URLSearchParams(params).toString(), baseUrl)
2225
+ // console.log('Import to dashboard: ' + url.toString())
2226
+ // return url
2227
+ // }
2228
+ // openDashboard() {
2229
+ // void this.getDashboardURL().then(url => {
2230
+ // if (url) window.open(url.toString(), '_blank')
2231
+ // })
2232
+ // }
2233
+ };
2234
+
1788
2235
  // src/crdt-helpers.ts
1789
2236
  function time(tag) {
1790
2237
  }
@@ -1833,7 +2280,7 @@ async function writeDocContent(store, blocks, update, logger) {
1833
2280
  await processFiles(store, blocks, update.value, logger);
1834
2281
  value = { doc: update.value };
1835
2282
  }
1836
- const block = await encode3({ value, hasher: hasher2, codec: codec2 });
2283
+ const block = await encode({ value, hasher: hasher5, codec });
1837
2284
  blocks.putSync(block.cid, block.bytes);
1838
2285
  return block.cid;
1839
2286
  }
@@ -1842,10 +2289,16 @@ async function processFiles(store, blocks, doc, logger) {
1842
2289
  await processFileset(logger, store, blocks, doc._files);
1843
2290
  }
1844
2291
  if (doc._publicFiles) {
1845
- await processFileset(logger, store, blocks, doc._publicFiles, true);
2292
+ await processFileset(
2293
+ logger,
2294
+ store,
2295
+ blocks,
2296
+ doc._publicFiles
2297
+ /*, true*/
2298
+ );
1846
2299
  }
1847
2300
  }
1848
- async function processFileset(logger, store, blocks, files, publicFiles = false) {
2301
+ async function processFileset(logger, store, blocks, files) {
1849
2302
  const dbBlockstore = blocks.parent;
1850
2303
  if (!dbBlockstore.loader) throw logger.Error().Msg("Missing loader, database name is required").AsError();
1851
2304
  const t = new CarTransaction(dbBlockstore);
@@ -1867,9 +2320,10 @@ async function processFileset(logger, store, blocks, files, publicFiles = false)
1867
2320
  }
1868
2321
  }
1869
2322
  if (didPut.length) {
1870
- const car = await dbBlockstore.loader.commitFiles(t, { files }, {
1871
- public: publicFiles
1872
- });
2323
+ const car = await dbBlockstore.loader.commitFiles(
2324
+ t,
2325
+ { files }
2326
+ );
1873
2327
  if (car) {
1874
2328
  for (const name of didPut) {
1875
2329
  files[name] = { car, ...files[name] };
@@ -1903,7 +2357,7 @@ function readFileset(blocks, files, isPublic = false) {
1903
2357
  fileMeta.file = async () => await blocks.ebOpts.storeRuntime.decodeFile(
1904
2358
  {
1905
2359
  get: async (cid) => {
1906
- return await blocks.getFile(throwFalsy(fileMeta.car), cid, isPublic);
2360
+ return await blocks.getFile(throwFalsy(fileMeta.car), cid);
1907
2361
  }
1908
2362
  },
1909
2363
  fileMeta.cid,
@@ -1917,7 +2371,7 @@ function readFileset(blocks, files, isPublic = false) {
1917
2371
  async function getValueFromLink(blocks, link, logger) {
1918
2372
  const block = await blocks.get(link);
1919
2373
  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 });
2374
+ const { value } = await decode({ bytes: block.bytes, hasher: hasher5, codec });
1921
2375
  const cvalue = {
1922
2376
  ...value,
1923
2377
  cid: link
@@ -1926,17 +2380,21 @@ async function getValueFromLink(blocks, link, logger) {
1926
2380
  return cvalue;
1927
2381
  }
1928
2382
  var DirtyEventFetcher = class extends EventFetcher {
2383
+ constructor(logger, blocks) {
2384
+ super(blocks);
2385
+ this.logger = logger;
2386
+ }
1929
2387
  async get(link) {
1930
2388
  try {
1931
2389
  return super.get(link);
1932
2390
  } catch (e) {
1933
- console.error("missing event", link.toString(), e);
2391
+ this.logger.Error().Ref("link", link.toString()).Err(e).Msg("Missing event");
1934
2392
  return { value: void 0 };
1935
2393
  }
1936
2394
  }
1937
2395
  };
1938
2396
  async function clockChangesSince(blocks, head, since, opts, logger) {
1939
- const eventsFetcher = opts.dirty ? new DirtyEventFetcher(blocks) : new EventFetcher(blocks);
2397
+ const eventsFetcher = opts.dirty ? new DirtyEventFetcher(logger, blocks) : new EventFetcher(blocks);
1940
2398
  const keys = /* @__PURE__ */ new Set();
1941
2399
  const updates = await gatherUpdates(
1942
2400
  blocks,
@@ -2034,18 +2492,17 @@ async function doCompact(blockLog, head, logger) {
2034
2492
  async function getBlock(blocks, cidString) {
2035
2493
  const block = await blocks.get(parse2(cidString));
2036
2494
  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 });
2495
+ const { cid, value } = await decode({ bytes: block.bytes, codec, hasher: hasher5 });
2496
+ return new Block({ cid, value, bytes: block.bytes });
2039
2497
  }
2040
2498
 
2041
2499
  // 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";
2500
+ import { sha256 as hasher6 } from "multiformats/hashes/sha2";
2501
+ import * as codec2 from "@ipld/dag-cbor";
2045
2502
  import charwise from "charwise";
2046
2503
  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";
2504
+ import { bf, simpleCompare } from "prolly-trees/utils";
2505
+ import { nocache as cache } from "prolly-trees/cache";
2049
2506
  var IndexTree = class {
2050
2507
  };
2051
2508
  function refCompare(aRef, bRef) {
@@ -2061,8 +2518,8 @@ function compare(a, b) {
2061
2518
  if (comp !== 0) return comp;
2062
2519
  return refCompare(aRef, bRef);
2063
2520
  }
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 };
2521
+ var byKeyOpts = { cache, chunker: bf(30), codec: codec2, hasher: hasher6, compare };
2522
+ var byIdOpts = { cache, chunker: bf(30), codec: codec2, hasher: hasher6, compare: simpleCompare };
2066
2523
  function indexEntriesForChanges(changes, mapFn) {
2067
2524
  const indexEntries = [];
2068
2525
  changes.forEach(({ id: key, value, del }) => {
@@ -2090,7 +2547,7 @@ function makeProllyGetBlock(blocks) {
2090
2547
  const block = await blocks.get(address);
2091
2548
  if (!block) throw new Error(`Missing block ${address.toString()}`);
2092
2549
  const { cid, bytes } = block;
2093
- return create3({ cid, bytes, hasher: hasher3, codec: codec3 });
2550
+ return create({ cid, bytes, hasher: hasher6, codec: codec2 });
2094
2551
  };
2095
2552
  }
2096
2553
  async function bulkIndex(tblocks, inIndex, indexEntries, opts) {
@@ -2161,25 +2618,25 @@ function encodeKey(key) {
2161
2618
  }
2162
2619
 
2163
2620
  // src/indexer.ts
2164
- function index({ _crdt }, name, mapFn, meta) {
2621
+ function index(sthis, { _crdt }, name, mapFn, meta) {
2165
2622
  if (mapFn && meta) throw _crdt.logger.Error().Msg("cannot provide both mapFn and meta").AsError();
2166
2623
  if (mapFn && mapFn.constructor.name !== "Function") throw _crdt.logger.Error().Msg("mapFn must be a function").AsError();
2167
2624
  if (_crdt.indexers.has(name)) {
2168
2625
  const idx = _crdt.indexers.get(name);
2169
2626
  idx.applyMapFn(name, mapFn, meta);
2170
2627
  } else {
2171
- const idx = new Index(_crdt, name, mapFn, meta);
2628
+ const idx = new Index(sthis, _crdt, name, mapFn, meta);
2172
2629
  _crdt.indexers.set(name, idx);
2173
2630
  }
2174
2631
  return _crdt.indexers.get(name);
2175
2632
  }
2176
2633
  var Index = class {
2177
- constructor(crdt, name, mapFn, meta) {
2634
+ constructor(sthis, crdt, name, mapFn, meta) {
2178
2635
  this.mapFnString = "";
2179
2636
  this.byKey = new IndexTree();
2180
2637
  this.byId = new IndexTree();
2181
2638
  this.includeDocsDefault = false;
2182
- this.logger = ensureLogger(crdt.logger, "Index");
2639
+ this.logger = ensureLogger(sthis, "Index");
2183
2640
  this.blockstore = crdt.indexBlockstore;
2184
2641
  this.crdt = crdt;
2185
2642
  this.applyMapFn(name, mapFn, meta);
@@ -2234,7 +2691,7 @@ var Index = class {
2234
2691
  }
2235
2692
  if (this.mapFnString) {
2236
2693
  if (this.mapFnString !== mapFn.toString()) {
2237
- throw this.logger.Error().Msg("cannot apply different mapFn app").AsError();
2694
+ throw this.logger.Error().Str("mapFnString", this.mapFnString).Str("mapFn", mapFn.toString()).Msg("cannot apply different mapFn app").AsError();
2238
2695
  }
2239
2696
  } else {
2240
2697
  this.mapFnString = mapFn.toString();
@@ -2428,7 +2885,7 @@ var CRDTClock = class {
2428
2885
  this.emptyWatchers = /* @__PURE__ */ new Set();
2429
2886
  this._ready = new ResolveOnce3();
2430
2887
  this.blockstore = blockstore;
2431
- this.logger = ensureLogger(blockstore.logger, "CRDTClock");
2888
+ this.logger = ensureLogger(blockstore.sthis, "CRDTClock");
2432
2889
  this.applyHeadQueue = applyHeadQueue(this.int_applyHead.bind(this), this.logger);
2433
2890
  }
2434
2891
  async ready() {
@@ -2501,7 +2958,7 @@ var CRDTClock = class {
2501
2958
  }
2502
2959
  return { head: advancedHead };
2503
2960
  },
2504
- { noLoader }
2961
+ { noLoader, add: false }
2505
2962
  );
2506
2963
  this.setHead(meta.head);
2507
2964
  }
@@ -2535,13 +2992,14 @@ async function advanceBlocks(logger, newHead, tblocks, head) {
2535
2992
 
2536
2993
  // src/crdt.ts
2537
2994
  var CRDT = class {
2538
- constructor(name, opts = {}) {
2539
- this.onceReady = new ResolveOnce4();
2995
+ constructor(sthis, name, opts = {}) {
2540
2996
  this.indexers = /* @__PURE__ */ new Map();
2997
+ this.onceReady = new ResolveOnce4();
2998
+ this.sthis = sthis;
2541
2999
  this.name = name;
2542
- this.logger = ensureLogger(opts, "CRDT");
3000
+ this.logger = ensureLogger(sthis, "CRDT");
2543
3001
  this.opts = opts;
2544
- this.blockstore = blockstoreFactory({
3002
+ this.blockstore = blockstoreFactory(sthis, {
2545
3003
  name,
2546
3004
  applyMeta: async (meta) => {
2547
3005
  const crdtMeta = meta;
@@ -2553,22 +3011,20 @@ var CRDT = class {
2553
3011
  return { head: this.clock.head };
2554
3012
  },
2555
3013
  autoCompact: this.opts.autoCompact || 100,
2556
- crypto: this.opts.crypto,
2557
3014
  store: { ...this.opts.store, isIndex: void 0 },
2558
3015
  public: this.opts.public,
2559
3016
  meta: this.opts.meta,
2560
3017
  threshold: this.opts.threshold
2561
3018
  });
2562
- this.indexBlockstore = blockstoreFactory({
3019
+ this.indexBlockstore = blockstoreFactory(sthis, {
2563
3020
  name,
2564
3021
  applyMeta: async (meta) => {
2565
3022
  const idxCarMeta = meta;
2566
3023
  if (!idxCarMeta.indexes) throw this.logger.Error().Msg("missing indexes").AsError();
2567
3024
  for (const [name2, idx] of Object.entries(idxCarMeta.indexes)) {
2568
- index({ _crdt: this }, name2, void 0, idx);
3025
+ index(this.sthis, { _crdt: this }, name2, void 0, idx);
2569
3026
  }
2570
3027
  },
2571
- crypto: this.opts.crypto,
2572
3028
  store: { ...this.opts.store, isIndex: this.opts.store?.isIndex || "idx" },
2573
3029
  public: this.opts.public
2574
3030
  });
@@ -2579,17 +3035,6 @@ var CRDT = class {
2579
3035
  }
2580
3036
  });
2581
3037
  }
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
3038
  async bulk(updates) {
2594
3039
  await this.ready();
2595
3040
  const prevHead = [...this.clock.head];
@@ -2610,6 +3055,21 @@ var CRDT = class {
2610
3055
  await this.clock.applyHead(done.meta.head, prevHead, updates);
2611
3056
  return done.meta;
2612
3057
  }
3058
+ async ready() {
3059
+ return this.onceReady.once(async () => {
3060
+ try {
3061
+ await Promise.all([this.blockstore.ready(), this.indexBlockstore.ready(), this.clock.ready()]);
3062
+ } catch (e) {
3063
+ throw this.logger.Error().Err(e).Msg("CRDT not ready").AsError();
3064
+ }
3065
+ });
3066
+ }
3067
+ async close() {
3068
+ await Promise.all([this.blockstore.close(), this.indexBlockstore.close(), this.clock.close()]);
3069
+ }
3070
+ async destroy() {
3071
+ await Promise.all([this.blockstore.destroy(), this.indexBlockstore.destroy()]);
3072
+ }
2613
3073
  // if (snap) await this.clock.applyHead(crdtMeta.head, this.clock.head)
2614
3074
  async allDocs() {
2615
3075
  await this.ready();
@@ -2657,8 +3117,9 @@ var Database = class {
2657
3117
  this._ready = new ResolveOnce5();
2658
3118
  this.name = name;
2659
3119
  this.opts = opts || this.opts;
2660
- this.logger = ensureLogger(this.opts, "Database");
2661
- this._crdt = new CRDT(name, this.opts);
3120
+ this.sthis = ensureSuperThis(this.opts);
3121
+ this.logger = ensureLogger(this.sthis, "Database");
3122
+ this._crdt = new CRDT(this.sthis, name, this.opts);
2662
3123
  this.blockstore = this._crdt.blockstore;
2663
3124
  this._writeQueue = writeQueue(async (updates) => {
2664
3125
  return await this._crdt.bulk(updates);
@@ -2682,7 +3143,7 @@ var Database = class {
2682
3143
  }
2683
3144
  async ready() {
2684
3145
  return this._ready.once(async () => {
2685
- await SysContainer.start();
3146
+ await this.sthis.start();
2686
3147
  await this._crdt.ready();
2687
3148
  await this.blockstore.ready();
2688
3149
  });
@@ -2702,7 +3163,7 @@ var Database = class {
2702
3163
  await this.ready();
2703
3164
  this.logger.Debug().Str("id", doc._id).Msg("put");
2704
3165
  const { _id, ...value } = doc;
2705
- const docId = _id || uuidv7();
3166
+ const docId = _id || this.sthis.nextId().str;
2706
3167
  const result = await this._writeQueue.push({
2707
3168
  id: docId,
2708
3169
  value: {
@@ -2767,7 +3228,7 @@ var Database = class {
2767
3228
  await this.ready();
2768
3229
  this.logger.Debug().Any("field", field).Any("opts", opts).Msg("query");
2769
3230
  const _crdt = this._crdt;
2770
- const idx = typeof field === "string" ? index({ _crdt }, field) : index({ _crdt }, makeName(field.toString()), field);
3231
+ const idx = typeof field === "string" ? index(this.sthis, { _crdt }, field) : index(this.sthis, { _crdt }, makeName(field.toString()), field);
2771
3232
  return await idx.query(opts);
2772
3233
  }
2773
3234
  async compact() {
@@ -2804,12 +3265,7 @@ function fireproof(name, opts) {
2804
3265
  const key = JSON.stringify(
2805
3266
  toSortedArray({
2806
3267
  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
3268
+ stores: toSortedArray(opts?.store?.stores)
2813
3269
  })
2814
3270
  );
2815
3271
  let db = Database.databases.get(key);
@@ -2824,7 +3280,10 @@ function makeName(fnString) {
2824
3280
  let found = null;
2825
3281
  const matches = Array.from(fnString.matchAll(regex), (match) => match[1].trim());
2826
3282
  if (matches.length === 0) {
2827
- found = /=>\s*(.*)/.exec(fnString);
3283
+ found = /=>\s*{?\s*([^{}]+)\s*}?/.exec(fnString);
3284
+ if (found && found[1].includes("return")) {
3285
+ found = null;
3286
+ }
2828
3287
  }
2829
3288
  if (!found) {
2830
3289
  return fnString;
@@ -2833,19 +3292,49 @@ function makeName(fnString) {
2833
3292
  }
2834
3293
  }
2835
3294
 
3295
+ // src/runtime/index.ts
3296
+ var runtime_exports = {};
3297
+ __export(runtime_exports, {
3298
+ FILESTORE_VERSION: () => FILESTORE_VERSION,
3299
+ INDEXDB_VERSION: () => INDEXDB_VERSION,
3300
+ files: () => files_exports,
3301
+ getFileName: () => getFileName,
3302
+ getFileSystem: () => getFileSystem,
3303
+ getPath: () => getPath,
3304
+ kb: () => key_bag_exports,
3305
+ kc: () => keyed_crypto_exports,
3306
+ mf: () => wait_pr_multiformats_exports,
3307
+ toArrayBuffer: () => toArrayBuffer
3308
+ });
3309
+
3310
+ // src/runtime/wait-pr-multiformats/index.ts
3311
+ var wait_pr_multiformats_exports = {};
3312
+ __export(wait_pr_multiformats_exports, {
3313
+ block: () => block_exports,
3314
+ codec: () => codec_interface_exports
3315
+ });
3316
+
3317
+ // src/runtime/wait-pr-multiformats/codec-interface.ts
3318
+ var codec_interface_exports = {};
3319
+
2836
3320
  // src/version.ts
2837
3321
  var PACKAGE_VERSION = Object.keys({
2838
- "0.19.8-dev-getcon": "xxxx"
3322
+ "0.19.9-dev-frag": "xxxx"
2839
3323
  })[0];
2840
3324
  export {
2841
3325
  CRDT,
2842
3326
  Database,
2843
3327
  Index,
3328
+ NotFoundError,
2844
3329
  PACKAGE_VERSION,
2845
3330
  Result,
3331
+ UInt8ArrayEqual,
2846
3332
  blockstore_exports as blockstore,
2847
3333
  blockstore_exports as bs,
3334
+ dataDir,
2848
3335
  ensureLogger,
3336
+ ensureSuperLog,
3337
+ ensureSuperThis,
2849
3338
  exception2Result,
2850
3339
  exceptionWrapper,
2851
3340
  falsyToUndef,
@@ -2855,6 +3344,7 @@ export {
2855
3344
  getStore,
2856
3345
  index,
2857
3346
  isFalsy,
3347
+ isNotFoundError,
2858
3348
  runtime_exports as rt,
2859
3349
  runtime_exports as runtime,
2860
3350
  throwFalsy